@output.ai/core 0.2.2 → 0.3.0-dev.pr263-a59dd0e
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/worker/loader.js +2 -3
- package/src/worker/loader.spec.js +21 -0
- package/src/worker/loader_tools.js +45 -4
- package/src/worker/loader_tools.spec.js +80 -0
- package/src/worker/webpack_loaders/consts.js +0 -14
- package/src/worker/webpack_loaders/tools.js +71 -27
- package/src/worker/webpack_loaders/tools.spec.js +63 -56
- package/src/worker/webpack_loaders/workflow_rewriter/index.spec.js +17 -11
- package/src/worker/webpack_loaders/workflow_validator/index.mjs +99 -33
- package/src/worker/webpack_loaders/workflow_validator/index.spec.js +401 -78
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
|
|
2
|
+
import { mkdtempSync, writeFileSync, rmSync, mkdirSync } from 'node:fs';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import validatorLoader from './index.mjs';
|
|
@@ -17,16 +17,14 @@ function runLoader( filename, source ) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
describe( 'workflow_validator loader', () => {
|
|
20
|
-
it( 'workflow.js: allows imports from steps/
|
|
20
|
+
it( 'workflow.js: allows imports from steps/evaluators/workflow', async () => {
|
|
21
21
|
const dir = mkdtempSync( join( tmpdir(), 'wf-allow-' ) );
|
|
22
22
|
writeFileSync( join( dir, 'steps.js' ), 'export const S = step({ name: "s" })\n' );
|
|
23
|
-
writeFileSync( join( dir, 'shared_steps.js' ), 'export const SS = step({ name: "ss" })\n' );
|
|
24
23
|
writeFileSync( join( dir, 'evaluators.js' ), 'export const E = evaluator({ name: "e" })\n' );
|
|
25
24
|
writeFileSync( join( dir, 'workflow.js' ), 'export const W = workflow({ name: "w" })\n' );
|
|
26
25
|
|
|
27
26
|
const src = [
|
|
28
27
|
'import { S } from "./steps.js";',
|
|
29
|
-
'import { SS } from "./shared_steps.js";',
|
|
30
28
|
'import { E } from "./evaluators.js";',
|
|
31
29
|
'import { W } from "./workflow.js";',
|
|
32
30
|
'const x = 1;'
|
|
@@ -36,10 +34,10 @@ describe( 'workflow_validator loader', () => {
|
|
|
36
34
|
rmSync( dir, { recursive: true, force: true } );
|
|
37
35
|
} );
|
|
38
36
|
|
|
39
|
-
it( 'workflow.js:
|
|
40
|
-
const dir = mkdtempSync( join( tmpdir(), 'wf-
|
|
37
|
+
it( 'workflow.js: allows imports from any non-component file', async () => {
|
|
38
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-any-allow-' ) );
|
|
41
39
|
const src = 'import x from "./foo.js";';
|
|
42
|
-
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).
|
|
40
|
+
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
43
41
|
rmSync( dir, { recursive: true, force: true } );
|
|
44
42
|
} );
|
|
45
43
|
|
|
@@ -54,7 +52,7 @@ describe( 'workflow_validator loader', () => {
|
|
|
54
52
|
rmSync( dir, { recursive: true, force: true } );
|
|
55
53
|
} );
|
|
56
54
|
|
|
57
|
-
it( 'steps.js: rejects importing steps/
|
|
55
|
+
it( 'steps.js: rejects importing steps/evaluators/workflow', async () => {
|
|
58
56
|
const dir = mkdtempSync( join( tmpdir(), 'steps-reject-' ) );
|
|
59
57
|
const src = 'import { S } from "./steps.js";';
|
|
60
58
|
await expect( runLoader( join( dir, 'steps.js' ), src ) ).rejects.toThrow( /Invalid (import|imports|dependency) in steps\.js/ );
|
|
@@ -68,44 +66,34 @@ describe( 'workflow_validator loader', () => {
|
|
|
68
66
|
rmSync( dir, { recursive: true, force: true } );
|
|
69
67
|
} );
|
|
70
68
|
|
|
71
|
-
it( 'evaluators.js: rejects importing evaluators/steps/
|
|
69
|
+
it( 'evaluators.js: rejects importing evaluators/steps/workflow', async () => {
|
|
72
70
|
const dir = mkdtempSync( join( tmpdir(), 'evals-reject-' ) );
|
|
73
71
|
const src = 'import { E } from "./evaluators.js";';
|
|
74
72
|
await expect( runLoader( join( dir, 'evaluators.js' ), src ) ).rejects.toThrow( /Invalid (import|imports|dependency) in evaluators\.js/ );
|
|
75
73
|
rmSync( dir, { recursive: true, force: true } );
|
|
76
74
|
} );
|
|
77
75
|
|
|
78
|
-
it( 'steps.js: rejects calling another step
|
|
76
|
+
it( 'steps.js: rejects calling another step inside fn', async () => {
|
|
79
77
|
const dir = mkdtempSync( join( tmpdir(), 'steps-call-reject-' ) );
|
|
78
|
+
// Can only test same-type components since cross-type declarations are now blocked by instantiation validation
|
|
80
79
|
const src = [
|
|
81
80
|
'const A = step({ name: "a" });',
|
|
82
81
|
'const B = step({ name: "b" });',
|
|
83
82
|
'const obj = { fn: function() { B(); } };'
|
|
84
83
|
].join( '\n' );
|
|
85
84
|
await expect( runLoader( join( dir, 'steps.js' ), src ) ).rejects.toThrow( /Invalid call in .*\.js fn/ );
|
|
86
|
-
|
|
87
|
-
const src2 = [
|
|
88
|
-
'const E = evaluator({ name: "e" });',
|
|
89
|
-
'const obj = { fn: () => { E(); } };'
|
|
90
|
-
].join( '\n' );
|
|
91
|
-
await expect( runLoader( join( dir, 'steps.js' ), src2 ) ).rejects.toThrow( /Invalid call in .*\.js fn/ );
|
|
92
85
|
rmSync( dir, { recursive: true, force: true } );
|
|
93
86
|
} );
|
|
94
87
|
|
|
95
|
-
it( 'evaluators.js: rejects calling another evaluator
|
|
88
|
+
it( 'evaluators.js: rejects calling another evaluator inside fn', async () => {
|
|
96
89
|
const dir = mkdtempSync( join( tmpdir(), 'evals-call-reject-' ) );
|
|
90
|
+
// Can only test same-type components since cross-type declarations are now blocked by instantiation validation
|
|
97
91
|
const src = [
|
|
98
92
|
'const E1 = evaluator({ name: "e1" });',
|
|
99
93
|
'const E2 = evaluator({ name: "e2" });',
|
|
100
94
|
'const obj = { fn: function() { E2(); } };'
|
|
101
95
|
].join( '\n' );
|
|
102
96
|
await expect( runLoader( join( dir, 'evaluators.js' ), src ) ).rejects.toThrow( /Invalid call in .*\.js fn/ );
|
|
103
|
-
|
|
104
|
-
const src2 = [
|
|
105
|
-
'const S = step({ name: "s" });',
|
|
106
|
-
'const obj = { fn: () => { S(); } };'
|
|
107
|
-
].join( '\n' );
|
|
108
|
-
await expect( runLoader( join( dir, 'evaluators.js' ), src2 ) ).rejects.toThrow( /Invalid call in .*\.js fn/ );
|
|
109
97
|
rmSync( dir, { recursive: true, force: true } );
|
|
110
98
|
} );
|
|
111
99
|
|
|
@@ -125,28 +113,25 @@ describe( 'workflow_validator loader', () => {
|
|
|
125
113
|
rmSync( dir, { recursive: true, force: true } );
|
|
126
114
|
} );
|
|
127
115
|
|
|
128
|
-
it( 'workflow.js: allows require from steps/
|
|
116
|
+
it( 'workflow.js: allows require from steps/evaluators/workflow; allows other require', async () => {
|
|
129
117
|
const dir = mkdtempSync( join( tmpdir(), 'wf-req-' ) );
|
|
130
118
|
writeFileSync( join( dir, 'steps.js' ), 'export const S = step({ name: "s" })\n' );
|
|
131
|
-
writeFileSync( join( dir, 'shared_steps.js' ), 'export const SS = step({ name: "ss" })\n' );
|
|
132
119
|
writeFileSync( join( dir, 'evaluators.js' ), 'export const E = evaluator({ name: "e" })\n' );
|
|
133
120
|
writeFileSync( join( dir, 'workflow.js' ), 'export default workflow({ name: "w" })\n' );
|
|
134
121
|
const ok = [
|
|
135
122
|
'const { S } = require("./steps.js");',
|
|
136
|
-
'const { SS } = require("./shared_steps.js");',
|
|
137
123
|
'const { E } = require("./evaluators.js");',
|
|
138
124
|
'const W = require("./workflow.js");'
|
|
139
125
|
].join( '\n' );
|
|
140
126
|
await expect( runLoader( join( dir, 'workflow.js' ), ok ) ).resolves.toBeTruthy();
|
|
141
|
-
|
|
142
|
-
|
|
127
|
+
// Also allow random files (not rejected anymore)
|
|
128
|
+
const ok2 = 'const X = require("./random_file.js");';
|
|
129
|
+
await expect( runLoader( join( dir, 'workflow.js' ), ok2 ) ).resolves.toBeTruthy();
|
|
143
130
|
rmSync( dir, { recursive: true, force: true } );
|
|
144
131
|
} );
|
|
145
132
|
|
|
146
|
-
it( 'steps.js: rejects importing
|
|
133
|
+
it( 'steps.js: rejects importing evaluators/workflow variants', async () => {
|
|
147
134
|
const dir = mkdtempSync( join( tmpdir(), 'steps-reject2-' ) );
|
|
148
|
-
await expect( runLoader( join( dir, 'steps.js' ), 'import { SS } from "./shared_steps.js";' ) )
|
|
149
|
-
.rejects.toThrow( /Invalid (import|imports|dependency) in steps\.js/ );
|
|
150
135
|
await expect( runLoader( join( dir, 'steps.js' ), 'import { E } from "./evaluators.js";' ) )
|
|
151
136
|
.rejects.toThrow( /Invalid (import|imports|dependency) in steps\.js/ );
|
|
152
137
|
await expect( runLoader( join( dir, 'steps.js' ), 'import WF from "./workflow.js";' ) )
|
|
@@ -154,12 +139,10 @@ describe( 'workflow_validator loader', () => {
|
|
|
154
139
|
rmSync( dir, { recursive: true, force: true } );
|
|
155
140
|
} );
|
|
156
141
|
|
|
157
|
-
it( 'evaluators.js: rejects importing steps/
|
|
142
|
+
it( 'evaluators.js: rejects importing steps/workflow variants', async () => {
|
|
158
143
|
const dir = mkdtempSync( join( tmpdir(), 'evals-reject2-' ) );
|
|
159
144
|
await expect( runLoader( join( dir, 'evaluators.js' ), 'import { S } from "./steps.js";' ) )
|
|
160
145
|
.rejects.toThrow( /Invalid (import|imports|dependency) in evaluators\.js/ );
|
|
161
|
-
await expect( runLoader( join( dir, 'evaluators.js' ), 'import { SS } from "./shared_steps.js";' ) )
|
|
162
|
-
.rejects.toThrow( /Invalid (import|imports|dependency) in evaluators\.js/ );
|
|
163
146
|
await expect( runLoader( join( dir, 'evaluators.js' ), 'import WF from "./workflow.js";' ) )
|
|
164
147
|
.rejects.toThrow( /Invalid (import|imports|dependency) in evaluators\.js/ );
|
|
165
148
|
rmSync( dir, { recursive: true, force: true } );
|
|
@@ -174,42 +157,6 @@ describe( 'workflow_validator loader', () => {
|
|
|
174
157
|
rmSync( dir, { recursive: true, force: true } );
|
|
175
158
|
} );
|
|
176
159
|
|
|
177
|
-
it( 'shared_steps.js: rejects importing steps/shared_steps/evaluators/workflow', async () => {
|
|
178
|
-
const dir = mkdtempSync( join( tmpdir(), 'shared-imp-reject-' ) );
|
|
179
|
-
await expect( runLoader( join( dir, 'shared_steps.js' ), 'import { S } from "./steps.js";' ) )
|
|
180
|
-
.rejects.toThrow( /Invalid (import|imports|dependency) in shared_steps\.js/ );
|
|
181
|
-
await expect( runLoader( join( dir, 'shared_steps.js' ), 'import { SS } from "./shared_steps.js";' ) )
|
|
182
|
-
.rejects.toThrow( /Invalid (import|imports|dependency) in shared_steps\.js/ );
|
|
183
|
-
await expect( runLoader( join( dir, 'shared_steps.js' ), 'import { E } from "./evaluators.js";' ) )
|
|
184
|
-
.rejects.toThrow( /Invalid (import|imports|dependency) in shared_steps\.js/ );
|
|
185
|
-
await expect( runLoader( join( dir, 'shared_steps.js' ), 'import WF from "./workflow.js";' ) )
|
|
186
|
-
.rejects.toThrow( /Invalid (import|imports|dependency) in shared_steps\.js/ );
|
|
187
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
188
|
-
} );
|
|
189
|
-
|
|
190
|
-
it( 'shared_steps.js: rejects calling step/evaluator/workflow inside fn', async () => {
|
|
191
|
-
const dir = mkdtempSync( join( tmpdir(), 'shared-call-reject-' ) );
|
|
192
|
-
const src1 = [
|
|
193
|
-
'const A = step({ name: "a" });',
|
|
194
|
-
'const obj = { fn: function() { A(); } };'
|
|
195
|
-
].join( '\n' );
|
|
196
|
-
await expect( runLoader( join( dir, 'shared_steps.js' ), src1 ) ).rejects.toThrow( /Invalid call in .*\.js fn/ );
|
|
197
|
-
|
|
198
|
-
const src2 = [
|
|
199
|
-
'const E = evaluator({ name: "e" });',
|
|
200
|
-
'const obj = { fn: () => { E(); } };'
|
|
201
|
-
].join( '\n' );
|
|
202
|
-
await expect( runLoader( join( dir, 'shared_steps.js' ), src2 ) ).rejects.toThrow( /Invalid call in .*\.js fn/ );
|
|
203
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
204
|
-
} );
|
|
205
|
-
|
|
206
|
-
it( 'shared_steps.js: top-level calls outside fn are allowed', async () => {
|
|
207
|
-
const dir = mkdtempSync( join( tmpdir(), 'shared-toplevel-allowed-' ) );
|
|
208
|
-
const src = [ 'const A = step({ name: "a" });', 'A();' ].join( '\n' );
|
|
209
|
-
await expect( runLoader( join( dir, 'shared_steps.js' ), src ) ).resolves.toBeTruthy();
|
|
210
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
211
|
-
} );
|
|
212
|
-
|
|
213
160
|
it( 'workflow.js: allows importing ./types.js and bare types', async () => {
|
|
214
161
|
const dir = mkdtempSync( join( tmpdir(), 'wf-types-allow-' ) );
|
|
215
162
|
writeFileSync( join( dir, 'types.js' ), 'export const T = {}\n' );
|
|
@@ -218,9 +165,9 @@ describe( 'workflow_validator loader', () => {
|
|
|
218
165
|
rmSync( dir, { recursive: true, force: true } );
|
|
219
166
|
} );
|
|
220
167
|
|
|
221
|
-
it( 'workflow.js: allows importing
|
|
168
|
+
it( 'workflow.js: allows importing any file (consts/constants/vars/variables/random)', async () => {
|
|
222
169
|
const dir = mkdtempSync( join( tmpdir(), 'wf-extra-allow-' ) );
|
|
223
|
-
const bases = [ 'consts', 'constants', 'vars', 'variables' ];
|
|
170
|
+
const bases = [ 'consts', 'constants', 'vars', 'variables', 'random', 'anything' ];
|
|
224
171
|
for ( const base of bases ) {
|
|
225
172
|
writeFileSync( join( dir, `${base}.js` ), 'export const X = 1\n' );
|
|
226
173
|
const src = `import x from "./${base}.js";`;
|
|
@@ -229,12 +176,10 @@ describe( 'workflow_validator loader', () => {
|
|
|
229
176
|
rmSync( dir, { recursive: true, force: true } );
|
|
230
177
|
} );
|
|
231
178
|
|
|
232
|
-
it( 'steps.js: rejects require of steps/
|
|
179
|
+
it( 'steps.js: rejects require of steps/evaluators/workflow; allows other require', async () => {
|
|
233
180
|
const dir = mkdtempSync( join( tmpdir(), 'steps-require-' ) );
|
|
234
181
|
await expect( runLoader( join( dir, 'steps.js' ), 'const { S } = require("./steps.js");' ) )
|
|
235
182
|
.rejects.toThrow( /Invalid (require|dependency) in steps\.js/ );
|
|
236
|
-
await expect( runLoader( join( dir, 'steps.js' ), 'const { SS } = require("./shared_steps.js");' ) )
|
|
237
|
-
.rejects.toThrow( /Invalid (require|dependency) in steps\.js/ );
|
|
238
183
|
await expect( runLoader( join( dir, 'steps.js' ), 'const { E } = require("./evaluators.js");' ) )
|
|
239
184
|
.rejects.toThrow( /Invalid (require|dependency) in steps\.js/ );
|
|
240
185
|
await expect( runLoader( join( dir, 'steps.js' ), 'const W = require("./workflow.js");' ) )
|
|
@@ -244,16 +189,394 @@ describe( 'workflow_validator loader', () => {
|
|
|
244
189
|
rmSync( dir, { recursive: true, force: true } );
|
|
245
190
|
} );
|
|
246
191
|
|
|
247
|
-
it( 'evaluators.js: rejects require of steps/
|
|
192
|
+
it( 'evaluators.js: rejects require of steps/workflow; allows other require', async () => {
|
|
248
193
|
const dir = mkdtempSync( join( tmpdir(), 'evals-require-' ) );
|
|
249
194
|
await expect( runLoader( join( dir, 'evaluators.js' ), 'const { S } = require("./steps.js");' ) )
|
|
250
195
|
.rejects.toThrow( /Invalid (require|dependency) in evaluators\.js/ );
|
|
251
|
-
await expect( runLoader( join( dir, 'evaluators.js' ), 'const { SS } = require("./shared_steps.js");' ) )
|
|
252
|
-
.rejects.toThrow( /Invalid (require|dependency) in evaluators\.js/ );
|
|
253
196
|
await expect( runLoader( join( dir, 'evaluators.js' ), 'const W = require("./workflow.js");' ) )
|
|
254
197
|
.rejects.toThrow( /Invalid (require|dependency) in evaluators\.js/ );
|
|
255
198
|
const ok = 'const util = require("./util.js");';
|
|
256
199
|
await expect( runLoader( join( dir, 'evaluators.js' ), ok ) ).resolves.toBeTruthy();
|
|
257
200
|
rmSync( dir, { recursive: true, force: true } );
|
|
258
201
|
} );
|
|
202
|
+
|
|
203
|
+
// =====================================================
|
|
204
|
+
// Folder-based utilities and shared directory
|
|
205
|
+
// =====================================================
|
|
206
|
+
|
|
207
|
+
describe( 'folder-based utilities', () => {
|
|
208
|
+
it( 'workflow.js: allows imports from ./utils/helper.js (folder-based utils)', async () => {
|
|
209
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-folder-utils-' ) );
|
|
210
|
+
mkdirSync( join( dir, 'utils' ) );
|
|
211
|
+
writeFileSync( join( dir, 'utils', 'helper.js' ), 'export const helper = () => 1;\n' );
|
|
212
|
+
const src = 'import { helper } from "./utils/helper.js";';
|
|
213
|
+
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
214
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
215
|
+
} );
|
|
216
|
+
|
|
217
|
+
it( 'workflow.js: allows imports from ./clients/redis.js (folder-based clients)', async () => {
|
|
218
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-folder-clients-' ) );
|
|
219
|
+
mkdirSync( join( dir, 'clients' ) );
|
|
220
|
+
writeFileSync( join( dir, 'clients', 'redis.js' ), 'export const client = {};\n' );
|
|
221
|
+
const src = 'import { client } from "./clients/redis.js";';
|
|
222
|
+
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
223
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
224
|
+
} );
|
|
225
|
+
|
|
226
|
+
it( 'steps/fetch_data.js: allows imports from ../utils/http.js', async () => {
|
|
227
|
+
const dir = mkdtempSync( join( tmpdir(), 'steps-folder-utils-' ) );
|
|
228
|
+
mkdirSync( join( dir, 'steps' ) );
|
|
229
|
+
mkdirSync( join( dir, 'utils' ) );
|
|
230
|
+
writeFileSync( join( dir, 'utils', 'http.js' ), 'export const get = () => {};\n' );
|
|
231
|
+
const src = 'import { get } from "../utils/http.js";';
|
|
232
|
+
await expect( runLoader( join( dir, 'steps', 'fetch_data.js' ), src ) ).resolves.toBeTruthy();
|
|
233
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
234
|
+
} );
|
|
235
|
+
|
|
236
|
+
it( 'evaluators/quality.js: allows imports from ../utils/metrics.js', async () => {
|
|
237
|
+
const dir = mkdtempSync( join( tmpdir(), 'evals-folder-utils-' ) );
|
|
238
|
+
mkdirSync( join( dir, 'evaluators' ) );
|
|
239
|
+
mkdirSync( join( dir, 'utils' ) );
|
|
240
|
+
writeFileSync( join( dir, 'utils', 'metrics.js' ), 'export const compute = () => {};\n' );
|
|
241
|
+
const src = 'import { compute } from "../utils/metrics.js";';
|
|
242
|
+
await expect( runLoader( join( dir, 'evaluators', 'quality.js' ), src ) ).resolves.toBeTruthy();
|
|
243
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
244
|
+
} );
|
|
245
|
+
} );
|
|
246
|
+
|
|
247
|
+
describe( 'shared directory imports', () => {
|
|
248
|
+
it( 'workflow.js: allows imports from ../../shared/utils/keys.js', async () => {
|
|
249
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-utils-' ) );
|
|
250
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
251
|
+
mkdirSync( join( dir, 'shared', 'utils' ), { recursive: true } );
|
|
252
|
+
writeFileSync( join( dir, 'shared', 'utils', 'keys.js' ), 'export const KEY = "test";\n' );
|
|
253
|
+
const src = 'import { KEY } from "../../shared/utils/keys.js";';
|
|
254
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
255
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
256
|
+
} );
|
|
257
|
+
|
|
258
|
+
it( 'workflow.js: allows imports from ../../shared/steps/common.js', async () => {
|
|
259
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-steps-' ) );
|
|
260
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
261
|
+
mkdirSync( join( dir, 'shared', 'steps' ), { recursive: true } );
|
|
262
|
+
writeFileSync( join( dir, 'shared', 'steps', 'common.js' ), 'export const commonStep = step({ name: "common" });\n' );
|
|
263
|
+
const src = 'import { commonStep } from "../../shared/steps/common.js";';
|
|
264
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
265
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
266
|
+
} );
|
|
267
|
+
|
|
268
|
+
it( 'workflow.js: allows imports from ../../shared/evaluators/quality.js', async () => {
|
|
269
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-evals-' ) );
|
|
270
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
271
|
+
mkdirSync( join( dir, 'shared', 'evaluators' ), { recursive: true } );
|
|
272
|
+
writeFileSync( join( dir, 'shared', 'evaluators', 'quality.js' ), 'export const qualityEval = evaluator({ name: "quality" });\n' );
|
|
273
|
+
const src = 'import { qualityEval } from "../../shared/evaluators/quality.js";';
|
|
274
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
275
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
276
|
+
} );
|
|
277
|
+
|
|
278
|
+
it( 'workflow.js: allows imports from ../../shared/clients/pokeapi.js', async () => {
|
|
279
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-clients-' ) );
|
|
280
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
281
|
+
mkdirSync( join( dir, 'shared', 'clients' ), { recursive: true } );
|
|
282
|
+
writeFileSync( join( dir, 'shared', 'clients', 'pokeapi.js' ), 'export const getPokemon = () => {};\n' );
|
|
283
|
+
const src = 'import { getPokemon } from "../../shared/clients/pokeapi.js";';
|
|
284
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
285
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
286
|
+
} );
|
|
287
|
+
|
|
288
|
+
it( 'steps.ts: allows imports from ../../shared/utils/keys.js', async () => {
|
|
289
|
+
const dir = mkdtempSync( join( tmpdir(), 'steps-shared-utils-' ) );
|
|
290
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
291
|
+
mkdirSync( join( dir, 'shared', 'utils' ), { recursive: true } );
|
|
292
|
+
writeFileSync( join( dir, 'shared', 'utils', 'keys.js' ), 'export const KEY = "test";\n' );
|
|
293
|
+
const src = 'import { KEY } from "../../shared/utils/keys.js";';
|
|
294
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'steps.js' ), src ) ).resolves.toBeTruthy();
|
|
295
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
296
|
+
} );
|
|
297
|
+
|
|
298
|
+
it( 'steps.ts: allows imports from ../../shared/clients/redis.js', async () => {
|
|
299
|
+
const dir = mkdtempSync( join( tmpdir(), 'steps-shared-clients-' ) );
|
|
300
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
301
|
+
mkdirSync( join( dir, 'shared', 'clients' ), { recursive: true } );
|
|
302
|
+
writeFileSync( join( dir, 'shared', 'clients', 'redis.js' ), 'export const client = {};\n' );
|
|
303
|
+
const src = 'import { client } from "../../shared/clients/redis.js";';
|
|
304
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'steps.js' ), src ) ).resolves.toBeTruthy();
|
|
305
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
306
|
+
} );
|
|
307
|
+
|
|
308
|
+
it( 'evaluators.ts: allows imports from ../../shared/utils/helpers.js', async () => {
|
|
309
|
+
const dir = mkdtempSync( join( tmpdir(), 'evals-shared-utils-' ) );
|
|
310
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
311
|
+
mkdirSync( join( dir, 'shared', 'utils' ), { recursive: true } );
|
|
312
|
+
writeFileSync( join( dir, 'shared', 'utils', 'helpers.js' ), 'export const helper = () => 1;\n' );
|
|
313
|
+
const src = 'import { helper } from "../../shared/utils/helpers.js";';
|
|
314
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'evaluators.js' ), src ) ).resolves.toBeTruthy();
|
|
315
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
316
|
+
} );
|
|
317
|
+
} );
|
|
318
|
+
|
|
319
|
+
describe( 'activity isolation - shared imports', () => {
|
|
320
|
+
it( 'steps.ts: rejects imports from ../../shared/steps/common.js (activity isolation)', async () => {
|
|
321
|
+
const dir = mkdtempSync( join( tmpdir(), 'steps-shared-steps-reject-' ) );
|
|
322
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
323
|
+
mkdirSync( join( dir, 'shared', 'steps' ), { recursive: true } );
|
|
324
|
+
writeFileSync( join( dir, 'shared', 'steps', 'common.js' ), 'export const commonStep = step({ name: "common" });\n' );
|
|
325
|
+
const src = 'import { commonStep } from "../../shared/steps/common.js";';
|
|
326
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'steps.js' ), src ) )
|
|
327
|
+
.rejects.toThrow( /Invalid (import|imports|dependency) in steps\.js/ );
|
|
328
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
329
|
+
} );
|
|
330
|
+
|
|
331
|
+
it( 'steps.ts: rejects imports from ../../shared/evaluators/quality.js (activity isolation)', async () => {
|
|
332
|
+
const dir = mkdtempSync( join( tmpdir(), 'steps-shared-evals-reject-' ) );
|
|
333
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
334
|
+
mkdirSync( join( dir, 'shared', 'evaluators' ), { recursive: true } );
|
|
335
|
+
writeFileSync( join( dir, 'shared', 'evaluators', 'quality.js' ), 'export const qualityEval = evaluator({ name: "quality" });\n' );
|
|
336
|
+
const src = 'import { qualityEval } from "../../shared/evaluators/quality.js";';
|
|
337
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'steps.js' ), src ) )
|
|
338
|
+
.rejects.toThrow( /Invalid (import|imports|dependency) in steps\.js/ );
|
|
339
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
340
|
+
} );
|
|
341
|
+
|
|
342
|
+
it( 'evaluators.ts: rejects imports from ../../shared/steps/common.js (activity isolation)', async () => {
|
|
343
|
+
const dir = mkdtempSync( join( tmpdir(), 'evals-shared-steps-reject-' ) );
|
|
344
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
345
|
+
mkdirSync( join( dir, 'shared', 'steps' ), { recursive: true } );
|
|
346
|
+
writeFileSync( join( dir, 'shared', 'steps', 'common.js' ), 'export const commonStep = step({ name: "common" });\n' );
|
|
347
|
+
const src = 'import { commonStep } from "../../shared/steps/common.js";';
|
|
348
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'evaluators.js' ), src ) )
|
|
349
|
+
.rejects.toThrow( /Invalid (import|imports|dependency) in evaluators\.js/ );
|
|
350
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
351
|
+
} );
|
|
352
|
+
|
|
353
|
+
it( 'evaluators.ts: rejects imports from ../../shared/evaluators/other.js (activity isolation)', async () => {
|
|
354
|
+
const dir = mkdtempSync( join( tmpdir(), 'evals-shared-evals-reject-' ) );
|
|
355
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
356
|
+
mkdirSync( join( dir, 'shared', 'evaluators' ), { recursive: true } );
|
|
357
|
+
writeFileSync( join( dir, 'shared', 'evaluators', 'other.js' ), 'export const otherEval = evaluator({ name: "other" });\n' );
|
|
358
|
+
const src = 'import { otherEval } from "../../shared/evaluators/other.js";';
|
|
359
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'evaluators.js' ), src ) )
|
|
360
|
+
.rejects.toThrow( /Invalid (import|imports|dependency) in evaluators\.js/ );
|
|
361
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
362
|
+
} );
|
|
363
|
+
} );
|
|
364
|
+
|
|
365
|
+
describe( 'workflow import scope', () => {
|
|
366
|
+
it( 'workflow.js: allows imports from other workflow directories (cross-workflow)', async () => {
|
|
367
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-cross-allow-' ) );
|
|
368
|
+
mkdirSync( join( dir, 'workflows', 'workflow_a' ), { recursive: true } );
|
|
369
|
+
mkdirSync( join( dir, 'workflows', 'workflow_b' ), { recursive: true } );
|
|
370
|
+
writeFileSync( join( dir, 'workflows', 'workflow_b', 'steps.js' ), 'export const S = step({ name: "s" });\n' );
|
|
371
|
+
// Cross-workflow imports are allowed for workflows (they can import steps from other workflows)
|
|
372
|
+
const src = 'import { S } from "../workflow_b/steps.js";';
|
|
373
|
+
await expect( runLoader( join( dir, 'workflows', 'workflow_a', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
374
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
375
|
+
} );
|
|
376
|
+
|
|
377
|
+
it( 'workflow.js: allows imports from utils with relative parent paths', async () => {
|
|
378
|
+
// The validator does not enforce strict scope boundaries, it validates by file type patterns
|
|
379
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-parent-utils-' ) );
|
|
380
|
+
mkdirSync( join( dir, 'src', 'workflows', 'my_workflow' ), { recursive: true } );
|
|
381
|
+
mkdirSync( join( dir, 'utils' ), { recursive: true } );
|
|
382
|
+
writeFileSync( join( dir, 'utils', 'helpers.js' ), 'export const helper = () => 1;\n' );
|
|
383
|
+
const src = 'import { helper } from "../../../utils/helpers.js";';
|
|
384
|
+
// This should pass because it's not a component file
|
|
385
|
+
await expect( runLoader( join( dir, 'src', 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
386
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
387
|
+
} );
|
|
388
|
+
} );
|
|
389
|
+
|
|
390
|
+
// =====================================================
|
|
391
|
+
// Arbitrary path imports (proving any folder name works)
|
|
392
|
+
// =====================================================
|
|
393
|
+
|
|
394
|
+
describe( 'arbitrary path imports', () => {
|
|
395
|
+
it( 'workflow.js: allows imports from ./foobar.js', async () => {
|
|
396
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-arbitrary-1-' ) );
|
|
397
|
+
const src = 'import { foo } from "./foobar.js";';
|
|
398
|
+
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
399
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
400
|
+
} );
|
|
401
|
+
|
|
402
|
+
it( 'workflow.js: allows imports from ./foobar/baz.js', async () => {
|
|
403
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-arbitrary-2-' ) );
|
|
404
|
+
mkdirSync( join( dir, 'foobar' ) );
|
|
405
|
+
writeFileSync( join( dir, 'foobar', 'baz.js' ), 'export const baz = 1;\n' );
|
|
406
|
+
const src = 'import { baz } from "./foobar/baz.js";';
|
|
407
|
+
await expect( runLoader( join( dir, 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
408
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
409
|
+
} );
|
|
410
|
+
|
|
411
|
+
it( 'workflow.js: allows imports from ../../shared/foobar.js', async () => {
|
|
412
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-arbitrary-3-' ) );
|
|
413
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
414
|
+
mkdirSync( join( dir, 'shared' ), { recursive: true } );
|
|
415
|
+
writeFileSync( join( dir, 'shared', 'foobar.js' ), 'export const foobar = 1;\n' );
|
|
416
|
+
const src = 'import { foobar } from "../../shared/foobar.js";';
|
|
417
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
418
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
419
|
+
} );
|
|
420
|
+
|
|
421
|
+
it( 'workflow.js: allows imports from ../../shared/foobar/baz.js', async () => {
|
|
422
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-arbitrary-4-' ) );
|
|
423
|
+
mkdirSync( join( dir, 'workflows', 'my_workflow' ), { recursive: true } );
|
|
424
|
+
mkdirSync( join( dir, 'shared', 'foobar' ), { recursive: true } );
|
|
425
|
+
writeFileSync( join( dir, 'shared', 'foobar', 'baz.js' ), 'export const baz = 1;\n' );
|
|
426
|
+
const src = 'import { baz } from "../../shared/foobar/baz.js";';
|
|
427
|
+
await expect( runLoader( join( dir, 'workflows', 'my_workflow', 'workflow.js' ), src ) ).resolves.toBeTruthy();
|
|
428
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
429
|
+
} );
|
|
430
|
+
|
|
431
|
+
it( 'steps.js: allows imports from ./helpers/anything.js', async () => {
|
|
432
|
+
const dir = mkdtempSync( join( tmpdir(), 'steps-arbitrary-1-' ) );
|
|
433
|
+
mkdirSync( join( dir, 'helpers' ) );
|
|
434
|
+
writeFileSync( join( dir, 'helpers', 'anything.js' ), 'export const anything = 1;\n' );
|
|
435
|
+
const src = 'import { anything } from "./helpers/anything.js";';
|
|
436
|
+
await expect( runLoader( join( dir, 'steps.js' ), src ) ).resolves.toBeTruthy();
|
|
437
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
438
|
+
} );
|
|
439
|
+
|
|
440
|
+
it( 'evaluators.js: allows imports from ./my_custom_lib/tools.js', async () => {
|
|
441
|
+
const dir = mkdtempSync( join( tmpdir(), 'evals-arbitrary-1-' ) );
|
|
442
|
+
mkdirSync( join( dir, 'my_custom_lib' ) );
|
|
443
|
+
writeFileSync( join( dir, 'my_custom_lib', 'tools.js' ), 'export const tools = {};\n' );
|
|
444
|
+
const src = 'import { tools } from "./my_custom_lib/tools.js";';
|
|
445
|
+
await expect( runLoader( join( dir, 'evaluators.js' ), src ) ).resolves.toBeTruthy();
|
|
446
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
447
|
+
} );
|
|
448
|
+
} );
|
|
449
|
+
|
|
450
|
+
// =====================================================
|
|
451
|
+
// Instantiation location validation
|
|
452
|
+
// =====================================================
|
|
453
|
+
|
|
454
|
+
describe( 'instantiation location tests - correct locations', () => {
|
|
455
|
+
it( 'step() called in steps/fetch_data.js is allowed', async () => {
|
|
456
|
+
const dir = mkdtempSync( join( tmpdir(), 'step-folder-allowed-' ) );
|
|
457
|
+
mkdirSync( join( dir, 'steps' ) );
|
|
458
|
+
const src = [
|
|
459
|
+
'import { step } from "@output.ai/core";',
|
|
460
|
+
'export const fetchData = step({ name: "fetch_data", fn: async () => ({}) });'
|
|
461
|
+
].join( '\n' );
|
|
462
|
+
await expect( runLoader( join( dir, 'steps', 'fetch_data.js' ), src ) ).resolves.toBeTruthy();
|
|
463
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
464
|
+
} );
|
|
465
|
+
|
|
466
|
+
it( 'step() called in src/shared/steps/common.js is allowed', async () => {
|
|
467
|
+
const dir = mkdtempSync( join( tmpdir(), 'step-shared-allowed-' ) );
|
|
468
|
+
mkdirSync( join( dir, 'src', 'shared', 'steps' ), { recursive: true } );
|
|
469
|
+
const src = [
|
|
470
|
+
'import { step } from "@output.ai/core";',
|
|
471
|
+
'export const commonStep = step({ name: "common_step", fn: async () => ({}) });'
|
|
472
|
+
].join( '\n' );
|
|
473
|
+
await expect( runLoader( join( dir, 'src', 'shared', 'steps', 'common.js' ), src ) ).resolves.toBeTruthy();
|
|
474
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
475
|
+
} );
|
|
476
|
+
|
|
477
|
+
it( 'evaluator() called in evaluators/quality.js is allowed', async () => {
|
|
478
|
+
const dir = mkdtempSync( join( tmpdir(), 'eval-folder-allowed-' ) );
|
|
479
|
+
mkdirSync( join( dir, 'evaluators' ) );
|
|
480
|
+
const src = [
|
|
481
|
+
'import { evaluator } from "@output.ai/core";',
|
|
482
|
+
'export const quality = evaluator({ name: "quality", fn: async () => ({ value: 1 }) });'
|
|
483
|
+
].join( '\n' );
|
|
484
|
+
await expect( runLoader( join( dir, 'evaluators', 'quality.js' ), src ) ).resolves.toBeTruthy();
|
|
485
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
486
|
+
} );
|
|
487
|
+
|
|
488
|
+
it( 'evaluator() called in src/shared/evaluators/metrics.js is allowed', async () => {
|
|
489
|
+
const dir = mkdtempSync( join( tmpdir(), 'eval-shared-allowed-' ) );
|
|
490
|
+
mkdirSync( join( dir, 'src', 'shared', 'evaluators' ), { recursive: true } );
|
|
491
|
+
const src = [
|
|
492
|
+
'import { evaluator } from "@output.ai/core";',
|
|
493
|
+
'export const metrics = evaluator({ name: "metrics", fn: async () => ({ value: 1 }) });'
|
|
494
|
+
].join( '\n' );
|
|
495
|
+
await expect( runLoader( join( dir, 'src', 'shared', 'evaluators', 'metrics.js' ), src ) ).resolves.toBeTruthy();
|
|
496
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
497
|
+
} );
|
|
498
|
+
} );
|
|
499
|
+
|
|
500
|
+
describe( 'instantiation location tests - wrong locations', () => {
|
|
501
|
+
it( 'step() called in utils.js is blocked by validator', async () => {
|
|
502
|
+
const dir = mkdtempSync( join( tmpdir(), 'step-utils-fail-' ) );
|
|
503
|
+
const src = [
|
|
504
|
+
'import { step } from "@output.ai/core";',
|
|
505
|
+
'export const badStep = step({ name: "bad", fn: async () => ({}) });'
|
|
506
|
+
].join( '\n' );
|
|
507
|
+
await expect( runLoader( join( dir, 'utils.js' ), src ) )
|
|
508
|
+
.rejects.toThrow( /Invalid instantiation location.*step\(\).*steps/ );
|
|
509
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
510
|
+
} );
|
|
511
|
+
|
|
512
|
+
it( 'step() called in clients/api.js is blocked by validator', async () => {
|
|
513
|
+
const dir = mkdtempSync( join( tmpdir(), 'step-clients-fail-' ) );
|
|
514
|
+
mkdirSync( join( dir, 'clients' ) );
|
|
515
|
+
const src = [
|
|
516
|
+
'import { step } from "@output.ai/core";',
|
|
517
|
+
'export const badStep = step({ name: "bad", fn: async () => ({}) });'
|
|
518
|
+
].join( '\n' );
|
|
519
|
+
await expect( runLoader( join( dir, 'clients', 'api.js' ), src ) )
|
|
520
|
+
.rejects.toThrow( /Invalid instantiation location.*step\(\).*steps/ );
|
|
521
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
522
|
+
} );
|
|
523
|
+
|
|
524
|
+
it( 'evaluator() called in utils.js is blocked by validator', async () => {
|
|
525
|
+
const dir = mkdtempSync( join( tmpdir(), 'eval-utils-fail-' ) );
|
|
526
|
+
const src = [
|
|
527
|
+
'import { evaluator } from "@output.ai/core";',
|
|
528
|
+
'export const badEval = evaluator({ name: "bad", fn: async () => ({ value: 1 }) });'
|
|
529
|
+
].join( '\n' );
|
|
530
|
+
await expect( runLoader( join( dir, 'utils.js' ), src ) )
|
|
531
|
+
.rejects.toThrow( /Invalid instantiation location.*evaluator\(\).*evaluators/ );
|
|
532
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
533
|
+
} );
|
|
534
|
+
|
|
535
|
+
it( 'evaluator() called in clients/api.js is blocked by validator', async () => {
|
|
536
|
+
const dir = mkdtempSync( join( tmpdir(), 'eval-clients-fail-' ) );
|
|
537
|
+
mkdirSync( join( dir, 'clients' ) );
|
|
538
|
+
const src = [
|
|
539
|
+
'import { evaluator } from "@output.ai/core";',
|
|
540
|
+
'export const badEval = evaluator({ name: "bad", fn: async () => ({ value: 1 }) });'
|
|
541
|
+
].join( '\n' );
|
|
542
|
+
await expect( runLoader( join( dir, 'clients', 'api.js' ), src ) )
|
|
543
|
+
.rejects.toThrow( /Invalid instantiation location.*evaluator\(\).*evaluators/ );
|
|
544
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
545
|
+
} );
|
|
546
|
+
|
|
547
|
+
it( 'evaluator() called in helpers.js is blocked by validator', async () => {
|
|
548
|
+
const dir = mkdtempSync( join( tmpdir(), 'eval-helpers-fail-' ) );
|
|
549
|
+
const src = [
|
|
550
|
+
'import { evaluator } from "@output.ai/core";',
|
|
551
|
+
'export const badEval = evaluator({ name: "bad", fn: async () => ({ value: 1 }) });'
|
|
552
|
+
].join( '\n' );
|
|
553
|
+
await expect( runLoader( join( dir, 'helpers.js' ), src ) )
|
|
554
|
+
.rejects.toThrow( /Invalid instantiation location.*evaluator\(\).*evaluators/ );
|
|
555
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
556
|
+
} );
|
|
557
|
+
|
|
558
|
+
it( 'workflow() called in shared/common.js is blocked by validator', async () => {
|
|
559
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-shared-fail-' ) );
|
|
560
|
+
mkdirSync( join( dir, 'shared' ) );
|
|
561
|
+
const src = [
|
|
562
|
+
'import { workflow } from "@output.ai/core";',
|
|
563
|
+
'export const badWf = workflow({ name: "bad", fn: async () => ({}) });'
|
|
564
|
+
].join( '\n' );
|
|
565
|
+
await expect( runLoader( join( dir, 'shared', 'common.js' ), src ) )
|
|
566
|
+
.rejects.toThrow( /Invalid instantiation location.*workflow\(\).*workflow/ );
|
|
567
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
568
|
+
} );
|
|
569
|
+
|
|
570
|
+
it( 'workflow() called in utils/index.js is blocked by validator', async () => {
|
|
571
|
+
const dir = mkdtempSync( join( tmpdir(), 'wf-utils-fail-' ) );
|
|
572
|
+
mkdirSync( join( dir, 'utils' ) );
|
|
573
|
+
const src = [
|
|
574
|
+
'import { workflow } from "@output.ai/core";',
|
|
575
|
+
'export const badWf = workflow({ name: "bad", fn: async () => ({}) });'
|
|
576
|
+
].join( '\n' );
|
|
577
|
+
await expect( runLoader( join( dir, 'utils', 'index.js' ), src ) )
|
|
578
|
+
.rejects.toThrow( /Invalid instantiation location.*workflow\(\).*workflow/ );
|
|
579
|
+
rmSync( dir, { recursive: true, force: true } );
|
|
580
|
+
} );
|
|
581
|
+
} );
|
|
259
582
|
} );
|