@lickle/docs 0.0.0-dev.1

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 (407) hide show
  1. package/README.md +3 -0
  2. package/dist/esm/_lib/fs/index.js +20 -0
  3. package/dist/esm/_lib/fs/index.js.map +1 -0
  4. package/dist/esm/_lib/fs/watch.js +30 -0
  5. package/dist/esm/_lib/fs/watch.js.map +1 -0
  6. package/dist/esm/_lib/index.js +9 -0
  7. package/dist/esm/_lib/index.js.map +1 -0
  8. package/dist/esm/_lib/jiti/index.js +16 -0
  9. package/dist/esm/_lib/jiti/index.js.map +1 -0
  10. package/dist/esm/_lib/path/index.js +42 -0
  11. package/dist/esm/_lib/path/index.js.map +1 -0
  12. package/dist/esm/_lib/pkg/index.js +128 -0
  13. package/dist/esm/_lib/pkg/index.js.map +1 -0
  14. package/dist/esm/_lib/repo/index.js +100 -0
  15. package/dist/esm/_lib/repo/index.js.map +1 -0
  16. package/dist/esm/_lib/slug/index.js +23 -0
  17. package/dist/esm/_lib/slug/index.js.map +1 -0
  18. package/dist/esm/_lib/t.js +2 -0
  19. package/dist/esm/_lib/t.js.map +1 -0
  20. package/dist/esm/_lib/tsconfig/index.js +12 -0
  21. package/dist/esm/_lib/tsconfig/index.js.map +1 -0
  22. package/dist/esm/_lib/util/index.js +54 -0
  23. package/dist/esm/_lib/util/index.js.map +1 -0
  24. package/dist/esm/cli/cmd/dev.js +74 -0
  25. package/dist/esm/cli/cmd/dev.js.map +1 -0
  26. package/dist/esm/cli/cmd/index.js +4 -0
  27. package/dist/esm/cli/cmd/index.js.map +1 -0
  28. package/dist/esm/cli/cmd/init.js +74 -0
  29. package/dist/esm/cli/cmd/init.js.map +1 -0
  30. package/dist/esm/cli/cmd/json.js +28 -0
  31. package/dist/esm/cli/cmd/json.js.map +1 -0
  32. package/dist/esm/cli/env.js +5 -0
  33. package/dist/esm/cli/env.js.map +1 -0
  34. package/dist/esm/cli/index.js +13 -0
  35. package/dist/esm/cli/index.js.map +1 -0
  36. package/dist/esm/cli/vite/client/index.jsx +20 -0
  37. package/dist/esm/cli/vite/client/index.jsx.map +1 -0
  38. package/dist/esm/cli/vite/index.js +100 -0
  39. package/dist/esm/cli/vite/index.js.map +1 -0
  40. package/dist/esm/cli.js +5 -0
  41. package/dist/esm/cli.js.map +1 -0
  42. package/dist/esm/config/defaults.js +32 -0
  43. package/dist/esm/config/defaults.js.map +1 -0
  44. package/dist/esm/config/file.js +48 -0
  45. package/dist/esm/config/file.js.map +1 -0
  46. package/dist/esm/config/index.js +7 -0
  47. package/dist/esm/config/index.js.map +1 -0
  48. package/dist/esm/config/load.js +79 -0
  49. package/dist/esm/config/load.js.map +1 -0
  50. package/dist/esm/config/types.js +2 -0
  51. package/dist/esm/config/types.js.map +1 -0
  52. package/dist/esm/core/index.js +3 -0
  53. package/dist/esm/core/index.js.map +1 -0
  54. package/dist/esm/core/project/debug.js +26 -0
  55. package/dist/esm/core/project/debug.js.map +1 -0
  56. package/dist/esm/core/project/index.js +39 -0
  57. package/dist/esm/core/project/index.js.map +1 -0
  58. package/dist/esm/core/project/naming.js +39 -0
  59. package/dist/esm/core/project/naming.js.map +1 -0
  60. package/dist/esm/core/project/routing.js +173 -0
  61. package/dist/esm/core/project/routing.js.map +1 -0
  62. package/dist/esm/core/project/types.js +4 -0
  63. package/dist/esm/core/project/types.js.map +1 -0
  64. package/dist/esm/core/reflect/index.js +10 -0
  65. package/dist/esm/core/reflect/index.js.map +1 -0
  66. package/dist/esm/core/reflect/indexed.js +195 -0
  67. package/dist/esm/core/reflect/indexed.js.map +1 -0
  68. package/dist/esm/core/reflect/resolve.js +157 -0
  69. package/dist/esm/core/reflect/resolve.js.map +1 -0
  70. package/dist/esm/core/reflect/scan.js +787 -0
  71. package/dist/esm/core/reflect/scan.js.map +1 -0
  72. package/dist/esm/core/reflect/state.js +29 -0
  73. package/dist/esm/core/reflect/state.js.map +1 -0
  74. package/dist/esm/core/reflect/types.js +16 -0
  75. package/dist/esm/core/reflect/types.js.map +1 -0
  76. package/dist/esm/core/reflect/walk.js +106 -0
  77. package/dist/esm/core/reflect/walk.js.map +1 -0
  78. package/dist/esm/solidjs/index.js +2 -0
  79. package/dist/esm/solidjs/index.js.map +1 -0
  80. package/dist/esm/solidjs/jsx-runtime.js +2 -0
  81. package/dist/esm/solidjs/jsx-runtime.js.map +1 -0
  82. package/dist/esm/ui/App.jsx +71 -0
  83. package/dist/esm/ui/App.jsx.map +1 -0
  84. package/dist/esm/ui/components/Breadcrumb.jsx +45 -0
  85. package/dist/esm/ui/components/Breadcrumb.jsx.map +1 -0
  86. package/dist/esm/ui/components/Code/index.jsx +89 -0
  87. package/dist/esm/ui/components/Code/index.jsx.map +1 -0
  88. package/dist/esm/ui/components/Comment.jsx +176 -0
  89. package/dist/esm/ui/components/Comment.jsx.map +1 -0
  90. package/dist/esm/ui/components/Declaration.jsx +147 -0
  91. package/dist/esm/ui/components/Declaration.jsx.map +1 -0
  92. package/dist/esm/ui/components/Header.jsx +66 -0
  93. package/dist/esm/ui/components/Header.jsx.map +1 -0
  94. package/dist/esm/ui/components/Layout.jsx +44 -0
  95. package/dist/esm/ui/components/Layout.jsx.map +1 -0
  96. package/dist/esm/ui/components/Link.jsx +34 -0
  97. package/dist/esm/ui/components/Link.jsx.map +1 -0
  98. package/dist/esm/ui/components/LivePreview/Example.jsx +76 -0
  99. package/dist/esm/ui/components/LivePreview/Example.jsx.map +1 -0
  100. package/dist/esm/ui/components/LivePreview/Sandbox.jsx +25 -0
  101. package/dist/esm/ui/components/LivePreview/Sandbox.jsx.map +1 -0
  102. package/dist/esm/ui/components/LivePreview/index.js +4 -0
  103. package/dist/esm/ui/components/LivePreview/index.js.map +1 -0
  104. package/dist/esm/ui/components/LivePreview/transform.js +16 -0
  105. package/dist/esm/ui/components/LivePreview/transform.js.map +1 -0
  106. package/dist/esm/ui/components/Markdown.jsx +14 -0
  107. package/dist/esm/ui/components/Markdown.jsx.map +1 -0
  108. package/dist/esm/ui/components/Page.jsx +121 -0
  109. package/dist/esm/ui/components/Page.jsx.map +1 -0
  110. package/dist/esm/ui/components/References.jsx +32 -0
  111. package/dist/esm/ui/components/References.jsx.map +1 -0
  112. package/dist/esm/ui/components/SearchPalette.jsx +178 -0
  113. package/dist/esm/ui/components/SearchPalette.jsx.map +1 -0
  114. package/dist/esm/ui/components/Sidebar.jsx +63 -0
  115. package/dist/esm/ui/components/Sidebar.jsx.map +1 -0
  116. package/dist/esm/ui/components/Syntax.jsx +10 -0
  117. package/dist/esm/ui/components/Syntax.jsx.map +1 -0
  118. package/dist/esm/ui/components/ThemeToggle.jsx +25 -0
  119. package/dist/esm/ui/components/ThemeToggle.jsx.map +1 -0
  120. package/dist/esm/ui/components/Type.jsx +444 -0
  121. package/dist/esm/ui/components/Type.jsx.map +1 -0
  122. package/dist/esm/ui/components/index.js +16 -0
  123. package/dist/esm/ui/components/index.js.map +1 -0
  124. package/dist/esm/ui/context/components.jsx +30 -0
  125. package/dist/esm/ui/context/components.jsx.map +1 -0
  126. package/dist/esm/ui/context/global.js +15 -0
  127. package/dist/esm/ui/context/global.js.map +1 -0
  128. package/dist/esm/ui/context/index.js +5 -0
  129. package/dist/esm/ui/context/index.js.map +1 -0
  130. package/dist/esm/ui/context/markup/index.jsx +25 -0
  131. package/dist/esm/ui/context/markup/index.jsx.map +1 -0
  132. package/dist/esm/ui/context/markup/markdown.js +34 -0
  133. package/dist/esm/ui/context/markup/markdown.js.map +1 -0
  134. package/dist/esm/ui/context/markup/shiki.js +58 -0
  135. package/dist/esm/ui/context/markup/shiki.js.map +1 -0
  136. package/dist/esm/ui/context/markup/util.js +22 -0
  137. package/dist/esm/ui/context/markup/util.js.map +1 -0
  138. package/dist/esm/ui/context/project/index.jsx +27 -0
  139. package/dist/esm/ui/context/project/index.jsx.map +1 -0
  140. package/dist/esm/ui/context/project/indexed.js +47 -0
  141. package/dist/esm/ui/context/project/indexed.js.map +1 -0
  142. package/dist/esm/ui/context/project/types.js +2 -0
  143. package/dist/esm/ui/context/project/types.js.map +1 -0
  144. package/dist/esm/ui/context/theme.jsx +36 -0
  145. package/dist/esm/ui/context/theme.jsx.map +1 -0
  146. package/dist/esm/ui/hooks/index.js +94 -0
  147. package/dist/esm/ui/hooks/index.js.map +1 -0
  148. package/dist/esm/ui/index.js +5 -0
  149. package/dist/esm/ui/index.js.map +1 -0
  150. package/dist/esm/ui/renderer.jsx +21 -0
  151. package/dist/esm/ui/renderer.jsx.map +1 -0
  152. package/dist/esm/ui/util/comment.js +14 -0
  153. package/dist/esm/ui/util/comment.js.map +1 -0
  154. package/dist/esm/ui/util/kind.js +85 -0
  155. package/dist/esm/ui/util/kind.js.map +1 -0
  156. package/dist/esm/ui/util/markdown.js +66 -0
  157. package/dist/esm/ui/util/markdown.js.map +1 -0
  158. package/dist/esm/ui/util/search.js +75 -0
  159. package/dist/esm/ui/util/search.js.map +1 -0
  160. package/dist/ts/_lib/fs/index.d.ts +6 -0
  161. package/dist/ts/_lib/fs/index.d.ts.map +1 -0
  162. package/dist/ts/_lib/fs/watch.d.ts +14 -0
  163. package/dist/ts/_lib/fs/watch.d.ts.map +1 -0
  164. package/dist/ts/_lib/index.d.ts +10 -0
  165. package/dist/ts/_lib/index.d.ts.map +1 -0
  166. package/dist/ts/_lib/jiti/index.d.ts +2 -0
  167. package/dist/ts/_lib/jiti/index.d.ts.map +1 -0
  168. package/dist/ts/_lib/path/index.d.ts +12 -0
  169. package/dist/ts/_lib/path/index.d.ts.map +1 -0
  170. package/dist/ts/_lib/pkg/index.d.ts +28 -0
  171. package/dist/ts/_lib/pkg/index.d.ts.map +1 -0
  172. package/dist/ts/_lib/repo/index.d.ts +30 -0
  173. package/dist/ts/_lib/repo/index.d.ts.map +1 -0
  174. package/dist/ts/_lib/slug/index.d.ts +4 -0
  175. package/dist/ts/_lib/slug/index.d.ts.map +1 -0
  176. package/dist/ts/_lib/t.d.ts +11 -0
  177. package/dist/ts/_lib/t.d.ts.map +1 -0
  178. package/dist/ts/_lib/tsconfig/index.d.ts +8 -0
  179. package/dist/ts/_lib/tsconfig/index.d.ts.map +1 -0
  180. package/dist/ts/_lib/util/index.d.ts +9 -0
  181. package/dist/ts/_lib/util/index.d.ts.map +1 -0
  182. package/dist/ts/cli/cmd/dev.d.ts +27 -0
  183. package/dist/ts/cli/cmd/dev.d.ts.map +1 -0
  184. package/dist/ts/cli/cmd/index.d.ts +4 -0
  185. package/dist/ts/cli/cmd/index.d.ts.map +1 -0
  186. package/dist/ts/cli/cmd/init.d.ts +14 -0
  187. package/dist/ts/cli/cmd/init.d.ts.map +1 -0
  188. package/dist/ts/cli/cmd/json.d.ts +12 -0
  189. package/dist/ts/cli/cmd/json.d.ts.map +1 -0
  190. package/dist/ts/cli/env.d.ts +2 -0
  191. package/dist/ts/cli/env.d.ts.map +1 -0
  192. package/dist/ts/cli/index.d.ts +78 -0
  193. package/dist/ts/cli/index.d.ts.map +1 -0
  194. package/dist/ts/cli/vite/client/index.d.ts +10 -0
  195. package/dist/ts/cli/vite/client/index.d.ts.map +1 -0
  196. package/dist/ts/cli/vite/index.d.ts +12 -0
  197. package/dist/ts/cli/vite/index.d.ts.map +1 -0
  198. package/dist/ts/cli.d.ts +3 -0
  199. package/dist/ts/cli.d.ts.map +1 -0
  200. package/dist/ts/config/defaults.d.ts +10 -0
  201. package/dist/ts/config/defaults.d.ts.map +1 -0
  202. package/dist/ts/config/file.d.ts +3 -0
  203. package/dist/ts/config/file.d.ts.map +1 -0
  204. package/dist/ts/config/index.d.ts +6 -0
  205. package/dist/ts/config/index.d.ts.map +1 -0
  206. package/dist/ts/config/load.d.ts +36 -0
  207. package/dist/ts/config/load.d.ts.map +1 -0
  208. package/dist/ts/config/types.d.ts +56 -0
  209. package/dist/ts/config/types.d.ts.map +1 -0
  210. package/dist/ts/core/index.d.ts +3 -0
  211. package/dist/ts/core/index.d.ts.map +1 -0
  212. package/dist/ts/core/project/debug.d.ts +3 -0
  213. package/dist/ts/core/project/debug.d.ts.map +1 -0
  214. package/dist/ts/core/project/index.d.ts +17 -0
  215. package/dist/ts/core/project/index.d.ts.map +1 -0
  216. package/dist/ts/core/project/naming.d.ts +23 -0
  217. package/dist/ts/core/project/naming.d.ts.map +1 -0
  218. package/dist/ts/core/project/routing.d.ts +61 -0
  219. package/dist/ts/core/project/routing.d.ts.map +1 -0
  220. package/dist/ts/core/project/types.d.ts +56 -0
  221. package/dist/ts/core/project/types.d.ts.map +1 -0
  222. package/dist/ts/core/reflect/index.d.ts +22 -0
  223. package/dist/ts/core/reflect/index.d.ts.map +1 -0
  224. package/dist/ts/core/reflect/indexed.d.ts +83 -0
  225. package/dist/ts/core/reflect/indexed.d.ts.map +1 -0
  226. package/dist/ts/core/reflect/resolve.d.ts +3 -0
  227. package/dist/ts/core/reflect/resolve.d.ts.map +1 -0
  228. package/dist/ts/core/reflect/scan.d.ts +218 -0
  229. package/dist/ts/core/reflect/scan.d.ts.map +1 -0
  230. package/dist/ts/core/reflect/state.d.ts +44 -0
  231. package/dist/ts/core/reflect/state.d.ts.map +1 -0
  232. package/dist/ts/core/reflect/types.d.ts +289 -0
  233. package/dist/ts/core/reflect/types.d.ts.map +1 -0
  234. package/dist/ts/core/reflect/walk.d.ts +28 -0
  235. package/dist/ts/core/reflect/walk.d.ts.map +1 -0
  236. package/dist/ts/solidjs/index.d.ts +2 -0
  237. package/dist/ts/solidjs/index.d.ts.map +1 -0
  238. package/dist/ts/solidjs/jsx-runtime.d.ts +2 -0
  239. package/dist/ts/solidjs/jsx-runtime.d.ts.map +1 -0
  240. package/dist/ts/ui/App.d.ts +17 -0
  241. package/dist/ts/ui/App.d.ts.map +1 -0
  242. package/dist/ts/ui/components/Breadcrumb.d.ts +4 -0
  243. package/dist/ts/ui/components/Breadcrumb.d.ts.map +1 -0
  244. package/dist/ts/ui/components/Code/index.d.ts +17 -0
  245. package/dist/ts/ui/components/Code/index.d.ts.map +1 -0
  246. package/dist/ts/ui/components/Comment.d.ts +49 -0
  247. package/dist/ts/ui/components/Comment.d.ts.map +1 -0
  248. package/dist/ts/ui/components/Declaration.d.ts +122 -0
  249. package/dist/ts/ui/components/Declaration.d.ts.map +1 -0
  250. package/dist/ts/ui/components/Header.d.ts +5 -0
  251. package/dist/ts/ui/components/Header.d.ts.map +1 -0
  252. package/dist/ts/ui/components/Layout.d.ts +5 -0
  253. package/dist/ts/ui/components/Layout.d.ts.map +1 -0
  254. package/dist/ts/ui/components/Link.d.ts +15 -0
  255. package/dist/ts/ui/components/Link.d.ts.map +1 -0
  256. package/dist/ts/ui/components/LivePreview/Example.d.ts +16 -0
  257. package/dist/ts/ui/components/LivePreview/Example.d.ts.map +1 -0
  258. package/dist/ts/ui/components/LivePreview/Sandbox.d.ts +20 -0
  259. package/dist/ts/ui/components/LivePreview/Sandbox.d.ts.map +1 -0
  260. package/dist/ts/ui/components/LivePreview/index.d.ts +4 -0
  261. package/dist/ts/ui/components/LivePreview/index.d.ts.map +1 -0
  262. package/dist/ts/ui/components/LivePreview/transform.d.ts +19 -0
  263. package/dist/ts/ui/components/LivePreview/transform.d.ts.map +1 -0
  264. package/dist/ts/ui/components/Markdown.d.ts +11 -0
  265. package/dist/ts/ui/components/Markdown.d.ts.map +1 -0
  266. package/dist/ts/ui/components/Page.d.ts +21 -0
  267. package/dist/ts/ui/components/Page.d.ts.map +1 -0
  268. package/dist/ts/ui/components/References.d.ts +2 -0
  269. package/dist/ts/ui/components/References.d.ts.map +1 -0
  270. package/dist/ts/ui/components/SearchPalette.d.ts +5 -0
  271. package/dist/ts/ui/components/SearchPalette.d.ts.map +1 -0
  272. package/dist/ts/ui/components/Sidebar.d.ts +5 -0
  273. package/dist/ts/ui/components/Sidebar.d.ts.map +1 -0
  274. package/dist/ts/ui/components/Syntax.d.ts +15 -0
  275. package/dist/ts/ui/components/Syntax.d.ts.map +1 -0
  276. package/dist/ts/ui/components/ThemeToggle.d.ts +2 -0
  277. package/dist/ts/ui/components/ThemeToggle.d.ts.map +1 -0
  278. package/dist/ts/ui/components/Type.d.ts +82 -0
  279. package/dist/ts/ui/components/Type.d.ts.map +1 -0
  280. package/dist/ts/ui/components/index.d.ts +15 -0
  281. package/dist/ts/ui/components/index.d.ts.map +1 -0
  282. package/dist/ts/ui/context/components.d.ts +124 -0
  283. package/dist/ts/ui/context/components.d.ts.map +1 -0
  284. package/dist/ts/ui/context/global.d.ts +210 -0
  285. package/dist/ts/ui/context/global.d.ts.map +1 -0
  286. package/dist/ts/ui/context/index.d.ts +5 -0
  287. package/dist/ts/ui/context/index.d.ts.map +1 -0
  288. package/dist/ts/ui/context/markup/index.d.ts +20 -0
  289. package/dist/ts/ui/context/markup/index.d.ts.map +1 -0
  290. package/dist/ts/ui/context/markup/markdown.d.ts +4 -0
  291. package/dist/ts/ui/context/markup/markdown.d.ts.map +1 -0
  292. package/dist/ts/ui/context/markup/shiki.d.ts +17 -0
  293. package/dist/ts/ui/context/markup/shiki.d.ts.map +1 -0
  294. package/dist/ts/ui/context/markup/util.d.ts +11 -0
  295. package/dist/ts/ui/context/markup/util.d.ts.map +1 -0
  296. package/dist/ts/ui/context/project/index.d.ts +25 -0
  297. package/dist/ts/ui/context/project/index.d.ts.map +1 -0
  298. package/dist/ts/ui/context/project/indexed.d.ts +4 -0
  299. package/dist/ts/ui/context/project/indexed.d.ts.map +1 -0
  300. package/dist/ts/ui/context/project/types.d.ts +13 -0
  301. package/dist/ts/ui/context/project/types.d.ts.map +1 -0
  302. package/dist/ts/ui/context/theme.d.ts +12 -0
  303. package/dist/ts/ui/context/theme.d.ts.map +1 -0
  304. package/dist/ts/ui/hooks/index.d.ts +29 -0
  305. package/dist/ts/ui/hooks/index.d.ts.map +1 -0
  306. package/dist/ts/ui/index.d.ts +5 -0
  307. package/dist/ts/ui/index.d.ts.map +1 -0
  308. package/dist/ts/ui/renderer.d.ts +200 -0
  309. package/dist/ts/ui/renderer.d.ts.map +1 -0
  310. package/dist/ts/ui/util/comment.d.ts +4 -0
  311. package/dist/ts/ui/util/comment.d.ts.map +1 -0
  312. package/dist/ts/ui/util/kind.d.ts +15 -0
  313. package/dist/ts/ui/util/kind.d.ts.map +1 -0
  314. package/dist/ts/ui/util/markdown.d.ts +8 -0
  315. package/dist/ts/ui/util/markdown.d.ts.map +1 -0
  316. package/dist/ts/ui/util/search.d.ts +20 -0
  317. package/dist/ts/ui/util/search.d.ts.map +1 -0
  318. package/package.json +89 -0
  319. package/src/_lib/fs/index.ts +23 -0
  320. package/src/_lib/fs/watch.ts +40 -0
  321. package/src/_lib/index.ts +9 -0
  322. package/src/_lib/jiti/index.ts +18 -0
  323. package/src/_lib/path/index.ts +44 -0
  324. package/src/_lib/pkg/index.ts +165 -0
  325. package/src/_lib/repo/index.ts +138 -0
  326. package/src/_lib/slug/index.ts +26 -0
  327. package/src/_lib/t.ts +17 -0
  328. package/src/_lib/tsconfig/index.ts +20 -0
  329. package/src/_lib/util/index.ts +53 -0
  330. package/src/cli/cmd/dev.ts +86 -0
  331. package/src/cli/cmd/index.ts +3 -0
  332. package/src/cli/cmd/init.ts +80 -0
  333. package/src/cli/cmd/json.ts +28 -0
  334. package/src/cli/env.ts +6 -0
  335. package/src/cli/index.ts +14 -0
  336. package/src/cli/vite/client/index.html +27 -0
  337. package/src/cli/vite/client/index.tsx +30 -0
  338. package/src/cli/vite/client/public/apple-touch-icon.png +0 -0
  339. package/src/cli/vite/client/public/favicon-96x96.png +0 -0
  340. package/src/cli/vite/client/public/favicon.ico +0 -0
  341. package/src/cli/vite/client/public/favicon.svg +1 -0
  342. package/src/cli/vite/client/public/site.webmanifest +21 -0
  343. package/src/cli/vite/client/public/web-app-manifest-192x192.png +0 -0
  344. package/src/cli/vite/client/public/web-app-manifest-512x512.png +0 -0
  345. package/src/cli/vite/index.ts +115 -0
  346. package/src/cli.ts +6 -0
  347. package/src/config/defaults.ts +36 -0
  348. package/src/config/file.ts +53 -0
  349. package/src/config/index.ts +11 -0
  350. package/src/config/load.ts +95 -0
  351. package/src/config/types.ts +59 -0
  352. package/src/core/index.ts +2 -0
  353. package/src/core/project/debug.ts +30 -0
  354. package/src/core/project/index.ts +58 -0
  355. package/src/core/project/naming.ts +49 -0
  356. package/src/core/project/routing.ts +234 -0
  357. package/src/core/project/types.ts +47 -0
  358. package/src/core/reflect/index.ts +18 -0
  359. package/src/core/reflect/indexed.ts +242 -0
  360. package/src/core/reflect/resolve.ts +159 -0
  361. package/src/core/reflect/scan.ts +816 -0
  362. package/src/core/reflect/state.ts +75 -0
  363. package/src/core/reflect/types.ts +164 -0
  364. package/src/core/reflect/walk.ts +121 -0
  365. package/src/solidjs/index.ts +1 -0
  366. package/src/solidjs/jsx-runtime.ts +1 -0
  367. package/src/ui/App.tsx +115 -0
  368. package/src/ui/components/Breadcrumb.tsx +53 -0
  369. package/src/ui/components/Code/index.tsx +112 -0
  370. package/src/ui/components/Comment.tsx +221 -0
  371. package/src/ui/components/Declaration.tsx +210 -0
  372. package/src/ui/components/Header.tsx +99 -0
  373. package/src/ui/components/Layout.tsx +62 -0
  374. package/src/ui/components/Link.tsx +43 -0
  375. package/src/ui/components/LivePreview/Example.tsx +104 -0
  376. package/src/ui/components/LivePreview/Sandbox.tsx +36 -0
  377. package/src/ui/components/LivePreview/index.ts +3 -0
  378. package/src/ui/components/LivePreview/transform.ts +28 -0
  379. package/src/ui/components/Markdown.tsx +16 -0
  380. package/src/ui/components/Page.tsx +162 -0
  381. package/src/ui/components/References.tsx +34 -0
  382. package/src/ui/components/SearchPalette.tsx +266 -0
  383. package/src/ui/components/Sidebar.tsx +107 -0
  384. package/src/ui/components/Syntax.tsx +10 -0
  385. package/src/ui/components/ThemeToggle.tsx +50 -0
  386. package/src/ui/components/Type.tsx +583 -0
  387. package/src/ui/components/index.ts +15 -0
  388. package/src/ui/context/components.tsx +103 -0
  389. package/src/ui/context/global.ts +33 -0
  390. package/src/ui/context/index.ts +4 -0
  391. package/src/ui/context/markup/index.tsx +39 -0
  392. package/src/ui/context/markup/markdown.ts +37 -0
  393. package/src/ui/context/markup/shiki.ts +72 -0
  394. package/src/ui/context/markup/util.ts +20 -0
  395. package/src/ui/context/project/index.tsx +47 -0
  396. package/src/ui/context/project/indexed.ts +52 -0
  397. package/src/ui/context/project/types.ts +14 -0
  398. package/src/ui/context/theme.tsx +45 -0
  399. package/src/ui/hooks/index.ts +116 -0
  400. package/src/ui/index.ts +4 -0
  401. package/src/ui/renderer.tsx +31 -0
  402. package/src/ui/util/comment.ts +12 -0
  403. package/src/ui/util/kind.ts +120 -0
  404. package/src/ui/util/markdown.ts +74 -0
  405. package/src/ui/util/search.ts +84 -0
  406. package/theme.css +301 -0
  407. package/tsconfig.client.json +12 -0
