@zenithbuild/core 0.4.7 → 0.5.0-beta.2.2

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 (110) hide show
  1. package/CORE_CONTRACT.md +143 -0
  2. package/README.md +11 -31
  3. package/bin/zenith.js +68 -0
  4. package/package.json +41 -53
  5. package/src/config.js +134 -0
  6. package/src/core-template.js +30 -0
  7. package/src/errors.js +54 -0
  8. package/src/guards.js +61 -0
  9. package/src/hash.js +52 -0
  10. package/src/index.js +26 -0
  11. package/src/ir/index.js +1 -0
  12. package/src/order.js +69 -0
  13. package/src/path.js +131 -0
  14. package/src/schema.js +28 -0
  15. package/src/version.js +67 -0
  16. package/bin/zen-build.ts +0 -2
  17. package/bin/zen-dev.ts +0 -2
  18. package/bin/zen-preview.ts +0 -2
  19. package/bin/zenith.ts +0 -2
  20. package/cli/commands/add.ts +0 -37
  21. package/cli/commands/build.ts +0 -37
  22. package/cli/commands/create.ts +0 -702
  23. package/cli/commands/dev.ts +0 -335
  24. package/cli/commands/index.ts +0 -112
  25. package/cli/commands/preview.ts +0 -62
  26. package/cli/commands/remove.ts +0 -33
  27. package/cli/index.ts +0 -10
  28. package/cli/main.ts +0 -101
  29. package/cli/utils/branding.ts +0 -178
  30. package/cli/utils/content.ts +0 -112
  31. package/cli/utils/logger.ts +0 -46
  32. package/cli/utils/plugin-manager.ts +0 -114
  33. package/cli/utils/project.ts +0 -77
  34. package/compiler/README.md +0 -380
  35. package/compiler/build-analyzer.ts +0 -122
  36. package/compiler/css/index.ts +0 -317
  37. package/compiler/discovery/componentDiscovery.ts +0 -178
  38. package/compiler/discovery/layouts.ts +0 -70
  39. package/compiler/errors/compilerError.ts +0 -56
  40. package/compiler/finalize/finalizeOutput.ts +0 -192
  41. package/compiler/finalize/generateFinalBundle.ts +0 -82
  42. package/compiler/index.ts +0 -82
  43. package/compiler/ir/types.ts +0 -162
  44. package/compiler/output/types.ts +0 -34
  45. package/compiler/parse/detectMapExpressions.ts +0 -102
  46. package/compiler/parse/parseScript.ts +0 -46
  47. package/compiler/parse/parseTemplate.ts +0 -599
  48. package/compiler/parse/parseZenFile.ts +0 -66
  49. package/compiler/parse/scriptAnalysis.ts +0 -91
  50. package/compiler/parse/trackLoopContext.ts +0 -82
  51. package/compiler/runtime/dataExposure.ts +0 -317
  52. package/compiler/runtime/generateDOM.ts +0 -246
  53. package/compiler/runtime/generateHydrationBundle.ts +0 -407
  54. package/compiler/runtime/hydration.ts +0 -309
  55. package/compiler/runtime/navigation.ts +0 -432
  56. package/compiler/runtime/thinRuntime.ts +0 -160
  57. package/compiler/runtime/transformIR.ts +0 -363
  58. package/compiler/runtime/wrapExpression.ts +0 -95
  59. package/compiler/runtime/wrapExpressionWithLoop.ts +0 -83
  60. package/compiler/spa-build.ts +0 -917
  61. package/compiler/ssg-build.ts +0 -422
  62. package/compiler/test/validate-test.ts +0 -104
  63. package/compiler/transform/classifyExpression.ts +0 -444
  64. package/compiler/transform/componentResolver.ts +0 -312
  65. package/compiler/transform/componentScriptTransformer.ts +0 -147
  66. package/compiler/transform/expressionTransformer.ts +0 -385
  67. package/compiler/transform/fragmentLowering.ts +0 -634
  68. package/compiler/transform/generateBindings.ts +0 -47
  69. package/compiler/transform/generateHTML.ts +0 -28
  70. package/compiler/transform/layoutProcessor.ts +0 -132
  71. package/compiler/transform/slotResolver.ts +0 -292
  72. package/compiler/transform/transformNode.ts +0 -126
  73. package/compiler/transform/transformTemplate.ts +0 -38
  74. package/compiler/validate/invariants.ts +0 -292
  75. package/compiler/validate/validateExpressions.ts +0 -168
  76. package/core/config/index.ts +0 -16
  77. package/core/config/loader.ts +0 -69
  78. package/core/config/types.ts +0 -89
  79. package/core/index.ts +0 -135
  80. package/core/lifecycle/index.ts +0 -49
  81. package/core/lifecycle/zen-mount.ts +0 -182
  82. package/core/lifecycle/zen-unmount.ts +0 -88
  83. package/core/plugins/index.ts +0 -7
  84. package/core/plugins/registry.ts +0 -81
  85. package/core/reactivity/index.ts +0 -54
  86. package/core/reactivity/tracking.ts +0 -167
  87. package/core/reactivity/zen-batch.ts +0 -57
  88. package/core/reactivity/zen-effect.ts +0 -139
  89. package/core/reactivity/zen-memo.ts +0 -146
  90. package/core/reactivity/zen-ref.ts +0 -52
  91. package/core/reactivity/zen-signal.ts +0 -121
  92. package/core/reactivity/zen-state.ts +0 -180
  93. package/core/reactivity/zen-untrack.ts +0 -44
  94. package/dist/cli.js +0 -11659
  95. package/dist/zen-build.js +0 -15633
  96. package/dist/zen-dev.js +0 -15633
  97. package/dist/zen-preview.js +0 -15633
  98. package/dist/zenith.js +0 -15633
  99. package/router/index.ts +0 -76
  100. package/router/manifest.ts +0 -314
  101. package/router/navigation/ZenLink.zen +0 -231
  102. package/router/navigation/index.ts +0 -78
  103. package/router/navigation/zen-link.ts +0 -584
  104. package/router/runtime.ts +0 -458
  105. package/router/types.ts +0 -168
  106. package/runtime/build.ts +0 -17
  107. package/runtime/bundle-generator.ts +0 -943
  108. package/runtime/client-runtime.ts +0 -549
  109. package/runtime/serve.ts +0 -93
  110. package/tsconfig.json +0 -28
