@zenithbuild/compiler 1.3.2 → 1.3.9

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 (73) hide show
  1. package/dist/build-analyzer.d.ts +44 -0
  2. package/dist/build-analyzer.js +87 -0
  3. package/dist/bundler.d.ts +31 -0
  4. package/dist/bundler.js +92 -0
  5. package/dist/core/config/index.d.ts +11 -0
  6. package/dist/core/config/index.js +10 -0
  7. package/dist/core/config/loader.d.ts +17 -0
  8. package/dist/core/config/loader.js +60 -0
  9. package/dist/core/config/types.d.ts +98 -0
  10. package/dist/core/config/types.js +32 -0
  11. package/dist/core/index.d.ts +7 -0
  12. package/dist/core/index.js +6 -0
  13. package/dist/core/plugins/bridge.d.ts +116 -0
  14. package/dist/core/plugins/bridge.js +121 -0
  15. package/dist/core/plugins/index.d.ts +6 -0
  16. package/dist/core/plugins/index.js +6 -0
  17. package/dist/core/plugins/registry.d.ts +67 -0
  18. package/dist/core/plugins/registry.js +112 -0
  19. package/dist/css/index.d.ts +73 -0
  20. package/dist/css/index.js +246 -0
  21. package/dist/discovery/componentDiscovery.d.ts +41 -0
  22. package/dist/discovery/componentDiscovery.js +66 -0
  23. package/dist/discovery/layouts.d.ts +14 -0
  24. package/dist/discovery/layouts.js +36 -0
  25. package/dist/errors/compilerError.d.ts +31 -0
  26. package/dist/errors/compilerError.js +51 -0
  27. package/dist/finalize/generateFinalBundle.d.ts +24 -0
  28. package/dist/finalize/generateFinalBundle.js +68 -0
  29. package/dist/index.d.ts +34 -0
  30. package/dist/index.js +44 -0
  31. package/dist/ir/types.d.ts +206 -0
  32. package/dist/ir/types.js +8 -0
  33. package/dist/output/types.d.ts +39 -0
  34. package/dist/output/types.js +6 -0
  35. package/dist/parseZenFile.d.ts +17 -0
  36. package/dist/parseZenFile.js +52 -0
  37. package/dist/runtime/build.d.ts +6 -0
  38. package/dist/runtime/build.js +13 -0
  39. package/dist/runtime/bundle-generator.d.ts +27 -0
  40. package/dist/runtime/bundle-generator.js +1438 -0
  41. package/dist/runtime/client-runtime.d.ts +41 -0
  42. package/dist/runtime/client-runtime.js +397 -0
  43. package/dist/runtime/hydration.d.ts +53 -0
  44. package/dist/runtime/hydration.js +271 -0
  45. package/dist/runtime/navigation.d.ts +58 -0
  46. package/dist/runtime/navigation.js +372 -0
  47. package/dist/runtime/serve.d.ts +13 -0
  48. package/dist/runtime/serve.js +76 -0
  49. package/dist/runtime/thinRuntime.d.ts +23 -0
  50. package/dist/runtime/thinRuntime.js +158 -0
  51. package/dist/spa-build.d.ts +26 -0
  52. package/dist/spa-build.js +849 -0
  53. package/dist/ssg-build.d.ts +31 -0
  54. package/dist/ssg-build.js +429 -0
  55. package/dist/test/bundler-contract.test.d.ts +1 -0
  56. package/dist/test/bundler-contract.test.js +137 -0
  57. package/dist/test/compiler-entry.test.d.ts +1 -0
  58. package/dist/test/compiler-entry.test.js +28 -0
  59. package/dist/test/error-native-bridge.test.d.ts +1 -0
  60. package/dist/test/error-native-bridge.test.js +31 -0
  61. package/dist/test/error-serialization.test.d.ts +1 -0
  62. package/dist/test/error-serialization.test.js +38 -0
  63. package/dist/test/phase5-boundary.test.d.ts +1 -0
  64. package/dist/test/phase5-boundary.test.js +51 -0
  65. package/dist/transform/layoutProcessor.d.ts +26 -0
  66. package/dist/transform/layoutProcessor.js +34 -0
  67. package/dist/validate/invariants.d.ts +23 -0
  68. package/dist/validate/invariants.js +55 -0
  69. package/native/compiler-native/compiler-native.node +0 -0
  70. package/native/compiler-native/index.d.ts +2 -46
  71. package/native/compiler-native/index.js +1 -16
  72. package/native/compiler-native/package.json +1 -1
  73. package/package.json +15 -5
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Zenith Build Analyzer
3
+ *
4
+ * Analyzes .zen page source to determine build strategy:
5
+ * - Static: Pure HTML+CSS, no JS needed
6
+ * - Hydration: Has state/events/hooks, needs page-specific JS
7
+ * - SSR: Uses useFetchServer, needs server rendering
8
+ * - SPA: Uses ZenLink with passHref, needs client router
9
+ */
10
+ export interface PageAnalysis {
11
+ /** Page has state declarations that need hydration */
12
+ hasState: boolean;
13
+ /** Page has event handlers (onclick, etc.) */
14
+ hasEventHandlers: boolean;
15
+ /** Page uses lifecycle hooks (zenOnMount, zenOnUnmount) */
16
+ hasLifecycleHooks: boolean;
17
+ /** Page uses useFetchServer (requires SSR) */
18
+ usesServerFetch: boolean;
19
+ /** Page uses useFetchClient (client-side data) */
20
+ usesClientFetch: boolean;
21
+ /** Page uses ZenLink with passHref (SPA navigation) */
22
+ usesZenLink: boolean;
23
+ /** Page uses reactive expressions in templates */
24
+ hasReactiveExpressions: boolean;
25
+ /** Computed: page needs any JavaScript */
26
+ needsHydration: boolean;
27
+ /** Computed: page is purely static (no JS) */
28
+ isStatic: boolean;
29
+ /** Computed: page needs SSR */
30
+ needsSSR: boolean;
31
+ }
32
+ /**
33
+ * Analyze a .zen page source to determine build requirements
34
+ */
35
+ export declare function analyzePageSource(source: string): PageAnalysis;
36
+ /**
37
+ * Get a human-readable summary of the page analysis
38
+ */
39
+ export declare function getAnalysisSummary(analysis: PageAnalysis): string;
40
+ /**
41
+ * Determine build output type for a page
42
+ */
43
+ export type BuildOutputType = 'static' | 'hydrated' | 'ssr';
44
+ export declare function getBuildOutputType(analysis: PageAnalysis): BuildOutputType;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Zenith Build Analyzer
3
+ *
4
+ * Analyzes .zen page source to determine build strategy:
5
+ * - Static: Pure HTML+CSS, no JS needed
6
+ * - Hydration: Has state/events/hooks, needs page-specific JS
7
+ * - SSR: Uses useFetchServer, needs server rendering
8
+ * - SPA: Uses ZenLink with passHref, needs client router
9
+ */
10
+ /**
11
+ * Analyze a .zen page source to determine build requirements
12
+ */
13
+ export function analyzePageSource(source) {
14
+ // Extract script content for analysis
15
+ const scriptMatch = source.match(/<script[^>]*>([\s\S]*?)<\/script>/i);
16
+ const scriptContent = scriptMatch?.[1] || '';
17
+ // Extract template content (everything outside script/style)
18
+ const templateContent = source
19
+ .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
20
+ .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '');
21
+ // Check for state declarations: "state varName = ..."
22
+ const hasState = /\bstate\s+\w+\s*=/.test(scriptContent);
23
+ // Check for event handlers in template
24
+ const hasEventHandlers = /\bon(click|change|input|submit|focus|blur|keydown|keyup|keypress|mousedown|mouseup|mouseover|mouseout|mouseenter|mouseleave|load)\s*=\s*["'{]/.test(templateContent);
25
+ // Check for lifecycle hooks
26
+ const hasLifecycleHooks = /\bzen(OnMount|OnUnmount)\s*\(/.test(scriptContent);
27
+ // Check for server fetch
28
+ const usesServerFetch = /\buseFetchServer\s*\(/.test(scriptContent);
29
+ // Check for client fetch
30
+ const usesClientFetch = /\buseFetchClient\s*\(/.test(scriptContent);
31
+ // Check for ZenLink with passHref
32
+ const usesZenLink = /<ZenLink[^>]*passHref[^>]*>/.test(templateContent);
33
+ // Check for reactive expressions in template: {expression}
34
+ // Must be actual expressions, not just static text
35
+ // Exclude attribute values like href="/path"
36
+ const hasReactiveExpressions = /{[^{}]+}/.test(templateContent);
37
+ // Compute derived properties
38
+ const needsHydration = hasState || hasEventHandlers || hasLifecycleHooks ||
39
+ usesClientFetch || hasReactiveExpressions;
40
+ const isStatic = !needsHydration && !usesServerFetch;
41
+ const needsSSR = usesServerFetch;
42
+ return {
43
+ hasState,
44
+ hasEventHandlers,
45
+ hasLifecycleHooks,
46
+ usesServerFetch,
47
+ usesClientFetch,
48
+ usesZenLink,
49
+ hasReactiveExpressions,
50
+ needsHydration,
51
+ isStatic,
52
+ needsSSR
53
+ };
54
+ }
55
+ /**
56
+ * Get a human-readable summary of the page analysis
57
+ */
58
+ export function getAnalysisSummary(analysis) {
59
+ const flags = [];
60
+ if (analysis.isStatic) {
61
+ flags.push('STATIC (no JS)');
62
+ }
63
+ else {
64
+ if (analysis.hasState)
65
+ flags.push('state');
66
+ if (analysis.hasEventHandlers)
67
+ flags.push('events');
68
+ if (analysis.hasLifecycleHooks)
69
+ flags.push('lifecycle');
70
+ if (analysis.hasReactiveExpressions)
71
+ flags.push('reactive');
72
+ if (analysis.usesClientFetch)
73
+ flags.push('clientFetch');
74
+ }
75
+ if (analysis.needsSSR)
76
+ flags.push('SSR');
77
+ if (analysis.usesZenLink)
78
+ flags.push('SPA');
79
+ return flags.length > 0 ? flags.join(', ') : 'minimal';
80
+ }
81
+ export function getBuildOutputType(analysis) {
82
+ if (analysis.needsSSR)
83
+ return 'ssr';
84
+ if (analysis.needsHydration)
85
+ return 'hydrated';
86
+ return 'static';
87
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @zenithbuild/core - Page Script Bundler
3
+ *
4
+ * COMPILER-FIRST ARCHITECTURE
5
+ * ═══════════════════════════════════════════════════════════════════════════════
6
+ *
7
+ * This bundler performs ZERO inference. It executes exactly what the compiler specifies.
8
+ *
9
+ * Rules:
10
+ * - If a BundlePlan is provided, bundling MUST occur
11
+ * - If bundling fails, throw a hard error (no fallback)
12
+ * - The bundler never inspects source code for intent
13
+ * - No temp files, no heuristics, no recovery
14
+ *
15
+ * Bundler failure = compiler bug.
16
+ * ═══════════════════════════════════════════════════════════════════════════════
17
+ */
18
+ import type { BundlePlan } from './ir/types';
19
+ /**
20
+ * Execute a compiler-emitted BundlePlan
21
+ *
22
+ * This is a PURE PLAN EXECUTOR. It does not:
23
+ * - Inspect source code for imports
24
+ * - Decide whether bundling is needed
25
+ * - Fall back on failure
26
+ * - Use temp files
27
+ *
28
+ * @param plan - Compiler-emitted BundlePlan (must exist; caller must not call if no plan)
29
+ * @throws Error if bundling fails (no fallback, no recovery)
30
+ */
31
+ export declare function bundlePageScript(plan: BundlePlan): Promise<string>;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @zenithbuild/core - Page Script Bundler
3
+ *
4
+ * COMPILER-FIRST ARCHITECTURE
5
+ * ═══════════════════════════════════════════════════════════════════════════════
6
+ *
7
+ * This bundler performs ZERO inference. It executes exactly what the compiler specifies.
8
+ *
9
+ * Rules:
10
+ * - If a BundlePlan is provided, bundling MUST occur
11
+ * - If bundling fails, throw a hard error (no fallback)
12
+ * - The bundler never inspects source code for intent
13
+ * - No temp files, no heuristics, no recovery
14
+ *
15
+ * Bundler failure = compiler bug.
16
+ * ═══════════════════════════════════════════════════════════════════════════════
17
+ */
18
+ import { rolldown } from 'rolldown';
19
+ /**
20
+ * Execute a compiler-emitted BundlePlan
21
+ *
22
+ * This is a PURE PLAN EXECUTOR. It does not:
23
+ * - Inspect source code for imports
24
+ * - Decide whether bundling is needed
25
+ * - Fall back on failure
26
+ * - Use temp files
27
+ *
28
+ * @param plan - Compiler-emitted BundlePlan (must exist; caller must not call if no plan)
29
+ * @throws Error if bundling fails (no fallback, no recovery)
30
+ */
31
+ export async function bundlePageScript(plan) {
32
+ // Virtual entry module ID
33
+ const VIRTUAL_ENTRY = '\0zenith:entry.tsx';
34
+ /*
35
+ console.log('[Zenith Bundler] Input entry length:', plan.entry.length)
36
+ if (plan.entry.length > 4000) {
37
+ console.log('[Zenith Bundler] Input entry tail:', plan.entry.slice(-200))
38
+ }
39
+ */
40
+ // Build virtual modules map from plan
41
+ const virtualModules = new Map();
42
+ virtualModules.set(VIRTUAL_ENTRY, plan.entry);
43
+ for (const vm of plan.virtualModules) {
44
+ virtualModules.set(vm.id, vm.code);
45
+ }
46
+ // Execute Rolldown with plan-specified configuration
47
+ // No inference, no heuristics, no semantic analysis
48
+ const bundle = await rolldown({
49
+ input: VIRTUAL_ENTRY,
50
+ platform: plan.platform,
51
+ resolve: {
52
+ modules: plan.resolveRoots
53
+ },
54
+ plugins: [{
55
+ name: 'zenith-virtual',
56
+ resolveId(source) {
57
+ // Virtual modules from plan
58
+ if (virtualModules.has(source)) {
59
+ return { id: source, moduleSideEffects: true };
60
+ }
61
+ // Special case: zenith:content namespace
62
+ if (source === 'zenith:content') {
63
+ return { id: '\0zenith:content', moduleSideEffects: true };
64
+ }
65
+ return null;
66
+ },
67
+ load(id) {
68
+ return virtualModules.get(id) ?? null;
69
+ }
70
+ }],
71
+ // DETERMINISTIC OUTPUT: Disable all semantic optimizations
72
+ // Tree-shaking implies semantic analysis - bundler must not infer
73
+ treeshake: false,
74
+ // HARD FAILURE on unresolved imports - no silent external treatment
75
+ onLog(level, log) {
76
+ if (log.code === 'UNRESOLVED_IMPORT') {
77
+ throw new Error(`[Zenith Bundler] Unresolved import: ${log.message}. ` +
78
+ `This is a compiler error - the BundlePlan references a module that cannot be resolved.`);
79
+ }
80
+ }
81
+ });
82
+ // Generate output with plan-specified format
83
+ const { output } = await bundle.generate({
84
+ format: plan.format
85
+ });
86
+ // Hard failure if no output - this is a compiler bug
87
+ if (!output[0]?.code) {
88
+ throw new Error('[Zenith Bundler] Rolldown produced no output. ' +
89
+ 'This is a compiler error - the BundlePlan was invalid or Rolldown failed silently.');
90
+ }
91
+ return output[0].code;
92
+ }
@@ -0,0 +1,11 @@
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
+ export { defineConfig } from './types';
10
+ export type { ZenithConfig, ZenithPlugin, PluginContext, PluginData } from './types';
11
+ export { loadZenithConfig, hasZenithConfig } from './loader';
@@ -0,0 +1,10 @@
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
+ export { defineConfig } from './types';
10
+ export { loadZenithConfig, hasZenithConfig } from './loader';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Zenith Config Loader
3
+ *
4
+ * Loads zenith.config.ts from the project root
5
+ */
6
+ import type { ZenithConfig } from './types';
7
+ /**
8
+ * Load zenith.config.ts from the project root
9
+ *
10
+ * @param projectRoot - Absolute path to the project root
11
+ * @returns Parsed ZenithConfig or empty config if not found
12
+ */
13
+ export declare function loadZenithConfig(projectRoot: string): Promise<ZenithConfig>;
14
+ /**
15
+ * Check if a zenith.config.ts exists in the project
16
+ */
17
+ export declare function hasZenithConfig(projectRoot: string): boolean;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Zenith Config Loader
3
+ *
4
+ * Loads zenith.config.ts from the project root
5
+ */
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ /**
9
+ * Load zenith.config.ts from the project root
10
+ *
11
+ * @param projectRoot - Absolute path to the project root
12
+ * @returns Parsed ZenithConfig or empty config if not found
13
+ */
14
+ export async function loadZenithConfig(projectRoot) {
15
+ // Check for TypeScript config first, then JavaScript
16
+ const configPaths = [
17
+ path.join(projectRoot, 'zenith.config.ts'),
18
+ path.join(projectRoot, 'zenith.config.js'),
19
+ path.join(projectRoot, 'zenith.config.mjs'),
20
+ ];
21
+ let configPath = null;
22
+ for (const p of configPaths) {
23
+ if (fs.existsSync(p)) {
24
+ configPath = p;
25
+ break;
26
+ }
27
+ }
28
+ if (!configPath) {
29
+ // No config file found, return empty config
30
+ return { plugins: [] };
31
+ }
32
+ try {
33
+ // Use dynamic import to load the config
34
+ // Bun supports importing TS files directly
35
+ const configModule = await import(configPath);
36
+ const config = configModule.default || configModule;
37
+ // Validate basic structure
38
+ if (typeof config !== 'object' || config === null) {
39
+ console.warn(`[Zenith] Invalid config format in ${configPath}`);
40
+ return { plugins: [] };
41
+ }
42
+ return config;
43
+ }
44
+ catch (error) {
45
+ const message = error instanceof Error ? error.message : String(error);
46
+ console.error(`[Zenith] Failed to load config from ${configPath}:`, message);
47
+ return { plugins: [] };
48
+ }
49
+ }
50
+ /**
51
+ * Check if a zenith.config.ts exists in the project
52
+ */
53
+ export function hasZenithConfig(projectRoot) {
54
+ const configPaths = [
55
+ path.join(projectRoot, 'zenith.config.ts'),
56
+ path.join(projectRoot, 'zenith.config.js'),
57
+ path.join(projectRoot, 'zenith.config.mjs'),
58
+ ];
59
+ return configPaths.some(p => fs.existsSync(p));
60
+ }
@@ -0,0 +1,98 @@
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
+ import type { CLIBridgeAPI } from '../plugins/bridge';
28
+ /**
29
+ * Generic data record for plugin data exchange
30
+ * Plugins define their own specific types internally
31
+ */
32
+ export type PluginData = Record<string, unknown[]>;
33
+ /**
34
+ * Context passed to plugins during setup
35
+ *
36
+ * This is intentionally generic - plugins define their own data shapes.
37
+ * Core provides the stage, plugins bring the actors.
38
+ */
39
+ export interface PluginContext {
40
+ /** Absolute path to project root */
41
+ projectRoot: string;
42
+ /**
43
+ * Set plugin data for the runtime
44
+ *
45
+ * Generic setter - plugins define their own data structures.
46
+ * The runtime stores this data and makes it available to components.
47
+ *
48
+ * @example
49
+ * // Content plugin uses it for content items
50
+ * ctx.setPluginData('content', contentItems);
51
+ *
52
+ * // Analytics plugin uses it for tracking config
53
+ * ctx.setPluginData('analytics', analyticsConfig);
54
+ */
55
+ setPluginData: (namespace: string, data: unknown[]) => void;
56
+ /** Additional options passed from config */
57
+ options?: Record<string, unknown>;
58
+ }
59
+ /**
60
+ * A Zenith plugin definition
61
+ *
62
+ * Plugins are self-contained, removable extensions.
63
+ * Core must build and run identically with or without any plugin installed.
64
+ */
65
+ export interface ZenithPlugin {
66
+ /** Unique plugin name */
67
+ name: string;
68
+ /** Setup function called during initialization */
69
+ setup: (ctx: PluginContext) => void | Promise<void>;
70
+ /** Plugin-specific configuration (preserved for reference) */
71
+ config?: unknown;
72
+ /**
73
+ * Optional CLI registration
74
+ *
75
+ * Plugin receives the CLI bridge API to register namespaced hooks.
76
+ * CLI lifecycle hooks: 'cli:*' (owned by CLI)
77
+ * Plugin hooks: '<namespace>:*' (owned by plugin)
78
+ *
79
+ * @example
80
+ * registerCLI(api) {
81
+ * api.on('cli:runtime:collect', (ctx) => {
82
+ * return { namespace: 'myPlugin', payload: ctx.getPluginData('myPlugin') }
83
+ * })
84
+ * }
85
+ */
86
+ registerCLI?: (api: CLIBridgeAPI) => void;
87
+ }
88
+ /**
89
+ * Zenith configuration object
90
+ */
91
+ export interface ZenithConfig {
92
+ /** List of plugins to load */
93
+ plugins?: ZenithPlugin[];
94
+ }
95
+ /**
96
+ * Define a Zenith configuration with full type safety
97
+ */
98
+ export declare function defineConfig(config: ZenithConfig): ZenithConfig;
@@ -0,0 +1,32 @@
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
+ * Define a Zenith configuration with full type safety
29
+ */
30
+ export function defineConfig(config) {
31
+ return config;
32
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Zenith Compiler Core Modules
3
+ */
4
+ export { loadZenithConfig } from './config/loader';
5
+ export { PluginRegistry, createPluginContext, getPluginDataByNamespace } from './plugins/registry';
6
+ export { createBridgeAPI, runPluginHooks, collectHookReturns, buildRuntimeEnvelope, clearHooks } from './plugins/bridge';
7
+ export type { HookContext } from './plugins/bridge';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Zenith Compiler Core Modules
3
+ */
4
+ export { loadZenithConfig } from './config/loader';
5
+ export { PluginRegistry, createPluginContext, getPluginDataByNamespace } from './plugins/registry';
6
+ export { createBridgeAPI, runPluginHooks, collectHookReturns, buildRuntimeEnvelope, clearHooks } from './plugins/bridge';
@@ -0,0 +1,116 @@
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
+ * CLI Bridge API - passed to plugins during CLI registration
19
+ *
20
+ * Plugins use this to register namespaced hooks.
21
+ * CLI lifecycle hooks: 'cli:*'
22
+ * Plugin hooks: '<namespace>:*'
23
+ */
24
+ export interface CLIBridgeAPI {
25
+ /**
26
+ * Register a hook handler
27
+ *
28
+ * @param hook - Namespaced hook name (e.g., 'cli:runtime:collect', 'content:dev:watch')
29
+ * @param handler - Handler function that receives context and optionally returns data
30
+ */
31
+ on(hook: string, handler: (ctx: HookContext) => unknown | void | Promise<unknown | void>): void;
32
+ }
33
+ /**
34
+ * Context passed to hook handlers
35
+ *
36
+ * CLI provides this but never uses getPluginData itself.
37
+ * Only plugins call getPluginData with their own namespace.
38
+ */
39
+ export interface HookContext {
40
+ /** Absolute path to project root */
41
+ projectRoot: string;
42
+ /**
43
+ * Opaque data accessor
44
+ *
45
+ * CLI passes this function but NEVER calls it.
46
+ * Only plugins use it to access their own namespaced data.
47
+ */
48
+ getPluginData: (namespace: string) => unknown;
49
+ /** Additional context data (e.g., filename for file-change hooks) */
50
+ [key: string]: unknown;
51
+ }
52
+ /**
53
+ * Runtime payload returned by plugins
54
+ *
55
+ * CLI collects these and serializes without inspection.
56
+ * The envelope structure is: { [namespace]: payload }
57
+ */
58
+ export interface RuntimePayload {
59
+ /** Plugin namespace (e.g., 'content', 'router') */
60
+ namespace: string;
61
+ /** Opaque payload - CLI never inspects this */
62
+ payload: unknown;
63
+ }
64
+ type HookHandler = (ctx: HookContext) => unknown | void | Promise<unknown | void>;
65
+ /**
66
+ * Register a hook handler
67
+ *
68
+ * @internal Called by CLIBridgeAPI.on()
69
+ */
70
+ export declare function registerHook(hook: string, handler: HookHandler): void;
71
+ /**
72
+ * Clear all registered hooks
73
+ *
74
+ * @internal Used for testing and cleanup
75
+ */
76
+ export declare function clearHooks(): void;
77
+ /**
78
+ * Run all handlers for a hook (fire-and-forget)
79
+ *
80
+ * CLI calls this for lifecycle events.
81
+ * No return values are collected.
82
+ *
83
+ * @param hook - Hook name to dispatch
84
+ * @param ctx - Hook context
85
+ */
86
+ export declare function runPluginHooks(hook: string, ctx: HookContext): Promise<void>;
87
+ /**
88
+ * Collect return values from all handlers for a hook
89
+ *
90
+ * CLI calls this for 'cli:runtime:collect' to gather plugin payloads.
91
+ * Only RuntimePayload-shaped returns are collected.
92
+ *
93
+ * @param hook - Hook name to dispatch
94
+ * @param ctx - Hook context
95
+ * @returns Array of runtime payloads from plugins
96
+ */
97
+ export declare function collectHookReturns(hook: string, ctx: HookContext): Promise<RuntimePayload[]>;
98
+ /**
99
+ * Build runtime envelope from collected payloads
100
+ *
101
+ * CLI calls this to serialize plugin data for injection.
102
+ * CLI never inspects the envelope contents.
103
+ *
104
+ * @param payloads - Array of runtime payloads from collectHookReturns
105
+ * @returns Envelope object: { [namespace]: payload }
106
+ */
107
+ export declare function buildRuntimeEnvelope(payloads: RuntimePayload[]): Record<string, unknown>;
108
+ /**
109
+ * Create a CLI Bridge API for plugin registration
110
+ *
111
+ * CLI calls this once and passes to each plugin's registerCLI method.
112
+ *
113
+ * @returns CLIBridgeAPI instance
114
+ */
115
+ export declare function createBridgeAPI(): CLIBridgeAPI;
116
+ export {};