@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.
Files changed (112) hide show
  1. package/CORE_CONTRACT.md +145 -0
  2. package/README.md +14 -29
  3. package/bin/zenith.js +89 -0
  4. package/package.json +39 -56
  5. package/src/config.js +136 -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 -388
  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 -83
  43. package/compiler/ir/types.ts +0 -174
  44. package/compiler/output/types.ts +0 -34
  45. package/compiler/parse/detectMapExpressions.ts +0 -102
  46. package/compiler/parse/importTypes.ts +0 -78
  47. package/compiler/parse/parseImports.ts +0 -309
  48. package/compiler/parse/parseScript.ts +0 -46
  49. package/compiler/parse/parseTemplate.ts +0 -599
  50. package/compiler/parse/parseZenFile.ts +0 -66
  51. package/compiler/parse/scriptAnalysis.ts +0 -91
  52. package/compiler/parse/trackLoopContext.ts +0 -82
  53. package/compiler/runtime/dataExposure.ts +0 -317
  54. package/compiler/runtime/generateDOM.ts +0 -246
  55. package/compiler/runtime/generateHydrationBundle.ts +0 -407
  56. package/compiler/runtime/hydration.ts +0 -309
  57. package/compiler/runtime/navigation.ts +0 -432
  58. package/compiler/runtime/thinRuntime.ts +0 -160
  59. package/compiler/runtime/transformIR.ts +0 -370
  60. package/compiler/runtime/wrapExpression.ts +0 -95
  61. package/compiler/runtime/wrapExpressionWithLoop.ts +0 -83
  62. package/compiler/spa-build.ts +0 -917
  63. package/compiler/ssg-build.ts +0 -422
  64. package/compiler/test/validate-test.ts +0 -104
  65. package/compiler/transform/classifyExpression.ts +0 -444
  66. package/compiler/transform/componentResolver.ts +0 -312
  67. package/compiler/transform/componentScriptTransformer.ts +0 -303
  68. package/compiler/transform/expressionTransformer.ts +0 -385
  69. package/compiler/transform/fragmentLowering.ts +0 -634
  70. package/compiler/transform/generateBindings.ts +0 -47
  71. package/compiler/transform/generateHTML.ts +0 -28
  72. package/compiler/transform/layoutProcessor.ts +0 -132
  73. package/compiler/transform/slotResolver.ts +0 -292
  74. package/compiler/transform/transformNode.ts +0 -126
  75. package/compiler/transform/transformTemplate.ts +0 -38
  76. package/compiler/validate/invariants.ts +0 -292
  77. package/compiler/validate/validateExpressions.ts +0 -168
  78. package/core/config/index.ts +0 -16
  79. package/core/config/loader.ts +0 -69
  80. package/core/config/types.ts +0 -89
  81. package/core/index.ts +0 -135
  82. package/core/lifecycle/index.ts +0 -49
  83. package/core/lifecycle/zen-mount.ts +0 -182
  84. package/core/lifecycle/zen-unmount.ts +0 -88
  85. package/core/plugins/index.ts +0 -7
  86. package/core/plugins/registry.ts +0 -81
  87. package/core/reactivity/index.ts +0 -54
  88. package/core/reactivity/tracking.ts +0 -167
  89. package/core/reactivity/zen-batch.ts +0 -57
  90. package/core/reactivity/zen-effect.ts +0 -139
  91. package/core/reactivity/zen-memo.ts +0 -146
  92. package/core/reactivity/zen-ref.ts +0 -52
  93. package/core/reactivity/zen-signal.ts +0 -121
  94. package/core/reactivity/zen-state.ts +0 -180
  95. package/core/reactivity/zen-untrack.ts +0 -44
  96. package/dist/cli.js +0 -11665
  97. package/dist/zen-build.js +0 -21172
  98. package/dist/zen-dev.js +0 -21172
  99. package/dist/zen-preview.js +0 -21172
  100. package/dist/zenith.js +0 -21172
  101. package/router/index.ts +0 -28
  102. package/router/manifest.ts +0 -314
  103. package/router/navigation/ZenLink.zen +0 -231
  104. package/router/navigation/index.ts +0 -78
  105. package/router/navigation/zen-link.ts +0 -584
  106. package/router/runtime.ts +0 -458
  107. package/router/types.ts +0 -168
  108. package/runtime/build.ts +0 -17
  109. package/runtime/bundle-generator.ts +0 -1247
  110. package/runtime/client-runtime.ts +0 -549
  111. package/runtime/serve.ts +0 -93
  112. package/tsconfig.json +0 -28
