meno-core 1.0.31 → 1.0.34

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 (373) hide show
  1. package/.claude/settings.local.json +7 -0
  2. package/build-static.test.ts +424 -0
  3. package/build-static.ts +1045 -0
  4. package/bunfig.toml +42 -0
  5. package/dist/bin/cli.js +1 -1
  6. package/dist/build-static.js +6 -6
  7. package/dist/chunks/{chunk-INK4UWAN.js → chunk-7PCKKQQI.js} +47 -15
  8. package/dist/chunks/chunk-7PCKKQQI.js.map +7 -0
  9. package/dist/chunks/{chunk-MJD62IUJ.js → chunk-E6L5FESH.js} +2 -1
  10. package/dist/chunks/{chunk-MJD62IUJ.js.map → chunk-E6L5FESH.js.map} +2 -2
  11. package/dist/chunks/{chunk-NBMAZOCJ.js → chunk-LDJGXCRR.js} +4 -3
  12. package/dist/chunks/chunk-LDJGXCRR.js.map +7 -0
  13. package/dist/chunks/{chunk-7ZZIWLUS.js → chunk-RDI56Q2W.js} +61 -11
  14. package/dist/chunks/chunk-RDI56Q2W.js.map +7 -0
  15. package/dist/chunks/{chunk-HE67KV43.js → chunk-RO5BCYPR.js} +7 -5
  16. package/dist/chunks/chunk-RO5BCYPR.js.map +7 -0
  17. package/dist/chunks/{chunk-4KWEMYQE.js → chunk-VNAPFF4I.js} +17 -4
  18. package/dist/chunks/chunk-VNAPFF4I.js.map +7 -0
  19. package/dist/chunks/{chunk-M4B7T6NE.js → chunk-YSV4AG55.js} +2 -2
  20. package/dist/chunks/{configService-UJGQY46I.js → configService-SASOCJRE.js} +3 -3
  21. package/dist/entries/server-router.js +6 -6
  22. package/dist/lib/client/index.js +8 -3
  23. package/dist/lib/client/index.js.map +2 -2
  24. package/dist/lib/server/index.js +7 -7
  25. package/dist/lib/shared/index.js +1 -1
  26. package/entries/client-router.tsx +206 -0
  27. package/entries/server-router.tsx +77 -0
  28. package/lib/client/ClientInitializer.test.ts +9 -0
  29. package/lib/client/ClientInitializer.test.ts.skip +92 -0
  30. package/lib/client/ClientInitializer.ts +110 -0
  31. package/lib/client/ErrorBoundary.test.tsx +595 -0
  32. package/lib/client/ErrorBoundary.tsx +230 -0
  33. package/lib/client/InteractiveStylesRegistry.ts +96 -0
  34. package/lib/client/componentRegistry.test.ts +211 -0
  35. package/lib/client/componentRegistry.ts +18 -0
  36. package/lib/client/contexts/ThemeContext.tsx +73 -0
  37. package/lib/client/core/ComponentBuilder.test.ts +1699 -0
  38. package/lib/client/core/ComponentBuilder.ts +1000 -0
  39. package/lib/client/core/ComponentRenderer.test.tsx +175 -0
  40. package/lib/client/core/ComponentRenderer.tsx +90 -0
  41. package/lib/client/core/builders/embedBuilder.ts +229 -0
  42. package/lib/client/core/builders/index.ts +30 -0
  43. package/lib/client/core/builders/linkBuilder.ts +136 -0
  44. package/lib/client/core/builders/linkNodeBuilder.ts +216 -0
  45. package/lib/client/core/builders/listBuilder.ts +599 -0
  46. package/lib/client/core/builders/localeListBuilder.ts +235 -0
  47. package/lib/client/core/builders/types.ts +97 -0
  48. package/lib/client/core/cmsTemplateProcessor.ts +147 -0
  49. package/lib/client/elementRegistry.ts +117 -0
  50. package/lib/client/hmr/HMRManager.tsx +205 -0
  51. package/lib/client/hmr/index.ts +5 -0
  52. package/lib/client/hmrWebSocket.test.ts +9 -0
  53. package/lib/client/hmrWebSocket.ts +269 -0
  54. package/lib/client/hooks/useColorVariables.test.ts +166 -0
  55. package/lib/client/hooks/useColorVariables.ts +249 -0
  56. package/lib/client/hooks/usePropertyAutocomplete.test.ts +9 -0
  57. package/lib/client/hooks/usePropertyAutocomplete.ts +40 -0
  58. package/lib/client/hooks/useVariables.ts +101 -0
  59. package/lib/client/hydration/HydrationUtils.test.ts +154 -0
  60. package/lib/client/hydration/HydrationUtils.ts +35 -0
  61. package/lib/client/i18nConfigService.test.ts +73 -0
  62. package/lib/client/i18nConfigService.ts +78 -0
  63. package/lib/client/index.ts +61 -0
  64. package/lib/client/meno-filter/MenoFilter.test.ts +1230 -0
  65. package/lib/client/meno-filter/MenoFilter.ts +1281 -0
  66. package/lib/client/meno-filter/bindings.ts +555 -0
  67. package/lib/client/meno-filter/constants.ts +72 -0
  68. package/lib/client/meno-filter/index.ts +58 -0
  69. package/lib/client/meno-filter/init.ts +259 -0
  70. package/lib/client/meno-filter/renderer.ts +410 -0
  71. package/lib/client/meno-filter/script.generated.ts +56 -0
  72. package/lib/client/meno-filter/types.ts +165 -0
  73. package/lib/client/meno-filter/ui.ts +364 -0
  74. package/lib/client/meno-filter/updates.ts +674 -0
  75. package/lib/client/meno-filter/utils.ts +44 -0
  76. package/lib/client/navigation.test.ts +441 -0
  77. package/lib/client/navigation.ts +23 -0
  78. package/lib/client/responsiveStyleResolver.test.ts +496 -0
  79. package/lib/client/responsiveStyleResolver.ts +196 -0
  80. package/lib/client/routing/RouteLoader.test.ts +753 -0
  81. package/lib/client/routing/RouteLoader.ts +380 -0
  82. package/lib/client/routing/Router.tsx +651 -0
  83. package/lib/client/scripts/ScriptExecutor.test.ts +465 -0
  84. package/lib/client/scripts/ScriptExecutor.ts +317 -0
  85. package/lib/client/scripts/formHandler.ts +103 -0
  86. package/lib/client/services/PrefetchService.test.ts +362 -0
  87. package/lib/client/services/PrefetchService.ts +344 -0
  88. package/lib/client/styleProcessor.test.ts +126 -0
  89. package/lib/client/styleProcessor.ts +93 -0
  90. package/lib/client/styles/StyleInjector.test.ts +370 -0
  91. package/lib/client/styles/StyleInjector.ts +195 -0
  92. package/lib/client/styles/UtilityClassCollector.ts +208 -0
  93. package/lib/client/templateEngine.test.ts +787 -0
  94. package/lib/client/templateEngine.ts +830 -0
  95. package/lib/client/theme.test.ts +173 -0
  96. package/lib/client/theme.ts +147 -0
  97. package/lib/client/utils/toast.ts +47 -0
  98. package/lib/server/__integration__/api-routes.test.ts +148 -0
  99. package/lib/server/__integration__/cms-integration.test.ts +161 -0
  100. package/lib/server/__integration__/server-lifecycle.test.ts +101 -0
  101. package/lib/server/__integration__/ssr-rendering.test.ts +131 -0
  102. package/lib/server/__integration__/static-assets.test.ts +80 -0
  103. package/lib/server/__integration__/test-helpers.ts +205 -0
  104. package/lib/server/ab/generateFunctions.ts +346 -0
  105. package/lib/server/ab/trackingScript.ts +45 -0
  106. package/lib/server/createServer.ts +175 -0
  107. package/lib/server/cssGenerator.test.ts +172 -0
  108. package/lib/server/cssGenerator.ts +146 -0
  109. package/lib/server/errors.ts +65 -0
  110. package/lib/server/fileWatcher.ts +302 -0
  111. package/lib/server/index.ts +78 -0
  112. package/lib/server/jsonLoader.test.ts +106 -0
  113. package/lib/server/jsonLoader.ts +504 -0
  114. package/lib/server/middleware/cors.test.ts +177 -0
  115. package/lib/server/middleware/cors.ts +69 -0
  116. package/lib/server/middleware/errorHandler.test.ts +208 -0
  117. package/lib/server/middleware/errorHandler.ts +63 -0
  118. package/lib/server/middleware/index.ts +9 -0
  119. package/lib/server/middleware/logger.test.ts +233 -0
  120. package/lib/server/middleware/logger.ts +99 -0
  121. package/lib/server/migrateTemplates.ts +22 -0
  122. package/lib/server/pageCache.test.ts +167 -0
  123. package/lib/server/pageCache.ts +97 -0
  124. package/lib/server/projectContext.ts +59 -0
  125. package/lib/server/providers/fileSystemCMSProvider.test.ts +345 -0
  126. package/lib/server/providers/fileSystemCMSProvider.ts +340 -0
  127. package/lib/server/providers/fileSystemPageProvider.ts +152 -0
  128. package/lib/server/routes/api/cms.test.ts +183 -0
  129. package/lib/server/routes/api/cms.ts +131 -0
  130. package/lib/server/routes/api/colors.test.ts +103 -0
  131. package/lib/server/routes/api/colors.ts +44 -0
  132. package/lib/server/routes/api/components.ts +81 -0
  133. package/lib/server/routes/api/config.test.ts +9 -0
  134. package/lib/server/routes/api/config.ts +47 -0
  135. package/lib/server/routes/api/core-routes.ts +262 -0
  136. package/lib/server/routes/api/enums.test.ts +53 -0
  137. package/lib/server/routes/api/enums.ts +16 -0
  138. package/lib/server/routes/api/functions.ts +168 -0
  139. package/lib/server/routes/api/index.ts +69 -0
  140. package/lib/server/routes/api/pages.ts +97 -0
  141. package/lib/server/routes/api/shared.test.ts +81 -0
  142. package/lib/server/routes/api/shared.ts +31 -0
  143. package/lib/server/routes/api/variables.test.ts +74 -0
  144. package/lib/server/routes/api/variables.ts +32 -0
  145. package/lib/server/routes/editor.test.ts +9 -0
  146. package/lib/server/routes/index.ts +149 -0
  147. package/lib/server/routes/pages.ts +269 -0
  148. package/lib/server/routes/static.ts +96 -0
  149. package/lib/server/runtime/bundler.ts +285 -0
  150. package/lib/server/runtime/fs.ts +232 -0
  151. package/lib/server/runtime/httpServer.ts +228 -0
  152. package/lib/server/runtime/index.ts +36 -0
  153. package/lib/server/scriptCache.ts +36 -0
  154. package/lib/server/services/CachedConfigLoader.ts +55 -0
  155. package/lib/server/services/ColorService.test.ts +216 -0
  156. package/lib/server/services/ColorService.ts +224 -0
  157. package/lib/server/services/EnumService.test.ts +192 -0
  158. package/lib/server/services/EnumService.ts +123 -0
  159. package/lib/server/services/VariableService.test.ts +183 -0
  160. package/lib/server/services/VariableService.ts +101 -0
  161. package/lib/server/services/cmsService.test.ts +792 -0
  162. package/lib/server/services/cmsService.ts +682 -0
  163. package/lib/server/services/componentService.test.ts +276 -0
  164. package/lib/server/services/componentService.ts +570 -0
  165. package/lib/server/services/configService.test.ts +856 -0
  166. package/lib/server/services/configService.ts +271 -0
  167. package/lib/server/services/fileWatcherService.ts +125 -0
  168. package/lib/server/services/index.ts +10 -0
  169. package/lib/server/services/pageService.test.ts +258 -0
  170. package/lib/server/services/pageService.ts +402 -0
  171. package/lib/server/ssr/attributeBuilder.ts +90 -0
  172. package/lib/server/ssr/buildErrorOverlay.ts +341 -0
  173. package/lib/server/ssr/clientDataInjector.test.ts +337 -0
  174. package/lib/server/ssr/clientDataInjector.ts +161 -0
  175. package/lib/server/ssr/cmsSSRProcessor.ts +113 -0
  176. package/lib/server/ssr/cssCollector.ts +33 -0
  177. package/lib/server/ssr/errorOverlay.test.ts +73 -0
  178. package/lib/server/ssr/errorOverlay.ts +263 -0
  179. package/lib/server/ssr/htmlGenerator.test.ts +993 -0
  180. package/lib/server/ssr/htmlGenerator.ts +498 -0
  181. package/lib/server/ssr/imageMetadata.test.ts +168 -0
  182. package/lib/server/ssr/imageMetadata.ts +179 -0
  183. package/lib/server/ssr/index.ts +35 -0
  184. package/lib/server/ssr/jsCollector.test.ts +287 -0
  185. package/lib/server/ssr/jsCollector.ts +155 -0
  186. package/lib/server/ssr/metaTagGenerator.ts +137 -0
  187. package/lib/server/ssr/ssrRenderer.test.ts +3868 -0
  188. package/lib/server/ssr/ssrRenderer.ts +1718 -0
  189. package/lib/server/ssrRenderer.test.ts +2114 -0
  190. package/lib/server/ssrRenderer.ts +11 -0
  191. package/lib/server/utilityClassGenerator.ts +11 -0
  192. package/lib/server/utils/index.ts +5 -0
  193. package/lib/server/utils/jsonLineMapper.test.ts +100 -0
  194. package/lib/server/utils/jsonLineMapper.ts +166 -0
  195. package/lib/server/validateStyleCoverage.test.ts +9 -0
  196. package/lib/server/validateStyleCoverage.ts +163 -0
  197. package/lib/server/websocketManager.test.ts +9 -0
  198. package/lib/server/websocketManager.ts +135 -0
  199. package/lib/shared/attributeNodeUtils.test.ts +152 -0
  200. package/lib/shared/attributeNodeUtils.ts +73 -0
  201. package/lib/shared/breakpoints.test.ts +353 -0
  202. package/lib/shared/breakpoints.ts +172 -0
  203. package/lib/shared/cmsQueryParser.test.ts +288 -0
  204. package/lib/shared/cmsQueryParser.ts +188 -0
  205. package/lib/shared/colorConversions.test.ts +140 -0
  206. package/lib/shared/colorConversions.ts +181 -0
  207. package/lib/shared/colorProperties.test.ts +111 -0
  208. package/lib/shared/colorProperties.ts +40 -0
  209. package/lib/shared/colorVariableUtils.test.ts +319 -0
  210. package/lib/shared/colorVariableUtils.ts +97 -0
  211. package/lib/shared/constants.test.ts +175 -0
  212. package/lib/shared/constants.ts +177 -0
  213. package/lib/shared/cssGeneration.test.ts +192 -0
  214. package/lib/shared/cssGeneration.ts +903 -0
  215. package/lib/shared/cssProperties.test.ts +252 -0
  216. package/lib/shared/cssProperties.ts +470 -0
  217. package/lib/shared/elementClassName.test.ts +319 -0
  218. package/lib/shared/elementClassName.ts +102 -0
  219. package/lib/shared/elementUtils.test.ts +245 -0
  220. package/lib/shared/elementUtils.ts +90 -0
  221. package/lib/shared/errorLogger.test.ts +136 -0
  222. package/lib/shared/errorLogger.ts +87 -0
  223. package/lib/shared/errors.test.ts +99 -0
  224. package/lib/shared/errors.ts +50 -0
  225. package/lib/shared/expressionEvaluator.ts +161 -0
  226. package/lib/shared/fontLoader.test.ts +344 -0
  227. package/lib/shared/fontLoader.ts +158 -0
  228. package/lib/shared/globalTemplateContext.ts +45 -0
  229. package/lib/shared/gradientUtils.test.ts +183 -0
  230. package/lib/shared/gradientUtils.ts +184 -0
  231. package/lib/shared/i18n.test.ts +419 -0
  232. package/lib/shared/i18n.ts +312 -0
  233. package/lib/shared/index.ts +128 -0
  234. package/lib/shared/interactiveStyleMappings.test.ts +463 -0
  235. package/lib/shared/interactiveStyleMappings.ts +284 -0
  236. package/lib/shared/interactiveStyles.test.ts +486 -0
  237. package/lib/shared/interfaces/contentProvider.test.ts +9 -0
  238. package/lib/shared/interfaces/contentProvider.ts +124 -0
  239. package/lib/shared/itemTemplateUtils.test.ts +740 -0
  240. package/lib/shared/itemTemplateUtils.ts +472 -0
  241. package/lib/shared/libraryLoader.test.ts +503 -0
  242. package/lib/shared/libraryLoader.ts +252 -0
  243. package/lib/shared/linkUtils.ts +24 -0
  244. package/lib/shared/nodeUtils.test.ts +543 -0
  245. package/lib/shared/nodeUtils.ts +419 -0
  246. package/lib/shared/pathArrayUtils.test.ts +315 -0
  247. package/lib/shared/pathArrayUtils.ts +17 -0
  248. package/lib/shared/pathSecurity.test.ts +156 -0
  249. package/lib/shared/pathSecurity.ts +95 -0
  250. package/lib/shared/pathUtils.test.ts +260 -0
  251. package/lib/shared/pathUtils.ts +244 -0
  252. package/lib/shared/paths/Path.test.ts +74 -0
  253. package/lib/shared/paths/Path.ts +23 -0
  254. package/lib/shared/paths/PathConverter.test.ts +232 -0
  255. package/lib/shared/paths/PathConverter.ts +141 -0
  256. package/lib/shared/paths/PathUtils.ts +290 -0
  257. package/lib/shared/paths/PathValidator.test.ts +193 -0
  258. package/lib/shared/paths/PathValidator.ts +53 -0
  259. package/lib/shared/paths/index.ts +48 -0
  260. package/lib/shared/propResolver.test.ts +744 -0
  261. package/lib/shared/propResolver.ts +211 -0
  262. package/lib/shared/registry/BaseNodeTypeRegistry.test.ts +190 -0
  263. package/lib/shared/registry/BaseNodeTypeRegistry.ts +200 -0
  264. package/lib/shared/registry/ClientNodeTypeRegistry.ts +34 -0
  265. package/lib/shared/registry/ClientRegistry.test.ts +26 -0
  266. package/lib/shared/registry/ClientRegistry.ts +15 -0
  267. package/lib/shared/registry/ComponentRegistry.test.ts +293 -0
  268. package/lib/shared/registry/ComponentRegistry.ts +100 -0
  269. package/lib/shared/registry/NodeTypeDefinition.ts +198 -0
  270. package/lib/shared/registry/NodeTypeManager.ts +94 -0
  271. package/lib/shared/registry/RegistryManager.test.ts +58 -0
  272. package/lib/shared/registry/RegistryManager.ts +60 -0
  273. package/lib/shared/registry/SSRNodeTypeRegistry.ts +33 -0
  274. package/lib/shared/registry/SSRRegistry.test.ts +26 -0
  275. package/lib/shared/registry/SSRRegistry.ts +15 -0
  276. package/lib/shared/registry/createNodeType.ts +175 -0
  277. package/lib/shared/registry/defineNodeType.ts +73 -0
  278. package/lib/shared/registry/fieldPresets.ts +109 -0
  279. package/lib/shared/registry/index.ts +51 -0
  280. package/lib/shared/registry/nodeTypes/ComponentInstanceNodeType.ts +75 -0
  281. package/lib/shared/registry/nodeTypes/EmbedNodeType.ts +67 -0
  282. package/lib/shared/registry/nodeTypes/HtmlNodeType.ts +92 -0
  283. package/lib/shared/registry/nodeTypes/LinkNodeType.ts +79 -0
  284. package/lib/shared/registry/nodeTypes/ListNodeType.ts +176 -0
  285. package/lib/shared/registry/nodeTypes/LocaleListNodeType.ts +72 -0
  286. package/lib/shared/registry/nodeTypes/SlotMarkerType.ts +55 -0
  287. package/lib/shared/registry/nodeTypes/index.ts +76 -0
  288. package/lib/shared/responsiveScaling.test.ts +368 -0
  289. package/lib/shared/responsiveScaling.ts +203 -0
  290. package/lib/shared/responsiveStyleUtils.test.ts +300 -0
  291. package/lib/shared/responsiveStyleUtils.ts +145 -0
  292. package/lib/shared/richtext/htmlToTiptap.test.ts +948 -0
  293. package/lib/shared/richtext/htmlToTiptap.ts +542 -0
  294. package/lib/shared/richtext/index.ts +8 -0
  295. package/lib/shared/richtext/tiptapToHtml.test.ts +322 -0
  296. package/lib/shared/richtext/tiptapToHtml.ts +448 -0
  297. package/lib/shared/richtext/types.ts +86 -0
  298. package/lib/shared/slugTranslator.test.ts +325 -0
  299. package/lib/shared/slugTranslator.ts +179 -0
  300. package/lib/shared/slugify.ts +118 -0
  301. package/lib/shared/styleNodeUtils.test.ts +132 -0
  302. package/lib/shared/styleNodeUtils.ts +102 -0
  303. package/lib/shared/styleUtils.test.ts +238 -0
  304. package/lib/shared/styleUtils.ts +63 -0
  305. package/lib/shared/styleValueRegistry.ts +106 -0
  306. package/lib/shared/themeDefaults.test.ts +163 -0
  307. package/lib/shared/themeDefaults.ts +129 -0
  308. package/lib/shared/tree/PathBuilder.test.ts +395 -0
  309. package/lib/shared/tree/PathBuilder.ts +409 -0
  310. package/lib/shared/treePathUtils.test.ts +539 -0
  311. package/lib/shared/treePathUtils.ts +357 -0
  312. package/lib/shared/types/api.ts +64 -0
  313. package/lib/shared/types/cms.ts +291 -0
  314. package/lib/shared/types/colors.ts +55 -0
  315. package/lib/shared/types/components.ts +188 -0
  316. package/lib/shared/types/config.ts +38 -0
  317. package/lib/shared/types/errors.test.ts +103 -0
  318. package/lib/shared/types/errors.ts +69 -0
  319. package/lib/shared/types/experiments.ts +55 -0
  320. package/lib/shared/types/index.ts +174 -0
  321. package/lib/shared/types/libraries.ts +80 -0
  322. package/lib/shared/types/nodes.ts +19 -0
  323. package/lib/shared/types/prefetch.ts +78 -0
  324. package/lib/shared/types/rendering.ts +62 -0
  325. package/lib/shared/types/styles.ts +83 -0
  326. package/lib/shared/types/variables.test.ts +132 -0
  327. package/lib/shared/types/variables.ts +215 -0
  328. package/lib/shared/types.ts +11 -0
  329. package/lib/shared/utilityClassConfig.ts +454 -0
  330. package/lib/shared/utilityClassMapper.test.ts +175 -0
  331. package/lib/shared/utilityClassMapper.ts +350 -0
  332. package/lib/shared/utils/fileUtils.test.ts +99 -0
  333. package/lib/shared/utils/fileUtils.ts +56 -0
  334. package/lib/shared/utils.test.ts +261 -0
  335. package/lib/shared/utils.ts +112 -0
  336. package/lib/shared/validation/cmsValidators.ts +38 -0
  337. package/lib/shared/validation/index.ts +8 -0
  338. package/lib/shared/validation/propValidator.test.ts +272 -0
  339. package/lib/shared/validation/propValidator.ts +265 -0
  340. package/lib/shared/validation/schemas.test.ts +177 -0
  341. package/lib/shared/validation/schemas.ts +641 -0
  342. package/lib/shared/validation/validators.test.ts +108 -0
  343. package/lib/shared/validation/validators.ts +304 -0
  344. package/lib/test-utils/dom-setup.ts +56 -0
  345. package/lib/test-utils/factories/ConsoleMockFactory.ts +200 -0
  346. package/lib/test-utils/factories/DomMockFactory.ts +487 -0
  347. package/lib/test-utils/factories/EventMockFactory.ts +244 -0
  348. package/lib/test-utils/factories/FetchMockFactory.ts +210 -0
  349. package/lib/test-utils/factories/ServerMockFactory.ts +223 -0
  350. package/lib/test-utils/factories/StoreMockFactory.ts +370 -0
  351. package/lib/test-utils/factories/index.ts +11 -0
  352. package/lib/test-utils/fixtures.ts +134 -0
  353. package/lib/test-utils/helpers/asyncHelpers.test.ts +112 -0
  354. package/lib/test-utils/helpers/asyncHelpers.ts +196 -0
  355. package/lib/test-utils/helpers/index.ts +6 -0
  356. package/lib/test-utils/helpers.test.ts +73 -0
  357. package/lib/test-utils/helpers.ts +90 -0
  358. package/lib/test-utils/index.ts +18 -0
  359. package/lib/test-utils/mockFactories.ts +92 -0
  360. package/lib/test-utils/mocks.ts +341 -0
  361. package/package.json +9 -24
  362. package/scripts/build-for-publish.mjs +64 -0
  363. package/scripts/build-meno-filter.ts +110 -0
  364. package/templates/index-router.html +34 -0
  365. package/tsconfig.json +14 -0
  366. package/vite.config.ts +43 -0
  367. package/dist/chunks/chunk-4KWEMYQE.js.map +0 -7
  368. package/dist/chunks/chunk-7ZZIWLUS.js.map +0 -7
  369. package/dist/chunks/chunk-HE67KV43.js.map +0 -7
  370. package/dist/chunks/chunk-INK4UWAN.js.map +0 -7
  371. package/dist/chunks/chunk-NBMAZOCJ.js.map +0 -7
  372. /package/dist/chunks/{chunk-M4B7T6NE.js.map → chunk-YSV4AG55.js.map} +0 -0
  373. /package/dist/chunks/{configService-UJGQY46I.js.map → configService-SASOCJRE.js.map} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npx tsc:*)"
