@microlight/core 0.2.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.
Files changed (49) hide show
  1. package/README.md +77 -0
  2. package/bin/microlight-core.js +70 -0
  3. package/dist/scripts/generate-folder-index.js +120 -0
  4. package/dist/scripts/generate-task-imports.js +64 -0
  5. package/dist/scripts/generate-task-index.js +61 -0
  6. package/dist/scripts/prepareFolders.js +119 -0
  7. package/dist/scripts/prepareServer.js +34 -0
  8. package/dist/scripts/prepareTasks.js +114 -0
  9. package/dist/server/app/api/tasks/[slug]/route.js +54 -0
  10. package/dist/server/app/layout.js +41 -0
  11. package/dist/server/app/library/[[...f_path]]/ViewFolder.js +113 -0
  12. package/dist/server/app/library/[[...f_path]]/page.js +42 -0
  13. package/dist/server/app/page.js +4 -0
  14. package/dist/server/app/tasks/[slug]/ViewTask.js +252 -0
  15. package/dist/server/app/tasks/[slug]/action.js +44 -0
  16. package/dist/server/app/tasks/[slug]/page.js +33 -0
  17. package/dist/server/app/tasks/[slug]/runs/[r_id]/ViewRun.js +230 -0
  18. package/dist/server/app/tasks/[slug]/runs/[r_id]/_components/DropdownActions/DropdownActions.js +46 -0
  19. package/dist/server/app/tasks/[slug]/runs/[r_id]/_components/DropdownActions/action.js +35 -0
  20. package/dist/server/app/tasks/[slug]/runs/[r_id]/page.js +43 -0
  21. package/dist/server/components/Icon.js +22 -0
  22. package/dist/server/components/Link.js +52 -0
  23. package/dist/server/components/MLInput.js +29 -0
  24. package/dist/server/components/Navbar/Navbar.js +38 -0
  25. package/dist/server/components/Navbar/NavbarContainer.js +26 -0
  26. package/dist/server/components/PageHeader.js +87 -0
  27. package/dist/server/components/StatusChip.js +11 -0
  28. package/dist/server/components/Test.js +5 -0
  29. package/dist/server/components/TopLoader.js +8 -0
  30. package/dist/server/database/microlight/index.js +52 -0
  31. package/dist/server/database/microlight/tables/Logs.model.js +34 -0
  32. package/dist/server/database/microlight/tables/Runs.model.js +61 -0
  33. package/dist/server/instrumentation.js +16 -0
  34. package/dist/server/lib/executeRun.js +80 -0
  35. package/dist/server/lib/generateDisplayFunctions.js +89 -0
  36. package/dist/server/lib/getAllTasks.js +32 -0
  37. package/dist/server/lib/getTaskDetails.js +17 -0
  38. package/dist/server/lib/loadSchedules.js +77 -0
  39. package/dist/server/tasks/1.intro/hello_world2.task.js +21 -0
  40. package/dist/server/tasks/1.intro/microlight.folder.js +5 -0
  41. package/dist/server/tasks/1.intro/ml.task.js +31 -0
  42. package/dist/server/tasks/1.intro/scheduled.task.js +18 -0
  43. package/dist/server/tasks/1.intro/takes_time.task.js +28 -0
  44. package/dist/server/tasks/1.intro/test/microlight.folder.js +5 -0
  45. package/dist/server/tasks/1.intro/test/takes_time2.task.js +28 -0
  46. package/dist/server/tasks/index.js +33 -0
  47. package/dist/server/tasks/microlight.folder.js +5 -0
  48. package/index.js +1 -0
  49. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ ![Logo](/public/logo500.png)
