meno-core 1.0.53 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (415) hide show
  1. package/.claude/settings.local.json +1 -3
  2. package/bin/cli.ts +66 -261
  3. package/build-astro.ts +150 -128
  4. package/dist/bin/cli.js +42 -185
  5. package/dist/bin/cli.js.map +2 -2
  6. package/dist/chunks/chunk-2AR55GYH.js +42 -0
  7. package/dist/chunks/chunk-2AR55GYH.js.map +7 -0
  8. package/dist/chunks/{chunk-JGWFTO6P.js → chunk-2IIQK7T3.js} +2624 -1389
  9. package/dist/chunks/chunk-2IIQK7T3.js.map +7 -0
  10. package/dist/chunks/chunk-4ZRU52J2.js +169 -0
  11. package/dist/chunks/chunk-4ZRU52J2.js.map +7 -0
  12. package/dist/chunks/{chunk-UB44F4Z2.js → chunk-5X4HCN7J.js} +5 -7
  13. package/dist/chunks/chunk-5X4HCN7J.js.map +7 -0
  14. package/dist/chunks/{chunk-WQFG7PAH.js → chunk-7CCVOL5M.js} +15 -19
  15. package/dist/chunks/chunk-7CCVOL5M.js.map +7 -0
  16. package/dist/chunks/{chunk-YBLHKYFF.js → chunk-AR7LHIFY.js} +8 -2
  17. package/dist/chunks/chunk-AR7LHIFY.js.map +7 -0
  18. package/dist/chunks/{chunk-O3NAGJP4.js → chunk-NUP7H7D3.js} +135 -41
  19. package/dist/chunks/chunk-NUP7H7D3.js.map +7 -0
  20. package/dist/chunks/{chunk-X754AHS5.js → chunk-QWTQZHG3.js} +194 -90
  21. package/dist/chunks/chunk-QWTQZHG3.js.map +7 -0
  22. package/dist/chunks/{chunk-H3GJ4H2U.js → chunk-XTKNX4FW.js} +216 -87
  23. package/dist/chunks/chunk-XTKNX4FW.js.map +7 -0
  24. package/dist/chunks/{fs-JGINUXGL.js → fs-G3ANWEFP.js} +2 -2
  25. package/dist/lib/client/index.js +1003 -475
  26. package/dist/lib/client/index.js.map +3 -3
  27. package/dist/lib/server/index.js +14393 -6371
  28. package/dist/lib/server/index.js.map +4 -4
  29. package/dist/lib/shared/index.js +342 -101
  30. package/dist/lib/shared/index.js.map +4 -4
  31. package/dist/lib/shared/richtext/index.js +1 -1
  32. package/dist/lib/test-utils/index.js +64 -80
  33. package/dist/lib/test-utils/index.js.map +2 -2
  34. package/entries/client-router.tsx +10 -8
  35. package/lib/client/ClientInitializer.ts +8 -8
  36. package/lib/client/ErrorBoundary.test.tsx +246 -186
  37. package/lib/client/ErrorBoundary.tsx +183 -132
  38. package/lib/client/componentRegistry.test.ts +96 -108
  39. package/lib/client/componentRegistry.ts +1 -3
  40. package/lib/client/contexts/ThemeContext.tsx +3 -2
  41. package/lib/client/core/ComponentBuilder.test.ts +663 -560
  42. package/lib/client/core/ComponentBuilder.ts +427 -155
  43. package/lib/client/core/ComponentRenderer.test.tsx +2 -4
  44. package/lib/client/core/ComponentRenderer.tsx +46 -33
  45. package/lib/client/core/builders/embedBuilder.ts +242 -54
  46. package/lib/client/core/builders/linkBuilder.ts +72 -45
  47. package/lib/client/core/builders/linkNodeBuilder.ts +79 -54
  48. package/lib/client/core/builders/listBuilder.ts +155 -89
  49. package/lib/client/core/builders/localeListBuilder.ts +97 -62
  50. package/lib/client/core/builders/types.ts +5 -5
  51. package/lib/client/core/cmsTemplateProcessor.ts +8 -9
  52. package/lib/client/elementRegistry.ts +3 -3
  53. package/lib/client/fontFamiliesService.test.ts +2 -10
  54. package/lib/client/fontFamiliesService.ts +3 -3
  55. package/lib/client/hmr/HMRManager.tsx +47 -30
  56. package/lib/client/hmrCssReload.ts +49 -14
  57. package/lib/client/hmrWebSocket.ts +14 -19
  58. package/lib/client/hooks/useColorVariables.test.ts +21 -21
  59. package/lib/client/hooks/useColorVariables.ts +23 -18
  60. package/lib/client/hooks/usePropertyAutocomplete.ts +4 -6
  61. package/lib/client/hooks/useVariables.ts +6 -4
  62. package/lib/client/hydration/HydrationUtils.test.ts +24 -25
  63. package/lib/client/hydration/HydrationUtils.ts +3 -4
  64. package/lib/client/i18nConfigService.test.ts +2 -7
  65. package/lib/client/i18nConfigService.ts +2 -2
  66. package/lib/client/meno-filter/MenoFilter.test.ts +47 -49
  67. package/lib/client/meno-filter/MenoFilter.ts +14 -15
  68. package/lib/client/meno-filter/bindings.ts +18 -43
  69. package/lib/client/meno-filter/init.ts +4 -4
  70. package/lib/client/meno-filter/renderer.ts +30 -32
  71. package/lib/client/meno-filter/script.generated.ts +1 -3
  72. package/lib/client/meno-filter/ui.ts +4 -6
  73. package/lib/client/meno-filter/updates.ts +18 -23
  74. package/lib/client/meno-filter/utils.ts +1 -1
  75. package/lib/client/navigation.test.ts +174 -178
  76. package/lib/client/navigation.ts +0 -1
  77. package/lib/client/responsiveStyleResolver.knownTokens.test.ts +71 -0
  78. package/lib/client/responsiveStyleResolver.test.ts +234 -232
  79. package/lib/client/responsiveStyleResolver.ts +74 -20
  80. package/lib/client/routing/RouteLoader.test.ts +24 -25
  81. package/lib/client/routing/RouteLoader.ts +27 -35
  82. package/lib/client/routing/Router.tsx +210 -153
  83. package/lib/client/scripts/ScriptExecutor.test.ts +157 -158
  84. package/lib/client/scripts/ScriptExecutor.ts +18 -36
  85. package/lib/client/services/PrefetchService.test.ts +3 -3
  86. package/lib/client/services/PrefetchService.ts +23 -29
  87. package/lib/client/styleProcessor.test.ts +9 -9
  88. package/lib/client/styleProcessor.ts +24 -15
  89. package/lib/client/styles/StyleInjector.test.ts +122 -115
  90. package/lib/client/styles/StyleInjector.ts +10 -7
  91. package/lib/client/styles/UtilityClassCollector.ts +62 -28
  92. package/lib/client/styles/cspNonce.test.ts +2 -5
  93. package/lib/client/templateEngine.test.ts +554 -488
  94. package/lib/client/templateEngine.ts +203 -73
  95. package/lib/client/theme.test.ts +1 -1
  96. package/lib/client/theme.ts +0 -1
  97. package/lib/client/utils/toast.ts +0 -1
  98. package/lib/server/__integration__/api-routes.test.ts +8 -4
  99. package/lib/server/__integration__/cms-integration.test.ts +1 -4
  100. package/lib/server/__integration__/server-lifecycle.test.ts +4 -5
  101. package/lib/server/__integration__/ssr-rendering.test.ts +47 -37
  102. package/lib/server/__integration__/static-assets.test.ts +3 -3
  103. package/lib/server/__integration__/test-helpers.ts +87 -74
  104. package/lib/server/ab/generateFunctions.ts +12 -10
  105. package/lib/server/astro/cmsPageEmitter.ts +26 -42
  106. package/lib/server/astro/componentEmitter.ts +35 -43
  107. package/lib/server/astro/cssCollector.ts +10 -26
  108. package/lib/server/astro/nodeToAstro.test.ts +1754 -34
  109. package/lib/server/astro/nodeToAstro.ts +232 -216
  110. package/lib/server/astro/normalizeOrphanTemplateProps.test.ts +115 -119
  111. package/lib/server/astro/normalizeOrphanTemplateProps.ts +11 -18
  112. package/lib/server/astro/pageEmitter.ts +9 -13
  113. package/lib/server/astro/tailwindMapper.test.ts +10 -37
  114. package/lib/server/astro/tailwindMapper.ts +33 -40
  115. package/lib/server/astro/templateTransformer.ts +17 -20
  116. package/lib/server/createServer.ts +7 -19
  117. package/lib/server/cssGenerator.test.ts +35 -44
  118. package/lib/server/cssGenerator.ts +8 -19
  119. package/lib/server/fileWatcher.test.ts +164 -13
  120. package/lib/server/fileWatcher.ts +209 -124
  121. package/lib/server/index.ts +14 -17
  122. package/lib/server/jsonLoader.test.ts +39 -2
  123. package/lib/server/jsonLoader.ts +39 -34
  124. package/lib/server/middleware/cors.test.ts +21 -21
  125. package/lib/server/middleware/cors.ts +28 -4
  126. package/lib/server/middleware/errorHandler.test.ts +7 -5
  127. package/lib/server/middleware/errorHandler.ts +3 -8
  128. package/lib/server/middleware/index.ts +0 -1
  129. package/lib/server/middleware/logger.test.ts +10 -8
  130. package/lib/server/middleware/logger.ts +17 -29
  131. package/lib/server/migrateTemplates.ts +3 -3
  132. package/lib/server/pageCache.test.ts +76 -77
  133. package/lib/server/pageCache.ts +0 -1
  134. package/lib/server/projectContext.ts +5 -4
  135. package/lib/server/providers/fileSystemCMSProvider.test.ts +142 -99
  136. package/lib/server/providers/fileSystemCMSProvider.ts +62 -38
  137. package/lib/server/routes/api/cms.test.ts +26 -14
  138. package/lib/server/routes/api/cms.ts +9 -14
  139. package/lib/server/routes/api/colors.test.ts +2 -2
  140. package/lib/server/routes/api/components.ts +31 -35
  141. package/lib/server/routes/api/config.ts +3 -4
  142. package/lib/server/routes/api/core-routes.ts +49 -76
  143. package/lib/server/routes/api/enums.test.ts +2 -2
  144. package/lib/server/routes/api/functions.ts +9 -17
  145. package/lib/server/routes/api/index.ts +3 -6
  146. package/lib/server/routes/api/pages.ts +8 -11
  147. package/lib/server/routes/api/shared.test.ts +1 -1
  148. package/lib/server/routes/api/shared.ts +12 -9
  149. package/lib/server/routes/api/variables.test.ts +3 -5
  150. package/lib/server/routes/api/variables.ts +1 -1
  151. package/lib/server/routes/index.ts +25 -28
  152. package/lib/server/routes/pages.ts +35 -31
  153. package/lib/server/routes/static.ts +17 -6
  154. package/lib/server/runtime/bundler.ts +98 -61
  155. package/lib/server/runtime/fs.ts +16 -26
  156. package/lib/server/runtime/httpServer.ts +8 -12
  157. package/lib/server/services/ColorService.test.ts +3 -3
  158. package/lib/server/services/ColorService.ts +37 -29
  159. package/lib/server/services/EnumService.test.ts +4 -8
  160. package/lib/server/services/EnumService.ts +11 -3
  161. package/lib/server/services/VariableService.test.ts +8 -12
  162. package/lib/server/services/VariableService.ts +11 -3
  163. package/lib/server/services/cmsService.test.ts +158 -120
  164. package/lib/server/services/cmsService.ts +36 -146
  165. package/lib/server/services/componentService.test.ts +125 -45
  166. package/lib/server/services/componentService.ts +70 -46
  167. package/lib/server/services/configService.test.ts +22 -45
  168. package/lib/server/services/configService.ts +50 -27
  169. package/lib/server/services/fileWatcherService.ts +42 -8
  170. package/lib/server/services/index.ts +0 -1
  171. package/lib/server/services/pageService.test.ts +8 -10
  172. package/lib/server/services/pageService.ts +32 -18
  173. package/lib/server/ssr/attributeBuilder.ts +18 -8
  174. package/lib/server/ssr/buildErrorOverlay.ts +11 -12
  175. package/lib/server/ssr/clientDataInjector.ts +7 -21
  176. package/lib/server/ssr/cmsSSRProcessor.ts +4 -8
  177. package/lib/server/ssr/cssCollector.ts +1 -1
  178. package/lib/server/ssr/errorOverlay.test.ts +1 -1
  179. package/lib/server/ssr/errorOverlay.ts +3 -9
  180. package/lib/server/ssr/htmlGenerator.nonce.test.ts +9 -14
  181. package/lib/server/ssr/htmlGenerator.test.ts +120 -44
  182. package/lib/server/ssr/htmlGenerator.ts +126 -91
  183. package/lib/server/ssr/imageMetadata.test.ts +3 -1
  184. package/lib/server/ssr/imageMetadata.ts +27 -21
  185. package/lib/server/ssr/jsCollector.test.ts +8 -18
  186. package/lib/server/ssr/jsCollector.ts +3 -8
  187. package/lib/server/ssr/liveReloadIntegration.test.ts +76 -36
  188. package/lib/server/ssr/metaTagGenerator.ts +2 -2
  189. package/lib/server/ssr/ssrRenderer.branches.test.ts +1103 -0
  190. package/lib/server/ssr/ssrRenderer.test.ts +316 -256
  191. package/lib/server/ssr/ssrRenderer.ts +795 -243
  192. package/lib/server/ssrRenderer.test.ts +1048 -954
  193. package/lib/server/utils/jsonLineMapper.test.ts +28 -28
  194. package/lib/server/utils/jsonLineMapper.ts +7 -7
  195. package/lib/server/validateStyleCoverage.ts +18 -21
  196. package/lib/server/websocketManager.ts +28 -19
  197. package/lib/shared/attributeNodeUtils.test.ts +15 -15
  198. package/lib/shared/attributeNodeUtils.ts +5 -12
  199. package/lib/shared/breakpoints.test.ts +5 -5
  200. package/lib/shared/breakpoints.ts +4 -11
  201. package/lib/shared/cmsQuery.test.ts +81 -0
  202. package/lib/shared/cmsQuery.ts +92 -0
  203. package/lib/shared/cmsQueryParser.test.ts +50 -42
  204. package/lib/shared/cmsQueryParser.ts +60 -38
  205. package/lib/shared/colorConversions.ts +9 -9
  206. package/lib/shared/colorVariableUtils.test.ts +27 -5
  207. package/lib/shared/colorVariableUtils.ts +21 -12
  208. package/lib/shared/componentRefs.ts +1 -5
  209. package/lib/shared/constants.test.ts +3 -3
  210. package/lib/shared/constants.ts +8 -8
  211. package/lib/shared/cssGeneration.test.ts +285 -144
  212. package/lib/shared/cssGeneration.ts +217 -531
  213. package/lib/shared/cssNamedColors.ts +152 -30
  214. package/lib/shared/cssProperties.test.ts +69 -70
  215. package/lib/shared/cssProperties.ts +298 -114
  216. package/lib/shared/elementClassName.test.ts +109 -109
  217. package/lib/shared/elementClassName.ts +3 -3
  218. package/lib/shared/elementUtils.ts +12 -16
  219. package/lib/shared/errorLogger.test.ts +12 -12
  220. package/lib/shared/errorLogger.ts +2 -10
  221. package/lib/shared/errors.test.ts +2 -13
  222. package/lib/shared/errors.ts +2 -8
  223. package/lib/shared/expressionEvaluator.test.ts +145 -0
  224. package/lib/shared/expressionEvaluator.ts +52 -24
  225. package/lib/shared/fontLoader.test.ts +32 -18
  226. package/lib/shared/fontLoader.ts +2 -2
  227. package/lib/shared/friendlyError.ts +2 -3
  228. package/lib/shared/gradientUtils.test.ts +3 -7
  229. package/lib/shared/gradientUtils.ts +17 -14
  230. package/lib/shared/hrefRefs.test.ts +2 -2
  231. package/lib/shared/hrefRefs.ts +2 -10
  232. package/lib/shared/i18n.test.ts +4 -4
  233. package/lib/shared/i18n.ts +18 -38
  234. package/lib/shared/index.ts +27 -0
  235. package/lib/shared/inlineSvgStyleRules.ts +14 -13
  236. package/lib/shared/interactiveStyleMappings.test.ts +32 -54
  237. package/lib/shared/interactiveStyleMappings.ts +11 -24
  238. package/lib/shared/interactiveStyles.test.ts +165 -188
  239. package/lib/shared/interfaces/contentProvider.ts +1 -1
  240. package/lib/shared/itemTemplateUtils.test.ts +11 -17
  241. package/lib/shared/itemTemplateUtils.ts +27 -39
  242. package/lib/shared/jsonRepair.ts +16 -10
  243. package/lib/shared/libraryLoader.test.ts +21 -55
  244. package/lib/shared/libraryLoader.ts +7 -22
  245. package/lib/shared/linkUtils.ts +1 -1
  246. package/lib/shared/logger.test.ts +66 -0
  247. package/lib/shared/logger.ts +94 -0
  248. package/lib/shared/markdown.ts +25 -0
  249. package/lib/shared/netlifyLocale404.test.ts +179 -0
  250. package/lib/shared/netlifyLocale404.ts +110 -0
  251. package/lib/shared/nodeUtils.test.ts +28 -16
  252. package/lib/shared/nodeUtils.ts +76 -23
  253. package/lib/shared/pathArrayUtils.test.ts +1 -2
  254. package/lib/shared/pathArrayUtils.ts +1 -1
  255. package/lib/shared/pathSecurity.ts +2 -2
  256. package/lib/shared/pathUtils.test.ts +4 -6
  257. package/lib/shared/pathUtils.ts +42 -49
  258. package/lib/shared/paths/Path.test.ts +2 -2
  259. package/lib/shared/paths/Path.ts +0 -1
  260. package/lib/shared/paths/PathConverter.test.ts +1 -1
  261. package/lib/shared/paths/PathConverter.ts +17 -20
  262. package/lib/shared/paths/PathUtils.ts +13 -13
  263. package/lib/shared/paths/PathValidator.test.ts +2 -15
  264. package/lib/shared/paths/PathValidator.ts +12 -10
  265. package/lib/shared/paths/index.ts +1 -2
  266. package/lib/shared/permissions.test.ts +168 -0
  267. package/lib/shared/permissions.ts +162 -0
  268. package/lib/shared/propResolver.test.ts +240 -244
  269. package/lib/shared/propResolver.ts +15 -26
  270. package/lib/shared/pxToRem.test.ts +7 -6
  271. package/lib/shared/pxToRem.ts +2 -5
  272. package/lib/shared/registry/BaseNodeTypeRegistry.test.ts +12 -6
  273. package/lib/shared/registry/ClientRegistry.ts +0 -2
  274. package/lib/shared/registry/ComponentRegistry.test.ts +46 -32
  275. package/lib/shared/registry/ComponentRegistry.ts +12 -9
  276. package/lib/shared/registry/NodeTypeDefinition.ts +16 -9
  277. package/lib/shared/registry/RegistryManager.ts +1 -2
  278. package/lib/shared/registry/SSRRegistry.ts +0 -2
  279. package/lib/shared/registry/createNodeType.ts +7 -9
  280. package/lib/shared/registry/defineNodeType.ts +2 -6
  281. package/lib/shared/registry/fieldPresets.ts +3 -1
  282. package/lib/shared/registry/index.ts +0 -1
  283. package/lib/shared/registry/nodeTypes/ComponentInstanceNodeType.ts +14 -15
  284. package/lib/shared/registry/nodeTypes/CustomNodeType.ts +103 -0
  285. package/lib/shared/registry/nodeTypes/EmbedNodeType.ts +18 -11
  286. package/lib/shared/registry/nodeTypes/HtmlNodeType.ts +48 -19
  287. package/lib/shared/registry/nodeTypes/IslandNodeType.ts +129 -0
  288. package/lib/shared/registry/nodeTypes/LinkNodeType.ts +21 -19
  289. package/lib/shared/registry/nodeTypes/ListNodeType.ts +117 -77
  290. package/lib/shared/registry/nodeTypes/LocaleListNodeType.ts +27 -21
  291. package/lib/shared/registry/nodeTypes/MarkdownNodeType.ts +78 -0
  292. package/lib/shared/registry/nodeTypes/SlotMarkerType.ts +12 -8
  293. package/lib/shared/registry/nodeTypes/index.ts +26 -3
  294. package/lib/shared/responsiveScaling.test.ts +16 -34
  295. package/lib/shared/responsiveScaling.ts +61 -42
  296. package/lib/shared/responsiveStyleUtils.test.ts +0 -1
  297. package/lib/shared/responsiveStyleUtils.ts +11 -13
  298. package/lib/shared/richtext/htmlToTiptap.test.ts +139 -130
  299. package/lib/shared/richtext/htmlToTiptap.ts +2 -4
  300. package/lib/shared/richtext/tiptapToHtml.test.ts +5 -6
  301. package/lib/shared/richtext/types.ts +1 -8
  302. package/lib/shared/slugTranslator.test.ts +13 -13
  303. package/lib/shared/slugTranslator.ts +12 -16
  304. package/lib/shared/slugify.ts +9 -15
  305. package/lib/shared/styleNodeUtils.test.ts +8 -8
  306. package/lib/shared/styleNodeUtils.ts +18 -20
  307. package/lib/shared/styleUtils.test.ts +87 -61
  308. package/lib/shared/styleUtils.ts +5 -6
  309. package/lib/shared/themeDefaults.test.ts +11 -14
  310. package/lib/shared/themeDefaults.ts +3 -4
  311. package/lib/shared/tree/PathBuilder.test.ts +63 -145
  312. package/lib/shared/tree/PathBuilder.ts +59 -47
  313. package/lib/shared/treePathUtils.test.ts +51 -12
  314. package/lib/shared/treePathUtils.ts +91 -60
  315. package/lib/shared/types/api.ts +105 -8
  316. package/lib/shared/types/cms.test.ts +34 -0
  317. package/lib/shared/types/cms.ts +90 -34
  318. package/lib/shared/types/comment.ts +49 -16
  319. package/lib/shared/types/components.ts +51 -25
  320. package/lib/shared/types/errors.test.ts +1 -6
  321. package/lib/shared/types/errors.ts +3 -7
  322. package/lib/shared/types/experiments.ts +28 -28
  323. package/lib/shared/types/index.ts +25 -2
  324. package/lib/shared/types/permissions.ts +139 -0
  325. package/lib/shared/types/styles.ts +0 -1
  326. package/lib/shared/types/variables.test.ts +4 -13
  327. package/lib/shared/types/variables.ts +51 -30
  328. package/lib/shared/types.ts +1 -2
  329. package/lib/shared/utilityClassConfig.ts +751 -321
  330. package/lib/shared/utilityClassMapper.durability.test.ts +117 -0
  331. package/lib/shared/utilityClassMapper.test.ts +433 -95
  332. package/lib/shared/utilityClassMapper.ts +322 -249
  333. package/lib/shared/utilityClassNames.test.ts +38 -0
  334. package/lib/shared/utilityClassNames.ts +458 -0
  335. package/lib/shared/utils.test.ts +2 -10
  336. package/lib/shared/utils.ts +19 -10
  337. package/lib/shared/validation/cmsValidators.ts +2 -1
  338. package/lib/shared/validation/commentValidators.test.ts +53 -0
  339. package/lib/shared/validation/commentValidators.ts +12 -1
  340. package/lib/shared/validation/index.ts +1 -0
  341. package/lib/shared/validation/permissionsValidators.test.ts +49 -0
  342. package/lib/shared/validation/permissionsValidators.ts +49 -0
  343. package/lib/shared/validation/propValidator.test.ts +19 -21
  344. package/lib/shared/validation/propValidator.ts +13 -18
  345. package/lib/shared/validation/schemas.test.ts +64 -32
  346. package/lib/shared/validation/schemas.ts +616 -345
  347. package/lib/shared/validation/validators.test.ts +3 -8
  348. package/lib/shared/validation/validators.ts +89 -68
  349. package/lib/shared/viewportUnits.integration.test.ts +14 -10
  350. package/lib/shared/viewportUnits.test.ts +24 -23
  351. package/lib/shared/viewportUnits.ts +12 -5
  352. package/lib/test-utils/dom-setup.ts +1 -1
  353. package/lib/test-utils/factories/ConsoleMockFactory.ts +10 -14
  354. package/lib/test-utils/factories/DomMockFactory.ts +17 -23
  355. package/lib/test-utils/factories/EventMockFactory.ts +7 -13
  356. package/lib/test-utils/factories/FetchMockFactory.ts +39 -57
  357. package/lib/test-utils/factories/ServerMockFactory.ts +6 -10
  358. package/lib/test-utils/factories/StoreMockFactory.ts +18 -29
  359. package/lib/test-utils/fixtures.ts +45 -45
  360. package/lib/test-utils/helpers/asyncHelpers.test.ts +15 -18
  361. package/lib/test-utils/helpers/asyncHelpers.ts +11 -20
  362. package/lib/test-utils/helpers.ts +1 -5
  363. package/lib/test-utils/index.ts +0 -4
  364. package/lib/test-utils/mockFactories.ts +13 -19
  365. package/lib/test-utils/mocks.ts +6 -4
  366. package/package.json +3 -5
  367. package/scripts/build-for-publish.mjs +2 -4
  368. package/scripts/build-meno-filter.ts +4 -7
  369. package/tsconfig.json +1 -0
  370. package/vite.config.ts +4 -4
  371. package/build-next.ts +0 -1361
  372. package/build-static.test.ts +0 -424
  373. package/build-static.ts +0 -1074
  374. package/dist/build-static.js +0 -36
  375. package/dist/chunks/chunk-2MHDV5BF.js +0 -251
  376. package/dist/chunks/chunk-2MHDV5BF.js.map +0 -7
  377. package/dist/chunks/chunk-AZQYF6KE.js +0 -559
  378. package/dist/chunks/chunk-AZQYF6KE.js.map +0 -7
  379. package/dist/chunks/chunk-GZHGVVW3.js +0 -322
  380. package/dist/chunks/chunk-GZHGVVW3.js.map +0 -7
  381. package/dist/chunks/chunk-H3GJ4H2U.js.map +0 -7
  382. package/dist/chunks/chunk-I7YIGZXT.js +0 -467
  383. package/dist/chunks/chunk-I7YIGZXT.js.map +0 -7
  384. package/dist/chunks/chunk-IGYR22T6.js +0 -6192
  385. package/dist/chunks/chunk-IGYR22T6.js.map +0 -7
  386. package/dist/chunks/chunk-JGP5A3Y5.js +0 -1136
  387. package/dist/chunks/chunk-JGP5A3Y5.js.map +0 -7
  388. package/dist/chunks/chunk-JGWFTO6P.js.map +0 -7
  389. package/dist/chunks/chunk-O3NAGJP4.js.map +0 -7
  390. package/dist/chunks/chunk-QB2LNO4W.js +0 -77
  391. package/dist/chunks/chunk-QB2LNO4W.js.map +0 -7
  392. package/dist/chunks/chunk-R6XHAFBF.js +0 -3821
  393. package/dist/chunks/chunk-R6XHAFBF.js.map +0 -7
  394. package/dist/chunks/chunk-UB44F4Z2.js.map +0 -7
  395. package/dist/chunks/chunk-WQFG7PAH.js.map +0 -7
  396. package/dist/chunks/chunk-X754AHS5.js.map +0 -7
  397. package/dist/chunks/chunk-YBLHKYFF.js.map +0 -7
  398. package/dist/chunks/configService-R3OGU2UD.js +0 -13
  399. package/dist/chunks/configService-R3OGU2UD.js.map +0 -7
  400. package/dist/chunks/constants-STK2YBIW.js +0 -46
  401. package/dist/chunks/constants-STK2YBIW.js.map +0 -7
  402. package/dist/chunks/fs-JGINUXGL.js.map +0 -7
  403. package/dist/entries/server-router.js +0 -67
  404. package/dist/entries/server-router.js.map +0 -7
  405. package/entries/server-router.tsx +0 -81
  406. package/lib/server/providers/fileSystemPageProvider.ts +0 -160
  407. package/lib/server/webflow/buildWebflow.ts +0 -635
  408. package/lib/server/webflow/index.ts +0 -23
  409. package/lib/server/webflow/nodeToWebflow.test.ts +0 -3170
  410. package/lib/server/webflow/nodeToWebflow.ts +0 -2435
  411. package/lib/server/webflow/styleMapper.test.ts +0 -389
  412. package/lib/server/webflow/styleMapper.ts +0 -695
  413. package/lib/server/webflow/templateWrapper.ts +0 -49
  414. package/lib/server/webflow/types.ts +0 -396
  415. /package/dist/{build-static.js.map → chunks/fs-G3ANWEFP.js.map} +0 -0
