juxscript 1.0.66 ā 1.0.67
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/machinery/verifier.js +12 -21
- package/package.json +1 -1
- package/machinery/build.js +0 -467
package/machinery/verifier.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import http from 'http';
|
|
4
|
-
import * as acorn from 'acorn';
|
|
4
|
+
import * as acorn from 'acorn';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Checks the static `distDir` for critical files and valid import map references.
|
|
8
8
|
* Returns true if healthy, false if broken.
|
|
9
9
|
*/
|
|
10
10
|
export function verifyStaticBuild(distDir) {
|
|
11
|
-
// console.log('šµļø Verifying build integrity...');
|
|
12
11
|
const errors = [];
|
|
13
12
|
|
|
14
13
|
if (!fs.existsSync(distDir)) {
|
|
@@ -17,7 +16,8 @@ export function verifyStaticBuild(distDir) {
|
|
|
17
16
|
}
|
|
18
17
|
|
|
19
18
|
// 1. Critical Files Existence
|
|
20
|
-
|
|
19
|
+
// ā
FIX: Removed lib/jux.js as it is no longer the primary artifact with v2 components
|
|
20
|
+
const critical = ['index.html', 'main.js'];
|
|
21
21
|
for (const f of critical) {
|
|
22
22
|
if (!fs.existsSync(path.join(distDir, f))) {
|
|
23
23
|
errors.push(`Missing critical artifact: ${f}`);
|
|
@@ -41,6 +41,8 @@ export function verifyStaticBuild(distDir) {
|
|
|
41
41
|
const fullPath = path.join(distDir, fsPath);
|
|
42
42
|
|
|
43
43
|
if (!fs.existsSync(fullPath)) {
|
|
44
|
+
// Downgrade missing imports to warnings if they look like vendored libs?
|
|
45
|
+
// For now, keep as error to be safe.
|
|
44
46
|
errors.push(`Broken Import Map: "${key}" -> ${url} (File not found)`);
|
|
45
47
|
}
|
|
46
48
|
}
|
|
@@ -62,14 +64,10 @@ export function verifyStaticBuild(distDir) {
|
|
|
62
64
|
if (node.type === 'ImportDeclaration') {
|
|
63
65
|
const source = node.source.value;
|
|
64
66
|
|
|
65
|
-
// Allow internal relative paths if they exist
|
|
66
67
|
if (source.startsWith('/') || source.startsWith('.')) {
|
|
67
|
-
// basic existence check (simplified)
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
// Check if bare specifier exists in Import Map
|
|
72
|
-
// e.g. import axios from 'axios' -> must be in map
|
|
73
71
|
if (!importMap[source] && !importMap[source + '/']) {
|
|
74
72
|
errors.push(`Ghost Dependency: '${source}' is imported in main.js but missing from Import Map.`);
|
|
75
73
|
}
|
|
@@ -87,33 +85,26 @@ export function verifyStaticBuild(distDir) {
|
|
|
87
85
|
return false;
|
|
88
86
|
}
|
|
89
87
|
|
|
90
|
-
// console.log(' ā Static verification passed');
|
|
91
88
|
return true;
|
|
92
89
|
}
|
|
93
90
|
|
|
94
|
-
/**
|
|
95
|
-
* Pings the running server to ensure correct MIME types and Route availability.
|
|
96
|
-
* Detects "serving JS as HTML" (MIME type mismatch) errors.
|
|
97
|
-
*/
|
|
98
91
|
export function verifyRuntime(port) {
|
|
99
92
|
return new Promise((resolve) => {
|
|
100
|
-
console.log('𩺠Performing runtime diagnostics...');
|
|
93
|
+
// console.log('𩺠Performing runtime diagnostics...');
|
|
101
94
|
const errors = [];
|
|
102
95
|
|
|
103
96
|
// Helper to check a single URL
|
|
104
97
|
const check = (urlPath, expectedMime) => new Promise(r => {
|
|
105
98
|
const req = http.get(`http://localhost:${port}${urlPath}`, res => {
|
|
106
|
-
// Check Status
|
|
107
99
|
if (res.statusCode !== 200 && res.statusCode !== 304) {
|
|
108
100
|
errors.push(`GET ${urlPath} : Status ${res.statusCode} (Expected 200)`);
|
|
109
101
|
} else {
|
|
110
|
-
// Check MIME type
|
|
111
102
|
const ct = res.headers['content-type'] || '';
|
|
112
103
|
if (expectedMime && !ct.includes(expectedMime)) {
|
|
113
|
-
errors.push(`GET ${urlPath} : Bad MIME type. Got "${ct}", expected "${expectedMime}"
|
|
104
|
+
errors.push(`GET ${urlPath} : Bad MIME type. Got "${ct}", expected "${expectedMime}".`);
|
|
114
105
|
}
|
|
115
106
|
}
|
|
116
|
-
res.resume();
|
|
107
|
+
res.resume();
|
|
117
108
|
r();
|
|
118
109
|
});
|
|
119
110
|
|
|
@@ -125,9 +116,9 @@ export function verifyRuntime(port) {
|
|
|
125
116
|
|
|
126
117
|
// Run checks in parallel
|
|
127
118
|
Promise.all([
|
|
128
|
-
check('/', 'text/html'),
|
|
129
|
-
check('/main.js', 'application/javascript'),
|
|
130
|
-
check('/lib/jux.js', 'application/javascript') //
|
|
119
|
+
check('/', 'text/html'),
|
|
120
|
+
check('/main.js', 'application/javascript'),
|
|
121
|
+
// check('/lib/jux.js', 'application/javascript') // Removed check
|
|
131
122
|
]).then(() => {
|
|
132
123
|
if (errors.length > 0) {
|
|
133
124
|
console.error(`\nš„ RUNTIME VERIFICATION FAILED (` + errors.length + ` errors):`);
|
|
@@ -135,7 +126,7 @@ export function verifyRuntime(port) {
|
|
|
135
126
|
console.log('');
|
|
136
127
|
resolve(false);
|
|
137
128
|
} else {
|
|
138
|
-
console.log(' ā Runtime health healthy
|
|
129
|
+
// console.log(' ā Runtime health healthy\n');
|
|
139
130
|
resolve(true);
|
|
140
131
|
}
|
|
141
132
|
});
|
package/package.json
CHANGED
package/machinery/build.js
DELETED
|
@@ -1,467 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import esbuild from 'esbuild';
|
|
4
|
-
import {
|
|
5
|
-
bundleJuxFilesToRouter,
|
|
6
|
-
generateRouterIndex
|
|
7
|
-
} from './compiler.js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Generate import map script tag
|
|
11
|
-
*/
|
|
12
|
-
function generateImportMapScript() {
|
|
13
|
-
return `<script type="importmap">
|
|
14
|
-
{
|
|
15
|
-
"imports": {
|
|
16
|
-
"juxscript": "./lib/jux.js",
|
|
17
|
-
"juxscript/": "./lib/",
|
|
18
|
-
"juxscript/reactivity": "./lib/reactivity/state.js",
|
|
19
|
-
"juxscript/presets/": "./presets/",
|
|
20
|
-
"juxscript/components/": "./lib/components/",
|
|
21
|
-
"juxscript/componentsv2/": "./lib/componentsv2/"
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
</script>`;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Compile a .jux file to .js and .html
|
|
29
|
-
*
|
|
30
|
-
* @param {string} juxFilePath - Path to the .jux file
|
|
31
|
-
* @param {Object} options - Compilation options
|
|
32
|
-
* @param {string} options.distDir - Output directory
|
|
33
|
-
* @param {string} options.projectRoot - Project root directory
|
|
34
|
-
* @param {boolean} options.isServe - Whether serving for development
|
|
35
|
-
* @returns {Promise<{jsOutputPath: string, htmlOutputPath: string}>}
|
|
36
|
-
*/
|
|
37
|
-
export async function compileJuxFile(juxFilePath, options = {}) {
|
|
38
|
-
const { distDir, projectRoot, isServe = false } = options;
|
|
39
|
-
|
|
40
|
-
const relativePath = path.relative(projectRoot, juxFilePath);
|
|
41
|
-
const parsedPath = path.parse(relativePath);
|
|
42
|
-
|
|
43
|
-
// Output paths
|
|
44
|
-
const outputDir = path.join(distDir, parsedPath.dir);
|
|
45
|
-
const jsOutputPath = path.join(outputDir, `${parsedPath.name}.js`);
|
|
46
|
-
const htmlOutputPath = path.join(outputDir, `${parsedPath.name}.html`);
|
|
47
|
-
|
|
48
|
-
// Ensure output directory exists
|
|
49
|
-
if (!fs.existsSync(outputDir)) {
|
|
50
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
console.log(`š Compiling: ${relativePath}`);
|
|
54
|
-
|
|
55
|
-
// Read the .jux file
|
|
56
|
-
const juxContent = fs.readFileSync(juxFilePath, 'utf-8');
|
|
57
|
-
|
|
58
|
-
// Calculate depth for relative paths
|
|
59
|
-
const depth = parsedPath.dir.split(path.sep).filter(p => p).length;
|
|
60
|
-
const libPath = depth === 0 ? './lib/jux.js' : '../'.repeat(depth) + 'lib/jux.js';
|
|
61
|
-
|
|
62
|
-
// Transform imports
|
|
63
|
-
let transformedContent = juxContent;
|
|
64
|
-
|
|
65
|
-
// Replace common import patterns with calculated path
|
|
66
|
-
transformedContent = transformedContent.replace(
|
|
67
|
-
/from\s+['"]\.\.?\/lib\/jux\.js['"]/g,
|
|
68
|
-
`from '${libPath}'`
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
// Only inject import if:
|
|
72
|
-
// 1. File is not empty (ignoring whitespace and comments)
|
|
73
|
-
// 2. File uses 'jux.' but has no import statement
|
|
74
|
-
const contentWithoutComments = transformedContent
|
|
75
|
-
.replace(/\/\*[\s\S]*?\*\//g, '') // Remove block comments
|
|
76
|
-
.replace(/\/\/.*/g, '') // Remove line comments
|
|
77
|
-
.trim();
|
|
78
|
-
|
|
79
|
-
const hasContent = contentWithoutComments.length > 0;
|
|
80
|
-
const usesJux = /\bjux\./g.test(contentWithoutComments);
|
|
81
|
-
const hasImport = /import\s+.*from/.test(transformedContent);
|
|
82
|
-
|
|
83
|
-
if (hasContent && usesJux && !hasImport) {
|
|
84
|
-
transformedContent = `import { jux } from '${libPath}';\n\n${transformedContent}`;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Write the transformed JS
|
|
88
|
-
fs.writeFileSync(jsOutputPath, transformedContent);
|
|
89
|
-
|
|
90
|
-
console.log(` ā JS: ${path.relative(projectRoot, jsOutputPath)}`);
|
|
91
|
-
|
|
92
|
-
// Generate HTML with import map and correct script path
|
|
93
|
-
const scriptPath = `./${parsedPath.name}.js`;
|
|
94
|
-
const importMapScript = generateImportMapScript();
|
|
95
|
-
|
|
96
|
-
const html = `<!DOCTYPE html>
|
|
97
|
-
<html lang="en">
|
|
98
|
-
<head>
|
|
99
|
-
<meta charset="UTF-8">
|
|
100
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
101
|
-
<title>${parsedPath.name}</title>
|
|
102
|
-
</head>
|
|
103
|
-
<body data-theme="">
|
|
104
|
-
<!-- App container -->
|
|
105
|
-
<div id="app" data-jux-page="${parsedPath.name}"></div>
|
|
106
|
-
|
|
107
|
-
${importMapScript}
|
|
108
|
-
<script type="module" src="${scriptPath}"></script>
|
|
109
|
-
${isServe ? `
|
|
110
|
-
<!-- Hot reload -->
|
|
111
|
-
<script type="module">
|
|
112
|
-
const ws = new WebSocket('ws://localhost:3001');
|
|
113
|
-
ws.onmessage = (msg) => {
|
|
114
|
-
const data = JSON.parse(msg.data);
|
|
115
|
-
if (data.type === 'reload') {
|
|
116
|
-
console.log('š Reloading page...');
|
|
117
|
-
location.reload();
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
ws.onerror = () => console.warn('ā ļø WebSocket connection failed');
|
|
121
|
-
</script>
|
|
122
|
-
` : ''}
|
|
123
|
-
</body>
|
|
124
|
-
</html>`;
|
|
125
|
-
|
|
126
|
-
fs.writeFileSync(htmlOutputPath, html);
|
|
127
|
-
console.log(` ā HTML: ${path.relative(projectRoot, htmlOutputPath)}`);
|
|
128
|
-
|
|
129
|
-
return { jsOutputPath, htmlOutputPath };
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Copy and build the JUX library from TypeScript to JavaScript
|
|
134
|
-
*
|
|
135
|
-
* @param {string} projectRoot - Root directory containing lib/
|
|
136
|
-
* @param {string} distDir - Destination directory for built files
|
|
137
|
-
*/
|
|
138
|
-
export async function copyLibToOutput(projectRoot, distDir) {
|
|
139
|
-
// Simplified lib path resolution
|
|
140
|
-
const libSrc = path.resolve(projectRoot, '../lib');
|
|
141
|
-
|
|
142
|
-
if (!fs.existsSync(libSrc)) {
|
|
143
|
-
throw new Error(`lib/ directory not found at ${libSrc}`);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const libDest = path.join(distDir, 'lib');
|
|
147
|
-
|
|
148
|
-
console.log('š¦ Building TypeScript library...');
|
|
149
|
-
console.log(` From: ${libSrc}`);
|
|
150
|
-
console.log(` To: ${libDest}`);
|
|
151
|
-
|
|
152
|
-
if (fs.existsSync(libDest)) {
|
|
153
|
-
fs.rmSync(libDest, { recursive: true });
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
fs.mkdirSync(libDest, { recursive: true });
|
|
157
|
-
|
|
158
|
-
// Find all TypeScript entry points
|
|
159
|
-
const tsFiles = findFiles(libSrc, '.ts');
|
|
160
|
-
|
|
161
|
-
if (tsFiles.length === 0) {
|
|
162
|
-
console.warn('ā ļø No TypeScript files found in lib/');
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
console.log(` Found ${tsFiles.length} TypeScript files`);
|
|
167
|
-
|
|
168
|
-
// Build all TypeScript files with esbuild
|
|
169
|
-
try {
|
|
170
|
-
await esbuild.build({
|
|
171
|
-
entryPoints: tsFiles,
|
|
172
|
-
bundle: false,
|
|
173
|
-
format: 'esm',
|
|
174
|
-
outdir: libDest,
|
|
175
|
-
outbase: libSrc,
|
|
176
|
-
platform: 'browser',
|
|
177
|
-
target: 'es2020',
|
|
178
|
-
loader: {
|
|
179
|
-
'.ts': 'ts'
|
|
180
|
-
},
|
|
181
|
-
logLevel: 'warning'
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
console.log(' ā TypeScript compiled to JavaScript');
|
|
185
|
-
|
|
186
|
-
// Copy non-TS files (CSS, HTML, etc.)
|
|
187
|
-
console.log(' Copying lib assets...');
|
|
188
|
-
copyNonTsFiles(libSrc, libDest);
|
|
189
|
-
console.log(' ā Lib assets copied');
|
|
190
|
-
|
|
191
|
-
} catch (err) {
|
|
192
|
-
console.error('ā Failed to build TypeScript:', err.message);
|
|
193
|
-
throw err;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
console.log('ā
Library ready\n');
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Copy project assets (CSS, JS, images) from jux/ to dist/
|
|
201
|
-
*
|
|
202
|
-
* @param {string} projectRoot - Source directory (jux/)
|
|
203
|
-
* @param {string} distDir - Destination directory (jux-dist/)
|
|
204
|
-
*/
|
|
205
|
-
export async function copyProjectAssets(projectRoot, distDir) {
|
|
206
|
-
console.log('š¦ Copying project assets...');
|
|
207
|
-
|
|
208
|
-
// Find all CSS and JS files in project root (excluding node_modules, dist, .git)
|
|
209
|
-
const allFiles = [];
|
|
210
|
-
findProjectFiles(projectRoot, ['.css', '.js'], allFiles, projectRoot);
|
|
211
|
-
|
|
212
|
-
console.log(` Found ${allFiles.length} asset file(s)`);
|
|
213
|
-
|
|
214
|
-
for (const srcPath of allFiles) {
|
|
215
|
-
const relativePath = path.relative(projectRoot, srcPath);
|
|
216
|
-
const destPath = path.join(distDir, relativePath);
|
|
217
|
-
const destDir = path.dirname(destPath);
|
|
218
|
-
|
|
219
|
-
// Create destination directory if needed
|
|
220
|
-
if (!fs.existsSync(destDir)) {
|
|
221
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Copy file
|
|
225
|
-
fs.copyFileSync(srcPath, destPath);
|
|
226
|
-
console.log(` ā ${relativePath}`);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
console.log('ā
Project assets copied\n');
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Transpile TypeScript files from jux/ to jux-dist/, preserving folder structure
|
|
234
|
-
*
|
|
235
|
-
* @param {string} srcDir - Source directory (jux/)
|
|
236
|
-
* @param {string} destDir - Destination directory (jux-dist/)
|
|
237
|
-
* @example
|
|
238
|
-
* // jux/samples/mypage.ts -> jux-dist/samples/mypage.js
|
|
239
|
-
* await transpileProjectTypeScript('jux/', 'jux-dist/');
|
|
240
|
-
*/
|
|
241
|
-
export async function transpileProjectTypeScript(srcDir, destDir) {
|
|
242
|
-
console.log('š· Transpiling TypeScript files...');
|
|
243
|
-
|
|
244
|
-
// Find all TypeScript files in the project
|
|
245
|
-
const tsFiles = findFiles(srcDir, '.ts');
|
|
246
|
-
|
|
247
|
-
if (tsFiles.length === 0) {
|
|
248
|
-
console.log(' No TypeScript files found in project');
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
console.log(` Found ${tsFiles.length} TypeScript file(s)`);
|
|
253
|
-
|
|
254
|
-
try {
|
|
255
|
-
// Build all TypeScript files with esbuild
|
|
256
|
-
await esbuild.build({
|
|
257
|
-
entryPoints: tsFiles,
|
|
258
|
-
bundle: false,
|
|
259
|
-
format: 'esm',
|
|
260
|
-
outdir: destDir,
|
|
261
|
-
outbase: srcDir,
|
|
262
|
-
platform: 'browser',
|
|
263
|
-
target: 'es2020',
|
|
264
|
-
loader: {
|
|
265
|
-
'.ts': 'ts'
|
|
266
|
-
},
|
|
267
|
-
logLevel: 'warning'
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
// Log each transpiled file
|
|
271
|
-
tsFiles.forEach(tsFile => {
|
|
272
|
-
const relativePath = path.relative(srcDir, tsFile);
|
|
273
|
-
const jsPath = relativePath.replace(/\.ts$/, '.js');
|
|
274
|
-
console.log(` ā ${relativePath} ā ${jsPath}`);
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
console.log('ā
TypeScript transpiled\n');
|
|
278
|
-
|
|
279
|
-
} catch (err) {
|
|
280
|
-
console.error('ā Failed to transpile TypeScript:', err.message);
|
|
281
|
-
throw err;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Copy presets folder from lib to dist
|
|
287
|
-
*
|
|
288
|
-
* @param {string} packageRoot - Source package root directory
|
|
289
|
-
* @param {string} distDir - Destination directory
|
|
290
|
-
*/
|
|
291
|
-
export async function copyPresetsToOutput(packageRoot, distDir) {
|
|
292
|
-
console.log('š¦ Copying presets...');
|
|
293
|
-
|
|
294
|
-
const presetsSrc = path.join(packageRoot, 'presets');
|
|
295
|
-
const presetsDest = path.join(distDir, 'presets');
|
|
296
|
-
|
|
297
|
-
if (!fs.existsSync(presetsSrc)) {
|
|
298
|
-
console.log(' No presets directory found');
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
if (fs.existsSync(presetsDest)) {
|
|
303
|
-
fs.rmSync(presetsDest, { recursive: true });
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
fs.mkdirSync(presetsDest, { recursive: true });
|
|
307
|
-
|
|
308
|
-
// Copy all files in presets directory
|
|
309
|
-
const files = fs.readdirSync(presetsSrc);
|
|
310
|
-
let copiedCount = 0;
|
|
311
|
-
|
|
312
|
-
for (const file of files) {
|
|
313
|
-
const srcPath = path.join(presetsSrc, file);
|
|
314
|
-
const destPath = path.join(presetsDest, file);
|
|
315
|
-
|
|
316
|
-
if (fs.statSync(srcPath).isFile()) {
|
|
317
|
-
fs.copyFileSync(srcPath, destPath);
|
|
318
|
-
console.log(` ā ${file}`);
|
|
319
|
-
copiedCount++;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
console.log(`ā
Copied ${copiedCount} preset file(s)\n`);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Recursively find files with a specific extension
|
|
328
|
-
*
|
|
329
|
-
* @param {string} dir - Directory to search
|
|
330
|
-
* @param {string} extension - File extension (e.g., '.ts')
|
|
331
|
-
* @param {string[]} fileList - Accumulator for found files
|
|
332
|
-
* @returns {string[]} Array of file paths
|
|
333
|
-
*/
|
|
334
|
-
async function findFiles(dir, extension, fileList = []) {
|
|
335
|
-
const fs = await import('fs');
|
|
336
|
-
const path = await import('path');
|
|
337
|
-
const files = fs.readdirSync(dir);
|
|
338
|
-
|
|
339
|
-
files.forEach(file => {
|
|
340
|
-
const filePath = path.join(dir, file);
|
|
341
|
-
const stat = fs.statSync(filePath);
|
|
342
|
-
|
|
343
|
-
if (stat.isDirectory() && !['node_modules', 'jux-dist', '.git', 'lib'].includes(file)) {
|
|
344
|
-
findFiles(filePath, extension, fileList);
|
|
345
|
-
} else if (file.endsWith(extension)) {
|
|
346
|
-
fileList.push(filePath);
|
|
347
|
-
}
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
return fileList;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Copy non-TypeScript files (CSS, JSON, JS, SVG, etc.)
|
|
355
|
-
*
|
|
356
|
-
* @param {string} src - Source directory
|
|
357
|
-
* @param {string} dest - Destination directory
|
|
358
|
-
*/
|
|
359
|
-
function copyNonTsFiles(src, dest) {
|
|
360
|
-
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
361
|
-
|
|
362
|
-
for (const entry of entries) {
|
|
363
|
-
const srcPath = path.join(src, entry.name);
|
|
364
|
-
const destPath = path.join(dest, entry.name);
|
|
365
|
-
|
|
366
|
-
if (entry.isDirectory()) {
|
|
367
|
-
if (!fs.existsSync(destPath)) {
|
|
368
|
-
fs.mkdirSync(destPath, { recursive: true });
|
|
369
|
-
}
|
|
370
|
-
copyNonTsFiles(srcPath, destPath);
|
|
371
|
-
} else if (entry.isFile()) {
|
|
372
|
-
const ext = path.extname(entry.name);
|
|
373
|
-
// Copy CSS, JSON, SVG, and JS files (but not .ts files)
|
|
374
|
-
if (['.css', '.json', '.js', '.svg', '.png', '.jpg', '.jpeg', '.gif', '.webp'].includes(ext)) {
|
|
375
|
-
fs.copyFileSync(srcPath, destPath);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* Find project files with specific extensions, excluding certain directories
|
|
383
|
-
*
|
|
384
|
-
* @param {string} dir - Directory to search
|
|
385
|
-
* @param {string[]} extensions - File extensions to find
|
|
386
|
-
* @param {string[]} fileList - Accumulator for found files
|
|
387
|
-
* @param {string} rootDir - Root directory for relative paths
|
|
388
|
-
* @param {string[]} excludeDirs - Directories to exclude
|
|
389
|
-
* @returns {string[]} Array of file paths
|
|
390
|
-
*/
|
|
391
|
-
function findProjectFiles(dir, extensions, fileList = [], rootDir = dir, excludeDirs = ['node_modules', 'jux-dist', '.git', 'lib']) {
|
|
392
|
-
if (!fs.existsSync(dir)) return fileList;
|
|
393
|
-
|
|
394
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
395
|
-
|
|
396
|
-
for (const entry of entries) {
|
|
397
|
-
const fullPath = path.join(dir, entry.name);
|
|
398
|
-
|
|
399
|
-
if (entry.isDirectory()) {
|
|
400
|
-
// Skip excluded directories
|
|
401
|
-
if (excludeDirs.includes(entry.name)) {
|
|
402
|
-
continue;
|
|
403
|
-
}
|
|
404
|
-
findProjectFiles(fullPath, extensions, fileList, rootDir, excludeDirs);
|
|
405
|
-
} else {
|
|
406
|
-
// Check if file has one of the desired extensions
|
|
407
|
-
const hasExtension = extensions.some(ext => entry.name.endsWith(ext));
|
|
408
|
-
if (hasExtension) {
|
|
409
|
-
fileList.push(fullPath);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
return fileList;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* Build a project
|
|
419
|
-
*
|
|
420
|
-
* @param {string} projectRoot - Root directory containing lib/
|
|
421
|
-
* @param {string} distDir - Destination directory for built files
|
|
422
|
-
* @param {Object} options - Compilation options
|
|
423
|
-
* @param {string} options.routePrefix - Route prefix
|
|
424
|
-
* @returns {Promise<{jsOutputPath: string, htmlOutputPath: string}>}
|
|
425
|
-
*/
|
|
426
|
-
export async function buildProject(options = {}) {
|
|
427
|
-
const { projectRoot, distDir } = options;
|
|
428
|
-
|
|
429
|
-
// Ensure project root and dist directory exist
|
|
430
|
-
if (!fs.existsSync(projectRoot)) {
|
|
431
|
-
throw new Error(`Project root directory not found: ${projectRoot}`);
|
|
432
|
-
}
|
|
433
|
-
if (!fs.existsSync(distDir)) {
|
|
434
|
-
fs.mkdirSync(distDir, { recursive: true });
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// Option to use router mode
|
|
438
|
-
if (options.router) {
|
|
439
|
-
console.log('š Building in router mode...\n');
|
|
440
|
-
|
|
441
|
-
await bundleJuxFilesToRouter(projectRoot, distDir, {
|
|
442
|
-
routePrefix: options.routePrefix || ''
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
// Get route information for index generation
|
|
446
|
-
const juxFiles = findFiles(projectRoot, '.jux');
|
|
447
|
-
const routes = juxFiles.map(juxFile => {
|
|
448
|
-
const relativePath = path.relative(projectRoot, juxFile);
|
|
449
|
-
const parsedPath = path.parse(relativePath);
|
|
450
|
-
const functionName = parsedPath.dir
|
|
451
|
-
? `${parsedPath.dir.replace(/\//g, '_')}_${parsedPath.name}`
|
|
452
|
-
: parsedPath.name;
|
|
453
|
-
const routePath = (options.routePrefix || '') + '/' +
|
|
454
|
-
(parsedPath.dir ? `${parsedPath.dir}/` : '') + parsedPath.name;
|
|
455
|
-
return {
|
|
456
|
-
path: routePath.replace(/\/+/g, '/'),
|
|
457
|
-
functionName
|
|
458
|
-
};
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
generateRouterIndex(distDir, routes);
|
|
462
|
-
} else {
|
|
463
|
-
// ...existing individual page compilation...
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// ...existing code...
|
|
467
|
-
}
|