@zenithbuild/core 0.6.1 → 0.6.2

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.
@@ -18,7 +18,7 @@ import {
18
18
  discoverPages,
19
19
  generateRouteDefinition,
20
20
  routePathToRegex
21
- } from "../router/manifest"
21
+ } from "@zenithbuild/router/manifest"
22
22
 
23
23
  interface CompiledPage {
24
24
  routePath: string
@@ -16,7 +16,7 @@ import path from "path"
16
16
  import { compileZenSource } from "./index"
17
17
  import { discoverLayouts } from "./discovery/layouts"
18
18
  import { processLayout } from "./transform/layoutProcessor"
19
- import { discoverPages, generateRouteDefinition } from "../router/manifest"
19
+ import { discoverPages, generateRouteDefinition } from "@zenithbuild/router/manifest"
20
20
  import { analyzePageSource, getAnalysisSummary, getBuildOutputType, type PageAnalysis } from "./build-analyzer"
21
21
  import { generateBundleJS } from "../runtime/bundle-generator"
22
22
  import { loadContent } from "../cli/utils/content"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenithbuild/core",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "Core library for the Zenith framework",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -59,6 +59,7 @@
59
59
  "typescript": "^5"
60
60
  },
61
61
  "dependencies": {
62
+ "@zenithbuild/router": "latest",
62
63
  "@types/acorn": "^6.0.4",
63
64
  "@types/marked": "^6.0.0",
64
65
  "@types/parse5": "^7.0.0",
package/router/index.ts CHANGED
@@ -1,8 +1,12 @@
1
1
  /**
2
2
  * Zenith Router
3
3
  *
4
- * File-based SPA router for Zenith framework.
5
- * Includes routing, navigation, and ZenLink components.
4
+ * This module re-exports from @zenithbuild/router package.
5
+ *
6
+ * The router has been extracted to its own package for:
7
+ * - Independent versioning
8
+ * - Better separation of concerns
9
+ * - Easier maintenance
6
10
  *
7
11
  * @example
8
12
  * ```ts
@@ -16,61 +20,9 @@
16
20
  * console.log('On blog section')
17
21
  * }
18
22
  * ```
23
+ *
24
+ * @deprecated Import directly from '@zenithbuild/router' for new projects
19
25
  */
20
26
 
21
- // Core router types and utilities
22
- export * from "./types"
23
- export * from "./manifest"
24
-
25
- // Router runtime (core router implementation)
26
- // These are the primary exports for router functionality
27
- export {
28
- initRouter,
29
- resolveRoute,
30
- navigate,
31
- getRoute,
32
- onRouteChange,
33
- beforeEach,
34
- afterEach,
35
- isActive,
36
- prefetch,
37
- isPrefetched
38
- } from "./runtime"
39
-
40
- // Navigation utilities (additional helpers and zen* prefixed exports)
41
- // Note: Some functions like navigate, isActive, prefetch are also in runtime
42
- // We export runtime's versions above, and navigation's unique functions here
43
- export {
44
- // Navigation API (zen* prefixed names)
45
- zenNavigate,
46
- zenBack,
47
- zenForward,
48
- zenGo,
49
- zenIsActive,
50
- zenPrefetch,
51
- zenIsPrefetched,
52
- zenGetRoute,
53
- zenGetParam,
54
- zenGetQuery,
55
- createZenLink,
56
- zenLink,
57
- // Additional navigation utilities (not in runtime)
58
- back,
59
- forward,
60
- go,
61
- getParam,
62
- getQuery,
63
- isExternalUrl,
64
- shouldUseSPANavigation,
65
- normalizePath,
66
- setGlobalTransition,
67
- getGlobalTransition,
68
- createTransitionContext
69
- } from "./navigation/index"
70
-
71
- // Navigation-specific types
72
- export type {
73
- ZenLinkProps,
74
- TransitionContext,
75
- TransitionHandler
76
- } from "./navigation/index"
27
+ // Re-export everything from @zenithbuild/router
28
+ export * from "@zenithbuild/router"
@@ -876,6 +876,310 @@ export function generateBundleJS(): string {
876
876
  global.processRawSections = processRawSections;
877
877
  global.slugify = slugify;
878
878
 
879
+ // ============================================
880
+ // SPA Router Runtime
881
+ // ============================================
882
+
883
+ (function() {
884
+ 'use strict';
885
+
886
+ // Current route state
887
+ var currentRoute = {
888
+ path: '/',
889
+ params: {},
890
+ query: {}
891
+ };
892
+
893
+ // Route listeners
894
+ var routeListeners = new Set();
895
+
896
+ // Router outlet element
897
+ var routerOutlet = null;
898
+
899
+ // Page modules registry
900
+ var pageModules = {};
901
+
902
+ // Route manifest
903
+ var routeManifest = [];
904
+
905
+ /**
906
+ * Parse query string
907
+ */
908
+ function parseQueryString(search) {
909
+ var query = {};
910
+ if (!search || search === '?') return query;
911
+ var params = new URLSearchParams(search);
912
+ params.forEach(function(value, key) { query[key] = value; });
913
+ return query;
914
+ }
915
+
916
+ /**
917
+ * Resolve route from pathname
918
+ */
919
+ function resolveRoute(pathname) {
920
+ var normalizedPath = pathname === '' ? '/' : pathname;
921
+
922
+ for (var i = 0; i < routeManifest.length; i++) {
923
+ var route = routeManifest[i];
924
+ var match = route.regex.exec(normalizedPath);
925
+ if (match) {
926
+ var params = {};
927
+ for (var j = 0; j < route.paramNames.length; j++) {
928
+ var paramValue = match[j + 1];
929
+ if (paramValue !== undefined) {
930
+ params[route.paramNames[j]] = decodeURIComponent(paramValue);
931
+ }
932
+ }
933
+ return { record: route, params: params };
934
+ }
935
+ }
936
+ return null;
937
+ }
938
+
939
+ /**
940
+ * Clean up previous page
941
+ */
942
+ function cleanupPreviousPage() {
943
+ // Trigger unmount lifecycle hooks
944
+ if (global.__zenith && global.__zenith.triggerUnmount) {
945
+ global.__zenith.triggerUnmount();
946
+ }
947
+
948
+ // Remove previous page styles
949
+ var prevStyles = document.querySelectorAll('style[data-zen-page-style]');
950
+ prevStyles.forEach(function(s) { s.remove(); });
951
+
952
+ // Clean up window properties
953
+ if (global.__zenith_cleanup) {
954
+ global.__zenith_cleanup.forEach(function(key) {
955
+ try { delete global[key]; } catch(e) {}
956
+ });
957
+ }
958
+ global.__zenith_cleanup = [];
959
+ }
960
+
961
+ /**
962
+ * Inject styles
963
+ */
964
+ function injectStyles(styles) {
965
+ styles.forEach(function(content, i) {
966
+ var style = document.createElement('style');
967
+ style.setAttribute('data-zen-page-style', String(i));
968
+ style.textContent = content;
969
+ document.head.appendChild(style);
970
+ });
971
+ }
972
+
973
+ /**
974
+ * Execute scripts
975
+ */
976
+ function executeScripts(scripts) {
977
+ scripts.forEach(function(content) {
978
+ try {
979
+ var fn = new Function(content);
980
+ fn();
981
+ } catch (e) {
982
+ console.error('[Zenith Router] Script error:', e);
983
+ }
984
+ });
985
+ }
986
+
987
+ /**
988
+ * Render page
989
+ */
990
+ function renderPage(pageModule) {
991
+ if (!routerOutlet) {
992
+ console.warn('[Zenith Router] No router outlet');
993
+ return;
994
+ }
995
+
996
+ cleanupPreviousPage();
997
+ routerOutlet.innerHTML = pageModule.html;
998
+ injectStyles(pageModule.styles);
999
+ executeScripts(pageModule.scripts);
1000
+
1001
+ // Trigger mount lifecycle hooks after scripts are executed
1002
+ if (global.__zenith && global.__zenith.triggerMount) {
1003
+ global.__zenith.triggerMount();
1004
+ }
1005
+ }
1006
+
1007
+ /**
1008
+ * Notify listeners
1009
+ */
1010
+ function notifyListeners(route, prevRoute) {
1011
+ routeListeners.forEach(function(listener) {
1012
+ try { listener(route, prevRoute); } catch(e) {}
1013
+ });
1014
+ }
1015
+
1016
+ /**
1017
+ * Resolve and render
1018
+ */
1019
+ function resolveAndRender(path, query, updateHistory, replace) {
1020
+ replace = replace || false;
1021
+ var prevRoute = Object.assign({}, currentRoute);
1022
+ var resolved = resolveRoute(path);
1023
+
1024
+ if (resolved) {
1025
+ currentRoute = {
1026
+ path: path,
1027
+ params: resolved.params,
1028
+ query: query,
1029
+ matched: resolved.record
1030
+ };
1031
+
1032
+ var pageModule = pageModules[resolved.record.path];
1033
+ if (pageModule) {
1034
+ renderPage(pageModule);
1035
+ }
1036
+ } else {
1037
+ currentRoute = { path: path, params: {}, query: query, matched: undefined };
1038
+ console.warn('[Zenith Router] No route matched:', path);
1039
+
1040
+ // Render 404 if available
1041
+ if (routerOutlet) {
1042
+ routerOutlet.innerHTML = '<div style="padding: 2rem; text-align: center;"><h1>404</h1><p>Page not found</p></div>';
1043
+ }
1044
+ }
1045
+
1046
+ if (updateHistory) {
1047
+ var url = path + (Object.keys(query).length ? '?' + new URLSearchParams(query) : '');
1048
+ if (replace) {
1049
+ history.replaceState(null, '', url);
1050
+ } else {
1051
+ history.pushState(null, '', url);
1052
+ }
1053
+ }
1054
+
1055
+ notifyListeners(currentRoute, prevRoute);
1056
+ global.__zenith_route = currentRoute;
1057
+ }
1058
+
1059
+ /**
1060
+ * Handle popstate
1061
+ */
1062
+ function handlePopState() {
1063
+ resolveAndRender(
1064
+ location.pathname,
1065
+ parseQueryString(location.search),
1066
+ false,
1067
+ false
1068
+ );
1069
+ }
1070
+
1071
+ /**
1072
+ * Navigate (public API)
1073
+ */
1074
+ function navigate(to, options) {
1075
+ options = options || {};
1076
+ var path, query = {};
1077
+
1078
+ if (to.includes('?')) {
1079
+ var parts = to.split('?');
1080
+ path = parts[0];
1081
+ query = parseQueryString('?' + parts[1]);
1082
+ } else {
1083
+ path = to;
1084
+ }
1085
+
1086
+ if (!path.startsWith('/')) {
1087
+ var currentDir = currentRoute.path.split('/').slice(0, -1).join('/');
1088
+ path = currentDir + '/' + path;
1089
+ }
1090
+
1091
+ var normalizedPath = path === '' ? '/' : path;
1092
+ var currentPath = currentRoute.path === '' ? '/' : currentRoute.path;
1093
+ var isSamePath = normalizedPath === currentPath;
1094
+
1095
+ if (isSamePath && JSON.stringify(query) === JSON.stringify(currentRoute.query)) {
1096
+ return;
1097
+ }
1098
+
1099
+ resolveAndRender(path, query, true, options.replace || false);
1100
+ }
1101
+
1102
+ /**
1103
+ * Get current route
1104
+ */
1105
+ function getRoute() {
1106
+ return Object.assign({}, currentRoute);
1107
+ }
1108
+
1109
+ /**
1110
+ * Subscribe to route changes
1111
+ */
1112
+ function onRouteChange(listener) {
1113
+ routeListeners.add(listener);
1114
+ return function() { routeListeners.delete(listener); };
1115
+ }
1116
+
1117
+ /**
1118
+ * Check if path is active
1119
+ */
1120
+ function isActive(path, exact) {
1121
+ if (exact) return currentRoute.path === path;
1122
+ return currentRoute.path.startsWith(path);
1123
+ }
1124
+
1125
+ /**
1126
+ * Prefetch a route
1127
+ */
1128
+ var prefetchedRoutes = new Set();
1129
+ function prefetch(path) {
1130
+ var normalizedPath = path === '' ? '/' : path;
1131
+
1132
+ if (prefetchedRoutes.has(normalizedPath)) {
1133
+ return Promise.resolve();
1134
+ }
1135
+ prefetchedRoutes.add(normalizedPath);
1136
+
1137
+ var resolved = resolveRoute(normalizedPath);
1138
+ if (!resolved) {
1139
+ return Promise.resolve();
1140
+ }
1141
+
1142
+ // In SPA build, all modules are already loaded
1143
+ return Promise.resolve();
1144
+ }
1145
+
1146
+ /**
1147
+ * Initialize router
1148
+ */
1149
+ function initRouter(manifest, modules, outlet) {
1150
+ routeManifest = manifest;
1151
+ Object.assign(pageModules, modules);
1152
+
1153
+ if (outlet) {
1154
+ routerOutlet = typeof outlet === 'string'
1155
+ ? document.querySelector(outlet)
1156
+ : outlet;
1157
+ }
1158
+
1159
+ window.addEventListener('popstate', handlePopState);
1160
+
1161
+ // Initial route resolution
1162
+ resolveAndRender(
1163
+ location.pathname,
1164
+ parseQueryString(location.search),
1165
+ false
1166
+ );
1167
+ }
1168
+
1169
+ // Expose router API globally
1170
+ global.__zenith_router = {
1171
+ navigate: navigate,
1172
+ getRoute: getRoute,
1173
+ onRouteChange: onRouteChange,
1174
+ isActive: isActive,
1175
+ prefetch: prefetch,
1176
+ initRouter: initRouter
1177
+ };
1178
+
1179
+ // Also expose navigate directly for convenience
1180
+ global.navigate = navigate;
1181
+ })();
1182
+
879
1183
  // ============================================
880
1184
  // HMR Client (Development Only)
881
1185
  // ============================================