@@ -1,335 +0,0 @@
1
- import path from 'path'
2
- import fs from 'fs'
3
- import { serve, type ServerWebSocket } from 'bun'
4
- import { requireProject } from '../utils/project'
5
- import * as logger from '../utils/logger'
6
- import * as brand from '../utils/branding'
7
- import { compileZenSource } from '../../compiler/index'
8
- import { discoverLayouts } from '../../compiler/discovery/layouts'
9
- import { processLayout } from '../../compiler/transform/layoutProcessor'
10
- import { generateRouteDefinition } from '../../router/manifest'
11
- import { generateBundleJS } from '../../runtime/bundle-generator'
12
- import { loadContent } from '../utils/content'
13
- import { loadZenithConfig } from '../../core/config/loader'
14
- import { PluginRegistry, createPluginContext } from '../../core/plugins/registry'
15
- import type { ContentItem } from '../../core/config/types'
16
- import { compileCssAsync, resolveGlobalsCss } from '../../compiler/css'
17
-
18
- export interface DevOptions {
19
- port?: number
20
- }
21
-
22
- interface CompiledPage {
23
- html: string
24
- script: string
25
- styles: string[]
26
- route: string
27
- lastModified: number
28
- }
29
-
30
- const pageCache = new Map<string, CompiledPage>()
31
-
32
- export async function dev(options: DevOptions = {}): Promise<void> {
33
- const project = requireProject()
34
- const port = options.port || parseInt(process.env.PORT || '3000', 10)
35
- const pagesDir = project.pagesDir
36
- const rootDir = project.root
37
- const contentDir = path.join(rootDir, 'content')
38
-
39
- // Load zenith.config.ts if present
40
- const config = await loadZenithConfig(rootDir)
41
- const registry = new PluginRegistry()
42
-
43
- console.log('[Zenith] Config plugins:', config.plugins?.length ?? 0)
44
-
45
- // Register plugins from config
46
- for (const plugin of config.plugins || []) {
47
- console.log('[Zenith] Registering plugin:', plugin.name)
48
- registry.register(plugin)
49
- }
50
-
51
- // Initialize content data
52
- let contentData: Record<string, ContentItem[]> = {}
53
-
54
- // Initialize plugins with context
55
- const hasContentPlugin = registry.has('zenith-content')
56
- console.log('[Zenith] Has zenith-content plugin:', hasContentPlugin)
57
-
58
- if (hasContentPlugin) {
59
- await registry.initAll(createPluginContext(rootDir, (data) => {
60
- console.log('[Zenith] Content plugin set data, collections:', Object.keys(data))
61
- contentData = data
62
- }))
63
- } else {
64
- // Fallback to legacy content loading if no content plugin configured
65
- console.log('[Zenith] Using legacy content loading from:', contentDir)
66
- contentData = loadContent(contentDir)
67
- }
68
-
69
- console.log('[Zenith] Content collections loaded:', Object.keys(contentData))
70
-
71
- // ============================================
72
- // CSS Compilation (Compiler-Owned)
73
- // ============================================
74
- const globalsCssPath = resolveGlobalsCss(rootDir)
75
- let compiledCss = ''
76
-
77
- if (globalsCssPath) {
78
- console.log('[Zenith] Compiling CSS:', path.relative(rootDir, globalsCssPath))
79
- const cssResult = await compileCssAsync({ input: globalsCssPath, output: ':memory:' })
80
- if (cssResult.success) {
81
- compiledCss = cssResult.css
82
- console.log(`[Zenith] CSS compiled in ${cssResult.duration}ms`)
83
- } else {
84
- console.error('[Zenith] CSS compilation failed:', cssResult.error)
85
- }
86
- }
87
-
88
- const clients = new Set<ServerWebSocket<unknown>>()
89
-
90
- // Branded Startup Panel
91
- brand.showServerPanel({
92
- project: project.root,
93
- pages: project.pagesDir,
94
- url: `http://localhost:${port}`,
95
- hmr: true,
96
- mode: 'In-memory compilation'
97
- })
98
-
99
- // File extensions that should be served as static assets
100
- const STATIC_EXTENSIONS = new Set([
101
- '.js', '.css', '.ico', '.png', '.jpg', '.jpeg', '.gif', '.svg',
102
- '.webp', '.woff', '.woff2', '.ttf', '.eot', '.json', '.map'
103
- ])
104
-
105
- /**
106
- * Compile a .zen page in memory
107
- */
108
- function compilePageInMemory(pagePath: string): CompiledPage | null {
109
- try {
110
- const layoutsDir = path.join(pagesDir, '../layouts')
111
- const componentsDir = path.join(pagesDir, '../components')
112
- const layouts = discoverLayouts(layoutsDir)
113
- const source = fs.readFileSync(pagePath, 'utf-8')
114
-
115
- let processedSource = source
116
- let layoutToUse = layouts.get('DefaultLayout')
117
-
118
- if (layoutToUse) processedSource = processLayout(source, layoutToUse)
119
-
120
- const result = compileZenSource(processedSource, pagePath, {
121
- componentsDir: fs.existsSync(componentsDir) ? componentsDir : undefined
122
- })
123
- if (!result.finalized) throw new Error('Compilation failed')
124
-
125
- const routeDef = generateRouteDefinition(pagePath, pagesDir)
126
-
127
- return {
128
- html: result.finalized.html,
129
- script: result.finalized.js,
130
- styles: result.finalized.styles,
131
- route: routeDef.path,
132
- lastModified: Date.now()
133
- }
134
- } catch (error: any) {
135
- logger.error(`Compilation error: ${error.message}`)
136
- return null
137
- }
138
- }
139
-
140
- // Set up file watching for HMR
141
- const watcher = fs.watch(path.join(pagesDir, '..'), { recursive: true }, async (event, filename) => {
142
- if (!filename) return
143
-
144
- if (filename.endsWith('.zen')) {
145
- logger.hmr('Page', filename)
146
-
147
- // Clear page cache to force fresh compilation on next request
148
- pageCache.clear()
149
-
150
- // Recompile CSS for new Tailwind classes in .zen files
151
- if (globalsCssPath) {
152
- const cssResult = await compileCssAsync({ input: globalsCssPath, output: ':memory:' })
153
- if (cssResult.success) {
154
- compiledCss = cssResult.css
155
- }
156
- }
157
-
158
- // Broadcast page reload AFTER cache cleared and CSS ready
159
- for (const client of clients) {
160
- client.send(JSON.stringify({ type: 'reload' }))
161
- }
162
- } else if (filename.endsWith('.css')) {
163
- logger.hmr('CSS', filename)
164
- // Recompile CSS
165
- if (globalsCssPath) {
166
- const cssResult = await compileCssAsync({ input: globalsCssPath, output: ':memory:' })
167
- if (cssResult.success) {
168
- compiledCss = cssResult.css
169
- }
170
- }
171
- for (const client of clients) {
172
- client.send(JSON.stringify({ type: 'style-update', url: '/assets/styles.css' }))
173
- }
174
- } else if (filename.startsWith('content') || filename.includes('zenith-docs')) {
175
- logger.hmr('Content', filename)
176
- // Reinitialize content plugin to reload data
177
- if (registry.has('zenith-content')) {
178
- registry.initAll(createPluginContext(rootDir, (data) => {
179
- contentData = data
180
- }))
181
- } else {
182
- contentData = loadContent(contentDir)
183
- }
184
- for (const client of clients) {
185
- client.send(JSON.stringify({ type: 'reload' }))
186
- }
187
- }
188
- })
189
-
190
- const server = serve({
191
- port,
192
- fetch(req, server) {
193
- const startTime = performance.now()
194
- const url = new URL(req.url)
195
- const pathname = url.pathname
196
- const ext = path.extname(pathname).toLowerCase()
197
-
198
- // Upgrade to WebSocket for HMR
199
- if (pathname === '/hmr') {
200
- const upgraded = server.upgrade(req)
201
- if (upgraded) return undefined
202
- }
203
-
204
- // Handle Zenith assets
205
- if (pathname === '/runtime.js') {
206
- const response = new Response(generateBundleJS(), {
207
- headers: { 'Content-Type': 'application/javascript; charset=utf-8' }
208
- })
209
- logger.route('GET', pathname, 200, Math.round(performance.now() - startTime), 0, Math.round(performance.now() - startTime))
210
- return response
211
- }
212
-
213
- // Serve compiler-owned CSS (Tailwind compiled)
214
- if (pathname === '/assets/styles.css') {
215
- const response = new Response(compiledCss, {
216
- headers: { 'Content-Type': 'text/css; charset=utf-8' }
217
- })
218
- logger.route('GET', pathname, 200, Math.round(performance.now() - startTime), 0, Math.round(performance.now() - startTime))
219
- return response
220
- }
221
-
222
- // Legacy: also support /styles/globals.css or /styles/global.css for backwards compat
223
- if (pathname === '/styles/globals.css' || pathname === '/styles/global.css') {
224
- const response = new Response(compiledCss, {
225
- headers: { 'Content-Type': 'text/css; charset=utf-8' }
226
- })
227
- logger.route('GET', pathname, 200, Math.round(performance.now() - startTime), 0, Math.round(performance.now() - startTime))
228
- return response
229
- }
230
-
231
- // Static files
232
- if (STATIC_EXTENSIONS.has(ext)) {
233
- const publicPath = path.join(pagesDir, '../public', pathname)
234
- if (fs.existsSync(publicPath)) {
235
- const response = new Response(Bun.file(publicPath))
236
- logger.route('GET', pathname, 200, Math.round(performance.now() - startTime), 0, Math.round(performance.now() - startTime))
237
- return response
238
- }
239
- }
240
-
241
- // Zenith Pages
242
- const pagePath = findPageForRoute(pathname, pagesDir)
243
- if (pagePath) {
244
- const compileStart = performance.now()
245
- let cached = pageCache.get(pagePath)
246
- const stat = fs.statSync(pagePath)
247
-
248
- if (!cached || stat.mtimeMs > cached.lastModified) {
249
- cached = compilePageInMemory(pagePath) || undefined
250
- if (cached) pageCache.set(pagePath, cached)
251
- }
252
- const compileEnd = performance.now()
253
-
254
- if (cached) {
255
- const renderStart = performance.now()
256
- const html = generateDevHTML(cached, contentData)
257
- const renderEnd = performance.now()
258
-
259
- const totalTime = Math.round(performance.now() - startTime)
260
- const compileTime = Math.round(compileEnd - compileStart)
261
- const renderTime = Math.round(renderEnd - renderStart)
262
-
263
- logger.route('GET', pathname, 200, totalTime, compileTime, renderTime)
264
- return new Response(html, { headers: { 'Content-Type': 'text/html' } })
265
- }
266
- }
267
-
268
- logger.route('GET', pathname, 404, Math.round(performance.now() - startTime), 0, 0)
269
- return new Response('Not Found', { status: 404 })
270
- },
271
- websocket: {
272
- open(ws) {
273
- clients.add(ws)
274
- },
275
- close(ws) {
276
- clients.delete(ws)
277
- },
278
- message() { }
279
- }
280
- })
281
-
282
- process.on('SIGINT', () => {
283
- watcher.close()
284
- server.stop()
285
- process.exit(0)
286
- })
287
-
288
- await new Promise(() => { })
289
- }
290
-
291
- function findPageForRoute(route: string, pagesDir: string): string | null {
292
- // 1. Try exact match first (e.g., /about -> about.zen)
293
- const exactPath = path.join(pagesDir, route === '/' ? 'index.zen' : `${route.slice(1)}.zen`)
294
- if (fs.existsSync(exactPath)) return exactPath
295
-
296
- // 2. Try index.zen in directory (e.g., /about -> about/index.zen)
297
- const indexPath = path.join(pagesDir, route === '/' ? 'index.zen' : `${route.slice(1)}/index.zen`)
298
- if (fs.existsSync(indexPath)) return indexPath
299
-
300
- // 3. Try dynamic routes [slug].zen, [...slug].zen
301
- // Walk up the path looking for dynamic segments
302
- const segments = route === '/' ? [] : route.slice(1).split('/').filter(Boolean)
303
-
304
- // Try matching with dynamic [slug].zen at each level
305
- for (let i = segments.length - 1; i >= 0; i--) {
306
- const staticPart = segments.slice(0, i).join('/')
307
- const baseDir = staticPart ? path.join(pagesDir, staticPart) : pagesDir
308
-
309
- // Check for [slug].zen (single segment catch)
310
- const singleDynamicPath = path.join(baseDir, '[slug].zen')
311
- if (fs.existsSync(singleDynamicPath)) return singleDynamicPath
312
-
313
- // Check for [...slug].zen (catch-all)
314
- const catchAllPath = path.join(baseDir, '[...slug].zen')
315
- if (fs.existsSync(catchAllPath)) return catchAllPath
316
- }
317
-
318
- // 4. Check for catch-all at root
319
- const rootCatchAll = path.join(pagesDir, '[...slug].zen')
320
- if (fs.existsSync(rootCatchAll)) return rootCatchAll
321
-
322
- return null
323
- }
324
-
325
- function generateDevHTML(page: CompiledPage, contentData: any = {}): string {
326
- const runtimeTag = `<script src="/runtime.js"></script>`
327
- // Escape </script> sequences in JSON content to prevent breaking the script tag
328
- const contentJson = JSON.stringify(contentData).replace(/<\//g, '<\\/')
329
- const contentTag = `<script>window.__ZENITH_CONTENT__ = ${contentJson};</script>`
330
- const scriptTag = `<script>\n${page.script}\n</script>`
331
- const allScripts = `${runtimeTag}\n${contentTag}\n${scriptTag}`
332
- return page.html.includes('</body>')
333
- ? page.html.replace('</body>', `${allScripts}\n</body>`)
334
- : `${page.html}\n${allScripts}`
335
- }
@@ -1,112 +0,0 @@
1
- /**
2
- * @zenith/cli - Command Registry
3
- *
4
- * Central registry for all CLI commands
5
- */
6
-
7
- import { dev, type DevOptions } from './dev'
8
- import { preview, type PreviewOptions } from './preview'
9
- import { build, type BuildOptions } from './build'
10
- import { add, type AddOptions } from './add'
11
- import { remove } from './remove'
12
- import { create } from './create'
13
- import * as logger from '../utils/logger'
14
-
15
- export interface Command {
16
- name: string
17
- description: string
18
- usage: string
19
- run: (args: string[], options: Record<string, string>) => Promise<void>
20
- }
21
-
22
- export const commands: Command[] = [
23
- {
24
- name: 'create',
25
- description: 'Create a new Zenith project',
26
- usage: 'zenith create [project-name]',
27
- async run(args) {
28
- const projectName = args[0]
29
- await create(projectName)
30
- }
31
- },
32
- {
33
- name: 'dev',
34
- description: 'Start development server',
35
- usage: 'zenith dev [--port <port>]',
36
- async run(args, options) {
37
- const opts: DevOptions = {}
38
- if (options.port) opts.port = parseInt(options.port, 10)
39
- await dev(opts)
40
- }
41
- },
42
- {
43
- name: 'preview',
44
- description: 'Preview production build',
45
- usage: 'zenith preview [--port <port>]',
46
- async run(args, options) {
47
- const opts: PreviewOptions = {}
48
- if (options.port) opts.port = parseInt(options.port, 10)
49
- await preview(opts)
50
- }
51
- },
52
- {
53
- name: 'build',
54
- description: 'Build for production',
55
- usage: 'zenith build [--outDir <dir>]',
56
- async run(args, options) {
57
- const opts: BuildOptions = {}
58
- if (options.outDir) opts.outDir = options.outDir
59
- await build(opts)
60
- }
61
- },
62
- {
63
- name: 'add',
64
- description: 'Add a plugin',
65
- usage: 'zenith add <plugin>',
66
- async run(args) {
67
- const pluginName = args[0]
68
- if (!pluginName) {
69
- logger.error('Plugin name required')
70
- process.exit(1)
71
- }
72
- await add(pluginName)
73
- }
74
- },
75
- {
76
- name: 'remove',
77
- description: 'Remove a plugin',
78
- usage: 'zenith remove <plugin>',
79
- async run(args) {
80
- const pluginName = args[0]
81
- if (!pluginName) {
82
- logger.error('Plugin name required')
83
- process.exit(1)
84
- }
85
- await remove(pluginName)
86
- }
87
- }
88
- ]
89
-
90
- // Placeholder commands for future expansion
91
- export const placeholderCommands = ['test', 'export', 'deploy']
92
-
93
- export function getCommand(name: string): Command | undefined {
94
- return commands.find(c => c.name === name)
95
- }
96
-
97
- export function showHelp(): void {
98
- logger.header('Zenith CLI')
99
- console.log('Usage: zenith <command> [options]\n')
100
- console.log('Commands:')
101
-
102
- for (const cmd of commands) {
103
- console.log(` ${cmd.name.padEnd(12)} ${cmd.description}`)
104
- }
105
-
106
- console.log('\nComing soon:')
107
- for (const cmd of placeholderCommands) {
108
- console.log(` ${cmd.padEnd(12)} (not yet implemented)`)
109
- }
110
-
111
- console.log('\nRun `zenith <command> --help` for command-specific help.')
112
- }
@@ -1,62 +0,0 @@
1
- /**
2
- * @zenith/cli - Preview Command
3
- *
4
- * Serves the production build from the distribution directory.
5
- */
6
-
7
- import path from 'path'
8
- import { serve } from 'bun'
9
- import { requireProject } from '../utils/project'
10
- import * as logger from '../utils/logger'
11
-
12
- export interface PreviewOptions {
13
- port?: number
14
- }
15
-
16
- export async function preview(options: PreviewOptions = {}): Promise<void> {
17
- const project = requireProject()
18
- const distDir = project.distDir
19
- const port = options.port || parseInt(process.env.PORT || '4173', 10)
20
-
21
- logger.header('Zenith Preview Server')
22
- logger.log(`Serving: ${distDir}`)
23
-
24
- // File extensions that should be served as static assets
25
- const STATIC_EXTENSIONS = new Set([
26
- '.js', '.css', '.ico', '.png', '.jpg', '.jpeg', '.gif', '.svg',
27
- '.webp', '.woff', '.woff2', '.ttf', '.eot', '.json', '.map'
28
- ])
29
-
30
- const server = serve({
31
- port,
32
- async fetch(req) {
33
- const url = new URL(req.url)
34
- const pathname = url.pathname
35
- const ext = path.extname(pathname).toLowerCase()
36
-
37
- if (STATIC_EXTENSIONS.has(ext)) {
38
- const filePath = path.join(distDir, pathname)
39
- const file = Bun.file(filePath)
40
- if (await file.exists()) {
41
- return new Response(file)
42
- }
43
- return new Response('Not found', { status: 404 })
44
- }
45
-
46
- const indexPath = path.join(distDir, 'index.html')
47
- const indexFile = Bun.file(indexPath)
48
- if (await indexFile.exists()) {
49
- return new Response(indexFile, {
50
- headers: { 'Content-Type': 'text/html; charset=utf-8' }
51
- })
52
- }
53
-
54
- return new Response('No production build found. Run `zenith build` first.', { status: 500 })
55
- }
56
- })
57
-
58
- logger.success(`Preview server running at http://localhost:${server.port}`)
59
- logger.info('Press Ctrl+C to stop')
60
-
61
- await new Promise(() => { })
62
- }
@@ -1,33 +0,0 @@
1
- /**
2
- * @zenith/cli - Remove Command
3
- *
4
- * Removes a plugin from the project registry
5
- */
6
-
7
- import { requireProject } from '../utils/project'
8
- import { removePlugin, hasPlugin } from '../utils/plugin-manager'
9
- import * as logger from '../utils/logger'
10
-
11
- export async function remove(pluginName: string): Promise<void> {
12
- requireProject()
13
-
14
- logger.header('Remove Plugin')
15
-
16
- if (!pluginName) {
17
- logger.error('Plugin name required. Usage: zenith remove <plugin>')
18
- process.exit(1)
19
- }
20
-
21
- if (!hasPlugin(pluginName)) {
22
- logger.warn(`Plugin "${pluginName}" is not registered`)
23
- return
24
- }
25
-
26
- const success = removePlugin(pluginName)
27
-
28
- if (success) {
29
- logger.info(`Plugin "${pluginName}" has been unregistered.`)
30
- logger.info('Note: You may want to remove the package manually:')
31
- logger.log(` bun remove @zenith/plugin-${pluginName}`)
32
- }
33
- }
package/cli/index.ts DELETED
@@ -1,10 +0,0 @@
1
- /**
2
- * @zenith/cli
3
- *
4
- * CLI for Zenith framework - dev server, build tools, and plugin management
5
- */
6
-
7
- export * from './commands/index'
8
- export * from './utils/logger'
9
- export * from './utils/project'
10
- export * from './utils/plugin-manager'
package/cli/main.ts DELETED
@@ -1,101 +0,0 @@
1
- /**
2
- * @zenith/cli - Shared CLI Execution Logic
3
- */
4
-
5
- import process from 'node:process'
6
- import { getCommand, showHelp, placeholderCommands } from './commands/index'
7
- import * as logger from './utils/logger'
8
- import { execSync } from 'node:child_process'
9
-
10
- /**
11
- * Check if Bun is available in the environment
12
- */
13
- function checkBun() {
14
- try {
15
- execSync('bun --version', { stdio: 'pipe' })
16
- return true
17
- } catch {
18
- return false
19
- }
20
- }
21
-
22
- export interface CLIOptions {
23
- defaultCommand?: string
24
- }
25
-
26
- /**
27
- * Main CLI execution entry point
28
- */
29
- export async function runCLI(options: CLIOptions = {}) {
30
- // 1. Check for Bun
31
- if (!checkBun()) {
32
- logger.error('Bun is required to run Zenith.')
33
- logger.info('Please install Bun: https://bun.sh/install')
34
- process.exit(1)
35
- }
36
-
37
- const args = process.argv.slice(2)
38
- const VERSION = '0.3.0'
39
-
40
- // 2. Handle global version flag
41
- if (args.includes('--version') || args.includes('-v')) {
42
- console.log(`Zenith CLI v${VERSION}`)
43
- process.exit(0)
44
- }
45
-
46
- // Determine command name: either from args or default (for aliases)
47
- let commandName = args[0]
48
- let commandArgs = args.slice(1)
49
-
50
- if (options.defaultCommand) {
51
- if (!commandName || commandName.startsWith('-')) {
52
- commandName = options.defaultCommand
53
- commandArgs = args
54
- }
55
- }
56
-
57
- // Handle help
58
- if (!commandName || ((commandName === '--help' || commandName === '-h') && !options.defaultCommand)) {
59
- showHelp()
60
- process.exit(0)
61
- }
62
-
63
- // Parse options (--key value format) for internal use if needed
64
- const cliOptions: Record<string, string> = {}
65
- for (let i = 0; i < commandArgs.length; i++) {
66
- const arg = commandArgs[i]!
67
- if (arg.startsWith('--')) {
68
- const key = arg.slice(2)
69
- const value = commandArgs[i + 1]
70
- if (value && !value.startsWith('--')) {
71
- cliOptions[key] = value
72
- i++
73
- } else {
74
- cliOptions[key] = 'true'
75
- }
76
- }
77
- }
78
-
79
- // Check for placeholder commands
80
- if (placeholderCommands.includes(commandName)) {
81
- logger.warn(`Command "${commandName}" is not yet implemented.`)
82
- logger.info('This feature is planned for a future release.')
83
- process.exit(0)
84
- }
85
-
86
- const command = getCommand(commandName)
87
-
88
- if (!command) {
89
- logger.error(`Unknown command: ${commandName}`)
90
- showHelp()
91
- process.exit(1)
92
- }
93
-
94
- try {
95
- await command!.run(commandArgs, cliOptions)
96
- } catch (err: unknown) {
97
- const message = err instanceof Error ? err.message : String(err)
98
- logger.error(message)
99
- process.exit(1)
100
- }
101
- }