Skip to content

Commit 00862f7

Browse files
committed
Add support for loading actions from .action files
Refactored project action logic into a separate .action.ts file and updated the loader to automatically load actions from .action.js/.action.ts files. Added tests and fixtures to verify that actions are correctly loaded and attached to object configs.
1 parent 5c4d453 commit 00862f7

File tree

5 files changed

+74
-17
lines changed

5 files changed

+74
-17
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { ObjectQLContext } from '@objectql/core';
2+
3+
export const listenTo = 'projects';
4+
5+
export const complete = async (ctx: ObjectQLContext, params: { id: string, comment?: string }) => {
6+
const { id, comment } = params;
7+
console.log(`[Action] Completing project ${id} by ${ctx.userId}. Comment: ${comment}`);
8+
9+
// Use the context to get a repo for this object
10+
const repo = ctx.object('projects');
11+
12+
// Update the project status
13+
await repo.update(id, {
14+
status: 'completed',
15+
description: comment ? `Completed with comment: ${comment}` : undefined
16+
});
17+
18+
return { success: true, message: "Project completed" };
19+
};

examples/basic-usage/src/objects/projects.hook.ts

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,5 @@ export async function beforeCreate(context: HookContext) {
1919
}
2020
}
2121

22-
export const actions = {
23-
complete: async (ctx: ObjectQLContext, params: { id: string, comment?: string }) => {
24-
const { id, comment } = params;
25-
console.log(`[Action] Completing project ${id} by ${ctx.userId}. Comment: ${comment}`);
26-
27-
// Use the context to get a repo for this object
28-
const repo = ctx.object('projects');
29-
30-
// Update the project status
31-
await repo.update(id, {
32-
status: 'completed',
33-
description: comment ? `Completed with comment: ${comment}` : undefined
34-
});
35-
36-
return { success: true, message: "Project completed" };
37-
}
38-
};
22+
// Actions are now in projects.action.ts
3923

packages/core/src/loader.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,46 @@ export function loadObjectConfigs(dir: string): Record<string, ObjectConfig> {
114114
console.error(`Error loading hook from ${file}:`, e);
115115
}
116116
}
117+
118+
// 3. Load Actions (.action.js, .action.ts)
119+
const actionFiles = glob.sync(['**/*.action.{js,ts}'], {
120+
cwd: dir,
121+
absolute: true
122+
});
123+
124+
for (const file of actionFiles) {
125+
try {
126+
const actionModule = require(file);
127+
let objectName = actionModule.listenTo;
128+
129+
if (!objectName) {
130+
const basename = path.basename(file);
131+
const match = basename.match(/^(.+)\.action\.(ts|js)$/);
132+
if (match) {
133+
objectName = match[1];
134+
}
135+
}
136+
137+
if (objectName && configs[objectName]) {
138+
if (!configs[objectName].actions) {
139+
configs[objectName].actions = {};
140+
}
141+
142+
// Treat all exported functions as actions
143+
for (const [key, value] of Object.entries(actionModule)) {
144+
if (key === 'listenTo') continue;
145+
if (typeof value === 'function') {
146+
if (!configs[objectName].actions![key]) {
147+
configs[objectName].actions![key] = {};
148+
}
149+
configs[objectName].actions![key].handler = value as any;
150+
}
151+
}
152+
}
153+
} catch (e) {
154+
console.error(`Error loading action from ${file}:`, e);
155+
}
156+
}
117157

118158
return configs;
119159
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Fixture for testing action loader
2+
export const listenTo = 'project';
3+
4+
export async function closeProject(ctx: any, params: any) {
5+
return { success: true };
6+
}

packages/core/test/loader.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,12 @@ describe('Loader', () => {
1111
expect(configs['project'].fields).toBeDefined();
1212
expect(configs['project'].fields.name).toBeDefined();
1313
});
14+
15+
it('should load actions from .action.ts files', () => {
16+
const fixturesDir = path.join(__dirname, 'fixtures');
17+
const configs = loadObjectConfigs(fixturesDir);
18+
expect(configs['project'].actions).toBeDefined();
19+
expect(configs['project'].actions!.closeProject).toBeDefined();
20+
expect(typeof configs['project'].actions!.closeProject.handler).toBe('function');
21+
});
1422
});

0 commit comments

Comments
 (0)