funkophile 0.2.4 → 0.2.5
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/dev.js +59 -0
- package/dist/esm/funkophileHelpers.js +62 -22
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +311 -67
- package/funkophileHelpers.ts +55 -5
- package/index.ts +336 -81
- package/package.json +6 -2
- package/tsconfig.json +2 -1
package/index.ts
CHANGED
|
@@ -4,8 +4,10 @@ import { Action, createStore, Store } from "redux";
|
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import fse from "fs-extra";
|
|
6
6
|
import { glob } from "glob";
|
|
7
|
+
import http from "http";
|
|
7
8
|
import path from "path";
|
|
8
9
|
import Promise from "bluebird";
|
|
10
|
+
import url from "url";
|
|
9
11
|
|
|
10
12
|
export default (funkophileConfig: {
|
|
11
13
|
mode: 'build' | 'watch';
|
|
@@ -13,6 +15,7 @@ export default (funkophileConfig: {
|
|
|
13
15
|
options: {
|
|
14
16
|
inFolder: string;
|
|
15
17
|
outFolder: string;
|
|
18
|
+
port?: number;
|
|
16
19
|
},
|
|
17
20
|
encodings: Record<string, string[]>,
|
|
18
21
|
inputs: Record<string, string>,
|
|
@@ -170,76 +173,218 @@ export default (funkophileConfig: {
|
|
|
170
173
|
Object.keys(funkophileConfig.inputs).reduce((mm, inputKey) => {
|
|
171
174
|
return {
|
|
172
175
|
...mm,
|
|
173
|
-
[inputKey]: createSelector([(x) => x], (root) =>
|
|
176
|
+
[inputKey]: createSelector([(x) => x], (root) => {
|
|
177
|
+
const result = root[inputKey];
|
|
178
|
+
if (result === undefined) {
|
|
179
|
+
throw new Error(
|
|
180
|
+
`Input key "${inputKey}" is undefined in state. ` +
|
|
181
|
+
`This means no files were found for the pattern "${funkophileConfig.inputs[inputKey]}". ` +
|
|
182
|
+
`Available state keys: ${Object.keys(root).join(', ')}`
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
return result;
|
|
186
|
+
}),
|
|
174
187
|
};
|
|
175
188
|
}, {})
|
|
176
189
|
);
|
|
177
190
|
|
|
191
|
+
// Start HTTP server in watch mode
|
|
192
|
+
let server: http.Server | null = null;
|
|
193
|
+
if (funkophileConfig.mode === "watch") {
|
|
194
|
+
const port = funkophileConfig.options.port || 8080;
|
|
195
|
+
server = http.createServer((req, res) => {
|
|
196
|
+
if (!req.url) {
|
|
197
|
+
res.statusCode = 400;
|
|
198
|
+
res.end('Bad Request');
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const parsedUrl = url.parse(req.url);
|
|
203
|
+
let pathname = parsedUrl.pathname;
|
|
204
|
+
|
|
205
|
+
// Default to index.html if the path ends with /
|
|
206
|
+
if (pathname && pathname.endsWith('/')) {
|
|
207
|
+
pathname += 'index.html';
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Remove leading slash
|
|
211
|
+
const filePath = pathname ? pathname.substring(1) : 'index.html';
|
|
212
|
+
|
|
213
|
+
// Construct the full path to the file
|
|
214
|
+
const fullPath = path.join(process.cwd(), funkophileConfig.options.outFolder, filePath);
|
|
215
|
+
|
|
216
|
+
// Check if file exists
|
|
217
|
+
fs.access(fullPath, fs.constants.F_OK, (err) => {
|
|
218
|
+
if (err) {
|
|
219
|
+
// Try with .html extension
|
|
220
|
+
const htmlPath = fullPath + '.html';
|
|
221
|
+
fs.access(htmlPath, fs.constants.F_OK, (htmlErr) => {
|
|
222
|
+
if (htmlErr) {
|
|
223
|
+
// File not found
|
|
224
|
+
res.statusCode = 404;
|
|
225
|
+
res.end('File not found');
|
|
226
|
+
} else {
|
|
227
|
+
// Serve the .html file
|
|
228
|
+
fs.readFile(htmlPath, (readErr, data) => {
|
|
229
|
+
if (readErr) {
|
|
230
|
+
res.statusCode = 500;
|
|
231
|
+
res.end('Internal Server Error');
|
|
232
|
+
} else {
|
|
233
|
+
res.setHeader('Content-Type', 'text/html');
|
|
234
|
+
res.end(data);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
} else {
|
|
240
|
+
// Serve the file
|
|
241
|
+
fs.readFile(fullPath, (readErr, data) => {
|
|
242
|
+
if (readErr) {
|
|
243
|
+
res.statusCode = 500;
|
|
244
|
+
res.end('Internal Server Error');
|
|
245
|
+
} else {
|
|
246
|
+
// Set appropriate content type based on file extension
|
|
247
|
+
const ext = path.extname(fullPath).toLowerCase();
|
|
248
|
+
const contentTypes: Record<string, string> = {
|
|
249
|
+
'.html': 'text/html',
|
|
250
|
+
'.css': 'text/css',
|
|
251
|
+
'.js': 'application/javascript',
|
|
252
|
+
'.json': 'application/json',
|
|
253
|
+
'.png': 'image/png',
|
|
254
|
+
'.jpg': 'image/jpeg',
|
|
255
|
+
'.jpeg': 'image/jpeg',
|
|
256
|
+
'.gif': 'image/gif',
|
|
257
|
+
'.svg': 'image/svg+xml',
|
|
258
|
+
'.ico': 'image/x-icon'
|
|
259
|
+
};
|
|
260
|
+
res.setHeader('Content-Type', contentTypes[ext] || 'application/octet-stream');
|
|
261
|
+
res.end(data);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
server.listen(port, () => {
|
|
269
|
+
console.log(`\u001b[36m\u001b[1m[Funkophile]\u001b[0m Server running at http://localhost:${port}/`);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
178
273
|
// Wait for all the file watchers to check in
|
|
179
274
|
Promise.all(
|
|
180
275
|
Object.keys(funkophileConfig.inputs).map((inputRuleKey) => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
276
|
+
// Ensure the pattern includes the inFolder and is relative to the current working directory
|
|
277
|
+
// Also, make sure to handle patterns that might already include the inFolder
|
|
278
|
+
const pattern = funkophileConfig.inputs[inputRuleKey] || "";
|
|
279
|
+
// For glob, we want the pattern to be relative to process.cwd()
|
|
280
|
+
// Join inFolder and pattern using forward slashes
|
|
281
|
+
const globPattern = path.posix.join(funkophileConfig.options.inFolder, pattern);
|
|
282
|
+
// console.log(`[Funkophile] Looking for files with glob pattern: ${globPattern}`);
|
|
283
|
+
// console.log(`[Funkophile] Current working directory: ${process.cwd()}`);
|
|
186
284
|
|
|
187
285
|
return new Promise((fulfill, reject) => {
|
|
188
286
|
if (funkophileConfig.mode === "build") {
|
|
189
|
-
glob
|
|
287
|
+
// Use the glob pattern we constructed earlier
|
|
288
|
+
// console.log(`[Funkophile] Searching for files matching pattern: ${globPattern}`);
|
|
289
|
+
// console.log(`[Funkophile] Input rule key: ${inputRuleKey}`);
|
|
290
|
+
|
|
291
|
+
glob(globPattern, { cwd: process.cwd() })
|
|
190
292
|
.then((files: string[]) => {
|
|
293
|
+
// console.log(`[Funkophile] Found ${files.length} files for ${inputRuleKey} (pattern: ${pattern}):`, files);
|
|
294
|
+
if (files.length === 0) {
|
|
295
|
+
console.warn(`No files found for input key "${inputRuleKey}" with pattern "${globPattern}"`);
|
|
296
|
+
// console.log(`[Funkophile] The glob pattern used was: ${globPattern}`);
|
|
297
|
+
} else {
|
|
298
|
+
files.forEach((file) => {
|
|
299
|
+
// Make sure the file path is absolute
|
|
300
|
+
const absoluteFilePath = path.resolve(process.cwd(), file);
|
|
301
|
+
// console.log(`[Funkophile] Adding file to state for key ${inputRuleKey}: ${absoluteFilePath}`);
|
|
302
|
+
dispatchUpsert(
|
|
303
|
+
store,
|
|
304
|
+
inputRuleKey,
|
|
305
|
+
absoluteFilePath,
|
|
306
|
+
funkophileConfig.encodings
|
|
307
|
+
);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
})
|
|
311
|
+
.then(() => {
|
|
312
|
+
fulfill();
|
|
313
|
+
})
|
|
314
|
+
.catch((error) => {
|
|
315
|
+
// console.error(`[Funkophile] Error globbing for pattern ${globPattern}:`, error);
|
|
316
|
+
reject(error);
|
|
317
|
+
});
|
|
318
|
+
} else if (funkophileConfig.mode === "watch") {
|
|
319
|
+
// Use the same glob pattern for watch mode
|
|
320
|
+
// console.log(`[Funkophile] Watching for files matching pattern: ${globPattern}`);
|
|
321
|
+
|
|
322
|
+
// First, use glob to find existing files to ensure they're added to the state
|
|
323
|
+
glob(globPattern, { cwd: process.cwd() })
|
|
324
|
+
.then((files: string[]) => {
|
|
325
|
+
// console.log(`[Funkophile] Found ${files.length} existing files for ${inputRuleKey} (pattern: ${pattern}):`, files);
|
|
191
326
|
files.forEach((file) => {
|
|
327
|
+
const absoluteFilePath = path.resolve(process.cwd(), file);
|
|
328
|
+
// console.log(`[Funkophile] Adding existing file to state for key ${inputRuleKey}: ${absoluteFilePath}`);
|
|
192
329
|
dispatchUpsert(
|
|
193
330
|
store,
|
|
194
331
|
inputRuleKey,
|
|
195
|
-
|
|
332
|
+
absoluteFilePath,
|
|
196
333
|
funkophileConfig.encodings
|
|
197
334
|
);
|
|
198
335
|
});
|
|
336
|
+
|
|
337
|
+
// Now set up the watcher
|
|
338
|
+
const watcher = chokidar
|
|
339
|
+
.watch(globPattern, {
|
|
340
|
+
cwd: process.cwd(),
|
|
341
|
+
ignoreInitial: true // We've already handled initial files above
|
|
342
|
+
})
|
|
343
|
+
.on("error", (error) => {
|
|
344
|
+
logger.watchError(globPattern);
|
|
345
|
+
})
|
|
346
|
+
.on("ready", () => {
|
|
347
|
+
logger.watchReady(globPattern);
|
|
348
|
+
fulfill();
|
|
349
|
+
})
|
|
350
|
+
.on("add", (filePath) => {
|
|
351
|
+
logger.watchAdd(filePath);
|
|
352
|
+
const absoluteFilePath = path.resolve(process.cwd(), filePath);
|
|
353
|
+
dispatchUpsert(
|
|
354
|
+
store,
|
|
355
|
+
inputRuleKey,
|
|
356
|
+
absoluteFilePath,
|
|
357
|
+
funkophileConfig.encodings
|
|
358
|
+
);
|
|
359
|
+
})
|
|
360
|
+
.on("change", (filePath) => {
|
|
361
|
+
logger.watchChange(filePath);
|
|
362
|
+
const absoluteFilePath = path.resolve(process.cwd(), filePath);
|
|
363
|
+
dispatchUpsert(
|
|
364
|
+
store,
|
|
365
|
+
inputRuleKey,
|
|
366
|
+
absoluteFilePath,
|
|
367
|
+
funkophileConfig.encodings
|
|
368
|
+
);
|
|
369
|
+
})
|
|
370
|
+
.on("unlink", (filePath) => {
|
|
371
|
+
logger.watchUnlink(filePath);
|
|
372
|
+
const absoluteFilePath = path.resolve(process.cwd(), filePath);
|
|
373
|
+
store.dispatch({
|
|
374
|
+
type: REMOVE,
|
|
375
|
+
payload: {
|
|
376
|
+
key: inputRuleKey,
|
|
377
|
+
file: absoluteFilePath,
|
|
378
|
+
},
|
|
379
|
+
});
|
|
380
|
+
})
|
|
381
|
+
.on("unlinkDir", (filePath) => {
|
|
382
|
+
logger.watchUnlink(filePath);
|
|
383
|
+
});
|
|
199
384
|
})
|
|
200
|
-
.
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
} else if (funkophileConfig.mode === "watch") {
|
|
204
|
-
chokidar
|
|
205
|
-
.watch(p, {})
|
|
206
|
-
.on("error", (error) => {
|
|
207
|
-
logger.watchError(p);
|
|
208
|
-
})
|
|
209
|
-
.on("ready", () => {
|
|
210
|
-
logger.watchReady(p);
|
|
211
|
-
fulfill();
|
|
212
|
-
})
|
|
213
|
-
.on("add", (p) => {
|
|
214
|
-
logger.watchAdd(p);
|
|
215
|
-
dispatchUpsert(
|
|
216
|
-
store,
|
|
217
|
-
inputRuleKey,
|
|
218
|
-
p,
|
|
219
|
-
funkophileConfig.encodings
|
|
220
|
-
);
|
|
221
|
-
})
|
|
222
|
-
.on("change", (p) => {
|
|
223
|
-
logger.watchChange(p);
|
|
224
|
-
dispatchUpsert(
|
|
225
|
-
store,
|
|
226
|
-
inputRuleKey,
|
|
227
|
-
p,
|
|
228
|
-
funkophileConfig.encodings
|
|
229
|
-
);
|
|
230
|
-
})
|
|
231
|
-
.on("unlink", (p) => {
|
|
232
|
-
logger.watchUnlink(p);
|
|
233
|
-
store.dispatch({
|
|
234
|
-
type: REMOVE,
|
|
235
|
-
payload: {
|
|
236
|
-
key: inputRuleKey,
|
|
237
|
-
file: p,
|
|
238
|
-
},
|
|
239
|
-
});
|
|
240
|
-
})
|
|
241
|
-
.on("unlinkDir", (p) => {
|
|
242
|
-
logger.watchUnlink(p);
|
|
385
|
+
.catch((error) => {
|
|
386
|
+
console.error(`[Funkophile] Error globbing for pattern ${globPattern}:`, error);
|
|
387
|
+
reject(error);
|
|
243
388
|
});
|
|
244
389
|
// .on('raw', (event, p, details) => { // internal
|
|
245
390
|
// log('Raw event info:', event, p, details);
|
|
@@ -253,15 +398,57 @@ export default (funkophileConfig: {
|
|
|
253
398
|
});
|
|
254
399
|
})
|
|
255
400
|
).then(function () {
|
|
401
|
+
// console.log('\u001b[36m\u001b[1m[Funkophile]\u001b[0m All input files processed. Setting up store subscription...');
|
|
402
|
+
|
|
403
|
+
// Debug: log the current state after all files are processed
|
|
404
|
+
const currentState = store.getState();
|
|
405
|
+
console.log('\u001b[36m\u001b[1m[Funkophile]\u001b[0m Current state keys:', Object.keys(currentState));
|
|
406
|
+
// Log all input keys to see if they're present
|
|
407
|
+
Object.keys(funkophileConfig.inputs).forEach(inputKey => {
|
|
408
|
+
if (currentState[inputKey]) {
|
|
409
|
+
// console.log(`[Funkophile] Input key "${inputKey}" found in state with ${Object.keys(currentState[inputKey]).length} files`);
|
|
410
|
+
} else {
|
|
411
|
+
throw(`Input key "${inputKey}" NOT found in state`);
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
|
|
256
415
|
// listen for changes to the store
|
|
257
416
|
store.subscribe(() => {
|
|
258
417
|
const s = store.getState();
|
|
418
|
+
|
|
419
|
+
// Skip processing during initial load
|
|
420
|
+
if (s.initialLoad) {
|
|
421
|
+
console.log('\u001b[36m\u001b[1m[Funkophile]\u001b[0m Initial load in progress, skipping processing...');
|
|
422
|
+
console.log('\u001b[36m\u001b[1m[Funkophile]\u001b[0m State keys during initial load:', Object.keys(s));
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
259
425
|
|
|
260
426
|
logger.stateChange();
|
|
261
|
-
|
|
427
|
+
console.log('\u001b[36m\u001b[1m[Funkophile]\u001b[0m Processing state changes...');
|
|
428
|
+
|
|
429
|
+
let outputs;
|
|
430
|
+
try {
|
|
431
|
+
outputs = finalSelector(s);
|
|
432
|
+
console.log(`\u001b[36m\u001b[1m[Funkophile]\u001b[0m Generated ${Object.keys(outputs).length} outputs`);
|
|
433
|
+
} catch (error) {
|
|
434
|
+
console.error('\u001b[31m\u001b[1m[Funkophile]\u001b[0m FATAL: Error in output selector chain:');
|
|
435
|
+
console.error(' Error:', error.message);
|
|
436
|
+
console.error(' Stack:', error.stack);
|
|
437
|
+
// Don't exit the process in watch mode, just log the error and continue
|
|
438
|
+
if (funkophileConfig.mode === 'build') {
|
|
439
|
+
process.exit(1);
|
|
440
|
+
} else {
|
|
441
|
+
console.log('\u001b[33m\u001b[1m[Funkophile]\u001b[0m Continuing to watch for changes despite error...');
|
|
442
|
+
// Reset previousState to empty to ensure we try processing again on next change
|
|
443
|
+
Object.keys(previousState).forEach(key => {
|
|
444
|
+
delete previousState[key];
|
|
445
|
+
});
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
262
449
|
|
|
263
450
|
if (outputPromise.isPending()) {
|
|
264
|
-
console.log("
|
|
451
|
+
console.log("\u001b[33m\u001b[1m[Funkophile]\u001b[0m Cancelling previous write operation!");
|
|
265
452
|
outputPromise.cancel();
|
|
266
453
|
}
|
|
267
454
|
|
|
@@ -273,6 +460,7 @@ export default (funkophileConfig: {
|
|
|
273
460
|
if (!outputs[key]) {
|
|
274
461
|
const file = funkophileConfig.options.outFolder + "/" + key;
|
|
275
462
|
logger.removedFile(file);
|
|
463
|
+
console.log(`\u001b[31m\u001b[1m[Funkophile]\u001b[0m Removing file: ${file}`);
|
|
276
464
|
|
|
277
465
|
try {
|
|
278
466
|
fse.unlinkSync("./" + file);
|
|
@@ -280,14 +468,12 @@ export default (funkophileConfig: {
|
|
|
280
468
|
"./" + file.substring(0, file.lastIndexOf("/"))
|
|
281
469
|
);
|
|
282
470
|
} catch (ex) {
|
|
283
|
-
//
|
|
284
|
-
|
|
471
|
+
// Log error but don't fail the entire process
|
|
472
|
+
console.error(`\u001b[31m\u001b[1m[Funkophile]\u001b[0m Error removing file ${file}:`, ex.message);
|
|
285
473
|
} finally {
|
|
286
|
-
|
|
287
|
-
|
|
474
|
+
delete previousState[key];
|
|
475
|
+
fulfill();
|
|
288
476
|
}
|
|
289
|
-
// delete previousState[key]
|
|
290
|
-
// fulfill()
|
|
291
477
|
} else {
|
|
292
478
|
if (outputs[key] !== previousState[key]) {
|
|
293
479
|
previousState[key] = outputs[key];
|
|
@@ -296,77 +482,146 @@ export default (funkophileConfig: {
|
|
|
296
482
|
"./" + funkophileConfig.options.outFolder + "/" + key;
|
|
297
483
|
const contents = outputs[key];
|
|
298
484
|
|
|
485
|
+
// console.log(`\u001b[32m\u001b[1m[Funkophile]\u001b[0m Writing file: ${relativeFilePath}`);
|
|
486
|
+
|
|
299
487
|
if (typeof contents === "function") {
|
|
300
488
|
logger.writingFunction(relativeFilePath);
|
|
301
489
|
contents((err, res) => {
|
|
302
|
-
|
|
303
|
-
|
|
490
|
+
if (err) {
|
|
491
|
+
logger.writingError(relativeFilePath, err.message);
|
|
492
|
+
fulfill(); // Still fulfill to continue processing other files
|
|
493
|
+
} else {
|
|
494
|
+
fse.outputFile(relativeFilePath, res, (err) => {
|
|
495
|
+
if (err) {
|
|
496
|
+
logger.writingError(relativeFilePath, err.message);
|
|
497
|
+
fulfill(); // Still fulfill to continue processing other files
|
|
498
|
+
} else {
|
|
499
|
+
logger.writingString(relativeFilePath);
|
|
500
|
+
fulfill();
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
}
|
|
304
504
|
});
|
|
305
505
|
} else if (typeof contents === "string") {
|
|
306
|
-
fse.outputFile(relativeFilePath, contents,
|
|
307
|
-
|
|
506
|
+
fse.outputFile(relativeFilePath, contents, (err) => {
|
|
507
|
+
if (err) {
|
|
508
|
+
logger.writingError(relativeFilePath, err.message);
|
|
509
|
+
fulfill();
|
|
510
|
+
} else {
|
|
511
|
+
logger.writingString(relativeFilePath);
|
|
512
|
+
fulfill();
|
|
513
|
+
}
|
|
514
|
+
});
|
|
308
515
|
} else if (Buffer.isBuffer(contents)) {
|
|
309
|
-
fse.outputFile(relativeFilePath, contents,
|
|
310
|
-
|
|
516
|
+
fse.outputFile(relativeFilePath, contents, (err) => {
|
|
517
|
+
if (err) {
|
|
518
|
+
logger.writingError(relativeFilePath, err.message);
|
|
519
|
+
fulfill();
|
|
520
|
+
} else {
|
|
521
|
+
logger.writingString(relativeFilePath);
|
|
522
|
+
fulfill();
|
|
523
|
+
}
|
|
524
|
+
});
|
|
311
525
|
} else if (Array.isArray(contents)) {
|
|
312
526
|
fse.outputFile(
|
|
313
527
|
relativeFilePath,
|
|
314
528
|
JSON.stringify(contents),
|
|
315
|
-
|
|
529
|
+
(err) => {
|
|
530
|
+
if (err) {
|
|
531
|
+
logger.writingError(relativeFilePath, err.message);
|
|
532
|
+
fulfill();
|
|
533
|
+
} else {
|
|
534
|
+
logger.writingString(relativeFilePath);
|
|
535
|
+
fulfill();
|
|
536
|
+
}
|
|
537
|
+
}
|
|
316
538
|
);
|
|
317
|
-
logger.writingString(relativeFilePath);
|
|
318
539
|
} else if (typeof contents.then === "function") {
|
|
319
540
|
logger.writingPromise(relativeFilePath);
|
|
320
541
|
Promise.resolve(contents).then(
|
|
321
542
|
function (value) {
|
|
322
543
|
if (value instanceof Error) {
|
|
323
544
|
logger.writingError(relativeFilePath, value.message);
|
|
545
|
+
fulfill();
|
|
324
546
|
} else {
|
|
325
|
-
fse.outputFile(relativeFilePath, value,
|
|
326
|
-
|
|
547
|
+
fse.outputFile(relativeFilePath, value, (err) => {
|
|
548
|
+
if (err) {
|
|
549
|
+
logger.writingError(relativeFilePath, err.message);
|
|
550
|
+
fulfill();
|
|
551
|
+
} else {
|
|
552
|
+
logger.writingString(relativeFilePath);
|
|
553
|
+
fulfill();
|
|
554
|
+
}
|
|
555
|
+
});
|
|
327
556
|
}
|
|
328
557
|
},
|
|
329
|
-
function (
|
|
330
|
-
|
|
558
|
+
function (error) {
|
|
559
|
+
logger.writingError(relativeFilePath, error.message);
|
|
560
|
+
fulfill();
|
|
331
561
|
}
|
|
332
562
|
);
|
|
333
563
|
} else {
|
|
334
564
|
console.log(
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
typeof contents,
|
|
338
|
-
contents
|
|
565
|
+
`\u001b[33m\u001b[1m[Funkophile]\u001b[0m Unrecognized content type for ${relativeFilePath}, attempting to write:`,
|
|
566
|
+
typeof contents
|
|
339
567
|
);
|
|
340
|
-
fse.outputFile(relativeFilePath, contents,
|
|
341
|
-
|
|
568
|
+
fse.outputFile(relativeFilePath, contents, (err) => {
|
|
569
|
+
if (err) {
|
|
570
|
+
logger.writingError(relativeFilePath, err.message);
|
|
571
|
+
fulfill();
|
|
572
|
+
} else {
|
|
573
|
+
logger.writingString(relativeFilePath);
|
|
574
|
+
fulfill();
|
|
575
|
+
}
|
|
576
|
+
});
|
|
342
577
|
}
|
|
343
578
|
} else {
|
|
579
|
+
// console.log(`\u001b[90m\u001b[1m[Funkophile]\u001b[0m Skipping unchanged file: ${key}`);
|
|
344
580
|
fulfill();
|
|
345
581
|
}
|
|
346
582
|
}
|
|
347
583
|
});
|
|
348
584
|
})
|
|
349
585
|
).then(() => {
|
|
586
|
+
// console.log('\u001b[36m\u001b[1m[Funkophile]\u001b[0m Cleaning empty folders...');
|
|
350
587
|
cleanEmptyFoldersRecursively(funkophileConfig.options.outFolder);
|
|
351
588
|
|
|
352
589
|
if (funkophileConfig.mode === "build") {
|
|
590
|
+
console.log('\u001b[32m\u001b[1m[Funkophile]\u001b[0m Build completed successfully!');
|
|
353
591
|
logger.done();
|
|
354
592
|
} else if (funkophileConfig.mode === "watch") {
|
|
593
|
+
console.log('\u001b[36m\u001b[1m[Funkophile]\u001b[0m Watching for file changes...');
|
|
594
|
+
// Log the localhost URL if port is specified
|
|
595
|
+
const port = funkophileConfig.options.port || 8080;
|
|
596
|
+
console.log(`\u001b[36m\u001b[1m[Funkophile]\u001b[0m Serving at: http://localhost:${port}/`);
|
|
355
597
|
logger.waiting();
|
|
356
598
|
} else {
|
|
357
|
-
|
|
358
|
-
|
|
599
|
+
throw (
|
|
600
|
+
`\u001b[31m\u001b[1m[Funkophile]\u001b[0m The mode should be 'watch' or 'build', not "${funkophileConfig.mode}"`
|
|
359
601
|
);
|
|
360
|
-
|
|
602
|
+
|
|
361
603
|
}
|
|
362
|
-
})
|
|
604
|
+
})
|
|
605
|
+
// .catch((error) => {
|
|
606
|
+
// // console.error('\u001b[31m\u001b[1m[Funkophile]\u001b[0m Error during file operations:', error);
|
|
607
|
+
// });
|
|
363
608
|
});
|
|
364
609
|
|
|
610
|
+
// console.log('\u001b[36m\u001b[1m[Funkophile]\u001b[0m Initializing store...');
|
|
365
611
|
// lastly, turn the store `on`.
|
|
366
612
|
// This is to prevent unecessary recomputations when initialy adding files to redux
|
|
367
613
|
store.dispatch({
|
|
368
614
|
type: INITIALIZE,
|
|
369
615
|
payload: true,
|
|
370
616
|
});
|
|
617
|
+
// console.log('\u001b[36m\u001b[1m[Funkophile]\u001b[0m Store initialized. Starting processing...');
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
// Handle process exit to close the server
|
|
621
|
+
process.on('SIGINT', () => {
|
|
622
|
+
if (server) {
|
|
623
|
+
server.close();
|
|
624
|
+
}
|
|
625
|
+
process.exit(0);
|
|
371
626
|
});
|
|
372
627
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "funkophile",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"repository": "git@github.com:adamwong246/funkophile.git",
|
|
5
5
|
"author": "adam wong <adamwong246@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"main": "./dist/esm.index.js",
|
|
13
13
|
"types": "./dist/esm/index.d.ts",
|
|
14
14
|
"scripts": {
|
|
15
|
-
"transpile": "tsc --project tsconfig.json
|
|
15
|
+
"transpile": "tsc --project tsconfig.json",
|
|
16
|
+
"dev": "tsc --watch --project tsconfig.json"
|
|
16
17
|
},
|
|
17
18
|
"dependencies": {
|
|
18
19
|
"@tsconfig/node-lts-strictest-esm": "^18.12.1",
|
|
@@ -28,6 +29,9 @@
|
|
|
28
29
|
"tsc": "^2.0.4",
|
|
29
30
|
"typescript": "^5.8.2"
|
|
30
31
|
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"chokidar-cli": "^3.0.0"
|
|
34
|
+
},
|
|
31
35
|
"exports": {
|
|
32
36
|
".": {
|
|
33
37
|
"types": "./dist/esm/index.d.ts",
|