@zenithbuild/core 0.6.2 → 0.6.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.
- package/CORE_CONTRACT.md +145 -0
- package/README.md +14 -29
- package/bin/zenith.js +89 -0
- package/package.json +39 -56
- package/src/config.js +136 -0
- package/src/core-template.js +30 -0
- package/src/errors.js +54 -0
- package/src/guards.js +61 -0
- package/src/hash.js +52 -0
- package/src/index.js +26 -0
- package/src/ir/index.js +1 -0
- package/src/order.js +69 -0
- package/src/path.js +131 -0
- package/src/schema.js +28 -0
- package/src/version.js +67 -0
- package/bin/zen-build.ts +0 -2
- package/bin/zen-dev.ts +0 -2
- package/bin/zen-preview.ts +0 -2
- package/bin/zenith.ts +0 -2
- package/cli/commands/add.ts +0 -37
- package/cli/commands/build.ts +0 -37
- package/cli/commands/create.ts +0 -702
- package/cli/commands/dev.ts +0 -388
- package/cli/commands/index.ts +0 -112
- package/cli/commands/preview.ts +0 -62
- package/cli/commands/remove.ts +0 -33
- package/cli/index.ts +0 -10
- package/cli/main.ts +0 -101
- package/cli/utils/branding.ts +0 -178
- package/cli/utils/content.ts +0 -112
- package/cli/utils/logger.ts +0 -46
- package/cli/utils/plugin-manager.ts +0 -114
- package/cli/utils/project.ts +0 -77
- package/compiler/README.md +0 -380
- package/compiler/build-analyzer.ts +0 -122
- package/compiler/css/index.ts +0 -317
- package/compiler/discovery/componentDiscovery.ts +0 -178
- package/compiler/discovery/layouts.ts +0 -70
- package/compiler/errors/compilerError.ts +0 -56
- package/compiler/finalize/finalizeOutput.ts +0 -192
- package/compiler/finalize/generateFinalBundle.ts +0 -82
- package/compiler/index.ts +0 -83
- package/compiler/ir/types.ts +0 -174
- package/compiler/output/types.ts +0 -34
- package/compiler/parse/detectMapExpressions.ts +0 -102
- package/compiler/parse/importTypes.ts +0 -78
- package/compiler/parse/parseImports.ts +0 -309
- package/compiler/parse/parseScript.ts +0 -46
- package/compiler/parse/parseTemplate.ts +0 -599
- package/compiler/parse/parseZenFile.ts +0 -66
- package/compiler/parse/scriptAnalysis.ts +0 -91
- package/compiler/parse/trackLoopContext.ts +0 -82
- package/compiler/runtime/dataExposure.ts +0 -317
- package/compiler/runtime/generateDOM.ts +0 -246
- package/compiler/runtime/generateHydrationBundle.ts +0 -407
- package/compiler/runtime/hydration.ts +0 -309
- package/compiler/runtime/navigation.ts +0 -432
- package/compiler/runtime/thinRuntime.ts +0 -160
- package/compiler/runtime/transformIR.ts +0 -370
- package/compiler/runtime/wrapExpression.ts +0 -95
- package/compiler/runtime/wrapExpressionWithLoop.ts +0 -83
- package/compiler/spa-build.ts +0 -917
- package/compiler/ssg-build.ts +0 -422
- package/compiler/test/validate-test.ts +0 -104
- package/compiler/transform/classifyExpression.ts +0 -444
- package/compiler/transform/componentResolver.ts +0 -312
- package/compiler/transform/componentScriptTransformer.ts +0 -303
- package/compiler/transform/expressionTransformer.ts +0 -385
- package/compiler/transform/fragmentLowering.ts +0 -634
- package/compiler/transform/generateBindings.ts +0 -47
- package/compiler/transform/generateHTML.ts +0 -28
- package/compiler/transform/layoutProcessor.ts +0 -132
- package/compiler/transform/slotResolver.ts +0 -292
- package/compiler/transform/transformNode.ts +0 -126
- package/compiler/transform/transformTemplate.ts +0 -38
- package/compiler/validate/invariants.ts +0 -292
- package/compiler/validate/validateExpressions.ts +0 -168
- package/core/config/index.ts +0 -16
- package/core/config/loader.ts +0 -69
- package/core/config/types.ts +0 -89
- package/core/index.ts +0 -135
- package/core/lifecycle/index.ts +0 -49
- package/core/lifecycle/zen-mount.ts +0 -182
- package/core/lifecycle/zen-unmount.ts +0 -88
- package/core/plugins/index.ts +0 -7
- package/core/plugins/registry.ts +0 -81
- package/core/reactivity/index.ts +0 -54
- package/core/reactivity/tracking.ts +0 -167
- package/core/reactivity/zen-batch.ts +0 -57
- package/core/reactivity/zen-effect.ts +0 -139
- package/core/reactivity/zen-memo.ts +0 -146
- package/core/reactivity/zen-ref.ts +0 -52
- package/core/reactivity/zen-signal.ts +0 -121
- package/core/reactivity/zen-state.ts +0 -180
- package/core/reactivity/zen-untrack.ts +0 -44
- package/dist/cli.js +0 -11665
- package/dist/zen-build.js +0 -21172
- package/dist/zen-dev.js +0 -21172
- package/dist/zen-preview.js +0 -21172
- package/dist/zenith.js +0 -21172
- package/router/index.ts +0 -28
- package/router/manifest.ts +0 -314
- package/router/navigation/ZenLink.zen +0 -231
- package/router/navigation/index.ts +0 -78
- package/router/navigation/zen-link.ts +0 -584
- package/router/runtime.ts +0 -458
- package/router/types.ts +0 -168
- package/runtime/build.ts +0 -17
- package/runtime/bundle-generator.ts +0 -1247
- package/runtime/client-runtime.ts +0 -549
- package/runtime/serve.ts +0 -93
- package/tsconfig.json +0 -28
package/CORE_CONTRACT.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# CORE_CONTRACT.md — Deterministic Utility Substrate
|
|
2
|
+
|
|
3
|
+
Canonical public docs: `../zenith-docs/documentation/contracts/core-contract.md`
|
|
4
|
+
|
|
5
|
+
> **This document is a legal boundary.**
|
|
6
|
+
> Core is a shared utility layer. It contains no business logic,
|
|
7
|
+
> no routing, no DOM, no framework behavior. Pure helper substrate only.
|
|
8
|
+
>
|
|
9
|
+
> **Standalone test:** If `zenith-core` were published alone on npm,
|
|
10
|
+
> it must make sense as a generic deterministic utility library.
|
|
11
|
+
|
|
12
|
+
## Status: FROZEN (V0)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 1. Core Identity
|
|
17
|
+
|
|
18
|
+
Core provides deterministic **transforms**, **formatting**, and **schema validation**.
|
|
19
|
+
|
|
20
|
+
**Core provides:**
|
|
21
|
+
- Deterministic transforms: `hash`, `normalizePath`, `sortRoutes`, `parseConfig`, `parseSemver`
|
|
22
|
+
- Deterministic formatting: `formatError`
|
|
23
|
+
- Deterministic schema validation: `validateConfigSchema`, `validateRouteParams`
|
|
24
|
+
|
|
25
|
+
**Core does NOT:**
|
|
26
|
+
- Scan repositories
|
|
27
|
+
- Enforce cross-layer behavior
|
|
28
|
+
- Know about router semantics
|
|
29
|
+
- Know about bundler internals
|
|
30
|
+
- Police other layers' architecture
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 2. Allowed Modules
|
|
35
|
+
|
|
36
|
+
| Module | Purpose |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `config.js` | Load + validate config schema |
|
|
39
|
+
| `path.js` | Normalize paths + `[param]` → `:param` |
|
|
40
|
+
| `order.js` | Static-first stable sort |
|
|
41
|
+
| `hash.js` | SHA-256 content hashing |
|
|
42
|
+
| `errors.js` | Error factory + prefixing |
|
|
43
|
+
| `version.js` | SemVer parsing + major compatibility |
|
|
44
|
+
| `guards.js` | Small pure validation helpers |
|
|
45
|
+
| `index.js` | Re-exports |
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 3. Determinism Guarantees
|
|
50
|
+
|
|
51
|
+
| Rule | Guarantee |
|
|
52
|
+
|---|---|
|
|
53
|
+
| Hashing | Same input → same hash, cross-platform |
|
|
54
|
+
| Ordering | Stable sort: static first, dynamic after, alpha tiebreak |
|
|
55
|
+
| Paths | Normalized separators (`/`), consistent param format |
|
|
56
|
+
| Config | Missing keys → explicit defaults, unknown keys → throw |
|
|
57
|
+
| Errors | Consistent format: `[Zenith:MODULE] message` |
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 4. Explicit Prohibitions
|
|
62
|
+
|
|
63
|
+
Core source **must never**:
|
|
64
|
+
|
|
65
|
+
1. Import from `@zenithbuild/compiler`, `@zenithbuild/bundler`, `@zenithbuild/runtime`, or `@zenithbuild/router`
|
|
66
|
+
2. Reference `window`, `document`, `navigator`, or any browser API
|
|
67
|
+
3. Use `eval()`, `new Function()`, or `document.write()`
|
|
68
|
+
4. Perform build orchestration of any kind
|
|
69
|
+
5. Access the filesystem **except when explicitly loading `zenith.config.js`**
|
|
70
|
+
6. Mutate global state
|
|
71
|
+
7. Contain preset/mode logic (`basic`, `router`, `fullstack` belong in `create-zenith`)
|
|
72
|
+
8. Initiate version checks against other packages (other layers call core's utility)
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 5. Hash Contract
|
|
77
|
+
|
|
78
|
+
- Algorithm: **SHA-256** via `node:crypto`
|
|
79
|
+
- Output: **hex string**
|
|
80
|
+
- Input normalization: path separators → `/`, trailing newlines stripped
|
|
81
|
+
|
|
82
|
+
> **Critical rule:** Hash algorithm must match bundler's algorithm exactly.
|
|
83
|
+
> If bundler changes hash algorithm, core must change in lockstep.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 6. Config Schema (V0)
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
// zenith.config.js
|
|
91
|
+
export default {
|
|
92
|
+
router: false, // boolean — opt-in client router
|
|
93
|
+
outDir: 'dist', // string — output directory
|
|
94
|
+
pagesDir: 'pages' // string — pages directory
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
| Key | Type | Default | Validation |
|
|
99
|
+
|---|---|---|---|
|
|
100
|
+
| `router` | `boolean` | `false` | Must be boolean |
|
|
101
|
+
| `outDir` | `string` | `'dist'` | Non-empty string |
|
|
102
|
+
| `pagesDir` | `string` | `'pages'` | Non-empty string |
|
|
103
|
+
|
|
104
|
+
Unknown keys → throw `[Zenith:Config] Unknown key: "foo"`.
|
|
105
|
+
|
|
106
|
+
**No other keys for V0.** No `mode`, `target`, `presets`, `experimental`, `base`, `assetsDir`.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 7. Version Compatibility API
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
validateCompatibility(coreVersion, otherVersion)
|
|
114
|
+
// Throws if major versions differ
|
|
115
|
+
// Warns if minor versions differ by > 1
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Direction of control:** Other layers call this function.
|
|
119
|
+
Core never imports other packages to auto-check.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 8. Guard Helpers
|
|
124
|
+
|
|
125
|
+
Guards are **small pure validation helpers**:
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
containsForbiddenPattern(source, patterns) // returns boolean
|
|
129
|
+
validateRouteParams(routePath) // throws on repeated params
|
|
130
|
+
validateConfigSchema(config) // throws on unknown keys / wrong types
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Guards do NOT:
|
|
134
|
+
- Scan entire repositories
|
|
135
|
+
- Enforce architectural decisions
|
|
136
|
+
- Assert that other layers used sorting correctly
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 9. Dependency Rules
|
|
141
|
+
|
|
142
|
+
- **Zero dependencies on other Zenith packages**
|
|
143
|
+
- Zero runtime npm dependencies
|
|
144
|
+
- Dev dependencies: Jest only
|
|
145
|
+
- Pure ESM, Node.js built-ins only
|
package/README.md
CHANGED
|
@@ -1,39 +1,24 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@zenithbuild/core`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This is the **sole public entrypoint** for the Zenith framework.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Canonical Docs
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
-
|
|
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
|
+
- Core contract: `../zenith-docs/documentation/contracts/core-contract.md`
|
|
8
|
+
- Zenith contract: `../zenith-docs/documentation/zenith-contract.md`
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
Use this package directly in your projects to run Zenith utilities and access the official APIs.
|
|
14
11
|
|
|
15
|
-
|
|
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.
|
|
12
|
+
## Installation
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
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)
|
|
14
|
+
```bash
|
|
15
|
+
npm install @zenithbuild/core
|
|
16
|
+
```
|
|
29
17
|
|
|
30
|
-
|
|
18
|
+
## Running the CLI
|
|
31
19
|
|
|
32
|
-
|
|
33
|
-
import { compile } from '@zenithbuild/core/compiler';
|
|
34
|
-
// ... compile logic
|
|
35
|
-
```
|
|
20
|
+
The `.bin` wrapper is exposed as `zenith`. Running `npx zenith dev` or `npx zenith build` executes the corresponding framework command.
|
|
36
21
|
|
|
37
|
-
##
|
|
22
|
+
## Internal Dependencies
|
|
38
23
|
|
|
39
|
-
|
|
24
|
+
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,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { fileURLToPath, pathToFileURL } 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
|
+
const cwdRequire = createRequire(join(process.cwd(), 'package.json'));
|
|
12
|
+
|
|
13
|
+
function resolveInternal(specifier) {
|
|
14
|
+
try {
|
|
15
|
+
return cwdRequire.resolve(specifier);
|
|
16
|
+
} catch {
|
|
17
|
+
return require.resolve(specifier);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Version mismatch check
|
|
22
|
+
const corePkgPath = join(__dirname, '../package.json');
|
|
23
|
+
const corePkg = JSON.parse(readFileSync(corePkgPath, 'utf-8'));
|
|
24
|
+
const args = process.argv.slice(2);
|
|
25
|
+
|
|
26
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
27
|
+
console.log(`zenith ${corePkg.version}`);
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
32
|
+
const { cli } = await import(pathToFileURL(resolveInternal('@zenithbuild/cli')).href);
|
|
33
|
+
await cli(args);
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const expectedInternals = [
|
|
38
|
+
'@zenithbuild/cli',
|
|
39
|
+
'@zenithbuild/compiler',
|
|
40
|
+
'@zenithbuild/runtime',
|
|
41
|
+
'@zenithbuild/router',
|
|
42
|
+
'@zenithbuild/bundler'
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
let hasMismatch = false;
|
|
46
|
+
|
|
47
|
+
for (const internal of expectedInternals) {
|
|
48
|
+
const expectedVersion = corePkg.dependencies[internal];
|
|
49
|
+
if (!expectedVersion) continue;
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const entryPath = resolveInternal(internal);
|
|
53
|
+
|
|
54
|
+
// Walk up to find the package's package.json
|
|
55
|
+
let currentDir = dirname(entryPath);
|
|
56
|
+
let pkgVersion = null;
|
|
57
|
+
|
|
58
|
+
while (currentDir !== '/' && currentDir !== '.') {
|
|
59
|
+
try {
|
|
60
|
+
const pkgTxt = readFileSync(join(currentDir, 'package.json'), 'utf-8');
|
|
61
|
+
const pkg = JSON.parse(pkgTxt);
|
|
62
|
+
if (pkg.name === internal) {
|
|
63
|
+
pkgVersion = pkg.version;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
} catch (e) {
|
|
67
|
+
// Ignored, continue walking up
|
|
68
|
+
}
|
|
69
|
+
currentDir = dirname(currentDir);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (pkgVersion && pkgVersion !== expectedVersion) {
|
|
73
|
+
console.error(`Version mismatch: ${internal} is version ${pkgVersion} but @zenithbuild/core expects exactly ${expectedVersion}`);
|
|
74
|
+
hasMismatch = true;
|
|
75
|
+
} else if (!pkgVersion) {
|
|
76
|
+
// In a strict mode, failing to find package.json might be treated as a failure.
|
|
77
|
+
}
|
|
78
|
+
} catch (err) {
|
|
79
|
+
console.error(`Version mismatch check failed: Could not resolve internal dependency ${internal}`);
|
|
80
|
+
hasMismatch = true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (hasMismatch) {
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Proceed to hand off execution to the underlying CLI implementation
|
|
89
|
+
import(pathToFileURL(resolveInternal('@zenithbuild/cli')).href);
|
package/package.json
CHANGED
|
@@ -1,72 +1,55 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenithbuild/core",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.6.4",
|
|
4
|
+
"description": "Deterministic utility substrate for the Zenith framework",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"main": "./index.
|
|
7
|
+
"main": "./src/index.js",
|
|
8
8
|
"bin": {
|
|
9
|
-
"zenith": "
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
"
|
|
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
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"router",
|
|
21
|
-
"runtime",
|
|
22
|
-
"dist",
|
|
23
|
-
"index.ts",
|
|
24
|
-
"tsconfig.json"
|
|
27
|
+
"CORE_CONTRACT.md",
|
|
28
|
+
"README.md",
|
|
29
|
+
"contracts"
|
|
25
30
|
],
|
|
26
|
-
"
|
|
27
|
-
"
|
|
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
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"repository": {
|
|
41
|
-
"type": "git",
|
|
42
|
-
"url": "git@github.com:zenithbuild/zenith-core.git"
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@zenithbuild/cli": "0.6.4",
|
|
36
|
+
"@zenithbuild/compiler": "0.6.4",
|
|
37
|
+
"@zenithbuild/runtime": "0.6.4",
|
|
38
|
+
"@zenithbuild/router": "0.6.4",
|
|
39
|
+
"@zenithbuild/bundler": "0.6.4"
|
|
43
40
|
},
|
|
44
41
|
"scripts": {
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
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
|
-
"@
|
|
55
|
-
"
|
|
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
|
-
"
|
|
62
|
-
"@zenithbuild/router": "latest",
|
|
63
|
-
"@types/acorn": "^6.0.4",
|
|
64
|
-
"@types/marked": "^6.0.0",
|
|
65
|
-
"@types/parse5": "^7.0.0",
|
|
66
|
-
"acorn": "^8.15.0",
|
|
67
|
-
"es-module-lexer": "^2.0.0",
|
|
68
|
-
"marked": "^17.0.1",
|
|
69
|
-
"parse5": "^8.0.0",
|
|
70
|
-
"picocolors": "^1.1.1"
|
|
71
|
-
}
|
|
54
|
+
"private": false
|
|
72
55
|
}
|
package/src/config.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
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
|
+
strictDomLints: false
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** Allowed keys and their expected types */
|
|
27
|
+
const SCHEMA = {
|
|
28
|
+
router: 'boolean',
|
|
29
|
+
embeddedMarkupExpressions: 'boolean',
|
|
30
|
+
types: 'boolean',
|
|
31
|
+
typescriptDefault: 'boolean',
|
|
32
|
+
outDir: 'string',
|
|
33
|
+
pagesDir: 'string',
|
|
34
|
+
experimental: 'object',
|
|
35
|
+
strictDomLints: 'boolean'
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Validate a config object against the V0 schema.
|
|
40
|
+
* Throws on unknown keys or wrong types.
|
|
41
|
+
*
|
|
42
|
+
* @param {object} config
|
|
43
|
+
* @returns {object} Normalized config with defaults applied
|
|
44
|
+
*/
|
|
45
|
+
export function validateConfig(config) {
|
|
46
|
+
if (config === null || config === undefined) {
|
|
47
|
+
return { ...DEFAULTS };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (typeof config !== 'object' || Array.isArray(config)) {
|
|
51
|
+
throw new Error('[Zenith:Config] Config must be a plain object');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Check for unknown keys
|
|
55
|
+
for (const key of Object.keys(config)) {
|
|
56
|
+
if (!(key in SCHEMA)) {
|
|
57
|
+
throw new Error(`[Zenith:Config] Unknown key: "${key}"`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Validate types and apply defaults
|
|
62
|
+
const result = { ...DEFAULTS };
|
|
63
|
+
|
|
64
|
+
for (const [key, expectedType] of Object.entries(SCHEMA)) {
|
|
65
|
+
if (key in config) {
|
|
66
|
+
const value = config[key];
|
|
67
|
+
if (typeof value !== expectedType) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`[Zenith:Config] Key "${key}" must be ${expectedType}, got ${typeof value}`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
if (expectedType === 'string' && value.trim() === '') {
|
|
73
|
+
throw new Error(
|
|
74
|
+
`[Zenith:Config] Key "${key}" must be a non-empty string`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
if (key === 'experimental' && value) {
|
|
78
|
+
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
79
|
+
throw new Error(`[Zenith:Config] Key "experimental" must be a plain object`);
|
|
80
|
+
}
|
|
81
|
+
const expDefaults = { ...DEFAULTS.experimental };
|
|
82
|
+
for (const expKey of Object.keys(value)) {
|
|
83
|
+
if (!(expKey in expDefaults)) {
|
|
84
|
+
throw new Error(`[Zenith:Config] Unknown experimental key: "${expKey}"`);
|
|
85
|
+
}
|
|
86
|
+
if (typeof value[expKey] !== typeof expDefaults[expKey]) {
|
|
87
|
+
throw new Error(`[Zenith:Config] Experimental key "${expKey}" must be ${typeof expDefaults[expKey]}`);
|
|
88
|
+
}
|
|
89
|
+
expDefaults[expKey] = value[expKey];
|
|
90
|
+
}
|
|
91
|
+
result[key] = expDefaults;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
result[key] = value;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Load zenith.config.js from a project root.
|
|
103
|
+
* Returns validated config with defaults applied.
|
|
104
|
+
*
|
|
105
|
+
* @param {string} projectRoot
|
|
106
|
+
* @returns {Promise<object>}
|
|
107
|
+
*/
|
|
108
|
+
export async function loadConfig(projectRoot) {
|
|
109
|
+
const configPath = join(projectRoot, 'zenith.config.js');
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const url = pathToFileURL(configPath).href;
|
|
113
|
+
const mod = await import(url);
|
|
114
|
+
const raw = mod.default || mod;
|
|
115
|
+
return validateConfig(raw);
|
|
116
|
+
} catch (err) {
|
|
117
|
+
// File not found — return defaults
|
|
118
|
+
if (
|
|
119
|
+
err.code === 'ERR_MODULE_NOT_FOUND' ||
|
|
120
|
+
err.code === 'ENOENT' ||
|
|
121
|
+
err.message?.includes('Cannot find module') ||
|
|
122
|
+
err.message?.includes('ENOENT')
|
|
123
|
+
) {
|
|
124
|
+
return { ...DEFAULTS };
|
|
125
|
+
}
|
|
126
|
+
throw err;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Return the default config.
|
|
132
|
+
* @returns {object}
|
|
133
|
+
*/
|
|
134
|
+
export function getDefaults() {
|
|
135
|
+
return { ...DEFAULTS };
|
|
136
|
+
}
|
|
@@ -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
|
+
];
|