@zenithbuild/core 1.2.2 → 1.2.4

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 (83) hide show
  1. package/README.md +20 -19
  2. package/cli/commands/add.ts +2 -2
  3. package/cli/commands/build.ts +2 -3
  4. package/cli/commands/dev.ts +94 -74
  5. package/cli/commands/index.ts +1 -1
  6. package/cli/commands/preview.ts +1 -1
  7. package/cli/commands/remove.ts +2 -2
  8. package/cli/index.ts +1 -1
  9. package/cli/main.ts +1 -1
  10. package/cli/utils/logger.ts +1 -1
  11. package/cli/utils/plugin-manager.ts +1 -1
  12. package/cli/utils/project.ts +4 -4
  13. package/core/components/ErrorPage.zen +218 -0
  14. package/core/components/index.ts +15 -0
  15. package/core/config.ts +1 -0
  16. package/core/index.ts +29 -0
  17. package/dist/compiler-native-frej59m4.node +0 -0
  18. package/dist/core/compiler-native-frej59m4.node +0 -0
  19. package/dist/core/index.js +6293 -0
  20. package/dist/runtime/lifecycle/index.js +1 -0
  21. package/dist/runtime/reactivity/index.js +1 -0
  22. package/dist/zen-build.js +1 -20118
  23. package/dist/zen-dev.js +1 -20118
  24. package/dist/zen-preview.js +1 -20118
  25. package/dist/zenith.js +1 -20118
  26. package/package.json +11 -20
  27. package/compiler/README.md +0 -380
  28. package/compiler/build-analyzer.ts +0 -122
  29. package/compiler/css/index.ts +0 -317
  30. package/compiler/discovery/componentDiscovery.ts +0 -242
  31. package/compiler/discovery/layouts.ts +0 -70
  32. package/compiler/errors/compilerError.ts +0 -56
  33. package/compiler/finalize/finalizeOutput.ts +0 -192
  34. package/compiler/finalize/generateFinalBundle.ts +0 -82
  35. package/compiler/index.ts +0 -83
  36. package/compiler/ir/types.ts +0 -174
  37. package/compiler/output/types.ts +0 -48
  38. package/compiler/parse/detectMapExpressions.ts +0 -102
  39. package/compiler/parse/importTypes.ts +0 -78
  40. package/compiler/parse/parseImports.ts +0 -309
  41. package/compiler/parse/parseScript.ts +0 -46
  42. package/compiler/parse/parseTemplate.ts +0 -628
  43. package/compiler/parse/parseZenFile.ts +0 -66
  44. package/compiler/parse/scriptAnalysis.ts +0 -91
  45. package/compiler/parse/trackLoopContext.ts +0 -82
  46. package/compiler/runtime/dataExposure.ts +0 -332
  47. package/compiler/runtime/generateDOM.ts +0 -255
  48. package/compiler/runtime/generateHydrationBundle.ts +0 -407
  49. package/compiler/runtime/hydration.ts +0 -309
  50. package/compiler/runtime/navigation.ts +0 -432
  51. package/compiler/runtime/thinRuntime.ts +0 -160
  52. package/compiler/runtime/transformIR.ts +0 -406
  53. package/compiler/runtime/wrapExpression.ts +0 -114
  54. package/compiler/runtime/wrapExpressionWithLoop.ts +0 -97
  55. package/compiler/spa-build.ts +0 -917
  56. package/compiler/ssg-build.ts +0 -486
  57. package/compiler/test/component-stacking.test.ts +0 -365
  58. package/compiler/test/map-lowering.test.ts +0 -130
  59. package/compiler/test/validate-test.ts +0 -104
  60. package/compiler/transform/classifyExpression.ts +0 -444
  61. package/compiler/transform/componentResolver.ts +0 -350
  62. package/compiler/transform/componentScriptTransformer.ts +0 -303
  63. package/compiler/transform/expressionTransformer.ts +0 -385
  64. package/compiler/transform/fragmentLowering.ts +0 -819
  65. package/compiler/transform/generateBindings.ts +0 -68
  66. package/compiler/transform/generateHTML.ts +0 -28
  67. package/compiler/transform/layoutProcessor.ts +0 -132
  68. package/compiler/transform/slotResolver.ts +0 -292
  69. package/compiler/transform/transformNode.ts +0 -314
  70. package/compiler/transform/transformTemplate.ts +0 -38
  71. package/compiler/validate/invariants.ts +0 -292
  72. package/compiler/validate/validateExpressions.ts +0 -168
  73. package/core/config/index.ts +0 -18
  74. package/core/config/loader.ts +0 -69
  75. package/core/config/types.ts +0 -119
  76. package/core/plugins/bridge.ts +0 -193
  77. package/core/plugins/index.ts +0 -7
  78. package/core/plugins/registry.ts +0 -126
  79. package/dist/cli.js +0 -11675
  80. package/runtime/build.ts +0 -17
  81. package/runtime/bundle-generator.ts +0 -1266
  82. package/runtime/client-runtime.ts +0 -891
  83. package/runtime/serve.ts +0 -93
