juxscript 1.0.0 → 1.0.1

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
@@ -10,11 +10,36 @@ import { fileURLToPath } from 'url';
10
10
  const __filename = fileURLToPath(import.meta.url);
11
11
  const __dirname = path.dirname(__filename);
12
12
 
13
+ // CLEAR PATH CONTRACT
14
+ const PATHS = {
15
+ // Where jux package is installed (in node_modules/juxscript or local dev)
16
+ packageRoot: path.resolve(__dirname, '..'),
17
+
18
+ // Where the user's project is (where they run `npx jux`)
19
+ projectRoot: process.cwd(),
20
+
21
+ // Where jux lib files are (components, layouts, etc.)
22
+ get juxLib() {
23
+ return path.join(this.packageRoot, 'lib');
24
+ },
25
+
26
+ // Where user's dist output goes
27
+ get projectDist() {
28
+ return path.join(this.projectRoot, 'dist');
29
+ }
30
+ };
31
+
32
+ console.log('šŸ“ JUX Paths:');
33
+ console.log(` Package: ${PATHS.packageRoot}`);
34
+ console.log(` Project: ${PATHS.projectRoot}`);
35
+ console.log(` Lib: ${PATHS.juxLib}`);
36
+ console.log(` Dist: ${PATHS.projectDist}\n`);
37
+
13
38
  const command = process.argv[2];
14
- const projectRoot = process.cwd();
15
- const distDir = path.join(projectRoot, 'dist');
16
39
 
