polen 0.9.1-next.2 → 0.10.0-next.10

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 (460) hide show
  1. package/README.md +49 -364
  2. package/build/api/api.d.ts +1 -0
  3. package/build/api/api.d.ts.map +1 -1
  4. package/build/api/api.js +1 -0
  5. package/build/api/api.js.map +1 -1
  6. package/build/api/config/configurator.d.ts +9 -1
  7. package/build/api/config/configurator.d.ts.map +1 -1
  8. package/build/api/config/configurator.js +18 -6
  9. package/build/api/config/configurator.js.map +1 -1
  10. package/build/api/config/load.js +5 -5
  11. package/build/api/config/load.js.map +1 -1
  12. package/build/api/config-resolver/resolve.js +2 -2
  13. package/build/api/config-resolver/resolve.js.map +1 -1
  14. package/build/api/content/$$.d.ts +7 -0
  15. package/build/api/content/$$.d.ts.map +1 -0
  16. package/build/api/content/$$.js +7 -0
  17. package/build/api/content/$$.js.map +1 -0
  18. package/build/api/content/$.d.ts +2 -0
  19. package/build/api/content/$.d.ts.map +1 -0
  20. package/build/api/content/$.js +2 -0
  21. package/build/api/content/$.js.map +1 -0
  22. package/build/api/content/metadata.d.ts +10 -0
  23. package/build/api/content/metadata.d.ts.map +1 -0
  24. package/build/api/content/metadata.js +9 -0
  25. package/build/api/content/metadata.js.map +1 -0
  26. package/build/api/content/navbar.d.ts +10 -0
  27. package/build/api/content/navbar.d.ts.map +1 -0
  28. package/build/api/content/navbar.js +45 -0
  29. package/build/api/content/navbar.js.map +1 -0
  30. package/build/api/content/page.d.ts +11 -0
  31. package/build/api/content/page.d.ts.map +1 -0
  32. package/build/api/content/page.js +2 -0
  33. package/build/api/content/page.js.map +1 -0
  34. package/build/api/content/scan.d.ts +19 -0
  35. package/build/api/content/scan.d.ts.map +1 -0
  36. package/build/api/content/scan.js +90 -0
  37. package/build/api/content/scan.js.map +1 -0
  38. package/build/api/content/sidebar.d.ts +104 -0
  39. package/build/api/content/sidebar.d.ts.map +1 -0
  40. package/build/api/content/sidebar.js +166 -0
  41. package/build/api/content/sidebar.js.map +1 -0
  42. package/build/api/content/utils.d.ts +5 -0
  43. package/build/api/content/utils.d.ts.map +1 -0
  44. package/build/api/content/utils.js +8 -0
  45. package/build/api/content/utils.js.map +1 -0
  46. package/build/api/schema/data-sources/schema-directory/schema-directory.js +1 -1
  47. package/build/api/schema/data-sources/schema-directory/schema-directory.js.map +1 -1
  48. package/build/api/static/index.d.ts +2 -0
  49. package/build/api/static/index.d.ts.map +1 -0
  50. package/build/api/static/index.js +2 -0
  51. package/build/api/static/index.js.map +1 -0
  52. package/build/api/static/manifest.d.ts +18 -0
  53. package/build/api/static/manifest.d.ts.map +1 -0
  54. package/build/api/static/manifest.js +13 -0
  55. package/build/api/static/manifest.js.map +1 -0
  56. package/build/api/static/rebase.d.ts +14 -0
  57. package/build/api/static/rebase.d.ts.map +1 -0
  58. package/build/api/static/rebase.js +110 -0
  59. package/build/api/static/rebase.js.map +1 -0
  60. package/build/api/static/static.d.ts +3 -0
  61. package/build/api/static/static.d.ts.map +1 -0
  62. package/build/api/static/static.js +3 -0
  63. package/build/api/static/static.js.map +1 -0
  64. package/build/api/vite/plugins/branding/index.d.ts +4 -0
  65. package/build/api/vite/plugins/branding/index.d.ts.map +1 -0
  66. package/build/api/vite/plugins/branding/index.js +80 -0
  67. package/build/api/vite/plugins/branding/index.js.map +1 -0
  68. package/build/api/vite/plugins/build.d.ts.map +1 -1
  69. package/build/api/vite/plugins/build.js +22 -1
  70. package/build/api/vite/plugins/build.js.map +1 -1
  71. package/build/api/vite/plugins/core.d.ts +2 -2
  72. package/build/api/vite/plugins/core.d.ts.map +1 -1
  73. package/build/api/vite/plugins/core.js +4 -5
  74. package/build/api/vite/plugins/core.js.map +1 -1
  75. package/build/api/vite/plugins/main.d.ts.map +1 -1
  76. package/build/api/vite/plugins/main.js +2 -1
  77. package/build/api/vite/plugins/main.js.map +1 -1
  78. package/build/api/vite/plugins/pages.d.ts +8 -14
  79. package/build/api/vite/plugins/pages.d.ts.map +1 -1
  80. package/build/api/vite/plugins/pages.js +110 -183
  81. package/build/api/vite/plugins/pages.js.map +1 -1
  82. package/build/api/vite/plugins/serve.js +5 -5
  83. package/build/api/vite/plugins/serve.js.map +1 -1
  84. package/build/cli/_/self-contained-mode.js +5 -5
  85. package/build/cli/_/self-contained-mode.js.map +1 -1
  86. package/build/cli/commands/static/$default.d.ts +3 -0
  87. package/build/cli/commands/static/$default.d.ts.map +1 -0
  88. package/build/cli/commands/static/$default.js +38 -0
  89. package/build/cli/commands/static/$default.js.map +1 -0
  90. package/build/cli/commands/static/rebase.d.ts +2 -0
  91. package/build/cli/commands/static/rebase.d.ts.map +1 -0
  92. package/build/cli/commands/static/rebase.js +26 -0
  93. package/build/cli/commands/static/rebase.js.map +1 -0
  94. package/build/cli/commands/static.d.ts +3 -0
  95. package/build/cli/commands/static.d.ts.map +1 -0
  96. package/build/cli/commands/static.js +5 -0
  97. package/build/cli/commands/static.js.map +1 -0
  98. package/build/exports/components.d.ts +2 -0
  99. package/build/exports/components.d.ts.map +1 -0
  100. package/build/exports/components.js +2 -0
  101. package/build/exports/components.js.map +1 -0
  102. package/build/lib/demos/builder.d.ts +83 -0
  103. package/build/lib/demos/builder.d.ts.map +1 -0
  104. package/build/lib/demos/builder.js +237 -0
  105. package/build/lib/demos/builder.js.map +1 -0
  106. package/build/lib/demos/config-schema.d.ts +243 -0
  107. package/build/lib/demos/config-schema.d.ts.map +1 -0
  108. package/build/lib/demos/config-schema.js +52 -0
  109. package/build/lib/demos/config-schema.js.map +1 -0
  110. package/build/lib/demos/config.d.ts +40 -0
  111. package/build/lib/demos/config.d.ts.map +1 -0
  112. package/build/lib/demos/config.js +180 -0
  113. package/build/lib/demos/config.js.map +1 -0
  114. package/build/lib/demos/index.d.ts +9 -0
  115. package/build/lib/demos/index.d.ts.map +1 -0
  116. package/build/lib/demos/index.js +8 -0
  117. package/build/lib/demos/index.js.map +1 -0
  118. package/build/lib/demos/ui/components.d.ts +33 -0
  119. package/build/lib/demos/ui/components.d.ts.map +1 -0
  120. package/build/lib/demos/ui/components.js +699 -0
  121. package/build/lib/demos/ui/components.js.map +1 -0
  122. package/build/lib/demos/ui/data-collector.d.ts +88 -0
  123. package/build/lib/demos/ui/data-collector.d.ts.map +1 -0
  124. package/build/lib/demos/ui/data-collector.js +174 -0
  125. package/build/lib/demos/ui/data-collector.js.map +1 -0
  126. package/build/lib/demos/ui/landing-page-cli.d.ts +3 -0
  127. package/build/lib/demos/ui/landing-page-cli.d.ts.map +1 -0
  128. package/build/lib/demos/ui/landing-page-cli.js +21 -0
  129. package/build/lib/demos/ui/landing-page-cli.js.map +1 -0
  130. package/build/lib/demos/ui/landing-page.d.ts +32 -0
  131. package/build/lib/demos/ui/landing-page.d.ts.map +1 -0
  132. package/build/lib/demos/ui/landing-page.js +83 -0
  133. package/build/lib/demos/ui/landing-page.js.map +1 -0
  134. package/build/lib/demos/ui/page-renderer.d.ts +26 -0
  135. package/build/lib/demos/ui/page-renderer.d.ts.map +1 -0
  136. package/build/lib/demos/ui/page-renderer.js +104 -0
  137. package/build/lib/demos/ui/page-renderer.js.map +1 -0
  138. package/build/lib/demos/utils.d.ts +14 -0
  139. package/build/lib/demos/utils.d.ts.map +1 -0
  140. package/build/lib/demos/utils.js +37 -0
  141. package/build/lib/demos/utils.js.map +1 -0
  142. package/build/lib/deployment/$$.d.ts +3 -0
  143. package/build/lib/deployment/$$.d.ts.map +1 -0
  144. package/build/lib/deployment/$$.js +3 -0
  145. package/build/lib/deployment/$$.js.map +1 -0
  146. package/build/lib/deployment/$.d.ts +2 -0
  147. package/build/lib/deployment/$.d.ts.map +1 -0
  148. package/build/lib/deployment/$.js +2 -0
  149. package/build/lib/deployment/$.js.map +1 -0
  150. package/build/lib/deployment/metadata.d.ts +32 -0
  151. package/build/lib/deployment/metadata.d.ts.map +1 -0
  152. package/build/lib/deployment/metadata.js +37 -0
  153. package/build/lib/deployment/metadata.js.map +1 -0
  154. package/build/lib/deployment/path-manager.d.ts +41 -0
  155. package/build/lib/deployment/path-manager.d.ts.map +1 -0
  156. package/build/lib/deployment/path-manager.js +157 -0
  157. package/build/lib/deployment/path-manager.js.map +1 -0
  158. package/build/lib/file-router/file-router.d.ts +0 -2
  159. package/build/lib/file-router/file-router.d.ts.map +1 -1
  160. package/build/lib/file-router/file-router.js +0 -2
  161. package/build/lib/file-router/file-router.js.map +1 -1
  162. package/build/lib/file-router/route.d.ts +2 -0
  163. package/build/lib/file-router/route.d.ts.map +1 -1
  164. package/build/lib/file-router/route.js.map +1 -1
  165. package/build/lib/file-router/scan.d.ts.map +1 -1
  166. package/build/lib/file-router/scan.js +22 -13
  167. package/build/lib/file-router/scan.js.map +1 -1
  168. package/build/lib/github-actions/git-controller.d.ts +50 -0
  169. package/build/lib/github-actions/git-controller.d.ts.map +1 -0
  170. package/build/lib/github-actions/git-controller.js +90 -0
  171. package/build/lib/github-actions/git-controller.js.map +1 -0
  172. package/build/lib/github-actions/github-actions.d.ts +7 -0
  173. package/build/lib/github-actions/github-actions.d.ts.map +1 -0
  174. package/build/lib/github-actions/github-actions.js +7 -0
  175. package/build/lib/github-actions/github-actions.js.map +1 -0
  176. package/build/lib/github-actions/index.d.ts +2 -0
  177. package/build/lib/github-actions/index.d.ts.map +1 -0
  178. package/build/lib/github-actions/index.js +2 -0
  179. package/build/lib/github-actions/index.js.map +1 -0
  180. package/build/lib/github-actions/lib/get-pr-deployments.d.ts +12 -0
  181. package/build/lib/github-actions/lib/get-pr-deployments.d.ts.map +1 -0
  182. package/build/lib/github-actions/lib/get-pr-deployments.js +51 -0
  183. package/build/lib/github-actions/lib/get-pr-deployments.js.map +1 -0
  184. package/build/lib/github-actions/pr-controller.d.ts +39 -0
  185. package/build/lib/github-actions/pr-controller.d.ts.map +1 -0
  186. package/build/lib/github-actions/pr-controller.js +122 -0
  187. package/build/lib/github-actions/pr-controller.js.map +1 -0
  188. package/build/lib/github-actions/run-step-cli.d.ts +9 -0
  189. package/build/lib/github-actions/run-step-cli.d.ts.map +1 -0
  190. package/build/lib/github-actions/run-step-cli.js +71 -0
  191. package/build/lib/github-actions/run-step-cli.js.map +1 -0
  192. package/build/lib/github-actions/runner.d.ts +17 -0
  193. package/build/lib/github-actions/runner.d.ts.map +1 -0
  194. package/build/lib/github-actions/runner.js +195 -0
  195. package/build/lib/github-actions/runner.js.map +1 -0
  196. package/build/lib/github-actions/schemas/context.d.ts +933 -0
  197. package/build/lib/github-actions/schemas/context.d.ts.map +1 -0
  198. package/build/lib/github-actions/schemas/context.js +407 -0
  199. package/build/lib/github-actions/schemas/context.js.map +1 -0
  200. package/build/lib/github-actions/schemas/index.d.ts +5 -0
  201. package/build/lib/github-actions/schemas/index.d.ts.map +1 -0
  202. package/build/lib/github-actions/schemas/index.js +5 -0
  203. package/build/lib/github-actions/schemas/index.js.map +1 -0
  204. package/build/lib/github-actions/search-module.d.ts +38 -0
  205. package/build/lib/github-actions/search-module.d.ts.map +1 -0
  206. package/build/lib/github-actions/search-module.js +40 -0
  207. package/build/lib/github-actions/search-module.js.map +1 -0
  208. package/build/lib/github-actions/step.d.ts +163 -0
  209. package/build/lib/github-actions/step.d.ts.map +1 -0
  210. package/build/lib/github-actions/step.js +121 -0
  211. package/build/lib/github-actions/step.js.map +1 -0
  212. package/build/lib/helpers.d.ts.map +1 -1
  213. package/build/lib/helpers.js +5 -3
  214. package/build/lib/helpers.js.map +1 -1
  215. package/build/lib/kit-temp.d.ts +54 -0
  216. package/build/lib/kit-temp.d.ts.map +1 -1
  217. package/build/lib/kit-temp.js +82 -14
  218. package/build/lib/kit-temp.js.map +1 -1
  219. package/build/lib/kit-temp.test-d.d.ts +2 -0
  220. package/build/lib/kit-temp.test-d.d.ts.map +1 -0
  221. package/build/lib/kit-temp.test-d.js +75 -0
  222. package/build/lib/kit-temp.test-d.js.map +1 -0
  223. package/build/lib/mask/$$.d.ts +3 -0
  224. package/build/lib/mask/$$.d.ts.map +1 -0
  225. package/build/lib/mask/$$.js +3 -0
  226. package/build/lib/mask/$$.js.map +1 -0
  227. package/build/lib/mask/$.d.ts +2 -0
  228. package/build/lib/mask/$.d.ts.map +1 -0
  229. package/build/lib/mask/$.js +2 -0
  230. package/build/lib/mask/$.js.map +1 -0
  231. package/build/lib/mask/apply.d.ts +86 -0
  232. package/build/lib/mask/apply.d.ts.map +1 -0
  233. package/build/lib/mask/apply.js +86 -0
  234. package/build/lib/mask/apply.js.map +1 -0
  235. package/build/lib/mask/mask.d.ts +124 -0
  236. package/build/lib/mask/mask.d.ts.map +1 -0
  237. package/build/lib/mask/mask.js +137 -0
  238. package/build/lib/mask/mask.js.map +1 -0
  239. package/build/lib/mask/mask.test-d.d.ts +2 -0
  240. package/build/lib/mask/mask.test-d.d.ts.map +1 -0
  241. package/build/lib/mask/mask.test-d.js +102 -0
  242. package/build/lib/mask/mask.test-d.js.map +1 -0
  243. package/build/lib/mutation-type.d.ts +18 -0
  244. package/build/lib/mutation-type.d.ts.map +1 -0
  245. package/build/lib/mutation-type.js +16 -0
  246. package/build/lib/mutation-type.js.map +1 -0
  247. package/build/lib/task/$$.d.ts +3 -0
  248. package/build/lib/task/$$.d.ts.map +1 -0
  249. package/build/lib/task/$$.js +3 -0
  250. package/build/lib/task/$$.js.map +1 -0
  251. package/build/lib/task/$.d.ts +2 -0
  252. package/build/lib/task/$.d.ts.map +1 -0
  253. package/build/lib/task/$.js +2 -0
  254. package/build/lib/task/$.js.map +1 -0
  255. package/build/lib/task/report.d.ts +28 -0
  256. package/build/lib/task/report.d.ts.map +1 -0
  257. package/build/lib/task/report.js +33 -0
  258. package/build/lib/task/report.js.map +1 -0
  259. package/build/lib/task/task.d.ts +44 -0
  260. package/build/lib/task/task.d.ts.map +1 -0
  261. package/build/lib/task/task.js +63 -0
  262. package/build/lib/task/task.js.map +1 -0
  263. package/build/lib/version-history/index.d.ts +3 -0
  264. package/build/lib/version-history/index.d.ts.map +1 -0
  265. package/build/lib/version-history/index.js +2 -0
  266. package/build/lib/version-history/index.js.map +1 -0
  267. package/build/lib/version-history/types.d.ts +64 -0
  268. package/build/lib/version-history/types.d.ts.map +1 -0
  269. package/build/lib/version-history/types.js +5 -0
  270. package/build/lib/version-history/types.js.map +1 -0
  271. package/build/lib/version-history/version-history.d.ts +85 -0
  272. package/build/lib/version-history/version-history.d.ts.map +1 -0
  273. package/build/lib/version-history/version-history.js +248 -0
  274. package/build/lib/version-history/version-history.js.map +1 -0
  275. package/build/project-data.d.ts +0 -1
  276. package/build/project-data.d.ts.map +1 -1
  277. package/build/sandbox.d.ts +2 -0
  278. package/build/sandbox.d.ts.map +1 -0
  279. package/build/sandbox.js +18 -0
  280. package/build/sandbox.js.map +1 -0
  281. package/build/singletons/debug.d.ts +1 -1
  282. package/build/singletons/debug.d.ts.map +1 -1
  283. package/build/singletons/debug.js +1 -1
  284. package/build/singletons/debug.js.map +1 -1
  285. package/build/template/components/HamburgerMenu.d.ts +9 -0
  286. package/build/template/components/HamburgerMenu.d.ts.map +1 -0
  287. package/build/template/components/HamburgerMenu.jsx +53 -0
  288. package/build/template/components/HamburgerMenu.jsx.map +1 -0
  289. package/build/template/components/Link.jsx +1 -1
  290. package/build/template/components/Logo.d.ts +9 -0
  291. package/build/template/components/Logo.d.ts.map +1 -0
  292. package/build/template/components/Logo.jsx +29 -0
  293. package/build/template/components/Logo.jsx.map +1 -0
  294. package/build/template/components/NotFound.d.ts +2 -0
  295. package/build/template/components/NotFound.d.ts.map +1 -0
  296. package/build/template/components/NotFound.jsx +26 -0
  297. package/build/template/components/NotFound.jsx.map +1 -0
  298. package/build/template/components/ThemeToggle.d.ts +3 -0
  299. package/build/template/components/ThemeToggle.d.ts.map +1 -0
  300. package/build/template/components/ThemeToggle.jsx +10 -0
  301. package/build/template/components/ThemeToggle.jsx.map +1 -0
  302. package/build/template/components/content/$$.d.ts +2 -0
  303. package/build/template/components/content/$$.d.ts.map +1 -0
  304. package/build/template/components/content/$$.js +2 -0
  305. package/build/template/components/content/$$.js.map +1 -0
  306. package/build/template/components/sidebar/Sidebar.d.ts +2 -2
  307. package/build/template/components/sidebar/Sidebar.d.ts.map +1 -1
  308. package/build/template/components/sidebar/SidebarItem.d.ts +3 -3
  309. package/build/template/components/sidebar/SidebarItem.d.ts.map +1 -1
  310. package/build/template/components/sidebar/SidebarItem.jsx +1 -1
  311. package/build/template/components/sidebar/SidebarItem.jsx.map +1 -1
  312. package/build/template/contexts/ThemeContext.d.ts +12 -0
  313. package/build/template/contexts/ThemeContext.d.ts.map +1 -0
  314. package/build/template/contexts/ThemeContext.jsx +41 -0
  315. package/build/template/contexts/ThemeContext.jsx.map +1 -0
  316. package/build/template/routes/root.d.ts.map +1 -1
  317. package/build/template/routes/root.jsx +66 -53
  318. package/build/template/routes/root.jsx.map +1 -1
  319. package/build/template/server/app.d.ts.map +1 -1
  320. package/build/template/server/app.js +2 -21
  321. package/build/template/server/app.js.map +1 -1
  322. package/package.json +27 -13
  323. package/src/api/api.ts +1 -0
  324. package/src/api/config/configurator.ts +28 -6
  325. package/src/api/config/load.ts +5 -5
  326. package/src/api/config-resolver/resolve.ts +2 -2
  327. package/src/api/content/$$.ts +6 -0
  328. package/src/api/content/$.test.ts +72 -0
  329. package/src/api/content/$.ts +1 -0
  330. package/src/api/content/metadata.ts +11 -0
  331. package/src/api/content/navbar.test.ts +55 -0
  332. package/src/api/content/navbar.ts +61 -0
  333. package/src/api/content/page.ts +12 -0
  334. package/src/api/content/scan.ts +117 -0
  335. package/src/api/content/sidebar.test.ts +297 -0
  336. package/src/api/content/sidebar.ts +283 -0
  337. package/src/api/content/utils.ts +7 -0
  338. package/src/api/schema/data-sources/schema-directory/schema-directory.ts +1 -1
  339. package/src/api/singletons/markdown/markdown.test.ts +1 -1
  340. package/src/api/static/index.ts +1 -0
  341. package/src/api/static/manifest.test.ts +106 -0
  342. package/src/api/static/manifest.ts +16 -0
  343. package/src/api/static/rebase.test.ts +229 -0
  344. package/src/api/static/rebase.ts +140 -0
  345. package/src/api/static/static.ts +2 -0
  346. package/src/api/utils/asset-url/asset-url.test.ts +4 -4
  347. package/src/api/vite/plugins/branding/index.ts +108 -0
  348. package/src/api/vite/plugins/build.ts +25 -1
  349. package/src/api/vite/plugins/core.ts +6 -7
  350. package/src/api/vite/plugins/main.ts +2 -0
  351. package/src/api/vite/plugins/pages.ts +131 -207
  352. package/src/api/vite/plugins/serve.ts +5 -5
  353. package/src/cli/_/self-contained-mode.ts +5 -5
  354. package/src/cli/commands/static/$default.ts +43 -0
  355. package/src/cli/commands/static/rebase.ts +37 -0
  356. package/src/cli/commands/static.ts +6 -0
  357. package/src/exports/components.ts +1 -0
  358. package/src/lib/demos/builder.ts +298 -0
  359. package/src/lib/demos/config-schema.ts +56 -0
  360. package/src/lib/demos/config.test.ts +193 -0
  361. package/src/lib/demos/config.ts +205 -0
  362. package/src/lib/demos/index.ts +9 -0
  363. package/src/lib/demos/ui/components.ts +739 -0
  364. package/src/lib/demos/ui/data-collector.ts +246 -0
  365. package/src/lib/demos/ui/landing-page-cli.ts +23 -0
  366. package/src/lib/demos/ui/landing-page.ts +126 -0
  367. package/src/lib/demos/ui/page-renderer.ts +124 -0
  368. package/src/lib/demos/utils.ts +43 -0
  369. package/src/lib/deployment/$$.ts +2 -0
  370. package/src/lib/deployment/$.test.ts +53 -0
  371. package/src/lib/deployment/$.ts +1 -0
  372. package/src/lib/deployment/metadata.ts +40 -0
  373. package/src/lib/deployment/path-manager.ts +186 -0
  374. package/src/lib/file-router/file-router.ts +0 -2
  375. package/src/lib/file-router/linter.test.ts +2 -0
  376. package/src/lib/file-router/route.ts +2 -0
  377. package/src/lib/file-router/scan.ts +26 -14
  378. package/src/lib/github-actions/git-controller.ts +151 -0
  379. package/src/lib/github-actions/github-actions.ts +6 -0
  380. package/src/lib/github-actions/index.ts +1 -0
  381. package/src/lib/github-actions/lib/get-pr-deployments.ts +76 -0
  382. package/src/lib/github-actions/pr-controller.test.ts +172 -0
  383. package/src/lib/github-actions/pr-controller.ts +183 -0
  384. package/src/lib/github-actions/run-step-cli.ts +84 -0
  385. package/src/lib/github-actions/runner.test.ts +192 -0
  386. package/src/lib/github-actions/runner.ts +226 -0
  387. package/src/lib/github-actions/schemas/context.ts +424 -0
  388. package/src/lib/github-actions/schemas/index.ts +5 -0
  389. package/src/lib/github-actions/search-module.test.ts +110 -0
  390. package/src/lib/github-actions/search-module.ts +76 -0
  391. package/src/lib/github-actions/step.test.ts +149 -0
  392. package/src/lib/github-actions/step.ts +232 -0
  393. package/src/lib/helpers.ts +4 -3
  394. package/src/lib/kit-temp.test-d.ts +115 -0
  395. package/src/lib/kit-temp.test.ts +127 -0
  396. package/src/lib/kit-temp.ts +128 -14
  397. package/src/lib/mask/$$.ts +2 -0
  398. package/src/lib/mask/$.test.ts +248 -0
  399. package/src/lib/mask/$.ts +1 -0
  400. package/src/lib/mask/apply.ts +134 -0
  401. package/src/lib/mask/mask.test-d.ts +144 -0
  402. package/src/lib/mask/mask.ts +244 -0
  403. package/src/lib/mutation-type.ts +20 -0
  404. package/src/lib/shiki/shiki.test.ts +1 -1
  405. package/src/lib/task/$$.ts +2 -0
  406. package/src/lib/task/$.test.ts +209 -0
  407. package/src/lib/task/$.ts +1 -0
  408. package/src/lib/task/report.ts +72 -0
  409. package/src/lib/task/task.ts +112 -0
  410. package/src/lib/version-history/index.test.ts +196 -0
  411. package/src/lib/version-history/index.ts +4 -0
  412. package/src/lib/version-history/types.ts +68 -0
  413. package/src/lib/version-history/version-history.ts +293 -0
  414. package/src/project-data.ts +0 -1
  415. package/src/sandbox.ts +20 -0
  416. package/src/singletons/debug.ts +1 -1
  417. package/src/template/components/HamburgerMenu.tsx +96 -0
  418. package/src/template/components/Link.tsx +1 -1
  419. package/src/template/components/Logo.tsx +46 -0
  420. package/src/template/components/NotFound.tsx +28 -0
  421. package/src/template/components/ThemeToggle.tsx +21 -0
  422. package/src/template/components/content/$$.ts +1 -0
  423. package/src/template/components/sidebar/Sidebar.tsx +2 -2
  424. package/src/template/components/sidebar/SidebarItem.tsx +8 -8
  425. package/src/template/contexts/ThemeContext.tsx +60 -0
  426. package/src/template/routes/root.tsx +85 -74
  427. package/src/template/server/app.ts +2 -27
  428. package/build/lib/file-router/scan-tree.d.ts +0 -20
  429. package/build/lib/file-router/scan-tree.d.ts.map +0 -1
  430. package/build/lib/file-router/scan-tree.js +0 -158
  431. package/build/lib/file-router/scan-tree.js.map +0 -1
  432. package/build/lib/file-router/sidebar/index.d.ts +0 -3
  433. package/build/lib/file-router/sidebar/index.d.ts.map +0 -1
  434. package/build/lib/file-router/sidebar/index.js +0 -4
  435. package/build/lib/file-router/sidebar/index.js.map +0 -1
  436. package/build/lib/file-router/sidebar/sidebar-tree.d.ts +0 -9
  437. package/build/lib/file-router/sidebar/sidebar-tree.d.ts.map +0 -1
  438. package/build/lib/file-router/sidebar/sidebar-tree.js +0 -85
  439. package/build/lib/file-router/sidebar/sidebar-tree.js.map +0 -1
  440. package/build/lib/file-router/sidebar/types.d.ts +0 -17
  441. package/build/lib/file-router/sidebar/types.d.ts.map +0 -1
  442. package/build/lib/file-router/sidebar/types.js +0 -2
  443. package/build/lib/file-router/sidebar/types.js.map +0 -1
  444. package/build/lib/tree/index.d.ts +0 -3
  445. package/build/lib/tree/index.d.ts.map +0 -1
  446. package/build/lib/tree/index.js +0 -2
  447. package/build/lib/tree/index.js.map +0 -1
  448. package/build/lib/tree/tree.d.ts +0 -62
  449. package/build/lib/tree/tree.d.ts.map +0 -1
  450. package/build/lib/tree/tree.js +0 -134
  451. package/build/lib/tree/tree.js.map +0 -1
  452. package/src/lib/file-router/scan-tree.test.ts +0 -189
  453. package/src/lib/file-router/scan-tree.ts +0 -205
  454. package/src/lib/file-router/sidebar/index.ts +0 -3
  455. package/src/lib/file-router/sidebar/sidebar-tree.test.ts +0 -123
  456. package/src/lib/file-router/sidebar/sidebar-tree.ts +0 -110
  457. package/src/lib/file-router/sidebar/types.ts +0 -19
  458. package/src/lib/tree/index.ts +0 -2
  459. package/src/lib/tree/tree.test.ts +0 -117
  460. package/src/lib/tree/tree.ts +0 -183
