@outputai/core 0.7.1-next.bd6bd49.0 → 0.7.1-next.c005dac.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/bin/worker.sh +6 -0
- package/package.json +1 -1
- package/src/consts.js +0 -4
- package/src/errors.js +6 -2
- package/src/interface/evaluator.js +7 -20
- package/src/interface/evaluator.spec.js +117 -1
- package/src/interface/step.js +8 -9
- package/src/interface/step.spec.js +124 -0
- package/src/interface/validations/index.js +108 -0
- package/src/interface/validations/index.spec.js +182 -0
- package/src/interface/validations/schemas.js +113 -0
- package/src/interface/validations/schemas.spec.js +209 -0
- package/src/interface/webhook.js +1 -1
- package/src/interface/webhook.spec.js +1 -1
- package/src/interface/workflow.d.ts +10 -9
- package/src/interface/workflow.js +76 -164
- package/src/interface/workflow.spec.js +637 -521
- package/src/interface/workflow_activity_options.js +16 -0
- package/src/interface/workflow_utils.js +1 -1
- package/src/interface/zod_integration.spec.js +2 -2
- package/src/internal_utils/aggregations.js +0 -10
- package/src/internal_utils/aggregations.spec.js +1 -48
- package/src/internal_utils/errors.js +14 -8
- package/src/internal_utils/errors.spec.js +73 -27
- package/src/worker/bundle.js +26 -0
- package/src/worker/bundle.spec.js +52 -0
- package/src/worker/check.js +24 -0
- package/src/worker/index.js +1 -1
- package/src/worker/index.spec.js +1 -1
- package/src/worker/interceptors/activity.js +7 -24
- package/src/worker/interceptors/activity.spec.js +97 -66
- package/src/worker/interceptors/index.js +4 -7
- package/src/worker/interceptors/modules.js +15 -0
- package/src/worker/interceptors/workflow.js +4 -7
- package/src/worker/interceptors/workflow.spec.js +49 -42
- package/src/worker/loader_tools.js +1 -1
- package/src/worker/loader_tools.spec.js +36 -0
- package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.js +5 -109
- package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.spec.js +31 -103
- package/src/worker/webpack_loaders/workflow_rewriter/index.mjs +5 -6
- package/src/worker/webpack_loaders/workflow_rewriter/index.spec.js +11 -83
- package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.js +8 -11
- package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.spec.js +9 -9
- package/src/interface/validations/runtime.js +0 -20
- package/src/interface/validations/runtime.spec.js +0 -29
- package/src/interface/validations/schema_utils.js +0 -8
- package/src/interface/validations/schema_utils.spec.js +0 -67
- package/src/interface/validations/static.js +0 -137
- package/src/interface/validations/static.spec.js +0 -397
- package/src/interface/workflow.replay_compatibility.spec.js +0 -254
|
@@ -1,31 +1,20 @@
|
|
|
1
|
-
import { join } from 'node:path';
|
|
2
1
|
import traverseModule from '@babel/traverse';
|
|
3
2
|
import {
|
|
4
|
-
buildWorkflowNameMap,
|
|
5
3
|
buildEvaluatorsNameMap,
|
|
6
4
|
buildSharedEvaluatorsNameMap,
|
|
7
5
|
buildSharedStepsNameMap,
|
|
8
6
|
buildStepsNameMap,
|
|
9
7
|
getLocalNameFromDestructuredProperty,
|
|
10
|
-
isAbsoluteWorkflowJsResource,
|
|
11
8
|
isEvaluatorsPath,
|
|
12
9
|
isSharedEvaluatorsPath,
|
|
13
10
|
isSharedStepsPath,
|
|
14
11
|
isStepsPath,
|
|
15
|
-
isWorkflowPath,
|
|
16
12
|
toAbsolutePath
|
|
17
13
|
} from '../tools.js';
|
|
18
|
-
import {
|
|
19
|
-
isBareNpmSpecifier,
|
|
20
|
-
resolveBareImportSpecifiersAsWorkflows,
|
|
21
|
-
resolveBareDestructuredRequireAsWorkflows,
|
|
22
|
-
resolveBareDefaultRequireAsWorkflow
|
|
23
|
-
} from '../npm_workflow_export_resolve.js';
|
|
24
14
|
|
|
25
15
|
import {
|
|
26
16
|
isCallExpression,
|
|
27
17
|
isIdentifier,
|
|
28
|
-
isImportDefaultSpecifier,
|
|
29
18
|
isImportSpecifier,
|
|
30
19
|
isObjectPattern,
|
|
31
20
|
isObjectProperty,
|
|
@@ -44,12 +33,6 @@ const unresolvedImportError = ( name, fileLabel, filePath ) =>
|
|
|
44
33
|
'(e.g. step() in steps files, evaluator() in evaluators files, workflow() in workflow files).'
|
|
45
34
|
);
|
|
46
35
|
|
|
47
|
-
const mixedBareWorkflowImportError = ( specifier, resourcePath ) => new Error(
|
|
48
|
-
`Workflow file '${resourcePath}': import from '${specifier}' mixes workflow exports with ` +
|
|
49
|
-
'non-workflow exports, or could not resolve every binding to a workflow.js module. ' +
|
|
50
|
-
'Split npm imports so each declaration only imports workflows, or only non-workflows.'
|
|
51
|
-
);
|
|
52
|
-
|
|
53
36
|
const removeRequireDeclarator = path => {
|
|
54
37
|
if ( isVariableDeclaration( path.parent ) && path.parent.declarations.length === 1 ) {
|
|
55
38
|
path.parentPath.remove();
|
|
@@ -84,28 +67,23 @@ const collectDestructuredRequires = ( path, absolutePath, req, descriptors ) =>
|
|
|
84
67
|
|
|
85
68
|
/**
|
|
86
69
|
* Collect and strip target imports and requires from an AST, producing
|
|
87
|
-
* step/
|
|
70
|
+
* step/evaluator import mappings for later rewrites.
|
|
88
71
|
*
|
|
89
72
|
* Mutates the AST by removing matching import declarations and require declarators.
|
|
90
73
|
*
|
|
91
74
|
* @param {import('@babel/types').File} ast - Parsed file AST.
|
|
92
75
|
* @param {string} fileDir - Absolute directory of the file represented by `ast`.
|
|
93
|
-
* @param {{ stepsNameCache: Map<string,Map<string,string
|
|
76
|
+
* @param {{ stepsNameCache: Map<string,Map<string,string>> }} caches
|
|
94
77
|
* Resolved-name caches to avoid re-reading same modules.
|
|
95
|
-
* @param {string} [resourcePath] - Absolute path of the file being transformed; used to resolve
|
|
96
|
-
* npm package imports from `workflow.js` via Node resolution and export following.
|
|
97
78
|
* @returns {{ stepImports: Array<{localName:string,stepName:string}>,
|
|
98
|
-
*
|
|
79
|
+
* evaluatorImports: Array<{localName:string,evaluatorName:string}> }} Collected info mappings.
|
|
99
80
|
*/
|
|
100
81
|
export default function collectTargetImports(
|
|
101
82
|
ast, fileDir,
|
|
102
|
-
{ stepsNameCache,
|
|
103
|
-
resourcePath
|
|
83
|
+
{ stepsNameCache, evaluatorsNameCache, sharedStepsNameCache, sharedEvaluatorsNameCache }
|
|
104
84
|
) {
|
|
105
|
-
const resolutionPath = resourcePath ?? join( fileDir, 'file.js' );
|
|
106
85
|
const stepImports = [];
|
|
107
86
|
const sharedStepImports = [];
|
|
108
|
-
const flowImports = [];
|
|
109
87
|
const evaluatorImports = [];
|
|
110
88
|
const sharedEvaluatorImports = [];
|
|
111
89
|
|
|
@@ -113,27 +91,7 @@ export default function collectTargetImports(
|
|
|
113
91
|
ImportDeclaration: path => {
|
|
114
92
|
const src = path.node.source.value;
|
|
115
93
|
|
|
116
|
-
if ( isBareNpmSpecifier( src ) && isAbsoluteWorkflowJsResource( resolutionPath ) ) {
|
|
117
|
-
const outcome = resolveBareImportSpecifiersAsWorkflows( {
|
|
118
|
-
fromAbsoluteFile: resolutionPath,
|
|
119
|
-
specifier: src,
|
|
120
|
-
specifiers: path.node.specifiers,
|
|
121
|
-
workflowNameCache
|
|
122
|
-
} );
|
|
123
|
-
if ( outcome.type === 'partial' ) {
|
|
124
|
-
throw mixedBareWorkflowImportError( src, resolutionPath );
|
|
125
|
-
}
|
|
126
|
-
if ( outcome.type === 'all' ) {
|
|
127
|
-
for ( const { localName, workflowName } of outcome.bindings ) {
|
|
128
|
-
flowImports.push( { localName, workflowName } );
|
|
129
|
-
}
|
|
130
|
-
path.remove();
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
94
|
const isTargetImport = isStepsPath( src ) || isSharedStepsPath( src ) ||
|
|
136
|
-
isWorkflowPath( src ) ||
|
|
137
95
|
isEvaluatorsPath( src ) || isSharedEvaluatorsPath( src );
|
|
138
96
|
if ( !isTargetImport ) {
|
|
139
97
|
return;
|
|
@@ -166,24 +124,6 @@ export default function collectTargetImports(
|
|
|
166
124
|
isSharedEvaluatorsPath( src ), buildSharedEvaluatorsNameMap,
|
|
167
125
|
sharedEvaluatorsNameCache, sharedEvaluatorImports, 'evaluatorName', 'shared evaluators'
|
|
168
126
|
);
|
|
169
|
-
if ( isWorkflowPath( src ) ) {
|
|
170
|
-
const { named, default: defName } = buildWorkflowNameMap( absolutePath, workflowNameCache );
|
|
171
|
-
for ( const s of path.node.specifiers ) {
|
|
172
|
-
if ( isImportDefaultSpecifier( s ) ) {
|
|
173
|
-
const localName = s.local.name;
|
|
174
|
-
flowImports.push( { localName, workflowName: defName ?? localName } );
|
|
175
|
-
} else if ( isImportSpecifier( s ) ) {
|
|
176
|
-
const importedName = s.imported.name;
|
|
177
|
-
const localName = s.local.name;
|
|
178
|
-
const workflowName = named.get( importedName );
|
|
179
|
-
if ( workflowName ) {
|
|
180
|
-
flowImports.push( { localName, workflowName } );
|
|
181
|
-
} else {
|
|
182
|
-
throw unresolvedImportError( importedName, 'workflow', absolutePath );
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
127
|
path.remove();
|
|
188
128
|
},
|
|
189
129
|
VariableDeclarator: path => {
|
|
@@ -201,38 +141,7 @@ export default function collectTargetImports(
|
|
|
201
141
|
|
|
202
142
|
const req = firstArgument.value;
|
|
203
143
|
|
|
204
|
-
if ( isBareNpmSpecifier( req ) && isAbsoluteWorkflowJsResource( resolutionPath ) ) {
|
|
205
|
-
if ( isObjectPattern( path.node.id ) ) {
|
|
206
|
-
const outcome = resolveBareDestructuredRequireAsWorkflows( {
|
|
207
|
-
fromAbsoluteFile: resolutionPath,
|
|
208
|
-
specifier: req,
|
|
209
|
-
properties: path.node.id.properties,
|
|
210
|
-
workflowNameCache
|
|
211
|
-
} );
|
|
212
|
-
if ( outcome.type === 'partial' ) {
|
|
213
|
-
throw mixedBareWorkflowImportError( req, resolutionPath );
|
|
214
|
-
}
|
|
215
|
-
if ( outcome.type === 'all' ) {
|
|
216
|
-
for ( const { localName, workflowName } of outcome.bindings ) {
|
|
217
|
-
flowImports.push( { localName, workflowName } );
|
|
218
|
-
}
|
|
219
|
-
removeRequireDeclarator( path );
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
} else if ( isIdentifier( path.node.id ) ) {
|
|
223
|
-
const outcome = resolveBareDefaultRequireAsWorkflow(
|
|
224
|
-
resolutionPath, req, path.node.id.name, workflowNameCache
|
|
225
|
-
);
|
|
226
|
-
if ( outcome.type === 'binding' ) {
|
|
227
|
-
flowImports.push( { localName: outcome.localName, workflowName: outcome.workflowName } );
|
|
228
|
-
removeRequireDeclarator( path );
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
144
|
const isTargetRequire = isStepsPath( req ) || isSharedStepsPath( req ) ||
|
|
235
|
-
isWorkflowPath( req ) ||
|
|
236
145
|
isEvaluatorsPath( req ) || isSharedEvaluatorsPath( req );
|
|
237
146
|
if ( !isTargetRequire ) {
|
|
238
147
|
return;
|
|
@@ -263,12 +172,6 @@ export default function collectTargetImports(
|
|
|
263
172
|
cache: sharedEvaluatorsNameCache ?? evaluatorsNameCache,
|
|
264
173
|
target: sharedEvaluatorImports,
|
|
265
174
|
valueKey: 'evaluatorName', label: 'shared evaluators'
|
|
266
|
-
},
|
|
267
|
-
{
|
|
268
|
-
match: isWorkflowPath,
|
|
269
|
-
buildMap: ( p, c ) => buildWorkflowNameMap( p, c ).named,
|
|
270
|
-
cache: workflowNameCache, target: flowImports,
|
|
271
|
-
valueKey: 'workflowName', label: 'workflow'
|
|
272
175
|
}
|
|
273
176
|
];
|
|
274
177
|
collectDestructuredRequires(
|
|
@@ -276,15 +179,8 @@ export default function collectTargetImports(
|
|
|
276
179
|
);
|
|
277
180
|
return;
|
|
278
181
|
}
|
|
279
|
-
|
|
280
|
-
if ( isWorkflowPath( req ) && isIdentifier( path.node.id ) ) {
|
|
281
|
-
const { default: defName } = buildWorkflowNameMap( absolutePath, workflowNameCache );
|
|
282
|
-
const localName = path.node.id.name;
|
|
283
|
-
flowImports.push( { localName, workflowName: defName ?? localName } );
|
|
284
|
-
removeRequireDeclarator( path );
|
|
285
|
-
}
|
|
286
182
|
}
|
|
287
183
|
} );
|
|
288
184
|
|
|
289
|
-
return { stepImports, sharedStepImports, evaluatorImports, sharedEvaluatorImports
|
|
185
|
+
return { stepImports, sharedStepImports, evaluatorImports, sharedEvaluatorImports };
|
|
290
186
|
}
|
|
@@ -10,7 +10,7 @@ function makeAst( source, filename ) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
describe( 'collect_target_imports', () => {
|
|
13
|
-
it( 'collects ESM imports for steps and
|
|
13
|
+
it( 'collects ESM imports for steps and evaluators and leaves workflow imports intact', () => {
|
|
14
14
|
const dir = mkdtempSync( join( tmpdir(), 'collect-esm-' ) );
|
|
15
15
|
writeFileSync( join( dir, 'steps.js' ), `
|
|
16
16
|
export const StepA = step({ name: 'step.a' });
|
|
@@ -27,25 +27,20 @@ import WF, { FlowA } from './workflow.js';
|
|
|
27
27
|
const x = 1;`;
|
|
28
28
|
|
|
29
29
|
const ast = makeAst( source, join( dir, 'file.js' ) );
|
|
30
|
-
const { stepImports, evaluatorImports
|
|
30
|
+
const { stepImports, evaluatorImports } = collectTargetImports(
|
|
31
31
|
ast,
|
|
32
32
|
dir,
|
|
33
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map()
|
|
33
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map() }
|
|
34
34
|
);
|
|
35
35
|
expect( evaluatorImports ).toEqual( [ { localName: 'EvalA', evaluatorName: 'eval.a' } ] );
|
|
36
36
|
|
|
37
37
|
expect( stepImports ).toEqual( [ { localName: 'StepA', stepName: 'step.a' } ] );
|
|
38
|
-
expect(
|
|
39
|
-
{ localName: 'WF', workflowName: 'flow.def' },
|
|
40
|
-
{ localName: 'FlowA', workflowName: 'flow.a' }
|
|
41
|
-
] );
|
|
42
|
-
// Import declarations should have been removed
|
|
43
|
-
expect( ast.program.body.find( n => n.type === 'ImportDeclaration' ) ).toBeUndefined();
|
|
38
|
+
expect( ast.program.body.find( n => n.type === 'ImportDeclaration' )?.source.value ).toBe( './workflow.js' );
|
|
44
39
|
|
|
45
40
|
rmSync( dir, { recursive: true, force: true } );
|
|
46
41
|
} );
|
|
47
42
|
|
|
48
|
-
it( 'collects CJS requires and
|
|
43
|
+
it( 'collects CJS requires for steps and evaluators and leaves workflow requires intact', () => {
|
|
49
44
|
const dir = mkdtempSync( join( tmpdir(), 'collect-cjs-' ) );
|
|
50
45
|
writeFileSync( join( dir, 'steps.js' ), 'export const StepB = step({ name: \'step.b\' })' );
|
|
51
46
|
writeFileSync( join( dir, 'evaluators.js' ), 'export const EvalB = evaluator({ name: \'eval.b\' })' );
|
|
@@ -58,20 +53,19 @@ const WF = require( './workflow.js' );
|
|
|
58
53
|
const obj = {};`;
|
|
59
54
|
|
|
60
55
|
const ast = makeAst( source, join( dir, 'file.js' ) );
|
|
61
|
-
const { stepImports, evaluatorImports
|
|
56
|
+
const { stepImports, evaluatorImports } = collectTargetImports(
|
|
62
57
|
ast,
|
|
63
58
|
dir,
|
|
64
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map()
|
|
59
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map() }
|
|
65
60
|
);
|
|
66
61
|
expect( evaluatorImports ).toEqual( [ { localName: 'EvalB', evaluatorName: 'eval.b' } ] );
|
|
67
62
|
|
|
68
63
|
expect( stepImports ).toEqual( [ { localName: 'StepB', stepName: 'step.b' } ] );
|
|
69
|
-
|
|
70
|
-
// All require-based declarators should have been removed (only non-require decls may remain)
|
|
64
|
+
// Only non-target require declarators should remain.
|
|
71
65
|
const hasRequireDecl = ast.program.body.some( n =>
|
|
72
66
|
n.type === 'VariableDeclaration' && n.declarations.some( d => d.init && d.init.type === 'CallExpression' )
|
|
73
67
|
);
|
|
74
|
-
expect( hasRequireDecl ).toBe(
|
|
68
|
+
expect( hasRequireDecl ).toBe( true );
|
|
75
69
|
|
|
76
70
|
rmSync( dir, { recursive: true, force: true } );
|
|
77
71
|
} );
|
|
@@ -86,7 +80,7 @@ const obj = {};`;
|
|
|
86
80
|
const { evaluatorImports } = collectTargetImports(
|
|
87
81
|
ast,
|
|
88
82
|
dir,
|
|
89
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map()
|
|
83
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map() }
|
|
90
84
|
);
|
|
91
85
|
expect( evaluatorImports ).toEqual( [ { localName: 'MyExport', evaluatorName: 'bad' } ] );
|
|
92
86
|
|
|
@@ -103,7 +97,7 @@ const obj = {};`;
|
|
|
103
97
|
const { stepImports } = collectTargetImports(
|
|
104
98
|
ast,
|
|
105
99
|
dir,
|
|
106
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map()
|
|
100
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map() }
|
|
107
101
|
);
|
|
108
102
|
expect( stepImports ).toEqual( [ { localName: 'MyExport', stepName: 'bad' } ] );
|
|
109
103
|
|
|
@@ -120,7 +114,7 @@ const obj = {};`;
|
|
|
120
114
|
const { evaluatorImports } = collectTargetImports(
|
|
121
115
|
ast,
|
|
122
116
|
dir,
|
|
123
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map()
|
|
117
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map() }
|
|
124
118
|
);
|
|
125
119
|
expect( evaluatorImports ).toEqual( [ { localName: 'MyExport', evaluatorName: 'bad' } ] );
|
|
126
120
|
|
|
@@ -137,14 +131,14 @@ const obj = {};`;
|
|
|
137
131
|
const { stepImports } = collectTargetImports(
|
|
138
132
|
ast,
|
|
139
133
|
dir,
|
|
140
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map()
|
|
134
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map() }
|
|
141
135
|
);
|
|
142
136
|
expect( stepImports ).toEqual( [ { localName: 'MyExport', stepName: 'bad' } ] );
|
|
143
137
|
|
|
144
138
|
rmSync( dir, { recursive: true, force: true } );
|
|
145
139
|
} );
|
|
146
140
|
|
|
147
|
-
it( '
|
|
141
|
+
it( 'leaves ESM imports from workflow.js alone', () => {
|
|
148
142
|
const dir = mkdtempSync( join( tmpdir(), 'collect-esm-mismatch-wf-' ) );
|
|
149
143
|
writeFileSync( join( dir, 'workflow.js' ), 'export const helper = () => 42;' );
|
|
150
144
|
|
|
@@ -154,13 +148,14 @@ const obj = {};`;
|
|
|
154
148
|
expect( () => collectTargetImports(
|
|
155
149
|
ast,
|
|
156
150
|
dir,
|
|
157
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map()
|
|
158
|
-
) ).toThrow(
|
|
151
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map() }
|
|
152
|
+
) ).not.toThrow();
|
|
153
|
+
expect( ast.program.body.find( n => n.type === 'ImportDeclaration' )?.source.value ).toBe( './workflow.js' );
|
|
159
154
|
|
|
160
155
|
rmSync( dir, { recursive: true, force: true } );
|
|
161
156
|
} );
|
|
162
157
|
|
|
163
|
-
it( '
|
|
158
|
+
it( 'leaves CJS requires from workflow.js alone', () => {
|
|
164
159
|
const dir = mkdtempSync( join( tmpdir(), 'collect-cjs-mismatch-wf-' ) );
|
|
165
160
|
writeFileSync( join( dir, 'workflow.js' ), 'export const helper = () => 42;' );
|
|
166
161
|
|
|
@@ -170,25 +165,26 @@ const obj = {};`;
|
|
|
170
165
|
expect( () => collectTargetImports(
|
|
171
166
|
ast,
|
|
172
167
|
dir,
|
|
173
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map()
|
|
174
|
-
) ).toThrow(
|
|
168
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map() }
|
|
169
|
+
) ).not.toThrow();
|
|
170
|
+
expect( ast.program.body.some( n => n.type === 'VariableDeclaration' ) ).toBe( true );
|
|
175
171
|
|
|
176
172
|
rmSync( dir, { recursive: true, force: true } );
|
|
177
173
|
} );
|
|
178
174
|
|
|
179
|
-
it( '
|
|
175
|
+
it( 'does not collect CJS destructured require from workflow.js', () => {
|
|
180
176
|
const dir = mkdtempSync( join( tmpdir(), 'collect-cjs-wf-destruct-' ) );
|
|
181
177
|
writeFileSync( join( dir, 'workflow.js' ), 'export const FlowX = workflow({ name: \'flow.x\' });' );
|
|
182
178
|
|
|
183
179
|
const source = 'const { FlowX } = require( \'./workflow.js\' );\nconst obj = {};';
|
|
184
180
|
const ast = makeAst( source, join( dir, 'file.js' ) );
|
|
185
181
|
|
|
186
|
-
|
|
182
|
+
collectTargetImports(
|
|
187
183
|
ast,
|
|
188
184
|
dir,
|
|
189
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map()
|
|
185
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map() }
|
|
190
186
|
);
|
|
191
|
-
expect(
|
|
187
|
+
expect( ast.program.body.some( n => n.type === 'VariableDeclaration' ) ).toBe( true );
|
|
192
188
|
|
|
193
189
|
rmSync( dir, { recursive: true, force: true } );
|
|
194
190
|
} );
|
|
@@ -208,7 +204,7 @@ const obj = {};`;
|
|
|
208
204
|
const { sharedEvaluatorImports } = collectTargetImports(
|
|
209
205
|
ast,
|
|
210
206
|
join( dir, 'workflows', 'my_workflow' ),
|
|
211
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map(), sharedEvaluatorsNameCache: new Map()
|
|
207
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map(), sharedEvaluatorsNameCache: new Map() }
|
|
212
208
|
);
|
|
213
209
|
expect( sharedEvaluatorImports ).toEqual( [ { localName: 'SharedEval', evaluatorName: 'shared.eval' } ] );
|
|
214
210
|
|
|
@@ -230,7 +226,7 @@ const obj = {};`;
|
|
|
230
226
|
const { sharedEvaluatorImports } = collectTargetImports(
|
|
231
227
|
ast,
|
|
232
228
|
join( dir, 'workflows', 'my_workflow' ),
|
|
233
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map(), sharedEvaluatorsNameCache: new Map()
|
|
229
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map(), sharedEvaluatorsNameCache: new Map() }
|
|
234
230
|
);
|
|
235
231
|
expect( sharedEvaluatorImports ).toEqual( [ { localName: 'SharedEval', evaluatorName: 'shared.eval' } ] );
|
|
236
232
|
|
|
@@ -254,8 +250,7 @@ const obj = {};`;
|
|
|
254
250
|
join( dir, 'workflows', 'my_workflow' ),
|
|
255
251
|
{
|
|
256
252
|
stepsNameCache: new Map(), sharedStepsNameCache: new Map(),
|
|
257
|
-
evaluatorsNameCache: new Map(), sharedEvaluatorsNameCache: new Map()
|
|
258
|
-
workflowNameCache: new Map()
|
|
253
|
+
evaluatorsNameCache: new Map(), sharedEvaluatorsNameCache: new Map()
|
|
259
254
|
}
|
|
260
255
|
);
|
|
261
256
|
expect( sharedStepImports ).toEqual( [ { localName: 'SharedA', stepName: 'shared.a' } ] );
|
|
@@ -280,8 +275,7 @@ const obj = {};`;
|
|
|
280
275
|
join( dir, 'workflows', 'my_workflow' ),
|
|
281
276
|
{
|
|
282
277
|
stepsNameCache: new Map(), sharedStepsNameCache: new Map(),
|
|
283
|
-
evaluatorsNameCache: new Map(), sharedEvaluatorsNameCache: new Map()
|
|
284
|
-
workflowNameCache: new Map()
|
|
278
|
+
evaluatorsNameCache: new Map(), sharedEvaluatorsNameCache: new Map()
|
|
285
279
|
}
|
|
286
280
|
);
|
|
287
281
|
expect( sharedStepImports ).toEqual( [ { localName: 'MyExport', stepName: 'bad' } ] );
|
|
@@ -304,7 +298,7 @@ const obj = {};`;
|
|
|
304
298
|
const { sharedEvaluatorImports } = collectTargetImports(
|
|
305
299
|
ast,
|
|
306
300
|
join( dir, 'workflows', 'my_workflow' ),
|
|
307
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map(), sharedEvaluatorsNameCache: new Map()
|
|
301
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map(), sharedEvaluatorsNameCache: new Map() }
|
|
308
302
|
);
|
|
309
303
|
expect( sharedEvaluatorImports ).toEqual( [ { localName: 'MyExport', evaluatorName: 'bad' } ] );
|
|
310
304
|
|
|
@@ -326,78 +320,12 @@ const obj = {};`;
|
|
|
326
320
|
const { sharedEvaluatorImports } = collectTargetImports(
|
|
327
321
|
ast,
|
|
328
322
|
join( dir, 'workflows', 'my_workflow' ),
|
|
329
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map(), sharedEvaluatorsNameCache: new Map()
|
|
323
|
+
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map(), sharedEvaluatorsNameCache: new Map() }
|
|
330
324
|
);
|
|
331
325
|
expect( sharedEvaluatorImports ).toEqual( [ { localName: 'MyExport', evaluatorName: 'bad' } ] );
|
|
332
326
|
|
|
333
327
|
rmSync( dir, { recursive: true, force: true } );
|
|
334
328
|
} );
|
|
335
329
|
|
|
336
|
-
it( 'collects ESM imports from @growthxlabs/workflows_catalog', () => {
|
|
337
|
-
const dir = mkdtempSync( join( tmpdir(), 'collect-cat-esm-' ) );
|
|
338
|
-
const pkgRoot = join( dir, 'node_modules', '@growthxlabs', 'workflows_catalog' );
|
|
339
|
-
const srcDir = join( pkgRoot, 'src' );
|
|
340
|
-
mkdirSync( join( srcDir, 'workflows', 'wf' ), { recursive: true } );
|
|
341
|
-
writeFileSync( join( pkgRoot, 'package.json' ), JSON.stringify( {
|
|
342
|
-
name: '@growthxlabs/workflows_catalog',
|
|
343
|
-
type: 'module',
|
|
344
|
-
main: './src/index.js',
|
|
345
|
-
dependencies: { '@outputai/core': '1.0.0' }
|
|
346
|
-
} ) );
|
|
347
|
-
writeFileSync( join( srcDir, 'index.js' ), 'export { default as sumNumbers } from \'./workflows/wf/workflow.js\';\n' );
|
|
348
|
-
writeFileSync( join( srcDir, 'workflows', 'wf', 'workflow.js' ), 'export default workflow({ name: \'cat.flow\' });\n' );
|
|
349
|
-
|
|
350
|
-
const fileDir = join( dir, 'consumer' );
|
|
351
|
-
mkdirSync( fileDir, { recursive: true } );
|
|
352
|
-
const resourcePath = join( fileDir, 'workflow.js' );
|
|
353
|
-
|
|
354
|
-
const source = `
|
|
355
|
-
import { sumNumbers as SN } from '@growthxlabs/workflows_catalog';
|
|
356
|
-
const x = 1;`;
|
|
357
|
-
const ast = makeAst( source, resourcePath );
|
|
358
|
-
|
|
359
|
-
const { flowImports } = collectTargetImports(
|
|
360
|
-
ast,
|
|
361
|
-
fileDir,
|
|
362
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map(), workflowNameCache: new Map() },
|
|
363
|
-
resourcePath
|
|
364
|
-
);
|
|
365
|
-
expect( flowImports ).toEqual( [ { localName: 'SN', workflowName: 'cat.flow' } ] );
|
|
366
|
-
expect( ast.program.body.find( n => n.type === 'ImportDeclaration' ) ).toBeUndefined();
|
|
367
|
-
|
|
368
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
369
|
-
} );
|
|
370
|
-
|
|
371
|
-
it( 'collects CJS destructured require from @growthxlabs/workflows_catalog', () => {
|
|
372
|
-
const dir = mkdtempSync( join( tmpdir(), 'collect-cat-cjs-' ) );
|
|
373
|
-
const pkgRoot = join( dir, 'node_modules', '@growthxlabs', 'workflows_catalog' );
|
|
374
|
-
const srcDir = join( pkgRoot, 'src' );
|
|
375
|
-
mkdirSync( join( srcDir, 'workflows', 'wf' ), { recursive: true } );
|
|
376
|
-
writeFileSync( join( pkgRoot, 'package.json' ), JSON.stringify( {
|
|
377
|
-
name: '@growthxlabs/workflows_catalog',
|
|
378
|
-
type: 'module',
|
|
379
|
-
main: './src/index.js',
|
|
380
|
-
dependencies: { '@outputai/core': '1.0.0' }
|
|
381
|
-
} ) );
|
|
382
|
-
writeFileSync( join( srcDir, 'index.js' ), 'export { default as sumNumbers } from \'./workflows/wf/workflow.js\';\n' );
|
|
383
|
-
writeFileSync( join( srcDir, 'workflows', 'wf', 'workflow.js' ), 'export default workflow({ name: \'cat.flow2\' });\n' );
|
|
384
|
-
|
|
385
|
-
const fileDir = join( dir, 'consumer' );
|
|
386
|
-
mkdirSync( fileDir, { recursive: true } );
|
|
387
|
-
const resourcePath = join( fileDir, 'workflow.js' );
|
|
388
|
-
|
|
389
|
-
const source = 'const { sumNumbers } = require( \'@growthxlabs/workflows_catalog\' );\nconst x = 1;';
|
|
390
|
-
const ast = makeAst( source, resourcePath );
|
|
391
|
-
|
|
392
|
-
const { flowImports } = collectTargetImports(
|
|
393
|
-
ast,
|
|
394
|
-
fileDir,
|
|
395
|
-
{ stepsNameCache: new Map(), evaluatorsNameCache: new Map(), workflowNameCache: new Map() },
|
|
396
|
-
resourcePath
|
|
397
|
-
);
|
|
398
|
-
expect( flowImports ).toEqual( [ { localName: 'sumNumbers', workflowName: 'cat.flow2' } ] );
|
|
399
|
-
|
|
400
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
401
|
-
} );
|
|
402
330
|
} );
|
|
403
331
|
|
|
@@ -13,10 +13,9 @@ const stepsNameCache = new Map(); // path -> Map<exported, stepName>
|
|
|
13
13
|
const sharedStepsNameCache = new Map(); // path -> Map<exported, stepName> (shared)
|
|
14
14
|
const evaluatorsNameCache = new Map(); // path -> Map<exported, evaluatorName>
|
|
15
15
|
const sharedEvaluatorsNameCache = new Map(); // path -> Map<exported, evaluatorName> (shared)
|
|
16
|
-
const workflowNameCache = new Map(); // path -> { default?: name, named: Map<exported, flowName> }
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
|
-
* Webpack loader that rewrites step/
|
|
18
|
+
* Webpack loader that rewrites step/evaluator calls by reading names from
|
|
20
19
|
* the respective modules and transforming `fn` bodies accordingly.
|
|
21
20
|
* Preserves sourcemaps.
|
|
22
21
|
*
|
|
@@ -28,21 +27,21 @@ const workflowNameCache = new Map(); // path -> { default?: name, named: Map<exp
|
|
|
28
27
|
export default function stepImportRewriterAstLoader( source, inputMap ) {
|
|
29
28
|
this.cacheable?.( true );
|
|
30
29
|
const callback = this.async?.() ?? this.callback;
|
|
31
|
-
const cache = { stepsNameCache, sharedStepsNameCache, evaluatorsNameCache, sharedEvaluatorsNameCache
|
|
30
|
+
const cache = { stepsNameCache, sharedStepsNameCache, evaluatorsNameCache, sharedEvaluatorsNameCache };
|
|
32
31
|
|
|
33
32
|
try {
|
|
34
33
|
const filename = this.resourcePath;
|
|
35
34
|
const ast = parse( String( source ), filename );
|
|
36
35
|
const fileDir = dirname( filename );
|
|
37
|
-
const { stepImports, sharedStepImports, evaluatorImports, sharedEvaluatorImports
|
|
36
|
+
const { stepImports, sharedStepImports, evaluatorImports, sharedEvaluatorImports } =
|
|
38
37
|
collectTargetImports( ast, fileDir, cache, filename );
|
|
39
38
|
|
|
40
39
|
// No imports
|
|
41
|
-
if ( [].concat( stepImports, sharedStepImports, evaluatorImports, sharedEvaluatorImports
|
|
40
|
+
if ( [].concat( stepImports, sharedStepImports, evaluatorImports, sharedEvaluatorImports ).length === 0 ) {
|
|
42
41
|
return callback( null, source, inputMap );
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
const rewrote = rewriteFnBodies( { ast, stepImports, sharedStepImports, evaluatorImports, sharedEvaluatorImports
|
|
44
|
+
const rewrote = rewriteFnBodies( { ast, stepImports, sharedStepImports, evaluatorImports, sharedEvaluatorImports } );
|
|
46
45
|
// No edits performed
|
|
47
46
|
if ( !rewrote ) {
|
|
48
47
|
return callback( null, source, inputMap );
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { mkdtempSync, writeFileSync, rmSync, mkdirSync } from 'node:fs';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
|
-
import {
|
|
4
|
+
import { join } from 'node:path';
|
|
5
5
|
import loader from './index.mjs';
|
|
6
6
|
|
|
7
7
|
function runLoader( source, resourcePath ) {
|
|
@@ -17,7 +17,7 @@ function runLoader( source, resourcePath ) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
describe( 'workflows_rewriter Webpack loader spec', () => {
|
|
20
|
-
it( 'rewrites ESM imports and
|
|
20
|
+
it( 'rewrites ESM step imports and leaves workflow calls intact', async () => {
|
|
21
21
|
const dir = mkdtempSync( join( tmpdir(), 'ast-loader-esm-' ) );
|
|
22
22
|
writeFileSync( join( dir, 'steps.js' ), 'export const StepA = step({ name: \'step.a\' });' );
|
|
23
23
|
writeFileSync( join( dir, 'workflow.js' ), `
|
|
@@ -39,11 +39,11 @@ const obj = {
|
|
|
39
39
|
const { code } = await runLoader( source, join( dir, 'file.js' ) );
|
|
40
40
|
|
|
41
41
|
expect( code ).not.toMatch( /from '\.\/steps\.js'/ );
|
|
42
|
-
expect( code ).
|
|
42
|
+
expect( code ).toMatch( /from '\.\/workflow\.js'/ );
|
|
43
43
|
expect( code ).toMatch( /fn:\s*async function \(x\)/ );
|
|
44
44
|
expect( code ).toMatch( /this\.invokeStep\('step\.a',\s*1\)/ );
|
|
45
|
-
expect( code ).toMatch( /
|
|
46
|
-
expect( code ).toMatch( /
|
|
45
|
+
expect( code ).toMatch( /FlowA\(2\)/ );
|
|
46
|
+
expect( code ).toMatch( /FlowDef\(3\)/ );
|
|
47
47
|
|
|
48
48
|
rmSync( dir, { recursive: true, force: true } );
|
|
49
49
|
} );
|
|
@@ -98,7 +98,7 @@ const obj = {
|
|
|
98
98
|
rmSync( dir, { recursive: true, force: true } );
|
|
99
99
|
} );
|
|
100
100
|
|
|
101
|
-
it( 'rewrites CJS requires and
|
|
101
|
+
it( 'rewrites CJS step requires and leaves workflow calls intact', async () => {
|
|
102
102
|
const dir = mkdtempSync( join( tmpdir(), 'ast-loader-cjs-' ) );
|
|
103
103
|
writeFileSync( join( dir, 'steps.js' ), 'export const StepB = step({ name: \'step.b\' });' );
|
|
104
104
|
writeFileSync( join( dir, 'workflow.js' ), 'export default workflow({ name: \'flow.c\' });' );
|
|
@@ -117,10 +117,10 @@ const obj = {
|
|
|
117
117
|
const { code } = await runLoader( source, join( dir, 'file.js' ) );
|
|
118
118
|
|
|
119
119
|
expect( code ).not.toMatch( /require\('\.\/steps\.js'\)/ );
|
|
120
|
-
expect( code ).
|
|
120
|
+
expect( code ).toMatch( /require\('\.\/workflow\.js'\)/ );
|
|
121
121
|
expect( code ).toMatch( /fn:\s*async function \(y\)/ );
|
|
122
122
|
expect( code ).toMatch( /this\.invokeStep\('step\.b'\)/ );
|
|
123
|
-
expect( code ).toMatch( /
|
|
123
|
+
expect( code ).toMatch( /FlowDefault\(\)/ );
|
|
124
124
|
|
|
125
125
|
rmSync( dir, { recursive: true, force: true } );
|
|
126
126
|
} );
|
|
@@ -143,8 +143,8 @@ const obj = { fn: async () => { StepC(); FlowC(); FlowDef(); } }`;
|
|
|
143
143
|
|
|
144
144
|
const { code } = await runLoader( source, join( dir, 'file.js' ) );
|
|
145
145
|
expect( code ).toMatch( /this\.invokeStep\('step\.const'\)/ );
|
|
146
|
-
expect( code ).toMatch( /
|
|
147
|
-
expect( code ).toMatch( /
|
|
146
|
+
expect( code ).toMatch( /FlowC\(\)/ );
|
|
147
|
+
expect( code ).toMatch( /FlowDef\(\)/ );
|
|
148
148
|
rmSync( dir, { recursive: true, force: true } );
|
|
149
149
|
} );
|
|
150
150
|
|
|
@@ -196,78 +196,6 @@ const obj = {
|
|
|
196
196
|
rmSync( dir, { recursive: true, force: true } );
|
|
197
197
|
} );
|
|
198
198
|
|
|
199
|
-
it( 'rewrites ESM imports from @growthxlabs/workflows_catalog to startWorkflow', async () => {
|
|
200
|
-
const dir = mkdtempSync( join( tmpdir(), 'ast-loader-catalog-' ) );
|
|
201
|
-
const pkgRoot = join( dir, 'node_modules', '@growthxlabs', 'workflows_catalog' );
|
|
202
|
-
const srcDir = join( pkgRoot, 'src' );
|
|
203
|
-
mkdirSync( join( srcDir, 'workflows', 'wf' ), { recursive: true } );
|
|
204
|
-
writeFileSync( join( pkgRoot, 'package.json' ), JSON.stringify( {
|
|
205
|
-
name: '@growthxlabs/workflows_catalog',
|
|
206
|
-
type: 'module',
|
|
207
|
-
main: './src/index.js',
|
|
208
|
-
dependencies: { '@outputai/core': '1.0.0' }
|
|
209
|
-
} ) );
|
|
210
|
-
writeFileSync( join( srcDir, 'index.js' ), 'export { default as sumNumbers } from \'./workflows/wf/workflow.js\';\n' );
|
|
211
|
-
writeFileSync( join( srcDir, 'workflows', 'wf', 'workflow.js' ), 'export default workflow({ name: \'nest.cat\' });\n' );
|
|
212
|
-
|
|
213
|
-
const resourcePath = join( dir, 'workflows', 'mine', 'workflow.js' );
|
|
214
|
-
mkdirSync( dirname( resourcePath ), { recursive: true } );
|
|
215
|
-
|
|
216
|
-
const source = `
|
|
217
|
-
import { sumNumbers } from '@growthxlabs/workflows_catalog';
|
|
218
|
-
|
|
219
|
-
const obj = {
|
|
220
|
-
fn: async () => {
|
|
221
|
-
sumNumbers( 1 );
|
|
222
|
-
}
|
|
223
|
-
}`;
|
|
224
|
-
|
|
225
|
-
const { code } = await runLoader( source, resourcePath );
|
|
226
|
-
|
|
227
|
-
expect( code ).not.toMatch( /@growthxlabs\/workflows_catalog/ );
|
|
228
|
-
expect( code ).toMatch( /this\.startWorkflow\('nest\.cat',\s*1\)/ );
|
|
229
|
-
|
|
230
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
231
|
-
} );
|
|
232
|
-
|
|
233
|
-
it( 'rewrites imports through the output workflow bundle export condition', async () => {
|
|
234
|
-
const dir = mkdtempSync( join( tmpdir(), 'ast-loader-catalog-condition-' ) );
|
|
235
|
-
const pkgRoot = join( dir, 'node_modules', '@test', 'conditional_catalog' );
|
|
236
|
-
mkdirSync( join( pkgRoot, 'bundle' ), { recursive: true } );
|
|
237
|
-
writeFileSync( join( pkgRoot, 'package.json' ), JSON.stringify( {
|
|
238
|
-
name: '@test/conditional_catalog',
|
|
239
|
-
type: 'module',
|
|
240
|
-
main: './node-entry.js',
|
|
241
|
-
exports: {
|
|
242
|
-
'.': {
|
|
243
|
-
'output-workflow-bundle': './bundle/workflow.js',
|
|
244
|
-
default: './node-entry.js'
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
} ) );
|
|
248
|
-
writeFileSync( join( pkgRoot, 'node-entry.js' ), 'export const helper = () => 1;\n' );
|
|
249
|
-
writeFileSync( join( pkgRoot, 'bundle', 'workflow.js' ), 'export default workflow({ name: \'bundle.cat\' });\n' );
|
|
250
|
-
|
|
251
|
-
const resourcePath = join( dir, 'workflows', 'mine', 'workflow.js' );
|
|
252
|
-
mkdirSync( dirname( resourcePath ), { recursive: true } );
|
|
253
|
-
|
|
254
|
-
const source = `
|
|
255
|
-
import BundleCatalog from '@test/conditional_catalog';
|
|
256
|
-
|
|
257
|
-
const obj = {
|
|
258
|
-
fn: async () => {
|
|
259
|
-
BundleCatalog( 1 );
|
|
260
|
-
}
|
|
261
|
-
}`;
|
|
262
|
-
|
|
263
|
-
const { code } = await runLoader( source, resourcePath );
|
|
264
|
-
|
|
265
|
-
expect( code ).not.toMatch( /@test\/conditional_catalog/ );
|
|
266
|
-
expect( code ).toMatch( /this\.startWorkflow\('bundle\.cat',\s*1\)/ );
|
|
267
|
-
|
|
268
|
-
rmSync( dir, { recursive: true, force: true } );
|
|
269
|
-
} );
|
|
270
|
-
|
|
271
199
|
it( 'throws on non-static name', async () => {
|
|
272
200
|
const dir = mkdtempSync( join( tmpdir(), 'ast-loader-error-' ) );
|
|
273
201
|
writeFileSync( join( dir, 'steps.js' ), `
|
|
@@ -282,7 +210,7 @@ import { StepX } from './steps.js';
|
|
|
282
210
|
import WF from './workflow.js';
|
|
283
211
|
const obj = { fn: async () => { StepX(); WF(); } }`;
|
|
284
212
|
|
|
285
|
-
await expect( runLoader( source, join( dir, 'file.js' ) ) ).rejects.toThrow( /Invalid
|
|
213
|
+
await expect( runLoader( source, join( dir, 'file.js' ) ) ).rejects.toThrow( /Invalid step name/ );
|
|
286
214
|
rmSync( dir, { recursive: true, force: true } );
|
|
287
215
|
} );
|
|
288
216
|
} );
|