meno-core 1.0.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 (231) hide show
  1. package/bin/cli.ts +281 -0
  2. package/build-static.ts +298 -0
  3. package/bunfig.toml +39 -0
  4. package/entries/client-router.tsx +111 -0
  5. package/entries/server-router.tsx +71 -0
  6. package/lib/client/ClientInitializer.test.ts +9 -0
  7. package/lib/client/ClientInitializer.test.ts.skip +92 -0
  8. package/lib/client/ClientInitializer.ts +60 -0
  9. package/lib/client/ErrorBoundary.test.tsx +595 -0
  10. package/lib/client/ErrorBoundary.tsx +230 -0
  11. package/lib/client/componentRegistry.test.ts +165 -0
  12. package/lib/client/componentRegistry.ts +18 -0
  13. package/lib/client/contexts/ThemeContext.tsx +73 -0
  14. package/lib/client/core/ComponentBuilder.test.ts +677 -0
  15. package/lib/client/core/ComponentBuilder.ts +660 -0
  16. package/lib/client/core/ComponentRenderer.test.tsx +176 -0
  17. package/lib/client/core/ComponentRenderer.tsx +83 -0
  18. package/lib/client/core/cmsTemplateProcessor.ts +129 -0
  19. package/lib/client/elementRegistry.ts +81 -0
  20. package/lib/client/hmr/HMRManager.tsx +179 -0
  21. package/lib/client/hmr/index.ts +5 -0
  22. package/lib/client/hmrWebSocket.test.ts +9 -0
  23. package/lib/client/hmrWebSocket.ts +250 -0
  24. package/lib/client/hooks/useColorVariables.test.ts +166 -0
  25. package/lib/client/hooks/useColorVariables.ts +249 -0
  26. package/lib/client/hooks/usePropertyAutocomplete.test.ts +9 -0
  27. package/lib/client/hooks/usePropertyAutocomplete.ts +40 -0
  28. package/lib/client/hydration/HydrationUtils.test.ts +154 -0
  29. package/lib/client/hydration/HydrationUtils.ts +35 -0
  30. package/lib/client/i18nConfigService.test.ts +74 -0
  31. package/lib/client/i18nConfigService.ts +78 -0
  32. package/lib/client/index.ts +56 -0
  33. package/lib/client/navigation.test.ts +441 -0
  34. package/lib/client/navigation.ts +23 -0
  35. package/lib/client/responsiveStyleResolver.test.ts +491 -0
  36. package/lib/client/responsiveStyleResolver.ts +184 -0
  37. package/lib/client/routing/RouteLoader.test.ts +635 -0
  38. package/lib/client/routing/RouteLoader.ts +347 -0
  39. package/lib/client/routing/Router.tsx +382 -0
  40. package/lib/client/scripts/ScriptExecutor.test.ts +489 -0
  41. package/lib/client/scripts/ScriptExecutor.ts +171 -0
  42. package/lib/client/scripts/formHandler.ts +103 -0
  43. package/lib/client/styleProcessor.test.ts +126 -0
  44. package/lib/client/styleProcessor.ts +92 -0
  45. package/lib/client/styles/StyleInjector.test.ts +354 -0
  46. package/lib/client/styles/StyleInjector.ts +154 -0
  47. package/lib/client/templateEngine.test.ts +660 -0
  48. package/lib/client/templateEngine.ts +667 -0
  49. package/lib/client/theme.test.ts +173 -0
  50. package/lib/client/theme.ts +159 -0
  51. package/lib/client/utils/toast.ts +46 -0
  52. package/lib/server/createServer.ts +170 -0
  53. package/lib/server/cssGenerator.test.ts +172 -0
  54. package/lib/server/cssGenerator.ts +58 -0
  55. package/lib/server/fileWatcher.ts +134 -0
  56. package/lib/server/index.ts +55 -0
  57. package/lib/server/jsonLoader.test.ts +103 -0
  58. package/lib/server/jsonLoader.ts +350 -0
  59. package/lib/server/middleware/cors.test.ts +177 -0
  60. package/lib/server/middleware/cors.ts +69 -0
  61. package/lib/server/middleware/errorHandler.test.ts +208 -0
  62. package/lib/server/middleware/errorHandler.ts +63 -0
  63. package/lib/server/middleware/index.ts +9 -0
  64. package/lib/server/middleware/logger.test.ts +233 -0
  65. package/lib/server/middleware/logger.ts +99 -0
  66. package/lib/server/pageCache.test.ts +167 -0
  67. package/lib/server/pageCache.ts +97 -0
  68. package/lib/server/projectContext.ts +51 -0
  69. package/lib/server/providers/fileSystemCMSProvider.test.ts +292 -0
  70. package/lib/server/providers/fileSystemCMSProvider.ts +227 -0
  71. package/lib/server/providers/fileSystemPageProvider.ts +83 -0
  72. package/lib/server/routes/api/cms.test.ts +177 -0
  73. package/lib/server/routes/api/cms.ts +82 -0
  74. package/lib/server/routes/api/colors.ts +59 -0
  75. package/lib/server/routes/api/components.ts +70 -0
  76. package/lib/server/routes/api/config.test.ts +9 -0
  77. package/lib/server/routes/api/config.ts +28 -0
  78. package/lib/server/routes/api/core-routes.ts +182 -0
  79. package/lib/server/routes/api/functions.ts +170 -0
  80. package/lib/server/routes/api/index.ts +69 -0
  81. package/lib/server/routes/api/pages.ts +95 -0
  82. package/lib/server/routes/api/shared.test.ts +81 -0
  83. package/lib/server/routes/api/shared.ts +31 -0
  84. package/lib/server/routes/editor.test.ts +9 -0
  85. package/lib/server/routes/index.ts +104 -0
  86. package/lib/server/routes/pages.ts +161 -0
  87. package/lib/server/routes/static.ts +107 -0
  88. package/lib/server/services/ColorService.ts +193 -0
  89. package/lib/server/services/cmsService.test.ts +388 -0
  90. package/lib/server/services/cmsService.ts +296 -0
  91. package/lib/server/services/componentService.test.ts +276 -0
  92. package/lib/server/services/componentService.ts +346 -0
  93. package/lib/server/services/configService.ts +156 -0
  94. package/lib/server/services/fileWatcherService.ts +67 -0
  95. package/lib/server/services/index.ts +10 -0
  96. package/lib/server/services/pageService.test.ts +258 -0
  97. package/lib/server/services/pageService.ts +240 -0
  98. package/lib/server/ssrRenderer.test.ts +1005 -0
  99. package/lib/server/ssrRenderer.ts +878 -0
  100. package/lib/server/utilityClassGenerator.ts +11 -0
  101. package/lib/server/utils/index.ts +5 -0
  102. package/lib/server/utils/jsonLineMapper.test.ts +100 -0
  103. package/lib/server/utils/jsonLineMapper.ts +166 -0
  104. package/lib/server/validateStyleCoverage.test.ts +9 -0
  105. package/lib/server/validateStyleCoverage.ts +167 -0
  106. package/lib/server/websocketManager.test.ts +9 -0
  107. package/lib/server/websocketManager.ts +95 -0
  108. package/lib/shared/attributeNodeUtils.test.ts +152 -0
  109. package/lib/shared/attributeNodeUtils.ts +50 -0
  110. package/lib/shared/breakpoints.test.ts +166 -0
  111. package/lib/shared/breakpoints.ts +65 -0
  112. package/lib/shared/colorProperties.test.ts +111 -0
  113. package/lib/shared/colorProperties.ts +40 -0
  114. package/lib/shared/colorVariableUtils.test.ts +319 -0
  115. package/lib/shared/colorVariableUtils.ts +97 -0
  116. package/lib/shared/constants.test.ts +175 -0
  117. package/lib/shared/constants.ts +116 -0
  118. package/lib/shared/cssGeneration.ts +481 -0
  119. package/lib/shared/cssProperties.test.ts +252 -0
  120. package/lib/shared/cssProperties.ts +338 -0
  121. package/lib/shared/elementUtils.test.ts +245 -0
  122. package/lib/shared/elementUtils.ts +90 -0
  123. package/lib/shared/fontLoader.ts +97 -0
  124. package/lib/shared/i18n.test.ts +313 -0
  125. package/lib/shared/i18n.ts +286 -0
  126. package/lib/shared/index.ts +50 -0
  127. package/lib/shared/interfaces/contentProvider.test.ts +9 -0
  128. package/lib/shared/interfaces/contentProvider.ts +121 -0
  129. package/lib/shared/nodeUtils.test.ts +320 -0
  130. package/lib/shared/nodeUtils.ts +220 -0
  131. package/lib/shared/pathArrayUtils.test.ts +315 -0
  132. package/lib/shared/pathArrayUtils.ts +17 -0
  133. package/lib/shared/pathUtils.test.ts +260 -0
  134. package/lib/shared/pathUtils.ts +244 -0
  135. package/lib/shared/paths/Path.test.ts +74 -0
  136. package/lib/shared/paths/Path.ts +23 -0
  137. package/lib/shared/paths/PathConverter.test.ts +232 -0
  138. package/lib/shared/paths/PathConverter.ts +141 -0
  139. package/lib/shared/paths/PathUtils.ts +290 -0
  140. package/lib/shared/paths/PathValidator.test.ts +193 -0
  141. package/lib/shared/paths/PathValidator.ts +53 -0
  142. package/lib/shared/paths/index.ts +48 -0
  143. package/lib/shared/propResolver.test.ts +639 -0
  144. package/lib/shared/propResolver.ts +124 -0
  145. package/lib/shared/registry/BaseNodeTypeRegistry.test.ts +190 -0
  146. package/lib/shared/registry/BaseNodeTypeRegistry.ts +200 -0
  147. package/lib/shared/registry/ClientNodeTypeRegistry.ts +34 -0
  148. package/lib/shared/registry/ClientRegistry.test.ts +26 -0
  149. package/lib/shared/registry/ClientRegistry.ts +15 -0
  150. package/lib/shared/registry/ComponentRegistry.test.ts +293 -0
  151. package/lib/shared/registry/ComponentRegistry.ts +100 -0
  152. package/lib/shared/registry/NodeTypeDefinition.ts +198 -0
  153. package/lib/shared/registry/NodeTypeManager.ts +94 -0
  154. package/lib/shared/registry/RegistryManager.test.ts +58 -0
  155. package/lib/shared/registry/RegistryManager.ts +60 -0
  156. package/lib/shared/registry/SSRNodeTypeRegistry.ts +33 -0
  157. package/lib/shared/registry/SSRRegistry.test.ts +26 -0
  158. package/lib/shared/registry/SSRRegistry.ts +15 -0
  159. package/lib/shared/registry/createNodeType.ts +175 -0
  160. package/lib/shared/registry/defineNodeType.ts +73 -0
  161. package/lib/shared/registry/fieldPresets.ts +109 -0
  162. package/lib/shared/registry/index.ts +50 -0
  163. package/lib/shared/registry/nodeTypes/ComponentInstanceNodeType.ts +71 -0
  164. package/lib/shared/registry/nodeTypes/EmbedNodeType.ts +61 -0
  165. package/lib/shared/registry/nodeTypes/HtmlNodeType.ts +88 -0
  166. package/lib/shared/registry/nodeTypes/LocaleListNodeType.ts +66 -0
  167. package/lib/shared/registry/nodeTypes/ObjectLinkNodeType.ts +75 -0
  168. package/lib/shared/registry/nodeTypes/SlotMarkerType.ts +49 -0
  169. package/lib/shared/registry/nodeTypes/TextNodeType.ts +52 -0
  170. package/lib/shared/registry/nodeTypes/index.ts +75 -0
  171. package/lib/shared/responsiveScaling.test.ts +268 -0
  172. package/lib/shared/responsiveScaling.ts +194 -0
  173. package/lib/shared/responsiveStyleUtils.test.ts +300 -0
  174. package/lib/shared/responsiveStyleUtils.ts +139 -0
  175. package/lib/shared/slugTranslator.test.ts +325 -0
  176. package/lib/shared/slugTranslator.ts +177 -0
  177. package/lib/shared/styleNodeUtils.test.ts +132 -0
  178. package/lib/shared/styleNodeUtils.ts +102 -0
  179. package/lib/shared/styleUtils.test.ts +238 -0
  180. package/lib/shared/styleUtils.ts +63 -0
  181. package/lib/shared/themeDefaults.test.ts +113 -0
  182. package/lib/shared/themeDefaults.ts +103 -0
  183. package/lib/shared/tree/PathBuilder.ts +383 -0
  184. package/lib/shared/treePathUtils.test.ts +539 -0
  185. package/lib/shared/treePathUtils.ts +339 -0
  186. package/lib/shared/types/api.ts +58 -0
  187. package/lib/shared/types/cms.ts +95 -0
  188. package/lib/shared/types/colors.ts +45 -0
  189. package/lib/shared/types/components.ts +121 -0
  190. package/lib/shared/types/errors.test.ts +103 -0
  191. package/lib/shared/types/errors.ts +69 -0
  192. package/lib/shared/types/index.ts +96 -0
  193. package/lib/shared/types/nodes.ts +20 -0
  194. package/lib/shared/types/rendering.ts +61 -0
  195. package/lib/shared/types/styles.ts +38 -0
  196. package/lib/shared/types.ts +11 -0
  197. package/lib/shared/utilityClassConfig.ts +287 -0
  198. package/lib/shared/utilityClassMapper.test.ts +140 -0
  199. package/lib/shared/utilityClassMapper.ts +229 -0
  200. package/lib/shared/utils/fileUtils.test.ts +99 -0
  201. package/lib/shared/utils/fileUtils.ts +56 -0
  202. package/lib/shared/utils.test.ts +261 -0
  203. package/lib/shared/utils.ts +84 -0
  204. package/lib/shared/validation/index.ts +7 -0
  205. package/lib/shared/validation/propValidator.test.ts +178 -0
  206. package/lib/shared/validation/propValidator.ts +238 -0
  207. package/lib/shared/validation/schemas.test.ts +177 -0
  208. package/lib/shared/validation/schemas.ts +401 -0
  209. package/lib/shared/validation/validators.test.ts +109 -0
  210. package/lib/shared/validation/validators.ts +304 -0
  211. package/lib/test-utils/dom-setup.ts +55 -0
  212. package/lib/test-utils/factories/ConsoleMockFactory.ts +200 -0
  213. package/lib/test-utils/factories/DomMockFactory.ts +487 -0
  214. package/lib/test-utils/factories/EventMockFactory.ts +244 -0
  215. package/lib/test-utils/factories/FetchMockFactory.ts +210 -0
  216. package/lib/test-utils/factories/ServerMockFactory.ts +223 -0
  217. package/lib/test-utils/factories/StoreMockFactory.ts +370 -0
  218. package/lib/test-utils/factories/index.ts +11 -0
  219. package/lib/test-utils/fixtures.ts +134 -0
  220. package/lib/test-utils/helpers/asyncHelpers.test.ts +112 -0
  221. package/lib/test-utils/helpers/asyncHelpers.ts +196 -0
  222. package/lib/test-utils/helpers/index.ts +6 -0
  223. package/lib/test-utils/helpers.test.ts +73 -0
  224. package/lib/test-utils/helpers.ts +90 -0
  225. package/lib/test-utils/index.ts +17 -0
  226. package/lib/test-utils/mockFactories.ts +92 -0
  227. package/lib/test-utils/mocks.ts +341 -0
  228. package/package.json +38 -0
  229. package/templates/index-router.html +34 -0
  230. package/tsconfig.json +14 -0
  231. package/vite.config.ts +43 -0
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Mock Factories
3
+ * Factory functions for creating mock objects used in tests
4
+ */
5
+
6
+ import { mock } from 'bun:test';
7
+ import type { ComponentRegistry } from '../client/componentRegistry';
8
+ import type { ComponentNode, ComponentDefinition, JSONPage, PageDataWithComponent } from '../shared/types';
9
+ import type { ElementRegistry } from '../client/elementRegistry';
10
+
11
+ // HighlightManager interface (module was removed, keeping type for mock compatibility)
12
+ interface HighlightManager {
13
+ highlightElements: (paths: string[]) => void;
14
+ setHoveredElement: (path: string | null) => void;
15
+ clearHover: () => void;
16
+ clearAll: () => void;
17
+ }
18
+ import { NODE_TYPE } from '../shared/constants';
19
+
20
+ /**
21
+ * Create a mock ComponentRegistry
22
+ */
23
+ export function createMockComponentRegistry(): ComponentRegistry {
24
+ return {
25
+ has: mock(() => false),
26
+ get: mock(() => undefined),
27
+ set: mock(() => {}),
28
+ delete: mock(() => {}),
29
+ clear: mock(() => {}),
30
+ getAll: mock(() => ({})),
31
+ } as any;
32
+ }
33
+
34
+ /**
35
+ * Create a mock ComponentNode
36
+ */
37
+ export function createMockComponentNode(overrides?: Partial<ComponentNode>): ComponentNode {
38
+ return {
39
+ type: NODE_TYPE.NODE,
40
+ tag: 'div',
41
+ children: [],
42
+ ...overrides,
43
+ } as ComponentNode;
44
+ }
45
+
46
+ /**
47
+ * Create a mock ComponentDefinition
48
+ */
49
+ export function createMockComponentDefinition(name: string, overrides?: Partial<ComponentDefinition>): ComponentDefinition {
50
+ return {
51
+ component: {
52
+ interface: {},
53
+ structure: {
54
+ type: NODE_TYPE.NODE,
55
+ tag: 'div',
56
+ children: [],
57
+ },
58
+ },
59
+ ...overrides,
60
+ } as ComponentDefinition;
61
+ }
62
+
63
+ /**
64
+ * Create a mock PageData
65
+ */
66
+ export function createMockPageData(overrides?: Partial<JSONPage>): JSONPage {
67
+ return {
68
+ meta: {
69
+ title: 'Test Page',
70
+ },
71
+ root: {
72
+ type: NODE_TYPE.NODE,
73
+ tag: 'div',
74
+ children: [],
75
+ },
76
+ ...overrides,
77
+ } as JSONPage;
78
+ }
79
+
80
+ /**
81
+ * Create a mock PageDataWithComponent
82
+ */
83
+ export function createMockPageDataWithComponent(overrides?: Partial<PageDataWithComponent>): PageDataWithComponent {
84
+ return {
85
+ component: {
86
+ interface: {},
87
+ structure: {
88
+ type: NODE_TYPE.NODE,
89
+ tag: 'div',
90
+ children: [],
91
+ },
92
+ javascript: '',
93
+ css: '',
94
+ ...overrides?.component,
95
+ },
96
+ } as PageDataWithComponent;
97
+ }
98
+
99
+ /**
100
+ * Create a mock HighlightManager
101
+ */
102
+ export function createMockHighlightManager(): HighlightManager {
103
+ return {
104
+ highlightElements: mock(() => {}),
105
+ setHoveredElement: mock(() => {}),
106
+ clearHover: mock(() => {}),
107
+ clearAll: mock(() => {}),
108
+ } as any;
109
+ }
110
+
111
+ /**
112
+ * Create a mock ElementRegistry
113
+ */
114
+ export function createMockElementRegistry(): ElementRegistry {
115
+ return {
116
+ register: mock(() => {}),
117
+ get: mock(() => null),
118
+ getAllComponentNames: mock(() => []),
119
+ getComponentRootPaths: mock(() => []),
120
+ getComponentProps: mock(() => undefined),
121
+ clear: mock(() => {}),
122
+ } as any;
123
+ }
124
+
125
+ /**
126
+ * Create a mock EditorStore
127
+ */
128
+ export function createMockEditorStore() {
129
+ return {
130
+ files: [],
131
+ selectedFile: null,
132
+ pageData: null,
133
+ selectedTreeItem: null,
134
+ setFiles: mock(() => {}),
135
+ setSelectedFile: mock(() => {}),
136
+ setPageData: mock(() => {}),
137
+ setSelectedTreeItem: mock(() => {}),
138
+ updateProp: mock(() => Promise.resolve()),
139
+ // Async file operations are now in editorServices.fileStoreService
140
+ } as any;
141
+ }
142
+
143
+ /**
144
+ * Create a mock editorServices object with all services mocked
145
+ */
146
+ export function createMockEditorServices() {
147
+ return {
148
+ fileService: {
149
+ loadAllFiles: mock(() => Promise.resolve({ pages: [], components: [] })),
150
+ loadFileData: mock(() => Promise.resolve({ component: { type: 'div', children: [] } })),
151
+ saveFileData: mock(() => Promise.resolve()),
152
+ saveComponentJS: mock(() => Promise.resolve()),
153
+ saveComponentCSS: mock(() => Promise.resolve()),
154
+ },
155
+ nodeService: {
156
+ addElement: mock(() => Promise.resolve()),
157
+ deleteElement: mock(() => Promise.resolve()),
158
+ moveElement: mock(() => Promise.resolve()),
159
+ },
160
+ componentService: {
161
+ loadComponentDefinition: mock(() => Promise.resolve()),
162
+ createFromSelection: mock(() => Promise.resolve()),
163
+ },
164
+ fileStoreService: {
165
+ loadFiles: mock(() => Promise.resolve()),
166
+ selectFile: mock(() => Promise.resolve({ component: { type: 'div', children: [] } })),
167
+ reloadSelectedFilePreservingSelection: mock(() => Promise.resolve({ component: { type: 'div', children: [] } })),
168
+ },
169
+ } as any;
170
+ }
171
+
172
+ /**
173
+ * Create a mock Window object
174
+ */
175
+ export function createMockWindow(): Window {
176
+ return {
177
+ location: {
178
+ href: 'http://localhost/',
179
+ pathname: '/',
180
+ search: '',
181
+ hash: '',
182
+ assign: mock(() => {}),
183
+ replace: mock(() => {}),
184
+ reload: mock(() => {}),
185
+ },
186
+ history: {
187
+ pushState: mock(() => {}),
188
+ replaceState: mock(() => {}),
189
+ go: mock(() => {}),
190
+ back: mock(() => {}),
191
+ forward: mock(() => {}),
192
+ length: 1,
193
+ state: null,
194
+ scrollRestoration: 'auto',
195
+ },
196
+ addEventListener: mock(() => {}),
197
+ removeEventListener: mock(() => {}),
198
+ dispatchEvent: mock(() => true),
199
+ } as unknown as Window;
200
+ }
201
+
202
+ /**
203
+ * Create a mock Document object
204
+ */
205
+ export function createMockDocument(): Document {
206
+ return {
207
+ createElement: mock(() => createMockHTMLElement()),
208
+ getElementById: mock(() => null),
209
+ querySelector: mock(() => null),
210
+ querySelectorAll: mock(() => []),
211
+ addEventListener: mock(() => {}),
212
+ removeEventListener: mock(() => {}),
213
+ dispatchEvent: mock(() => true),
214
+ } as unknown as Document;
215
+ }
216
+
217
+ /**
218
+ * Create a mock HTMLElement
219
+ */
220
+ export function createMockHTMLElement(): HTMLElement {
221
+ return {
222
+ tagName: 'DIV',
223
+ id: '',
224
+ className: '',
225
+ textContent: '',
226
+ innerHTML: '',
227
+ style: {} as CSSStyleDeclaration,
228
+ getAttribute: mock(() => null),
229
+ setAttribute: mock(() => {}),
230
+ removeAttribute: mock(() => {}),
231
+ addEventListener: mock(() => {}),
232
+ removeEventListener: mock(() => {}),
233
+ dispatchEvent: mock(() => true),
234
+ getBoundingClientRect: mock(() => ({
235
+ top: 0,
236
+ left: 0,
237
+ bottom: 0,
238
+ right: 0,
239
+ width: 0,
240
+ height: 0,
241
+ x: 0,
242
+ y: 0,
243
+ toJSON: mock(() => ({})),
244
+ })),
245
+ } as unknown as HTMLElement;
246
+ }
247
+
248
+ /**
249
+ * Create a mock PageProvider for testing PageService
250
+ * @param pages - Initial page content map (path -> content)
251
+ */
252
+ export function createMockPageProvider(pages: Record<string, string> = {}) {
253
+ const pageStore = { ...pages };
254
+
255
+ return {
256
+ loadAll: mock(async () => {
257
+ return new Map(Object.entries(pageStore));
258
+ }),
259
+ get: mock(async (path: string) => {
260
+ return pageStore[path] ?? null;
261
+ }),
262
+ save: mock(async (path: string, content: string) => {
263
+ pageStore[path] = content;
264
+ }),
265
+ delete: mock(async (path: string) => {
266
+ delete pageStore[path];
267
+ }),
268
+ exists: mock(async (path: string) => {
269
+ return path in pageStore;
270
+ }),
271
+ // Expose internal store for test assertions
272
+ _pages: pageStore,
273
+ };
274
+ }
275
+
276
+ /**
277
+ * Create a mock fs/promises module for testing file operations
278
+ * @param files - Initial file content map (path -> content)
279
+ */
280
+ export function createMockFs(files: Record<string, string> = {}) {
281
+ const fileSystem = { ...files };
282
+
283
+ return {
284
+ readFile: mock(async (path: string, encoding?: string) => {
285
+ if (path in fileSystem) {
286
+ return fileSystem[path];
287
+ }
288
+ const error = new Error(`ENOENT: no such file or directory, open '${path}'`);
289
+ (error as any).code = 'ENOENT';
290
+ throw error;
291
+ }),
292
+ writeFile: mock(async (path: string, content: string) => {
293
+ fileSystem[path] = content;
294
+ }),
295
+ unlink: mock(async (path: string) => {
296
+ if (!(path in fileSystem)) {
297
+ const error = new Error(`ENOENT: no such file or directory, unlink '${path}'`);
298
+ (error as any).code = 'ENOENT';
299
+ throw error;
300
+ }
301
+ delete fileSystem[path];
302
+ }),
303
+ readdir: mock(async (dir: string) => {
304
+ const normalizedDir = dir.endsWith('/') ? dir : dir + '/';
305
+ const entries = new Set<string>();
306
+ for (const path of Object.keys(fileSystem)) {
307
+ if (path.startsWith(normalizedDir)) {
308
+ const relativePath = path.slice(normalizedDir.length);
309
+ const firstSegment = relativePath.split('/')[0];
310
+ if (firstSegment) {
311
+ entries.add(firstSegment);
312
+ }
313
+ }
314
+ }
315
+ return Array.from(entries);
316
+ }),
317
+ stat: mock(async (path: string) => ({
318
+ isDirectory: () => !path.includes('.') || path.endsWith('/'),
319
+ isFile: () => path.includes('.') && !path.endsWith('/'),
320
+ })),
321
+ access: mock(async (path: string) => {
322
+ if (!(path in fileSystem)) {
323
+ const error = new Error(`ENOENT: no such file or directory, access '${path}'`);
324
+ (error as any).code = 'ENOENT';
325
+ throw error;
326
+ }
327
+ }),
328
+ mkdir: mock(async () => {}),
329
+ rm: mock(async (path: string) => {
330
+ // Remove all files under this path
331
+ for (const filePath of Object.keys(fileSystem)) {
332
+ if (filePath.startsWith(path)) {
333
+ delete fileSystem[filePath];
334
+ }
335
+ }
336
+ }),
337
+ // Expose internal file system for test assertions
338
+ _files: fileSystem,
339
+ };
340
+ }
341
+
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "meno-core",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "bin": {
6
+ "meno": "./bin/cli.ts"
7
+ },
8
+ "exports": {
9
+ ".": "./lib/shared/index.ts",
10
+ "./server": "./lib/server/index.ts",
11
+ "./client": "./lib/client/index.ts",
12
+ "./shared/*": "./lib/shared/*.ts",
13
+ "./test-utils": "./lib/test-utils/index.ts"
14
+ },
15
+ "scripts": {
16
+ "dev": "cd ../../example && bun run ../packages/core/bin/cli.ts dev",
17
+ "build": "vite build",
18
+ "build:static": "cd ../../example && bun run ../packages/core/bin/cli.ts build",
19
+ "test": "bun test",
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "dependencies": {
23
+ "@emotion/css": "^11.13.5",
24
+ "isomorphic-dompurify": "^2.32.0",
25
+ "react": "^18.2.0",
26
+ "react-dom": "^18.2.0",
27
+ "zod": "^3.22.4"
28
+ },
29
+ "devDependencies": {
30
+ "@types/react": "^18.2.0",
31
+ "@types/react-dom": "^18.2.0",
32
+ "@vitejs/plugin-react": "^4.2.0",
33
+ "bun-types": "^1.0.0",
34
+ "happy-dom": "^20.0.11",
35
+ "typescript": "^5.3.0",
36
+ "vite": "^5.0.0"
37
+ }
38
+ }
@@ -0,0 +1,34 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>YAML React Generator with Routing</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+ body {
14
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
15
+ }
16
+
17
+ button {
18
+ background: none;
19
+ border: none;
20
+ }
21
+
22
+ img {
23
+ width: 100%;
24
+ height: 100%;
25
+ }
26
+ </style>
27
+ </head>
28
+ <body>
29
+ <div id="root"></div>
30
+ <script src="https://cdn.jsdelivr.net/npm/cash-dom/dist/cash.min.js"></script>
31
+ <script type="module" src="/client-router.tsx"></script>
32
+ </body>
33
+ </html>
34
+
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": ".",
5
+ "outDir": "./dist",
6
+ "baseUrl": ".",
7
+ "paths": {
8
+ "@meno/core": ["./lib/shared/index.ts"],
9
+ "@meno/core/*": ["./lib/*"]
10
+ }
11
+ },
12
+ "include": ["lib/**/*", "entries/**/*", "bin/**/*"],
13
+ "exclude": ["node_modules", "dist"]
14
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,43 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+ import path from 'path'
4
+
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ build: {
8
+ outDir: 'dist',
9
+ lib: {
10
+ entry: {
11
+ 'shared/index': path.resolve(__dirname, 'lib/shared/index.ts'),
12
+ 'server/index': path.resolve(__dirname, 'lib/server/index.ts'),
13
+ 'client/index': path.resolve(__dirname, 'lib/client/index.ts'),
14
+ },
15
+ formats: ['es'],
16
+ },
17
+ rollupOptions: {
18
+ external: [
19
+ 'react',
20
+ 'react-dom',
21
+ 'bun',
22
+ // Node.js built-ins (server code)
23
+ 'path',
24
+ 'fs',
25
+ 'fs/promises',
26
+ 'url',
27
+ 'crypto',
28
+ 'stream',
29
+ 'os',
30
+ 'util',
31
+ 'events',
32
+ 'buffer',
33
+ // Bun-specific
34
+ 'bun:sqlite',
35
+ ],
36
+ },
37
+ },
38
+ resolve: {
39
+ alias: {
40
+ '@meno/core': path.resolve(__dirname, 'lib/shared/index.ts'),
41
+ },
42
+ },
43
+ })