17
40
  function findJuxFiles(dir, fileList = []) {
41
+ if (!fs.existsSync(dir)) return fileList;
42
+
18
43
  const files = fs.readdirSync(dir);
19
44
 
20
45
  files.forEach(file => {
@@ -34,7 +59,7 @@ function findJuxFiles(dir, fileList = []) {
34
59
  }
35
60
 
36
61
  async function loadConfig() {
37
- const configPath = path.join(projectRoot, 'jux.config.js');
62
+ const configPath = path.join(PATHS.projectRoot, 'jux.config.js');
38
63
 
39
64
  if (fs.existsSync(configPath)) {
40
65
  try {
@@ -53,41 +78,45 @@ async function buildProject(isServe = false) {
53
78
  console.log('šŸ”Ø Building JUX project...\n');
54
79
 
55
80
  try {
56
- if (fs.existsSync(distDir)) {
57
- fs.rmSync(distDir, { recursive: true, force: true });
81
+ // Clean and create dist
82
+ if (fs.existsSync(PATHS.projectDist)) {
83
+ fs.rmSync(PATHS.projectDist, { recursive: true, force: true });
58
84
  }
59
- fs.mkdirSync(distDir, { recursive: true });
85
+ fs.mkdirSync(PATHS.projectDist, { recursive: true });
60
86
 
61
- // Step 1: Generate documentation FIRST
87
+ // Step 1: Generate documentation from jux lib
62
88
  console.log('šŸ“š Generating documentation...');
63
89
  try {
64
- await generateDocs(projectRoot);
90
+ await generateDocs(PATHS.juxLib);
65
91
  console.log('āœ… Documentation generated\n');
66
92
  } catch (error) {
67
93
  console.warn('āš ļø Failed to generate docs:', error.message);
68
94
  }
69
95
 
70
- // Step 2: Copy lib/ to dist/lib/ (includes docs-data.json)
71
- await copyLibToOutput(projectRoot, distDir);
96
+ // Step 2: Copy jux lib to project dist
97
+ await copyLibToOutput(PATHS.juxLib, PATHS.projectDist);
72
98
 
73
- // Step 3: Copy project assets (CSS, JS) from project root
74
- await copyProjectAssets(projectRoot, distDir);
99
+ // Step 3: Copy project assets (CSS, JS)
100
+ await copyProjectAssets(PATHS.projectRoot, PATHS.projectDist);
75
101
 
76
- // Step 4: Find and compile project .jux files
77
- const projectJuxFiles = findJuxFiles(projectRoot);
102
+ // Step 4: Compile project .jux files
103
+ const projectJuxFiles = findJuxFiles(PATHS.projectRoot);
78
104
  console.log(`Found ${projectJuxFiles.length} project .jux file(s)\n`);
79
105
 
80
106
  for (const file of projectJuxFiles) {
81
107
  try {
82
- await compileJuxFile(file, { distDir, projectRoot, isServe });
108
+ await compileJuxFile(file, {
109
+ distDir: PATHS.projectDist,
110
+ projectRoot: PATHS.projectRoot,
111
+ isServe
112
+ });
83
113
  } catch (err) {
84
114
  console.error(`Error compiling ${file}:`, err.message);
85
115
  }
86
116
  }
87
117
 
88
- // Step 5: Find and compile vendor layout .jux files
89
- const libRoot = path.resolve(projectRoot, '../lib');
90
- const layoutsDir = path.join(libRoot, 'layouts');
118
+ // Step 5: Compile vendor layouts
119
+ const layoutsDir = path.join(PATHS.juxLib, 'layouts');
91
120
 
92
121
  if (fs.existsSync(layoutsDir)) {
93
122
  console.log('\nšŸ“ Compiling vendor layouts...');
@@ -96,11 +125,11 @@ async function buildProject(isServe = false) {
96
125
 
97
126
  for (const file of vendorJuxFiles) {
98
127
  try {
99
- const relPath = path.relative(libRoot, file);
128
+ const relPath = path.relative(PATHS.juxLib, file);
100
129
 
101
130
  await compileJuxFile(file, {
102
- distDir: path.join(distDir, 'lib'),
103
- projectRoot: libRoot,
131
+ distDir: path.join(PATHS.projectDist, 'lib'),
132
+ projectRoot: PATHS.juxLib,
104
133
  isServe
105
134
  });
106
135
 
@@ -114,6 +143,7 @@ async function buildProject(isServe = false) {
114
143
  console.log(`\nāœ… Built ${projectJuxFiles.length} project file(s) + layouts\n`);
115
144
  } catch (err) {
116
145
  console.error('āŒ Build error:', err.message);
146
+ console.error(err.stack);
117
147
  process.exit(1);
118
148
  }
119
149
  }
@@ -121,13 +151,10 @@ async function buildProject(isServe = false) {
121
151
  (async () => {
122
152
  if (command === 'build') {
123
153
  await buildProject(false);
124
- console.log(`āœ… Build complete: ${distDir}`);
154
+ console.log(`āœ… Build complete: ${PATHS.projectDist}`);
125
155
 
126
156
  } else if (command === 'serve') {
127
- // Build first
128
- await buildProject(true); // isServe = true
129
-
130
- // Start server with watcher
157
+ await buildProject(true);
131
158
  const config = await loadConfig();
132
159
  await start(3000, config);
133
160
 
@@ -138,7 +165,6 @@ JUX CLI - A JavaScript UX authorship platform
138
165
  Usage:
139
166
  npx jux build Compile all .jux files to HTML/CSS/JS
140
167
  npx jux serve [port] Start dev server with hot reload (default: 3000)
141
- Builds automatically if dist/ doesn't exist
142
168
 
143
169
  Examples:
144
170
  npx jux build Build for production
@@ -1207,5 +1207,5 @@
1207
1207
  }
1208
1208
  ],
1209
1209
  "version": "1.0.0",
1210
- "lastUpdated": "2026-01-16T19:58:49.958Z"
1210
+ "lastUpdated": "2026-01-16T22:00:11.522Z"
1211
1211
  }
@@ -4,10 +4,15 @@ import { glob } from 'glob';
4
4
 
5
5
  /**
6
6
  * Generate documentation from TypeScript component files
7
+ *
8
+ * @param {string} juxLibPath - Absolute path to jux/lib directory
7
9
  */
8
- export async function generateDocs(projectRoot) {
9
- const libRoot = path.resolve(projectRoot, '../lib');
10
- const componentsDir = path.join(libRoot, 'components');
10
+ export async function generateDocs(juxLibPath) {
11
+ const componentsDir = path.join(juxLibPath, 'components');
12
+
13
+ if (!fs.existsSync(componentsDir)) {
14
+ throw new Error(`Components directory not found: ${componentsDir}`);
15
+ }
11
16
 
12
17
  console.log(` Scanning: ${componentsDir}`);
13
18
 
@@ -15,7 +20,7 @@ export async function generateDocs(projectRoot) {
15
20
  const componentFiles = glob.sync('*.ts', {
16
21
  cwd: componentsDir,
17
22
  absolute: true,
18
- ignore: ['reactivity.js', 'error-handler.ts', 'docs.ts']
23
+ ignore: ['reactivity.ts', 'error-handler.ts']
19
24
  });
20
25
 
21
26
  console.log(` Found ${componentFiles.length} component files`);
@@ -62,23 +67,14 @@ function parseComponentFile(content, filePath) {
62
67
  const fileName = path.basename(filePath, '.ts');
63
68
  const className = fileName.charAt(0).toUpperCase() + fileName.slice(1);
64
69
 
65
- // Extract category from file content or infer
66
70
  const category = inferCategory(className, content);
67
-
68
- // Extract description from class JSDoc
69
71
  const descMatch = content.match(/\/\*\*\s*\n\s*\*\s*([^\n*]+)/);
70
72
  const description = descMatch ? descMatch[1].trim() : `${className} component`;
71
-
72
- // Extract constructor/factory pattern
73
73
  const factoryMatch = content.match(/export function\s+\w+\(([^)]*)\)/);
74
74
  const constructorSig = factoryMatch
75
75
  ? `jux.${fileName}(${factoryMatch[1]})`
76
76
  : `new ${className}()`;
77
-
78
- // Extract fluent methods
79
77
  const fluentMethods = extractFluentMethods(content, className);
80
-
81
- // Extract usage example from JSDoc
82
78
  const exampleMatch = content.match(/\*\s+Usage:\s*\n\s*\*\s+(.+?)(?:\n|$)/);
83
79
  let example = exampleMatch
84
80
  ? exampleMatch[1].trim()
@@ -99,28 +95,14 @@ function parseComponentFile(content, filePath) {
99
95
  */
100
96
  function extractFluentMethods(content, className) {
101
97
  const methods = [];
102
-
103
- // Match method patterns: methodName(params): this
104
98
  const methodRegex = /^\s*(\w+)\(([^)]*)\):\s*this\s*\{/gm;
105
99
  let match;
106
100
 
107
101
  while ((match = methodRegex.exec(content)) !== null) {
108
102
  const methodName = match[1];
109
103
  const params = match[2];
110
-
111
- // Skip private methods and constructor
112
104
  if (methodName.startsWith('_') || methodName === 'constructor') continue;
113
-
114
- // Clean up params
115
- const cleanParams = params
116
- .split(',')
117
- .map(p => {
118
- const parts = p.trim().split(':');
119
- return parts[0].trim();
120
- })
121
- .filter(p => p)
122
- .join(', ');
123
-
105
+ const cleanParams = params.split(',').map(p => p.trim().split(':')[0].trim()).filter(p => p).join(', ');
124
106
  methods.push({
125
107
  name: methodName,
126
108
  params: cleanParams ? `(${cleanParams})` : '()',
@@ -129,7 +111,6 @@ function extractFluentMethods(content, className) {
129
111
  });
130
112
  }
131
113
 
132
- // Also look for render methods
133
114
  const renderMatch = content.match(/^\s*render\(([^)]*)\):\s*(\w+)/m);
134
115
  if (renderMatch && !methods.find(m => m.name === 'render')) {
135
116
  methods.push({
@@ -149,12 +130,7 @@ function extractFluentMethods(content, className) {
149
130
  function inferCategory(name, content) {
150
131
  const dataComponents = ['Table', 'List', 'Chart', 'Data'];
151
132
  const coreComponents = ['App', 'Layout', 'Theme', 'Style', 'Script', 'Import'];
152
-
153
- if (dataComponents.some(dc => name.includes(dc))) {
154
- return 'Data Components';
155
- }
156
- if (coreComponents.includes(name)) {
157
- return 'Core';
158
- }
133
+ if (dataComponents.some(dc => name.includes(dc))) return 'Data Components';
134
+ if (coreComponents.includes(name)) return 'Core';
159
135
  return 'UI Components';
160
136
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "lib/jux.js",