juxscript 1.0.132 → 1.1.0

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 (129) hide show
  1. package/README.md +1 -32
  2. package/bin/cli.js +4 -2
  3. package/index.d.ts +200 -0
  4. package/index.js +96 -22
  5. package/juxconfig.example.js +58 -63
  6. package/lib/components/alert.ts +200 -0
  7. package/lib/components/app.ts +247 -0
  8. package/lib/components/badge.ts +101 -0
  9. package/lib/components/base/BaseComponent.ts +421 -0
  10. package/lib/components/base/FormInput.ts +227 -0
  11. package/lib/components/button.ts +178 -0
  12. package/lib/components/card.ts +173 -0
  13. package/lib/components/chart.ts +231 -0
  14. package/lib/components/checkbox.ts +242 -0
  15. package/lib/components/code.ts +123 -0
  16. package/lib/components/container.ts +140 -0
  17. package/lib/components/data.ts +135 -0
  18. package/lib/components/datepicker.ts +234 -0
  19. package/lib/components/dialog.ts +172 -0
  20. package/lib/components/divider.ts +100 -0
  21. package/lib/components/dropdown.ts +186 -0
  22. package/lib/components/element.ts +267 -0
  23. package/lib/components/fileupload.ts +309 -0
  24. package/lib/components/grid.ts +291 -0
  25. package/lib/components/guard.ts +92 -0
  26. package/lib/components/heading.ts +96 -0
  27. package/lib/components/helpers.ts +41 -0
  28. package/lib/components/hero.ts +224 -0
  29. package/lib/components/icon.ts +178 -0
  30. package/lib/components/icons.ts +464 -0
  31. package/lib/components/include.ts +410 -0
  32. package/lib/components/input.ts +457 -0
  33. package/lib/components/list.ts +419 -0
  34. package/lib/components/loading.ts +100 -0
  35. package/lib/components/menu.ts +275 -0
  36. package/lib/components/modal.ts +284 -0
  37. package/lib/components/nav.ts +257 -0
  38. package/lib/components/paragraph.ts +97 -0
  39. package/lib/components/progress.ts +159 -0
  40. package/lib/components/radio.ts +278 -0
  41. package/lib/components/req.ts +303 -0
  42. package/lib/components/script.ts +41 -0
  43. package/lib/components/select.ts +252 -0
  44. package/lib/components/sidebar.ts +275 -0
  45. package/lib/components/style.ts +41 -0
  46. package/lib/components/switch.ts +246 -0
  47. package/lib/components/table.ts +1249 -0
  48. package/lib/components/tabs.ts +250 -0
  49. package/lib/components/theme-toggle.ts +293 -0
  50. package/lib/components/tooltip.ts +144 -0
  51. package/lib/components/view.ts +190 -0
  52. package/lib/components/write.ts +272 -0
  53. package/lib/globals.d.ts +19 -5
  54. package/lib/layouts/default.css +260 -0
  55. package/lib/layouts/figma.css +334 -0
  56. package/lib/reactivity/state.ts +78 -0
  57. package/lib/utils/{fetch.js → fetch.ts} +206 -81
  58. package/package.json +9 -31
  59. package/create/index.jux +0 -77
  60. package/create/layout.jux +0 -18
  61. package/create/style.css +0 -57
  62. package/create/themes/assets/jux.svg +0 -34
  63. package/create/themes/base.css +0 -197
  64. package/create/themes/base2.css +0 -54
  65. package/create/themes/layouts/base.jux +0 -16
  66. package/create/themes/layouts/base_blog.jux +0 -0
  67. package/create/themes/layouts/base_docs.jux +0 -0
  68. package/create/themes/layouts/base_login.jux +0 -0
  69. package/create/themes/layouts/base_marketing.jux +0 -0
  70. package/create/themes/layouts/base_saas.jux +0 -0
  71. package/lib/componentsv2/base/BaseEngine.d.ts +0 -112
  72. package/lib/componentsv2/base/BaseEngine.js +0 -279
  73. package/lib/componentsv2/base/BaseSkin.d.ts +0 -74
  74. package/lib/componentsv2/base/BaseSkin.js +0 -130
  75. package/lib/componentsv2/base/Neighborhood.d.ts +0 -22
  76. package/lib/componentsv2/base/Neighborhood.js +0 -56
  77. package/lib/componentsv2/base/OptionsContract.d.ts +0 -20
  78. package/lib/componentsv2/base/OptionsContract.js +0 -107
  79. package/lib/componentsv2/base/State.d.ts +0 -18
  80. package/lib/componentsv2/base/State.js +0 -68
  81. package/lib/componentsv2/element/Element.d.ts +0 -30
  82. package/lib/componentsv2/element/Element.js +0 -50
  83. package/lib/componentsv2/element/ElementEngine.d.ts +0 -59
  84. package/lib/componentsv2/element/ElementEngine.js +0 -118
  85. package/lib/componentsv2/element/ElementSkin.d.ts +0 -10
  86. package/lib/componentsv2/element/ElementSkin.js +0 -56
  87. package/lib/componentsv2/element/structure.css +0 -261
  88. package/lib/componentsv2/grid/Grid.d.ts +0 -13
  89. package/lib/componentsv2/grid/Grid.js +0 -27
  90. package/lib/componentsv2/grid/GridEngine.d.ts +0 -77
  91. package/lib/componentsv2/grid/GridEngine.js +0 -153
  92. package/lib/componentsv2/grid/GridSkin.d.ts +0 -11
  93. package/lib/componentsv2/grid/GridSkin.js +0 -84
  94. package/lib/componentsv2/grid/structure.css +0 -27
  95. package/lib/componentsv2/input/Input.d.ts +0 -6
  96. package/lib/componentsv2/input/Input.js +0 -21
  97. package/lib/componentsv2/input/InputEngine.d.ts +0 -70
  98. package/lib/componentsv2/input/InputEngine.js +0 -143
  99. package/lib/componentsv2/input/InputSkin.d.ts +0 -11
  100. package/lib/componentsv2/input/InputSkin.js +0 -89
  101. package/lib/componentsv2/input/structure.css +0 -47
  102. package/lib/componentsv2/list/List.d.ts +0 -49
  103. package/lib/componentsv2/list/List.js +0 -105
  104. package/lib/componentsv2/list/ListEngine.d.ts +0 -121
  105. package/lib/componentsv2/list/ListEngine.js +0 -322
  106. package/lib/componentsv2/list/ListSkin.d.ts +0 -20
  107. package/lib/componentsv2/list/ListSkin.js +0 -345
  108. package/lib/componentsv2/list/structure.css +0 -359
  109. package/lib/componentsv2/plugins/ClientSQLitePlugin.d.ts +0 -21
  110. package/lib/componentsv2/plugins/ClientSQLitePlugin.js +0 -130
  111. package/lib/componentsv2/plugins/IndexedDBPlugin.d.ts +0 -18
  112. package/lib/componentsv2/plugins/IndexedDBPlugin.js +0 -75
  113. package/lib/componentsv2/plugins/LocalStoragePlugin.d.ts +0 -20
  114. package/lib/componentsv2/plugins/LocalStoragePlugin.js +0 -65
  115. package/lib/componentsv2/plugins/ServerSQLitePlugin.d.ts +0 -25
  116. package/lib/componentsv2/plugins/ServerSQLitePlugin.js +0 -70
  117. package/lib/componentsv2/stubs/ComponentComposition.ts.stub +0 -32
  118. package/lib/componentsv2/stubs/ComponentEngine.ts.stub +0 -36
  119. package/lib/componentsv2/stubs/ComponentSkin.ts.stub +0 -35
  120. package/lib/componentsv2/stubs/ComponentStructure.css.d.ts.stub +0 -2
  121. package/lib/componentsv2/stubs/ComponentStructure.css.stub +0 -13
  122. package/lib/utils/fetch.d.ts +0 -176
  123. package/machinery/build3.js +0 -159
  124. package/machinery/compiler3.js +0 -688
  125. package/machinery/config.js +0 -155
  126. package/machinery/serve.js +0 -255
  127. package/machinery/validators/file-validator.js +0 -123
  128. package/machinery/watcher.js +0 -59
  129. package/types/css.d.ts +0 -10
