@cocreate/file 1.19.6 → 1.21.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.
- package/CHANGELOG.md +22 -0
- package/package.json +1 -1
- package/src/client.js +1 -1
- package/src/server.js +315 -211
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
# [1.21.0](https://github.com/CoCreate-app/CoCreate-file/compare/v1.20.0...v1.21.0) (2025-11-16)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* enhance file processing by adding support for include/exclude filters and implementing dynamic data retrieval for various file types ([d8a2185](https://github.com/CoCreate-app/CoCreate-file/commit/d8a2185ce6f9554aa929f285e24526a281bc0b96))
|
|
7
|
+
|
|
8
|
+
# [1.20.0](https://github.com/CoCreate-app/CoCreate-file/compare/v1.19.6...v1.20.0) (2025-10-11)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* add error handling for translation service in file function ([262dc66](https://github.com/CoCreate-app/CoCreate-file/commit/262dc66d57c13a8948ef1afa863413c203f965bc))
|
|
14
|
+
* update import statement and modify exit behavior in server function ([6e72fde](https://github.com/CoCreate-app/CoCreate-file/commit/6e72fdec3867c031e342b3faef598b661f43a620))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* add options parameter to file function for enhanced translation support ([7fac13d](https://github.com/CoCreate-app/CoCreate-file/commit/7fac13d10b8abd40584d5abc6b89d110f84db288))
|
|
20
|
+
* enhance file handling by supporting base64 encoding for binary sources and improving file reading logic ([192337c](https://github.com/CoCreate-app/CoCreate-file/commit/192337c3a44d412f8a8d2c6bb1172451661eebf5))
|
|
21
|
+
* enhance file processing with support for base64 and binary types, and add variable processing functionality ([eabfddf](https://github.com/CoCreate-app/CoCreate-file/commit/eabfddf2e1c36e7abd330369c1f28f90290cc1b8))
|
|
22
|
+
|
|
1
23
|
## [1.19.6](https://github.com/CoCreate-app/CoCreate-file/compare/v1.19.5...v1.19.6) (2025-09-07)
|
|
2
24
|
|
|
3
25
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocreate/file",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0",
|
|
4
4
|
"description": "A versatile, configurable headless file uploader supporting local and server operations. Accessible via a JavaScript API and HTML5 attributes, it provides seamless file reading, writing, and uploading with fallbacks to the standard HTML5 file input API. Ideal for developers needing robust file management in headless environments.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"file-uploader",
|
package/src/client.js
CHANGED
|
@@ -28,7 +28,7 @@ import Elements from "@cocreate/elements";
|
|
|
28
28
|
import Actions from "@cocreate/actions";
|
|
29
29
|
import { render } from "@cocreate/render";
|
|
30
30
|
import { queryElements } from "@cocreate/utils";
|
|
31
|
-
import "@cocreate/element-prototype";
|
|
31
|
+
import { setValue } from "@cocreate/element-prototype";
|
|
32
32
|
|
|
33
33
|
const inputs = new Map();
|
|
34
34
|
const Files = new Map();
|
package/src/server.js
CHANGED
|
@@ -4,6 +4,7 @@ const fs = require("fs");
|
|
|
4
4
|
const realpathAsync = fs.promises.realpath;
|
|
5
5
|
|
|
6
6
|
const path = require("path");
|
|
7
|
+
const { pathToFileURL } = require("url");
|
|
7
8
|
const mimeTypes = {
|
|
8
9
|
".aac": "audio/aac",
|
|
9
10
|
".abw": "application/x-abiword",
|
|
@@ -83,7 +84,12 @@ const mimeTypes = {
|
|
|
83
84
|
".7z": "application/x-7z-compressed"
|
|
84
85
|
};
|
|
85
86
|
|
|
86
|
-
module.exports = async function file(
|
|
87
|
+
module.exports = async function file(
|
|
88
|
+
CoCreateConfig,
|
|
89
|
+
configPath,
|
|
90
|
+
match,
|
|
91
|
+
options
|
|
92
|
+
) {
|
|
87
93
|
let directories = CoCreateConfig.directories;
|
|
88
94
|
let sources = CoCreateConfig.sources;
|
|
89
95
|
let configDirectoryPath = path.dirname(configPath);
|
|
@@ -169,46 +175,60 @@ module.exports = async function file(CoCreateConfig, configPath, match) {
|
|
|
169
175
|
async function runDirectories() {
|
|
170
176
|
for (const directory of directories) {
|
|
171
177
|
const entry = directory.entry;
|
|
172
|
-
|
|
173
|
-
await runFiles(directory, entry, exclude);
|
|
178
|
+
await runFiles(directory, entry);
|
|
174
179
|
}
|
|
175
180
|
return;
|
|
176
181
|
}
|
|
177
182
|
|
|
178
|
-
async function runFiles(directory, entry,
|
|
183
|
+
async function runFiles(directory, entry, Path, directoryName) {
|
|
179
184
|
const entryPath = path.resolve(configDirectoryPath, entry);
|
|
180
185
|
let files = fs.readdirSync(entryPath);
|
|
181
|
-
|
|
186
|
+
let exclude = directory.exclude || [];
|
|
187
|
+
let include = directory.include || [];
|
|
182
188
|
for (let file of files) {
|
|
183
|
-
|
|
184
|
-
for (let i = 0; i < exclude.length; i++) {
|
|
185
|
-
if (file.includes(exclude[i])) {
|
|
186
|
-
skip = true;
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
if (skip) continue;
|
|
189
|
+
const filePath = path.resolve(entryPath, file);
|
|
191
190
|
|
|
192
191
|
let isDirectory;
|
|
193
192
|
let isSymlink = fs
|
|
194
|
-
.lstatSync(
|
|
193
|
+
.lstatSync(filePath)
|
|
195
194
|
.isSymbolicLink();
|
|
196
195
|
if (isSymlink) {
|
|
197
|
-
let symlinkPath = await realpathAsync(
|
|
196
|
+
let symlinkPath = await realpathAsync(filePath);
|
|
198
197
|
isDirectory =
|
|
199
198
|
fs.existsSync(symlinkPath) &&
|
|
200
199
|
fs.lstatSync(symlinkPath).isDirectory();
|
|
201
200
|
} else
|
|
202
201
|
isDirectory =
|
|
203
|
-
fs.existsSync(
|
|
204
|
-
fs.lstatSync(
|
|
202
|
+
fs.existsSync(filePath) &&
|
|
203
|
+
fs.lstatSync(filePath).isDirectory();
|
|
204
|
+
|
|
205
|
+
let skip = false;
|
|
206
|
+
for (let i = 0; i < exclude.length; i++) {
|
|
207
|
+
if (filePath.includes(exclude[i])) {
|
|
208
|
+
skip = true;
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
for (let i = 0; i < include.length; i++) {
|
|
214
|
+
if (filePath.includes(include[i])) {
|
|
215
|
+
skip = false;
|
|
216
|
+
break;
|
|
217
|
+
} else if (isDirectory) {
|
|
218
|
+
skip = "directory";
|
|
219
|
+
break;
|
|
220
|
+
} else {
|
|
221
|
+
skip = true;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (skip === true) continue;
|
|
205
226
|
|
|
206
227
|
let name = file;
|
|
207
228
|
let source = "";
|
|
208
229
|
|
|
209
230
|
for (let i = 0; i < match.length; i++) {
|
|
210
231
|
skip = true;
|
|
211
|
-
const filePath = path.resolve(entryPath, file);
|
|
212
232
|
if (filePath.startsWith(match[i])) {
|
|
213
233
|
skip = false;
|
|
214
234
|
break;
|
|
@@ -232,7 +252,7 @@ module.exports = async function file(CoCreateConfig, configPath, match) {
|
|
|
232
252
|
} else directoryName = "/";
|
|
233
253
|
}
|
|
234
254
|
|
|
235
|
-
if (exclude && exclude.includes(directoryName)) continue;
|
|
255
|
+
// if (exclude && exclude.includes(directoryName)) continue;
|
|
236
256
|
|
|
237
257
|
if (!Path) {
|
|
238
258
|
if (directoryName === "/") Path = directoryName;
|
|
@@ -243,76 +263,136 @@ module.exports = async function file(CoCreateConfig, configPath, match) {
|
|
|
243
263
|
if (Path === "/") pathname = Path + name;
|
|
244
264
|
else pathname = Path + "/" + name;
|
|
245
265
|
|
|
246
|
-
if (isDirectory)
|
|
247
|
-
|
|
266
|
+
if (isDirectory) {
|
|
267
|
+
mimeType = "text/directory";
|
|
268
|
+
} else {
|
|
248
269
|
source = await getSource(
|
|
249
270
|
`${entryPath}/${file}`,
|
|
250
271
|
mimeType,
|
|
251
272
|
isSymlink
|
|
252
273
|
);
|
|
274
|
+
}
|
|
253
275
|
|
|
254
276
|
let values = {
|
|
255
277
|
"{{name}}": name || "",
|
|
256
|
-
"{{source}}": source || "",
|
|
278
|
+
"{{source}}": Buffer.isBuffer(source) ? `data:${mimeType};base64,${source.toString('base64')}` : source || "",
|
|
257
279
|
"{{directory}}": directoryName || "",
|
|
258
280
|
"{{path}}": Path || "",
|
|
259
281
|
"{{pathname}}": pathname,
|
|
260
|
-
"{{content-type}}": mimeType || ""
|
|
282
|
+
"{{content-type}}": mimeType || "",
|
|
261
283
|
};
|
|
262
284
|
|
|
263
|
-
let
|
|
264
|
-
|
|
265
|
-
if (!object.src) object.src = "{{source}}";
|
|
266
|
-
if (!object.directory) object.directory = "{{directory}}";
|
|
267
|
-
if (!object.path) object.path = "{{path}}";
|
|
268
|
-
if (!object.pathname) object.pathname = "{{pathname}}";
|
|
269
|
-
if (!object["content-type"])
|
|
270
|
-
object["content-type"] = "{{content-type}}";
|
|
271
|
-
if (
|
|
272
|
-
!object.public &&
|
|
273
|
-
object.public != false &&
|
|
274
|
-
object.public != "false"
|
|
275
|
-
)
|
|
276
|
-
object.public = "true";
|
|
277
|
-
|
|
278
|
-
let newObject = {
|
|
279
|
-
array: directory.array || "files",
|
|
280
|
-
object
|
|
285
|
+
let data = {
|
|
286
|
+
array: directory.array || "files"
|
|
281
287
|
};
|
|
282
288
|
|
|
283
|
-
|
|
284
|
-
if (directory
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
289
|
+
let isData = false;
|
|
290
|
+
if ( typeof directory.$data === "string") {
|
|
291
|
+
if (isDirectory) {
|
|
292
|
+
skip = "directory";
|
|
293
|
+
} else {
|
|
294
|
+
isData = true;
|
|
295
|
+
data = await getData(
|
|
296
|
+
`${entryPath}/${file}`,
|
|
297
|
+
mimeType,
|
|
298
|
+
isSymlink
|
|
299
|
+
);
|
|
300
|
+
if (!data) continue
|
|
301
|
+
}
|
|
302
|
+
} else if ( typeof directory.object === "string") {
|
|
303
|
+
if (isDirectory) {
|
|
304
|
+
skip = "directory";
|
|
305
|
+
} else {
|
|
306
|
+
isData = true;
|
|
307
|
+
data.object = await getData(
|
|
308
|
+
`${entryPath}/${file}`,
|
|
309
|
+
mimeType,
|
|
310
|
+
isSymlink
|
|
291
311
|
);
|
|
292
|
-
if (
|
|
293
|
-
for (let variable of variables) {
|
|
294
|
-
newObject.object[key] = newObject.object[
|
|
295
|
-
key
|
|
296
|
-
].replace(variable, values[variable]);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
312
|
+
if (!data.object) continue
|
|
299
313
|
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
if (!
|
|
304
|
-
|
|
314
|
+
} else if (typeof directory.object === "object" && directory.object !== null) {
|
|
315
|
+
data.array = directory.array || "files";
|
|
316
|
+
let object = { ...directory.object };
|
|
317
|
+
if (!object.name) object.name = "{{name}}";
|
|
318
|
+
if (!object.src) object.src = "{{source}}";
|
|
319
|
+
if (!object.directory) object.directory = "{{directory}}";
|
|
320
|
+
if (!object.path) object.path = "{{path}}";
|
|
321
|
+
if (!object.pathname) object.pathname = "{{pathname}}";
|
|
322
|
+
if (!object["content-type"])
|
|
323
|
+
object["content-type"] = "{{content-type}}";
|
|
324
|
+
if (
|
|
325
|
+
!object.public &&
|
|
326
|
+
object.public != false &&
|
|
327
|
+
object.public != "false"
|
|
328
|
+
)
|
|
329
|
+
object.public = "true";
|
|
330
|
+
|
|
331
|
+
data.object = object;
|
|
332
|
+
|
|
333
|
+
if (!data.object._id) {
|
|
334
|
+
data.$filter = {
|
|
305
335
|
query: {
|
|
306
336
|
pathname
|
|
307
337
|
}
|
|
308
338
|
};
|
|
339
|
+
}
|
|
309
340
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
341
|
+
if (
|
|
342
|
+
options.translate &&
|
|
343
|
+
mimeType === "text/html" &&
|
|
344
|
+
Array.isArray(directory.languages) &&
|
|
345
|
+
!object.translations
|
|
346
|
+
) {
|
|
347
|
+
try {
|
|
348
|
+
// Call your AI translation service
|
|
349
|
+
const translations = await options.translate(
|
|
350
|
+
Buffer.isBuffer(source) ? source.toString('utf-8') : source,
|
|
351
|
+
directory.languages
|
|
352
|
+
);
|
|
353
|
+
data.object.translations = translations;
|
|
354
|
+
} catch (err) {
|
|
355
|
+
console.error("Translation error:", err);
|
|
356
|
+
// Continue without translations
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (directory.storage) data.storage = directory.storage;
|
|
361
|
+
if (directory.database) data.database = directory.database;
|
|
362
|
+
if (directory.array) data.array = directory.array || "files";
|
|
363
|
+
|
|
364
|
+
for (const key of Object.keys(directory.object)) {
|
|
365
|
+
if (typeof directory.object[key] == "string") {
|
|
366
|
+
let variables = directory.object[key].match(
|
|
367
|
+
/{{([A-Za-z0-9_.,\[\]\-\/ ]*)}}/g
|
|
368
|
+
);
|
|
369
|
+
if (variables) {
|
|
370
|
+
for (let variable of variables) {
|
|
371
|
+
let replacement = values[variable];
|
|
372
|
+
if (key === 'src' && variable === '{{source}}' && Buffer.isBuffer(source)) {
|
|
373
|
+
replacement = `data:${mimeType};base64,${source.toString('base64')}`;
|
|
374
|
+
}
|
|
375
|
+
data.object[key] = data.object[
|
|
376
|
+
key
|
|
377
|
+
].replace(variable, replacement);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
315
383
|
|
|
384
|
+
if (skip !== "directory") {
|
|
385
|
+
response = await runStore(data);
|
|
386
|
+
if (isData) {
|
|
387
|
+
console.log(
|
|
388
|
+
`Saved: ${entryPath}/${file}`
|
|
389
|
+
);
|
|
390
|
+
} else {
|
|
391
|
+
console.log(
|
|
392
|
+
`Uploaded: ${entryPath}/${file}`,
|
|
393
|
+
`To: ${pathname}`
|
|
394
|
+
);
|
|
395
|
+
}
|
|
316
396
|
if (response.error) errorLog.push(response.error);
|
|
317
397
|
}
|
|
318
398
|
|
|
@@ -321,151 +401,195 @@ module.exports = async function file(CoCreateConfig, configPath, match) {
|
|
|
321
401
|
if (entry.endsWith("/")) newEntry = entry + name;
|
|
322
402
|
else newEntry = entry + "/" + name;
|
|
323
403
|
|
|
324
|
-
await runFiles(directory, newEntry,
|
|
404
|
+
await runFiles(directory, newEntry, pathname, name);
|
|
325
405
|
}
|
|
326
406
|
}
|
|
327
407
|
// if (errorLog.length)
|
|
328
408
|
// console.log(...errorLog)
|
|
329
409
|
}
|
|
330
410
|
|
|
331
|
-
async function getSource(
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
411
|
+
async function getSource(filePath, mimeType, isSymlink) {
|
|
412
|
+
// 1. UPDATED: Includes standard font types and uses simpler matching
|
|
413
|
+
const base64MimeTypes = /^(image|audio|video|font\/(woff2?|ttf|otf|eot)|application\/vnd\.ms-fontobject|application\/x-font-.*|application\/octet-stream)/;
|
|
414
|
+
|
|
415
|
+
// We only care if it needs to be Base64-encoded for a Data URI.
|
|
416
|
+
const needsBase64 = base64MimeTypes.test(mimeType);
|
|
417
|
+
|
|
418
|
+
let resolvedPath = filePath;
|
|
419
|
+
if (isSymlink) {
|
|
420
|
+
// Use promises for realpath
|
|
421
|
+
resolvedPath = await realpathAsync(filePath);
|
|
337
422
|
}
|
|
338
423
|
|
|
339
|
-
|
|
424
|
+
// 2. READ: Always read the file as a raw Buffer (omitting encoding)
|
|
425
|
+
// This gives us the raw bytes, which is the safest start for any file.
|
|
426
|
+
let fileBuffer;
|
|
427
|
+
try {
|
|
428
|
+
fileBuffer = await fs.promises.readFile(resolvedPath);
|
|
429
|
+
} catch (error) {
|
|
430
|
+
console.error(`Error reading file: ${resolvedPath}`, error);
|
|
431
|
+
return ""; // Return empty string or handle error as appropriate
|
|
432
|
+
}
|
|
340
433
|
|
|
341
|
-
|
|
342
|
-
|
|
434
|
+
if (needsBase64) {
|
|
435
|
+
// 3. RETURN BUFFER: Return the raw buffer for binary files.
|
|
436
|
+
return fileBuffer;
|
|
437
|
+
} else {
|
|
438
|
+
// 4. HANDLE TEXT/OTHER:
|
|
439
|
+
// For files not intended for Base64, convert the Buffer to a string using 'utf8'.
|
|
440
|
+
return fileBuffer.toString('utf8');
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
async function getData(filePath, mimeType, isSymlink) {
|
|
445
|
+
let resolvedPath = filePath;
|
|
446
|
+
if (isSymlink) {
|
|
447
|
+
resolvedPath = await realpathAsync(filePath);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
try {
|
|
451
|
+
const fileMimeType = mimeTypes[path.extname(resolvedPath)] || "text/plain";
|
|
452
|
+
if (fileMimeType === "application/json") {
|
|
453
|
+
// Parse JSON files
|
|
454
|
+
return JSON.parse(fs.readFileSync(resolvedPath, "utf8"));
|
|
455
|
+
} else if (
|
|
456
|
+
fileMimeType === "application/javascript" ||
|
|
457
|
+
fileMimeType === "text/javascript"
|
|
458
|
+
) {
|
|
459
|
+
// Try CommonJS require first (fast path)
|
|
460
|
+
try {
|
|
461
|
+
// clear require cache to ensure fresh load
|
|
462
|
+
delete require.cache[require.resolve(resolvedPath)];
|
|
463
|
+
return require(resolvedPath);
|
|
464
|
+
} catch (err) {
|
|
465
|
+
// If require fails due to ESM syntax (export / import), fall back to dynamic import
|
|
466
|
+
const isESMSyntaxError =
|
|
467
|
+
err instanceof SyntaxError ||
|
|
468
|
+
/Unexpected token 'export'/.test(err.message) ||
|
|
469
|
+
/Cannot use import statement outside a module/.test(err.message) ||
|
|
470
|
+
/Unexpected token 'import'/.test(err.message);
|
|
471
|
+
|
|
472
|
+
if (isESMSyntaxError) {
|
|
473
|
+
try {
|
|
474
|
+
const module = await import(pathToFileURL(resolvedPath).href);
|
|
475
|
+
// return default export when present otherwise return full module
|
|
476
|
+
return module && module.default ? module.default : module;
|
|
477
|
+
} catch (impErr) {
|
|
478
|
+
console.error(`Failed to dynamic-import module: ${resolvedPath}`, impErr);
|
|
479
|
+
throw impErr;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
// rethrow original require error if it's not an ESM issue
|
|
483
|
+
throw err;
|
|
484
|
+
}
|
|
485
|
+
} else {
|
|
486
|
+
return fs.readFileSync(resolvedPath, "utf8");
|
|
487
|
+
}
|
|
488
|
+
} catch (error) {
|
|
489
|
+
console.error(`Failed to process file: ${resolvedPath}`, error);
|
|
490
|
+
return "";
|
|
491
|
+
}
|
|
343
492
|
|
|
344
|
-
return content;
|
|
345
493
|
}
|
|
346
494
|
|
|
347
495
|
/**
|
|
348
496
|
* Store files by config sources
|
|
349
497
|
**/
|
|
350
498
|
async function runSources() {
|
|
351
|
-
let
|
|
499
|
+
let newConfig = require(configPath);
|
|
352
500
|
|
|
353
501
|
for (let i = 0; i < sources.length; i++) {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
);
|
|
371
|
-
if (variables) {
|
|
372
|
-
let originalValue = object[key];
|
|
373
|
-
keys.set(key, originalValue);
|
|
374
|
-
let value = "";
|
|
375
|
-
for (let variable of variables) {
|
|
376
|
-
let entry = /{{\s*([\w\W]+)\s*}}/g.exec(
|
|
377
|
-
variable
|
|
378
|
-
);
|
|
379
|
-
entry = entry[1].trim();
|
|
380
|
-
if (entry) {
|
|
381
|
-
if (!fs.existsSync(entry)) continue;
|
|
382
|
-
|
|
383
|
-
if (!isMatch) {
|
|
384
|
-
const filePath = path.resolve(
|
|
385
|
-
configDirectoryPath,
|
|
386
|
-
entry
|
|
387
|
-
);
|
|
388
|
-
for (
|
|
389
|
-
let i = 0;
|
|
390
|
-
i < match.length;
|
|
391
|
-
i++
|
|
392
|
-
) {
|
|
393
|
-
if (
|
|
394
|
-
filePath.startsWith(
|
|
395
|
-
match[i]
|
|
396
|
-
)
|
|
397
|
-
) {
|
|
398
|
-
console.log(
|
|
399
|
-
"Source saved",
|
|
400
|
-
sources[i]
|
|
401
|
-
);
|
|
402
|
-
isMatch = true;
|
|
403
|
-
break;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
let read_type = "utf8";
|
|
409
|
-
const fileExtension =
|
|
410
|
-
path.extname(entry);
|
|
411
|
-
let mime_type =
|
|
412
|
-
mimeTypes[fileExtension] ||
|
|
413
|
-
"text/html";
|
|
414
|
-
|
|
415
|
-
if (
|
|
416
|
-
/^(image|audio|video)\/[-+.\w]+/.test(
|
|
417
|
-
mime_type
|
|
418
|
-
)
|
|
419
|
-
) {
|
|
420
|
-
read_type = "base64";
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
let binary = fs.readFileSync(entry);
|
|
424
|
-
let content = new Buffer.from(
|
|
425
|
-
binary
|
|
426
|
-
).toString(read_type);
|
|
427
|
-
if (content) value += content;
|
|
428
|
-
// object[key] = object[key].replace(variable, content);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
object[key] = value;
|
|
432
|
-
}
|
|
502
|
+
let data = sources[i];
|
|
503
|
+
|
|
504
|
+
// Handle string values
|
|
505
|
+
if (typeof data === "string") {
|
|
506
|
+
let {value, filePath } = await processVariables(data);
|
|
507
|
+
let response = await runStore(value);
|
|
508
|
+
if (response && response.object && response.object[0]) {
|
|
509
|
+
updateFilePath(filePath, response); // Call the new function to update the file path
|
|
510
|
+
}
|
|
511
|
+
} else if (data.array && data.object) {
|
|
512
|
+
if (typeof data.object === "string") {
|
|
513
|
+
let {value, filePath } = await processVariables(data.object);
|
|
514
|
+
if (value) {
|
|
515
|
+
let response = await runStore(value);
|
|
516
|
+
if (response && response.object && response.object[0]) {
|
|
517
|
+
updateFilePath(filePath, response.object);
|
|
433
518
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (
|
|
444
|
-
|
|
519
|
+
}
|
|
520
|
+
} else if (typeof data.object === "object" && data.object !== null) {
|
|
521
|
+
for (const key in data) {
|
|
522
|
+
let {value } = await processVariables(data[key]);
|
|
523
|
+
if (data) {
|
|
524
|
+
data.object[key] = value;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
let response = await runStore(data);
|
|
528
|
+
if (response && response.object && response.object[0] && response.object[0]._id) {
|
|
529
|
+
newConfig.sources[i].object._id = response.object[0]._id;
|
|
530
|
+
}
|
|
445
531
|
}
|
|
446
|
-
} catch (err) {
|
|
447
|
-
console.log(err);
|
|
448
|
-
process.exit();
|
|
449
532
|
}
|
|
450
533
|
|
|
451
|
-
|
|
452
|
-
response.object &&
|
|
453
|
-
response.object[0] &&
|
|
454
|
-
response.object[0]._id
|
|
455
|
-
) {
|
|
456
|
-
source.object._id = response.object[0]._id;
|
|
457
|
-
}
|
|
534
|
+
}
|
|
458
535
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
536
|
+
return newConfig;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
async function processVariables(value) {
|
|
540
|
+
let variableMatch = /{{\s*([\w\W]+)\s*}}/g.exec(value);
|
|
541
|
+
if (!variableMatch) return { value, filePath: null };
|
|
542
|
+
|
|
543
|
+
let entry = variableMatch[1].trim();
|
|
544
|
+
if (!fs.existsSync(entry)) return { value, filePath: null };
|
|
462
545
|
|
|
463
|
-
|
|
546
|
+
const filePath = path.resolve(configDirectoryPath, entry);
|
|
547
|
+
|
|
548
|
+
// Check if the file path matches any of the provided match patterns
|
|
549
|
+
let isMatched = match.some((pattern) => filePath.startsWith(pattern));
|
|
550
|
+
if (!isMatched) return { value, filePath: null };
|
|
551
|
+
|
|
552
|
+
// Read the file as is
|
|
553
|
+
let content;
|
|
554
|
+
try {
|
|
555
|
+
const fileMimeType = mimeTypes[path.extname(entry)] || "text/plain";
|
|
556
|
+
|
|
557
|
+
if (fileMimeType === "application/json") {
|
|
558
|
+
// Parse JSON files
|
|
559
|
+
content = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
560
|
+
} else if (fileMimeType === "application/javascript" || fileMimeType === "text/javascript") {
|
|
561
|
+
// For JavaScript files, require the file to execute exports
|
|
562
|
+
content = require(filePath);
|
|
563
|
+
} else {
|
|
564
|
+
// For plain strings, read as UTF-8 without conversion
|
|
565
|
+
content = fs.readFileSync(filePath, "utf8");
|
|
566
|
+
}
|
|
567
|
+
} catch (error) {
|
|
568
|
+
console.error(`Failed to process file: ${filePath}`, error);
|
|
569
|
+
return { value, filePath: null };
|
|
464
570
|
}
|
|
465
571
|
|
|
466
|
-
return
|
|
572
|
+
return { value: content, filePath };
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Updates the file at the given file path with the provided data.
|
|
577
|
+
* The data is saved as a JSON string.
|
|
578
|
+
*
|
|
579
|
+
* @param {string} filePath - The path of the file to update.
|
|
580
|
+
* @param {object} data - The data to write to the file.
|
|
581
|
+
*/
|
|
582
|
+
function updateFilePath(filePath, data) {
|
|
583
|
+
try {
|
|
584
|
+
const jsonData = JSON.stringify(data, null, 4); // Format JSON with indentation
|
|
585
|
+
fs.writeFileSync(filePath, jsonData, "utf8");
|
|
586
|
+
console.log(`File updated successfully at: ${filePath}`);
|
|
587
|
+
} catch (error) {
|
|
588
|
+
console.error(`Failed to update file at: ${filePath}`, error);
|
|
589
|
+
}
|
|
467
590
|
}
|
|
468
591
|
|
|
592
|
+
|
|
469
593
|
async function runStore(data) {
|
|
470
594
|
try {
|
|
471
595
|
let response;
|
|
@@ -493,42 +617,22 @@ module.exports = async function file(CoCreateConfig, configPath, match) {
|
|
|
493
617
|
}
|
|
494
618
|
|
|
495
619
|
async function run() {
|
|
496
|
-
if (directories)
|
|
620
|
+
if (directories) {
|
|
621
|
+
await runDirectories();
|
|
622
|
+
}
|
|
497
623
|
|
|
498
624
|
if (sources && sources.length) {
|
|
499
|
-
let
|
|
500
|
-
let newConfig = { ...CoCreateConfig };
|
|
501
|
-
if (directories && directories.length)
|
|
502
|
-
newConfig.directories = directories;
|
|
503
|
-
|
|
504
|
-
newConfig.sources = sources;
|
|
505
|
-
|
|
506
|
-
if (newConfig.repositories)
|
|
507
|
-
newConfig.repositories.forEach((obj) => {
|
|
508
|
-
for (const key in obj) {
|
|
509
|
-
if (!["path", "repo", "exclude"].includes(key)) {
|
|
510
|
-
delete obj[key];
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
delete newConfig.url;
|
|
516
|
-
delete newConfig.broadcast;
|
|
517
|
-
|
|
625
|
+
let newConfig = await runSources();
|
|
518
626
|
fs.writeFileSync(
|
|
519
627
|
configPath,
|
|
520
628
|
`module.exports = ${JSON.stringify(newConfig, null, 4)};`
|
|
521
629
|
);
|
|
522
630
|
}
|
|
523
|
-
|
|
524
|
-
if (!match.length) {
|
|
525
|
-
console.log("upload complete!");
|
|
526
|
-
|
|
527
|
-
setTimeout(function () {
|
|
528
|
-
process.exit();
|
|
529
|
-
}, 2000);
|
|
530
|
-
}
|
|
531
631
|
}
|
|
532
632
|
|
|
533
633
|
await run();
|
|
634
|
+
// Only exit if not in watch mode
|
|
635
|
+
if (!process.argv.includes("--watch") && !process.argv.includes("-w")) {
|
|
636
|
+
process.exit();
|
|
637
|
+
}
|
|
534
638
|
};
|