juxscript 1.0.89 → 1.0.91

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/bin/cli.js CHANGED
@@ -3,124 +3,275 @@
3
3
  import path from 'path';
4
4
  import fs from 'fs';
5
5
  import { fileURLToPath } from 'url';
6
+ import { spawn } from 'child_process';
6
7
 
7
8
  const __filename = fileURLToPath(import.meta.url);
8
9
  const __dirname = path.dirname(__filename);
9
- const command = process.argv[2];
10
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
10
11
 
11
- function scaffoldProject(targetDir, packageRoot) {
12
+ const [, , command, ...args] = process.argv;
13
+
14
+ // ═══════════════════════════════════════════════════════════════
15
+ // COMMAND: create <project-name>
16
+ // Creates a new JUX project from the template
17
+ // ═══════════════════════════════════════════════════════════════
18
+ async function createProject(projectName) {
19
+ if (!projectName) {
20
+ console.error('❌ Usage: jux create <project-name>');
21
+ process.exit(1);
22
+ }
23
+
24
+ const targetDir = path.join(process.cwd(), projectName);
25
+
26
+ if (fs.existsSync(targetDir)) {
27
+ console.error(`❌ Directory "${projectName}" already exists.`);
28
+ process.exit(1);
29
+ }
30
+
31
+ console.log(`\n📦 Creating JUX project: ${projectName}\n`);
32
+
33
+ // 1. Create project directory
34
+ fs.mkdirSync(targetDir, { recursive: true });
35
+
36
+ // 2. Copy template from /create folder
37
+ const templateDir = path.join(PACKAGE_ROOT, 'create');
38
+ if (fs.existsSync(templateDir)) {
39
+ copyDirRecursive(templateDir, path.join(targetDir, 'jux'));
40
+ console.log(' ✓ Copied template files');
41
+ } else {
42
+ // Fallback: create minimal starter
43
+ const juxDir = path.join(targetDir, 'jux');
44
+ fs.mkdirSync(juxDir, { recursive: true });
45
+ fs.writeFileSync(
46
+ path.join(juxDir, 'index.jux'),
47
+ `import { Element } from 'juxscript';\n\nElement('welcome', { tagName: 'h1' })\n .text('Welcome to JUX!')\n .render('app');\n`
48
+ );
49
+ console.log(' ✓ Created starter file');
50
+ }
51
+
52
+ // 3. Copy example config
53
+ const configSrc = path.join(PACKAGE_ROOT, 'juxconfig.example.js');
54
+ const configDest = path.join(targetDir, 'juxconfig.js');
55
+ if (fs.existsSync(configSrc)) {
56
+ fs.copyFileSync(configSrc, configDest);
57
+ console.log(' ✓ Created juxconfig.js');
58
+ }
59
+
60
+ // 4. Create package.json
61
+ const pkg = {
62
+ name: projectName,
63
+ version: '0.1.0',
64
+ type: 'module',
65
+ scripts: {
66
+ dev: 'jux serve --hot',
67
+ build: 'jux build',
68
+ start: 'jux serve'
69
+ },
70
+ dependencies: {
71
+ juxscript: 'latest'
72
+ }
73
+ };
74
+ fs.writeFileSync(path.join(targetDir, 'package.json'), JSON.stringify(pkg, null, 2));
75
+ console.log(' ✓ Created package.json');
76
+
77
+ // 5. Create .gitignore
78
+ fs.writeFileSync(
79
+ path.join(targetDir, '.gitignore'),
80
+ `.jux-dist/\nnode_modules/\n.DS_Store\n.env\n*.log\n`
81
+ );
82
+ console.log(' ✓ Created .gitignore');
83
+
84
+ // 6. Install dependencies
85
+ console.log('\n📥 Installing dependencies...\n');
86
+ try {
87
+ const { execSync } = await import('child_process');
88
+ execSync('npm install', { cwd: targetDir, stdio: 'inherit' });
89
+ } catch (err) {
90
+ console.warn('⚠️ npm install failed. Run it manually.');
91
+ }
92
+
93
+ console.log(`
94
+ ✅ Project created successfully!
95
+
96
+ cd ${projectName}
97
+ npm run dev
98
+
99
+ `);
100
+ }
101
+
102
+ // ═══════════════════════════════════════════════════════════════
103
+ // COMMAND: init
104
+ // Initializes JUX in an existing project
105
+ // ═══════════════════════════════════════════════════════════════
106
+ function initProject() {
107
+ const targetDir = process.cwd();
108
+
109
+ console.log('\n📦 Initializing JUX in current directory\n');
110
+
111
+ // 1. Copy template to ./jux
112
+ const templateDir = path.join(PACKAGE_ROOT, 'create');
12
113
  const juxDir = path.join(targetDir, 'jux');
13
- if (!fs.existsSync(juxDir)) fs.mkdirSync(juxDir, { recursive: true });
14
- const presetDir = path.join(packageRoot, 'create');
15
- let copied = 0;
16
- if (fs.existsSync(presetDir)) {
17
- fs.readdirSync(presetDir).forEach(file => {
18
- if (file.startsWith('.')) return;
19
- if (fs.statSync(path.join(presetDir, file)).isFile()) {
20
- fs.copyFileSync(path.join(presetDir, file), path.join(juxDir, file));
21
- copied++;
22
- }
23
- });
114
+
115
+ if (!fs.existsSync(juxDir)) {
116
+ fs.mkdirSync(juxDir, { recursive: true });
24
117
  }
25
- if (copied === 0 && !fs.existsSync(path.join(juxDir, 'index.jux'))) {
26
- fs.writeFileSync(path.join(juxDir, 'index.jux'), `import { Element } from 'juxscript';\nElement('welcome', { tag: 'h1' }).text('Welcome to JUX!').render('app');\n`);
118
+
119
+ if (fs.existsSync(templateDir)) {
120
+ copyDirRecursive(templateDir, juxDir);
121
+ console.log(' ✓ Copied template files to ./jux');
122
+ } else {
123
+ fs.writeFileSync(
124
+ path.join(juxDir, 'index.jux'),
125
+ `import { Element } from 'juxscript';\n\nElement('welcome', { tagName: 'h1' })\n .text('Welcome to JUX!')\n .render('app');\n`
126
+ );
127
+ console.log(' ✓ Created starter file');
27
128
  }
28
- const configSrc = path.join(packageRoot, 'juxconfig.example.js');
129
+
130
+ // 2. Copy config if not exists
29
131
  const configDest = path.join(targetDir, 'juxconfig.js');
30
- if (fs.existsSync(configSrc) && !fs.existsSync(configDest)) fs.copyFileSync(configSrc, configDest);
31
- const gitIgnore = path.join(targetDir, '.gitignore');
32
- if (!fs.existsSync(gitIgnore)) fs.writeFileSync(gitIgnore, `.jux-dist/\nnode_modules/\n.DS_Store\n.env\n*.log\n`);
132
+ if (!fs.existsSync(configDest)) {
133
+ const configSrc = path.join(PACKAGE_ROOT, 'juxconfig.example.js');
134
+ if (fs.existsSync(configSrc)) {
135
+ fs.copyFileSync(configSrc, configDest);
136
+ console.log(' ✓ Created juxconfig.js');
137
+ }
138
+ }
139
+
140
+ // 3. Update package.json scripts if exists
33
141
  const pkgPath = path.join(targetDir, 'package.json');
34
142
  if (fs.existsSync(pkgPath)) {
35
143
  try {
36
144
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
37
145
  pkg.scripts = pkg.scripts || {};
38
146
  let modified = false;
39
- if (!pkg.scripts.dev) { pkg.scripts.dev = 'jux serve'; modified = true; }
147
+
148
+ if (!pkg.scripts.dev) { pkg.scripts.dev = 'jux serve --hot'; modified = true; }
40
149
  if (!pkg.scripts.build) { pkg.scripts.build = 'jux build'; modified = true; }
41
- if (modified) fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
42
- } catch (e) { }
150
+ if (!pkg.scripts.start) { pkg.scripts.start = 'jux serve'; modified = true; }
151
+
152
+ if (modified) {
153
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
154
+ console.log(' ✓ Updated package.json scripts');
155
+ }
156
+ } catch (e) {
157
+ console.warn(' ⚠️ Could not update package.json');
158
+ }
43
159
  }
160
+
161
+ console.log('\n✅ Initialized. Run: npm run dev\n');
44
162
  }
45
163
 
46
- if (command === 'create') {
47
- const projectName = process.argv[3] || 'my-jux-app';
48
- const projectPath = path.join(process.cwd(), projectName);
49
- if (fs.existsSync(projectPath)) { console.error(`❌ Directory "${projectName}" already exists.`); process.exit(1); }
50
- try {
51
- const { execSync } = await import('child_process');
52
- fs.mkdirSync(projectPath, { recursive: true });
53
- process.chdir(projectPath);
54
- const pkg = { name: projectName, version: '0.1.0', type: 'module', scripts: { dev: 'jux serve', build: 'jux build' }, dependencies: { juxscript: 'latest' } };
55
- fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
56
- const packageRoot = path.resolve(__dirname, '..');
57
- scaffoldProject(projectPath, packageRoot);
58
- try { execSync('npm install', { stdio: 'inherit' }); } catch (err) { }
59
- console.log(`\n✅ Project created! Run: cd ${projectName} && npm run dev\n`);
60
- } catch (err) { console.error(`\n❌ Failed:`, err.message); process.exit(1); }
61
- process.exit(0);
164
+ // ═══════════════════════════════════════════════════════════════
165
+ // COMMAND: build
166
+ // Delegates to machinery/build3.js
167
+ // ═══════════════════════════════════════════════════════════════
168
+ function runBuild() {
169
+ const buildScript = path.join(PACKAGE_ROOT, 'machinery', 'build3.js');
170
+
171
+ if (!fs.existsSync(buildScript)) {
172
+ console.error(' Build script not found:', buildScript);
173
+ process.exit(1);
174
+ }
175
+
176
+ const child = spawn('node', [buildScript, ...args], {
177
+ cwd: process.cwd(),
178
+ stdio: 'inherit',
179
+ env: process.env
180
+ });
181
+
182
+ child.on('close', (code) => process.exit(code || 0));
62
183
  }
63
184
 
64
- import { copyLibToOutput, copyProjectAssets, transpileProjectTypeScript, copyPresetsToOutput, bundleJuxFilesToRouter, generateIndexHtml } from '../machinery/compiler.js';
65
- import { verifyStaticBuild } from '../machinery/verifier.js';
66
- import { resolveConfig } from '../machinery/config.js';
67
- import { start } from '../machinery/server.js';
185
+ // ═══════════════════════════════════════════════════════════════
186
+ // COMMAND: serve [--hot]
187
+ // Delegates to machinery/serve.js
188
+ // ═══════════════════════════════════════════════════════════════
189
+ function runServe() {
190
+ const serveScript = path.join(PACKAGE_ROOT, 'machinery', 'serve.js');
191
+
192
+ if (!fs.existsSync(serveScript)) {
193
+ console.error('❌ Serve script not found:', serveScript);
194
+ process.exit(1);
195
+ }
196
+
197
+ // Pass through all args (including --hot)
198
+ const child = spawn('node', [serveScript, ...args], {
199
+ cwd: process.cwd(),
200
+ stdio: 'inherit',
201
+ env: process.env
202
+ });
68
203
 
69
- async function loadUserConfig(projectRoot) {
70
- const configPath = path.join(projectRoot, 'juxconfig.js');
71
- let rawConfig = {};
72
- if (fs.existsSync(configPath)) { try { const module = await import(configPath); rawConfig = module.default || module.config || {}; } catch (err) { } }
73
- return resolveConfig(rawConfig, projectRoot);
204
+ child.on('close', (code) => process.exit(code || 0));
74
205
  }
75
206
 
76
- (async () => {
77
- const projectRoot = process.cwd();
78
- const config = await loadUserConfig(projectRoot);
79
- const PATHS = {
80
- packageRoot: path.resolve(__dirname, '..'),
81
- projectRoot: projectRoot,
82
- get juxSource() { return path.join(this.projectRoot, config.directories?.source || 'jux'); },
83
- get juxLib() { return path.resolve(this.packageRoot, 'lib'); },
84
- get frontendDist() { return path.join(this.projectRoot, config.directories?.distribution || '.jux-dist'); }
85
- };
207
+ // ═══════════════════════════════════════════════════════════════
208
+ // UTILITIES
209
+ // ═══════════════════════════════════════════════════════════════
210
+ function copyDirRecursive(src, dest) {
211
+ if (!fs.existsSync(dest)) {
212
+ fs.mkdirSync(dest, { recursive: true });
213
+ }
86
214
 
87
- async function buildProject(isServe = false, wsPort = 3001) {
88
- if (!fs.existsSync(PATHS.juxSource)) { console.error(`❌ Source not found: ${PATHS.juxSource}`); process.exit(1); }
89
- if (fs.existsSync(PATHS.frontendDist)) fs.rmSync(PATHS.frontendDist, { recursive: true, force: true });
90
- fs.mkdirSync(PATHS.frontendDist, { recursive: true });
215
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
216
+ if (entry.name.startsWith('.')) continue; // Skip hidden files
91
217
 
92
- // Clean Log
93
- process.stdout.write('🔨 Building JUX... ');
218
+ const srcPath = path.join(src, entry.name);
219
+ const destPath = path.join(dest, entry.name);
94
220
 
95
- try {
96
- await copyLibToOutput(PATHS.juxLib, PATHS.frontendDist);
97
- await copyPresetsToOutput(PATHS.packageRoot, PATHS.frontendDist);
98
- await copyProjectAssets(PATHS.juxSource, PATHS.frontendDist);
99
- await transpileProjectTypeScript(PATHS.juxSource, PATHS.frontendDist);
100
- const bundleResult = await bundleJuxFilesToRouter(PATHS.juxSource, PATHS.frontendDist, { routePrefix: '', config });
101
- generateIndexHtml(PATHS.frontendDist, bundleResult, { isDev: isServe, wsPort: isServe ? wsPort : undefined });
102
- if (!verifyStaticBuild(PATHS.frontendDist)) { console.error('🛑 Critical Build Failure.'); process.exit(1); }
103
-
104
- const fileCount = fs.readdirSync(PATHS.juxSource).filter(f => f.endsWith('.jux')).length; // Approximate check
105
- console.log(`✅ Done. (${fileCount} files, ${(fs.statSync(path.join(PATHS.frontendDist, 'main.js')).size / 1024).toFixed(1)}KB)`);
106
- } catch (err) {
107
- console.log('❌ Failed.');
108
- console.error(err.message);
109
- process.exit(1);
221
+ if (entry.isDirectory()) {
222
+ copyDirRecursive(srcPath, destPath);
223
+ } else {
224
+ fs.copyFileSync(srcPath, destPath);
110
225
  }
111
226
  }
227
+ }
112
228
 
113
- if (command === 'init' || command === 'install') {
114
- scaffoldProject(PATHS.projectRoot, PATHS.packageRoot);
115
- console.log('✅ Initialized. Next: npm run dev');
116
- } else if (command === 'build') {
117
- await buildProject(false);
118
- } else if (command === 'serve') {
119
- const httpPort = parseInt(process.argv[3]) || config.defaults?.httpPort || 3000;
120
- const wsPort = parseInt(process.argv[4]) || config.defaults?.wsPort || 3001;
121
- await buildProject(true, wsPort);
122
- await start(httpPort, wsPort, PATHS.frontendDist, config);
123
- } else {
124
- console.log(`Usage: npx jux [create|init|build|serve]`);
125
- }
126
- })();
229
+ function showHelp() {
230
+ console.log(`
231
+ JUX CLI
232
+
233
+ Usage:
234
+ jux create <name> Create a new JUX project
235
+ jux init Initialize JUX in current directory
236
+ jux build Build for production
237
+ jux serve Start production server
238
+ jux serve --hot Start dev server with hot reload
239
+
240
+ Options:
241
+ --help, -h Show this help message
242
+ `);
243
+ }
244
+
245
+ // ═══════════════════════════════════════════════════════════════
246
+ // MAIN ROUTER
247
+ // ═══════════════════════════════════════════════════════════════
248
+ switch (command) {
249
+ case 'create':
250
+ createProject(args[0]);
251
+ break;
252
+
253
+ case 'init':
254
+ case 'install':
255
+ initProject();
256
+ break;
257
+
258
+ case 'build':
259
+ runBuild();
260
+ break;
261
+
262
+ case 'serve':
263
+ case 'dev':
264
+ runServe();
265
+ break;
266
+
267
+ case '--help':
268
+ case '-h':
269
+ case undefined:
270
+ showHelp();
271
+ break;
272
+
273
+ default:
274
+ console.error(`❌ Unknown command: ${command}`);
275
+ showHelp();
276
+ process.exit(1);
277
+ }
package/index.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * JUX - JavaScript UX Authorship Platform
3
+ *
4
+ * Main entry point for the juxscript package.
5
+ * Re-exports all public components and utilities.
6
+ */
7
+
8
+ // Core Components
9
+ export { Element } from './lib/componentsv2/element/component.js';
10
+ export { Grid } from './lib/componentsv2/grid/component.js';
11
+ export { Input } from './lib/componentsv2/input/component.js';
12
+ export { List } from './lib/componentsv2/list/component.js';
13
+
14
+ // Base Classes (for extension)
15
+ // Note: BaseState is a TypeScript interface, not exported at runtime
16
+ export { BaseEngine } from './lib/componentsv2/base/BaseEngine.js';
17
+ export { BaseSkin } from './lib/componentsv2/base/BaseSkin.js';
18
+ export { State } from './lib/componentsv2/base/State.js';
19
+ export { GlobalBus } from './lib/componentsv2/base/GlobalBus.js';
20
+
21
+ // Utilities
22
+ export { validateOptions } from './lib/componentsv2/base/OptionsContract.js';
package/lib/globals.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- // CSS Module Support
2
- declare module '*.css' {
3
- const content: string;
4
- export default content;
5
- }
1
+ /**
2
+ * JUX Type Exports
3
+ * Re-export types for TypeScript consumers
4
+ */
5
+ export type { BaseState } from './componentsv2/base/BaseEngine.js';
6
+ export type { JuxServiceContract } from './componentsv2/base/BaseEngine.js';
7
+ export type { OptionsContractSchema, OptionDefinition, ValidationResult } from './componentsv2/base/OptionsContract.js';
@@ -0,0 +1,21 @@
1
+ import { JuxCompiler } from './compiler3.js';
2
+ import path from 'path';
3
+
4
+ // Resolve paths relative to CWD (user's project)
5
+ const PROJECT_ROOT = process.cwd();
6
+
7
+ const compiler = new JuxCompiler({
8
+ srcDir: path.resolve(PROJECT_ROOT, 'jux'),
9
+ distDir: path.resolve(PROJECT_ROOT, '.jux-dist')
10
+ });
11
+
12
+ compiler.build()
13
+ .then(result => {
14
+ if (!result.success) {
15
+ process.exit(1);
16
+ }
17
+ })
18
+ .catch(err => {
19
+ console.error('❌ Build failed:', err.message);
20
+ process.exit(1);
21
+ });