@@ -0,0 +1,816 @@
1
+ import { makeScanState, type ScanOptions, type ScanState as State } from './state.ts'
2
+ import ts from 'typescript'
3
+
4
+ import type * as T from './types.ts'
5
+
6
+ export const scan = (rootFiles: string[], options: ScanOptions) => {
7
+ const compilerOptions: ts.CompilerOptions = { jsx: ts.JsxEmit.ReactJSX, ...options.compilerOptions }
8
+ const program = ts.createProgram(rootFiles, compilerOptions)
9
+ const checker = program.getTypeChecker()
10
+ const s = makeScanState(checker, options)
11
+
12
+ const files = new Array<ts.SourceFile>()
13
+ for (const file of rootFiles) {
14
+ const sf = program.getSourceFile(file)
15
+ if (!sf) continue
16
+ files.push(sf)
17
+ }
18
+
19
+ while (files.length) {
20
+ const sf = files.shift()!
21
+ scan.SourceFile(s, sf, files)
22
+ }
23
+
24
+ return s
25
+ }
26
+
27
+ scan.SourceFile = (s: State, node: ts.SourceFile, queue: ts.SourceFile[]) => {
28
+ if (s.seen.has(node) || !s.include(node)) return
29
+ s.seen.add(node)
30
+ s.parent = s.root
31
+ const f = statement(s, node, 'module', () => ({ path: s.getPath(node) }))
32
+ s.parent = f.id
33
+ node.statements.forEach((stmt) => {
34
+ if (ts.isExportDeclaration(stmt)) return scan.ExportDeclaration(s, stmt, queue)
35
+ if (ts.isExportAssignment(stmt)) return scan.ExportAssignment(s, stmt)
36
+ scan.Statement(s, stmt)
37
+ })
38
+ return
39
+ }
40
+
41
+ scan.Statement = (s: State, node: ts.Statement) => {
42
+ if (ts.isVariableStatement(node)) {
43
+ return node.declarationList.declarations.forEach((d) => scan.VariableDeclaration(s, d))
44
+ }
45
+ if (ts.isVariableDeclaration(node)) return scan.VariableDeclaration(s, node)
46
+ if (ts.isFunctionDeclaration(node)) return scan.FunctionDeclaration(s, node)
47
+ if (ts.isClassDeclaration(node)) return scan.ClassDeclaration(s, node)
48
+ if (ts.isInterfaceDeclaration(node)) return scan.InterfaceDeclaration(s, node)
49
+ if (ts.isTypeAliasDeclaration(node)) return scan.TypeAliasDeclaration(s, node)
50
+ if (ts.isEnumDeclaration(node)) return scan.EnumDeclaration(s, node)
51
+ if (ts.isModuleDeclaration(node)) return scan.ModuleDeclaration(s, node)
52
+ }
53
+
54
+ scan.VariableDeclaration = (s: State, node: ts.VariableDeclaration) => {
55
+ const init = node.initializer
56
+ if (init && (ts.isArrowFunction(init) || ts.isFunctionExpression(init))) {
57
+ return statement(s, node, 'function', () => functionBody(s, init))
58
+ }
59
+ return statement(s, node, 'variable', () => ({
60
+ type: node.type ? scan.Type(s, node.type) : inferAt(s, node),
61
+ defaultValue: node.initializer?.getText(),
62
+ }))
63
+ }
64
+
65
+ scan.FunctionDeclaration = (s: State, decl: ts.FunctionDeclaration) => {
66
+ return statement(s, decl, 'function', () => functionBody(s, decl))
67
+ }
68
+
69
+ scan.ClassDeclaration = (s: State, node: ts.ClassDeclaration) => {
70
+ const constructors: T.Part<'signature'>[] = []
71
+ const properties: T.Part<'property'>[] = []
72
+ const methods: T.Part<'method'>[] = []
73
+ let indexSignature: T.Part<'index-signature'> | undefined
74
+ for (const m of node.members) {
75
+ if (ts.isConstructorDeclaration(m)) constructors.push(signature(s, m))
76
+ else if (ts.isPropertyDeclaration(m) && ts.isIdentifier(m.name)) properties.push(property(s, m))
77
+ else if (ts.isMethodDeclaration(m) && ts.isIdentifier(m.name)) methods.push(method(s, m))
78
+ else if (ts.isIndexSignatureDeclaration(m)) indexSignature = indexSignatureDecl(s, m)
79
+ }
80
+ return statement(s, node, 'class', () => ({
81
+ ...generics(s, node),
82
+ ...heritage(s, node),
83
+ constructors,
84
+ properties,
85
+ methods,
86
+ ...(indexSignature ? { indexSignature } : {}),
87
+ }))
88
+ }
89
+
90
+ scan.InterfaceDeclaration = (s: State, node: ts.InterfaceDeclaration) =>
91
+ statement(s, node, 'interface', () => ({
92
+ ...generics(s, node),
93
+ ...interfaceExtends(s, node),
94
+ ...objectMembers(s, node.members),
95
+ }))
96
+
97
+ scan.TypeAliasDeclaration = (s: State, node: ts.TypeAliasDeclaration) =>
98
+ statement(s, node, 'type-alias', () => ({
99
+ ...generics(s, node),
100
+ type: scan.Type(s, node.type),
101
+ }))
102
+
103
+ scan.EnumDeclaration = (s: State, node: ts.EnumDeclaration) =>
104
+ statement(s, node, 'enum', () => ({
105
+ const: !!node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ConstKeyword),
106
+ members: node.members.map((m) => enumMember(s, m)),
107
+ }))
108
+
109
+ scan.ModuleDeclaration = (s: State, node: ts.ModuleDeclaration) => {
110
+ const ns = statement(s, node, 'namespace', () => ({}))
111
+ const body = node.body
112
+ if (!body) return ns
113
+
114
+ const prev = s.parent
115
+ s.parent = ns.id
116
+ if (ts.isModuleBlock(body)) {
117
+ body.statements.forEach((stmt) => scan.Statement(s, stmt))
118
+ } else if (ts.isModuleDeclaration(body)) {
119
+ // `namespace A.B { … }` → recurse on the inner `B`.
120
+ scan.ModuleDeclaration(s, body)
121
+ }
122
+ s.parent = prev
123
+ return ns
124
+ }
125
+
126
+ scan.ExportDeclaration = (s: State, node: ts.ExportDeclaration, queue: ts.SourceFile[]) => {
127
+ const spec = node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier) ? node.moduleSpecifier.text : undefined
128
+
129
+ // Enqueue the source module so its declarations exist for resolution.
130
+ if (spec) {
131
+ const sym = s.checker.getSymbolAtLocation(node.moduleSpecifier!)
132
+ const decl = sym?.valueDeclaration ?? sym?.declarations?.[0]
133
+ if (decl && ts.isSourceFile(decl) && !s.seen.has(decl) && s.include(decl)) {
134
+ queue.push(decl)
135
+ }
136
+ }
137
+
138
+ // Emit an `export` declaration node (ref filled by resolver).
139
+ const exp = statement(s, node, 'export', () => ({ names: [], star: false }))
140
+ s.exports.push(exp)
141
+
142
+ if (!node.exportClause) {
143
+ if (!spec) return
144
+ s.exportsForm.set(exp.id, 'star')
145
+ s.exportsSpec.set(exp.id, spec)
146
+ s.exportsOrigin.set(exp.id, node)
147
+ exp.star = true
148
+ return
149
+ }
150
+ if (ts.isNamespaceExport(node.exportClause)) {
151
+ if (!spec) return
152
+ s.exportsForm.set(exp.id, 'namespace-from')
153
+ s.exportsSpec.set(exp.id, spec)
154
+ s.exportsAlias.set(exp.id, node.exportClause.name.text)
155
+ s.exportsOrigin.set(exp.id, node)
156
+ return
157
+ }
158
+ const entries = node.exportClause.elements.map((el) => ({
159
+ name: (el.propertyName ?? el.name).text,
160
+ ...(el.propertyName ? { as: el.name.text } : {}),
161
+ }))
162
+ s.exportsForm.set(exp.id, spec ? 'named-from' : 'named-local')
163
+ if (spec) s.exportsSpec.set(exp.id, spec)
164
+ s.exportsEntries.set(exp.id, entries)
165
+ s.exportsOrigin.set(exp.id, node)
166
+ }
167
+
168
+ // `export default <expr>` / `export = <expr>`. The target is resolved later.
169
+ scan.ExportAssignment = (s: State, node: ts.ExportAssignment) => {
170
+ const exp = statement(s, node, 'export', () => ({ names: [], star: false }))
171
+ s.exports.push(exp)
172
+ s.exportsForm.set(exp.id, 'assignment')
173
+ s.exportsOrigin.set(exp.id, node)
174
+ return exp
175
+ }
176
+
177
+ // ---------------- Type Components ----------------
178
+ scan.Type = (s: State, node: ts.TypeNode): T.Type => {
179
+ if (ts.isLiteralTypeNode(node)) return scan.Literal(s, node)
180
+ if (ts.isArrayTypeNode(node)) return scan.Array(s, node)
181
+ if (ts.isTupleTypeNode(node)) return scan.Tuple(s, node)
182
+ if (ts.isUnionTypeNode(node)) return scan.Union(s, node)
183
+ if (ts.isIntersectionTypeNode(node)) return scan.Intersection(s, node)
184
+ if (ts.isTypeOperatorNode(node)) return scan.TypeOperator(s, node)
185
+ if (ts.isFunctionTypeNode(node) || ts.isConstructorTypeNode(node)) return scan.FunctionType(s, node)
186
+ if (ts.isTypeLiteralNode(node)) return scan.Record(s, node)
187
+ if (ts.isParenthesizedTypeNode(node)) return scan.Type(s, node.type)
188
+ if (ts.isConditionalTypeNode(node)) return scan.Conditional(s, node)
189
+ if (ts.isInferTypeNode(node)) return scan.Infer(s, node)
190
+ if (ts.isIndexedAccessTypeNode(node)) return scan.IndexedAccess(s, node)
191
+ if (ts.isMappedTypeNode(node)) return scan.Mapped(s, node)
192
+ if (ts.isTypeQueryNode(node)) return scan.Query(s, node)
193
+ if (ts.isTemplateLiteralTypeNode(node)) return scan.TemplateLiteral(s, node)
194
+ if (ts.isTypePredicateNode(node)) return scan.Predicate(s, node)
195
+ if (ts.isImportTypeNode(node)) return scan.ImportType(s, node)
196
+ const name = INTRINSICS[node.kind]
197
+ if (name) return scan.Intrinsic(s, node, name)
198
+
199
+ if (ts.isTypeReferenceNode(node)) return scan.TypeReference(s, node)
200
+
201
+ return scan.Unknown(s, node)
202
+ }
203
+
204
+ scan.Literal = (s: State, node: ts.LiteralTypeNode): T.Type<'literal'> =>
205
+ type(s, node, 'literal', { value: literalValue(node.literal) })
206
+
207
+ scan.Array = (s: State, node: ts.ArrayTypeNode): T.Type<'array'> =>
208
+ type(s, node, 'array', { elementType: scan.Type(s, node.elementType) })
209
+
210
+ scan.Union = (s: State, node: ts.UnionTypeNode): T.Type<'union'> =>
211
+ type(s, node, 'union', { types: node.types.map((t) => scan.Type(s, t)) })
212
+
213
+ scan.Intersection = (s: State, node: ts.IntersectionTypeNode): T.Type<'intersection'> =>
214
+ type(s, node, 'intersection', { types: node.types.map((t) => scan.Type(s, t)) })
215
+
216
+ scan.Tuple = (s: State, node: ts.TupleTypeNode): T.Type<'tuple'> =>
217
+ type(s, node, 'tuple', { elements: node.elements.map((el) => tupleElement(s, el)) })
218
+
219
+ scan.TypeOperator = (s: State, node: ts.TypeOperatorNode): T.Type<'type-operator'> =>
220
+ type(s, node, 'type-operator', { operator: TYPE_OPERATORS[node.operator]!, target: scan.Type(s, node.type) })
221
+
222
+ scan.FunctionType = (s: State, node: ts.FunctionTypeNode | ts.ConstructorTypeNode): T.Type<'function-type'> =>
223
+ type(s, node, 'function-type', { signatures: [signature(s, node)] })
224
+
225
+ scan.Record = (s: State, node: ts.TypeLiteralNode): T.Type<'record'> =>
226
+ type(s, node, 'record', objectMembers(s, node.members))
227
+
228
+ scan.Conditional = (s: State, node: ts.ConditionalTypeNode): T.Type<'conditional'> =>
229
+ type(s, node, 'conditional', {
230
+ check: scan.Type(s, node.checkType),
231
+ extends: scan.Type(s, node.extendsType),
232
+ true: scan.Type(s, node.trueType),
233
+ false: scan.Type(s, node.falseType),
234
+ })
235
+
236
+ scan.Infer = (s: State, node: ts.InferTypeNode): T.Type<'infer'> =>
237
+ type(s, node, 'infer', {
238
+ name: node.typeParameter.name.text,
239
+ ...(node.typeParameter.constraint ? { constraint: scan.Type(s, node.typeParameter.constraint) } : {}),
240
+ })
241
+
242
+ scan.IndexedAccess = (s: State, node: ts.IndexedAccessTypeNode): T.Type<'indexed-access'> =>
243
+ type(s, node, 'indexed-access', { object: scan.Type(s, node.objectType), index: scan.Type(s, node.indexType) })
244
+
245
+ scan.Mapped = (s: State, node: ts.MappedTypeNode): T.Type<'mapped'> =>
246
+ type(s, node, 'mapped', {
247
+ typeParameter: scan.TypeParam(s, node.typeParameter),
248
+ ...(node.nameType ? { nameType: scan.Type(s, node.nameType) } : {}),
249
+ ...(node.type ? { type: scan.Type(s, node.type) } : {}),
250
+ ...(node.questionToken ? { optional: true } : {}),
251
+ ...(node.readonlyToken ? { readonly: true } : {}),
252
+ })
253
+
254
+ scan.Query = (s: State, node: ts.TypeQueryNode): T.Type<'query'> =>
255
+ type(s, node, 'query', {
256
+ name: node.exprName.getText(),
257
+ ...(node.typeArguments?.length ? { args: node.typeArguments.map((a) => scan.Type(s, a)) } : {}),
258
+ })
259
+
260
+ scan.TemplateLiteral = (s: State, node: ts.TemplateLiteralTypeNode): T.Type<'template-literal'> =>
261
+ type(s, node, 'template-literal', {
262
+ head: node.head.text,
263
+ spans: node.templateSpans.map((sp) => ({ type: scan.Type(s, sp.type), literal: sp.literal.text })),
264
+ })
265
+
266
+ scan.Predicate = (s: State, node: ts.TypePredicateNode): T.Type<'predicate'> =>
267
+ type(s, node, 'predicate', {
268
+ parameter: node.parameterName.getText(),
269
+ ...(node.assertsModifier ? { asserts: true } : {}),
270
+ ...(node.type ? { type: scan.Type(s, node.type) } : {}),
271
+ })
272
+
273
+ scan.ImportType = (s: State, node: ts.ImportTypeNode): T.Type<'import-type'> => {
274
+ const arg = ts.isLiteralTypeNode(node.argument) && ts.isStringLiteral(node.argument.literal)
275
+ ? node.argument.literal.text
276
+ : node.argument.getText()
277
+ return type(s, node, 'import-type', {
278
+ argument: arg,
279
+ ...(node.qualifier ? { qualifier: node.qualifier.getText() } : {}),
280
+ ...(node.isTypeOf ? { isTypeOf: true } : {}),
281
+ ...(node.typeArguments?.length ? { args: node.typeArguments.map((a) => scan.Type(s, a)) } : {}),
282
+ })
283
+ }
284
+
285
+ scan.TypeReference = (s: State, node: ts.TypeReferenceNode): T.Type<'reference'> => {
286
+ const r = type(s, node, 'reference', { type: 'internal', targetId: 0 } as any)
287
+ r.id = s.nextId()
288
+ r.owner = s.currentStmt
289
+ r.name = getName(node) ?? 'unknown'
290
+ if (node.typeArguments?.length) r.args = node.typeArguments.map((a) => scan.Type(s, a))
291
+ s.references.push(r)
292
+ s.referenceOrigins.set(r.id, node)
293
+ return r
294
+ }
295
+
296
+ scan.Unknown = (s: State, node: ts.Node): T.Type<'unknown'> =>
297
+ type(s, node, 'unknown', { text: node.getText(), nodeType: ts.SyntaxKind[node.kind] })
298
+
299
+ scan.Intrinsic = (s: State, node: ts.Node, name: T.IntrinsicName): T.Type => {
300
+ return type(s, node, 'intrinsic', { name })
301
+ }
302
+
303
+ scan.TypeParam = (s: State, node: ts.TypeParameterDeclaration): T.Part<'generic'> => {
304
+ return part(s, node, 'generic', {
305
+ constraint: node.constraint ? scan.Type(s, node.constraint) : undefined,
306
+ default: node.default ? scan.Type(s, node.default) : undefined,
307
+ })
308
+ }
309
+
310
+ // ---------------- Inference ----------------
311
+ /**
312
+ * Infer a declaration's type from the checker when no annotation is present.
313
+ * Builds a structured `Type` for the common shapes (primitives, literals,
314
+ * unions, arrays, named references, object literals) and falls back to the
315
+ * checker's string form for anything more exotic — the hybrid contract.
316
+ */
317
+ const inferAt = (s: State, node: ts.Node): T.Type => fromType(s, node, s.checker.getTypeAtLocation(node), new Set())
318
+
319
+ const inferReturn = (s: State, node: ts.SignatureDeclarationBase): T.Type => {
320
+ const sig = s.checker.getSignatureFromDeclaration(node as ts.SignatureDeclaration)
321
+ return sig ? fromType(s, node, sig.getReturnType(), new Set()) : scan.Intrinsic(s, node, 'unknown')
322
+ }
323
+
324
+ const fromType = (s: State, ctx: ts.Node, type: ts.Type, seen: Set<ts.Type>): T.Type =>
325
+ structured(s, ctx, type, seen) ?? inferredText(s, ctx, type)
326
+
327
+ const inferredText = (s: State, ctx: ts.Node, type: ts.Type): T.Type =>
328
+ inode(s, 'unknown', { text: s.checker.typeToString(type, ctx, ts.TypeFormatFlags.NoTruncation), nodeType: 'inferred' })
329
+
330
+ const structured = (s: State, ctx: ts.Node, type: ts.Type, seen: Set<ts.Type>): T.Type | undefined => {
331
+ const f = type.flags
332
+ // Literals first — their flags never overlap the primitive intrinsics.
333
+ if (f & ts.TypeFlags.StringLiteral) return inode(s, 'literal', { value: (type as ts.StringLiteralType).value })
334
+ if (f & ts.TypeFlags.NumberLiteral) return inode(s, 'literal', { value: (type as ts.NumberLiteralType).value })
335
+ if (f & ts.TypeFlags.BigIntLiteral) {
336
+ const v = (type as ts.BigIntLiteralType).value
337
+ return inode(s, 'literal', { value: BigInt((v.negative ? '-' : '') + v.base10Value) })
338
+ }
339
+ if (f & ts.TypeFlags.BooleanLiteral) return inode(s, 'literal', { value: (type as any).intrinsicName === 'true' })
340
+ const intr = intrinsicName(f)
341
+ if (intr) return inode(s, 'intrinsic', { name: intr })
342
+ // Keep a named alias rather than expanding it inline.
343
+ const alias = type.aliasSymbol
344
+ if (alias && isNamed(alias)) return inferRef(s, alias.getName(), alias, mapArgs(s, ctx, type.aliasTypeArguments, seen))
345
+ if (type.isUnion()) return inode(s, 'union', { types: type.types.map((t) => fromType(s, ctx, t, seen)) })
346
+ if (type.isIntersection()) return inode(s, 'intersection', { types: type.types.map((t) => fromType(s, ctx, t, seen)) })
347
+ return objectType(s, ctx, type, seen)
348
+ }
349
+
350
+ /** Arrays, named references, and anonymous object literals. */
351
+ const objectType = (s: State, ctx: ts.Node, type: ts.Type, seen: Set<ts.Type>): T.Type | undefined => {
352
+ if (!(type.flags & ts.TypeFlags.Object)) return undefined
353
+ const obj = type as ts.ObjectType
354
+ if (obj.objectFlags & ts.ObjectFlags.Reference) {
355
+ const ref = type as ts.TypeReference
356
+ if (ref.target.objectFlags & ts.ObjectFlags.Tuple) return undefined // → string form
357
+ const args = s.checker.getTypeArguments(ref)
358
+ const tname = ref.target.symbol?.getName()
359
+ if ((tname === 'Array' || tname === 'ReadonlyArray') && args.length === 1)
360
+ return inode(s, 'array', { elementType: fromType(s, ctx, args[0]!, seen) })
361
+ const sym = type.getSymbol()
362
+ if (sym && isNamed(sym)) return inferRef(s, sym.getName(), sym, mapArgs(s, ctx, args, seen))
363
+ }
364
+ const sym = type.getSymbol()
365
+ if (sym && isNamed(sym)) return inferRef(s, sym.getName(), sym, undefined)
366
+ // Callable / constructable objects are too rich for a record — defer to text.
367
+ if (type.getCallSignatures().length || type.getConstructSignatures().length) return undefined
368
+ const props = type.getProperties()
369
+ if (!props.length || seen.has(type)) return undefined
370
+ seen.add(type)
371
+ return inode(s, 'record', { properties: props.map((p) => inferProp(s, ctx, p, seen)), methods: [] })
372
+ }
373
+
374
+ const inferProp = (s: State, ctx: ts.Node, sym: ts.Symbol, seen: Set<ts.Type>): T.Part<'property'> => {
375
+ const decl = sym.valueDeclaration ?? sym.declarations?.[0] ?? ctx
376
+ const pt = s.checker.getTypeOfSymbolAtLocation(sym, decl)
377
+ return {
378
+ kind: 'property',
379
+ parent: s.parent,
380
+ sources: [],
381
+ name: sym.getName(),
382
+ type: fromType(s, ctx, pt, seen),
383
+ ...(sym.flags & ts.SymbolFlags.Optional ? { optional: true } : {}),
384
+ } as T.Part<'property'>
385
+ }
386
+
387
+ const inferRef = (s: State, name: string, symbol: ts.Symbol, args?: T.Type[]): T.Type<'reference'> => {
388
+ const r = {
389
+ kind: 'reference',
390
+ parent: s.parent,
391
+ sources: [],
392
+ type: 'internal',
393
+ targetId: 0,
394
+ id: s.nextId(),
395
+ name,
396
+ owner: s.currentStmt,
397
+ ...(args?.length ? { args } : {}),
398
+ } as T.Type<'reference'>
399
+ s.references.push(r)
400
+ s.referenceSymbols.set(r.id, symbol)
401
+ return r
402
+ }
403
+
404
+ const mapArgs = (s: State, ctx: ts.Node, args: readonly ts.Type[] | undefined, seen: Set<ts.Type>): T.Type[] | undefined =>
405
+ args?.length ? args.map((a) => fromType(s, ctx, a, seen)) : undefined
406
+
407
+ /** A symbol that should render as a clickable name rather than an expanded shape. */
408
+ const isNamed = (sym: ts.Symbol): boolean => {
409
+ if (sym.flags & ts.SymbolFlags.TypeParameter) return false
410
+ const n = sym.getName()
411
+ return !!n && !n.startsWith('__')
412
+ }
413
+
414
+ const inode = <K extends keyof T.TypeMap>(
415
+ s: State,
416
+ kind: K,
417
+ fields: Omit<T.TypeMap[K], keyof T.Typebase | 'kind'>,
418
+ ): T.Type<K> => ({ kind, parent: s.parent, sources: [], ...fields }) as unknown as T.Type<K>
419
+
420
+ const intrinsicName = (f: ts.TypeFlags): T.IntrinsicName | undefined => {
421
+ if (f & ts.TypeFlags.String) return 'string'
422
+ if (f & ts.TypeFlags.Number) return 'number'
423
+ if (f & ts.TypeFlags.Boolean) return 'boolean'
424
+ if (f & ts.TypeFlags.BigInt) return 'bigint'
425
+ if (f & (ts.TypeFlags.ESSymbol | ts.TypeFlags.UniqueESSymbol)) return 'symbol'
426
+ if (f & ts.TypeFlags.Void) return 'void'
427
+ if (f & ts.TypeFlags.Undefined) return 'undefined'
428
+ if (f & ts.TypeFlags.Null) return 'null'
429
+ if (f & ts.TypeFlags.Never) return 'never'
430
+ if (f & ts.TypeFlags.Any) return 'any'
431
+ if (f & ts.TypeFlags.Unknown) return 'unknown'
432
+ if (f & ts.TypeFlags.NonPrimitive) return 'object'
433
+ return undefined
434
+ }
435
+
436
+ // ---------------- Type Components ----------------
437
+ const signature = (s: State, node: ts.SignatureDeclarationBase): T.Part<'signature'> =>
438
+ part(s, node, 'signature', {
439
+ ...(node.typeParameters ? { generics: node.typeParameters.map((tp) => scan.TypeParam(s, tp)) } : {}),
440
+ params: node.parameters.map((p) => parameter(s, p)),
441
+ return: node.type ? scan.Type(s, node.type) : inferReturn(s, node),
442
+ })
443
+
444
+ const parameter = (b: State, node: ts.ParameterDeclaration): T.Part<'parameter'> =>
445
+ part(b, node, 'parameter', {
446
+ type: node.type ? scan.Type(b, node.type) : inferAt(b, node),
447
+ optional: !!node.questionToken || !!node.initializer,
448
+ ...(node.dotDotDotToken ? { rest: true } : {}),
449
+ ...(node.initializer ? { default: node.initializer.getText() } : {}),
450
+ })
451
+
452
+ const functionBody = (s: State, node: ts.SignatureDeclarationBase): T.DeclerationDefinitions['function'] => ({
453
+ signatures: [signature(s, node)],
454
+ })
455
+
456
+ const commentForNode = (b: State, node: ts.Node): T.Comment | undefined => {
457
+ const all = ts.getJSDocCommentsAndTags(node)
458
+ if (!all.length) return undefined
459
+ const parts: T.CommentPart[] = []
460
+ const tags: T.CommentTag[] = []
461
+ let seenBlock = false
462
+ for (const doc of all) {
463
+ if (!ts.isJSDoc(doc)) continue
464
+ seenBlock = true
465
+ appendCommentBody(doc.comment, parts)
466
+ if (doc.tags)
467
+ for (const t of doc.tags) {
468
+ const tag = buildTag(b, t)
469
+ if (tag.tag === '@module') return undefined
470
+ tags.push(tag)
471
+ }
472
+ }
473
+ if (!seenBlock) return undefined
474
+ return { parts, ...(tags.length ? { tags } : {}) }
475
+ }
476
+ /** Flatten a JSDoc comment into `parts`. */
477
+ const appendCommentBody = (
478
+ comment: string | ts.NodeArray<ts.JSDocComment> | undefined,
479
+ parts: T.CommentPart[],
480
+ ): void => {
481
+ if (!comment) return
482
+ if (typeof comment === 'string') {
483
+ const trimmed = comment.trim()
484
+ if (trimmed) parts.push({ kind: 'text', text: trimmed })
485
+ return
486
+ }
487
+ for (const c of comment) {
488
+ if (c.kind === ts.SyntaxKind.JSDocText) {
489
+ parts.push({ kind: 'text', text: c.text })
490
+ continue
491
+ }
492
+ const target = c.name?.getText() ?? ''
493
+ const linkText = c.text || undefined
494
+ const style = ts.isJSDocLinkCode(c) ? ('code' as const) : ts.isJSDocLinkPlain(c) ? ('plain' as const) : undefined
495
+ parts.push({ kind: 'link', target, ...(linkText ? { text: linkText } : {}), ...(style ? { style } : {}) })
496
+ }
497
+ }
498
+ const buildTag = (s: State, tag: ts.JSDocTag): T.CommentTag => {
499
+ const text = ts.getTextOfJSDocComment(tag.comment)?.trim() ?? ''
500
+ const exprType = (te?: ts.JSDocTypeExpression) => (te ? scan.Type(s, te.type) : undefined)
501
+ if (ts.isJSDocPropertyTag(tag)) {
502
+ return {
503
+ tag: '@property',
504
+ name: tag.name.getText(),
505
+ type: exprType(tag.typeExpression),
506
+ text,
507
+ }
508
+ }
509
+ if (ts.isJSDocParameterTag(tag)) {
510
+ return {
511
+ tag: '@param',
512
+ name: tag.name.getText(),
513
+ type: exprType(tag.typeExpression),
514
+ ...(tag.isBracketed ? { optional: true } : {}),
515
+ text,
516
+ }
517
+ }
518
+ if (ts.isJSDocReturnTag(tag)) {
519
+ const type = exprType(tag.typeExpression)
520
+ return { tag: '@returns', ...(type ? { type } : {}), text }
521
+ }
522
+ if (ts.isJSDocThrowsTag(tag)) {
523
+ const type = exprType(tag.typeExpression)
524
+ return { tag: '@throws', ...(type ? { type } : {}), text }
525
+ }
526
+ if (ts.isJSDocTypeTag(tag)) return { tag: '@type', type: exprType(tag.typeExpression)!, text }
527
+ if (ts.isJSDocSatisfiesTag(tag)) return { tag: '@satisfies', type: exprType(tag.typeExpression)!, text }
528
+ if (ts.isJSDocTemplateTag(tag)) {
529
+ return { tag: '@template', generics: tag.typeParameters.map((tp) => scan.TypeParam(s, tp)), text }
530
+ }
531
+ if (ts.isJSDocSeeTag(tag)) {
532
+ return { tag: '@see', ...(tag.name ? { target: tag.name.name.getText() } : {}), text }
533
+ }
534
+ if (ts.isJSDocAugmentsTag(tag)) return { tag: '@augments', class: scan.Type(s, tag.class), text }
535
+ if (ts.isJSDocImplementsTag(tag)) return { tag: '@implements', class: scan.Type(s, tag.class), text }
536
+ const name = '@' + tag.tagName.text
537
+ // `@example` carries semantic indentation; re-extract from source so the
538
+ // leader-strip never eats author tabs (see `rawTagBody`).
539
+ if (name === '@example') return parseExample(rawTagBody(tag))
540
+ return { tag: name, text }
541
+ }
542
+ /**
543
+ * Reconstruct the body of a JSDoc tag from source, stripping the per-line
544
+ * `*` leader and at most one *space* of separator. Unlike
545
+ * `ts.getTextOfJSDocComment` — which strips `[ \t]?` and so eats a single
546
+ * tab of user indentation — this preserves tabs intact.
547
+ */
548
+ const rawTagBody = (tag: ts.JSDocTag): string => {
549
+ const src = tag.getSourceFile().text
550
+ // Body starts immediately after the tag name (`@example`), runs to tag end.
551
+ const raw = src.slice(tag.tagName.end, tag.end)
552
+ return raw
553
+ .split('\n')
554
+ .map((line, i) => (i === 0 ? line : line.replace(/^[ \t]*\*( ?)/, '')))
555
+ .join('\n')
556
+ .trim()
557
+ }
558
+ /**
559
+ * Pull an optional caption out of an `@example` body. Two forms are recognised:
560
+ * 1. Legacy JSDoc: `<caption>…</caption>` prefix.
561
+ * 2. TypeDoc-style: any text on the line(s) before the first fenced code
562
+ * block becomes the caption; the fence and its body become the code.
563
+ * When neither pattern matches, the entire body is treated as `code`.
564
+ */
565
+ const parseExample = (raw: string): T.CommentTagMap['@example'] => {
566
+ const html = raw.match(/^<caption>([\s\S]*?)<\/caption>\s*([\s\S]*)$/)
567
+ if (html) return { tag: '@example', caption: html[1]!.trim(), code: html[2]!.trim() }
568
+ const fence = raw.search(/^```/m)
569
+ if (fence > 0) {
570
+ const caption = raw.slice(0, fence).trim()
571
+ if (caption) return { tag: '@example', caption, code: raw.slice(fence).trim() }
572
+ }
573
+ return { tag: '@example', code: raw.trim() }
574
+ }
575
+ export const commentForModule = (s: State, sf: ts.SourceFile): T.Comment | undefined => {
576
+ if (sf.statements.length === 0) return undefined
577
+ // 1. Target the leading comment ranges for the first statement per your rules
578
+ const sourceText = sf.getFullText()
579
+ const commentRanges = ts.getLeadingCommentRanges(sourceText, sf.statements[0]!.pos)
580
+ if (!commentRanges || commentRanges.length === 0) return undefined
581
+ const parts: T.CommentPart[] = []
582
+ const tags: T.CommentTag[] = []
583
+ let seenBlock = false
584
+ // 2. Evaluate each comment text range
585
+ for (let i = 0; i < commentRanges.length; i++) {
586
+ const range = commentRanges[i]!
587
+ const commentText = sourceText.slice(range.pos, range.end)
588
+ // Apply your specific layout logic
589
+ const isModuleComment = i < commentRanges.length - 1 || commentText.includes('@module')
590
+ if (isModuleComment) {
591
+ // 3. Trick the compiler into parsing the raw text snippet back into an AST Node block
592
+ // We append an empty statement (;) so the parser attaches the JSDoc to a valid target.
593
+ const dummyFile = ts.createSourceFile(
594
+ 'dummy.ts',
595
+ `${commentText}\n;`,
596
+ ts.ScriptTarget.Latest,
597
+ true, // Set parent pointers to true
598
+ )
599
+ // 4. Safely extract the compiled JSDoc node from the dummy file
600
+ const dummyStmt = dummyFile.statements[0]
601
+ if (dummyStmt) {
602
+ const jsdocBlocks = ts.getJSDocCommentsAndTags(dummyStmt)
603
+ const matchingBlock = jsdocBlocks.find(ts.isJSDoc) as ts.JSDoc | undefined
604
+ if (matchingBlock) {
605
+ seenBlock = true
606
+ // Feed the generated AST structure down your pipeline seamlessly
607
+ appendCommentBody(matchingBlock.comment, parts)
608
+ if (matchingBlock.tags) {
609
+ for (const t of matchingBlock.tags) {
610
+ tags.push(buildTag(s, t))
611
+ }
612
+ }
613
+ }
614
+ }
615
+ }
616
+ }
617
+ if (!seenBlock) return undefined
618
+ return { parts, ...(tags.length ? { tags } : {}) }
619
+ }
620
+
621
+ const statement = <K extends keyof T.DeclarationMap>(
622
+ s: State,
623
+ node: ts.Node,
624
+ kind: K,
625
+ fields: () => Omit<T.DeclarationMap[K], keyof T.Base | 'kind'> & Partial<T.Base>,
626
+ ): T.Declaration<K> => {
627
+ const b = base(s, node)
628
+ s.currentStmt = b.id
629
+ Object.assign(b, fields(), { kind })
630
+ s.declarations.push(b as any)
631
+ return b as any
632
+ }
633
+
634
+ const type = <K extends keyof T.TypeMap>(
635
+ s: State,
636
+ node: ts.Node,
637
+ kind: K,
638
+ fields: Omit<T.TypeMap[K], keyof T.Base | 'kind'> & Partial<T.Base>,
639
+ ): T.Type<K> => {
640
+ const nd = typeBase(s, node) as T.Type
641
+ Object.assign(nd, { kind }, fields)
642
+ return nd as any
643
+ }
644
+
645
+ const part = <K extends keyof T.PartMap>(
646
+ s: State,
647
+ node: ts.Node,
648
+ kind: K,
649
+ fields: Omit<T.PartMap[K], 'kind' | 'name' | keyof T.Typebase> & { name?: string },
650
+ ): T.Part<K> => {
651
+ const nd = typeBase(s, node) as T.Typebase & { kind?: string; name?: string }
652
+ Object.assign(nd, { kind }, fields)
653
+ if (nd.name === undefined) {
654
+ const n = getName(node)
655
+ if (n !== undefined) nd.name = n
656
+ }
657
+ return nd as any
658
+ }
659
+ const base = (s: State, node: ts.Node): T.Base => {
660
+ const result: T.Base = typeBase(s, node) as any
661
+ result.id = s.nextId()
662
+ result.name = getName(node) ?? 'unknown'
663
+ result.exported = isExported(node)
664
+
665
+ const named = (node as { name?: ts.Node }).name
666
+ const sym = s.checker.getSymbolAtLocation(named ?? node)
667
+ if (sym) s.symbolsById.set(result.id, sym)
668
+
669
+ return result
670
+ }
671
+
672
+ const typeBase = (s: State, node: ts.Node): T.Typebase => {
673
+ const result: T.Typebase = { parent: s.parent, sources: [] } as T.Typebase
674
+
675
+ const named = (node as { name?: ts.Node }).name
676
+ const sym = s.checker.getSymbolAtLocation(named ?? node)
677
+ if (sym?.declarations?.length) result.sources = sym.declarations!.map((d) => sourceOf(s, d))
678
+ else result.sources = [sourceOf(s, node)]
679
+
680
+ const comment = ts.isSourceFile(node) ? commentForModule(s, node) : commentForNode(s, node)
681
+ if (comment) result.comment = comment
682
+
683
+ return result
684
+ }
685
+
686
+ const sourceOf = (s: State, node: ts.Node): T.Source => {
687
+ const sf = node.getSourceFile()
688
+ const { line, character } = sf.getLineAndCharacterOfPosition(node.getStart())
689
+ return { file: s.getPath(sf), line: line + 1, column: character + 1 }
690
+ }
691
+
692
+ // ---------------- Utilities ----------------
693
+ export const isExported = (node: ts.Node): boolean => {
694
+ if (ts.isExportDeclaration(node) || ts.isExportAssignment(node)) return true
695
+ // `export const x` carries the modifier on the enclosing `VariableStatement`.
696
+ if (ts.isVariableDeclaration(node)) {
697
+ const stmt = node.parent?.parent
698
+ return !!stmt && ts.isVariableStatement(stmt) && isExported(stmt)
699
+ }
700
+ const mods = (node as { modifiers?: ts.NodeArray<ts.ModifierLike> }).modifiers
701
+ return !!mods?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)
702
+ }
703
+
704
+ export const getName = (node: ts.Node): string | undefined => {
705
+ if (ts.isTypeReferenceNode(node)) return node.typeName.getText()
706
+ if (ts.isExpressionWithTypeArguments(node)) return node.expression.getText()
707
+ if (ts.isTypeQueryNode(node)) return node.exprName.getText()
708
+ if (ts.isDeclarationStatement(node)) return ts.getNameOfDeclaration(node)?.getText()
709
+ if (ts.isExpression(node)) return ts.getNameOfDeclaration(node)?.getText()
710
+ if ((node as { name?: ts.Node }).name) return (node as { name?: ts.Node }).name!.getText()
711
+ return undefined
712
+ }
713
+
714
+ const property = (s: State, node: ts.PropertyDeclaration | ts.PropertySignature): T.Part<'property'> =>
715
+ part(s, node, 'property', {
716
+ type: node.type ? scan.Type(s, node.type) : inferAt(s, node),
717
+ ...(node.questionToken ? { optional: true } : {}),
718
+ ...('initializer' in node && node.initializer ? { defaultValue: node.initializer.getText() } : {}),
719
+ })
720
+
721
+ const method = (s: State, node: ts.MethodDeclaration | ts.MethodSignature): T.Part<'method'> =>
722
+ part(s, node, 'method', { signatures: [signature(s, node)] })
723
+
724
+ const indexSignatureDecl = (s: State, node: ts.IndexSignatureDeclaration): T.Part<'index-signature'> =>
725
+ part(s, node, 'index-signature', {
726
+ parameter: parameter(s, node.parameters[0]!),
727
+ type: node.type ? scan.Type(s, node.type) : scan.Intrinsic(s, node, 'unknown'),
728
+ })
729
+
730
+ const enumMember = (s: State, node: ts.EnumMember): T.Part<'enum-member'> => {
731
+ const value = s.checker.getConstantValue(node)
732
+ return part(s, node, 'enum-member', { ...(value !== undefined ? { value } : {}) })
733
+ }
734
+
735
+ const generics = (s: State, node: { typeParameters?: ts.NodeArray<ts.TypeParameterDeclaration> }) =>
736
+ node.typeParameters?.length ? { generics: node.typeParameters.map((tp) => scan.TypeParam(s, tp)) } : {}
737
+
738
+ const heritage = (s: State, node: ts.ClassDeclaration): { extends?: T.Type[]; implements?: T.Type[] } => {
739
+ const out: { extends?: T.Type[]; implements?: T.Type[] } = {}
740
+ for (const h of node.heritageClauses ?? []) {
741
+ const types = h.types.map((t) => scan.Type(s, t))
742
+ if (h.token === ts.SyntaxKind.ExtendsKeyword) out.extends = types
743
+ else out.implements = types
744
+ }
745
+ return out
746
+ }
747
+
748
+ const interfaceExtends = (s: State, node: ts.InterfaceDeclaration): { extends?: T.Type[] } => {
749
+ const ext = node.heritageClauses?.flatMap((h) => h.types).map((t) => scan.Type(s, t))
750
+ return ext?.length ? { extends: ext } : {}
751
+ }
752
+
753
+ const objectMembers = (s: State, members: ts.NodeArray<ts.TypeElement>) => {
754
+ const properties: T.Part<'property'>[] = []
755
+ const methods: T.Part<'method'>[] = []
756
+ const callSignatures: T.Part<'signature'>[] = []
757
+ const constructSignatures: T.Part<'signature'>[] = []
758
+ let indexSignature: T.Part<'index-signature'> | undefined
759
+ for (const m of members) {
760
+ if (ts.isPropertySignature(m) && ts.isIdentifier(m.name)) properties.push(property(s, m))
761
+ else if (ts.isMethodSignature(m) && ts.isIdentifier(m.name)) methods.push(method(s, m))
762
+ else if (ts.isCallSignatureDeclaration(m)) callSignatures.push(signature(s, m))
763
+ else if (ts.isConstructSignatureDeclaration(m)) constructSignatures.push(signature(s, m))
764
+ else if (ts.isIndexSignatureDeclaration(m)) indexSignature = indexSignatureDecl(s, m)
765
+ }
766
+ return {
767
+ properties,
768
+ methods,
769
+ ...(callSignatures.length ? { callSignatures } : {}),
770
+ ...(constructSignatures.length ? { constructSignatures } : {}),
771
+ ...(indexSignature ? { indexSignature } : {}),
772
+ }
773
+ }
774
+
775
+ const literalValue = (lit: ts.Node): T.Type<'literal'>['value'] => {
776
+ if (lit.kind === ts.SyntaxKind.NullKeyword) return null
777
+ if (ts.isStringLiteral(lit)) return lit.text
778
+ if (ts.isNumericLiteral(lit)) return Number(lit.text)
779
+ if (lit.kind === ts.SyntaxKind.TrueKeyword) return true
780
+ if (lit.kind === ts.SyntaxKind.FalseKeyword) return false
781
+ if (ts.isBigIntLiteral(lit)) return BigInt(lit.text.replace(/n$/, ''))
782
+ return lit.getText()
783
+ }
784
+
785
+ const tupleElement = (s: State, el: ts.TypeNode): T.Part<'tuple-element'> => {
786
+ if (ts.isNamedTupleMember(el))
787
+ return part(s, el, 'tuple-element', {
788
+ type: scan.Type(s, el.type),
789
+ ...(el.questionToken ? { optional: true } : {}),
790
+ ...(el.dotDotDotToken ? { rest: true } : {}),
791
+ })
792
+ if (ts.isOptionalTypeNode(el)) return part(s, el, 'tuple-element', { type: scan.Type(s, el.type), optional: true })
793
+ if (ts.isRestTypeNode(el)) return part(s, el, 'tuple-element', { type: scan.Type(s, el.type), rest: true })
794
+ return part(s, el, 'tuple-element', { type: scan.Type(s, el) })
795
+ }
796
+
797
+ const INTRINSICS: Partial<Record<ts.SyntaxKind, T.IntrinsicName>> = {
798
+ [ts.SyntaxKind.StringKeyword]: 'string',
799
+ [ts.SyntaxKind.NumberKeyword]: 'number',
800
+ [ts.SyntaxKind.BooleanKeyword]: 'boolean',
801
+ [ts.SyntaxKind.BigIntKeyword]: 'bigint',
802
+ [ts.SyntaxKind.SymbolKeyword]: 'symbol',
803
+ [ts.SyntaxKind.VoidKeyword]: 'void',
804
+ [ts.SyntaxKind.UndefinedKeyword]: 'undefined',
805
+ [ts.SyntaxKind.NeverKeyword]: 'never',
806
+ [ts.SyntaxKind.AnyKeyword]: 'any',
807
+ [ts.SyntaxKind.UnknownKeyword]: 'unknown',
808
+ [ts.SyntaxKind.ObjectKeyword]: 'object',
809
+ [ts.SyntaxKind.ThisType]: 'this',
810
+ }
811
+
812
+ const TYPE_OPERATORS: Partial<Record<ts.SyntaxKind, 'keyof' | 'readonly' | 'unique'>> = {
813
+ [ts.SyntaxKind.KeyOfKeyword]: 'keyof',
814
+ [ts.SyntaxKind.ReadonlyKeyword]: 'readonly',
815
+ [ts.SyntaxKind.UniqueKeyword]: 'unique',
816
+ }