package/src/hash.js ADDED
@@ -0,0 +1,52 @@
1
+ // ---------------------------------------------------------------------------
2
+ // hash.js — Zenith Core V0
3
+ // ---------------------------------------------------------------------------
4
+ // Deterministic content hashing. SHA-256, hex output.
5
+ //
6
+ // CRITICAL: This algorithm must match the bundler's hashing exactly.
7
+ // If bundler changes hash algorithm, core must change in lockstep.
8
+ //
9
+ // Input normalization:
10
+ // - Path separators → /
11
+ // - Trailing newlines stripped
12
+ // ---------------------------------------------------------------------------
13
+
14
+ import { createHash } from 'node:crypto';
15
+
16
+ /**
17
+ * Hash a string using SHA-256. Returns hex digest.
18
+ *
19
+ * @param {string} content
20
+ * @returns {string}
21
+ */
22
+ export function hash(content) {
23
+ const normalized = _normalizeInput(content);
24
+ return createHash('sha256').update(normalized).digest('hex');
25
+ }
26
+
27
+ /**
28
+ * Hash a string and return a truncated hash (first N characters).
29
+ * Useful for content-hashed filenames.
30
+ *
31
+ * @param {string} content
32
+ * @param {number} [length=8]
33
+ * @returns {string}
34
+ */
35
+ export function hashShort(content, length = 8) {
36
+ return hash(content).slice(0, length);
37
+ }
38
+
39
+ /**
40
+ * Normalize input for deterministic hashing.
41
+ * - Replaces backslashes with forward slashes
42
+ * - Strips trailing newlines
43
+ *
44
+ * @param {string} content
45
+ * @returns {string}
46
+ */
47
+ function _normalizeInput(content) {
48
+ let result = content.replace(/\\/g, '/');
49
+ // Strip trailing newlines
50
+ result = result.replace(/\n+$/, '');
51
+ return result;
52
+ }
package/src/index.js ADDED
@@ -0,0 +1,26 @@
1
+ // ---------------------------------------------------------------------------
2
+ // index.js — Zenith Core V0
3
+ // ---------------------------------------------------------------------------
4
+ // Public API. Re-exports frozen module namespaces only.
5
+ // ---------------------------------------------------------------------------
6
+
7
+ export { validateConfig, loadConfig, getDefaults } from './config.js';
8
+ export {
9
+ normalizeSeparators,
10
+ fileToRoute,
11
+ extractParams,
12
+ isDynamic,
13
+ validateRouteParams,
14
+ canonicalize
15
+ } from './path.js';
16
+ export { sortRoutes, sortAlpha, isCorrectOrder } from './order.js';
17
+ export { hash, hashShort } from './hash.js';
18
+ export { createError, formatError, isZenithError, ErrorCodes } from './errors.js';
19
+ export { parseSemver, formatVersion, validateCompatibility } from './version.js';
20
+ export { IR_VERSION, IR_SCHEMA } from './schema.js';
21
+ export { coreModuleSource } from './core-template.js';
22
+ export {
23
+ containsForbiddenPattern,
24
+ FORBIDDEN_PATTERNS,
25
+ BROWSER_GLOBALS
26
+ } from './guards.js';
@@ -0,0 +1 @@
1
+ export { IR_VERSION, IR_SCHEMA } from '../schema.js';
package/src/order.js ADDED
@@ -0,0 +1,69 @@
1
+ // ---------------------------------------------------------------------------
2
+ // order.js — Zenith Core V0
3
+ // ---------------------------------------------------------------------------
4
+ // Deterministic ordering utilities. Pure transforms.
5
+ //
6
+ // Sorting contract:
7
+ // 1. Static routes first, dynamic routes second
8
+ // 2. Alphabetical tiebreak within each group
9
+ // 3. Stable across runs
10
+ // ---------------------------------------------------------------------------
11
+
12
+ /**
13
+ * Check if a route path contains dynamic segments (starts with :).
14
+ *
15
+ * @param {string} routePath
16
+ * @returns {boolean}
17
+ */
18
+ function _isDynamic(routePath) {
19
+ return routePath.includes(':');
20
+ }
21
+
22
+ /**
23
+ * Sort route entries deterministically.
24
+ *
25
+ * Rules:
26
+ * 1. Static routes before dynamic routes
27
+ * 2. Alphabetical (lexicographic) within each group
28
+ *
29
+ * Entries must have a `path` property.
30
+ *
31
+ * @param {{ path: string }[]} entries
32
+ * @returns {{ path: string }[]}
33
+ */
34
+ export function sortRoutes(entries) {
35
+ return [...entries].sort((a, b) => {
36
+ const aDynamic = _isDynamic(a.path);
37
+ const bDynamic = _isDynamic(b.path);
38
+
39
+ // Static before dynamic
40
+ if (!aDynamic && bDynamic) return -1;
41
+ if (aDynamic && !bDynamic) return 1;
42
+
43
+ // Alphabetical tiebreak
44
+ return a.path.localeCompare(b.path);
45
+ });
46
+ }
47
+
48
+ /**
49
+ * Sort an array of strings deterministically.
50
+ * Simple alphabetical sort with stable ordering.
51
+ *
52
+ * @param {string[]} items
53
+ * @returns {string[]}
54
+ */
55
+ export function sortAlpha(items) {
56
+ return [...items].sort((a, b) => a.localeCompare(b));
57
+ }
58
+
59
+ /**
60
+ * Check if an array of route entries is in correct deterministic order.
61
+ * Does not throw — returns boolean.
62
+ *
63
+ * @param {{ path: string }[]} entries
64
+ * @returns {boolean}
65
+ */
66
+ export function isCorrectOrder(entries) {
67
+ const sorted = sortRoutes(entries);
68
+ return entries.every((entry, i) => entry.path === sorted[i].path);
69
+ }
package/src/path.js ADDED
@@ -0,0 +1,131 @@
1
+ // ---------------------------------------------------------------------------
2
+ // path.js — Zenith Core V0
3
+ // ---------------------------------------------------------------------------
4
+ // Path normalization utilities. Pure transforms — no filesystem access.
5
+ //
6
+ // - Normalizes separators (\ → /)
7
+ // - Converts [param] → :param
8
+ // - Extracts params from route strings
9
+ // - Validates no repeated param names
10
+ // - Strips file extensions
11
+ // ---------------------------------------------------------------------------
12
+
13
+ /**
14
+ * Normalize path separators to forward slashes.
15
+ *
16
+ * @param {string} filePath
17
+ * @returns {string}
18
+ */
19
+ export function normalizeSeparators(filePath) {
20
+ return filePath.replace(/\\/g, '/');
21
+ }
22
+
23
+ /**
24
+ * Convert a file-system path to a route path.
25
+ *
26
+ * Rules:
27
+ * - Normalize separators
28
+ * - Strip the extension
29
+ * - Convert [param] → :param
30
+ * - index files → parent path
31
+ * - Ensure leading /
32
+ *
33
+ * @param {string} filePath Relative path from pages dir (e.g. "users/[id].zen")
34
+ * @param {string} [extension='.zen']
35
+ * @returns {string}
36
+ */
37
+ export function fileToRoute(filePath, extension = '.zen') {
38
+ let route = normalizeSeparators(filePath);
39
+
40
+ // Strip extension
41
+ if (route.endsWith(extension)) {
42
+ route = route.slice(0, -extension.length);
43
+ }
44
+
45
+ // Convert [param] → :param
46
+ route = route.replace(/\[([^\]]+)\]/g, ':$1');
47
+
48
+ // Handle index → parent
49
+ if (route === 'index') {
50
+ return '/';
51
+ }
52
+ if (route.endsWith('/index')) {
53
+ route = route.slice(0, -'/index'.length);
54
+ }
55
+
56
+ // Ensure leading /
57
+ if (!route.startsWith('/')) {
58
+ route = '/' + route;
59
+ }
60
+
61
+ return route;
62
+ }
63
+
64
+ /**
65
+ * Extract parameter names from a route path.
66
+ *
67
+ * @param {string} routePath e.g. "/users/:id/posts/:postId"
68
+ * @returns {string[]} e.g. ["id", "postId"]
69
+ */
70
+ export function extractParams(routePath) {
71
+ const params = [];
72
+ const segments = routePath.split('/');
73
+ for (const segment of segments) {
74
+ if (segment.startsWith(':')) {
75
+ params.push(segment.slice(1));
76
+ }
77
+ }
78
+ return params;
79
+ }
80
+
81
+ /**
82
+ * Check if a route path contains dynamic segments.
83
+ *
84
+ * @param {string} routePath
85
+ * @returns {boolean}
86
+ */
87
+ export function isDynamic(routePath) {
88
+ return routePath.includes(':');
89
+ }
90
+
91
+ /**
92
+ * Validate that a route path has no repeated parameter names.
93
+ * Throws on violation.
94
+ *
95
+ * @param {string} routePath
96
+ */
97
+ export function validateRouteParams(routePath) {
98
+ const params = extractParams(routePath);
99
+ const seen = new Set();
100
+ for (const param of params) {
101
+ if (seen.has(param)) {
102
+ throw new Error(
103
+ `[Zenith:Path] Repeated parameter name ":${param}" in route "${routePath}"`
104
+ );
105
+ }
106
+ seen.add(param);
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Canonicalize a route path.
112
+ * Strips trailing slashes (except root), normalizes separators.
113
+ *
114
+ * @param {string} routePath
115
+ * @returns {string}
116
+ */
117
+ export function canonicalize(routePath) {
118
+ let path = normalizeSeparators(routePath);
119
+
120
+ // Remove trailing slash (unless root)
121
+ if (path.length > 1 && path.endsWith('/')) {
122
+ path = path.slice(0, -1);
123
+ }
124
+
125
+ // Ensure leading slash
126
+ if (!path.startsWith('/')) {
127
+ path = '/' + path;
128
+ }
129
+
130
+ return path;
131
+ }
package/src/schema.js ADDED
@@ -0,0 +1,28 @@
1
+ // ---------------------------------------------------------------------------
2
+ // schema.js — Zenith Core IR authority
3
+ // ---------------------------------------------------------------------------
4
+
5
+ export const IR_VERSION = 1;
6
+
7
+ export const IR_SCHEMA = Object.freeze({
8
+ version: IR_VERSION,
9
+ requiredTopLevelKeys: Object.freeze([
10
+ 'ir_version',
11
+ 'graph_hash',
12
+ 'graph_edges',
13
+ 'graph_nodes',
14
+ 'html',
15
+ 'expressions',
16
+ 'hoisted',
17
+ 'components_scripts',
18
+ 'component_instances',
19
+ 'imports',
20
+ 'modules',
21
+ 'prerender',
22
+ 'signals',
23
+ 'expression_bindings',
24
+ 'marker_bindings',
25
+ 'event_bindings',
26
+ 'style_blocks'
27
+ ])
28
+ });
package/src/version.js ADDED
@@ -0,0 +1,67 @@
1
+ // ---------------------------------------------------------------------------
2
+ // version.js — Zenith Core V0
3
+ // ---------------------------------------------------------------------------
4
+ // SemVer parsing and compatibility validation.
5
+ //
6
+ // Direction of control: Other layers call core's version utility.
7
+ // Core never imports other packages to auto-check.
8
+ // ---------------------------------------------------------------------------
9
+
10
+ /**
11
+ * Parse a SemVer string into components.
12
+ *
13
+ * @param {string} version e.g. "1.2.3"
14
+ * @returns {{ major: number, minor: number, patch: number }}
15
+ */
16
+ export function parseSemver(version) {
17
+ const cleaned = version.replace(/^v/, '');
18
+ const match = cleaned.match(/^(\d+)\.(\d+)\.(\d+)/);
19
+ if (!match) {
20
+ throw new Error(`[Zenith:Version] Invalid semver: "${version}"`);
21
+ }
22
+ return {
23
+ major: parseInt(match[1], 10),
24
+ minor: parseInt(match[2], 10),
25
+ patch: parseInt(match[3], 10)
26
+ };
27
+ }
28
+
29
+ /**
30
+ * Format a version object back to a string.
31
+ *
32
+ * @param {{ major: number, minor: number, patch: number }} ver
33
+ * @returns {string}
34
+ */
35
+ export function formatVersion(ver) {
36
+ return `${ver.major}.${ver.minor}.${ver.patch}`;
37
+ }
38
+
39
+ /**
40
+ * Validate compatibility between two versions.
41
+ *
42
+ * Rules:
43
+ * - Major versions must match (throws if different)
44
+ * - Minor version difference > 1 produces a warning (returns warning string)
45
+ * - Otherwise returns null (compatible)
46
+ *
47
+ * @param {string} coreVersion
48
+ * @param {string} otherVersion
49
+ * @returns {string|null} Warning message or null if fully compatible
50
+ */
51
+ export function validateCompatibility(coreVersion, otherVersion) {
52
+ const core = parseSemver(coreVersion);
53
+ const other = parseSemver(otherVersion);
54
+
55
+ if (core.major !== other.major) {
56
+ throw new Error(
57
+ `[Zenith:Version] Incompatible major versions: core=${formatVersion(core)}, other=${formatVersion(other)}`
58
+ );
59
+ }
60
+
61
+ const minorDiff = Math.abs(core.minor - other.minor);
62
+ if (minorDiff > 1) {
63
+ return `[Zenith:Version] Minor version drift: core=${formatVersion(core)}, other=${formatVersion(other)} (diff=${minorDiff})`;
64
+ }
65
+
66
+ return null;
67
+ }
package/bin/zen-build.ts DELETED
@@ -1,2 +0,0 @@
1
- import { runCLI } from '../cli/main'
2
- runCLI({ defaultCommand: 'build' })
package/bin/zen-dev.ts DELETED
@@ -1,2 +0,0 @@
1
- import { runCLI } from '../cli/main'
2
- runCLI({ defaultCommand: 'dev' })
@@ -1,2 +0,0 @@
1
- import { runCLI } from '../cli/main'
2
- runCLI({ defaultCommand: 'preview' })
package/bin/zenith.ts DELETED
@@ -1,2 +0,0 @@
1
- import { runCLI } from '../cli/main'
2
- runCLI()
@@ -1,37 +0,0 @@
1
- /**
2
- * @zenith/cli - Add Command
3
- *
4
- * Registers a plugin in the project
5
- */
6
-
7
- import { requireProject } from '../utils/project'
8
- import { addPlugin, hasPlugin } from '../utils/plugin-manager'
9
- import * as logger from '../utils/logger'
10
-
11
- export interface AddOptions {
12
- options?: Record<string, unknown>
13
- }
14
-
15
- export async function add(pluginName: string, options: AddOptions = {}): Promise<void> {
16
- requireProject()
17
-
18
- logger.header('Add Plugin')
19
-
20
- if (!pluginName) {
21
- logger.error('Plugin name required. Usage: zenith add <plugin>')
22
- process.exit(1)
23
- }
24
-
25
- if (hasPlugin(pluginName)) {
26
- logger.warn(`Plugin "${pluginName}" is already registered`)
27
- return
28
- }
29
-
30
- const success = addPlugin(pluginName, options.options)
31
-
32
- if (success) {
33
- logger.info(`Plugin "${pluginName}" has been registered.`)
34
- logger.info('Note: You may need to install the package manually:')
35
- logger.log(` bun add @zenith/plugin-${pluginName}`)
36
- }
37
- }
@@ -1,37 +0,0 @@
1
- /**
2
- * @zenith/cli - Build Command
3
- *
4
- * Builds the application for production using SSG.
5
- */
6
-
7
- import path from 'path'
8
- import { requireProject } from '../utils/project'
9
- import * as logger from '../utils/logger'
10
- import { buildSSG } from '../../compiler/ssg-build'
11
-
12
- export interface BuildOptions {
13
- outDir?: string
14
- }
15
-
16
- export async function build(options: BuildOptions = {}): Promise<void> {
17
- const project = requireProject()
18
- const outDir = options.outDir || project.distDir
19
-
20
- logger.header('Zenith Build')
21
- logger.log(`Source: ${project.pagesDir}`)
22
- logger.log(`Output: ${outDir}`)
23
-
24
- try {
25
- buildSSG({
26
- pagesDir: project.pagesDir,
27
- outDir: outDir,
28
- baseDir: project.root
29
- })
30
- logger.success('Build complete!')
31
-
32
- } catch (err: unknown) {
33
- const message = err instanceof Error ? err.message : String(err)
34
- logger.error(`Build failed: ${message}`)
35
- process.exit(1)
36
- }
37
- }