@@ -1,25 +0,0 @@
1
- import { JuxServiceContract, BaseEngine } from '../base/BaseEngine.js';
2
- export interface ServerSQLiteConfig {
3
- /** The Database Driver Instance (e.g. better-sqlite3) */
4
- database: any;
5
- /** Optional: SQL Query to fetch data automatically */
6
- query?: string;
7
- /**
8
- * State Binding: The property key on the Engine's state to populate.
9
- * e.g., 'items' for a ListEngine, or 'rows' for a GridEngine.
10
- */
11
- bindTo?: string;
12
- /**
13
- * Transformation Strategy:
14
- * Converts a raw DB row into the shape expected by the Engine's state.
15
- */
16
- mapRow?: (row: any) => any;
17
- /** If true, runs the query immediately on install */
18
- autoLoad?: boolean;
19
- }
20
- /**
21
- * Server-Side SQLite Plugin
22
- * Decoupled Service that injects SQL capabilities and binds data to ANY Engine state.
23
- */
24
- export declare const ServerSQLitePlugin: (config: ServerSQLiteConfig) => JuxServiceContract<BaseEngine<any>>;
25
- //# sourceMappingURL=ServerSQLitePlugin.d.ts.map
@@ -1,70 +0,0 @@
1
- /**
2
- * Server-Side SQLite Plugin
3
- * Decoupled Service that injects SQL capabilities and binds data to ANY Engine state.
4
- */
5
- export const ServerSQLitePlugin = (config) => ({
6
- name: 'server-sqlite-driver',
7
- version: '2.0.0',
8
- targetEnv: 'server',
9
- install: (engine) => {
10
- // 1. Expose SQL Capability (Mixin)
11
- // Adds a .query() method to the engine instance
12
- Object.assign(engine, {
13
- query: (sql, params = []) => {
14
- if (!config.database || typeof config.database.prepare !== 'function') {
15
- throw new Error('Invalid Database Driver provided to ServerSQLitePlugin.');
16
- }
17
- const stmt = config.database.prepare(sql);
18
- const rows = stmt.all(params);
19
- // Emit audit event for queries
20
- // @ts-ignore - access protected emit
21
- if (typeof engine.emit === 'function')
22
- engine.emit('sql:query', { sql, rows: rows.length });
23
- return rows;
24
- }
25
- });
26
- // 2. Hydration Logic
27
- const hydrate = () => {
28
- if (!config.query)
29
- return;
30
- try {
31
- // Use the newly injected capability
32
- // @ts-ignore
33
- const rows = engine.query(config.query);
34
- if (config.bindTo) {
35
- const data = config.mapRow ? rows.map(config.mapRow) : rows;
36
- // Generic State Update (Decoupled from ListEngine)
37
- // @ts-ignore - access protected updateState
38
- if (typeof engine.updateState === 'function') {
39
- // @ts-ignore
40
- engine.updateState({ [config.bindTo]: data });
41
- }
42
- // Optional: Update loading state if the engine supports it
43
- // @ts-ignore
44
- if (typeof engine.loading === 'function')
45
- engine.loading(false);
46
- // Emit data event for loose coupling
47
- // @ts-ignore
48
- if (typeof engine.emit === 'function')
49
- engine.emit('plugin:data', { source: 'sqlite', count: data.length });
50
- }
51
- }
52
- catch (err) {
53
- console.error('[ServerSQLitePlugin] Hydration Error:', err.message);
54
- // @ts-ignore
55
- if (typeof engine.loading === 'function')
56
- engine.loading(false);
57
- }
58
- };
59
- // 3. Auto-Start
60
- if (config.autoLoad) {
61
- // @ts-ignore
62
- if (typeof engine.loading === 'function')
63
- engine.loading(true);
64
- hydrate();
65
- }
66
- // 4. Listen for Reload Signal
67
- engine.on('db:reload', hydrate);
68
- }
69
- });
70
- //# sourceMappingURL=ServerSQLitePlugin.js.map
@@ -1,32 +0,0 @@
1
- import { [% ComponentName %]Engine, [% ComponentName %]Options } from './engine.js';
2
- import { [% ComponentName %]Skin } from './skin.js';
3
-
4
- export type [% ComponentName %]Component = [% ComponentName %]Engine & {
5
- render: (targetId: string | HTMLElement) => [% ComponentName %]Component;
6
- injectCSS: (id: string, cssContent: string) => void;
7
- };
8
-
9
- export function [% ComponentName %](id: string, options: [% ComponentName %]Options = {}): [% ComponentName %]Component {
10
- const engine = new [% ComponentName %]Engine(id, options);
11
-
12
- if (typeof window !== 'undefined') {
13
- // @ts-ignore
14
- window.juxEngines = window.juxEngines || {};
15
- // @ts-ignore
16
- window.juxEngines[id] = engine;
17
- }
18
-
19
- const skin = new [% ComponentName %]Skin(engine);
20
-
21
- // @ts-ignore
22
- engine.render = (targetId: string | HTMLElement) => {
23
- const target = typeof targetId === 'string' ? document.getElementById(targetId) : targetId;
24
- if (target) skin.renderSkin(target);
25
- return engine as [% ComponentName %]Component;
26
- };
27
-
28
- // @ts-ignore
29
- engine.injectCSS = (id, css) => skin.injectCSS(id, css);
30
-
31
- return engine as [% ComponentName %]Component;
32
- }
@@ -1,36 +0,0 @@
1
- import { BaseEngine, BaseState } from '../base/BaseEngine.js';
2
-
3
- export interface [% ComponentName %]State extends BaseState {
4
- // TODO: Define your state properties
5
- text: string;
6
- }
7
-
8
- export interface [% ComponentName %]Options {
9
- // TODO: Define configuration options
10
- text?: string;
11
- }
12
-
13
- export class [% ComponentName %]Engine extends BaseEngine<[% ComponentName %]State, [% ComponentName %]Options> {
14
- constructor(id: string, options: [% ComponentName %]Options = {}) {
15
- super(id, options);
16
- }
17
-
18
- protected prepareState(id: string, options: [% ComponentName %]Options): [% ComponentName %]State {
19
- return {
20
- id,
21
- classes: ['jux-[% component-name %]'],
22
- visible: true,
23
- disabled: false,
24
- loading: false,
25
- attributes: {},
26
- text: options.text || 'Hello World'
27
- };
28
- }
29
-
30
- // Example Mutator
31
- setText(value: string): this {
32
- this.updateState({ text: value });
33
- this.emit('textChange', { value });
34
- return this;
35
- }
36
- }
@@ -1,35 +0,0 @@
1
- import { BaseSkin } from '../base/BaseSkin.js';
2
- import { [% ComponentName %]Engine, [% ComponentName %]State } from './engine.js';
3
- import structureCss from './structure.css';
4
-
5
- export class [% ComponentName %]Skin extends BaseSkin<[% ComponentName %]State, [% ComponentName %]Engine> {
6
- constructor(engine: [% ComponentName %]Engine) {
7
- super(engine);
8
- }
9
-
10
- /**
11
- * Define the structural CSS for this component.
12
- */
13
- protected get structureCss(): string {
14
- return structureCss;
15
- }
16
-
17
- protected bindEvents(root: HTMLElement): void {
18
- // TODO: Bind DOM events to Engine methods
19
- root.addEventListener('click', () => {
20
- console.log('[% ComponentName %] clicked');
21
- });
22
- }
23
-
24
- protected updateSkin(state: [% ComponentName %]State): void {
25
- if (!this.root) return;
26
- this.applySkinAttributes(this.root, state);
27
-
28
- // TODO: Render state to DOM
29
- this.root.textContent = state.text;
30
- }
31
-
32
- protected createRoot(): HTMLElement {
33
- return document.createElement('div');
34
- }
35
- }
@@ -1,2 +0,0 @@
1
- declare const styles: string;
2
- export default styles;
@@ -1,13 +0,0 @@
1
- .jux-[% component-name %] {
2
- display: block;
3
- padding: var(--space-md);
4
- border: 1px solid var(--color-border);
5
- border-radius: var(--radius-sm);
6
- background-color: var(--color-surface-base);
7
- color: var(--color-text-primary);
8
- transition: all var(--transition-fast);
9
- }
10
-
11
- .jux-[% component-name %]:hover {
12
- background-color: var(--color-surface-hover);
13
- }
@@ -1,176 +0,0 @@
1
- /**
2
- * Jux Fetch Utility
3
- *
4
- * A lightweight fetch wrapper with sensible defaults, error handling, and method chaining.
5
- * Includes configuration helpers for juxconfig.js integration.
6
- *
7
- * Usage:
8
- * // Configure once (optional)
9
- * jux.fetch.config({
10
- * baseUrl: 'https://api.example.com',
11
- * credentials: 'include',
12
- * timeout: 10000,
13
- * log: 'errors',
14
- * onUnauthorized: () => window.location.href = '/login'
15
- * });
16
- *
17
- * // Simple GET
18
- * const { data, error } = await jux.fetch('/users').send();
19
- *
20
- * // Method chaining
21
- * const { data, error } = await jux.fetch('/users')
22
- * .method('POST')
23
- * .body({ name: 'John' })
24
- * .params({ limit: 10 })
25
- * .timeout(5000)
26
- * .log(true)
27
- * .send();
28
- *
29
- * // With juxconfig services
30
- * const { data } = await jux.fetch('/users')
31
- * .baseUrl(jux.fetch.getServiceUrl('database'))
32
- * .send();
33
- *
34
- * // Service client helper
35
- * const db = jux.fetch.serviceClient('database');
36
- * const { data } = await db.fetch('/users').send();
37
- */
38
- export type LogLevel = boolean | 'errors';
39
- export interface FetchConfig {
40
- baseUrl?: string;
41
- credentials?: RequestCredentials;
42
- headers?: Record<string, string>;
43
- timeout?: number;
44
- log?: LogLevel;
45
- onUnauthorized?: () => void;
46
- onError?: (error: FetchError) => void;
47
- }
48
- export interface FetchOptions extends Omit<RequestInit, 'body'> {
49
- params?: Record<string, any>;
50
- body?: any;
51
- timeout?: number;
52
- log?: LogLevel;
53
- onUnauthorized?: () => void;
54
- onError?: (error: FetchError) => void;
55
- parseResponse?: boolean;
56
- }
57
- export interface FetchError {
58
- message: string;
59
- status?: number;
60
- statusText?: string;
61
- data?: any;
62
- }
63
- export interface FetchResult<T = any> {
64
- data: T | null;
65
- error: FetchError | null;
66
- status: number;
67
- response: Response;
68
- }
69
- /**
70
- * Configure global fetch defaults
71
- */
72
- export declare function configureFetch(config: FetchConfig): void;
73
- /**
74
- * FetchBuilder class for method chaining
75
- */
76
- declare class FetchBuilder<T = any> {
77
- url: string;
78
- options: FetchOptions;
79
- constructor(url: string, options?: FetchOptions);
80
- method(value: string): this;
81
- body(value: any): this;
82
- params(value: Record<string, any>): this;
83
- headers(value: Record<string, string>): this;
84
- header(key: string, value: string): this;
85
- timeout(value: number): this;
86
- credentials(value: RequestCredentials): this;
87
- log(value: LogLevel): this;
88
- parseResponse(value: boolean): this;
89
- onUnauthorized(callback: () => void): this;
90
- onError(callback: (error: FetchError) => void): this;
91
- /**
92
- * Execute the fetch request
93
- */
94
- send(): Promise<FetchResult<T>>;
95
- /**
96
- * Alias for send()
97
- */
98
- fetch(): Promise<FetchResult<T>>;
99
- /**
100
- * Make the builder thenable (Promise-like) so it can be awaited directly
101
- * This allows: await jux.fetch('/users') without needing .send()
102
- */
103
- then<TResult1 = FetchResult<T>, TResult2 = never>(onfulfilled?: ((value: FetchResult<T>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
104
- /**
105
- * Make the builder catchable for Promise.catch()
106
- */
107
- catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null): Promise<FetchResult<T> | TResult>;
108
- /**
109
- * Make the builder finally-able for Promise.finally()
110
- */
111
- finally(onfinally?: (() => void) | null): Promise<FetchResult<T>>;
112
- }
113
- /**
114
- * Create a fetch builder
115
- */
116
- export declare function juxFetch<T = any>(url: string, options?: FetchOptions): FetchBuilder<T>;
117
- /**
118
- * Convenience methods for common HTTP verbs
119
- */
120
- export declare const fetchHelpers: {
121
- get: <T = any>(url: string, options?: Omit<FetchOptions, "method">) => FetchBuilder<T>;
122
- post: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, "method" | "body">) => FetchBuilder<T>;
123
- put: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, "method" | "body">) => FetchBuilder<T>;
124
- patch: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, "method" | "body">) => FetchBuilder<T>;
125
- delete: <T = any>(url: string, options?: Omit<FetchOptions, "method">) => FetchBuilder<T>;
126
- };
127
- /**
128
- * Fetch multiple URLs in parallel
129
- */
130
- export declare function fetchAll<T = any>(urls: string[], options?: FetchOptions): Promise<FetchResult<T>[]>;
131
- /**
132
- * Get a service URL from window.juxConfig
133
- */
134
- export declare function getServiceUrl(serviceName: string): string | null;
135
- /**
136
- * Create a fetch instance preconfigured for a specific service
137
- *
138
- * Usage:
139
- * const api = jux.fetch.serviceClient('database');
140
- * const { data } = await api.fetch('/users').send();
141
- */
142
- export declare function serviceClient(serviceName: string): {
143
- fetch: (url: string, options?: any) => FetchBuilder<any>;
144
- baseUrl: string | null;
145
- };
146
- /**
147
- * Setup fetch from juxconfig
148
- * Call this in your bootstrap function
149
- *
150
- * Usage:
151
- * export default {
152
- * bootstrap: [
153
- * async function initFetch() {
154
- * await jux.fetch.setupConfig();
155
- * }
156
- * ]
157
- * };
158
- */
159
- export declare function setupConfig(): Promise<{
160
- services: any;
161
- getServiceUrl: typeof getServiceUrl;
162
- } | undefined>;
163
- export declare const fetchAPI: typeof juxFetch & {
164
- all: typeof fetchAll;
165
- get: <T = any>(url: string, options?: Omit<FetchOptions, "method">) => FetchBuilder<T>;
166
- post: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, "method" | "body">) => FetchBuilder<T>;
167
- put: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, "method" | "body">) => FetchBuilder<T>;
168
- patch: <T = any>(url: string, body?: any, options?: Omit<FetchOptions, "method" | "body">) => FetchBuilder<T>;
169
- delete: <T = any>(url: string, options?: Omit<FetchOptions, "method">) => FetchBuilder<T>;
170
- config: typeof configureFetch;
171
- setupConfig: typeof setupConfig;
172
- getServiceUrl: typeof getServiceUrl;
173
- serviceClient: typeof serviceClient;
174
- };
175
- export {};
176
- //# sourceMappingURL=fetch.d.ts.map
@@ -1,159 +0,0 @@
1
- import { JuxCompiler } from './compiler3.js';
2
- import path from 'path';
3
- import fs from 'fs';
4
-
5
- const PROJECT_ROOT = process.cwd();
6
-
7
- // ═══════════════════════════════════════════════════════════════
8
- // LOAD CONFIG
9
- // ═══════════════════════════════════════════════════════════════
10
- const JUX_CONFIG_PATH = path.resolve(PROJECT_ROOT, 'juxconfig.js');
11
- let rawConfig = {};
12
-
13
- try {
14
- rawConfig = (await import(JUX_CONFIG_PATH)).config;
15
- console.log(`⚙️ Loaded config: ${JUX_CONFIG_PATH}`);
16
- } catch (err) {
17
- console.warn(`⚠️ No juxconfig.js found, using defaults`);
18
- }
19
-
20
- // ═══════════════════════════════════════════════════════════════
21
- // EXPLODE CONFIG INTO NAMED OBJECTS
22
- // ═══════════════════════════════════════════════════════════════
23
- const directories = {
24
- source: rawConfig.directories?.source || './jux',
25
- distribution: rawConfig.directories?.distribution || './.jux-dist',
26
- themes: rawConfig.directories?.themes || './themes',
27
- layouts: rawConfig.directories?.layouts || './themes/layouts',
28
- assets: rawConfig.directories?.assets || './themes/assets'
29
- };
30
-
31
- const defaults = {
32
- httpPort: rawConfig.defaults?.httpPort || 3000,
33
- wsPort: rawConfig.defaults?.wsPort || 3001,
34
- autoRoute: rawConfig.defaults?.autoRoute ?? true,
35
- layout: rawConfig.defaults?.layout || null,
36
- theme: rawConfig.defaults?.theme || null
37
- };
38
-
39
- // Resolve absolute paths
40
- const paths = {
41
- source: path.resolve(PROJECT_ROOT, directories.source),
42
- distribution: path.resolve(PROJECT_ROOT, directories.distribution),
43
- themes: path.resolve(PROJECT_ROOT, directories.source, directories.themes),
44
- layouts: path.resolve(PROJECT_ROOT, directories.source, directories.layouts),
45
- assets: path.resolve(PROJECT_ROOT, directories.source, directories.assets)
46
- };
47
-
48
- // ═══════════════════════════════════════════════════════════════
49
- // VALIDATE DIRECTORIES
50
- // ═══════════════════════════════════════════════════════════════
51
- console.log(`\n📁 Directory Check:`);
52
-
53
- const dirStatus = {};
54
- for (const [name, dirPath] of Object.entries(paths)) {
55
- if (name === 'distribution') continue;
56
-
57
- const exists = fs.existsSync(dirPath);
58
- dirStatus[name] = exists;
59
-
60
- const icon = exists ? '✓' : '✗';
61
- const suffix = exists ? '' : ' (will be skipped)';
62
- console.log(` ${icon} ${name}: ${dirPath}${suffix}`);
63
- }
64
-
65
- // ═══════════════════════════════════════════════════════════════
66
- // RESOLVE DEFAULT LAYOUT & THEME
67
- // ═══════════════════════════════════════════════════════════════
68
- function resolveFile(filename, ...searchPaths) {
69
- if (!filename) return null;
70
-
71
- // First try the filename as-is
72
- if (fs.existsSync(filename)) {
73
- return path.resolve(filename);
74
- }
75
-
76
- // Try each search path
77
- for (const searchPath of searchPaths) {
78
- if (!searchPath || !fs.existsSync(searchPath)) continue;
79
-
80
- const fullPath = path.resolve(searchPath, filename);
81
- if (fs.existsSync(fullPath)) {
82
- return fullPath;
83
- }
84
- }
85
-
86
- return null;
87
- }
88
-
89
- console.log(`\n🎨 Defaults Resolution:`);
90
-
91
- // Resolve layout
92
- const layoutPath = defaults.layout ? resolveFile(
93
- defaults.layout,
94
- paths.layouts,
95
- paths.source,
96
- PROJECT_ROOT
97
- ) : null;
98
-
99
- if (defaults.layout) {
100
- if (layoutPath) {
101
- console.log(` ✓ layout: ${layoutPath}`);
102
- } else {
103
- console.log(` ✗ layout: "${defaults.layout}" not found, will be skipped`);
104
- }
105
- } else {
106
- console.log(` - layout: not configured`);
107
- }
108
-
109
- // Resolve theme
110
- const themePath = defaults.theme ? resolveFile(
111
- defaults.theme,
112
- paths.themes,
113
- paths.source,
114
- PROJECT_ROOT
115
- ) : null;
116
-
117
- if (defaults.theme) {
118
- if (themePath) {
119
- console.log(` ✓ theme: ${themePath}`);
120
- } else {
121
- console.log(` ✗ theme: "${defaults.theme}" not found, will be skipped`);
122
- }
123
- } else {
124
- console.log(` - theme: not configured`);
125
- }
126
-
127
- // ═══════════════════════════════════════════════════════════════
128
- // VALIDATE SOURCE DIRECTORY EXISTS
129
- // ═══════════════════════════════════════════════════════════════
130
- if (!dirStatus.source) {
131
- console.error(`\n❌ Source directory not found: ${paths.source}`);
132
- console.error(` Create the directory or update juxconfig.js`);
133
- process.exit(1);
134
- }
135
-
136
- // ═══════════════════════════════════════════════════════════════
137
- // RUN BUILD
138
- // ═══════════════════════════════════════════════════════════════
139
- console.log(`\n`);
140
-
141
- const compiler = new JuxCompiler({
142
- srcDir: paths.source,
143
- distDir: paths.distribution,
144
- layoutPath,
145
- themePath,
146
- defaults,
147
- paths
148
- });
149
-
150
- compiler.build()
151
- .then(result => {
152
- if (!result.success) {
153
- process.exit(1);
154
- }
155
- })
156
- .catch(err => {
157
- console.error('❌ Build failed:', err.message);
158
- process.exit(1);
159
- });