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
@@ -1,635 +0,0 @@
1
- /**
2
- * Webflow Export Build Orchestrator
3
- * Loads the project, renders all pages, and converts to Webflow payload.
4
- * Mirrors the pattern of build-astro.ts.
5
- */
6
-
7
- import { existsSync, readdirSync } from 'fs';
8
- import { readFile } from 'fs/promises';
9
- import { join } from 'path';
10
- import {
11
- loadJSONFile,
12
- loadComponentDirectory,
13
- mapPageNameToPath,
14
- parseJSON,
15
- loadI18nConfig,
16
- loadBreakpointConfig,
17
- } from '../jsonLoader';
18
- import { renderPageSSR } from '../ssr/ssrRenderer';
19
- import { projectPaths } from '../projectContext';
20
- import { loadProjectConfig } from '../../shared/fontLoader';
21
- import { FileSystemCMSProvider } from '../providers/fileSystemCMSProvider';
22
- import { CMSService } from '../services/cmsService';
23
- import { isI18nValue, resolveI18nValue } from '../../shared/i18n';
24
- import { RAW_HTML_PREFIX } from '../../shared/constants';
25
- import { extractPageMeta, type PageMeta } from '../ssr/metaTagGenerator';
26
- import { configService } from '../services/configService';
27
- import { colorService } from '../services/ColorService';
28
- import { variableService } from '../services/VariableService';
29
- import { migrateTemplatesDirectory } from '../migrateTemplates';
30
- import type {
31
- ComponentDefinition,
32
- JSONPage,
33
- CMSSchema,
34
- CMSItem,
35
- I18nConfig,
36
- ThemeConfig,
37
- } from '../../shared/types';
38
- import { resolvePaletteColor } from '../../shared/types/colors';
39
- import type { SlugMap } from '../../shared/slugTranslator';
40
- import type {
41
- WebflowExportPayload,
42
- WebflowPage,
43
- WebflowStyleClass,
44
- WebflowAssetRef,
45
- WebflowScript,
46
- WebflowComponentDef,
47
- } from './types';
48
- import { nodeToWebflow, normalizeListChildren, type WebflowEmitContext } from './nodeToWebflow';
49
- import { isWebflowHandledRule } from './styleMapper';
50
- import { generateInteractiveCSS } from '../../shared/cssGeneration';
51
- import { generateVariablesCSS } from '../cssGenerator';
52
- import type { InteractiveStyles } from '../../shared/types/styles';
53
- import { resolveVariableValueAtBreakpoint } from '../../shared/responsiveScaling';
54
- import type { ResponsiveScales } from '../../shared/responsiveScaling';
55
- import type { VariablesConfig } from '../../shared/types';
56
- import type { BreakpointConfig } from '../../shared/breakpoints';
57
-
58
- // ---------------------------------------------------------------------------
59
- // Helpers
60
- // ---------------------------------------------------------------------------
61
-
62
- function scanJSONFiles(dir: string, prefix: string = ''): string[] {
63
- const results: string[] = [];
64
- if (!existsSync(dir)) return results;
65
- const entries = readdirSync(dir, { withFileTypes: true });
66
- for (const entry of entries) {
67
- if (entry.isFile() && entry.name.endsWith('.json')) {
68
- results.push(prefix ? `${prefix}/${entry.name}` : entry.name);
69
- } else if (entry.isDirectory()) {
70
- results.push(...scanJSONFiles(join(dir, entry.name), prefix ? `${prefix}/${entry.name}` : entry.name));
71
- }
72
- }
73
- return results;
74
- }
75
-
76
- function isCMSPage(pageData: JSONPage): boolean {
77
- return pageData.meta?.source === 'cms' && !!pageData.meta?.cms;
78
- }
79
-
80
- /**
81
- * Flatten a CMS item for the Webflow emit path: resolve i18n values to the
82
- * current locale and unwrap rich-text markers (`{ __richtext__, html }`) into
83
- * `RAW_HTML_PREFIX + html` so `nodeToWebflow`'s `resolveTemplate` can flatten
84
- * inline HTML to plain text. Mirrors what SSR's `processCMSTemplate`
85
- * (`cmsSSRProcessor.ts`) does inline at every interpolation site — but applied
86
- * once up front so the simpler Webflow `resolveTemplate` (which only does
87
- * `String(value)`) renders meaningful text instead of `[object Object]` /
88
- * empty strings.
89
- */
90
- function flattenCMSItemForLocale(
91
- item: CMSItem,
92
- locale: string,
93
- i18nConfig: I18nConfig
94
- ): Record<string, unknown> {
95
- const flatten = (value: unknown): unknown => {
96
- if (value === null || value === undefined) return value;
97
- if (isI18nValue(value)) {
98
- return flatten(resolveI18nValue(value, locale, i18nConfig));
99
- }
100
- if (typeof value === 'object' && '__richtext__' in (value as object)) {
101
- const html = (value as { html?: unknown }).html;
102
- if (typeof html === 'string') return RAW_HTML_PREFIX + html;
103
- }
104
- return value;
105
- };
106
- const out: Record<string, unknown> = {};
107
- for (const [key, value] of Object.entries(item)) {
108
- out[key] = flatten(value);
109
- }
110
- return out;
111
- }
112
-
113
- /**
114
- * Resolve a page-meta value (which may be an i18n object) to a string for the
115
- * given locale, or undefined when the field is empty.
116
- */
117
- function resolveMetaString(
118
- value: unknown,
119
- locale: string,
120
- i18nConfig: I18nConfig
121
- ): string | undefined {
122
- if (value === undefined || value === null || value === '') return undefined;
123
- const resolved = isI18nValue(value)
124
- ? resolveI18nValue(value, locale, i18nConfig)
125
- : value;
126
- if (resolved === undefined || resolved === null || resolved === '') return undefined;
127
- return String(resolved);
128
- }
129
-
130
- /**
131
- * Lift the structured meta from a page (title, description, OG fields,
132
- * keywords) into the per-locale fields of a `WebflowPage`. SSR's `result.title`
133
- * is preserved as the canonical title; the rest comes from `extractPageMeta`.
134
- */
135
- function buildPageMetaForLocale(
136
- meta: PageMeta,
137
- locale: string,
138
- i18nConfig: I18nConfig
139
- ): Pick<WebflowPage, 'description' | 'keywords' | 'ogTitle' | 'ogDescription' | 'ogImage'> {
140
- return {
141
- description: resolveMetaString(meta.description, locale, i18nConfig),
142
- keywords: resolveMetaString(meta.keywords, locale, i18nConfig),
143
- ogTitle: resolveMetaString(meta.ogTitle, locale, i18nConfig),
144
- ogDescription: resolveMetaString(meta.ogDescription, locale, i18nConfig),
145
- ogImage: resolveMetaString(meta.ogImage, locale, i18nConfig),
146
- };
147
- }
148
-
149
- function scanAssets(projectRoot: string): WebflowAssetRef[] {
150
- const assets: WebflowAssetRef[] = [];
151
- const assetDirs: Array<{ dir: string; type: WebflowAssetRef['type'] }> = [
152
- { dir: 'images', type: 'image' },
153
- { dir: 'fonts', type: 'font' },
154
- { dir: 'videos', type: 'video' },
155
- { dir: 'assets', type: 'file' },
156
- ];
157
-
158
- for (const { dir, type } of assetDirs) {
159
- const fullDir = join(projectRoot, dir);
160
- if (!existsSync(fullDir)) continue;
161
- const files = scanJSONFiles(fullDir).map(f => f.replace('.json', '')); // scanJSONFiles works for any extension
162
- // Re-scan properly for all file types
163
- const allFiles = scanAllFiles(fullDir);
164
- for (const file of allFiles) {
165
- assets.push({
166
- localPath: `${dir}/${file}`,
167
- type,
168
- fileName: file.split('/').pop()!,
169
- });
170
- }
171
- }
172
-
173
- return assets;
174
- }
175
-
176
- function scanAllFiles(dir: string, prefix: string = ''): string[] {
177
- const results: string[] = [];
178
- if (!existsSync(dir)) return results;
179
- const entries = readdirSync(dir, { withFileTypes: true });
180
- for (const entry of entries) {
181
- const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
182
- if (entry.isFile()) {
183
- results.push(relativePath);
184
- } else if (entry.isDirectory()) {
185
- results.push(...scanAllFiles(join(dir, entry.name), relativePath));
186
- }
187
- }
188
- return results;
189
- }
190
-
191
- /**
192
- * Build per-theme `--var` maps so the walker can resolve `var(--bg)` against
193
- * whatever theme an element actually inherits. Each theme key holds its full
194
- * resolved palette (text, bg, border, …); `defaultThemeName` is what we fall
195
- * back to when an element has no `theme` ancestor.
196
- */
197
- function buildThemeVarMaps(
198
- themeConfig: ThemeConfig
199
- ): { byTheme: Record<string, Record<string, string>>; defaultTheme: string } {
200
- const palette = themeConfig.palette;
201
- const byTheme: Record<string, Record<string, string>> = {};
202
- for (const [themeName, theme] of Object.entries(themeConfig.themes)) {
203
- const vars: Record<string, string> = {};
204
- for (const [name, value] of Object.entries(theme.colors)) {
205
- vars[`--${name}`] = resolvePaletteColor(value, palette);
206
- }
207
- byTheme[themeName] = vars;
208
- }
209
- return { byTheme, defaultTheme: themeConfig.default };
210
- }
211
-
212
- /**
213
- * Build a per-breakpoint `--var → value` map directly from the variables
214
- * config. Each breakpoint key (`base`, `tablet`, `mobile`, …) holds the full
215
- * resolved variable map at that breakpoint, with per-variable `scales`
216
- * overrides and global category scaling already applied
217
- * (`resolveVariableValueAtBreakpoint` mirrors `generateVariablesCSS` and the
218
- * runtime CSS resolver).
219
- *
220
- * The walker uses these maps to inline `var(--x)` references in element
221
- * styles per-breakpoint, so the Webflow class system receives concrete
222
- * scaled values at every tier instead of a single flat base value.
223
- */
224
- function buildProjectVarMaps(
225
- variablesConfig: VariablesConfig,
226
- breakpoints: BreakpointConfig,
227
- responsiveScales: ResponsiveScales | undefined
228
- ): Record<string, Record<string, string>> {
229
- const out: Record<string, Record<string, string>> = { base: {} };
230
- for (const bpName of Object.keys(breakpoints)) out[bpName] = {};
231
-
232
- for (const variable of variablesConfig.variables) {
233
- if (!variable.cssVar) continue;
234
- out.base[variable.cssVar] = variable.value;
235
- for (const bpName of Object.keys(breakpoints)) {
236
- const resolved = resolveVariableValueAtBreakpoint(
237
- { value: variable.value, type: variable.type, scales: variable.scales },
238
- bpName,
239
- responsiveScales
240
- );
241
- out[bpName][variable.cssVar] = resolved;
242
- }
243
- }
244
- return out;
245
- }
246
-
247
- // ---------------------------------------------------------------------------
248
- // Main export
249
- // ---------------------------------------------------------------------------
250
-
251
- export async function buildWebflowPayload(
252
- options?: { bindCollectionLists?: boolean; promotedComponentNames?: string[]; locale?: string }
253
- ): Promise<WebflowExportPayload> {
254
- const bindCollectionLists = options?.bindCollectionLists === true;
255
- const promotedComponentNames = Array.isArray(options?.promotedComponentNames)
256
- ? new Set(options!.promotedComponentNames.filter((n): n is string => typeof n === 'string' && n.length > 0))
257
- : undefined;
258
- // 1. Setup: load project configuration
259
- configService.reset();
260
-
261
- const projectConfig = await loadProjectConfig();
262
- const siteUrl = (projectConfig as { siteUrl?: string }).siteUrl?.replace(/\/$/, '') || '';
263
- const i18nConfig = await loadI18nConfig();
264
-
265
- // Pick which locale to render. Multi-locale projects export one locale at a
266
- // time so the Webflow site mirrors a single language; the extension surfaces
267
- // a picker that defaults to `i18nConfig.defaultLocale`. An invalid/missing
268
- // request falls back to the default locale (silent — the picker is the
269
- // source of truth here, not the URL).
270
- const requestedLocale = options?.locale;
271
- const selectedLocale = (requestedLocale && i18nConfig.locales.some(l => l.code === requestedLocale))
272
- ? requestedLocale
273
- : i18nConfig.defaultLocale;
274
- const localesToBuild = i18nConfig.locales.filter(l => l.code === selectedLocale);
275
-
276
- await migrateTemplatesDirectory();
277
-
278
- const { components } = await loadComponentDirectory(projectPaths.components());
279
- const globalComponents: Record<string, ComponentDefinition> = {};
280
- components.forEach((value, key) => { globalComponents[key] = value; });
281
-
282
- const cmsProvider = new FileSystemCMSProvider(projectPaths.templates(), projectPaths.cms());
283
- const cmsService = new CMSService(cmsProvider);
284
- await cmsService.initialize();
285
-
286
- const themeConfig = await colorService.loadThemeConfig();
287
- const variablesConfig = await variableService.loadConfig();
288
- const breakpoints = await loadBreakpointConfig();
289
-
290
- await configService.load();
291
- const responsiveScales = configService.getResponsiveScales();
292
-
293
- // 2. Scan pages
294
- const pagesDir = projectPaths.pages();
295
- if (!existsSync(pagesDir)) {
296
- return emptyPayload();
297
- }
298
-
299
- const pageFiles = scanJSONFiles(pagesDir);
300
- if (pageFiles.length === 0) {
301
- return emptyPayload();
302
- }
303
-
304
- // Collect slug mappings
305
- const slugMappings: SlugMap[] = [];
306
- for (const file of pageFiles) {
307
- const pageName = file.replace('.json', '');
308
- const basePath = mapPageNameToPath(pageName);
309
- const pageContent = await loadJSONFile(join(pagesDir, file));
310
- if (!pageContent) continue;
311
- try {
312
- const pageData = parseJSON<JSONPage>(pageContent);
313
- if (pageData.meta?.slugs) {
314
- const pageId = basePath === '/' ? 'index' : basePath.substring(1);
315
- slugMappings.push({ pageId, slugs: pageData.meta.slugs });
316
- }
317
- } catch { /* ignore */ }
318
- }
319
-
320
- // 3. Render and convert pages
321
- const allPages: WebflowPage[] = [];
322
- const allStyleClasses = new Map<string, WebflowStyleClass>();
323
- // elementClass → interactiveStyles, populated during the node walk and
324
- // drained at the end into raw CSS (see step 6 below).
325
- const allInteractiveStylesMap = new Map<string, InteractiveStyles>();
326
- // Combo class name → owning identity, shared across every page emit so
327
- // collisions are visible project-wide. Drives `mintInstanceComboName` in
328
- // nodeToWebflow.ts.
329
- const allComboIdentityByName = new Map<string, string>();
330
- // First-encounter snapshot of each promoted component (Navigation, Footer)
331
- // shared across every page so the extension registers each definition once.
332
- const promotedComponents = new Map<string, WebflowComponentDef>();
333
-
334
- // Theme + project-level CSS variables are resolved during the walk so the
335
- // ancestor `theme` attribute can pick the right palette per element. The
336
- // project var map is per-breakpoint so `var(--x)` refs in element styles
337
- // can be inlined at each tier with the right scaled value.
338
- const variablesCSS = generateVariablesCSS(variablesConfig, breakpoints, responsiveScales);
339
- const projectVars = buildProjectVarMaps(variablesConfig, breakpoints, responsiveScales);
340
- const { byTheme: themeVars, defaultTheme } = buildThemeVarMaps(themeConfig);
341
-
342
- // Regular pages
343
- for (const file of pageFiles) {
344
- const pageName = file.replace('.json', '');
345
- const basePath = mapPageNameToPath(pageName);
346
- const pageContent = await loadJSONFile(join(pagesDir, file));
347
- if (!pageContent) continue;
348
-
349
- try {
350
- const pageData = parseJSON<JSONPage>(pageContent);
351
- if (pageData.meta?.draft === true) continue;
352
-
353
- const slugs = pageData.meta?.slugs;
354
-
355
- for (const localeConfig of localesToBuild) {
356
- const locale = localeConfig.code;
357
- const isDefault = locale === i18nConfig.defaultLocale;
358
-
359
- let slug: string;
360
- if (slugs && slugs[locale]) {
361
- slug = slugs[locale];
362
- } else if (basePath === '/') {
363
- slug = '';
364
- } else {
365
- slug = basePath.substring(1);
366
- }
367
-
368
- const urlPath = isDefault
369
- ? (slug === '' ? '/' : `/${slug}`)
370
- : (slug === '' ? `/${locale}` : `/${locale}/${slug}`);
371
-
372
- // Render via SSR to resolve all props
373
- const result = await renderPageSSR(
374
- pageData,
375
- globalComponents,
376
- urlPath,
377
- siteUrl,
378
- locale,
379
- i18nConfig,
380
- slugMappings,
381
- undefined,
382
- cmsService,
383
- true
384
- );
385
-
386
- // Convert node tree to Webflow elements
387
- const ctx: WebflowEmitContext = {
388
- globalComponents,
389
- elementPath: [0],
390
- fileType: 'page',
391
- fileName: pageName,
392
- breakpoints,
393
- styleClasses: allStyleClasses,
394
- comboIdentityByName: allComboIdentityByName,
395
- interactiveStylesMap: allInteractiveStylesMap,
396
- cmsService,
397
- i18nConfig,
398
- locale,
399
- slugMappings,
400
- pagePath: urlPath,
401
- themeVars,
402
- projectVars,
403
- defaultTheme,
404
- responsiveScales,
405
- promotedComponents,
406
- promotedComponentNames,
407
- bindCollectionLists,
408
- };
409
-
410
- const body = pageData.root || (pageData as any).node;
411
- const elements = body ? await nodeToWebflow(body, ctx) : [];
412
- normalizeListChildren(elements);
413
-
414
- const pageMeta = extractPageMeta(pageData);
415
- allPages.push({
416
- title: result.title,
417
- slug: slug || 'index',
418
- elements,
419
- locale,
420
- ...buildPageMetaForLocale(pageMeta, locale, i18nConfig),
421
- });
422
- }
423
- } catch (error: any) {
424
- console.error(`Error processing ${basePath}:`, error?.message);
425
- }
426
- }
427
-
428
- // CMS template pages — imported as a single regular Webflow page per locale,
429
- // bound to the FIRST CMS item's content. Webflow can't natively bind a page
430
- // to a Meno-side collection, and a separate "Sync CMS" flow in the extension
431
- // handles collection schema/items, so this code path stays page-only.
432
- const templatesDir = projectPaths.templates();
433
-
434
- if (existsSync(templatesDir)) {
435
- const templateFiles = readdirSync(templatesDir).filter(f => f.endsWith('.json'));
436
-
437
- for (const file of templateFiles) {
438
- const templateContent = await loadJSONFile(join(templatesDir, file));
439
- if (!templateContent) continue;
440
-
441
- try {
442
- const pageData = parseJSON<JSONPage>(templateContent);
443
- if (pageData.meta?.draft === true) continue;
444
- if (!isCMSPage(pageData)) continue;
445
-
446
- const cmsSchema = pageData.meta!.cms as CMSSchema;
447
- const items = await cmsService.queryItems({ collection: cmsSchema.id });
448
- if (items.length === 0) continue;
449
-
450
- const item = items[0];
451
- const pageName = file.replace('.json', '');
452
-
453
- for (const localeConfig of localesToBuild) {
454
- const locale = localeConfig.code;
455
- // Use the first item's resolved URL (from cmsSchema.urlPattern) as
456
- // the slug, so a template like `templates/blog.json` lands at
457
- // `/blog/<first-slug>` and doesn't collide with a sibling listing
458
- // page like `pages/blog.json`.
459
- let itemSlug = item[cmsSchema.slugField] ?? item._slug ?? item._filename ?? item._id;
460
- if (isI18nValue(itemSlug)) {
461
- itemSlug = resolveI18nValue(itemSlug, locale, i18nConfig) as string;
462
- }
463
- const resolvedItemPath = cmsSchema.urlPattern.replace('{{slug}}', String(itemSlug));
464
- const isDefault = locale === i18nConfig.defaultLocale;
465
- const localizedItemPath = isDefault
466
- ? resolvedItemPath
467
- : `/${locale}${resolvedItemPath.startsWith('/') ? '' : '/'}${resolvedItemPath}`;
468
- const slug = localizedItemPath.startsWith('/')
469
- ? localizedItemPath.substring(1)
470
- : localizedItemPath;
471
- const urlPath = localizedItemPath;
472
- // SSR (`renderPageSSR`) gets the raw item — its `processCMSTemplate`
473
- // resolves i18n + richtext at each interpolation. The Webflow path
474
- // re-walks the same `pageData.root` with the simpler `resolveTemplate`
475
- // (no i18n / richtext awareness), so we hand it a pre-flattened item.
476
- const flatItem = flattenCMSItemForLocale(item, locale, i18nConfig);
477
- const itemWithUrl: CMSItem = { ...flatItem, _url: urlPath } as CMSItem;
478
- const ssrItem: CMSItem = { ...item, _url: urlPath };
479
-
480
- const result = await renderPageSSR(
481
- pageData,
482
- globalComponents,
483
- urlPath,
484
- siteUrl,
485
- locale,
486
- i18nConfig,
487
- slugMappings,
488
- { cms: ssrItem },
489
- cmsService,
490
- true
491
- );
492
-
493
- const ctx: WebflowEmitContext = {
494
- globalComponents,
495
- elementPath: [0],
496
- fileType: 'page',
497
- fileName: pageName,
498
- breakpoints,
499
- styleClasses: allStyleClasses,
500
- comboIdentityByName: allComboIdentityByName,
501
- interactiveStylesMap: allInteractiveStylesMap,
502
- cmsService,
503
- i18nConfig,
504
- locale,
505
- slugMappings,
506
- pagePath: urlPath,
507
- cmsContext: { cms: itemWithUrl },
508
- // Seed `templateContext` with the bound item so descendants inside
509
- // a component slot still see `cms`. `emitInlineComponentBody`
510
- // merges `ctx.templateContext` into the body's `instanceProps`
511
- // (nodeToWebflow.ts:1140-1143), and `<slot>` rendering forwards
512
- // those merged props to slot children — without this, anything
513
- // wrapped in (e.g.) Section loses the page-level CMS scope and
514
- // `{{cms.title}}` resolves to empty.
515
- templateContext: { cms: itemWithUrl } as Record<string, unknown>,
516
- themeVars,
517
- projectVars,
518
- defaultTheme,
519
- responsiveScales,
520
- promotedComponents,
521
- promotedComponentNames,
522
- bindCollectionLists,
523
- };
524
-
525
- const body = pageData.root || (pageData as any).node;
526
- const elements = body ? await nodeToWebflow(body, ctx, { cms: itemWithUrl }) : [];
527
- normalizeListChildren(elements);
528
-
529
- const cmsPageMeta = extractPageMeta(pageData);
530
- allPages.push({
531
- title: result.title,
532
- slug,
533
- elements,
534
- locale,
535
- ...buildPageMetaForLocale(cmsPageMeta, locale, i18nConfig),
536
- });
537
- }
538
- } catch (error: any) {
539
- console.error(`Error processing template ${file}:`, error?.message);
540
- }
541
- }
542
- }
543
-
544
- // Promoted components (Navigation, Footer) are emitted via the same
545
- // `nodeToWebflow` walk as pages, so they share the same `<ul>`-with-
546
- // non-`<li>`-children pitfall. Normalize their element trees too before
547
- // they leave the build.
548
- for (const def of promotedComponents.values()) {
549
- normalizeListChildren(def.elements);
550
- }
551
-
552
- // 4. Scan assets
553
- const styleClasses = Array.from(allStyleClasses.values());
554
- const assets = scanAssets(projectPaths.project);
555
-
556
- // 5. Collect component scripts and component-scoped CSS sidecars. Both get
557
- // bundled into the manual-paste UI: scripts as a `<script>` at body end,
558
- // CSS as part of the `<style>` block at head. CSS in particular is
559
- // critical for components that drive visibility through hand-written
560
- // rules (e.g. NavDropdown's `[data-nav-dropdown="container"].open ...`)
561
- // — those don't translate to Webflow's class system at all.
562
- const scripts: WebflowScript[] = [];
563
- const cssBlocks: string[] = [];
564
- for (const [name, def] of Object.entries(globalComponents)) {
565
- const code = def.component?.javascript;
566
- if (typeof code === 'string' && code.trim().length > 0) {
567
- scripts.push({
568
- componentName: name,
569
- code,
570
- defineVars: def.component?.defineVars,
571
- });
572
- }
573
- const css = def.component?.css;
574
- if (typeof css === 'string' && css.trim().length > 0) {
575
- cssBlocks.push(`/* ${name}.css */\n${css.trim()}`);
576
- }
577
- }
578
- const componentCss = cssBlocks.length > 0 ? cssBlocks.join('\n\n') : undefined;
579
-
580
- // 6. Per-element interactiveStyles → raw CSS for rules Webflow's class
581
- // system can't represent (anything with `prefix`, class-style postfix,
582
- // or breakpoint-divided pseudos). Pseudo-only rules with empty prefix
583
- // have already been written into `primaryClass.pseudoStates` upstream
584
- // via `Style.setProperties({ pseudo })`; we filter those out here so
585
- // the bundle doesn't double-emit them.
586
- const interactiveCssBlocks: string[] = [];
587
- for (const [elementClass, rules] of allInteractiveStylesMap) {
588
- const customRules = rules.filter((r) => !isWebflowHandledRule(r));
589
- if (customRules.length === 0) continue;
590
- const css = generateInteractiveCSS(elementClass, customRules, breakpoints, undefined, responsiveScales);
591
- if (css && css.trim().length > 0) {
592
- interactiveCssBlocks.push(css);
593
- }
594
- }
595
- const interactiveCss = interactiveCssBlocks.length > 0
596
- ? interactiveCssBlocks.join('\n\n')
597
- : undefined;
598
-
599
- return {
600
- version: 1,
601
- exportedAt: new Date().toISOString(),
602
- pages: allPages,
603
- styles: styleClasses,
604
- cms: [],
605
- assets,
606
- slugMappings: slugMappings.length > 0 ? slugMappings : undefined,
607
- scripts: scripts.length > 0 ? scripts : undefined,
608
- components: promotedComponents.size > 0
609
- ? Array.from(promotedComponents.values())
610
- : undefined,
611
- componentCss,
612
- interactiveCss,
613
- i18n: {
614
- defaultLocale: i18nConfig.defaultLocale,
615
- locales: i18nConfig.locales.map(l => ({
616
- code: l.code,
617
- name: l.name,
618
- nativeName: l.nativeName,
619
- })),
620
- selectedLocale,
621
- },
622
- };
623
- }
624
-
625
- function emptyPayload(): WebflowExportPayload {
626
- return {
627
- version: 1,
628
- exportedAt: new Date().toISOString(),
629
- pages: [],
630
- styles: [],
631
- cms: [],
632
- assets: [],
633
- };
634
- }
635
-
@@ -1,23 +0,0 @@
1
- /**
2
- * Webflow Export Module
3
- * Re-exports the main build function and types.
4
- */
5
-
6
- export { buildWebflowPayload } from './buildWebflow';
7
- export { nodeToWebflow } from './nodeToWebflow';
8
- export { mapStylesToWebflow } from './styleMapper';
9
- export { wrapInWebflowTemplate } from './templateWrapper';
10
- export type {
11
- WebflowExportPayload,
12
- WebflowPage,
13
- WebflowElement,
14
- WebflowStyleClass,
15
- WebflowCMSCollection,
16
- WebflowCMSField,
17
- WebflowAssetRef,
18
- WebflowBreakpoint,
19
- WebflowPseudoState,
20
- WebflowFieldType,
21
- CSSProperties,
22
- } from './types';
23
- export { mapCMSFieldType } from './types';