@zenithbuild/core 0.4.7 → 0.5.0-beta.2.1

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 +40 -52
  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
@@ -0,0 +1,143 @@
1
+ # CORE_CONTRACT.md — Deterministic Utility Substrate
2
+
3
+ > **This document is a legal boundary.**
4
+ > Core is a shared utility layer. It contains no business logic,
5
+ > no routing, no DOM, no framework behavior. Pure helper substrate only.
6
+ >
7
+ > **Standalone test:** If `zenith-core` were published alone on npm,
8
+ > it must make sense as a generic deterministic utility library.
9
+
10
+ ## Status: FROZEN (V0)
11
+
12
+ ---
13
+
14
+ ## 1. Core Identity
15
+
16
+ Core provides deterministic **transforms**, **formatting**, and **schema validation**.
17
+
18
+ **Core provides:**
19
+ - Deterministic transforms: `hash`, `normalizePath`, `sortRoutes`, `parseConfig`, `parseSemver`
20
+ - Deterministic formatting: `formatError`
21
+ - Deterministic schema validation: `validateConfigSchema`, `validateRouteParams`
22
+
23
+ **Core does NOT:**
24
+ - Scan repositories
25
+ - Enforce cross-layer behavior
26
+ - Know about router semantics
27
+ - Know about bundler internals
28
+ - Police other layers' architecture
29
+
30
+ ---
31
+
32
+ ## 2. Allowed Modules
33
+
34
+ | Module | Purpose |
35
+ |---|---|
36
+ | `config.js` | Load + validate config schema |
37
+ | `path.js` | Normalize paths + `[param]` → `:param` |
38
+ | `order.js` | Static-first stable sort |
39
+ | `hash.js` | SHA-256 content hashing |
40
+ | `errors.js` | Error factory + prefixing |
41
+ | `version.js` | SemVer parsing + major compatibility |
42
+ | `guards.js` | Small pure validation helpers |
43
+ | `index.js` | Re-exports |
44
+
45
+ ---
46
+
47
+ ## 3. Determinism Guarantees
48
+
49
+ | Rule | Guarantee |
50
+ |---|---|
51
+ | Hashing | Same input → same hash, cross-platform |
52
+ | Ordering | Stable sort: static first, dynamic after, alpha tiebreak |
53
+ | Paths | Normalized separators (`/`), consistent param format |
54
+ | Config | Missing keys → explicit defaults, unknown keys → throw |
55
+ | Errors | Consistent format: `[Zenith:MODULE] message` |
56
+
57
+ ---
58
+
59
+ ## 4. Explicit Prohibitions
60
+
61
+ Core source **must never**:
62
+
63
+ 1. Import from `@zenithbuild/compiler`, `@zenithbuild/bundler`, `@zenithbuild/runtime`, or `@zenithbuild/router`
64
+ 2. Reference `window`, `document`, `navigator`, or any browser API
65
+ 3. Use `eval()`, `new Function()`, or `document.write()`
66
+ 4. Perform build orchestration of any kind
67
+ 5. Access the filesystem **except when explicitly loading `zenith.config.js`**
68
+ 6. Mutate global state
69
+ 7. Contain preset/mode logic (`basic`, `router`, `fullstack` belong in `create-zenith`)
70
+ 8. Initiate version checks against other packages (other layers call core's utility)
71
+
72
+ ---
73
+
74
+ ## 5. Hash Contract
75
+
76
+ - Algorithm: **SHA-256** via `node:crypto`
77
+ - Output: **hex string**
78
+ - Input normalization: path separators → `/`, trailing newlines stripped
79
+
80
+ > **Critical rule:** Hash algorithm must match bundler's algorithm exactly.
81
+ > If bundler changes hash algorithm, core must change in lockstep.
82
+
83
+ ---
84
+
85
+ ## 6. Config Schema (V0)
86
+
87
+ ```js
88
+ // zenith.config.js
89
+ export default {
90
+ router: false, // boolean — opt-in client router
91
+ outDir: 'dist', // string — output directory
92
+ pagesDir: 'pages' // string — pages directory
93
+ }
94
+ ```
95
+
96
+ | Key | Type | Default | Validation |
97
+ |---|---|---|---|
98
+ | `router` | `boolean` | `false` | Must be boolean |
99
+ | `outDir` | `string` | `'dist'` | Non-empty string |
100
+ | `pagesDir` | `string` | `'pages'` | Non-empty string |
101
+
102
+ Unknown keys → throw `[Zenith:Config] Unknown key: "foo"`.
103
+
104
+ **No other keys for V0.** No `mode`, `target`, `presets`, `experimental`, `base`, `assetsDir`.
105
+
106
+ ---
107
+
108
+ ## 7. Version Compatibility API
109
+
110
+ ```js
111
+ validateCompatibility(coreVersion, otherVersion)
112
+ // Throws if major versions differ
113
+ // Warns if minor versions differ by > 1
114
+ ```
115
+
116
+ **Direction of control:** Other layers call this function.
117
+ Core never imports other packages to auto-check.
118
+
119
+ ---
120
+
121
+ ## 8. Guard Helpers
122
+
123
+ Guards are **small pure validation helpers**:
124
+
125
+ ```js
126
+ containsForbiddenPattern(source, patterns) // returns boolean
127
+ validateRouteParams(routePath) // throws on repeated params
128
+ validateConfigSchema(config) // throws on unknown keys / wrong types
129
+ ```
130
+
131
+ Guards do NOT:
132
+ - Scan entire repositories
133
+ - Enforce architectural decisions
134
+ - Assert that other layers used sorting correctly
135
+
136
+ ---
137
+
138
+ ## 9. Dependency Rules
139
+
140
+ - **Zero dependencies on other Zenith packages**
141
+ - Zero runtime npm dependencies
142
+ - Dev dependencies: Jest only
143
+ - Pure ESM, Node.js built-ins only
package/README.md CHANGED
@@ -1,39 +1,19 @@
1
- # @zenithbuild/core
1
+ # `@zenithbuild/core`
2
2
 
3
- The heart of the Zenith framework. High-performance reactive runtime, compiler, and build primitives.
3
+ This is the **sole public entrypoint** for the Zenith framework.
4
4
 
5
- ## Overview
5
+ Use this package directly in your projects to run Zenith utilities and access the official APIs.
6
6
 
7
- Zenith is a modern reactive web framework designed for maximum performance and developer experience. The core package contains the essential building blocks:
8
- - **Compiler**: Transforms `.zen` files into optimized JavaScript.
9
- - **Runtime**: A lightweight, efficient reactive system for the browser.
10
- - **Router**: Lightweight client-side routing.
11
- - **Build Primitives**: Tools for dev servers and production builds.
7
+ ## Installation
12
8
 
13
- ## Key Components
14
-
15
- ### 1. Compiler (`/compiler`)
16
- The Zenith compiler handles parsing and transforming Single File Components (`.zen`). It leverages `parse5` for robust HTML parsing and generates highly optimized render functions.
17
-
18
- ### 2. Runtime (`/runtime`)
19
- Our runtime is designed to be minimal. It manages the reactive cycle, efficient DOM updates, and lifecycle management (like `zenOnMount`).
20
-
21
- ### 3. Server (`/bin/zen-dev`, `/bin/zen-build`)
22
- Low-level binaries for orchestrating development and production environments.
23
-
24
- ## Architecture
25
-
26
- Zenith follows a "Compiler-First" philosophy. We shift as much work as possible to build time, keeping the client-side bundle lean and fast.
27
-
28
- ## Usage (Internal)
9
+ ```bash
10
+ npm install @zenithbuild/core
11
+ ```
29
12
 
30
- This package is typically consumed by the Zenith CLI and other ecosystem tools.
13
+ ## Running the CLI
31
14
 
32
- ```typescript
33
- import { compile } from '@zenithbuild/core/compiler';
34
- // ... compile logic
35
- ```
15
+ The `.bin` wrapper is exposed as `zenith`. Running `npx zenith dev` or `npx zenith build` executes the corresponding framework command.
36
16
 
37
- ## License
17
+ ## Internal Dependencies
38
18
 
39
- MIT
19
+ For developers: DO NOT import any other `@zenithbuild/*` packages directly (e.g. `@zenithbuild/compiler`, `@zenithbuild/runtime`, `@zenithbuild/cli`). All needed features are either opaque implementation details or safely exposed through exports here. Direct access of inner implementation details is strictly forbidden.
package/bin/zenith.js ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from 'node:fs';
4
+ import { dirname, join } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { createRequire } from 'node:module';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+ const require = createRequire(import.meta.url);
11
+
12
+ // Version mismatch check
13
+ const corePkgPath = join(__dirname, '../package.json');
14
+ const corePkg = JSON.parse(readFileSync(corePkgPath, 'utf-8'));
15
+
16
+ const expectedInternals = [
17
+ '@zenithbuild/cli',
18
+ '@zenithbuild/compiler',
19
+ '@zenithbuild/runtime',
20
+ '@zenithbuild/router',
21
+ '@zenithbuild/bundler'
22
+ ];
23
+
24
+ let hasMismatch = false;
25
+
26
+ for (const internal of expectedInternals) {
27
+ const expectedVersion = corePkg.dependencies[internal];
28
+ if (!expectedVersion) continue;
29
+
30
+ try {
31
+ const entryPath = require.resolve(internal);
32
+
33
+ // Walk up to find the package's package.json
34
+ let currentDir = dirname(entryPath);
35
+ let pkgVersion = null;
36
+
37
+ while (currentDir !== '/' && currentDir !== '.') {
38
+ try {
39
+ const pkgTxt = readFileSync(join(currentDir, 'package.json'), 'utf-8');
40
+ const pkg = JSON.parse(pkgTxt);
41
+ if (pkg.name === internal) {
42
+ pkgVersion = pkg.version;
43
+ break;
44
+ }
45
+ } catch (e) {
46
+ // Ignored, continue walking up
47
+ }
48
+ currentDir = dirname(currentDir);
49
+ }
50
+
51
+ if (pkgVersion && pkgVersion !== expectedVersion) {
52
+ console.error(`Version mismatch: ${internal} is version ${pkgVersion} but @zenithbuild/core expects exactly ${expectedVersion}`);
53
+ hasMismatch = true;
54
+ } else if (!pkgVersion) {
55
+ // In a strict mode, failing to find package.json might be treated as a failure.
56
+ }
57
+ } catch (err) {
58
+ console.error(`Version mismatch check failed: Could not resolve internal dependency ${internal}`);
59
+ hasMismatch = true;
60
+ }
61
+ }
62
+
63
+ if (hasMismatch) {
64
+ process.exit(1);
65
+ }
66
+
67
+ // Proceed to hand off execution to the underlying CLI implementation
68
+ import('@zenithbuild/cli');
package/package.json CHANGED
@@ -1,67 +1,55 @@
1
1
  {
2
2
  "name": "@zenithbuild/core",
3
- "version": "0.4.7",
4
- "description": "Core library for the Zenith framework",
3
+ "version": "0.5.0-beta.2.1",
4
+ "description": "Deterministic utility substrate for the Zenith framework",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
- "main": "./index.ts",
7
+ "main": "./src/index.js",
8
8
  "bin": {
9
- "zenith": "./dist/zenith.js",
10
- "zenith-dev": "./dist/zen-dev.js",
11
- "zen-dev": "./dist/zen-dev.js",
12
- "zen-build": "./dist/zen-build.js",
13
- "zen-preview": "./dist/zen-preview.js"
9
+ "zenith": "./bin/zenith.js"
10
+ },
11
+ "exports": {
12
+ ".": "./src/index.js",
13
+ "./config": "./src/config.js",
14
+ "./path": "./src/path.js",
15
+ "./order": "./src/order.js",
16
+ "./hash": "./src/hash.js",
17
+ "./errors": "./src/errors.js",
18
+ "./version": "./src/version.js",
19
+ "./guards": "./src/guards.js",
20
+ "./schema": "./src/schema.js",
21
+ "./core-template": "./src/core-template.js",
22
+ "./ir": "./src/ir/index.js"
14
23
  },
15
24
  "files": [
25
+ "src",
16
26
  "bin",
17
- "cli",
18
- "compiler",
19
- "core",
20
- "router",
21
- "runtime",
22
- "dist",
23
- "index.ts",
24
- "tsconfig.json"
27
+ "CORE_CONTRACT.md",
28
+ "README.md",
29
+ "contracts"
25
30
  ],
26
- "exports": {
27
- ".": "./index.ts",
28
- "./compiler": "./compiler/index.ts",
29
- "./config": "./core/config/index.ts",
30
- "./core": "./core/index.ts",
31
- "./router": "./router/index.ts",
32
- "./runtime": "./runtime/index.ts"
31
+ "publishConfig": {
32
+ "access": "public"
33
33
  },
34
- "keywords": [
35
- "zenith",
36
- "core",
37
- "framework"
38
- ],
39
- "author": "Zenith Team",
40
- "repository": {
41
- "type": "git",
42
- "url": "git@github.com:zenithbuild/zenith-core.git"
34
+ "dependencies": {
35
+ "@zenithbuild/cli": "0.5.0-beta.2.1",
36
+ "@zenithbuild/compiler": "0.5.0-beta.2.1",
37
+ "@zenithbuild/runtime": "0.5.0-beta.2.1",
38
+ "@zenithbuild/router": "0.5.0-beta.2.1",
39
+ "@zenithbuild/bundler": "0.5.0-beta.2.1"
43
40
  },
44
41
  "scripts": {
45
- "dev": "bun dev",
46
- "build": "bun build",
47
- "start": "bun run build && bun run dev",
48
- "build:cli": "bun build bin/zenith.ts bin/zen-dev.ts bin/zen-build.ts bin/zen-preview.ts --outdir dist --target bun --bundle && for f in dist/*.js; do echo '#!/usr/bin/env bun' | cat - \"$f\" > \"$f.tmp\" && mv \"$f.tmp\" \"$f\" && chmod +x \"$f\"; done",
49
- "format": "prettier --write \"**/*.ts\"",
50
- "format:check": "prettier --check \"**/*.ts\""
42
+ "test": "npm run contract:deps && npm run contract:scan && npm run contract:api && npm run contract:template && npm run contract:golden",
43
+ "test:legacy": "NODE_OPTIONS=--experimental-vm-modules jest --config jest.config.js",
44
+ "contract:deps": "node dependency_contract.spec.js",
45
+ "contract:scan": "node contract-scan.mjs",
46
+ "contract:api": "node core_api_lock.spec.js",
47
+ "contract:template": "node template-contract.spec.js",
48
+ "contract:golden": "node golden-contract.spec.js"
51
49
  },
52
- "private": false,
53
50
  "devDependencies": {
54
- "@types/bun": "latest",
55
- "@types/node": "latest",
56
- "prettier": "^3.7.4"
57
- },
58
- "peerDependencies": {
59
- "typescript": "^5"
51
+ "@jest/globals": "^30.2.0",
52
+ "jest": "^30.2.0"
60
53
  },
61
- "dependencies": {
62
- "@types/marked": "^6.0.0",
63
- "@types/parse5": "^7.0.0",
64
- "marked": "^17.0.1",
65
- "parse5": "^8.0.0"
66
- }
67
- }
54
+ "private": false
55
+ }
package/src/config.js ADDED
@@ -0,0 +1,134 @@
1
+ // ---------------------------------------------------------------------------
2
+ // config.js — Zenith Core V0
3
+ // ---------------------------------------------------------------------------
4
+ // Load and validate zenith.config.js. This is the ONLY module in core
5
+ // that touches the filesystem (via dynamic import).
6
+ //
7
+ // V0 Schema: { router, outDir, pagesDir }
8
+ // Unknown keys → throw.
9
+ // ---------------------------------------------------------------------------
10
+
11
+ import { join } from 'node:path';
12
+ import { pathToFileURL } from 'node:url';
13
+
14
+ /** V0 config defaults */
15
+ const DEFAULTS = {
16
+ router: false,
17
+ embeddedMarkupExpressions: false,
18
+ types: true,
19
+ typescriptDefault: true,
20
+ outDir: 'dist',
21
+ pagesDir: 'pages',
22
+ experimental: {}
23
+ };
24
+
25
+ /** Allowed keys and their expected types */
26
+ const SCHEMA = {
27
+ router: 'boolean',
28
+ embeddedMarkupExpressions: 'boolean',
29
+ types: 'boolean',
30
+ typescriptDefault: 'boolean',
31
+ outDir: 'string',
32
+ pagesDir: 'string',
33
+ experimental: 'object'
34
+ };
35
+
36
+ /**
37
+ * Validate a config object against the V0 schema.
38
+ * Throws on unknown keys or wrong types.
39
+ *
40
+ * @param {object} config
41
+ * @returns {object} Normalized config with defaults applied
42
+ */
43
+ export function validateConfig(config) {
44
+ if (config === null || config === undefined) {
45
+ return { ...DEFAULTS };
46
+ }
47
+
48
+ if (typeof config !== 'object' || Array.isArray(config)) {
49
+ throw new Error('[Zenith:Config] Config must be a plain object');
50
+ }
51
+
52
+ // Check for unknown keys
53
+ for (const key of Object.keys(config)) {
54
+ if (!(key in SCHEMA)) {
55
+ throw new Error(`[Zenith:Config] Unknown key: "${key}"`);
56
+ }
57
+ }
58
+
59
+ // Validate types and apply defaults
60
+ const result = { ...DEFAULTS };
61
+
62
+ for (const [key, expectedType] of Object.entries(SCHEMA)) {
63
+ if (key in config) {
64
+ const value = config[key];
65
+ if (typeof value !== expectedType) {
66
+ throw new Error(
67
+ `[Zenith:Config] Key "${key}" must be ${expectedType}, got ${typeof value}`
68
+ );
69
+ }
70
+ if (expectedType === 'string' && value.trim() === '') {
71
+ throw new Error(
72
+ `[Zenith:Config] Key "${key}" must be a non-empty string`
73
+ );
74
+ }
75
+ if (key === 'experimental' && value) {
76
+ if (typeof value !== 'object' || Array.isArray(value)) {
77
+ throw new Error(`[Zenith:Config] Key "experimental" must be a plain object`);
78
+ }
79
+ const expDefaults = { ...DEFAULTS.experimental };
80
+ for (const expKey of Object.keys(value)) {
81
+ if (!(expKey in expDefaults)) {
82
+ throw new Error(`[Zenith:Config] Unknown experimental key: "${expKey}"`);
83
+ }
84
+ if (typeof value[expKey] !== typeof expDefaults[expKey]) {
85
+ throw new Error(`[Zenith:Config] Experimental key "${expKey}" must be ${typeof expDefaults[expKey]}`);
86
+ }
87
+ expDefaults[expKey] = value[expKey];
88
+ }
89
+ result[key] = expDefaults;
90
+ continue;
91
+ }
92
+ result[key] = value;
93
+ }
94
+ }
95
+
96
+ return result;
97
+ }
98
+
99
+ /**
100
+ * Load zenith.config.js from a project root.
101
+ * Returns validated config with defaults applied.
102
+ *
103
+ * @param {string} projectRoot
104
+ * @returns {Promise<object>}
105
+ */
106
+ export async function loadConfig(projectRoot) {
107
+ const configPath = join(projectRoot, 'zenith.config.js');
108
+
109
+ try {
110
+ const url = pathToFileURL(configPath).href;
111
+ const mod = await import(url);
112
+ const raw = mod.default || mod;
113
+ return validateConfig(raw);
114
+ } catch (err) {
115
+ // File not found — return defaults
116
+ if (
117
+ err.code === 'ERR_MODULE_NOT_FOUND' ||
118
+ err.code === 'ENOENT' ||
119
+ err.message?.includes('Cannot find module') ||
120
+ err.message?.includes('ENOENT')
121
+ ) {
122
+ return { ...DEFAULTS };
123
+ }
124
+ throw err;
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Return the default config.
130
+ * @returns {object}
131
+ */
132
+ export function getDefaults() {
133
+ return { ...DEFAULTS };
134
+ }
@@ -0,0 +1,30 @@
1
+ // ---------------------------------------------------------------------------
2
+ // core-template.js — source template for emitted core asset
3
+ // ---------------------------------------------------------------------------
4
+
5
+ function assertRuntimeImport(runtimeImport) {
6
+ if (typeof runtimeImport !== 'string' || runtimeImport.trim().length === 0) {
7
+ throw new Error('[Zenith Core] coreModuleSource(runtimeImport) requires non-empty runtimeImport');
8
+ }
9
+ }
10
+
11
+ export function coreModuleSource(runtimeImport) {
12
+ assertRuntimeImport(runtimeImport);
13
+ const runtimeImportLiteral = JSON.stringify(runtimeImport);
14
+
15
+ return [
16
+ `import { signal, state, zeneffect, zenEffect as __zenithZenEffect, zenMount as __zenithZenMount } from ${runtimeImportLiteral};`,
17
+ '',
18
+ 'export const zenSignal = signal;',
19
+ 'export const zenState = state;',
20
+ 'export const zenEffect = __zenithZenEffect;',
21
+ 'export const zenMount = __zenithZenMount;',
22
+ '',
23
+ 'export function zenOnMount(callback) {',
24
+ ' return __zenithZenMount(callback);',
25
+ '}',
26
+ '',
27
+ 'export { signal, state, zeneffect };',
28
+ ''
29
+ ].join('\n');
30
+ }
package/src/errors.js ADDED
@@ -0,0 +1,54 @@
1
+ // ---------------------------------------------------------------------------
2
+ // errors.js — Zenith Core V0
3
+ // ---------------------------------------------------------------------------
4
+ // Shared error formatting. All Zenith errors use the format:
5
+ // [Zenith:MODULE] message
6
+ //
7
+ // Pure factory functions. No side effects.
8
+ // ---------------------------------------------------------------------------
9
+
10
+ /**
11
+ * Create a Zenith error with standard formatting.
12
+ *
13
+ * @param {string} module Module name (e.g. 'Config', 'Path', 'Build')
14
+ * @param {string} message Error message
15
+ * @returns {Error}
16
+ */
17
+ export function createError(module, message) {
18
+ const err = new Error(`[Zenith:${module}] ${message}`);
19
+ err.zenithModule = module;
20
+ return err;
21
+ }
22
+
23
+ /**
24
+ * Format an error message with the Zenith prefix.
25
+ *
26
+ * @param {string} module
27
+ * @param {string} message
28
+ * @returns {string}
29
+ */
30
+ export function formatError(module, message) {
31
+ return `[Zenith:${module}] ${message}`;
32
+ }
33
+
34
+ /**
35
+ * Check if an error is a Zenith error.
36
+ *
37
+ * @param {Error} err
38
+ * @returns {boolean}
39
+ */
40
+ export function isZenithError(err) {
41
+ return err instanceof Error && typeof err.zenithModule === 'string';
42
+ }
43
+
44
+ /**
45
+ * Predefined error codes for common situations.
46
+ */
47
+ export const ErrorCodes = {
48
+ CONFIG_UNKNOWN_KEY: 'CONFIG_UNKNOWN_KEY',
49
+ CONFIG_INVALID_TYPE: 'CONFIG_INVALID_TYPE',
50
+ CONFIG_EMPTY_VALUE: 'CONFIG_EMPTY_VALUE',
51
+ PATH_REPEATED_PARAM: 'PATH_REPEATED_PARAM',
52
+ VERSION_INCOMPATIBLE: 'VERSION_INCOMPATIBLE',
53
+ GUARD_VIOLATION: 'GUARD_VIOLATION'
54
+ };
package/src/guards.js ADDED
@@ -0,0 +1,61 @@
1
+ // ---------------------------------------------------------------------------
2
+ // guards.js — Zenith Core V0
3
+ // ---------------------------------------------------------------------------
4
+ // Small pure validation helpers. These provide primitives —
5
+ // they do NOT scan repos, enforce architecture, or police other layers.
6
+ // ---------------------------------------------------------------------------
7
+
8
+ /**
9
+ * Check if source contains any of the given forbidden patterns.
10
+ *
11
+ * @param {string} source Source code text
12
+ * @param {string[]} patterns Patterns to check for
13
+ * @returns {string[]} Array of matched patterns (empty if none)
14
+ */
15
+ export function containsForbiddenPattern(source, patterns) {
16
+ const found = [];
17
+ for (const pattern of patterns) {
18
+ if (source.includes(pattern)) {
19
+ found.push(pattern);
20
+ }
21
+ }
22
+ return found;
23
+ }
24
+
25
+ /**
26
+ * Validate that a route path has no repeated parameter names.
27
+ * Re-exported from path.js for convenience.
28
+ *
29
+ * @param {string} routePath
30
+ */
31
+ export { validateRouteParams } from './path.js';
32
+
33
+ /**
34
+ * Validate a config object against the V0 schema.
35
+ * Re-exported from config.js for convenience.
36
+ *
37
+ * @param {object} config
38
+ * @returns {object}
39
+ */
40
+ export { validateConfig as validateConfigSchema } from './config.js';
41
+
42
+ /**
43
+ * Default forbidden patterns for Zenith source code.
44
+ */
45
+ export const FORBIDDEN_PATTERNS = [
46
+ 'eval(',
47
+ 'new Function(',
48
+ 'new Function (',
49
+ 'document.write('
50
+ ];
51
+
52
+ /**
53
+ * Default browser globals that should not appear in Node-only code.
54
+ */
55
+ export const BROWSER_GLOBALS = [
56
+ 'window',
57
+ 'document',
58
+ 'navigator',
59
+ 'localStorage',
60
+ 'sessionStorage'
61
+ ];