@outputai/core 0.10.0 → 0.10.1-next.09ed166.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/package.json +1 -1
- package/src/bus.js +58 -20
- package/src/bus.spec.js +135 -77
- package/src/consts.js +2 -1
- package/src/helpers/object.js +48 -35
- package/src/helpers/object.spec.js +123 -75
- package/src/hooks/index.d.ts +48 -45
- package/src/hooks/index.js +49 -44
- package/src/hooks/index.spec.js +74 -102
- package/src/interface/workflow.js +92 -85
- package/src/interface/workflow.spec.js +135 -142
- package/src/sdk/helpers/objects.d.ts +24 -19
- package/src/sdk/runtime/events.d.ts +4 -6
- package/src/sdk/runtime/events.js +2 -15
- package/src/sdk/runtime/events.spec.js +14 -92
- package/src/worker/global_functions.js +2 -2
- package/src/worker/global_functions.spec.js +3 -3
- package/src/worker/index.js +3 -3
- package/src/worker/index.spec.js +6 -6
- package/src/worker/interceptors/activity.js +4 -4
- package/src/worker/interceptors/activity.spec.js +9 -9
- package/src/worker/interceptors/workflow.js +5 -5
- package/src/worker/interceptors/workflow.spec.js +7 -7
- package/src/worker/loader/activities.js +56 -40
- package/src/worker/loader/activities.spec.js +21 -22
- package/src/worker/loader/workflows.spec.js +1 -2
- package/src/worker/log_hooks.js +9 -9
- package/src/worker/log_hooks.spec.js +2 -2
- package/src/worker/sinks.js +8 -8
- package/src/worker/sinks.spec.js +9 -9
- package/src/worker/webpack_loaders/consts.js +6 -0
- package/src/worker/webpack_loaders/tools.js +1 -146
- package/src/worker/webpack_loaders/tools.spec.js +0 -23
- package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.js +24 -32
- package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.spec.js +82 -279
- package/src/worker/webpack_loaders/workflow_rewriter/index.mjs +6 -7
- package/src/worker/webpack_loaders/workflow_rewriter/index.spec.js +57 -119
- package/src/worker/webpack_loaders/workflow_rewriter/rewrite_activity_calls.js +88 -0
- package/src/worker/webpack_loaders/workflow_rewriter/rewrite_activity_calls.spec.js +165 -0
- package/src/worker/webpack_loaders/workflow_validator/index.mjs +96 -29
- package/src/worker/webpack_loaders/workflow_validator/index.spec.js +110 -583
- package/src/worker/webpack_loaders/{npm_workflow_export_resolve.js → workflow_validator/npm_workflow_export_resolve.js} +1 -1
- package/src/worker/webpack_loaders/{npm_workflow_export_resolve.spec.js → workflow_validator/npm_workflow_export_resolve.spec.js} +1 -1
- package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.js +0 -193
- package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.spec.js +0 -123
|
@@ -4,11 +4,6 @@ import { tmpdir } from 'node:os';
|
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import validatorLoader from './index.mjs';
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* Minimal published catalog under `dir/node_modules` so `require.resolve` / export following works.
|
|
9
|
-
* @param {string} dir - Temp project root containing `steps.js` / `workflow.js` under test.
|
|
10
|
-
* @param {string} workflowName - Declared workflow `name` in the leaf `workflow.js`.
|
|
11
|
-
*/
|
|
12
7
|
const writeMockGrowthxlabsCatalog = ( dir, workflowName ) => {
|
|
13
8
|
const pkgRoot = join( dir, 'node_modules', '@growthxlabs', 'workflows_catalog' );
|
|
14
9
|
const srcDir = join( pkgRoot, 'src' );
|
|
@@ -41,635 +36,167 @@ function runLoader( filename, source ) {
|
|
|
41
36
|
}
|
|
42
37
|
|
|
43
38
|
describe( 'workflow_validator loader', () => {
|
|
44
|
-
it( 'workflow
|
|
45
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-allow-' ) );
|
|
39
|
+
it( 'allows supported workflow imports and arbitrary non-component imports', async () => {
|
|
40
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-imports-allow-' ) );
|
|
46
41
|
writeFileSync( join( dir, 'steps.js' ), 'export const S = step({ name: "s" })\n' );
|
|
47
42
|
writeFileSync( join( dir, 'evaluators.js' ), 'export const E = evaluator({ name: "e" })\n' );
|
|
48
43
|
writeFileSync( join( dir, 'workflow.js' ), 'export const W = workflow({ name: "w" })\n' );
|
|
44
|
+
mkdirSync( join( dir, 'utils' ) );
|
|
45
|
+
writeFileSync( join( dir, 'utils', 'helper.js' ), 'export const helper = () => 1;\n' );
|
|
49
46
|
|
|
50
|
-
const
|
|
47
|
+
const source = [
|
|
51
48
|
'import { S } from "./steps.js";',
|
|
52
49
|
'import { E } from "./evaluators.js";',
|
|
53
50
|
'import { W } from "./workflow.js";',
|
|
51
|
+
'import { helper } from "./utils/helper.js";',
|
|
54
52
|
'const x = 1;'
|
|
55
53
|
].join( '\n' );
|
|
56
54
|
|
|
57
|
-
await expect( runLoader( join( dir, 'workflow.js' ),
|
|
55
|
+
await expect( runLoader( join( dir, 'workflow.js' ), source ) ).resolves.toBeTruthy();
|
|
58
56
|
rmSync( dir, { recursive: true, force: true } );
|
|
59
57
|
} );
|
|
60
58
|
|
|
61
|
-
it( '
|
|
62
|
-
const dir = mkdtempSync( join( tmpdir(), '
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
'import a from "@outputai/core";',
|
|
72
|
-
'const z = 1;'
|
|
73
|
-
].join( '\n' );
|
|
74
|
-
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
75
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
76
|
-
} );
|
|
77
|
-
|
|
78
|
-
it( 'steps.js: allows importing steps/evaluators/workflow (no import restrictions)', async () => {
|
|
79
|
-
const dir = mkdtempSync( join( tmpdir(), 'steps-allow-import-' ) );
|
|
80
|
-
const src = 'import { S } from "./steps.js";';
|
|
81
|
-
const result = await runLoader( join( dir, 'steps.js' ), src );
|
|
82
|
-
expect( result.warnings ).toHaveLength( 0 );
|
|
83
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
84
|
-
} );
|
|
59
|
+
it( 'allows cross-component imports and requires in activity files', async () => {
|
|
60
|
+
const dir = mkdtempSync( join( tmpdir(), 'activity-cross-imports-' ) );
|
|
61
|
+
const stepsResult = await runLoader( join( dir, 'steps.js' ), [
|
|
62
|
+
'import { E } from "./evaluators.js";',
|
|
63
|
+
'const W = require("./workflow.js");'
|
|
64
|
+
].join( '\n' ) );
|
|
65
|
+
const evaluatorResult = await runLoader( join( dir, 'evaluators.js' ), [
|
|
66
|
+
'import { S } from "./steps.js";',
|
|
67
|
+
'const util = require("./util.js");'
|
|
68
|
+
].join( '\n' ) );
|
|
85
69
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const src = 'import x from "./util.js";\nconst obj = { fn: () => 1 };';
|
|
89
|
-
await expect( runLoader( join( dir, 'steps.js' ), src ) ).resolves.toBeTruthy();
|
|
70
|
+
expect( stepsResult.warnings ).toHaveLength( 0 );
|
|
71
|
+
expect( evaluatorResult.warnings ).toHaveLength( 0 );
|
|
90
72
|
rmSync( dir, { recursive: true, force: true } );
|
|
91
73
|
} );
|
|
92
74
|
|
|
93
|
-
it( '
|
|
94
|
-
const dir = mkdtempSync( join( tmpdir(), '
|
|
95
|
-
const src = 'import { E } from "./evaluators.js";';
|
|
96
|
-
const result = await runLoader( join( dir, 'evaluators.js' ), src );
|
|
97
|
-
expect( result.warnings ).toHaveLength( 0 );
|
|
98
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
99
|
-
} );
|
|
75
|
+
it( 'rejects default and namespace imports from activity files', async () => {
|
|
76
|
+
const dir = mkdtempSync( join( tmpdir(), 'activity-import-shape-' ) );
|
|
100
77
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
'const obj = { fn: function() { sumNumbers(); } };'
|
|
108
|
-
].join( '\n' );
|
|
109
|
-
const result = await runLoader( join( dir, 'steps.js' ), src );
|
|
110
|
-
expect( result.warnings ).toHaveLength( 1 );
|
|
111
|
-
expect( result.warnings[0].message ).toMatch( /Invalid call in .*steps\.js fn: calling a workflow/ );
|
|
112
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
113
|
-
} );
|
|
78
|
+
await expect( runLoader( join( dir, 'workflow.js' ), 'import StepA from "./steps.js";' ) )
|
|
79
|
+
.rejects.toThrow( /Invalid activity import.*named imports only/ );
|
|
80
|
+
await expect( runLoader( join( dir, 'workflow.js' ), 'import * as steps from "./steps.js";' ) )
|
|
81
|
+
.rejects.toThrow( /Invalid activity import.*named imports only/ );
|
|
82
|
+
await expect( runLoader( join( dir, 'workflow.js' ), 'import EvalA, { EvalB } from "./evaluators.js";' ) )
|
|
83
|
+
.rejects.toThrow( /Invalid activity import.*named imports only/ );
|
|
114
84
|
|
|
115
|
-
it( 'evaluators.js: warns when calling catalog workflow inside fn (require)', async () => {
|
|
116
|
-
const dir = mkdtempSync( join( tmpdir(), 'evals-catalog-warn-' ) );
|
|
117
|
-
writeMockGrowthxlabsCatalog( dir, 'cat.warn.req' );
|
|
118
|
-
const src = [
|
|
119
|
-
'const { sumNumbers } = require("@growthxlabs/workflows_catalog");',
|
|
120
|
-
'const E = evaluator({ name: "e", fn: async () => ({ value: 1 }) });',
|
|
121
|
-
'const obj = { fn: function() { sumNumbers(); } };'
|
|
122
|
-
].join( '\n' );
|
|
123
|
-
const result = await runLoader( join( dir, 'evaluators.js' ), src );
|
|
124
|
-
expect( result.warnings ).toHaveLength( 1 );
|
|
125
|
-
expect( result.warnings[0].message ).toMatch( /Invalid call in .*evaluators\.js fn: calling a workflow/ );
|
|
126
85
|
rmSync( dir, { recursive: true, force: true } );
|
|
127
86
|
} );
|
|
128
87
|
|
|
129
|
-
it( '
|
|
130
|
-
const dir = mkdtempSync( join( tmpdir(), '
|
|
131
|
-
writeMockGrowthxlabsCatalog( dir, 'cat.allow' );
|
|
132
|
-
const src = [
|
|
133
|
-
'import { sumNumbers } from "@growthxlabs/workflows_catalog";',
|
|
134
|
-
'const x = 1;'
|
|
135
|
-
].join( '\n' );
|
|
136
|
-
const result = await runLoader( join( dir, 'workflow.js' ), src );
|
|
137
|
-
expect( result.warnings ).toHaveLength( 0 );
|
|
138
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
139
|
-
} );
|
|
88
|
+
it( 'rejects non-destructured requires from activity files', async () => {
|
|
89
|
+
const dir = mkdtempSync( join( tmpdir(), 'activity-require-shape-' ) );
|
|
140
90
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
'const A = step({ name: "a" });',
|
|
146
|
-
'const B = step({ name: "b" });',
|
|
147
|
-
'const obj = { fn: function() { B(); } };'
|
|
148
|
-
].join( '\n' );
|
|
149
|
-
const result = await runLoader( join( dir, 'steps.js' ), src );
|
|
150
|
-
expect( result.warnings ).toHaveLength( 1 );
|
|
151
|
-
expect( result.warnings[0].message ).toMatch( /Invalid call in .*\.js fn/ );
|
|
152
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
153
|
-
} );
|
|
91
|
+
await expect( runLoader( join( dir, 'workflow.js' ), 'const steps = require("./steps.js");' ) )
|
|
92
|
+
.rejects.toThrow( /Invalid activity require.*destructured requires only/ );
|
|
93
|
+
await expect( runLoader( join( dir, 'workflow.js' ), 'const evaluators = require("./evaluators.js");' ) )
|
|
94
|
+
.rejects.toThrow( /Invalid activity require.*destructured requires only/ );
|
|
154
95
|
|
|
155
|
-
it( 'evaluators.js: warns when calling another evaluator inside fn', async () => {
|
|
156
|
-
const dir = mkdtempSync( join( tmpdir(), 'evals-call-reject-' ) );
|
|
157
|
-
// Can only test same-type components since cross-type declarations are now blocked by instantiation validation
|
|
158
|
-
const src = [
|
|
159
|
-
'const E1 = evaluator({ name: "e1" });',
|
|
160
|
-
'const E2 = evaluator({ name: "e2" });',
|
|
161
|
-
'const obj = { fn: function() { E2(); } };'
|
|
162
|
-
].join( '\n' );
|
|
163
|
-
const result = await runLoader( join( dir, 'evaluators.js' ), src );
|
|
164
|
-
expect( result.warnings ).toHaveLength( 1 );
|
|
165
|
-
expect( result.warnings[0].message ).toMatch( /Invalid call in .*\.js fn/ );
|
|
166
96
|
rmSync( dir, { recursive: true, force: true } );
|
|
167
97
|
} );
|
|
168
98
|
|
|
169
|
-
it( '
|
|
170
|
-
const dir = mkdtempSync( join( tmpdir(), '
|
|
171
|
-
const stepsSrc = [
|
|
172
|
-
'function helper() { return 1; }',
|
|
173
|
-
'const obj = { fn: function() { helper(); } };'
|
|
174
|
-
].join( '\n' );
|
|
175
|
-
await expect( runLoader( join( dir, 'steps.js' ), stepsSrc ) ).resolves.toBeTruthy();
|
|
99
|
+
it( 'rejects non-named exports from activity files', async () => {
|
|
100
|
+
const dir = mkdtempSync( join( tmpdir(), 'activity-export-shape-' ) );
|
|
176
101
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
await expect( runLoader( join( dir, '
|
|
182
|
-
|
|
183
|
-
} );
|
|
102
|
+
await expect( runLoader( join( dir, 'steps.js' ), 'export default step({ name: "a" });' ) )
|
|
103
|
+
.rejects.toThrow( /Invalid activity export.*named exports only/ );
|
|
104
|
+
await expect( runLoader( join( dir, 'evaluators.js' ), 'export * from "./other_evaluators.js";' ) )
|
|
105
|
+
.rejects.toThrow( /Invalid activity export.*named exports only/ );
|
|
106
|
+
await expect( runLoader( join( dir, 'steps.js' ), 'export const A = step({ name: "a" });' ) )
|
|
107
|
+
.resolves.toBeTruthy();
|
|
184
108
|
|
|
185
|
-
it( 'workflow.js: allows require from steps/evaluators/workflow; allows other require', async () => {
|
|
186
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-req-' ) );
|
|
187
|
-
writeFileSync( join( dir, 'steps.js' ), 'export const S = step({ name: "s" })\n' );
|
|
188
|
-
writeFileSync( join( dir, 'evaluators.js' ), 'export const E = evaluator({ name: "e" })\n' );
|
|
189
|
-
writeFileSync( join( dir, 'workflow.js' ), 'export default workflow({ name: "w" })\n' );
|
|
190
|
-
const ok = [
|
|
191
|
-
'const { S } = require("./steps.js");',
|
|
192
|
-
'const { E } = require("./evaluators.js");',
|
|
193
|
-
'const W = require("./workflow.js");'
|
|
194
|
-
].join( '\n' );
|
|
195
|
-
await expect( runLoader( join( dir, 'workflow.js' ), ok ) ).resolves.toBeTruthy();
|
|
196
|
-
// Also allow random files (not rejected anymore)
|
|
197
|
-
const ok2 = 'const X = require("./random_file.js");';
|
|
198
|
-
await expect( runLoader( join( dir, 'workflow.js' ), ok2 ) ).resolves.toBeTruthy();
|
|
199
109
|
rmSync( dir, { recursive: true, force: true } );
|
|
200
110
|
} );
|
|
201
111
|
|
|
202
|
-
it( '
|
|
203
|
-
const dir = mkdtempSync( join( tmpdir(), '
|
|
204
|
-
const result1 = await runLoader( join( dir, 'steps.js' ), 'import { E } from "./evaluators.js";' );
|
|
205
|
-
expect( result1.warnings ).toHaveLength( 0 );
|
|
206
|
-
const result2 = await runLoader( join( dir, 'steps.js' ), 'import WF from "./workflow.js";' );
|
|
207
|
-
expect( result2.warnings ).toHaveLength( 0 );
|
|
208
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
209
|
-
} );
|
|
112
|
+
it( 'rejects top-level activity calls but allows calls inside helper functions', async () => {
|
|
113
|
+
const dir = mkdtempSync( join( tmpdir(), 'top-level-activity-calls-' ) );
|
|
210
114
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
218
|
-
} );
|
|
115
|
+
await expect( runLoader( join( dir, 'steps.js' ), 'const A = step({ name: "a" });\nA();' ) )
|
|
116
|
+
.rejects.toThrow( /Invalid top-level step call 'A'/ );
|
|
117
|
+
await expect( runLoader( join( dir, 'evaluators.js' ), 'const E = evaluator({ name: "e" });\nE();' ) )
|
|
118
|
+
.rejects.toThrow( /Invalid top-level evaluator call 'E'/ );
|
|
119
|
+
await expect( runLoader( join( dir, 'steps.js' ), 'const A = step({ name: "a" });\nfunction helper() { return A(); }' ) )
|
|
120
|
+
.resolves.toBeTruthy();
|
|
219
121
|
|
|
220
|
-
it( 'top-level calls outside fn are allowed in steps.js and evaluators.js', async () => {
|
|
221
|
-
const dir = mkdtempSync( join( tmpdir(), 'toplevel-allowed-' ) );
|
|
222
|
-
const stepsTop = [ 'const A = step({ name: "a" });', 'A();' ].join( '\n' );
|
|
223
|
-
await expect( runLoader( join( dir, 'steps.js' ), stepsTop ) ).resolves.toBeTruthy();
|
|
224
|
-
const evaluatorsTop = [ 'const E = evaluator({ name: "e" });', 'E();' ].join( '\n' );
|
|
225
|
-
await expect( runLoader( join( dir, 'evaluators.js' ), evaluatorsTop ) ).resolves.toBeTruthy();
|
|
226
122
|
rmSync( dir, { recursive: true, force: true } );
|
|
227
123
|
} );
|
|
228
124
|
|
|
229
|
-
it( '
|
|
230
|
-
const dir = mkdtempSync( join( tmpdir(), '
|
|
231
|
-
|
|
232
|
-
const src1 = 'import { T } from "./types.js";';
|
|
233
|
-
await expect( runLoader( join( dir, 'workflow.js' ), src1 ) ).resolves.toBeTruthy();
|
|
234
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
235
|
-
} );
|
|
236
|
-
|
|
237
|
-
it( 'workflow.js: allows importing any file (consts/constants/vars/variables/random)', async () => {
|
|
238
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-extra-allow-' ) );
|
|
239
|
-
const bases = [ 'consts', 'constants', 'vars', 'variables', 'random', 'anything' ];
|
|
240
|
-
for ( const base of bases ) {
|
|
241
|
-
writeFileSync( join( dir, `${base}.js` ), 'export const X = 1\n' );
|
|
242
|
-
const src = `import x from "./${base}.js";`;
|
|
243
|
-
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
244
|
-
}
|
|
245
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
246
|
-
} );
|
|
125
|
+
it( 'warns when activity fn bodies call activities or workflows', async () => {
|
|
126
|
+
const dir = mkdtempSync( join( tmpdir(), 'activity-fn-call-warnings-' ) );
|
|
127
|
+
writeMockGrowthxlabsCatalog( dir, 'cat.warn' );
|
|
247
128
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
expect( resultOk.warnings ).toHaveLength( 0 );
|
|
259
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
260
|
-
} );
|
|
129
|
+
const stepResult = await runLoader( join( dir, 'steps.js' ), [
|
|
130
|
+
'const A = step({ name: "a" });',
|
|
131
|
+
'const B = step({ name: "b" });',
|
|
132
|
+
'const obj = { fn: function() { B(); } };'
|
|
133
|
+
].join( '\n' ) );
|
|
134
|
+
const evaluatorResult = await runLoader( join( dir, 'evaluators.js' ), [
|
|
135
|
+
'import { sumNumbers } from "@growthxlabs/workflows_catalog";',
|
|
136
|
+
'const E = evaluator({ name: "e", fn: async () => ({ value: 1 }) });',
|
|
137
|
+
'const obj = { fn: function() { sumNumbers(); } };'
|
|
138
|
+
].join( '\n' ) );
|
|
261
139
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
expect(
|
|
266
|
-
const result2 = await runLoader( join( dir, 'evaluators.js' ), 'const W = require("./workflow.js");' );
|
|
267
|
-
expect( result2.warnings ).toHaveLength( 0 );
|
|
268
|
-
const ok = 'const util = require("./util.js");';
|
|
269
|
-
const resultOk = await runLoader( join( dir, 'evaluators.js' ), ok );
|
|
270
|
-
expect( resultOk.warnings ).toHaveLength( 0 );
|
|
140
|
+
expect( stepResult.warnings ).toHaveLength( 1 );
|
|
141
|
+
expect( stepResult.warnings[0].message ).toMatch( /Invalid call in .*steps\.js fn: calling a step/ );
|
|
142
|
+
expect( evaluatorResult.warnings ).toHaveLength( 1 );
|
|
143
|
+
expect( evaluatorResult.warnings[0].message ).toMatch( /Invalid call in .*evaluators\.js fn: calling a workflow/ );
|
|
271
144
|
rmSync( dir, { recursive: true, force: true } );
|
|
272
145
|
} );
|
|
273
146
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
describe( 'folder-based utilities', () => {
|
|
279
|
-
it( 'workflow.js: allows imports from ./utils/helper.js (folder-based utils)', async () => {
|
|
280
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-folder-utils-' ) );
|
|
281
|
-
mkdirSync( join( dir, 'utils' ) );
|
|
282
|
-
writeFileSync( join( dir, 'utils', 'helper.js' ), 'export const helper = () => 1;\n' );
|
|
283
|
-
const src = 'import { helper } from "./utils/helper.js";';
|
|
284
|
-
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
285
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
286
|
-
} );
|
|
287
|
-
|
|
288
|
-
it( 'workflow.js: allows imports from ./clients/redis.js (folder-based clients)', async () => {
|
|
289
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-folder-clients-' ) );
|
|
290
|
-
mkdirSync( join( dir, 'clients' ) );
|
|
291
|
-
writeFileSync( join( dir, 'clients', 'redis.js' ), 'export const client = {};\n' );
|
|
292
|
-
const src = 'import { client } from "./clients/redis.js";';
|
|
293
|
-
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
294
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
295
|
-
} );
|
|
296
|
-
|
|
297
|
-
it( 'steps/fetch_data.js: allows imports from ../utils/http.js', async () => {
|
|
298
|
-
const dir = mkdtempSync( join( tmpdir(), 'steps-folder-utils-' ) );
|
|
299
|
-
mkdirSync( join( dir, 'steps' ) );
|
|
300
|
-
mkdirSync( join( dir, 'utils' ) );
|
|
301
|
-
writeFileSync( join( dir, 'utils', 'http.js' ), 'export const get = () => {};\n' );
|
|
302
|
-
const src = 'import { get } from "../utils/http.js";';
|
|
303
|
-
await expect( runLoader( join( dir, 'steps', 'fetch_data.js' ), src ) ).resolves.toBeTruthy();
|
|
304
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
305
|
-
} );
|
|
306
|
-
|
|
307
|
-
it( 'evaluators/quality.js: allows imports from ../utils/metrics.js', async () => {
|
|
308
|
-
const dir = mkdtempSync( join( tmpdir(), 'evals-folder-utils-' ) );
|
|
309
|
-
mkdirSync( join( dir, 'evaluators' ) );
|
|
310
|
-
mkdirSync( join( dir, 'utils' ) );
|
|
311
|
-
writeFileSync( join( dir, 'utils', 'metrics.js' ), 'export const compute = () => {};\n' );
|
|
312
|
-
const src = 'import { compute } from "../utils/metrics.js";';
|
|
313
|
-
await expect( runLoader( join( dir, 'evaluators', 'quality.js' ), src ) ).resolves.toBeTruthy();
|
|
314
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
315
|
-
} );
|
|
316
|
-
} );
|
|
317
|
-
|
|
318
|
-
describe( 'shared directory imports', () => {
|
|
319
|
-
it( 'workflow.js: allows imports from ../../shared/utils/keys.js', async () => {
|
|
320
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-utils-' ) );
|
|
321
|
-
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
322
|
-
mkdirSync( join( dir, 'shared', 'utils' ), { recursive: true } );
|
|
323
|
-
writeFileSync( join( dir, 'shared', 'utils', 'keys.js' ), 'export const KEY = "test";\n' );
|
|
324
|
-
const src = 'import { KEY } from "../../shared/utils/keys.js";';
|
|
325
|
-
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
326
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
327
|
-
} );
|
|
328
|
-
|
|
329
|
-
it( 'workflow.js: allows imports from ../../shared/steps/common.js', async () => {
|
|
330
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-steps-' ) );
|
|
331
|
-
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
332
|
-
mkdirSync( join( dir, 'shared', 'steps' ), { recursive: true } );
|
|
333
|
-
writeFileSync( join( dir, 'shared', 'steps', 'common.js' ), 'export const commonStep = step({ name: "common" });\n' );
|
|
334
|
-
const src = 'import { commonStep } from "../../shared/steps/common.js";';
|
|
335
|
-
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
336
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
337
|
-
} );
|
|
338
|
-
|
|
339
|
-
it( 'workflow.js: allows imports from ../../shared/evaluators/quality.js', async () => {
|
|
340
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-evals-' ) );
|
|
341
|
-
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
342
|
-
mkdirSync( join( dir, 'shared', 'evaluators' ), { recursive: true } );
|
|
343
|
-
writeFileSync( join( dir, 'shared', 'evaluators', 'quality.js' ), 'export const qualityEval = evaluator({ name: "quality" });\n' );
|
|
344
|
-
const src = 'import { qualityEval } from "../../shared/evaluators/quality.js";';
|
|
345
|
-
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
346
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
347
|
-
} );
|
|
348
|
-
|
|
349
|
-
it( 'workflow.js: allows imports from ../../clients/pokeapi.js', async () => {
|
|
350
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-clients-' ) );
|
|
351
|
-
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
352
|
-
mkdirSync( join( dir, 'clients' ), { recursive: true } );
|
|
353
|
-
writeFileSync( join( dir, 'clients', 'pokeapi.js' ), 'export const getPokemon = () => {};\n' );
|
|
354
|
-
const src = 'import { getPokemon } from "../../clients/pokeapi.js";';
|
|
355
|
-
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
356
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
357
|
-
} );
|
|
358
|
-
|
|
359
|
-
it( 'steps.ts: allows imports from ../../shared/utils/keys.js', async () => {
|
|
360
|
-
const dir = mkdtempSync( join( tmpdir(), 'steps-shared-utils-' ) );
|
|
361
|
-
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
362
|
-
mkdirSync( join( dir, 'shared', 'utils' ), { recursive: true } );
|
|
363
|
-
writeFileSync( join( dir, 'shared', 'utils', 'keys.js' ), 'export const KEY = "test";\n' );
|
|
364
|
-
const src = 'import { KEY } from "../../shared/utils/keys.js";';
|
|
365
|
-
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'steps.js' ), src ) ).resolves.toBeTruthy();
|
|
366
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
367
|
-
} );
|
|
368
|
-
|
|
369
|
-
it( 'steps.ts: allows imports from ../../clients/redis.js', async () => {
|
|
370
|
-
const dir = mkdtempSync( join( tmpdir(), 'steps-clients-' ) );
|
|
371
|
-
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
372
|
-
mkdirSync( join( dir, 'clients' ), { recursive: true } );
|
|
373
|
-
writeFileSync( join( dir, 'clients', 'redis.js' ), 'export const client = {};\n' );
|
|
374
|
-
const src = 'import { client } from "../../clients/redis.js";';
|
|
375
|
-
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'steps.js' ), src ) ).resolves.toBeTruthy();
|
|
376
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
377
|
-
} );
|
|
378
|
-
|
|
379
|
-
it( 'evaluators.ts: allows imports from ../../shared/utils/helpers.js', async () => {
|
|
380
|
-
const dir = mkdtempSync( join( tmpdir(), 'evals-shared-utils-' ) );
|
|
381
|
-
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
382
|
-
mkdirSync( join( dir, 'shared', 'utils' ), { recursive: true } );
|
|
383
|
-
writeFileSync( join( dir, 'shared', 'utils', 'helpers.js' ), 'export const helper = () => 1;\n' );
|
|
384
|
-
const src = 'import { helper } from "../../shared/utils/helpers.js";';
|
|
385
|
-
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'evaluators.js' ), src ) ).resolves.toBeTruthy();
|
|
386
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
387
|
-
} );
|
|
388
|
-
} );
|
|
389
|
-
|
|
390
|
-
describe( 'cross-component imports - now allowed (no import restrictions)', () => {
|
|
391
|
-
it( 'steps.ts: allows imports from ../../shared/steps/common.js', async () => {
|
|
392
|
-
const dir = mkdtempSync( join( tmpdir(), 'steps-shared-steps-allow-' ) );
|
|
393
|
-
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
394
|
-
mkdirSync( join( dir, 'shared', 'steps' ), { recursive: true } );
|
|
395
|
-
writeFileSync( join( dir, 'shared', 'steps', 'common.js' ), 'export const commonStep = step({ name: "common" });\n' );
|
|
396
|
-
const src = 'import { commonStep } from "../../shared/steps/common.js";';
|
|
397
|
-
const result = await runLoader( join( dir, 'workflows', 'my_workflow', 'steps.js' ), src );
|
|
398
|
-
expect( result.warnings ).toHaveLength( 0 );
|
|
399
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
400
|
-
} );
|
|
401
|
-
|
|
402
|
-
it( 'steps.ts: allows imports from ../../shared/evaluators/quality.js', async () => {
|
|
403
|
-
const dir = mkdtempSync( join( tmpdir(), 'steps-shared-evals-allow-' ) );
|
|
404
|
-
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
405
|
-
mkdirSync( join( dir, 'shared', 'evaluators' ), { recursive: true } );
|
|
406
|
-
writeFileSync( join( dir, 'shared', 'evaluators', 'quality.js' ), 'export const qualityEval = evaluator({ name: "quality" });\n' );
|
|
407
|
-
const src = 'import { qualityEval } from "../../shared/evaluators/quality.js";';
|
|
408
|
-
const result = await runLoader( join( dir, 'workflows', 'my_workflow', 'steps.js' ), src );
|
|
409
|
-
expect( result.warnings ).toHaveLength( 0 );
|
|
410
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
411
|
-
} );
|
|
147
|
+
it( 'allows component instantiation in matching files', async () => {
|
|
148
|
+
const dir = mkdtempSync( join( tmpdir(), 'instantiation-allowed-' ) );
|
|
149
|
+
mkdirSync( join( dir, 'steps' ) );
|
|
150
|
+
mkdirSync( join( dir, 'evaluators' ) );
|
|
412
151
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
152
|
+
await expect( runLoader(
|
|
153
|
+
join( dir, 'steps', 'fetch_data.js' ),
|
|
154
|
+
'export const fetchData = step({ name: "fetch_data", fn: async () => ({}) });'
|
|
155
|
+
) ).resolves.toBeTruthy();
|
|
156
|
+
await expect( runLoader(
|
|
157
|
+
join( dir, 'evaluators', 'quality.js' ),
|
|
158
|
+
'export const quality = evaluator({ name: "quality", fn: async () => ({ value: 1 }) });'
|
|
159
|
+
) ).resolves.toBeTruthy();
|
|
160
|
+
await expect( runLoader(
|
|
161
|
+
join( dir, 'workflow.js' ),
|
|
162
|
+
'export default workflow({ name: "wf", fn: async () => ({}) });'
|
|
163
|
+
) ).resolves.toBeTruthy();
|
|
423
164
|
|
|
424
|
-
|
|
425
|
-
const dir = mkdtempSync( join( tmpdir(), 'evals-shared-evals-allow-' ) );
|
|
426
|
-
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
427
|
-
mkdirSync( join( dir, 'shared', 'evaluators' ), { recursive: true } );
|
|
428
|
-
writeFileSync( join( dir, 'shared', 'evaluators', 'other.js' ), 'export const otherEval = evaluator({ name: "other" });\n' );
|
|
429
|
-
const src = 'import { otherEval } from "../../shared/evaluators/other.js";';
|
|
430
|
-
const result = await runLoader( join( dir, 'workflows', 'my_workflow', 'evaluators.js' ), src );
|
|
431
|
-
expect( result.warnings ).toHaveLength( 0 );
|
|
432
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
433
|
-
} );
|
|
434
|
-
} );
|
|
435
|
-
|
|
436
|
-
describe( 'workflow import scope', () => {
|
|
437
|
-
it( 'workflow.js: allows imports from other workflow directories (cross-workflow)', async () => {
|
|
438
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-cross-allow-' ) );
|
|
439
|
-
mkdirSync( join( dir, 'workflows', 'workflow_a' ), { recursive: true } );
|
|
440
|
-
mkdirSync( join( dir, 'workflows', 'workflow_b' ), { recursive: true } );
|
|
441
|
-
writeFileSync( join( dir, 'workflows', 'workflow_b', 'steps.js' ), 'export const S = step({ name: "s" });\n' );
|
|
442
|
-
// Cross-workflow imports are allowed for workflows (they can import steps from other workflows)
|
|
443
|
-
const src = 'import { S } from "../workflow_b/steps.js";';
|
|
444
|
-
await expect( runLoader( join( dir, 'workflows', 'workflow_a', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
445
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
446
|
-
} );
|
|
447
|
-
|
|
448
|
-
it( 'workflow.js: allows imports from utils with relative parent paths', async () => {
|
|
449
|
-
// The validator does not enforce strict scope boundaries, it validates by file type patterns
|
|
450
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-parent-utils-' ) );
|
|
451
|
-
mkdirSync( join( dir, 'src', 'workflows', 'my_workflow' ), { recursive: true } );
|
|
452
|
-
mkdirSync( join( dir, 'utils' ), { recursive: true } );
|
|
453
|
-
writeFileSync( join( dir, 'utils', 'helpers.js' ), 'export const helper = () => 1;\n' );
|
|
454
|
-
const src = 'import { helper } from "../../../utils/helpers.js";';
|
|
455
|
-
// This should pass because it's not a component file
|
|
456
|
-
await expect( runLoader( join( dir, 'src', 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
457
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
458
|
-
} );
|
|
459
|
-
} );
|
|
460
|
-
|
|
461
|
-
// =====================================================
|
|
462
|
-
// Arbitrary path imports (proving any folder name works)
|
|
463
|
-
// =====================================================
|
|
464
|
-
|
|
465
|
-
describe( 'arbitrary path imports', () => {
|
|
466
|
-
it( 'workflow.js: allows imports from ./foobar.js', async () => {
|
|
467
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-arbitrary-1-' ) );
|
|
468
|
-
const src = 'import { foo } from "./foobar.js";';
|
|
469
|
-
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
470
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
471
|
-
} );
|
|
472
|
-
|
|
473
|
-
it( 'workflow.js: allows imports from ./foobar/baz.js', async () => {
|
|
474
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-arbitrary-2-' ) );
|
|
475
|
-
mkdirSync( join( dir, 'foobar' ) );
|
|
476
|
-
writeFileSync( join( dir, 'foobar', 'baz.js' ), 'export const baz = 1;\n' );
|
|
477
|
-
const src = 'import { baz } from "./foobar/baz.js";';
|
|
478
|
-
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
479
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
480
|
-
} );
|
|
481
|
-
|
|
482
|
-
it( 'workflow.js: allows imports from ../../shared/foobar.js', async () => {
|
|
483
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-arbitrary-3-' ) );
|
|
484
|
-
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
485
|
-
mkdirSync( join( dir, 'shared' ), { recursive: true } );
|
|
486
|
-
writeFileSync( join( dir, 'shared', 'foobar.js' ), 'export const foobar = 1;\n' );
|
|
487
|
-
const src = 'import { foobar } from "../../shared/foobar.js";';
|
|
488
|
-
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
489
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
490
|
-
} );
|
|
491
|
-
|
|
492
|
-
it( 'workflow.js: allows imports from ../../shared/foobar/baz.js', async () => {
|
|
493
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-arbitrary-4-' ) );
|
|
494
|
-
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
495
|
-
mkdirSync( join( dir, 'shared', 'foobar' ), { recursive: true } );
|
|
496
|
-
writeFileSync( join( dir, 'shared', 'foobar', 'baz.js' ), 'export const baz = 1;\n' );
|
|
497
|
-
const src = 'import { baz } from "../../shared/foobar/baz.js";';
|
|
498
|
-
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
499
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
500
|
-
} );
|
|
501
|
-
|
|
502
|
-
it( 'steps.js: allows imports from ./helpers/anything.js', async () => {
|
|
503
|
-
const dir = mkdtempSync( join( tmpdir(), 'steps-arbitrary-1-' ) );
|
|
504
|
-
mkdirSync( join( dir, 'helpers' ) );
|
|
505
|
-
writeFileSync( join( dir, 'helpers', 'anything.js' ), 'export const anything = 1;\n' );
|
|
506
|
-
const src = 'import { anything } from "./helpers/anything.js";';
|
|
507
|
-
await expect( runLoader( join( dir, 'steps.js' ), src ) ).resolves.toBeTruthy();
|
|
508
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
509
|
-
} );
|
|
510
|
-
|
|
511
|
-
it( 'evaluators.js: allows imports from ./my_custom_lib/tools.js', async () => {
|
|
512
|
-
const dir = mkdtempSync( join( tmpdir(), 'evals-arbitrary-1-' ) );
|
|
513
|
-
mkdirSync( join( dir, 'my_custom_lib' ) );
|
|
514
|
-
writeFileSync( join( dir, 'my_custom_lib', 'tools.js' ), 'export const tools = {};\n' );
|
|
515
|
-
const src = 'import { tools } from "./my_custom_lib/tools.js";';
|
|
516
|
-
await expect( runLoader( join( dir, 'evaluators.js' ), src ) ).resolves.toBeTruthy();
|
|
517
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
518
|
-
} );
|
|
165
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
519
166
|
} );
|
|
520
167
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
168
|
+
it( 'rejects component instantiation in mismatched files', async () => {
|
|
169
|
+
const dir = mkdtempSync( join( tmpdir(), 'instantiation-rejected-' ) );
|
|
170
|
+
mkdirSync( join( dir, 'shared' ) );
|
|
524
171
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
172
|
+
await expect( runLoader(
|
|
173
|
+
join( dir, 'utils.js' ),
|
|
174
|
+
'export const badStep = step({ name: "bad", fn: async () => ({}) });'
|
|
175
|
+
) ).rejects.toThrow( /Invalid instantiation location.*step\(\).*steps/ );
|
|
176
|
+
await expect( runLoader(
|
|
177
|
+
join( dir, 'steps.js' ),
|
|
178
|
+
'export const badEval = evaluator({ name: "bad", fn: async () => ({ value: 1 }) });'
|
|
179
|
+
) ).rejects.toThrow( /Invalid instantiation location.*evaluator\(\).*evaluators/ );
|
|
180
|
+
await expect( runLoader(
|
|
181
|
+
join( dir, 'shared', 'common.js' ),
|
|
182
|
+
'export const badWf = workflow({ name: "bad", fn: async () => ({}) });'
|
|
183
|
+
) ).rejects.toThrow( /Invalid instantiation location.*workflow\(\).*workflow/ );
|
|
536
184
|
|
|
537
|
-
|
|
538
|
-
const dir = mkdtempSync( join( tmpdir(), 'step-shared-allowed-' ) );
|
|
539
|
-
mkdirSync( join( dir, 'src', 'shared', 'steps' ), { recursive: true } );
|
|
540
|
-
const src = [
|
|
541
|
-
'import { step } from "@outputai/core";',
|
|
542
|
-
'export const commonStep = step({ name: "common_step", fn: async () => ({}) });'
|
|
543
|
-
].join( '\n' );
|
|
544
|
-
await expect( runLoader( join( dir, 'src', 'shared', 'steps', 'common.js' ), src ) ).resolves.toBeTruthy();
|
|
545
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
546
|
-
} );
|
|
547
|
-
|
|
548
|
-
it( 'evaluator() called in evaluators/quality.js is allowed', async () => {
|
|
549
|
-
const dir = mkdtempSync( join( tmpdir(), 'eval-folder-allowed-' ) );
|
|
550
|
-
mkdirSync( join( dir, 'evaluators' ) );
|
|
551
|
-
const src = [
|
|
552
|
-
'import { evaluator } from "@outputai/core";',
|
|
553
|
-
'export const quality = evaluator({ name: "quality", fn: async () => ({ value: 1 }) });'
|
|
554
|
-
].join( '\n' );
|
|
555
|
-
await expect( runLoader( join( dir, 'evaluators', 'quality.js' ), src ) ).resolves.toBeTruthy();
|
|
556
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
557
|
-
} );
|
|
558
|
-
|
|
559
|
-
it( 'evaluator() called in src/shared/evaluators/metrics.js is allowed', async () => {
|
|
560
|
-
const dir = mkdtempSync( join( tmpdir(), 'eval-shared-allowed-' ) );
|
|
561
|
-
mkdirSync( join( dir, 'src', 'shared', 'evaluators' ), { recursive: true } );
|
|
562
|
-
const src = [
|
|
563
|
-
'import { evaluator } from "@outputai/core";',
|
|
564
|
-
'export const metrics = evaluator({ name: "metrics", fn: async () => ({ value: 1 }) });'
|
|
565
|
-
].join( '\n' );
|
|
566
|
-
await expect( runLoader( join( dir, 'src', 'shared', 'evaluators', 'metrics.js' ), src ) ).resolves.toBeTruthy();
|
|
567
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
568
|
-
} );
|
|
185
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
569
186
|
} );
|
|
570
187
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
const src = [
|
|
575
|
-
'import { step } from "@outputai/core";',
|
|
576
|
-
'export const badStep = step({ name: "bad", fn: async () => ({}) });'
|
|
577
|
-
].join( '\n' );
|
|
578
|
-
await expect( runLoader( join( dir, 'utils.js' ), src ) )
|
|
579
|
-
.rejects.toThrow( /Invalid instantiation location.*step\(\).*steps/ );
|
|
580
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
581
|
-
} );
|
|
582
|
-
|
|
583
|
-
it( 'step() called in clients/api.js is blocked by validator', async () => {
|
|
584
|
-
const dir = mkdtempSync( join( tmpdir(), 'step-clients-fail-' ) );
|
|
585
|
-
mkdirSync( join( dir, 'clients' ) );
|
|
586
|
-
const src = [
|
|
587
|
-
'import { step } from "@outputai/core";',
|
|
588
|
-
'export const badStep = step({ name: "bad", fn: async () => ({}) });'
|
|
589
|
-
].join( '\n' );
|
|
590
|
-
await expect( runLoader( join( dir, 'clients', 'api.js' ), src ) )
|
|
591
|
-
.rejects.toThrow( /Invalid instantiation location.*step\(\).*steps/ );
|
|
592
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
593
|
-
} );
|
|
594
|
-
|
|
595
|
-
it( 'evaluator() called in utils.js is blocked by validator', async () => {
|
|
596
|
-
const dir = mkdtempSync( join( tmpdir(), 'eval-utils-fail-' ) );
|
|
597
|
-
const src = [
|
|
598
|
-
'import { evaluator } from "@outputai/core";',
|
|
599
|
-
'export const badEval = evaluator({ name: "bad", fn: async () => ({ value: 1 }) });'
|
|
600
|
-
].join( '\n' );
|
|
601
|
-
await expect( runLoader( join( dir, 'utils.js' ), src ) )
|
|
602
|
-
.rejects.toThrow( /Invalid instantiation location.*evaluator\(\).*evaluators/ );
|
|
603
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
604
|
-
} );
|
|
605
|
-
|
|
606
|
-
it( 'evaluator() called in clients/api.js is blocked by validator', async () => {
|
|
607
|
-
const dir = mkdtempSync( join( tmpdir(), 'eval-clients-fail-' ) );
|
|
608
|
-
mkdirSync( join( dir, 'clients' ) );
|
|
609
|
-
const src = [
|
|
610
|
-
'import { evaluator } from "@outputai/core";',
|
|
611
|
-
'export const badEval = evaluator({ name: "bad", fn: async () => ({ value: 1 }) });'
|
|
612
|
-
].join( '\n' );
|
|
613
|
-
await expect( runLoader( join( dir, 'clients', 'api.js' ), src ) )
|
|
614
|
-
.rejects.toThrow( /Invalid instantiation location.*evaluator\(\).*evaluators/ );
|
|
615
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
616
|
-
} );
|
|
617
|
-
|
|
618
|
-
it( 'evaluator() called in helpers.js is blocked by validator', async () => {
|
|
619
|
-
const dir = mkdtempSync( join( tmpdir(), 'eval-helpers-fail-' ) );
|
|
620
|
-
const src = [
|
|
621
|
-
'import { evaluator } from "@outputai/core";',
|
|
622
|
-
'export const badEval = evaluator({ name: "bad", fn: async () => ({ value: 1 }) });'
|
|
623
|
-
].join( '\n' );
|
|
624
|
-
await expect( runLoader( join( dir, 'helpers.js' ), src ) )
|
|
625
|
-
.rejects.toThrow( /Invalid instantiation location.*evaluator\(\).*evaluators/ );
|
|
626
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
627
|
-
} );
|
|
628
|
-
|
|
629
|
-
it( 'step() called in evaluators.js is blocked by validator', async () => {
|
|
630
|
-
const dir = mkdtempSync( join( tmpdir(), 'step-evals-fail-' ) );
|
|
631
|
-
const src = [
|
|
632
|
-
'import { step } from "@outputai/core";',
|
|
633
|
-
'export const badStep = step({ name: "bad", fn: async () => ({}) });'
|
|
634
|
-
].join( '\n' );
|
|
635
|
-
await expect( runLoader( join( dir, 'evaluators.js' ), src ) )
|
|
636
|
-
.rejects.toThrow( /Invalid instantiation location.*step\(\).*steps/ );
|
|
637
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
638
|
-
} );
|
|
639
|
-
|
|
640
|
-
it( 'evaluator() called in steps.js is blocked by validator', async () => {
|
|
641
|
-
const dir = mkdtempSync( join( tmpdir(), 'eval-steps-fail-' ) );
|
|
642
|
-
const src = [
|
|
643
|
-
'import { evaluator } from "@outputai/core";',
|
|
644
|
-
'export const badEval = evaluator({ name: "bad", fn: async () => ({ value: 1 }) });'
|
|
645
|
-
].join( '\n' );
|
|
646
|
-
await expect( runLoader( join( dir, 'steps.js' ), src ) )
|
|
647
|
-
.rejects.toThrow( /Invalid instantiation location.*evaluator\(\).*evaluators/ );
|
|
648
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
649
|
-
} );
|
|
188
|
+
it( 'resolves bare npm workflows for require warnings in activity fn bodies', async () => {
|
|
189
|
+
const dir = mkdtempSync( join( tmpdir(), 'bare-require-workflow-warning-' ) );
|
|
190
|
+
writeMockGrowthxlabsCatalog( dir, 'cat.warn.req' );
|
|
650
191
|
|
|
651
|
-
|
|
652
|
-
const
|
|
653
|
-
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
'export const badWf = workflow({ name: "bad", fn: async () => ({}) });'
|
|
657
|
-
].join( '\n' );
|
|
658
|
-
await expect( runLoader( join( dir, 'shared', 'common.js' ), src ) )
|
|
659
|
-
.rejects.toThrow( /Invalid instantiation location.*workflow\(\).*workflow/ );
|
|
660
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
661
|
-
} );
|
|
192
|
+
const result = await runLoader( join( dir, 'evaluators.js' ), [
|
|
193
|
+
'const { sumNumbers } = require("@growthxlabs/workflows_catalog");',
|
|
194
|
+
'const E = evaluator({ name: "e", fn: async () => ({ value: 1 }) });',
|
|
195
|
+
'const obj = { fn: function() { sumNumbers(); } };'
|
|
196
|
+
].join( '\n' ) );
|
|
662
197
|
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
const src = [
|
|
667
|
-
'import { workflow } from "@outputai/core";',
|
|
668
|
-
'export const badWf = workflow({ name: "bad", fn: async () => ({}) });'
|
|
669
|
-
].join( '\n' );
|
|
670
|
-
await expect( runLoader( join( dir, 'utils', 'index.js' ), src ) )
|
|
671
|
-
.rejects.toThrow( /Invalid instantiation location.*workflow\(\).*workflow/ );
|
|
672
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
673
|
-
} );
|
|
198
|
+
expect( result.warnings ).toHaveLength( 1 );
|
|
199
|
+
expect( result.warnings[0].message ).toMatch( /Invalid call in .*evaluators\.js fn: calling a workflow/ );
|
|
200
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
674
201
|
} );
|
|
675
202
|
} );
|