5
+ ]
6
+ }
7
+ }
@@ -0,0 +1,424 @@
1
+ /**
2
+ * Tests for build-static.ts - Static Site Generation Build Script
3
+ *
4
+ * Tests pure/exported functions directly. Integration tests for buildStaticPages()
5
+ * require extensive mocking of the project context and are out of scope here.
6
+ */
7
+
8
+ import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
9
+ import { existsSync, mkdirSync, rmSync, readFileSync } from 'fs';
10
+ import { join } from 'path';
11
+ import { tmpdir } from 'os';
12
+ import {
13
+ hashContent,
14
+ formatBunLog,
15
+ getLocalizedOutputPath,
16
+ getDisplayPath,
17
+ isCMSPage,
18
+ buildCMSItemPath,
19
+ injectTrackingScript,
20
+ generateRobotsTxt,
21
+ generateSitemap,
22
+ } from './build-static';
23
+ import type { JSONPage, CMSItem, I18nConfig } from './lib/shared/types';
24
+
25
+ // ============================================================================
26
+ // Test Helpers
27
+ // ============================================================================
28
+
29
+ const TEST_DIR = join(tmpdir(), `build-static-test-${Date.now()}`);
30
+
31
+ function createTestDir(): string {
32
+ const dir = join(TEST_DIR, `sub-${Math.random().toString(36).slice(2, 8)}`);
33
+ mkdirSync(dir, { recursive: true });
34
+ return dir;
35
+ }
36
+
37
+ // ============================================================================
38
+ // hashContent
39
+ // ============================================================================
40
+
41
+ describe('hashContent', () => {
42
+ test('returns an 8-character hex string', () => {
43
+ const result = hashContent('hello world');
44
+ expect(result).toMatch(/^[0-9a-f]{8}$/);
45
+ });
46
+
47
+ test('is deterministic', () => {
48
+ expect(hashContent('test')).toBe(hashContent('test'));
49
+ });
50
+
51
+ test('different inputs produce different hashes', () => {
52
+ expect(hashContent('input-a')).not.toBe(hashContent('input-b'));
53
+ });
54
+
55
+ test('handles empty string', () => {
56
+ const result = hashContent('');
57
+ expect(result).toMatch(/^[0-9a-f]{8}$/);
58
+ });
59
+
60
+ test('handles unicode content', () => {
61
+ const result = hashContent('こんにちは世界');
62
+ expect(result).toMatch(/^[0-9a-f]{8}$/);
63
+ });
64
+ });
65
+
66
+ // ============================================================================
67
+ // formatBunLog
68
+ // ============================================================================
69
+
70
+ describe('formatBunLog', () => {
71
+ test('formats log with position info', () => {
72
+ const log = {
73
+ position: { file: 'src/app.ts', line: 42, column: 10, lineText: 'const x = y;' },
74
+ message: 'Variable not found'
75
+ };
76
+ const result = formatBunLog(log);
77
+ expect(result).toContain('File: src/app.ts');
78
+ expect(result).toContain('Line 42:10');
79
+ expect(result).toContain('const x = y;');
80
+ expect(result).toContain('Variable not found');
81
+ });
82
+
83
+ test('formats log with message only', () => {
84
+ const log = { message: 'Something went wrong' };
85
+ const result = formatBunLog(log);
86
+ expect(result).toBe('Something went wrong');
87
+ });
88
+
89
+ test('formats log with text property', () => {
90
+ const log = { text: 'Warning: deprecated function' };
91
+ const result = formatBunLog(log);
92
+ expect(result).toBe('Warning: deprecated function');
93
+ });
94
+
95
+ test('falls back to JSON.stringify when no extractable fields', () => {
96
+ const log = { custom: 'data', nested: { value: 1 } };
97
+ const result = formatBunLog(log);
98
+ expect(result).toContain('"custom"');
99
+ expect(result).toContain('"data"');
100
+ });
101
+
102
+ test('falls back to String() for non-serializable', () => {
103
+ const circular: any = {};
104
+ circular.self = circular;
105
+ // Should not throw
106
+ const result = formatBunLog(circular);
107
+ expect(typeof result).toBe('string');
108
+ });
109
+
110
+ test('handles position without lineText', () => {
111
+ const log = {
112
+ position: { file: 'index.ts', line: 1 },
113
+ message: 'Error'
114
+ };
115
+ const result = formatBunLog(log);
116
+ expect(result).toContain('File: index.ts');
117
+ expect(result).toContain('Line 1:0');
118
+ expect(result).toContain('Error');
119
+ });
120
+ });
121
+
122
+ // ============================================================================
123
+ // getLocalizedOutputPath
124
+ // ============================================================================
125
+
126
+ describe('getLocalizedOutputPath', () => {
127
+ const dist = '/project/dist';
128
+
129
+ test('root path with default locale', () => {
130
+ expect(getLocalizedOutputPath('/', 'en', 'en', dist)).toBe('/project/dist/index.html');
131
+ });
132
+
133
+ test('nested path with default locale', () => {
134
+ expect(getLocalizedOutputPath('/about', 'en', 'en', dist)).toBe('/project/dist/about.html');
135
+ });
136
+
137
+ test('root path with non-default locale', () => {
138
+ expect(getLocalizedOutputPath('/', 'fr', 'en', dist)).toBe('/project/dist/fr/index.html');
139
+ });
140
+
141
+ test('nested path with non-default locale', () => {
142
+ expect(getLocalizedOutputPath('/about', 'fr', 'en', dist)).toBe('/project/dist/fr/about.html');
143
+ });
144
+
145
+ test('uses translated slug when available', () => {
146
+ const slugs = { en: 'about', fr: 'a-propos' };
147
+ expect(getLocalizedOutputPath('/about', 'fr', 'en', dist, slugs)).toBe('/project/dist/fr/a-propos.html');
148
+ });
149
+
150
+ test('translated slug for default locale', () => {
151
+ const slugs = { en: 'about-us', fr: 'a-propos' };
152
+ expect(getLocalizedOutputPath('/about', 'en', 'en', dist, slugs)).toBe('/project/dist/about-us.html');
153
+ });
154
+
155
+ test('falls back to base path when locale has no slug', () => {
156
+ const slugs = { en: 'about' };
157
+ expect(getLocalizedOutputPath('/about', 'de', 'en', dist, slugs)).toBe('/project/dist/de/about.html');
158
+ });
159
+
160
+ test('deep nested path with default locale', () => {
161
+ expect(getLocalizedOutputPath('/blog/post', 'en', 'en', dist)).toBe('/project/dist/blog/post.html');
162
+ });
163
+ });
164
+
165
+ // ============================================================================
166
+ // getDisplayPath
167
+ // ============================================================================
168
+
169
+ describe('getDisplayPath', () => {
170
+ test('root path with default locale returns /', () => {
171
+ expect(getDisplayPath('/', 'en', 'en')).toBe('/');
172
+ });
173
+
174
+ test('nested path with default locale', () => {
175
+ expect(getDisplayPath('/about', 'en', 'en')).toBe('/about');
176
+ });
177
+
178
+ test('root path with non-default locale', () => {
179
+ expect(getDisplayPath('/', 'fr', 'en')).toBe('/fr');
180
+ });
181
+
182
+ test('nested path with non-default locale', () => {
183
+ expect(getDisplayPath('/about', 'fr', 'en')).toBe('/fr/about');
184
+ });
185
+
186
+ test('uses translated slug', () => {
187
+ const slugs = { en: 'about', fr: 'a-propos' };
188
+ expect(getDisplayPath('/about', 'fr', 'en', slugs)).toBe('/fr/a-propos');
189
+ });
190
+
191
+ test('translated slug for default locale', () => {
192
+ const slugs = { en: 'about-us', fr: 'a-propos' };
193
+ expect(getDisplayPath('/about', 'en', 'en', slugs)).toBe('/about-us');
194
+ });
195
+
196
+ test('falls back to base path when slug missing for locale', () => {
197
+ const slugs = { en: 'about' };
198
+ expect(getDisplayPath('/about', 'de', 'en', slugs)).toBe('/de/about');
199
+ });
200
+ });
201
+
202
+ // ============================================================================
203
+ // isCMSPage
204
+ // ============================================================================
205
+
206
+ describe('isCMSPage', () => {
207
+ test('returns true when source is cms and cms config exists', () => {
208
+ const page = {
209
+ meta: {
210
+ source: 'cms',
211
+ cms: { id: 'blog', urlPattern: '/blog/{{slug}}', slugField: 'slug' }
212
+ },
213
+ nodes: []
214
+ } as unknown as JSONPage;
215
+ expect(isCMSPage(page)).toBe(true);
216
+ });
217
+
218
+ test('returns false when source is not cms', () => {
219
+ const page = {
220
+ meta: { title: 'About' },
221
+ nodes: []
222
+ } as unknown as JSONPage;
223
+ expect(isCMSPage(page)).toBe(false);
224
+ });
225
+
226
+ test('returns false when source is cms but cms config is missing', () => {
227
+ const page = {
228
+ meta: { source: 'cms' },
229
+ nodes: []
230
+ } as unknown as JSONPage;
231
+ expect(isCMSPage(page)).toBe(false);
232
+ });
233
+
234
+ test('returns false when meta is missing', () => {
235
+ const page = { nodes: [] } as unknown as JSONPage;
236
+ expect(isCMSPage(page)).toBe(false);
237
+ });
238
+
239
+ test('returns false when meta is undefined', () => {
240
+ const page = { meta: undefined, nodes: [] } as unknown as JSONPage;
241
+ expect(isCMSPage(page)).toBe(false);
242
+ });
243
+ });
244
+
245
+ // ============================================================================
246
+ // buildCMSItemPath
247
+ // ============================================================================
248
+
249
+ describe('buildCMSItemPath', () => {
250
+ const defaultI18nConfig: I18nConfig = {
251
+ defaultLocale: 'en',
252
+ locales: [{ code: 'en', name: 'English' }, { code: 'fr', name: 'French' }]
253
+ };
254
+
255
+ test('replaces {{slug}} with item slug field', () => {
256
+ const item: CMSItem = { _id: '1', _slug: 'my-post', title: 'My Post' };
257
+ const result = buildCMSItemPath('/blog/{{slug}}', item, '_slug', 'en', defaultI18nConfig);
258
+ expect(result).toBe('/blog/my-post');
259
+ });
260
+
261
+ test('uses specified slugField', () => {
262
+ const item: CMSItem = { _id: '1', _slug: 'fallback', customSlug: 'custom-value', title: 'Test' };
263
+ const result = buildCMSItemPath('/posts/{{slug}}', item, 'customSlug', 'en', defaultI18nConfig);
264
+ expect(result).toBe('/posts/custom-value');
265
+ });
266
+
267
+ test('falls back to _slug when slugField is missing', () => {
268
+ const item: CMSItem = { _id: '1', _slug: 'fallback-slug', title: 'Test' };
269
+ const result = buildCMSItemPath('/posts/{{slug}}', item, 'nonexistent', 'en', defaultI18nConfig);
270
+ expect(result).toBe('/posts/fallback-slug');
271
+ });
272
+
273
+ test('falls back to _id when both slugField and _slug are missing', () => {
274
+ const item: CMSItem = { _id: 'abc123', title: 'Test' };
275
+ const result = buildCMSItemPath('/items/{{slug}}', item, 'missing', 'en', defaultI18nConfig);
276
+ expect(result).toBe('/items/abc123');
277
+ });
278
+
279
+ test('handles i18n slug values', () => {
280
+ const item: CMSItem = {
281
+ _id: '1',
282
+ _slug: { _i18n: true, en: 'hello', fr: 'bonjour' },
283
+ title: 'Test'
284
+ };
285
+ const result = buildCMSItemPath('/page/{{slug}}', item, '_slug', 'fr', defaultI18nConfig);
286
+ expect(result).toBe('/page/bonjour');
287
+ });
288
+
289
+ test('resolves i18n slug for default locale', () => {
290
+ const item: CMSItem = {
291
+ _id: '1',
292
+ _slug: { _i18n: true, en: 'hello', fr: 'bonjour' },
293
+ title: 'Test'
294
+ };
295
+ const result = buildCMSItemPath('/page/{{slug}}', item, '_slug', 'en', defaultI18nConfig);
296
+ expect(result).toBe('/page/hello');
297
+ });
298
+
299
+ test('handles numeric slug values', () => {
300
+ const item: CMSItem = { _id: '42', title: 'Test' };
301
+ const result = buildCMSItemPath('/item/{{slug}}', item, '_id', 'en', defaultI18nConfig);
302
+ expect(result).toBe('/item/42');
303
+ });
304
+ });
305
+
306
+ // ============================================================================
307
+ // injectTrackingScript
308
+ // ============================================================================
309
+
310
+ describe('injectTrackingScript', () => {
311
+ test('injects script before </head>', () => {
312
+ const html = '<html><head><title>Test</title></head><body></body></html>';
313
+ const script = 'console.log("tracking")';
314
+ const result = injectTrackingScript(html, script);
315
+ expect(result).toContain('<script>console.log("tracking")</script>\n</head>');
316
+ });
317
+
318
+ test('preserves existing head content', () => {
319
+ const html = '<html><head><meta charset="utf-8"><link rel="stylesheet" href="style.css"></head><body></body></html>';
320
+ const script = 'track()';
321
+ const result = injectTrackingScript(html, script);
322
+ expect(result).toContain('<meta charset="utf-8">');
323
+ expect(result).toContain('<link rel="stylesheet" href="style.css">');
324
+ expect(result).toContain('<script>track()</script>');
325
+ });
326
+
327
+ test('returns original html if no </head> tag', () => {
328
+ const html = '<html><body>no head</body></html>';
329
+ const script = 'track()';
330
+ const result = injectTrackingScript(html, script);
331
+ expect(result).toBe(html);
332
+ });
333
+ });
334
+
335
+ // ============================================================================
336
+ // generateRobotsTxt
337
+ // ============================================================================
338
+
339
+ describe('generateRobotsTxt', () => {
340
+ test('generates robots.txt with correct content', async () => {
341
+ const dir = createTestDir();
342
+ await generateRobotsTxt('https://example.com', dir);
343
+
344
+ const content = readFileSync(join(dir, 'robots.txt'), 'utf-8');
345
+ expect(content).toContain('User-agent: *');
346
+ expect(content).toContain('Allow: /');
347
+ expect(content).toContain('Sitemap: https://example.com/sitemap.xml');
348
+ });
349
+
350
+ test('uses provided siteUrl in sitemap reference', async () => {
351
+ const dir = createTestDir();
352
+ await generateRobotsTxt('https://mysite.dev', dir);
353
+
354
+ const content = readFileSync(join(dir, 'robots.txt'), 'utf-8');
355
+ expect(content).toContain('Sitemap: https://mysite.dev/sitemap.xml');
356
+ });
357
+ });
358
+
359
+ // ============================================================================
360
+ // generateSitemap
361
+ // ============================================================================
362
+
363
+ describe('generateSitemap', () => {
364
+ test('generates valid XML sitemap', async () => {
365
+ const dir = createTestDir();
366
+ const urls = ['/', '/about', '/contact'];
367
+ await generateSitemap(urls, 'https://example.com', dir);
368
+
369
+ const content = readFileSync(join(dir, 'sitemap.xml'), 'utf-8');
370
+ expect(content).toContain('<?xml version="1.0" encoding="UTF-8"?>');
371
+ expect(content).toContain('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');
372
+ expect(content).toContain('<url><loc>https://example.com/</loc></url>');
373
+ expect(content).toContain('<url><loc>https://example.com/about</loc></url>');
374
+ expect(content).toContain('<url><loc>https://example.com/contact</loc></url>');
375
+ });
376
+
377
+ test('sorts URLs for deterministic output', async () => {
378
+ const dir = createTestDir();
379
+ const urls = ['/z-page', '/a-page', '/m-page'];
380
+ await generateSitemap(urls, 'https://example.com', dir);
381
+
382
+ const content = readFileSync(join(dir, 'sitemap.xml'), 'utf-8');
383
+ const aIdx = content.indexOf('/a-page');
384
+ const mIdx = content.indexOf('/m-page');
385
+ const zIdx = content.indexOf('/z-page');
386
+ expect(aIdx).toBeLessThan(mIdx);
387
+ expect(mIdx).toBeLessThan(zIdx);
388
+ });
389
+
390
+ test('handles empty URL list', async () => {
391
+ const dir = createTestDir();
392
+ await generateSitemap([], 'https://example.com', dir);
393
+
394
+ const content = readFileSync(join(dir, 'sitemap.xml'), 'utf-8');
395
+ expect(content).toContain('<urlset');
396
+ expect(content).toContain('</urlset>');
397
+ // No <url> entries
398
+ expect(content).not.toContain('<url>');
399
+ });
400
+
401
+ test('handles single URL', async () => {
402
+ const dir = createTestDir();
403
+ await generateSitemap(['/'], 'https://example.com', dir);
404
+
405
+ const content = readFileSync(join(dir, 'sitemap.xml'), 'utf-8');
406
+ expect(content).toContain('<url><loc>https://example.com/</loc></url>');
407
+ });
408
+
409
+ test('does not mutate input array', async () => {
410
+ const dir = createTestDir();
411
+ const urls = ['/c', '/a', '/b'];
412
+ const original = [...urls];
413
+ await generateSitemap(urls, 'https://example.com', dir);
414
+ expect(urls).toEqual(original);
415
+ });
416
+ });
417
+
418
+ // ============================================================================
419
+ // Cleanup
420
+ // ============================================================================
421
+
422
+ afterEach(() => {
423
+ // Cleanup is done per-test via createTestDir
424
+ });