@@ -1,168 +0,0 @@
1
- /**
2
- * Expression Validation
3
- *
4
- * Phase 8/9/10: Compile-time validation of all expressions
5
- *
6
- * Ensures all expressions are valid JavaScript and will not cause runtime errors.
7
- * Build fails immediately if any expression is invalid.
8
- */
9
-
10
- import type { ExpressionIR } from '../ir/types'
11
- import { CompilerError } from '../errors/compilerError'
12
-
13
- /**
14
- * Validation result
15
- */
16
- export interface ValidationResult {
17
- valid: boolean
18
- errors: CompilerError[]
19
- }
20
-
21
- /**
22
- * Validate all expressions in the IR
23
- *
24
- * @param expressions - Array of expressions to validate
25
- * @param filePath - Source file path for error reporting
26
- * @returns Validation result with errors
27
- */
28
- export function validateExpressions(
29
- expressions: ExpressionIR[],
30
- filePath: string
31
- ): ValidationResult {
32
- const errors: CompilerError[] = []
33
-
34
- for (const expr of expressions) {
35
- const exprErrors = validateSingleExpression(expr, filePath)
36
- errors.push(...exprErrors)
37
- }
38
-
39
- return {
40
- valid: errors.length === 0,
41
- errors
42
- }
43
- }
44
-
45
- /**
46
- * Validate a single expression
47
- */
48
- function validateSingleExpression(
49
- expr: ExpressionIR,
50
- filePath: string
51
- ): CompilerError[] {
52
- const errors: CompilerError[] = []
53
- const { id, code, location } = expr
54
-
55
- // Basic syntax validation using a safe approach
56
- // We don't execute the code, just validate syntax
57
- // Note: Expressions may contain JSX/HTML syntax (e.g., condition && <element>)
58
- // which is not valid JavaScript but is valid in our expression language.
59
- // We skip strict JavaScript validation for expressions that contain JSX.
60
-
61
- const hasJSX = /<[a-zA-Z]/.test(code) || /\/>/.test(code)
62
-
63
- if (!hasJSX) {
64
- // Only validate JavaScript syntax if there's no JSX
65
- // Note: Using Function constructor here is for syntax validation only (compile-time)
66
- // This is safe because:
67
- // 1. It's only called at compile time, not runtime
68
- // 2. We're only checking syntax, not executing the code
69
- // 3. The actual runtime uses pre-compiled functions, not Function constructor
70
- try {
71
- // Use Function constructor to validate syntax (doesn't execute)
72
- // This is compile-time only - runtime never uses Function constructor
73
- new Function('state', 'loaderData', 'props', 'stores', `return ${code}`)
74
- } catch (error: any) {
75
- errors.push(
76
- new CompilerError(
77
- `Invalid expression syntax: ${code}\n${error.message}`,
78
- filePath,
79
- location.line,
80
- location.column
81
- )
82
- )
83
- }
84
- }
85
- // If hasJSX, we skip JavaScript validation - JSX syntax is handled by the parser/runtime
86
-
87
- // Check for dangerous patterns
88
- if (code.includes('eval(') || code.includes('Function(') || code.includes('with (')) {
89
- errors.push(
90
- new CompilerError(
91
- `Expression contains unsafe code: ${code}`,
92
- filePath,
93
- location.line,
94
- location.column
95
- )
96
- )
97
- }
98
-
99
- // Check for undefined global references (basic heuristic)
100
- // This is a simple check - can be enhanced with AST parsing
101
- const globalPattern = /\b(window|document|console|globalThis)\./g
102
- const matches = code.match(globalPattern)
103
- if (matches && matches.length > 0) {
104
- // Warn but don't fail - some global access might be intentional
105
- // In a stricter mode, we could fail here
106
- }
107
-
108
- // Check for common syntax errors
109
- const openBraces = (code.match(/\{/g) || []).length
110
- const closeBraces = (code.match(/\}/g) || []).length
111
- const openParens = (code.match(/\(/g) || []).length
112
- const closeParens = (code.match(/\)/g) || []).length
113
- const openBrackets = (code.match(/\[/g) || []).length
114
- const closeBrackets = (code.match(/\]/g) || []).length
115
-
116
- if (openBraces !== closeBraces) {
117
- errors.push(
118
- new CompilerError(
119
- `Mismatched braces in expression: ${code}`,
120
- filePath,
121
- location.line,
122
- location.column
123
- )
124
- )
125
- }
126
-
127
- if (openParens !== closeParens) {
128
- errors.push(
129
- new CompilerError(
130
- `Mismatched parentheses in expression: ${code}`,
131
- filePath,
132
- location.line,
133
- location.column
134
- )
135
- )
136
- }
137
-
138
- if (openBrackets !== closeBrackets) {
139
- errors.push(
140
- new CompilerError(
141
- `Mismatched brackets in expression: ${code}`,
142
- filePath,
143
- location.line,
144
- location.column
145
- )
146
- )
147
- }
148
-
149
- return errors
150
- }
151
-
152
- /**
153
- * Validate and throw if invalid
154
- *
155
- * @throws CompilerError if any expression is invalid
156
- */
157
- export function validateExpressionsOrThrow(
158
- expressions: ExpressionIR[],
159
- filePath: string
160
- ): void {
161
- const result = validateExpressions(expressions, filePath)
162
-
163
- if (!result.valid && result.errors.length > 0) {
164
- // Throw the first error (can be enhanced to collect all)
165
- throw result.errors[0]
166
- }
167
- }
168
-
@@ -1,18 +0,0 @@
1
- /**
2
- * Zenith Config
3
- *
4
- * Public exports for zenith/config
5
- *
6
- * Core exports ONLY generic plugin infrastructure.
7
- * Plugin-specific types are owned by their respective plugins.
8
- */
9
-
10
- export { defineConfig } from './types';
11
- export type {
12
- ZenithConfig,
13
- ZenithPlugin,
14
- PluginContext,
15
- PluginData
16
- } from './types';
17
- export { loadZenithConfig, hasZenithConfig } from './loader';
18
-
@@ -1,69 +0,0 @@
1
- /**
2
- * Zenith Config Loader
3
- *
4
- * Loads zenith.config.ts from the project root
5
- */
6
-
7
- import fs from 'node:fs';
8
- import path from 'node:path';
9
- import type { ZenithConfig } from './types';
10
-
11
- /**
12
- * Load zenith.config.ts from the project root
13
- *
14
- * @param projectRoot - Absolute path to the project root
15
- * @returns Parsed ZenithConfig or empty config if not found
16
- */
17
- export async function loadZenithConfig(projectRoot: string): Promise<ZenithConfig> {
18
- // Check for TypeScript config first, then JavaScript
19
- const configPaths = [
20
- path.join(projectRoot, 'zenith.config.ts'),
21
- path.join(projectRoot, 'zenith.config.js'),
22
- path.join(projectRoot, 'zenith.config.mjs'),
23
- ];
24
-
25
- let configPath: string | null = null;
26
- for (const p of configPaths) {
27
- if (fs.existsSync(p)) {
28
- configPath = p;
29
- break;
30
- }
31
- }
32
-
33
- if (!configPath) {
34
- // No config file found, return empty config
35
- return { plugins: [] };
36
- }
37
-
38
- try {
39
- // Use dynamic import to load the config
40
- // Bun supports importing TS files directly
41
- const configModule = await import(configPath);
42
- const config = configModule.default || configModule;
43
-
44
- // Validate basic structure
45
- if (typeof config !== 'object' || config === null) {
46
- console.warn(`[Zenith] Invalid config format in ${configPath}`);
47
- return { plugins: [] };
48
- }
49
-
50
- return config as ZenithConfig;
51
- } catch (error: unknown) {
52
- const message = error instanceof Error ? error.message : String(error);
53
- console.error(`[Zenith] Failed to load config from ${configPath}:`, message);
54
- return { plugins: [] };
55
- }
56
- }
57
-
58
- /**
59
- * Check if a zenith.config.ts exists in the project
60
- */
61
- export function hasZenithConfig(projectRoot: string): boolean {
62
- const configPaths = [
63
- path.join(projectRoot, 'zenith.config.ts'),
64
- path.join(projectRoot, 'zenith.config.js'),
65
- path.join(projectRoot, 'zenith.config.mjs'),
66
- ];
67
-
68
- return configPaths.some(p => fs.existsSync(p));
69
- }
@@ -1,119 +0,0 @@
1
- /**
2
- * Zenith Config Types
3
- *
4
- * Configuration interfaces for zenith.config.ts
5
- *
6
- * ═══════════════════════════════════════════════════════════════════════════════
7
- * HOOK OWNERSHIP RULE (CANONICAL)
8
- * ═══════════════════════════════════════════════════════════════════════════════
9
- *
10
- * Core may ONLY define types that are universally valid in all Zenith applications.
11
- * Plugin-specific types MUST be owned by their respective plugins.
12
- *
13
- * ✅ ALLOWED in Core:
14
- * - ZenithConfig, ZenithPlugin, PluginContext (generic plugin infrastructure)
15
- * - Universal lifecycle hooks (onMount, onUnmount)
16
- * - Reactivity primitives (signal, effect, etc.)
17
- *
18
- * ❌ PROHIBITED in Core:
19
- * - Content plugin types (ContentItem, ContentSourceConfig, etc.)
20
- * - Router plugin types (RouteState, NavigationGuard, etc.)
21
- * - Documentation plugin types
22
- * - Any type that exists only because a plugin exists
23
- *
24
- * If removing a plugin would make a type meaningless, that type belongs to the plugin.
25
- * ═══════════════════════════════════════════════════════════════════════════════
26
- */
27
-
28
- import type { CLIBridgeAPI } from '../plugins/bridge';
29
-
30
- // ============================================
31
- // Core Plugin Types (Generic Infrastructure)
32
- // ============================================
33
-
34
- /**
35
- * Generic data record for plugin data exchange
36
- * Plugins define their own specific types internally
37
- */
38
- export type PluginData = Record<string, unknown[]>;
39
-
40
- /**
41
- * Context passed to plugins during setup
42
- *
43
- * This is intentionally generic - plugins define their own data shapes.
44
- * Core provides the stage, plugins bring the actors.
45
- */
46
- export interface PluginContext {
47
- /** Absolute path to project root */
48
- projectRoot: string;
49
-
50
- /**
51
- * Set plugin data for the runtime
52
- *
53
- * Generic setter - plugins define their own data structures.
54
- * The runtime stores this data and makes it available to components.
55
- *
56
- * @example
57
- * // Content plugin uses it for content items
58
- * ctx.setPluginData('content', contentItems);
59
- *
60
- * // Analytics plugin uses it for tracking config
61
- * ctx.setPluginData('analytics', analyticsConfig);
62
- */
63
- setPluginData: (namespace: string, data: unknown[]) => void;
64
-
65
- /** Additional options passed from config */
66
- options?: Record<string, unknown>;
67
- }
68
-
69
- /**
70
- * A Zenith plugin definition
71
- *
72
- * Plugins are self-contained, removable extensions.
73
- * Core must build and run identically with or without any plugin installed.
74
- */
75
- export interface ZenithPlugin {
76
- /** Unique plugin name */
77
- name: string;
78
-
79
- /** Setup function called during initialization */
80
- setup: (ctx: PluginContext) => void | Promise<void>;
81
-
82
- /** Plugin-specific configuration (preserved for reference) */
83
- config?: unknown;
84
-
85
- /**
86
- * Optional CLI registration
87
- *
88
- * Plugin receives the CLI bridge API to register namespaced hooks.
89
- * CLI lifecycle hooks: 'cli:*' (owned by CLI)
90
- * Plugin hooks: '<namespace>:*' (owned by plugin)
91
- *
92
- * @example
93
- * registerCLI(api) {
94
- * api.on('cli:runtime:collect', (ctx) => {
95
- * return { namespace: 'myPlugin', payload: ctx.getPluginData('myPlugin') }
96
- * })
97
- * }
98
- */
99
- registerCLI?: (api: CLIBridgeAPI) => void;
100
- }
101
-
102
- // ============================================
103
- // Main Config Types
104
- // ============================================
105
-
106
- /**
107
- * Zenith configuration object
108
- */
109
- export interface ZenithConfig {
110
- /** List of plugins to load */
111
- plugins?: ZenithPlugin[];
112
- }
113
-
114
- /**
115
- * Define a Zenith configuration with full type safety
116
- */
117
- export function defineConfig(config: ZenithConfig): ZenithConfig {
118
- return config;
119
- }
@@ -1,193 +0,0 @@
1
- /**
2
- * Zenith CLI Bridge
3
- *
4
- * The ONLY interface between CLI and plugins.
5
- *
6
- * ═══════════════════════════════════════════════════════════════════════════════
7
- * CLI BRIDGE RULES (CANONICAL)
8
- * ═══════════════════════════════════════════════════════════════════════════════
9
- *
10
- * 1. No runtime emitters - plugins return data, CLI serializes blindly
11
- * 2. No plugin typing - all data is unknown
12
- * 3. No semantic helpers - CLI is blind to what data means
13
- *
14
- * The CLI dispatches hooks and collects returns. It never inspects payloads.
15
- * ═══════════════════════════════════════════════════════════════════════════════
16
- */
17
-
18
- /**
19
- * CLI Bridge API - passed to plugins during CLI registration
20
- *
21
- * Plugins use this to register namespaced hooks.
22
- * CLI lifecycle hooks: 'cli:*'
23
- * Plugin hooks: '<namespace>:*'
24
- */
25
- export interface CLIBridgeAPI {
26
- /**
27
- * Register a hook handler
28
- *
29
- * @param hook - Namespaced hook name (e.g., 'cli:runtime:collect', 'content:dev:watch')
30
- * @param handler - Handler function that receives context and optionally returns data
31
- */
32
- on(hook: string, handler: (ctx: HookContext) => unknown | void | Promise<unknown | void>): void
33
- }
34
-
35
- /**
36
- * Context passed to hook handlers
37
- *
38
- * CLI provides this but never uses getPluginData itself.
39
- * Only plugins call getPluginData with their own namespace.
40
- */
41
- export interface HookContext {
42
- /** Absolute path to project root */
43
- projectRoot: string
44
-
45
- /**
46
- * Opaque data accessor
47
- *
48
- * CLI passes this function but NEVER calls it.
49
- * Only plugins use it to access their own namespaced data.
50
- */
51
- getPluginData: (namespace: string) => unknown
52
-
53
- /** Additional context data (e.g., filename for file-change hooks) */
54
- [key: string]: unknown
55
- }
56
-
57
- /**
58
- * Runtime payload returned by plugins
59
- *
60
- * CLI collects these and serializes without inspection.
61
- * The envelope structure is: { [namespace]: payload }
62
- */
63
- export interface RuntimePayload {
64
- /** Plugin namespace (e.g., 'content', 'router') */
65
- namespace: string
66
- /** Opaque payload - CLI never inspects this */
67
- payload: unknown
68
- }
69
-
70
- // ============================================
71
- // Hook Registry (Internal)
72
- // ============================================
73
-
74
- type HookHandler = (ctx: HookContext) => unknown | void | Promise<unknown | void>
75
-
76
- const hookRegistry = new Map<string, HookHandler[]>()
77
-
78
- /**
79
- * Register a hook handler
80
- *
81
- * @internal Called by CLIBridgeAPI.on()
82
- */
83
- export function registerHook(hook: string, handler: HookHandler): void {
84
- if (!hookRegistry.has(hook)) {
85
- hookRegistry.set(hook, [])
86
- }
87
- hookRegistry.get(hook)!.push(handler)
88
- }
89
-
90
- /**
91
- * Clear all registered hooks
92
- *
93
- * @internal Used for testing and cleanup
94
- */
95
- export function clearHooks(): void {
96
- hookRegistry.clear()
97
- }
98
-
99
- // ============================================
100
- // Hook Execution (CLI-facing)
101
- // ============================================
102
-
103
- /**
104
- * Run all handlers for a hook (fire-and-forget)
105
- *
106
- * CLI calls this for lifecycle events.
107
- * No return values are collected.
108
- *
109
- * @param hook - Hook name to dispatch
110
- * @param ctx - Hook context
111
- */
112
- export async function runPluginHooks(hook: string, ctx: HookContext): Promise<void> {
113
- const handlers = hookRegistry.get(hook) || []
114
- for (const handler of handlers) {
115
- try {
116
- await handler(ctx)
117
- } catch (error) {
118
- console.error(`[Zenith] Hook "${hook}" error:`, error)
119
- }
120
- }
121
- }
122
-
123
- /**
124
- * Collect return values from all handlers for a hook
125
- *
126
- * CLI calls this for 'cli:runtime:collect' to gather plugin payloads.
127
- * Only RuntimePayload-shaped returns are collected.
128
- *
129
- * @param hook - Hook name to dispatch
130
- * @param ctx - Hook context
131
- * @returns Array of runtime payloads from plugins
132
- */
133
- export async function collectHookReturns(hook: string, ctx: HookContext): Promise<RuntimePayload[]> {
134
- const handlers = hookRegistry.get(hook) || []
135
- const results: RuntimePayload[] = []
136
-
137
- for (const handler of handlers) {
138
- try {
139
- const result = await handler(ctx)
140
-
141
- // Only collect properly shaped payloads
142
- if (
143
- result &&
144
- typeof result === 'object' &&
145
- 'namespace' in result &&
146
- 'payload' in result &&
147
- typeof (result as RuntimePayload).namespace === 'string'
148
- ) {
149
- results.push(result as RuntimePayload)
150
- }
151
- } catch (error) {
152
- console.error(`[Zenith] Hook "${hook}" collection error:`, error)
153
- }
154
- }
155
-
156
- return results
157
- }
158
-
159
- /**
160
- * Build runtime envelope from collected payloads
161
- *
162
- * CLI calls this to serialize plugin data for injection.
163
- * CLI never inspects the envelope contents.
164
- *
165
- * @param payloads - Array of runtime payloads from collectHookReturns
166
- * @returns Envelope object: { [namespace]: payload }
167
- */
168
- export function buildRuntimeEnvelope(payloads: RuntimePayload[]): Record<string, unknown> {
169
- const envelope: Record<string, unknown> = {}
170
-
171
- for (const { namespace, payload } of payloads) {
172
- envelope[namespace] = payload
173
- }
174
-
175
- return envelope
176
- }
177
-
178
- // ============================================
179
- // Bridge API Factory
180
- // ============================================
181
-
182
- /**
183
- * Create a CLI Bridge API for plugin registration
184
- *
185
- * CLI calls this once and passes to each plugin's registerCLI method.
186
- *
187
- * @returns CLIBridgeAPI instance
188
- */
189
- export function createBridgeAPI(): CLIBridgeAPI {
190
- return {
191
- on: registerHook
192
- }
193
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * Zenith Plugins
3
- *
4
- * Public exports for plugin system
5
- */
6
-
7
- export { PluginRegistry, createPluginContext } from './registry';
@@ -1,126 +0,0 @@
1
- /**
2
- * Zenith Plugin Registry
3
- *
4
- * Manages plugin registration and initialization
5
- *
6
- * ═══════════════════════════════════════════════════════════════════════════════
7
- * HOOK OWNERSHIP RULE (CANONICAL)
8
- * ═══════════════════════════════════════════════════════════════════════════════
9
- *
10
- * The plugin registry is part of core infrastructure.
11
- * It MUST remain plugin-agnostic:
12
- * - No plugin-specific types
13
- * - No plugin-specific logic
14
- * - Generic data handling only
15
- *
16
- * Plugins own their data structures; core provides the storage mechanism.
17
- * ═══════════════════════════════════════════════════════════════════════════════
18
- */
19
-
20
- import type { ZenithPlugin, PluginContext } from '../config/types';
21
-
22
- /**
23
- * Global plugin data store
24
- *
25
- * Plugins store their data here using namespaced keys.
26
- * Core does not interpret this data - it just stores and serves it.
27
- */
28
- const pluginDataStore: Record<string, unknown[]> = {};
29
-
30
- /**
31
- * Get all plugin data (for runtime access)
32
- */
33
- export function getPluginData(): Record<string, unknown[]> {
34
- return { ...pluginDataStore };
35
- }
36
-
37
- /**
38
- * Get plugin data by namespace
39
- */
40
- export function getPluginDataByNamespace(namespace: string): unknown[] {
41
- return pluginDataStore[namespace] || [];
42
- }
43
-
44
- /**
45
- * Plugin registry for managing Zenith plugins
46
- */
47
- export class PluginRegistry {
48
- private plugins = new Map<string, ZenithPlugin>();
49
-
50
- /**
51
- * Register a plugin
52
- */
53
- register(plugin: ZenithPlugin): void {
54
- if (this.plugins.has(plugin.name)) {
55
- console.warn(`[Zenith] Plugin "${plugin.name}" is already registered. Overwriting.`);
56
- }
57
- this.plugins.set(plugin.name, plugin);
58
- }
59
-
60
- /**
61
- * Get a plugin by name
62
- */
63
- get(name: string): ZenithPlugin | undefined {
64
- return this.plugins.get(name);
65
- }
66
-
67
- /**
68
- * Check if a plugin is registered
69
- */
70
- has(name: string): boolean {
71
- return this.plugins.has(name);
72
- }
73
-
74
- /**
75
- * Get all registered plugins
76
- */
77
- all(): ZenithPlugin[] {
78
- return Array.from(this.plugins.values());
79
- }
80
-
81
- /**
82
- * Initialize all plugins with the provided context
83
- */
84
- async initAll(ctx: PluginContext): Promise<void> {
85
- for (const plugin of this.plugins.values()) {
86
- try {
87
- await plugin.setup(ctx);
88
- console.log(`[Zenith] Plugin "${plugin.name}" initialized`);
89
- } catch (error: unknown) {
90
- const message = error instanceof Error ? error.message : String(error);
91
- console.error(`[Zenith] Failed to initialize plugin "${plugin.name}":`, message);
92
- }
93
- }
94
- }
95
-
96
- /**
97
- * Clear all registered plugins
98
- */
99
- clear(): void {
100
- this.plugins.clear();
101
- // Also clear plugin data
102
- for (const key of Object.keys(pluginDataStore)) {
103
- delete pluginDataStore[key];
104
- }
105
- }
106
- }
107
-
108
- /**
109
- * Create a plugin context for initialization
110
- *
111
- * Uses a generic data setter that stores data by namespace.
112
- * Plugins define their own data structures internally.
113
- *
114
- * @param projectRoot - Absolute path to the project root
115
- * @returns A PluginContext for plugin initialization
116
- */
117
- export function createPluginContext(projectRoot: string): PluginContext {
118
- return {
119
- projectRoot,
120
- setPluginData: (namespace: string, data: unknown[]) => {
121
- pluginDataStore[namespace] = data;
122
- },
123
- options: {}
124
- };
125
- }
126
-