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
@@ -50,7 +50,7 @@ describe('MenoFilter', () => {
50
50
  await filter.init();
51
51
 
52
52
  expect(filter.getAll()).toHaveLength(4);
53
- expect(filter.getAll()[0]._id).toBe('1');
53
+ expect(filter.getAll()[0]!._id).toBe('1');
54
54
  });
55
55
 
56
56
  test('should handle missing data gracefully', async () => {
@@ -83,7 +83,7 @@ describe('MenoFilter', () => {
83
83
  Promise.resolve({
84
84
  ok: true,
85
85
  json: () => Promise.resolve(sampleItems),
86
- })
86
+ }),
87
87
  );
88
88
  const originalFetch = (globalThis as any).fetch;
89
89
  (globalThis as any).fetch = mockFetch;
@@ -127,7 +127,7 @@ describe('MenoFilter', () => {
127
127
  Promise.resolve({
128
128
  ok: false,
129
129
  status: 404,
130
- })
130
+ }),
131
131
  );
132
132
  const originalFetch = (globalThis as any).fetch;
133
133
  (globalThis as any).fetch = mockFetch;
@@ -157,7 +157,7 @@ describe('MenoFilter', () => {
157
157
  Promise.resolve({
158
158
  ok: true,
159
159
  json: () => Promise.resolve([{ _id: 'fetch', title: 'Fetch Data' }]),
160
- })
160
+ }),
161
161
  );
162
162
  const originalFetch = (globalThis as any).fetch;
163
163
  (globalThis as any).fetch = mockFetch;