2
+
3
+ - [Docs](/docs/docs.md)
4
+ - [Change Log](/docs/changelog.md)
5
+
6
+ ## About
7
+ Microlight is a simple task(cron and adhoc) runner. The idea is this, there are tasks that needs to be done. For developers its easy to write a small script to execute the task - e.g. restart AWS redis. But to ask marketing team/sales team to restart redis by running a script is not practical. At the same time, as a small team, the devops guy getting called by the sales team to restart redis is also not practical.
8
+
9
+ This is a solution for small teams. This enables tech team to offload operational tasks to the actual team who needs the task to be executed. This also allows the stack to be light weight and tech teams can write simple scripts to do this.
10
+
11
+ Example usecases,
12
+ - restart redis/some server when overloaded.
13
+ - get fresh data . e.g. customer support person wants to know if customer has made a payment. Lets assume your system is not realtime and the CS person wants to trigger a sync.
14
+ - cron jobs
15
+
16
+ Microlight is designed with the following principles in mind
17
+ - Microlight is designed for light work loads such as
18
+ - personal use,
19
+ - small company - less than 10 people
20
+ - simple data pipeline usecases
21
+ - simple automation/devops usecases
22
+ - Running tasks should feel simple and easy
23
+ - Developers gets to write scripts to automate a task.
24
+ - Business team members gets to trigger the job at their convinience using a UI.
25
+ - Webhooks for other subsystems to trigger jobs
26
+ - Setting up and running microlight should be very easy and should have small footprint
27
+ - Single instance by design - no cluster config overhead
28
+ - uses sqlite only - host everything in one single server/container
29
+
30
+
31
+ Microlight also provides a UI for users to run cron jobs
32
+
33
+ Ways to trigger a job:
34
+ - Trigger jobs from UI
35
+ - Trigger jobs via webhooks
36
+ - Trigger jos from cronjob
37
+
38
+
39
+ ### Microlight can do
40
+ - Execution logic has to be written with code (will not no support no code ever)
41
+ - Tasks can be executed by non techincal people from a GUI
42
+ - Tasks can be scheduled
43
+ - Show console logs and execution output
44
+
45
+ thats it
46
+
47
+ ### Microlight cannot and will not do
48
+ - No code support
49
+ - Multiple server or master/worker mode
50
+
51
+
52
+
53
+ ### Simplicity
54
+
55
+ Microlight is designed as simple solution. This is not designed for massive scale. Intentionally Microlight does not support master/worker node. The Microlight server and the execution of task happens on the same machine. If you are looking for a multi node setup, then we recomment using rundeck. For most small startups, rundeck is an overkill. Scaling microlight can only be done by vertical scaling (increasing the size of the server). Microlight does not support horizontal scaling. Microlight is **NOT** designed to scale horizontally. This is intentional.
56
+
57
+ Microlight also uses sqlite. So you can run all microlight dependancies on one machine/container.
58
+
59
+
60
+ ## Alternatives to microlight
61
+
62
+ - trigger.dev
63
+ - rundeck.com
64
+ - activepieces.com
65
+
66
+ Microlight is the stripped down, simple version of these meant to be run on a single instance.
67
+
68
+ Compared to these solutions,
69
+ - microlight does **NOT** support horizontal scaling
70
+ - microlight does **NOT** have a hosted solution
71
+ - microlight does **NOT** support drag and drop UI tasks.
72
+ - microlight requires you to write scripts using a text editor and commit the code
73
+ - microlight is suitable for one man tech team
74
+
75
+ You should choose one of the alternatives if any of the above points are deal breakers.
76
+
77
+
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from "commander";
4
+ import path from "path";
5
+
6
+ import { packageUp } from "package-up";
7
+
8
+ import { prepareTasks } from "../scripts/prepareTasks.js";
9
+ import { prepareServer } from "../scripts/prepareServer.js";
10
+
11
+
12
+
13
+ const program = new Command();
14
+
15
+ let basePath = await packageUp();
16
+ basePath = basePath.split("/");
17
+ basePath.pop();
18
+ const tasksDir = path.join("/", ...basePath, "src", "tasks");
19
+
20
+ program
21
+ .name("microlight-core")
22
+ .description("Microlight core utilities")
23
+ .version("1.0.0");
24
+
25
+ // Define the `prepare` command
26
+ const prepareCommand = program
27
+ .command("prepare")
28
+ .description("Prepare the environment");
29
+ // .action(() => {
30
+ // console.log("Preparing environment...");
31
+ // });
32
+
33
+ prepareCommand
34
+ .command("all")
35
+ .description("Perform all prepare commands")
36
+ .action(async() => {
37
+ await prepareTasks();
38
+ console.log('\n');
39
+ const { prepareFolders } = await import("../scripts/prepareFolders.js");
40
+ await prepareFolders();
41
+
42
+ console.log('\n');
43
+ await prepareServer();
44
+ });
45
+
46
+ prepareCommand
47
+ .command("tasks")
48
+ .description("Index tasks and create an importer")
49
+ .action(async () => {
50
+ await prepareTasks();
51
+ });
52
+
53
+ prepareCommand
54
+ .command("folders")
55
+ .description("Index folders")
56
+ .action(async () => {
57
+ const { prepareFolders } = await import("../scripts/prepareFolders.js");
58
+ await prepareFolders();
59
+ });
60
+
61
+
62
+ prepareCommand
63
+ .command("server")
64
+ .description("Setup the server")
65
+ .action(async () => {
66
+ prepareServer();
67
+ });
68
+
69
+ // Parse CLI arguments
70
+ program.parse(process.argv);
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+ import { glob } from 'glob';
3
+ import path from 'path';
4
+ import fs from 'fs';
5
+ // import taskMap from '@/tasks/tasks';
6
+
7
+ // Ensure we're looking in the right directory relative to the script
8
+ const tasksDir = path.join(process.cwd(), 'src', 'tasks');
9
+ const outputFile = path.resolve(process.cwd(), '.microlight', 'folderMap.js');
10
+ const taskMapFile = path.resolve(process.cwd(), '.microlight', 'taskMap.js');
11
+ const taskMap = (await import(taskMapFile))?.default;
12
+ let taskMapByFileName = {};
13
+ Object.keys(taskMap).forEach(function (slug) {
14
+ const task = taskMap[slug];
15
+ taskMapByFileName[task.__folder + '/' + task.__file_name] = task;
16
+ });
17
+
18
+ // console.log(taskMapByFileName);
19
+
20
+ // Create tasks directory if it doesn't exist
21
+ if (!fs.existsSync(tasksDir)) {
22
+ fs.mkdirSync(tasksDir, {
23
+ recursive: true
24
+ });
25
+ }
26
+
27
+ // Find all folder files
28
+ const folderPatterns = ['__ml.js', 'ml.js', 'ml.folder.js', '**/microlight.folder.js'];
29
+ const folderFiles = glob.sync(folderPatterns, {
30
+ cwd: tasksDir,
31
+ absolute: false
32
+ });
33
+
34
+ // console.log(folderFiles);
35
+
36
+ // Import all task files dynamically
37
+ const folders = await Promise.all(folderFiles.map(async file => {
38
+ const filePath = path.resolve(tasksDir, file);
39
+ let folderName = file.split('/');
40
+ folderName.pop();
41
+ folderName = folderName.join('/');
42
+ console.log(folderName);
43
+ let folder = (await import(filePath))?.default;
44
+ // console.log(folder.default);
45
+ // const taskName = path.basename(filePath, '.task.js');
46
+ return [folderName, folder];
47
+ // return [task?.default?.slug, {...task?.default,...{file_name:taskName}}];
48
+ }));
49
+ // console.log(folders);
50
+
51
+ // Convert array of entries to an object
52
+ const folderMap = Object.fromEntries(folders);
53
+ // console.log(folderMap);
54
+
55
+ Object.keys(folderMap).map(folderName => {
56
+ folderMap[folderName].contents = [];
57
+ const contentList = fs.readdirSync(path.resolve(tasksDir, folderName));
58
+ // console.log(contentList);
59
+ for (const filename of contentList) {
60
+ const file = path.resolve(tasksDir, folderName, filename);
61
+ // const file = project_folder+`${dir}/${filename}`
62
+ // console.log(file);
63
+ if (fs.statSync(file).isDirectory()) {
64
+ // console.log('\n\n\n====');
65
+ // console.log(file);
66
+ const subFolderName = file.split('/src/tasks/')[1];
67
+ // console.log(subFolderName);
68
+ if (folderMap[subFolderName]) {
69
+ folderMap[folderName].contents.push({
70
+ type: 'folder',
71
+ slug: subFolderName,
72
+ ...folderMap[subFolderName]
73
+ });
74
+ }
75
+ } else {
76
+ if (filename.indexOf('.task.js') > -1) {
77
+ // console.log('\n\n\n====');
78
+ // console.log(filename);
79
+ const taskName = path.basename(filename, '.task.js');
80
+ // console.log(taskMapByFileName[folderName+'/'+filename]);
81
+ let item = {
82
+ type: 'task',
83
+ slug: taskName,
84
+ ...taskMapByFileName[folderName + '/' + filename]
85
+ };
86
+ folderMap[folderName].contents.push(item);
87
+ }
88
+ }
89
+ // console.log(filename);
90
+ }
91
+ });
92
+ // folderMap.map(folder=>{
93
+
94
+ //
95
+ // folder.content = [
96
+ // {
97
+ // type:'task',
98
+ // slug:'takes_time'
99
+ // },
100
+ // {
101
+ // type:'folder',
102
+ // slug:'1.intro'
103
+ // }
104
+ // ]
105
+ // })
106
+
107
+ // Write the generated code to a file
108
+ const outputCode = 'export default ' + JSON.stringify(folderMap, null, 2);
109
+
110
+ // Create the output directory if it doesn't exist
111
+ const outputDir = path.dirname(outputFile);
112
+ if (!fs.existsSync(outputDir)) {
113
+ fs.mkdirSync(outputDir, {
114
+ recursive: true
115
+ });
116
+ }
117
+
118
+ // Write the file
119
+ fs.writeFileSync(outputFile, outputCode, 'utf-8');
120
+ console.log(`Generated folder index at: ${outputFile}`);
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ import { glob } from 'glob';
3
+ import path from 'path';
4
+ // import { join, relative, dirname } from 'path';
5
+ import fs from 'fs';
6
+
7
+ // Ensure we're looking in the right directory relative to the script
8
+ const tasksDir = path.join(process.cwd(), 'src', 'tasks');
9
+ const outputFile = path.resolve(process.cwd(), '.microlight', 'importTaskModule.js');
10
+
11
+ // Create tasks directory if it doesn't exist
12
+ if (!fs.existsSync(tasksDir)) {
13
+ fs.mkdirSync(tasksDir, {
14
+ recursive: true
15
+ });
16
+ }
17
+
18
+ // Find all task files
19
+ const taskFiles = glob.sync('**/*.task.js', {
20
+ cwd: tasksDir,
21
+ absolute: false
22
+ });
23
+
24
+ // Generate the import switch statement
25
+ const generateImportSwitch = async tasks => {
26
+ let cases = await Promise.all(tasks.map(async file => {
27
+ const filePath = path.resolve(tasksDir, file);
28
+ const task = await import(filePath);
29
+ // console.log(task);
30
+ const taskName = path.basename(file, '.task.js');
31
+ const taskSlug = task?.default?.slug;
32
+ // const taskName = path.basename(filePath, '.task.js');
33
+ // return [taskName, task.default];
34
+ // return [task?.default?.slug, {...task?.default,...{file_name:taskName}}];
35
+
36
+ return ` case "${taskSlug || taskName}":\n return await import("../src/tasks/${file}");`;
37
+ }));
38
+ cases = cases.join('\n');
39
+ // console.log(cases);
40
+
41
+ return `
42
+ export const importTaskModule = async (task_slug) => {
43
+ switch (task_slug) {
44
+ ${cases}
45
+ default:
46
+ return { default: { name: "Library", description: "All executable tasks" } };
47
+ }
48
+ };`.trim();
49
+ };
50
+
51
+ // Write the generated code to a file
52
+ const outputCode = await generateImportSwitch(taskFiles);
53
+
54
+ // Create the output directory if it doesn't exist
55
+ const outputDir = path.dirname(outputFile);
56
+ if (!fs.existsSync(outputDir)) {
57
+ fs.mkdirSync(outputDir, {
58
+ recursive: true
59
+ });
60
+ }
61
+
62
+ // Write the file
63
+ fs.writeFileSync(outputFile, outputCode, 'utf-8');
64
+ console.log(`Generated import switch at: ${outputFile}`);
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ import { glob } from 'glob';
3
+ import path from 'path';
4
+ // import { join, relative, dirname } from 'path';
5
+ import fs from 'fs';
6
+
7
+ // Ensure we're looking in the right directory relative to the script
8
+ const tasksDir = path.join(process.cwd(), 'src', 'tasks');
9
+ const outputFile = path.resolve(process.cwd(), '.microlight', 'taskMap.js');
10
+
11
+ // Create tasks directory if it doesn't exist
12
+ if (!fs.existsSync(tasksDir)) {
13
+ fs.mkdirSync(tasksDir, {
14
+ recursive: true
15
+ });
16
+ }
17
+
18
+ // Find all task files
19
+ const taskFiles = glob.sync('**/*.task.js', {
20
+ cwd: tasksDir,
21
+ absolute: false
22
+ });
23
+ console.log(taskFiles);
24
+
25
+ // Import all task files dynamically
26
+ const tasks = await Promise.all(taskFiles.map(async file => {
27
+ const filePath = path.resolve(tasksDir, file);
28
+ const task = await import(filePath);
29
+ const taskName = path.basename(filePath);
30
+ let folderName = file.split('/');
31
+ folderName.pop();
32
+ folderName = folderName.join('/');
33
+ // return [taskName, task.default];
34
+ return [task?.default?.slug, {
35
+ ...task?.default,
36
+ ...{
37
+ __file_name: taskName,
38
+ __folder: folderName
39
+ }
40
+ }];
41
+ }));
42
+ // console.log(tasks);
43
+
44
+ // Convert array of entries to an object
45
+ const taskMap = Object.fromEntries(tasks);
46
+ console.log(taskMap);
47
+
48
+ // Write the generated code to a file
49
+ const outputCode = 'export default ' + JSON.stringify(taskMap, null, 2);
50
+
51
+ // Create the output directory if it doesn't exist
52
+ const outputDir = path.dirname(outputFile);
53
+ if (!fs.existsSync(outputDir)) {
54
+ fs.mkdirSync(outputDir, {
55
+ recursive: true
56
+ });
57
+ }
58
+
59
+ // Write the file
60
+ fs.writeFileSync(outputFile, outputCode, 'utf-8');
61
+ console.log(`Generated tasks index at: ${outputFile}`);
@@ -0,0 +1,119 @@
1
+ import { glob } from 'glob';
2
+ import path from 'path';
3
+ // import { join, relative, dirname } from 'path';
4
+ import fs from 'fs';
5
+ const tasksDir = path.join(process.cwd(), 'src', 'tasks');
6
+ const outputFile = path.resolve(process.cwd(), '.microlight', 'folderMap.js');
7
+ const taskMapFile = path.resolve(process.cwd(), '.microlight', 'taskMap.js');
8
+ const taskMap = (await import(taskMapFile))?.default;
9
+ let taskMapByFileName = {};
10
+ Object.keys(taskMap).forEach(function (slug) {
11
+ const task = taskMap[slug];
12
+ taskMapByFileName[task.__folder + '/' + task.__file_name] = task;
13
+ });
14
+
15
+ // Create tasks directory if it doesn't exist
16
+ if (!fs.existsSync(tasksDir)) {
17
+ fs.mkdirSync(tasksDir, {
18
+ recursive: true
19
+ });
20
+ }
21
+ const getFolderFiles = function () {
22
+ // Find all folder files
23
+ const folderPatterns = ['__ml.js', 'ml.js', 'ml.folder.js', '**/microlight.folder.js'];
24
+ const folderFiles = glob.sync(folderPatterns, {
25
+ cwd: tasksDir,
26
+ absolute: false
27
+ });
28
+ return folderFiles;
29
+ };
30
+ export async function prepareFolders() {
31
+ console.log('Preparing folders now');
32
+ const folderFiles = getFolderFiles();
33
+
34
+ // Import all task files dynamically
35
+ const folders = await Promise.all(folderFiles.map(async file => {
36
+ const filePath = path.resolve(tasksDir, file);
37
+ let folderName = file.split('/');
38
+ folderName.pop();
39
+ folderName = folderName.join('/');
40
+ // console.log(folderName);
41
+ let folder = (await import(filePath))?.default;
42
+ // console.log(folder.default);
43
+ // const taskName = path.basename(filePath, '.task.js');
44
+ return [folderName, folder];
45
+ // return [task?.default?.slug, {...task?.default,...{file_name:taskName}}];
46
+ }));
47
+ // console.log(folders);
48
+
49
+ // Convert array of entries to an object
50
+ const folderMap = Object.fromEntries(folders);
51
+ // console.log(folderMap);
52
+
53
+ Object.keys(folderMap).map(folderName => {
54
+ folderMap[folderName].contents = [];
55
+ const contentList = fs.readdirSync(path.resolve(tasksDir, folderName));
56
+ // console.log(contentList);
57
+ for (const filename of contentList) {
58
+ const file = path.resolve(tasksDir, folderName, filename);
59
+ // const file = project_folder+`${dir}/${filename}`
60
+ // console.log(file);
61
+ if (fs.statSync(file).isDirectory()) {
62
+ // console.log('\n\n\n====');
63
+ // console.log(file);
64
+ const subFolderName = file.split('/src/tasks/')[1];
65
+ // console.log(subFolderName);
66
+ if (folderMap[subFolderName]) {
67
+ folderMap[folderName].contents.push({
68
+ type: 'folder',
69
+ slug: subFolderName,
70
+ ...folderMap[subFolderName]
71
+ });
72
+ }
73
+ } else {
74
+ if (filename.indexOf('.task.js') > -1) {
75
+ // console.log('\n\n\n====');
76
+ // console.log(filename);
77
+ const taskName = path.basename(filename, '.task.js');
78
+ // console.log(taskMapByFileName[folderName+'/'+filename]);
79
+ let item = {
80
+ type: 'task',
81
+ slug: taskName,
82
+ ...taskMapByFileName[folderName + '/' + filename]
83
+ };
84
+ folderMap[folderName].contents.push(item);
85
+ }
86
+ }
87
+ // console.log(filename);
88
+ }
89
+ });
90
+ // folderMap.map(folder=>{
91
+
92
+ //
93
+ // folder.content = [
94
+ // {
95
+ // type:'task',
96
+ // slug:'takes_time'
97
+ // },
98
+ // {
99
+ // type:'folder',
100
+ // slug:'1.intro'
101
+ // }
102
+ // ]
103
+ // })
104
+
105
+ // Write the generated code to a file
106
+ const outputCode = 'export default ' + JSON.stringify(folderMap, null, 2);
107
+
108
+ // Create the output directory if it doesn't exist
109
+ const outputDir = path.dirname(outputFile);
110
+ if (!fs.existsSync(outputDir)) {
111
+ fs.mkdirSync(outputDir, {
112
+ recursive: true
113
+ });
114
+ }
115
+
116
+ // Write the file
117
+ fs.writeFileSync(outputFile, outputCode, 'utf-8');
118
+ console.log(`Generated folder index at: ${outputFile}`);
119
+ }
@@ -0,0 +1,34 @@
1
+ import path from "path";
2
+ import fs from "fs";
3
+ import { copySync } from "fs-extra";
4
+ import { createRequire } from "module";
5
+ const require = createRequire(import.meta.url); // Required for resolving CommonJS modules
6
+
7
+ export async function prepareServer() {
8
+ console.log('preparing the server');
9
+ const coreModulePath = require.resolve("@microlight/core/package.json"); // Find package.json
10
+ const coreRoot = path.dirname(coreModulePath); // Get package root
11
+ console.log(coreModulePath);
12
+ console.log(coreRoot);
13
+ const serverSrcDir = path.join(coreRoot, "dist", "server"); // Resolve /dist/server
14
+ console.log(serverSrcDir);
15
+
16
+ // Destination path
17
+ const processDir = process.cwd();
18
+ const serverDestDir = path.join(processDir, ".microlight", "server");
19
+ console.log("serverSrcDir:", serverSrcDir);
20
+ console.log("serverDestDir:", serverDestDir);
21
+
22
+ // Ensure destination exists
23
+ if (!fs.existsSync(serverDestDir)) {
24
+ fs.mkdirSync(serverDestDir, {
25
+ recursive: true
26
+ });
27
+ }
28
+
29
+ // Copy files
30
+ copySync(serverSrcDir, serverDestDir, {
31
+ overwrite: true
32
+ });
33
+ console.log("Server files copied successfully!");
34
+ }
@@ -0,0 +1,114 @@
1
+ import { glob } from 'glob';
2
+ import path from 'path';
3
+ // import { join, relative, dirname } from 'path';
4
+ import fs from 'fs';
5
+ const tasksDir = path.join(process.cwd(), 'src', 'tasks');
6
+
7
+ // Create tasks directory if it doesn't exist
8
+ if (!fs.existsSync(tasksDir)) {
9
+ fs.mkdirSync(tasksDir, {
10
+ recursive: true
11
+ });
12
+ }
13
+ const getTaskFiles = function () {
14
+ // Find all task files
15
+ const taskFiles = glob.sync('**/*.task.js', {
16
+ cwd: tasksDir,
17
+ absolute: false
18
+ });
19
+
20
+ // console.log(taskFiles);
21
+ return taskFiles;
22
+ };
23
+
24
+ // Generate the import switch statement
25
+ const generateImportSwitch = async tasks => {
26
+ let cases = await Promise.all(tasks.map(async file => {
27
+ const filePath = path.resolve(tasksDir, file);
28
+ const task = await import(filePath);
29
+ // console.log(task);
30
+ const taskName = path.basename(file, '.task.js');
31
+ const taskSlug = task?.default?.slug;
32
+ // const taskName = path.basename(filePath, '.task.js');
33
+ // return [taskName, task.default];
34
+ // return [task?.default?.slug, {...task?.default,...{file_name:taskName}}];
35
+
36
+ return ` case "${taskSlug || taskName}":\n return await import("../src/tasks/${file}");`;
37
+ }));
38
+ cases = cases.join('\n');
39
+ // console.log(cases);
40
+
41
+ return `
42
+ export const importTaskModule = async (task_slug) => {
43
+ switch (task_slug) {
44
+ ${cases}
45
+ default:
46
+ return { default: { name: "Library", description: "All executable tasks" } };
47
+ }
48
+ };`.trim();
49
+ };
50
+ export async function prepareTasks() {
51
+ console.log('Preparing tasks now');
52
+ await prepareTasksIndex();
53
+ await prepareTasksImports();
54
+ }
55
+ export async function prepareTasksIndex() {
56
+ const taskFiles = getTaskFiles();
57
+
58
+ // Import all task files dynamically
59
+ const tasks = await Promise.all(taskFiles.map(async file => {
60
+ const filePath = path.resolve(tasksDir, file);
61
+ const task = await import(filePath);
62
+ const taskName = path.basename(filePath);
63
+ let folderName = file.split('/');
64
+ folderName.pop();
65
+ folderName = folderName.join('/');
66
+ // return [taskName, task.default];
67
+ return [task?.default?.slug, {
68
+ ...task?.default,
69
+ ...{
70
+ __file_name: taskName,
71
+ __folder: folderName
72
+ }
73
+ }];
74
+ }));
75
+ // console.log(tasks);
76
+
77
+ // Convert array of entries to an object
78
+ const taskMap = Object.fromEntries(tasks);
79
+
80
+ // console.log(taskMap);
81
+
82
+ // Write the generated code to a file
83
+ const outputCode = 'export default ' + JSON.stringify(taskMap, null, 2);
84
+ const outputFile = path.resolve(process.cwd(), '.microlight', 'taskMap.js');
85
+ // Create the output directory if it doesn't exist
86
+ const outputDir = path.dirname(outputFile);
87
+ if (!fs.existsSync(outputDir)) {
88
+ fs.mkdirSync(outputDir, {
89
+ recursive: true
90
+ });
91
+ }
92
+
93
+ // Write the file
94
+ fs.writeFileSync(outputFile, outputCode, 'utf-8');
95
+ console.log(`Generated tasks index at: ${outputFile}`);
96
+ }
97
+ export async function prepareTasksImports() {
98
+ const taskFiles = getTaskFiles();
99
+
100
+ // Write the generated code to a file
101
+ const outputCode = await generateImportSwitch(taskFiles);
102
+ const outputFile = path.resolve(process.cwd(), '.microlight', 'importTaskModule.js');
103
+ // Create the output directory if it doesn't exist
104
+ const outputDir = path.dirname(outputFile);
105
+ if (!fs.existsSync(outputDir)) {
106
+ fs.mkdirSync(outputDir, {
107
+ recursive: true
108
+ });
109
+ }
110
+
111
+ // Write the file
112
+ fs.writeFileSync(outputFile, outputCode, 'utf-8');
113
+ console.log(`Generated importTaskModule at: ${outputFile}`);
114
+ }