@@ -13,13 +13,22 @@ import { generateFontCSS, generateFontPreloadTags, loadProjectConfig } from '../
13
13
  import { colorService } from '../services/ColorService';
14
14
  import { generateThemeColorVariablesCSS, generateVariablesCSS } from '../cssGenerator';
15
15
  import { variableService } from '../services/VariableService';
16
- import { generateUtilityCSS, extractUtilityClassesFromHTML, generateAllInteractiveCSS } from '../../shared/cssGeneration';
16
+ import {
17
+ generateUtilityCSS,
18
+ extractUtilityClassesFromHTML,
19
+ generateAllInteractiveCSS,
20
+ } from '../../shared/cssGeneration';
17
21
  import { rewriteViewportUnits } from '../../shared/viewportUnits';
18
22
  import { printMissingStyleWarnings } from '../validateStyleCoverage';
19
23
  import { formHandlerScript, needsFormHandler } from '../../client/scripts/formHandler';
20
24
  import { menoFilterScript, needsMenoFilter } from '../../client/meno-filter/script.generated';
21
25
  import { generateAllInlineDataScripts, prepareClientData, type ClientDataCollection } from './clientDataInjector';
22
- import { mergeLibraries, generateLibraryTags, collectComponentLibraries, filterLibrariesByContext } from '../../shared/libraryLoader';
26
+ import {
27
+ mergeLibraries,
28
+ generateLibraryTags,
29
+ collectComponentLibraries,
30
+ filterLibrariesByContext,
31
+ } from '../../shared/libraryLoader';
23
32
  import { escapeHtml } from './attributeBuilder';