@@ -12,8 +12,10 @@
12
12
  //
13
13
  //
14
14
 
15
- import { Fs, Http, Path, Undefined } from '@wollybeard/kit'
15
+ import { Arr, Err, Fs, Http, Path, type Ts, Undefined } from '@wollybeard/kit'
16
+ import { never } from '@wollybeard/kit/language'
16
17
  import type { ResolveHookContext } from 'node:module'
18
+ import type { IsNever } from 'type-fest'
17
19
 
18
20
  export const arrayEquals = (a: any[], b: any[]) => {
19
21
  if (a.length !== b.length) return false
@@ -60,23 +62,103 @@ export interface ImportEvent {
60
62
  context: ResolveHookContext
61
63
  }
62
64
 
63
- export const ObjPick = <T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Pick<T, K> => {
64
- return keys.reduce((acc, key) => {
65
- if (key in obj) {
66
- acc[key] = obj[key]
65
+ // dprint-ignore
66
+ export type ObjPolicyFilter<
67
+ $Object extends object,
68
+ $Key extends Keyof<$Object>,
69
+ Mode extends 'allow' | 'deny',
70
+ > = Mode extends 'allow'
71
+ ? Pick<$Object, Extract<$Key, keyof $Object>>
72
+ : Omit<$Object, Extract<$Key, keyof $Object>>
73
+
74
+ /**
75
+ * Like keyof but returns PropertyKey for object
76
+ */
77
+ type Keyof<$Object extends object> = object extends $Object ? PropertyKey : (keyof $Object)
78
+
79
+ /**
80
+ * Filter object properties based on a policy mode and set of keys
81
+ *
82
+ * @param mode - 'allow' to keep only specified keys, 'deny' to remove specified keys
83
+ * @param obj - The object to filter
84
+ * @param keys - The keys to process
85
+ * @returns A filtered object with proper type inference
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * const obj = { a: 1, b: 2, c: 3 }
90
+ *
91
+ * // Allow mode: keep only 'a' and 'c'
92
+ * objPolicyFilter('allow', obj, ['a', 'c']) // { a: 1, c: 3 }
93
+ *
94
+ * // Deny mode: remove 'a' and 'c'
95
+ * objPolicyFilter('deny', obj, ['a', 'c']) // { b: 2 }
96
+ * ```
97
+ */
98
+ export const objPolicyFilter = <
99
+ obj extends object,
100
+ keyUnion extends Keyof<obj>,
101
+ mode extends 'allow' | 'deny',
102
+ >(
103
+ mode: mode,
104
+ obj: obj,
105
+ keys: readonly keyUnion[],
106
+ ): ObjPolicyFilter<obj, keyUnion, mode> => {
107
+ const result: any = mode === 'deny' ? { ...obj } : {}
108
+
109
+ if (mode === 'allow') {
110
+ // For allow mode, only add specified keys
111
+ for (const key of keys) {
112
+ if (key in obj) {
113
+ // @ts-expect-error
114
+ result[key] = obj[key]
115
+ }
67
116
  }
68
- return acc
69
- }, {} as Pick<T, K>)
117
+ } else {
118
+ // For deny mode, remove specified keys
119
+ for (const key of keys) {
120
+ delete result[key]
121
+ }
122
+ }
123
+
124
+ return result
70
125
  }
71
126
 
72
- export const ObjOmit = <T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Omit<T, K> => {
73
- return keys.reduce((acc, key) => {
74
- if (key in acc) {
75
- // @ts-expect-error omitted already at type level
76
- delete acc[key]
127
+ /**
128
+ * Filter an object using a predicate function
129
+ *
130
+ * @param obj - The object to filter
131
+ * @param predicate - Function that returns true to keep a key/value pair
132
+ * @returns A new object with only the key/value pairs where predicate returned true
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * const obj = { a: 1, b: 2, c: 3 }
137
+ * objFilter(obj, (k, v) => v > 1) // { b: 2, c: 3 }
138
+ * objFilter(obj, k => k !== 'b') // { a: 1, c: 3 }
139
+ * ```
140
+ */
141
+ export const objFilter = <T extends object>(
142
+ obj: T,
143
+ predicate: (key: keyof T, value: T[keyof T], obj: T) => boolean,
144
+ ): Partial<T> => {
145
+ const result = {} as Partial<T>
146
+ // Use Object.keys to get all enumerable own properties
147
+ // This matches the behavior of for...in but only for own properties
148
+ for (const key of Object.keys(obj) as (keyof T)[]) {
149
+ if (predicate(key, obj[key], obj)) {
150
+ result[key] = obj[key]
77
151
  }
78
- return acc
79
- }, { ...obj } as Omit<T, K>)
152
+ }
153
+ return result
154
+ }
155
+
156
+ export const ObjPick = <T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Pick<T, K> => {
157
+ return objPolicyFilter('allow', obj, keys) as any
158
+ }
159
+
160
+ export const ObjOmit = <T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Omit<T, K> => {
161
+ return objPolicyFilter('deny', obj, keys) as any
80
162
  }
81
163
 
82
164
  export const ObjPartition = <T extends object, K extends keyof T>(
@@ -106,3 +188,35 @@ export const ResponseInternalServerError = () =>
106
188
  status: Http.Status.InternalServerError.code,
107
189
  statusText: Http.Status.InternalServerError.description,
108
190
  })
191
+
192
+ /**
193
+ * Execute an operation on multiple items, continuing even if some fail
194
+ */
195
+ export async function tryCatchMany<item, result>(
196
+ items: item[],
197
+ operation: (item: item) => Promise<result>,
198
+ ): Promise<[result[], (Error & { context: { item: item } })[]]> {
199
+ const partitionedResults = await Promise.all(items.map(async (item) => {
200
+ const result = await Err.tryCatch(() => operation(item))
201
+ if (Err.is(result)) {
202
+ const error = result as Error & { context: { item: item } }
203
+ error.context = { item }
204
+ return error
205
+ }
206
+ return result
207
+ })).then(Arr.partitionErrors)
208
+ return partitionedResults as any
209
+ }
210
+
211
+ /**
212
+ * Type-level helper to check if two types are exactly the same (invariant).
213
+ */
214
+ export type IsExact<T, U> = T extends U ? U extends T ? true : false : false
215
+
216
+ // dprint-ignore
217
+ export type ExtendsExact<$Input, $Constraint> =
218
+ $Input extends $Constraint
219
+ ? $Constraint extends $Input
220
+ ? $Input
221
+ : never
222
+ : never
@@ -0,0 +1,2 @@
1
+ export * from './apply.ts'
2
+ export * from './mask.ts'
@@ -0,0 +1,248 @@
1
+ import * as fc from 'fast-check'
2
+ import { describe, expect, test } from 'vitest'
3
+ import { Mask } from './$.ts'
4
+
5
+ describe('Mask.create', () => {
6
+ test('boolean options create binary masks', () => {
7
+ const showMask = Mask.create(true)
8
+ const hideMask = Mask.create(false)
9
+
10
+ expect(showMask.type).toBe('binary')
11
+ expect(hideMask.type).toBe('binary')
12
+
13
+ if (showMask.type === 'binary' && hideMask.type === 'binary') {
14
+ expect(showMask.show).toBe(true)
15
+ expect(hideMask.show).toBe(false)
16
+ }
17
+ })
18
+
19
+ test('array options create allow mode properties mask', () => {
20
+ const mask = Mask.create(['name', 'age'])
21
+
22
+ expect(mask.type).toBe('properties')
23
+ if (mask.type === 'properties') {
24
+ expect(mask.mode).toBe('allow')
25
+ expect(mask.properties).toEqual(['name', 'age'])
26
+ }
27
+ })
28
+
29
+ test('object options create mode based on values', () => {
30
+ const allowMask = Mask.create({ name: true, age: true, password: false })
31
+ const denyMask = Mask.create({ password: false, secret: false })
32
+
33
+ expect(allowMask.type).toBe('properties')
34
+ expect(denyMask.type).toBe('properties')
35
+
36
+ if (allowMask.type === 'properties' && denyMask.type === 'properties') {
37
+ expect(allowMask.mode).toBe('allow')
38
+ expect(allowMask.properties).toEqual(['name', 'age'])
39
+
40
+ expect(denyMask.mode).toBe('deny')
41
+ expect(denyMask.properties).toEqual(['password', 'secret'])
42
+ }
43
+ })
44
+ })
45
+
46
+ describe('Mask.apply', () => {
47
+ test('binary masks show/hide data', () => {
48
+ const data = { a: 1 }
49
+
50
+ expect(Mask.apply(data, Mask.create(true))).toBe(data)
51
+ expect(Mask.apply(data, Mask.create(false))).toBe(undefined)
52
+ })
53
+
54
+ test('properties masks filter objects', () => {
55
+ const data = { name: 'John', age: 30, password: 'secret' }
56
+
57
+ // Allow mode
58
+ const allowMask = Mask.create(['name', 'age'])
59
+ expect(Mask.apply(data, allowMask)).toEqual({ name: 'John', age: 30 })
60
+
61
+ // Deny mode
62
+ const denyMask = Mask.create({ password: false })
63
+ expect(Mask.apply(data, denyMask)).toEqual({ name: 'John', age: 30 })
64
+ })
65
+
66
+ test('properties masks throw for non-objects', () => {
67
+ const mask = Mask.create(['name'])
68
+
69
+ expect(() => Mask.apply('string' as any, mask)).toThrow()
70
+ expect(() => Mask.apply(123 as any, mask)).toThrow()
71
+ expect(() => Mask.apply(null as any, mask)).toThrow()
72
+ })
73
+ })
74
+
75
+ describe('apply variants', () => {
76
+ test('applyPartial allows missing properties', () => {
77
+ const mask = Mask.create<{ name: string; age: number }>(['name', 'age'])
78
+ const partial = { name: 'John' }
79
+
80
+ expect(Mask.applyPartial(partial, mask)).toEqual({ name: 'John' })
81
+ expect(Mask.applyPartial({}, mask)).toEqual({})
82
+ })
83
+
84
+ test('applyExact works with any data for binary masks', () => {
85
+ const showMask = Mask.create(true)
86
+ const hideMask = Mask.create(false)
87
+
88
+ expect(Mask.applyExact('hello' as any, showMask)).toBe('hello')
89
+ expect(Mask.applyExact('hello' as any, hideMask)).toBe(undefined)
90
+ })
91
+ })
92
+
93
+ describe('property-based tests', () => {
94
+ test('binary masks - invariants', () => {
95
+ fc.assert(
96
+ fc.property(fc.anything(), (data) => {
97
+ expect(Mask.apply(data, Mask.create(true))).toBe(data)
98
+ expect(Mask.apply(data, Mask.create(false))).toBe(undefined)
99
+ }),
100
+ )
101
+ })
102
+
103
+ test('properties mask - allow mode filters correctly', () => {
104
+ fc.assert(
105
+ fc.property(
106
+ fc.dictionary(fc.string(), fc.anything()),
107
+ fc.array(fc.string(), { minLength: 1 }),
108
+ (obj, keys) => {
109
+ const mask = Mask.create(keys)
110
+ const result = Mask.apply(obj as any, mask)
111
+ const resultKeys = Object.keys(result as any)
112
+
113
+ // Result contains only keys that were in both mask and object
114
+ expect(resultKeys.every(key => keys.includes(key))).toBe(true)
115
+
116
+ // All requested keys that exist in obj are in result
117
+ keys.forEach(key => {
118
+ if (key in obj) {
119
+ expect(result).toHaveProperty(key, (obj as any)[key])
120
+ }
121
+ })
122
+ },
123
+ ),
124
+ )
125
+ })
126
+
127
+ test('properties mask - deny mode filters correctly', () => {
128
+ fc.assert(
129
+ fc.property(
130
+ fc.dictionary(fc.string(), fc.anything()),
131
+ fc.uniqueArray(fc.string(), { minLength: 1 }),
132
+ (data, keysToRemove) => {
133
+ const maskSpec = Object.fromEntries(keysToRemove.map(k => [k, false]))
134
+ const mask = Mask.create(maskSpec)
135
+
136
+ expect(mask.type).toBe('properties')
137
+ if (mask.type !== 'properties') return
138
+ expect(mask.mode).toBe('deny')
139
+
140
+ const result = Mask.apply(data as any, mask)
141
+
142
+ // Result should not have any of the denied keys
143
+ keysToRemove.forEach(key => {
144
+ expect(Object.prototype.hasOwnProperty.call(result, key)).toBe(false)
145
+ })
146
+
147
+ // Result should have all other keys from data
148
+ Object.keys(data).forEach(key => {
149
+ if (!keysToRemove.includes(key)) {
150
+ expect(Object.prototype.hasOwnProperty.call(result, key)).toBe(true)
151
+ expect((result as any)[key]).toBe((data as any)[key])
152
+ }
153
+ })
154
+ },
155
+ ),
156
+ )
157
+ })
158
+
159
+ test('undefined values are preserved', () => {
160
+ fc.assert(
161
+ fc.property(
162
+ fc.record({
163
+ a: fc.oneof(fc.anything(), fc.constant(undefined)),
164
+ b: fc.oneof(fc.anything(), fc.constant(undefined)),
165
+ c: fc.oneof(fc.anything(), fc.constant(undefined)),
166
+ }),
167
+ fc.shuffledSubarray(['a', 'b', 'c'], { minLength: 1 }),
168
+ (obj, keys) => {
169
+ const result = Mask.apply(obj as any, Mask.create(keys))
170
+
171
+ keys.forEach(key => {
172
+ if (key in obj) {
173
+ expect(result).toHaveProperty(key)
174
+ expect((result as any)[key]).toBe((obj as any)[key])
175
+ }
176
+ })
177
+ },
178
+ ),
179
+ )
180
+ })
181
+
182
+ test('apply and applyPartial are consistent for complete data', () => {
183
+ fc.assert(
184
+ fc.property(
185
+ fc.dictionary(fc.string(), fc.anything()),
186
+ fc.array(fc.string(), { minLength: 1 }),
187
+ (data, keys) => {
188
+ const mask = Mask.create(keys)
189
+ expect(Mask.apply(data as any, mask)).toEqual(Mask.applyPartial(data as any, mask))
190
+ },
191
+ ),
192
+ )
193
+ })
194
+
195
+ test('non-objects throw with properties masks', () => {
196
+ fc.assert(
197
+ fc.property(
198
+ fc.oneof(
199
+ fc.string(),
200
+ fc.integer(),
201
+ fc.boolean(),
202
+ fc.constant(null),
203
+ fc.constant(undefined),
204
+ ),
205
+ fc.array(fc.string(), { minLength: 1 }),
206
+ (nonObject, keys) => {
207
+ const mask = Mask.create(keys)
208
+ expect(() => Mask.apply(nonObject as any, mask)).toThrow('Cannot apply properties mask to non-object data')
209
+ },
210
+ ),
211
+ )
212
+ })
213
+
214
+ test('immutability invariants', () => {
215
+ fc.assert(
216
+ fc.property(
217
+ fc.dictionary(
218
+ fc.string(),
219
+ fc.oneof(
220
+ fc.string(),
221
+ fc.integer(),
222
+ fc.boolean(),
223
+ fc.constant(null),
224
+ ),
225
+ ),
226
+ fc.oneof(
227
+ fc.boolean(),
228
+ fc.array(fc.string()),
229
+ fc.dictionary(fc.string(), fc.boolean()),
230
+ ),
231
+ (data, maskOptions) => {
232
+ const mask = Mask.create(maskOptions as any)
233
+ const originalData = { ...data }
234
+ const originalMask = JSON.parse(JSON.stringify(mask))
235
+
236
+ try {
237
+ Mask.apply(data as any, mask)
238
+ } catch {
239
+ // Ignore errors for invalid combinations
240
+ }
241
+
242
+ expect(data).toEqual(originalData)
243
+ expect(mask).toEqual(originalMask)
244
+ },
245
+ ),
246
+ )
247
+ })
248
+ })
@@ -0,0 +1 @@
1
+ export * as Mask from './$$.ts'
@@ -0,0 +1,134 @@
1
+ import { type ExtendsExact, objPolicyFilter } from '#lib/kit-temp'
2
+ import { Obj } from '@wollybeard/kit'
3
+ import { never } from '@wollybeard/kit/language'
4
+ import type { GetDataType, Mask } from './mask.ts'
5
+
6
+ /**
7
+ * Type-level function that applies a mask to data.
8
+ *
9
+ * @template Data - The data type
10
+ * @template M - The mask type
11
+ *
12
+ * Binary masks:
13
+ * - show=true returns the data unchanged
14
+ * - show=false returns undefined
15
+ *
16
+ * Properties masks:
17
+ * - 'allow' mode returns Pick<Data, keys>
18
+ * - 'deny' mode returns Omit<Data, keys>
19
+ * - Non-objects throw an error at runtime
20
+ */
21
+ // dprint-ignore
22
+ export type Apply<Data, M extends Mask<any>> =
23
+ M extends { type: 'binary', show: boolean }
24
+ ? M['show'] extends true
25
+ ? Data
26
+ : undefined
27
+ : M extends { type: 'properties', mode: string, properties: any[] }
28
+ ? Data extends object
29
+ ? M['mode'] extends 'allow'
30
+ ? Pick<Data, Extract<M['properties'][number], keyof Data>>
31
+ : Omit<Data, Extract<M['properties'][number], keyof Data>>
32
+ : never // Non-objects not allowed with property masks
33
+ : never
34
+
35
+ /**
36
+ * Apply mask to data with standard covariance.
37
+ *
38
+ * Data must be assignable to the mask's expected type (may have excess properties).
39
+ *
40
+ * @param data - The data to mask
41
+ * @param mask - The mask to apply
42
+ * @returns The masked data
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const user = { name: 'John', email: 'john@example.com', password: 'secret' }
47
+ * const mask = Mask.pick<User>(['name', 'email'])
48
+ * const safeUser = apply(user, mask) // { name: 'John', email: 'john@example.com' }
49
+ * ```
50
+ */
51
+ export const apply = <
52
+ data extends GetDataType<mask>,
53
+ mask extends Mask<any>,
54
+ >(data: data, mask: mask): Apply<data, mask> => {
55
+ return applyInternal(data, mask) as Apply<data, mask>
56
+ }
57
+
58
+ /**
59
+ * Apply mask to partial data.
60
+ *
61
+ * Data may have only a subset of the mask's expected properties.
62
+ * Useful when working with incomplete data or optional fields.
63
+ *
64
+ * @param data - The partial data to mask
65
+ * @param mask - The mask to apply
66
+ * @returns The masked data
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * const partialUser = { name: 'John' } // missing email
71
+ * const mask = Mask.pick<User>(['name', 'email'])
72
+ * const result = applyPartial(partialUser, mask) // { name: 'John' }
73
+ * ```
74
+ */
75
+ export const applyPartial = <
76
+ data extends Partial<GetDataType<mask>>,
77
+ mask extends Mask<any>,
78
+ >(data: data, mask: mask): Apply<data, mask> => {
79
+ return applyInternal(data, mask) as Apply<data, mask>
80
+ }
81
+
82
+ /**
83
+ * Apply mask to data with exact type matching.
84
+ *
85
+ * Data must exactly match the mask's expected type - no missing or excess properties.
86
+ * Provides the strictest type checking.
87
+ *
88
+ * @param data - The data to mask (must exactly match expected type)
89
+ * @param mask - The mask to apply
90
+ * @returns The masked data
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * type User = { name: string; email: string }
95
+ * const mask = Mask.pick<User>(['name'])
96
+ *
97
+ * // This works - exact match
98
+ * const user: User = { name: 'John', email: 'john@example.com' }
99
+ * const result = applyExact(user, mask)
100
+ *
101
+ * // This fails - has extra property
102
+ * const userWithExtra = { name: 'John', email: 'john@example.com', age: 30 }
103
+ * const result2 = applyExact(userWithExtra, mask) // Type error!
104
+ * ```
105
+ */
106
+ export const applyExact = <
107
+ data,
108
+ mask extends Mask<any>,
109
+ >(
110
+ data: ExtendsExact<data, GetDataType<mask>>,
111
+ mask: mask,
112
+ ): Apply<data, mask> => {
113
+ return applyInternal(data, mask) as Apply<data, mask>
114
+ }
115
+
116
+ // Internal implementation
117
+ const applyInternal = (data: any, mask: Mask<any>): any => {
118
+ // ━ Handle binary mask
119
+ if (mask.type === 'binary') {
120
+ return mask.show ? data : undefined
121
+ }
122
+
123
+ // ━ Handle properties mask
124
+ if (mask.type === 'properties') {
125
+ // Properties mask requires object data
126
+ if (!Obj.is(data)) {
127
+ throw new Error('Cannot apply properties mask to non-object data')
128
+ }
129
+
130
+ return objPolicyFilter(mask.mode, data, mask.properties)
131
+ }
132
+
133
+ never()
134
+ }
@@ -0,0 +1,144 @@
1
+ import { Ts } from '@wollybeard/kit'
2
+ import { Mask } from './$.ts'
3
+ import type { InferOptions, Mask as MaskType, PropertiesMask } from './mask.ts'
4
+
5
+ // Test 1: InferOptions with unknown should accept all option types
6
+ {
7
+ type Options = InferOptions<unknown>
8
+
9
+ // This is a type-level assertion - we need to use a different pattern
10
+ type _Test = Ts.AssertEqual<Options, boolean | string[] | Record<string, boolean>>
11
+
12
+ // All of these should be valid options
13
+ const option1: Options = true
14
+ const option2: Options = false
15
+ const option3: Options = ['name', 'age']
16
+ const option4: Options = []
17
+ const option5: Options = { name: true, age: false }
18
+ const option6: Options = {}
19
+ }
20
+
21
+ // Test 2: Mask.create with unknown data type should accept all option types
22
+ {
23
+ // Boolean options
24
+ const mask1 = Mask.create(true)
25
+ const mask2 = Mask.create(false)
26
+ // Without explicit type parameter, returns union type
27
+ Ts.assertEqual<MaskType<unknown>>()(mask1)
28
+ Ts.assertEqual<MaskType<unknown>>()(mask2)
29
+
30
+ // Array options (no type parameter needed)
31
+ const mask3 = Mask.create(['name', 'age'])
32
+ const mask4 = Mask.create([])
33
+ const mask5 = Mask.create(['a', 'b', 'c'])
34
+ // Returns union type with inferred properties
35
+ Ts.assertEqual<MaskType<{ name: any; age: any }>>()(mask3)
36
+ Ts.assertEqual<MaskType<unknown>>()(mask4)
37
+ Ts.assertEqual<MaskType<{ a: any; b: any; c: any }>>()(mask5)
38
+
39
+ // Object options
40
+ const mask6 = Mask.create({ name: true, age: false })
41
+ const mask7 = Mask.create({})
42
+ const mask8 = Mask.create({ foo: true, bar: true, baz: false })
43
+ // Returns union type with inferred properties
44
+ Ts.assertEqual<MaskType<unknown>>()(mask6)
45
+ Ts.assertEqual<MaskType<unknown>>()(mask7)
46
+ Ts.assertEqual<MaskType<unknown>>()(mask8)
47
+ }
48
+
49
+ // Test 3: With specific data type, options are constrained
50
+ {
51
+ type User = { name: string; age: number; email: string }
52
+
53
+ // Valid options
54
+ const mask1 = Mask.create<User>(true)
55
+ const mask2 = Mask.create<User>(['name', 'age'])
56
+ const mask3 = Mask.create<User>({ name: true, age: false, email: true })
57
+
58
+ // With explicit type parameter, still returns union type
59
+ Ts.assertEqual<MaskType<User>>()(mask1)
60
+ Ts.assertEqual<MaskType<User>>()(mask2)
61
+ Ts.assertEqual<MaskType<User>>()(mask3)
62
+
63
+ // Invalid cases would be compile errors
64
+ // const mask4 = Mask.create<User>(['invalid']) // Error: 'invalid' is not a key of User
65
+ // const mask5 = Mask.create<User>({ invalid: true }) // Error: 'invalid' is not a property of User
66
+ }
67
+
68
+ // Test 4: Non-object types only accept boolean
69
+ {
70
+ const mask1 = Mask.create<string>(true)
71
+ const mask2 = Mask.create<string>(false)
72
+
73
+ Ts.assertEqual<MaskType<string>>()(mask1)
74
+ Ts.assertEqual<MaskType<string>>()(mask2)
75
+
76
+ // Invalid cases would be compile errors
77
+ // const mask3 = Mask.create<string>(['prop']) // Error: string is not an object
78
+ // const mask4 = Mask.create<string>({ prop: true }) // Error: string is not an object
79
+ }
80
+
81
+ // Test 5: Test inference in practical scenarios
82
+ {
83
+ // Should infer PropertiesMask with object data type
84
+ const userMask = Mask.create(['name', 'email', 'password'])
85
+ Ts.assertEqual<MaskType<{ name: any; email: any; password: any }>>()(userMask)
86
+
87
+ // When mask is a union type, apply returns a union of possible results
88
+ const user1 = { name: 'John', email: 'john@example.com', password: 'secret', extra: 'data' }
89
+ const maskedUser1 = Mask.apply(user1, userMask)
90
+ // Result is a union type that includes the properties mask result
91
+ type MaskedUser1 = typeof maskedUser1
92
+ // Can't use assertSub with union types
93
+
94
+ // For partial data, use applyPartial
95
+ const user2 = { name: 'Jane', email: 'jane@example.com' }
96
+ const maskedUser2 = Mask.applyPartial(user2, userMask)
97
+ // Result is a union type
98
+ type MaskedUser2 = typeof maskedUser2
99
+ }
100
+
101
+ // Test 6: Pick and omit helpers
102
+ {
103
+ const pick1 = Mask.pick(['name', 'email'])
104
+ const omit1 = Mask.omit(['password', 'secret'])
105
+
106
+ // Infers specific property types
107
+ Ts.assertEqual<PropertiesMask<{ name: any; email: any }>>()(pick1)
108
+ Ts.assertEqual<PropertiesMask<{ password: any; secret: any }>>()(omit1)
109
+
110
+ type User = { name: string; email: string; password: string }
111
+ const pick2 = Mask.pick<User>(['name', 'email'])
112
+ const omit2 = Mask.omit<User>(['password'])
113
+
114
+ Ts.assertEqual<PropertiesMask<User>>()(pick2)
115
+ Ts.assertEqual<PropertiesMask<User>>()(omit2)
116
+ }
117
+
118
+ // Test 7: Apply type transformations
119
+ {
120
+ type User = { name: string; email: string; password: string }
121
+ const user: User = { name: 'John', email: 'john@example.com', password: 'secret' }
122
+
123
+ // Binary mask
124
+ const showMask = Mask.create<User>(true)
125
+ const hideMask = Mask.create<User>(false)
126
+ const shown = Mask.apply(user, showMask)
127
+ const hidden = Mask.apply(user, hideMask)
128
+
129
+ // showMask and hideMask are MaskType<User> (union types), so results are unions
130
+ type ShownType = typeof shown // Omit<User, keyof User> | undefined
131
+ type HiddenType = typeof hidden // Omit<User, keyof User> | undefined
132
+
133
+ // Properties mask - allow mode
134
+ const allowMask = Mask.create<User>(['name', 'email'])
135
+ const allowed = Mask.apply(user, allowMask)
136
+ // Result is a union due to mask being a union type
137
+ type AllowedType = typeof allowed
138
+
139
+ // Properties mask - deny mode
140
+ const denyMask = Mask.create<User>({ password: false })
141
+ const denied = Mask.apply(user, denyMask)
142
+ // Result is a union due to mask being a union type
143
+ type DeniedType = typeof denied
144
+ }