@@ -168,7 +168,7 @@ describe('MenoFilter', () => {
168
168
 
169
169
  // Should have inline data, not fetch data
170
170
  expect(filter.getAll()).toHaveLength(1);
171
- expect(filter.getAll()[0]._id).toBe('inline');
171
+ expect(filter.getAll()[0]!._id).toBe('inline');
172
172
  expect(mockFetch).not.toHaveBeenCalled();
173
173
  } finally {
174
174
  (globalThis as any).fetch = originalFetch;
@@ -193,14 +193,14 @@ describe('MenoFilter', () => {
193
193
  const result = filter.filter({ category: 'tech' });
194
194
 
195
195
  expect(result).toHaveLength(3);
196
- expect(result.every(item => item.category === 'tech')).toBe(true);
196
+ expect(result.every((item) => item.category === 'tech')).toBe(true);
197
197
  });
198
198
 
199
199
  test('should filter by multiple criteria (AND logic)', () => {
200
200
  const result = filter.filter({ category: 'tech', featured: true });
201
201
 
202
202
  expect(result).toHaveLength(1);
203
- expect(result[0].title).toBe('Hello World');
203
+ expect(result[0]!.title).toBe('Hello World');
204
204
  });
205
205
 
206
206
  test('should skip empty/undefined criteria values', () => {
@@ -217,14 +217,14 @@ describe('MenoFilter', () => {
217
217
 
218
218
  test('should emit to subscribers on filter', () => {
219
219
  let emittedItems: CMSItemClient[] = [];
220
- filter.subscribe(items => {
220
+ filter.subscribe((items) => {
221
221
  emittedItems = items;
222
222
  });
223
223
 
224
224
  filter.filter({ category: 'design' });
225
225
 
226
226
  expect(emittedItems).toHaveLength(1);
227
- expect(emittedItems[0].category).toBe('design');
227
+ expect(emittedItems[0]!.category).toBe('design');
228
228
  });
229
229
  });
230
230
 
@@ -245,8 +245,8 @@ describe('MenoFilter', () => {
245
245
  const result = filter.search('world');
246
246
 
247
247
  expect(result).toHaveLength(2);
248
- expect(result.map(i => i.title)).toContain('Hello World');
249
- expect(result.map(i => i.title)).toContain('Goodbye World');
248
+ expect(result.map((i) => i.title)).toContain('Hello World');
249
+ expect(result.map((i) => i.title)).toContain('Goodbye World');
250
250
  });
251
251
 
252
252
  test('should search specified fields only', () => {
@@ -278,22 +278,22 @@ describe('MenoFilter', () => {
278
278
  test('should sort ascending by default', () => {
279
279
  const result = filter.sort('title');
280
280
 
281
- expect(result[0].title).toBe('Coding Best Practices');
282
- expect(result[3].title).toBe('Hello World');
281
+ expect(result[0]!.title).toBe('Coding Best Practices');
282
+ expect(result[3]!.title).toBe('Hello World');
283
283
  });
284
284
 
285
285
  test('should sort descending', () => {
286
286
  const result = filter.sort('title', 'desc');
287
287
 
288
- expect(result[0].title).toBe('Hello World');
289
- expect(result[3].title).toBe('Coding Best Practices');
288
+ expect(result[0]!.title).toBe('Hello World');
289
+ expect(result[3]!.title).toBe('Coding Best Practices');
290
290
  });
291
291
 
292
292
  test('should sort numbers correctly', () => {
293
293
  const result = filter.sort('views', 'desc');
294
294
 
295
- expect(result[0].views).toBe(200);
296
- expect(result[3].views).toBe(50);
295
+ expect(result[0]!.views).toBe(200);
296
+ expect(result[3]!.views).toBe(50);
297
297
  });
298
298
 
299
299
  test('should handle undefined values in sort', () => {
@@ -312,7 +312,7 @@ describe('MenoFilter', () => {
312
312
  const result = filter2.sort('views', 'asc');
313
313
 
314
314
  // Undefined values should be sorted last in ascending order
315
- expect(result[result.length - 1].title).toBe('No Views');
315
+ expect(result[result.length - 1]!.title).toBe('No Views');
316
316
  });
317
317
  });
318
318
 
@@ -337,9 +337,7 @@ describe('MenoFilter', () => {
337
337
  });
338
338
 
339
339
  test('should find item by _filename', () => {
340
- const itemsWithFilename = [
341
- { _id: '1', _filename: 'hello-world', title: 'Hello' },
342
- ];
340
+ const itemsWithFilename = [{ _id: '1', _filename: 'hello-world', title: 'Hello' }];
343
341
  const mockElement = {
344
342
  textContent: JSON.stringify(itemsWithFilename),
345
343
  };
@@ -424,7 +422,7 @@ describe('MenoFilter', () => {
424
422
  await filter.init();
425
423
 
426
424
  let receivedItems: CMSItemClient[] = [];
427
- filter.subscribe(items => {
425
+ filter.subscribe((items) => {
428
426
  receivedItems = items;
429
427
  });
430
428
 
@@ -484,8 +482,8 @@ describe('MenoFilter', () => {
484
482
  const result = filter.getFiltered();
485
483
 
486
484
  expect(result).toHaveLength(2);
487
- expect(result[0].title).toBe('Goodbye World');
488
- expect(result[1].title).toBe('Hello World');
485
+ expect(result[0]!.title).toBe('Goodbye World');
486
+ expect(result[1]!.title).toBe('Hello World');
489
487
  });
490
488
  });
491
489
 
@@ -517,8 +515,8 @@ describe('MenoFilter', () => {
517
515
 
518
516
  const pageItems = filter.getItems();
519
517
  expect(pageItems).toHaveLength(3);
520
- expect(pageItems[0]._id).toBe('1');
521
- expect(pageItems[2]._id).toBe('3');
518
+ expect(pageItems[0]!._id).toBe('1');
519
+ expect(pageItems[2]!._id).toBe('3');
522
520
  });
523
521
 
524
522
  test('should return correct page info', async () => {
@@ -546,7 +544,7 @@ describe('MenoFilter', () => {
546
544
 
547
545
  const pageItems = filter.setPage(2);
548
546
  expect(pageItems).toHaveLength(3);
549
- expect(pageItems[0]._id).toBe('4');
547
+ expect(pageItems[0]!._id).toBe('4');
550
548
  expect(filter.getPageInfo().current).toBe(2);
551
549
  });
552
550
 
@@ -607,7 +605,7 @@ describe('MenoFilter', () => {
607
605
 
608
606
  const lastPageItems = filter.setPage(4);
609
607
  expect(lastPageItems).toHaveLength(1); // 10 items, pages 1-3 have 3 each, page 4 has 1
610
- expect(lastPageItems[0]._id).toBe('10');
608
+ expect(lastPageItems[0]!._id).toBe('10');
611
609
  });
612
610
 
613
611
  test('filter() should reset to page 1', async () => {
@@ -648,18 +646,18 @@ describe('MenoFilter', () => {
648
646
  await filter.init();
649
647
 
650
648
  let receivedItems: CMSItemClient[] = [];
651
- filter.subscribe(items => {
649
+ filter.subscribe((items) => {
652
650
  receivedItems = items;
653
651
  });
654
652
 
655
653
  // Initial subscription gets first page
656
654
  expect(receivedItems).toHaveLength(3);
657
- expect(receivedItems[0]._id).toBe('1');
655
+ expect(receivedItems[0]!._id).toBe('1');
658
656
 
659
657
  // Change page
660
658
  filter.setPage(2);
661
659
  expect(receivedItems).toHaveLength(3);
662
- expect(receivedItems[0]._id).toBe('4');
660
+ expect(receivedItems[0]!._id).toBe('4');
663
661
  });
664
662
 
665
663
  test('getFiltered() should return all filtered items ignoring pagination', async () => {
@@ -701,7 +699,7 @@ describe('MenoFilter', () => {
701
699
  const result = filter.filter({ price: { $gt: 100 } });
702
700
 
703
701
  expect(result).toHaveLength(2);
704
- expect(result.map(i => i.price)).toEqual([200, 150]);
702
+ expect(result.map((i) => i.price)).toEqual([200, 150]);
705
703
  });
706
704
 
707
705
  test('should filter numbers from string criteria', async () => {
@@ -718,7 +716,7 @@ describe('MenoFilter', () => {
718
716
  const result = filter.filter({ price: { $gte: '100', $lte: '150' } });
719
717
 
720
718
  expect(result).toHaveLength(2);
721
- expect(result.map(i => i.price)).toEqual([100, 150]);
719
+ expect(result.map((i) => i.price)).toEqual([100, 150]);
722
720
  });
723
721
 
724
722
  test('should filter dates with type coercion', async () => {
@@ -735,7 +733,7 @@ describe('MenoFilter', () => {
735
733
  const result = filter.filter({ date: { $gt: '2024-01-31' } });
736
734
 
737
735
  expect(result).toHaveLength(2);
738
- expect(result.map(i => i.date)).toEqual(['2024-02-15', '2024-03-15']);
736
+ expect(result.map((i) => i.date)).toEqual(['2024-02-15', '2024-03-15']);
739
737
  });
740
738
 
741
739
  test('should filter booleans with type coercion', async () => {
@@ -752,7 +750,7 @@ describe('MenoFilter', () => {
752
750
  const result = filter.filter({ featured: 'true' });
753
751
 
754
752
  expect(result).toHaveLength(2);
755
- expect(result.every(i => i.featured === true)).toBe(true);
753
+ expect(result.every((i) => i.featured === true)).toBe(true);
756
754
  });
757
755
 
758
756
  test('setFieldType() should update field types', async () => {
@@ -773,7 +771,7 @@ describe('MenoFilter', () => {
773
771
  result = filter.filter({ price: { $gt: 100 } });
774
772
 
775
773
  expect(result).toHaveLength(2);
776
- expect(result.map(i => i.price)).toEqual([200, 150]);
774
+ expect(result.map((i) => i.price)).toEqual([200, 150]);
777
775
  });
778
776
 
779
777
  test('setFieldTypes() should set multiple types', async () => {
@@ -820,7 +818,7 @@ describe('MenoFilter', () => {
820
818
  const result = filter.filterRange('price', { min: 100, max: 200 });
821
819
 
822
820
  expect(result).toHaveLength(3);
823
- expect(result.map(i => i.price).sort((a, b) => (a as number) - (b as number))).toEqual([100, 150, 200]);
821
+ expect(result.map((i) => i.price).sort((a, b) => (a as number) - (b as number))).toEqual([100, 150, 200]);
824
822
  });
825
823
 
826
824
  test('should filter with only min', async () => {
@@ -836,7 +834,7 @@ describe('MenoFilter', () => {
836
834
  const result = filter.filterRange('price', { min: 150 });
837
835
 
838
836
  expect(result).toHaveLength(3);
839
- expect(result.every(i => (i.price as number) >= 150)).toBe(true);
837
+ expect(result.every((i) => (i.price as number) >= 150)).toBe(true);
840
838
  });
841
839
 
842
840
  test('should filter with only max', async () => {
@@ -852,7 +850,7 @@ describe('MenoFilter', () => {
852
850
  const result = filter.filterRange('price', { max: 100 });
853
851
 
854
852
  expect(result).toHaveLength(2);
855
- expect(result.every(i => (i.price as number) <= 100)).toBe(true);
853
+ expect(result.every((i) => (i.price as number) <= 100)).toBe(true);
856
854
  });
857
855
 
858
856
  test('should clear filter when both min and max are empty', async () => {
@@ -932,7 +930,7 @@ describe('MenoFilter', () => {
932
930
  const result = filter.search('react', ['title']);
933
931
 
934
932
  expect(result).toHaveLength(1);
935
- expect(result[0].title).toBe('React Hooks Tutorial');
933
+ expect(result[0]!.title).toBe('React Hooks Tutorial');
936
934
  });
937
935
 
938
936
  test('should match with typos when fuzzy enabled', async () => {
@@ -956,7 +954,7 @@ describe('MenoFilter', () => {
956
954
  const result = filter.search('recat', ['title']);
957
955
 
958
956
  expect(result.length).toBeGreaterThanOrEqual(1);
959
- expect(result.some(i => i.title === 'React')).toBe(true);
957
+ expect(result.some((i) => i.title === 'React')).toBe(true);
960
958
  });
961
959
 
962
960
  test('should use exact match for short queries (< 3 chars)', async () => {
@@ -973,7 +971,7 @@ describe('MenoFilter', () => {
973
971
  const result = filter.search('js', ['title']);
974
972
 
975
973
  expect(result).toHaveLength(1);
976
- expect(result[0].title).toBe('Vue.js Components Guide');
974
+ expect(result[0]!.title).toBe('Vue.js Components Guide');
977
975
  });
978
976
 
979
977
  test('setFuzzySearch() should enable/disable fuzzy search', async () => {
@@ -1022,7 +1020,7 @@ describe('MenoFilter', () => {
1022
1020
  const result = filter.search('javascript', ['title']);
1023
1021
 
1024
1022
  expect(result).toHaveLength(1);
1025
- expect(result[0].title).toBe('JavaScript Best Practices');
1023
+ expect(result[0]!.title).toBe('JavaScript Best Practices');
1026
1024
  });
1027
1025
  });
1028
1026
 
@@ -1065,7 +1063,7 @@ describe('MenoFilter', () => {
1065
1063
 
1066
1064
  // Should have called replaceState (default mode)
1067
1065
  expect(mockHistory.replaceState).toHaveBeenCalled();
1068
- const lastCall = mockHistory.replaceState.mock.calls[mockHistory.replaceState.mock.calls.length - 1];
1066
+ const lastCall = mockHistory.replaceState.mock.calls[mockHistory.replaceState.mock.calls.length - 1]!;
1069
1067
  expect(lastCall[2]).toContain('filter.category=tech');
1070
1068
  });
1071
1069
 
@@ -1080,7 +1078,7 @@ describe('MenoFilter', () => {
1080
1078
  filter.filter({ category: 'design' });
1081
1079
 
1082
1080
  expect(mockHistory.pushState).toHaveBeenCalled();
1083
- const lastCall = mockHistory.pushState.mock.calls[mockHistory.pushState.mock.calls.length - 1];
1081
+ const lastCall = mockHistory.pushState.mock.calls[mockHistory.pushState.mock.calls.length - 1]!;
1084
1082
  expect(lastCall[2]).toContain('filter.category=design');
1085
1083
  });
1086
1084
 
@@ -1094,7 +1092,7 @@ describe('MenoFilter', () => {
1094
1092
  filter.enableUrlSync();
1095
1093
  filter.sort('title', 'desc');
1096
1094
 
1097
- const lastCall = mockHistory.replaceState.mock.calls[mockHistory.replaceState.mock.calls.length - 1];
1095
+ const lastCall = mockHistory.replaceState.mock.calls[mockHistory.replaceState.mock.calls.length - 1]!;
1098
1096
  // URLSearchParams encodes : as %3A
1099
1097
  const decodedUrl = decodeURIComponent(lastCall[2] as string);
1100
1098
  expect(decodedUrl).toContain('sort=title:desc');
@@ -1110,7 +1108,7 @@ describe('MenoFilter', () => {
1110
1108
  filter.enableUrlSync();
1111
1109
  filter.search('hello', ['title', 'category']);
1112
1110
 
1113
- const lastCall = mockHistory.replaceState.mock.calls[mockHistory.replaceState.mock.calls.length - 1];
1111
+ const lastCall = mockHistory.replaceState.mock.calls[mockHistory.replaceState.mock.calls.length - 1]!;
1114
1112
  // URLSearchParams encodes , as %2C
1115
1113
  const decodedUrl = decodeURIComponent(lastCall[2] as string);
1116
1114
  expect(decodedUrl).toContain('search=hello');
@@ -1132,7 +1130,7 @@ describe('MenoFilter', () => {
1132
1130
  filter.enableUrlSync();
1133
1131
  filter.setPage(3);
1134
1132
 
1135
- const lastCall = mockHistory.replaceState.mock.calls[mockHistory.replaceState.mock.calls.length - 1];
1133
+ const lastCall = mockHistory.replaceState.mock.calls[mockHistory.replaceState.mock.calls.length - 1]!;
1136
1134
  expect(lastCall[2]).toContain('page=3');
1137
1135
  });
1138
1136
 
@@ -1149,7 +1147,7 @@ describe('MenoFilter', () => {
1149
1147
  filter.enableUrlSync();
1150
1148
  filter.filter({ views: { $gt: 100, $lte: 200 } });
1151
1149
 
1152
- const lastCall = mockHistory.replaceState.mock.calls[mockHistory.replaceState.mock.calls.length - 1];
1150
+ const lastCall = mockHistory.replaceState.mock.calls[mockHistory.replaceState.mock.calls.length - 1]!;
1153
1151
  // URLSearchParams encodes $ as %24
1154
1152
  const decodedUrl = decodeURIComponent(lastCall[2] as string);
1155
1153
  expect(decodedUrl).toContain('filter.views.$gt=100');
@@ -562,7 +562,9 @@ export class MenoFilter {
562
562
  const value = item[field];
563
563
  if (value !== undefined && value !== null) {
564
564
  if (Array.isArray(value)) {
565
- value.forEach((v) => values.add(v));
565
+ value.forEach((v) => {
566
+ values.add(v);
567
+ });
566
568
  } else {
567
569
  values.add(value);
568
570
  }
@@ -669,12 +671,12 @@ export class MenoFilter {
669
671
  case 'number': {
670
672
  if (typeof value === 'number') return value;
671
673
  const num = parseFloat(String(value));
672
- return isNaN(num) ? value : num;
674
+ return Number.isNaN(num) ? value : num;
673
675
  }
674
676
  case 'date': {
675
677
  if (value instanceof Date) return value.getTime();
676
678
  const time = new Date(String(value)).getTime();
677
- return isNaN(time) ? value : time;
679
+ return Number.isNaN(time) ? value : time;
678
680
  }
679
681
  case 'boolean':
680
682
  return value === true || value === 'true' || value === '1';
@@ -797,9 +799,7 @@ export class MenoFilter {
797
799
  }
798
800
 
799
801
  const queryString = params.toString();
800
- const url = queryString
801
- ? `${window.location.pathname}?${queryString}`
802
- : window.location.pathname;
802
+ const url = queryString ? `${window.location.pathname}?${queryString}` : window.location.pathname;
803
803
 
804
804
  if (this.urlMode === 'push') {
805
805
  history.pushState(null, '', url);
@@ -825,6 +825,7 @@ export class MenoFilter {
825
825
  const parts = key.split('.');
826
826
  const field = parts[1];
827
827
  const op = parts[2]; // Optional operator
828
+ if (field === undefined) continue;
828
829
 
829
830
  if (op) {
830
831
  // Operator: filter.price.$gt=100
@@ -845,7 +846,7 @@ export class MenoFilter {
845
846
  // Parse sort
846
847
  const sortParam = params.get('sort');
847
848
  if (sortParam) {
848
- const [field, order = 'asc'] = sortParam.split(':');
849
+ const [field = '', order = 'asc'] = sortParam.split(':');
849
850
  this.sortConfig = { field, order: order as 'asc' | 'desc' };
850
851
  }
851
852
 
@@ -863,7 +864,7 @@ export class MenoFilter {
863
864
  const pageParam = params.get('page');
864
865
  if (pageParam) {
865
866
  const page = parseInt(pageParam, 10);
866
- if (!isNaN(page) && page > 0) {
867
+ if (!Number.isNaN(page) && page > 0) {
867
868
  this.currentPage = page;
868
869
  }
869
870
  }
@@ -872,7 +873,7 @@ export class MenoFilter {
872
873
  const perPageParam = params.get('perPage');
873
874
  if (perPageParam) {
874
875
  const perPage = parseInt(perPageParam, 10);
875
- if (!isNaN(perPage) && perPage > 0) {
876
+ if (!Number.isNaN(perPage) && perPage > 0) {
876
877
  this.perPage = perPage;
877
878
  }
878
879
  }
@@ -1082,17 +1083,14 @@ export class MenoFilter {
1082
1083
 
1083
1084
  // Apply OR criteria
1084
1085
  if (this.orCriteria.length > 0) {
1085
- result = result.filter((item) =>
1086
- this.orCriteria.some((criteria) => this.matchesCriteria(item, criteria))
1087
- );
1086
+ result = result.filter((item) => this.orCriteria.some((criteria) => this.matchesCriteria(item, criteria)));
1088
1087
  }
1089
1088
 
1090
1089
  // Apply search
1091
1090
  if (this.searchQuery) {
1092
1091
  const query = this.searchQuery;
1093
1092
  result = result.filter((item) => {
1094
- const fieldsToSearch =
1095
- this.searchFields.length > 0 ? this.searchFields : Object.keys(item);
1093
+ const fieldsToSearch = this.searchFields.length > 0 ? this.searchFields : Object.keys(item);
1096
1094
  return fieldsToSearch.some((field) => {
1097
1095
  const value = item[field];
1098
1096
  if (typeof value !== 'string') return false;
@@ -1259,13 +1257,14 @@ export class MenoFilter {
1259
1257
  case '$nin':
1260
1258
  return Array.isArray(opValue) ? !opValue.includes(itemValue) : true;
1261
1259
 
1262
- case '$empty':
1260
+ case '$empty': {
1263
1261
  const isEmpty =
1264
1262
  itemValue === undefined ||
1265
1263
  itemValue === null ||
1266
1264
  itemValue === '' ||
1267
1265
  (Array.isArray(itemValue) && itemValue.length === 0);
1268
1266
  return opValue ? isEmpty : !isEmpty;
1267
+ }
1269
1268
 
1270
1269
  default:
1271
1270
  console.warn(`MenoFilter: Unknown operator "${op}"`);
@@ -5,7 +5,7 @@
5
5
  * to MenoFilter instances via data attributes.
6
6
  */
7
7
 
8
- import { MenoFilter } from './MenoFilter';
8
+ import type { MenoFilter } from './MenoFilter';
9
9
  import { ATTR } from './constants';
10
10
  import type { FilterInstance, FilterMode } from './types';
11
11
 
@@ -42,12 +42,7 @@ function getFilterMode(element: HTMLElement): FilterMode | null {
42
42
  * Handle button click in multi-select mode
43
43
  * Toggles value in $in array
44
44
  */
45
- function handleMultiButtonClick(
46
- filter: MenoFilter,
47
- field: string,
48
- value: string,
49
- currentValue: unknown
50
- ): void {
45
+ function handleMultiButtonClick(filter: MenoFilter, field: string, value: string, currentValue: unknown): void {
51
46
  // Get current values as array
52
47
  let values: string[] = [];
53
48
  if (currentValue !== undefined) {
@@ -87,9 +82,7 @@ export function bindFilterControls(instance: FilterInstance): void {
87
82
  const { wrapper, filter, cleanup } = instance;
88
83
 
89
84
  // Filter buttons
90
- const filterButtons = wrapper.querySelectorAll<HTMLElement>(
91
- `[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`
92
- );
85
+ const filterButtons = wrapper.querySelectorAll<HTMLElement>(`[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`);
93
86
 
94
87
  for (const btn of filterButtons) {
95
88
  if (btn.tagName === 'INPUT') continue; // Handle inputs separately
@@ -118,7 +111,6 @@ export function bindFilterControls(instance: FilterInstance): void {
118
111
  filter.addFilter(field, value);
119
112
  }
120
113
  }
121
-
122
114
  };
123
115
 
124
116
  btn.addEventListener('click', handler);
@@ -126,9 +118,7 @@ export function bindFilterControls(instance: FilterInstance): void {
126
118
  }
127
119
 
128
120
  // Filter checkboxes (allow multiple selections with OR logic)
129
- const filterCheckboxes = wrapper.querySelectorAll<HTMLInputElement>(
130
- `input[type="checkbox"][${ATTR.FILTER_FIELD}]`
131
- );
121
+ const filterCheckboxes = wrapper.querySelectorAll<HTMLInputElement>(`input[type="checkbox"][${ATTR.FILTER_FIELD}]`);
132
122
 
133
123
  for (const checkbox of filterCheckboxes) {
134
124
  const field = checkbox.getAttribute(ATTR.FILTER_FIELD)!;
@@ -139,7 +129,7 @@ export function bindFilterControls(instance: FilterInstance): void {
139
129
  // Single mode: uncheck other checkboxes in the same field
140
130
  if (mode === 'single' && checkbox.checked) {
141
131
  const siblings = wrapper.querySelectorAll<HTMLInputElement>(
142
- `input[type="checkbox"][${ATTR.FILTER_FIELD}="${field}"]`
132
+ `input[type="checkbox"][${ATTR.FILTER_FIELD}="${field}"]`,
143
133
  );
144
134
  for (const sibling of siblings) {
145
135
  if (sibling !== checkbox) {
@@ -156,9 +146,7 @@ export function bindFilterControls(instance: FilterInstance): void {
156
146
  }
157
147
 
158
148
  // Filter selects
159
- const filterSelects = wrapper.querySelectorAll<HTMLSelectElement>(
160
- `select[${ATTR.FILTER_FIELD}]`
161
- );
149
+ const filterSelects = wrapper.querySelectorAll<HTMLSelectElement>(`select[${ATTR.FILTER_FIELD}]`);
162
150
 
163
151
  for (const select of filterSelects) {
164
152
  const field = select.getAttribute(ATTR.FILTER_FIELD)!;
@@ -177,9 +165,7 @@ export function bindFilterControls(instance: FilterInstance): void {
177
165
  }
178
166
 
179
167
  // Filter radio buttons
180
- const filterRadios = wrapper.querySelectorAll<HTMLInputElement>(
181
- `input[type="radio"][${ATTR.FILTER_FIELD}]`
182
- );
168
+ const filterRadios = wrapper.querySelectorAll<HTMLInputElement>(`input[type="radio"][${ATTR.FILTER_FIELD}]`);
183
169
 
184
170
  for (const radio of filterRadios) {
185
171
  const field = radio.getAttribute(ATTR.FILTER_FIELD)!;
@@ -203,18 +189,12 @@ export function bindFilterControls(instance: FilterInstance): void {
203
189
  /**
204
190
  * Update filters based on checked checkboxes for a field
205
191
  */
206
- function updateCheckboxFilters(
207
- wrapper: HTMLElement,
208
- filter: MenoFilter,
209
- field: string
210
- ): void {
192
+ function updateCheckboxFilters(wrapper: HTMLElement, filter: MenoFilter, field: string): void {
211
193
  const checkboxes = wrapper.querySelectorAll<HTMLInputElement>(
212
- `input[type="checkbox"][${ATTR.FILTER_FIELD}="${field}"]:checked`
194
+ `input[type="checkbox"][${ATTR.FILTER_FIELD}="${field}"]:checked`,
213
195
  );
214
196
 
215
- const values = Array.from(checkboxes).map(
216
- (cb) => cb.getAttribute(ATTR.FILTER_VALUE) || cb.value
217
- );
197
+ const values = Array.from(checkboxes).map((cb) => cb.getAttribute(ATTR.FILTER_VALUE) || cb.value);
218
198
 
219
199
  if (values.length === 0) {
220
200
  filter.removeFilter(field);
@@ -311,7 +291,7 @@ export function bindSortControls(instance: FilterInstance): void {
311
291
  }
312
292
 
313
293
  // Parse "field:order" format
314
- const [field, order = 'asc'] = value.split(':');
294
+ const [field = '', order = 'asc'] = value.split(':');
315
295
  filter.sort(field, order as 'asc' | 'desc');
316
296
  };
317
297
 
@@ -363,17 +343,13 @@ export function bindActionControls(instance: FilterInstance): void {
363
343
  */
364
344
  export function resetFormControls(wrapper: HTMLElement): void {
365
345
  // Reset checkboxes
366
- const checkboxes = wrapper.querySelectorAll<HTMLInputElement>(
367
- `input[type="checkbox"][${ATTR.FILTER_FIELD}]`
368
- );
346
+ const checkboxes = wrapper.querySelectorAll<HTMLInputElement>(`input[type="checkbox"][${ATTR.FILTER_FIELD}]`);
369
347
  for (const cb of checkboxes) {
370
348
  cb.checked = false;
371
349
  }
372
350
 
373
351
  // Reset selects
374
- const selects = wrapper.querySelectorAll<HTMLSelectElement>(
375
- `select[${ATTR.FILTER_FIELD}]`
376
- );
352
+ const selects = wrapper.querySelectorAll<HTMLSelectElement>(`select[${ATTR.FILTER_FIELD}]`);
377
353
  for (const select of selects) {
378
354
  select.selectedIndex = 0;
379
355
  }
@@ -421,12 +397,13 @@ export function bindPaginationControls(instance: FilterInstance): void {
421
397
  case 'last':
422
398
  filter.setPage(filter.getPageInfo().total);
423
399
  break;
424
- default:
400
+ default: {
425
401
  // Numeric page
426
402
  const page = parseInt(action || '1', 10);
427
- if (!isNaN(page)) {
403
+ if (!Number.isNaN(page)) {
428
404
  filter.setPage(page);
429
405
  }
406
+ }
430
407
  }
431
408
  };
432
409
 
@@ -435,14 +412,12 @@ export function bindPaginationControls(instance: FilterInstance): void {
435
412
  }
436
413
 
437
414
  // Per-page select
438
- const perPageSelects = wrapper.querySelectorAll<HTMLSelectElement>(
439
- `[${ATTR.PER_PAGE_SELECT}]`
440
- );
415
+ const perPageSelects = wrapper.querySelectorAll<HTMLSelectElement>(`[${ATTR.PER_PAGE_SELECT}]`);
441
416
 
442
417
  for (const select of perPageSelects) {
443
418
  const handler = () => {
444
419
  const perPage = parseInt(select.value, 10);
445
- if (!isNaN(perPage) && perPage > 0) {
420
+ if (!Number.isNaN(perPage) && perPage > 0) {
446
421
  filter.setPerPage(perPage);
447
422
  }
448
423
  };
@@ -79,7 +79,7 @@ async function initFilterInstance(wrapper: HTMLElement, collection: string): Pro
79
79
  const thresholdAttr = searchInput.getAttribute(ATTR.SEARCH_THRESHOLD);
80
80
  if (thresholdAttr) {
81
81
  const parsed = parseFloat(thresholdAttr);
82
- if (!isNaN(parsed)) {
82
+ if (!Number.isNaN(parsed)) {
83
83
  fuzzyThreshold = parsed;
84
84
  }
85
85
  }
@@ -136,7 +136,7 @@ async function initFilterInstance(wrapper: HTMLElement, collection: string): Pro
136
136
  cleanup.push(
137
137
  filter.watch(() => {
138
138
  updateUI(instance);
139
- })
139
+ }),
140
140
  );
141
141
  }
142
142
 
@@ -165,7 +165,7 @@ function extractItemTemplate(wrapper: HTMLElement): {
165
165
  const itemTemplate = emittedTemplate.innerHTML.trim();
166
166
  // Detect itemAs from template variables (e.g., {{post.title}} → "post")
167
167
  const match = itemTemplate.match(/\{\{(\w+)\./);
168
- if (match) itemAs = match[1];
168
+ if (match && match[1] !== undefined) itemAs = match[1];
169
169
 
170
170
  // Store SSR'd items by their data-id for potential reuse
171
171
  for (const child of Array.from(listEl.children) as HTMLElement[]) {
@@ -184,7 +184,7 @@ function extractItemTemplate(wrapper: HTMLElement): {
184
184
  if (userTemplate) {
185
185
  const itemTemplate = userTemplate.innerHTML.trim();
186
186
  const match = itemTemplate.match(/\{\{(\w+)\./);
187
- if (match) itemAs = match[1];
187
+ if (match && match[1] !== undefined) itemAs = match[1];
188
188
  return { itemTemplate, ssrItems, itemAs };
189
189
  }
190
190