24
33
  import { renderPageSSR, type PreloadImage } from './ssrRenderer';
25
34
  import type { CMSContext } from './cmsSSRProcessor';
@@ -34,7 +43,10 @@ function generateImagePreloadTags(preloadImages: PreloadImage[]): string {
34
43
  if (preloadImages.length === 0) return '';
35
44
 
36
45
  return preloadImages
37
- .map(img => `<link rel="preload" as="image" type="${img.type}" imagesrcset="${escapeHtml(img.srcset)}" imagesizes="${escapeHtml(img.sizes)}" fetchpriority="high">`)
46
+ .map(
47
+ (img) =>
48
+ `<link rel="preload" as="image" type="${img.type}" imagesrcset="${escapeHtml(img.srcset)}" imagesizes="${escapeHtml(img.sizes)}" fetchpriority="high">`,
49
+ )
38
50
  .join('\n ');
39
51
  }
40
52
 
@@ -45,29 +57,31 @@ function generateImagePreloadTags(preloadImages: PreloadImage[]): string {
45
57
  function minifyCSS(code: string): string {
46
58
  if (!code.trim()) return code;
47
59
 
48
- return code
49
- // Remove CSS comments
50
- .replace(/\/\*[\s\S]*?\*\//g, '')
51
- // Remove whitespace around block / declaration delimiters and selector
52
- // combinators. We deliberately exclude `+` and `-` from this set: they
53
- // are selector combinators (e.g. `a + b`, but `~` is also rare; siblings)
54
- // AND arithmetic operators inside `calc()` / `clamp()` / `min()` / `max()`,
55
- // where they REQUIRE surrounding spaces. Stripping there produces invalid
56
- // CSS like `padding-top: clamp(.5*16px,((.5 - .5)/(90 - 20))*16px+(...))`,
57
- // which the browser silently drops, collapsing paddings/margins to 0.
58
- // The cost of leaving spaces around `+` selectors is a few extra bytes;
59
- // the cost of stripping them is broken layout.
60
- .replace(/\s*([{};:,>~])\s*/g, '$1')
61
- // Collapse multiple spaces/newlines into single space
62
- .replace(/\s+/g, ' ')
63
- // Remove space after opening brace
64
- .replace(/\{\s+/g, '{')
65
- // Remove space before closing brace
66
- .replace(/\s+\}/g, '}')
67
- // Remove trailing semicolons before closing braces
68
- .replace(/;}/g, '}')
69
- // Remove leading/trailing whitespace
70
- .trim();
60
+ return (
61
+ code
62
+ // Remove CSS comments
63
+ .replace(/\/\*[\s\S]*?\*\//g, '')
64
+ // Remove whitespace around block / declaration delimiters and selector
65
+ // combinators. We deliberately exclude `+` and `-` from this set: they
66
+ // are selector combinators (e.g. `a + b`, but `~` is also rare; siblings)
67
+ // AND arithmetic operators inside `calc()` / `clamp()` / `min()` / `max()`,
68
+ // where they REQUIRE surrounding spaces. Stripping there produces invalid
69
+ // CSS like `padding-top: clamp(.5*16px,((.5 - .5)/(90 - 20))*16px+(...))`,
70
+ // which the browser silently drops, collapsing paddings/margins to 0.
71
+ // The cost of leaving spaces around `+` selectors is a few extra bytes;
72
+ // the cost of stripping them is broken layout.
73
+ .replace(/\s*([{};:,>~])\s*/g, '$1')
74
+ // Collapse multiple spaces/newlines into single space
75
+ .replace(/\s+/g, ' ')
76
+ // Remove space after opening brace
77
+ .replace(/\{\s+/g, '{')
78
+ // Remove space before closing brace
79
+ .replace(/\s+\}/g, '}')
80
+ // Remove trailing semicolons before closing braces
81
+ .replace(/;}/g, '}')
82
+ // Remove leading/trailing whitespace
83
+ .trim()
84
+ );
71
85
  }
72
86
 
73
87
  /**
@@ -172,22 +186,20 @@ export async function generateSSRHTML(
172
186
  slugMappings?: SlugMap[],
173
187
  cmsContext?: CMSContext,
174
188
  cmsService?: CMSService,
175
- externalScriptPath?: string
189
+ externalScriptPath?: string,
176
190
  ): Promise<string>;
177
191
 
178
192
  /**
179
193
  * Generate complete HTML document with SSR content (options object, returns separate JS for CSP)
180
194
  */
181
195
  export async function generateSSRHTML(
182
- options: GenerateSSRHTMLOptions & { returnSeparateJS: true }
196
+ options: GenerateSSRHTMLOptions & { returnSeparateJS: true },
183
197
  ): Promise<SSRHTMLResult>;
184
198
 
185
199
  /**
186
200
  * Generate complete HTML document with SSR content (options object)
187
201
  */
188
- export async function generateSSRHTML(
189
- options: GenerateSSRHTMLOptions & { returnSeparateJS?: false }
190
- ): Promise<string>;
202
+ export async function generateSSRHTML(options: GenerateSSRHTMLOptions & { returnSeparateJS?: false }): Promise<string>;
191
203
 
192
204
  /**
193
205
  * Generate complete HTML document with SSR content
@@ -202,7 +214,7 @@ export async function generateSSRHTML(
202
214
  slugMappings?: SlugMap[],
203
215
  cmsContext?: CMSContext,
204
216
  cmsService?: CMSService,
205
- externalScriptPath?: string
217
+ externalScriptPath?: string,
206
218
  ): Promise<string | SSRHTMLResult> {
207
219
  // Handle options object vs legacy positional args
208
220
  let options: GenerateSSRHTMLOptions & { returnSeparateJS?: boolean };
@@ -255,16 +267,26 @@ export async function generateSSRHTML(
255
267
  // on injectEditorAttrs — set ONLY when the request comes from the editor preview iframe
256
268
  // via the studio's /__static__/ proxy (which sends an `x-meno-editor` header).
257
269
  // Direct hits to the SSR preview server (e.g., http://localhost:8082/) get clean output.
258
- const rendered = await renderPageSSR(pageData, components, path, base, loc, undefined, slugs, cms, cmsServ, isProductionBuild, injectEditorAttrs);
270
+ const rendered = await renderPageSSR(
271
+ pageData,
272
+ components,
273
+ path,
274
+ base,
275
+ loc,
276
+ undefined,
277
+ slugs,
278
+ cms,
279
+ cmsServ,
280
+ isProductionBuild,
281
+ injectEditorAttrs,
282
+ );
259
283
 
260
284
  // Auto-inject data for nested collections (detected during SSR)
261
285
  // This enables client-side hydration for nested cms-list placeholders
262
286
  let finalClientDataCollections = clientDataCollections;
263
287
  if (rendered.neededCollections.size > 0 && cmsServ) {
264
288
  // Create a mutable copy if we need to add collections
265
- finalClientDataCollections = clientDataCollections
266
- ? new Map(clientDataCollections)
267
- : new Map();
289
+ finalClientDataCollections = clientDataCollections ? new Map(clientDataCollections) : new Map();
268
290
 
269
291
  for (const collectionId of rendered.neededCollections) {
270
292
  // Skip if already provided
@@ -273,9 +295,7 @@ export async function generateSSRHTML(
273
295
  // Get schema to check if clientData is enabled
274
296
  const schema = cmsServ.getSchema(collectionId);
275
297
  if (!schema?.clientData?.enabled) {
276
- console.warn(
277
- `[SSR] Nested collection "${collectionId}" needs clientData.enabled for client-side hydration`
278
- );
298
+ console.warn(`[SSR] Nested collection "${collectionId}" needs clientData.enabled for client-side hydration`);
279
299
  continue;
280
300
  }
281
301
 
@@ -322,31 +342,33 @@ export async function generateSSRHTML(
322
342
  const seenJS = new Set<string>();
323
343
  const seenCSS = new Set<string>();
324
344
  const mergedLibraries = {
325
- js: (mergedRaw.js || []).filter(lib => {
345
+ js: (mergedRaw.js || []).filter((lib) => {
326
346
  if (seenJS.has(lib.url)) return false;
327
347
  seenJS.add(lib.url);
328
348
  return true;
329
349
  }),
330
- css: (mergedRaw.css || []).filter(lib => {
350
+ css: (mergedRaw.css || []).filter((lib) => {
331
351
  if (seenCSS.has(lib.url)) return false;
332
352
  seenCSS.add(lib.url);
333
353
  return true;
334
354
  }),
335
355
  };
336
- const libraryContext = isEditor ? 'editor' : (useBundled && !injectLiveReload ? 'build' : 'preview');
356
+ const libraryContext = isEditor ? 'editor' : useBundled && !injectLiveReload ? 'build' : 'preview';
337
357
  const filteredLibraries = filterLibrariesByContext(mergedLibraries, libraryContext);
338
358
 
339
359
  // Cache-bust local library URLs in dev/preview to avoid stale browser cache
340
360
  const devMode = !useBundled || injectLiveReload;
341
361
  const bustCache = devMode ? `?v=${Date.now()}` : '';
342
- const finalLibraries = bustCache ? {
343
- js: (filteredLibraries.js || []).map(lib =>
344
- lib.url.startsWith('/') ? { ...lib, url: lib.url + bustCache } : lib
345
- ),
346
- css: (filteredLibraries.css || []).map(lib =>
347
- lib.url.startsWith('/') ? { ...lib, url: lib.url + bustCache } : lib
348
- ),
349
- } : filteredLibraries;
362
+ const finalLibraries = bustCache
363
+ ? {
364
+ js: (filteredLibraries.js || []).map((lib) =>
365
+ lib.url.startsWith('/') ? { ...lib, url: lib.url + bustCache } : lib,
366
+ ),
367
+ css: (filteredLibraries.css || []).map((lib) =>
368
+ lib.url.startsWith('/') ? { ...lib, url: lib.url + bustCache } : lib,
369
+ ),
370
+ }
371
+ : filteredLibraries;
350
372
 
351
373
  // Read local CSS files for inline embedding
352
374
  const inlineContents = new Map<string, string>();
@@ -355,7 +377,7 @@ export async function generateSSRHTML(
355
377
  const shouldInline = css.inline !== false && css.url.startsWith('/');
356
378
  if (shouldInline) {
357
379
  try {
358
- const cleanUrl = css.url.split('?')[0]; // Strip cache-bust query param
380
+ const cleanUrl = css.url.split('?')[0] ?? css.url; // Strip cache-bust query param
359
381
  const filePath = resolveProjectPath(cleanUrl.slice(1));
360
382
  const content = await readTextFile(filePath);
361
383
  inlineContents.set(css.url, content);
@@ -375,12 +397,15 @@ export async function generateSSRHTML(
375
397
  // Collect all JavaScript (component JS + form handler + meno filter if needed)
376
398
  const needsForm = needsFormHandler(rendered.html);
377
399
  // Include MenoFilter if: inline clientData exists OR page has cms-list nodes (for static strategy)
378
- const needsFilter = (finalClientDataCollections && finalClientDataCollections.size > 0) || needsMenoFilter(rendered.html);
400
+ const needsFilter =
401
+ (finalClientDataCollections && finalClientDataCollections.size > 0) || needsMenoFilter(rendered.html);
379
402
  const allJavaScript = [
380
403
  rendered.javascript || '',
381
404
  needsForm ? formHandlerScript : '',
382
- needsFilter ? menoFilterScript : ''
383
- ].filter(Boolean).join('\n\n');
405
+ needsFilter ? menoFilterScript : '',
406
+ ]
407
+ .filter(Boolean)
408
+ .join('\n\n');
384
409
 
385
410
  // Determine script output based on mode
386
411
  let componentScript = '';
@@ -426,12 +451,23 @@ export async function generateSSRHTML(
426
451
  const variablesConfig = await variableService.loadConfig();
427
452
  const variablesCSS = generateVariablesCSS(variablesConfig, breakpointConfig, responsiveScalesConfig);
428
453
  const remConversionConfig = configService.getRemConversion();
429
- const utilityCSS = generateUtilityCSS(usedUtilityClasses, breakpointConfig, responsiveScalesConfig, remConversionConfig);
454
+ const utilityCSS = generateUtilityCSS(
455
+ usedUtilityClasses,
456
+ breakpointConfig,
457
+ responsiveScalesConfig,
458
+ remConversionConfig,
459
+ );
430
460
 
431
461
  // Generate interactive styles CSS from map collected during render
432
- const interactiveCSS = rendered.interactiveStylesMap.size > 0
433
- ? generateAllInteractiveCSS(rendered.interactiveStylesMap, breakpointConfig, remConversionConfig, responsiveScalesConfig)
434
- : '';
462
+ const interactiveCSS =
463
+ rendered.interactiveStylesMap.size > 0
464
+ ? generateAllInteractiveCSS(
465
+ rendered.interactiveStylesMap,
466
+ breakpointConfig,
467
+ remConversionConfig,
468
+ responsiveScalesConfig,
469
+ )
470
+ : '';
435
471
 
436
472
  // Print warnings for any unmapped styles found during build
437
473
  printMissingStyleWarnings(false);
@@ -469,18 +505,20 @@ picture {
469
505
  display: inline-block;
470
506
  vertical-align: top;
471
507
  line-height: 0;
508
+ }
509
+ /* line-height:0 above kills the inline-block descender gap (inline SVG/icon
510
+ embeds), but line-height inherits — so block rich-text inside an <Embed>
511
+ (CMS content: <p>/<li>/…) would collapse its text lines onto each other.
512
+ Restore a normal line-height on the embed's children. Astro play renders
513
+ rich-text bare (no .oem), which is why it looked correct only there. */
514
+ .oem > * {
515
+ line-height: normal;
472
516
  }`;
473
517
 
474
518
  // Combine all CSS
475
- const combinedCSS = [
476
- fontCSS,
477
- themeColorVariablesCSS,
478
- variablesCSS,
479
- baseCSS,
480
- componentCSS,
481
- utilityCSS,
482
- interactiveCSS
483
- ].filter(Boolean).join('\n');
519
+ const combinedCSS = [fontCSS, themeColorVariablesCSS, variablesCSS, baseCSS, componentCSS, utilityCSS, interactiveCSS]
520
+ .filter(Boolean)
521
+ .join('\n');
484
522
 
485
523
  // Rewrite vh/vw to calc(var(--design-vh, 1vh) * N) so the studio's design
486
524
  // canvas can pin viewport units to a stable height (avoids the
@@ -497,24 +535,27 @@ picture {
497
535
  const menoConfig = prefetchConfig.enabled ? { prefetch: prefetchConfig } : {};
498
536
  // Config script - inline for dev, include in external JS for static build
499
537
  const hasConfig = Object.keys(menoConfig).length > 0;
500
- const configInlineScript = hasConfig && !extScriptPath && !returnSeparateJS
501
- ? `<script${nonceAttr}>window.__MENO_CONFIG__=${JSON.stringify(menoConfig)}</script>\n `
502
- : '';
538
+ const configInlineScript =
539
+ hasConfig && !extScriptPath && !returnSeparateJS
540
+ ? `<script${nonceAttr}>window.__MENO_CONFIG__=${JSON.stringify(menoConfig)}</script>\n `
541
+ : '';
503
542
  // Add config to external JS if using external scripts
504
543
  if (hasConfig && externalJavaScript !== null) {
505
- externalJavaScript = `window.__MENO_CONFIG__=${JSON.stringify(menoConfig)};\n\n` + externalJavaScript;
544
+ externalJavaScript = `window.__MENO_CONFIG__=${JSON.stringify(menoConfig)};\n\n${externalJavaScript}`;
506
545
  }
507
546
 
508
547
  // CMS context script - needed when a client-side Router is present (dev mode or studio preview)
509
548
  // Production builds are pure HTML with no client routing, so excluded
510
- const cmsInlineScript = cmsTemplatePath && cms && (!useBundled || injectLiveReload)
511
- ? `<script${nonceAttr}>window.__MENO_CMS__=${JSON.stringify({ item: cms.cms, templatePath: cmsTemplatePath })}</script>\n `
512
- : '';
549
+ const cmsInlineScript =
550
+ cmsTemplatePath && cms && (!useBundled || injectLiveReload)
551
+ ? `<script${nonceAttr}>window.__MENO_CMS__=${JSON.stringify({ item: cms.cms, templatePath: cmsTemplatePath })}</script>\n `
552
+ : '';
513
553
 
514
554
  // Client data scripts - inline JSON for MenoFilter (production builds only)
515
- const clientDataScripts = finalClientDataCollections && finalClientDataCollections.size > 0
516
- ? generateAllInlineDataScripts(finalClientDataCollections) + '\n '
517
- : '';
555
+ const clientDataScripts =
556
+ finalClientDataCollections && finalClientDataCollections.size > 0
557
+ ? `${generateAllInlineDataScripts(finalClientDataCollections)}\n `
558
+ : '';
518
559
 
519
560
  // Generate favicon and apple touch icon link tags.
520
561
  // When a dark-mode favicon is configured alongside the default, scope the
@@ -534,17 +575,13 @@ picture {
534
575
  const iconTags = [faviconTag, faviconDarkTag, appleTouchIconTag].filter(Boolean).join('\n ');
535
576
 
536
577
  // Script preload tag - eliminates critical request chain by discovering script early
537
- const scriptPreloadTag = extScriptPath
538
- ? `<link rel="preload" href="${extScriptPath}" as="script">`
539
- : '';
578
+ const scriptPreloadTag = extScriptPath ? `<link rel="preload" href="${extScriptPath}" as="script">` : '';
540
579
 
541
580
  // Image preload tags for high-priority images (LCP optimization)
542
581
  const imagePreloadTags = generateImagePreloadTags(rendered.preloadImages);
543
582
 
544
583
  // Live reload script for on-demand SSR preview mode (in-place DOM update, no white flash)
545
- const wsUrl = serverPort
546
- ? `'ws://localhost:${serverPort}/hmr'`
547
- : `location.origin.replace('http','ws')+'/hmr'`;
584
+ const wsUrl = serverPort ? `'ws://localhost:${serverPort}/hmr'` : `location.origin.replace('http','ws')+'/hmr'`;
548
585
  // True hot reload for the studio's static preview iframe.
549
586
  //
550
587
  // The central question on every edit is: did the EDITOR change page
@@ -617,23 +654,21 @@ picture {
617
654
  : '';
618
655
 
619
656
  // In production, output minified CSS on single line; in dev, preserve formatting
620
- const styleContent = useBundled
621
- ? finalCSS
622
- : `\n ${combinedCSS.split('\n').join('\n ')}\n `;
657
+ const styleContent = useBundled ? finalCSS : `\n ${combinedCSS.split('\n').join('\n ')}\n `;
623
658
 
624
659
  const htmlDocument = `<!DOCTYPE html>
625
660
  <html lang="${rendered.locale}" theme="${themeConfig.default}">
626
661
  <head>
627
662
  <meta charset="UTF-8">
628
663
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
629
- ${cspNonce ? `<meta name="csp-nonce" content="${cspNonce}">\n ` : ''}${iconTags ? iconTags + '\n ' : ''}${scriptPreloadTag ? scriptPreloadTag + '\n ' : ''}${imagePreloadTags ? imagePreloadTags + '\n ' : ''}${fontPreloadTags ? fontPreloadTags + '\n ' : ''}${libraryTags.headCSS ? libraryTags.headCSS + '\n ' : ''}${libraryTags.headJS ? libraryTags.headJS + '\n ' : ''}${rendered.meta}
630
- ${configInlineScript}${cmsInlineScript}${clientDataScripts}<style id="meno-styles"${nonceAttr}>${styleContent}</style>${mergedCustomCode.head ? '\n ' + mergedCustomCode.head : ''}
664
+ ${cspNonce ? `<meta name="csp-nonce" content="${cspNonce}">\n ` : ''}${iconTags ? `${iconTags}\n ` : ''}${scriptPreloadTag ? `${scriptPreloadTag}\n ` : ''}${imagePreloadTags ? `${imagePreloadTags}\n ` : ''}${fontPreloadTags ? `${fontPreloadTags}\n ` : ''}${libraryTags.headCSS ? `${libraryTags.headCSS}\n ` : ''}${libraryTags.headJS ? `${libraryTags.headJS}\n ` : ''}${rendered.meta}
665
+ ${configInlineScript}${cmsInlineScript}${clientDataScripts}<style id="meno-styles"${nonceAttr}>${styleContent}</style>${mergedCustomCode.head ? `\n ${mergedCustomCode.head}` : ''}
631
666
  </head>
632
- <body>${mergedCustomCode.bodyStart ? '\n ' + mergedCustomCode.bodyStart : ''}
667
+ <body>${mergedCustomCode.bodyStart ? `\n ${mergedCustomCode.bodyStart}` : ''}
633
668
  <div id="root">
634
669
  ${rendered.html}
635
670
  </div>
636
- ${clientScript}${componentScript}${libraryTags.bodyEndJS ? '\n ' + libraryTags.bodyEndJS : ''}${liveReloadScript ? '\n ' + liveReloadScript : ''}${scrollHandlerScript ? '\n ' + scrollHandlerScript : ''}${mergedCustomCode.bodyEnd ? '\n ' + mergedCustomCode.bodyEnd : ''}
671
+ ${clientScript}${componentScript}${libraryTags.bodyEndJS ? `\n ${libraryTags.bodyEndJS}` : ''}${liveReloadScript ? `\n ${liveReloadScript}` : ''}${scrollHandlerScript ? `\n ${scrollHandlerScript}` : ''}${mergedCustomCode.bodyEnd ? `\n ${mergedCustomCode.bodyEnd}` : ''}
637
672
  </body>
638
673
  </html>`;
639
674
 
@@ -641,7 +676,7 @@ picture {
641
676
  if (returnSeparateJS) {
642
677
  return {
643
678
  html: htmlDocument,
644
- javascript: externalJavaScript
679
+ javascript: externalJavaScript,
645
680
  };
646
681
  }
647
682
 
@@ -20,7 +20,9 @@ describe('extractImgSrc', () => {
20
20
  });
21
21
 
22
22
  describe('rewriteRichTextImages', () => {
23
- function buildMap(entries: Record<string, { srcset: string; avifSrcset?: string; width?: number; height?: number }>): ImageMetadataMap {
23
+ function buildMap(
24
+ entries: Record<string, { srcset: string; avifSrcset?: string; width?: number; height?: number }>,
25
+ ): ImageMetadataMap {
24
26
  const map = new Map() as ImageMetadataMap;
25
27
  for (const [key, value] of Object.entries(entries)) {
26
28
  map.set(key, value);
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { projectPaths } from '../projectContext';
7
- import * as path from 'path';
7
+ import * as path from 'node:path';
8
8
  import { escapeHtml } from './attributeBuilder';
9
9
  import { readTextFile, fileExists } from '../runtime';
10
10
 
@@ -58,14 +58,17 @@ export async function buildImageMetadataMap(): Promise<ImageMetadataMap> {
58
58
  const manifestContent = await readTextFile(manifestPath);
59
59
  const manifest = JSON.parse(manifestContent) as {
60
60
  version: number;
61
- images: Record<string, {
62
- filename: string;
63
- width: number;
64
- height: number;
65
- blurHash: string;
66
- formats: { avif: boolean; webp: boolean };
67
- variants: { width: number; webpFilename: string; avifFilename: string }[];
68
- }>;
61
+ images: Record<
62
+ string,
63
+ {
64
+ filename: string;
65
+ width: number;
66
+ height: number;
67
+ blurHash: string;
68
+ formats: { avif: boolean; webp: boolean };
69
+ variants: { width: number; webpFilename: string; avifFilename: string }[];
70
+ }
71
+ >;
69
72
  };
70
73
 
71
74
  // Build metadata for each image
@@ -78,13 +81,9 @@ export async function buildImageMetadataMap(): Promise<ImageMetadataMap> {
78
81
 
79
82
  // Add variants
80
83
  for (const variant of entry.variants) {
81
- webpSrcsetParts.push(
82
- `/images/${encodeURIComponent(variant.webpFilename)} ${variant.width}w`
83
- );
84
+ webpSrcsetParts.push(`/images/${encodeURIComponent(variant.webpFilename)} ${variant.width}w`);
84
85
  if (variant.avifFilename) {
85
- avifSrcsetParts.push(
86
- `/images/${encodeURIComponent(variant.avifFilename)} ${variant.width}w`
87
- );
86
+ avifSrcsetParts.push(`/images/${encodeURIComponent(variant.avifFilename)} ${variant.width}w`);
88
87
  }
89
88
  }
90
89
 
@@ -133,7 +132,7 @@ export async function buildImageMetadataMap(): Promise<ImageMetadataMap> {
133
132
  */
134
133
  export function extractImgSrc(imgTag: string): string | null {
135
134
  const match = imgTag.match(/src=["']([^"']+)["']/i);
136
- return match ? match[1] : null;
135
+ return match ? (match[1] ?? null) : null;
137
136
  }
138
137
 
139
138
  /**
@@ -141,7 +140,11 @@ export function extractImgSrc(imgTag: string): string | null {
141
140
  * Only rewrites images that exist in the metadata map (project images with generated variants).
142
141
  * External/unrecognized images are left unchanged.
143
142
  */
144
- export function rewriteRichTextImages(html: string, metadataMap: ImageMetadataMap, imageFormat?: 'webp' | 'avif'): string {
143
+ export function rewriteRichTextImages(
144
+ html: string,
145
+ metadataMap: ImageMetadataMap,
146
+ imageFormat?: 'webp' | 'avif',
147
+ ): string {
145
148
  return html.replace(/<img\b([^>]*)\/?>/gi, (fullMatch, innerAttrs: string) => {
146
149
  const src = extractImgSrc(fullMatch);
147
150
  if (!src) return fullMatch;
@@ -166,17 +169,20 @@ export function rewriteRichTextImages(html: string, metadataMap: ImageMetadataMa
166
169
 
167
170
  // Render as <picture> with AVIF + WebP sources when AVIF is available and format allows
168
171
  if (metadata.avifSrcset && imageFormat !== 'webp') {
169
- return `<picture>` +
172
+ return (
173
+ `<picture>` +
170
174
  `<source type="image/avif" srcset="${escapeHtml(metadata.avifSrcset)}" sizes="${escapeHtml(sizes)}" />` +
171
175
  `<source type="image/webp" srcset="${escapeHtml(metadata.srcset)}" sizes="${escapeHtml(sizes)}" />` +
172
176
  enhancedTag +
173
- `</picture>`;
177
+ `</picture>`
178
+ );
174
179
  }
175
180
 
176
181
  // WebP only: add srcset and sizes to existing <img>
177
182
  if (metadata.srcset) {
178
- enhancedTag = enhancedTag.replace(/<img\b/i,
179
- `<img srcset="${escapeHtml(metadata.srcset)}" sizes="${escapeHtml(sizes)}"`
183
+ enhancedTag = enhancedTag.replace(
184
+ /<img\b/i,
185
+ `<img srcset="${escapeHtml(metadata.srcset)}" sizes="${escapeHtml(sizes)}"`,
180
186
  );
181
187
  }
182
188
 
@@ -67,9 +67,9 @@ describe('jsCollector', () => {
67
67
 
68
68
  const errors = getJSValidationErrors();
69
69
  expect(errors).toHaveLength(1);
70
- expect(errors[0].component).toBe('myBadComp');
71
- expect(typeof errors[0].error).toBe('string');
72
- expect(errors[0].error.length).toBeGreaterThan(0);
70
+ expect(errors[0]!.component).toBe('myBadComp');
71
+ expect(typeof errors[0]!.error).toBe('string');
72
+ expect(errors[0]!.error.length).toBeGreaterThan(0);
73
73
  });
74
74
  });
75
75
 
@@ -154,10 +154,7 @@ describe('jsCollector', () => {
154
154
  const globalComp = makeComponent({ javascript: 'console.log("global");' });
155
155
  const pageComp = makeComponent({ javascript: 'console.log("page");' });
156
156
 
157
- const result = await collectComponentJavaScript(
158
- { header: globalComp },
159
- { footer: pageComp }
160
- );
157
+ const result = await collectComponentJavaScript({ header: globalComp }, { footer: pageComp });
161
158
 
162
159
  expect(result).toContain('// Component: header');
163
160
  expect(result).toContain('console.log("global");');
@@ -169,10 +166,7 @@ describe('jsCollector', () => {
169
166
  const globalComp = makeComponent({ javascript: 'console.log("global version");' });
170
167
  const pageComp = makeComponent({ javascript: 'console.log("page version");' });
171
168
 
172
- const result = await collectComponentJavaScript(
173
- { shared: globalComp },
174
- { shared: pageComp }
175
- );
169
+ const result = await collectComponentJavaScript({ shared: globalComp }, { shared: pageComp });
176
170
 
177
171
  expect(result).toContain('console.log("global version");');
178
172
  expect(result).not.toContain('console.log("page version");');
@@ -187,11 +181,7 @@ describe('jsCollector', () => {
187
181
  const badComp = makeComponent({ javascript: '%%%INVALID%%%' });
188
182
  const goodComp = makeComponent({ javascript: 'console.log("valid");' });
189
183
 
190
- const result = await collectComponentJavaScript(
191
- { bad: badComp, good: goodComp },
192
- {},
193
- onError
194
- );
184
+ const result = await collectComponentJavaScript({ bad: badComp, good: goodComp }, {}, onError);
195
185
 
196
186
  // The bad component should be skipped
197
187
  expect(result).not.toContain('%%%INVALID%%%');
@@ -200,8 +190,8 @@ describe('jsCollector', () => {
200
190
 
201
191
  // onError should have been called for the bad component
202
192
  expect(errors).toHaveLength(1);
203
- expect(errors[0].name).toBe('bad');
204
- expect(errors[0].error.length).toBeGreaterThan(0);
193
+ expect(errors[0]!.name).toBe('bad');
194
+ expect(errors[0]!.error.length).toBeGreaterThan(0);
205
195
  });
206
196
 
207
197
  test('should use validation cache on repeated calls for same component', async () => {
@@ -34,13 +34,8 @@ const DEFINE_VARS_RUNTIME = `(function() {
34
34
  /**
35
35
  * Generate destructure statement for defineVars
36
36
  */
37
- function generateDestructure(
38
- defineVars: true | string[],
39
- interfaceDef?: Record<string, unknown>
40
- ): string {
41
- const vars = defineVars === true
42
- ? Object.keys(interfaceDef || {})
43
- : defineVars;
37
+ function generateDestructure(defineVars: true | string[], interfaceDef?: Record<string, unknown>): string {
38
+ const vars = defineVars === true ? Object.keys(interfaceDef || {}) : defineVars;
44
39
  if (vars.length === 0) return '';
45
40
  return `var {${vars.join(', ')}} = props;`;
46
41
  }
@@ -89,7 +84,7 @@ export function getJSValidationErrors(): Array<{ component: string; error: strin
89
84
  export async function collectComponentJavaScript(
90
85
  globalComponents: Record<string, ComponentDefinition> = {},
91
86
  pageComponents: Record<string, ComponentDefinition> = {},
92
- onError?: JSErrorCallback
87
+ onError?: JSErrorCallback,
93
88
  ): Promise<string> {
94
89
  const jsCodeBlocks: string[] = [];
95
90
  let hasDefineVars = false;