@outputai/core 0.10.1-next.b7b2fbe.0 → 0.10.1-next.eaf62a3.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/consts.js +2 -1
- package/src/helpers/object.js +48 -35
- package/src/helpers/object.spec.js +123 -75
- 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/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/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
|
@@ -9,26 +9,13 @@ import {
|
|
|
9
9
|
isWorkflowPath,
|
|
10
10
|
isAbsoluteWorkflowJsResource
|
|
11
11
|
} from '../tools.js';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Files where a bare npm import may bind to child workflows (catalog packages, etc.).
|
|
15
|
-
* Matches {@link collectTargetImports} for `workflow.js`; steps/evaluators need the same
|
|
16
|
-
* binding knowledge for fn-body validation only.
|
|
17
|
-
* @param {string} filename - Absolute resource path.
|
|
18
|
-
* @returns {boolean}
|
|
19
|
-
*/
|
|
20
|
-
const fileMayBindBareNpmWorkflowImports = filename => {
|
|
21
|
-
const n = filename.replace( /\\/g, '/' );
|
|
22
|
-
return isAbsoluteWorkflowJsResource( filename ) ||
|
|
23
|
-
isAnyStepsPath( n ) || isAnyEvaluatorsPath( n );
|
|
24
|
-
};
|
|
25
12
|
import {
|
|
26
13
|
isBareNpmSpecifier,
|
|
27
14
|
resolveBareImportSpecifiersAsWorkflows,
|
|
28
15
|
resolveBareDestructuredRequireAsWorkflows,
|
|
29
16
|
resolveBareDefaultRequireAsWorkflow
|
|
30
|
-
} from '
|
|
31
|
-
import { ComponentFile } from '../consts.js';
|
|
17
|
+
} from './npm_workflow_export_resolve.js';
|
|
18
|
+
import { ComponentFactory, ComponentFile } from '../consts.js';
|
|
32
19
|
import {
|
|
33
20
|
isCallExpression,
|
|
34
21
|
isFunctionExpression,
|
|
@@ -41,6 +28,19 @@ import {
|
|
|
41
28
|
isStringLiteral
|
|
42
29
|
} from '@babel/types';
|
|
43
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Files where a bare npm import may bind to child workflows (catalog packages, etc.).
|
|
33
|
+
* Matches {@link collectTargetImports} for `workflow.js`; steps/evaluators need the same
|
|
34
|
+
* binding knowledge for fn-body validation only.
|
|
35
|
+
* @param {string} filename - Absolute resource path.
|
|
36
|
+
* @returns {boolean}
|
|
37
|
+
*/
|
|
38
|
+
const fileMayBindBareNpmWorkflowImports = filename => {
|
|
39
|
+
const n = filename.replace( /\\/g, '/' );
|
|
40
|
+
return isAbsoluteWorkflowJsResource( filename ) ||
|
|
41
|
+
isAnyStepsPath( n ) || isAnyEvaluatorsPath( n );
|
|
42
|
+
};
|
|
43
|
+
|
|
44
44
|
// Handle CJS/ESM interop for Babel packages when executed as a webpack loader
|
|
45
45
|
const traverse = traverseModule.default ?? traverseModule;
|
|
46
46
|
|
|
@@ -72,28 +72,77 @@ const getFileKindLabel = filename => {
|
|
|
72
72
|
* @param {string} filename - The file path where the call occurs
|
|
73
73
|
*/
|
|
74
74
|
const validateInstantiationLocation = ( calleeName, filename ) => {
|
|
75
|
-
if ( calleeName ===
|
|
75
|
+
if ( calleeName === ComponentFactory.STEP && !isAnyStepsPath( filename ) ) {
|
|
76
76
|
throw new Error( `Invalid instantiation location: step() can only be called in files with 'steps' in the path. Found in: ${filename}` );
|
|
77
77
|
}
|
|
78
|
-
if ( calleeName ===
|
|
78
|
+
if ( calleeName === ComponentFactory.EVALUATOR && !isAnyEvaluatorsPath( filename ) ) {
|
|
79
79
|
throw new Error( `Invalid instantiation location: evaluator() can only be called in files with 'evaluators' in the path. Found in: ${filename}` );
|
|
80
80
|
}
|
|
81
|
-
if ( calleeName ===
|
|
81
|
+
if ( calleeName === ComponentFactory.WORKFLOW && !isWorkflowPath( filename ) ) {
|
|
82
82
|
throw new Error( `Invalid instantiation location: workflow() can only be called in files with 'workflow' in the path. Found in: ${filename}` );
|
|
83
83
|
}
|
|
84
84
|
};
|
|
85
85
|
|
|
86
|
+
const validateActivityCallsAreInsideFunctions = ( {
|
|
87
|
+
ast, filename, localStepIds, localEvaluatorIds, importedStepIds, importedEvaluatorIds
|
|
88
|
+
} ) => {
|
|
89
|
+
traverse( ast, {
|
|
90
|
+
CallExpression: path => {
|
|
91
|
+
const callee = path.node.callee;
|
|
92
|
+
if ( !isIdentifier( callee ) || path.getFunctionParent() ) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const { name } = callee;
|
|
97
|
+
const violation = [
|
|
98
|
+
[ ComponentFactory.STEP, localStepIds.has( name ) || importedStepIds.has( name ) ],
|
|
99
|
+
[ ComponentFactory.EVALUATOR, localEvaluatorIds.has( name ) || importedEvaluatorIds.has( name ) ]
|
|
100
|
+
].find( v => v[1] )?.[0];
|
|
101
|
+
|
|
102
|
+
if ( violation ) {
|
|
103
|
+
throw new Error( `Invalid top-level ${violation} call '${name}' in ${filename}. Activities can only be invoked inside functions.` );
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} );
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const isActivityPath = specifier => isAnyStepsPath( specifier ) || isAnyEvaluatorsPath( specifier );
|
|
110
|
+
|
|
111
|
+
const validateActivityImportShape = ( specifier, specifiers ) => {
|
|
112
|
+
if ( !isActivityPath( specifier ) ) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if ( specifiers.some( s => !isImportSpecifier( s ) ) ) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`Invalid activity import from "${specifier}": use named imports only. ` +
|
|
119
|
+
'Default and namespace imports from steps/evaluators files cannot be rewritten.'
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const validateActivityExportShape = ( fileKind, node ) => {
|
|
125
|
+
if ( ![ ComponentFile.STEPS, ComponentFile.EVALUATORS ].includes( fileKind ) ) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if ( node.type === 'ExportDefaultDeclaration' || node.type === 'ExportAllDeclaration' ) {
|
|
130
|
+
throw new Error( 'Invalid activity export: steps/evaluators files must use named exports only.' );
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
86
134
|
/**
|
|
87
135
|
* Webpack loader that validates component instantiation and fn body calls.
|
|
88
136
|
* Returns the source unchanged unless a validation error is found.
|
|
89
137
|
*
|
|
90
138
|
* Rules enforced:
|
|
91
139
|
* - Instantiation location: step() must be in steps path, evaluator() in evaluators path, workflow() in workflow path
|
|
140
|
+
* - Activity files must use named exports only
|
|
141
|
+
* - Activity imports/requires must use named bindings so the rewriter can target each call
|
|
142
|
+
* - Top-level activity calls are rejected
|
|
92
143
|
* - steps.js `fn`: calling any step, evaluator, or workflow inside fn body emits warning
|
|
93
144
|
* - evaluators.js `fn`: calling any step, evaluator, or workflow inside fn body emits warning
|
|
94
145
|
*
|
|
95
|
-
* NOTE: Import restrictions have been removed - any file can import any other file.
|
|
96
|
-
*
|
|
97
146
|
* @param {string|Buffer} source
|
|
98
147
|
* @param {any} inputMap
|
|
99
148
|
* @this {import('webpack').LoaderContext<{}>}
|
|
@@ -122,6 +171,8 @@ export default function workflowValidatorLoader( source, inputMap ) {
|
|
|
122
171
|
ImportDeclaration: path => {
|
|
123
172
|
const specifier = path.node.source.value;
|
|
124
173
|
|
|
174
|
+
validateActivityImportShape( specifier, path.node.specifiers );
|
|
175
|
+
|
|
125
176
|
if ( isBareNpmSpecifier( specifier ) && fileMayBindBareNpmWorkflowImports( filename ) ) {
|
|
126
177
|
const outcome = resolveBareImportSpecifiersAsWorkflows( {
|
|
127
178
|
fromAbsoluteFile: filename,
|
|
@@ -152,6 +203,12 @@ export default function workflowValidatorLoader( source, inputMap ) {
|
|
|
152
203
|
}
|
|
153
204
|
}
|
|
154
205
|
},
|
|
206
|
+
ExportDefaultDeclaration: path => {
|
|
207
|
+
validateActivityExportShape( fileKind, path.node );
|
|
208
|
+
},
|
|
209
|
+
ExportAllDeclaration: path => {
|
|
210
|
+
validateActivityExportShape( fileKind, path.node );
|
|
211
|
+
},
|
|
155
212
|
VariableDeclarator: path => {
|
|
156
213
|
const init = path.node.init;
|
|
157
214
|
if ( !isCallExpression( init ) ) {
|
|
@@ -159,20 +216,20 @@ export default function workflowValidatorLoader( source, inputMap ) {
|
|
|
159
216
|
}
|
|
160
217
|
|
|
161
218
|
// Validate instantiation location for step/evaluator/workflow calls
|
|
162
|
-
if ( isIdentifier( init.callee, { name:
|
|
163
|
-
validateInstantiationLocation(
|
|
219
|
+
if ( isIdentifier( init.callee, { name: ComponentFactory.STEP } ) ) {
|
|
220
|
+
validateInstantiationLocation( ComponentFactory.STEP, filename );
|
|
164
221
|
if ( isIdentifier( path.node.id ) ) {
|
|
165
222
|
localStepIds.add( path.node.id.name );
|
|
166
223
|
}
|
|
167
224
|
}
|
|
168
|
-
if ( isIdentifier( init.callee, { name:
|
|
169
|
-
validateInstantiationLocation(
|
|
225
|
+
if ( isIdentifier( init.callee, { name: ComponentFactory.EVALUATOR } ) ) {
|
|
226
|
+
validateInstantiationLocation( ComponentFactory.EVALUATOR, filename );
|
|
170
227
|
if ( isIdentifier( path.node.id ) ) {
|
|
171
228
|
localEvaluatorIds.add( path.node.id.name );
|
|
172
229
|
}
|
|
173
230
|
}
|
|
174
|
-
if ( isIdentifier( init.callee, { name:
|
|
175
|
-
validateInstantiationLocation(
|
|
231
|
+
if ( isIdentifier( init.callee, { name: ComponentFactory.WORKFLOW } ) ) {
|
|
232
|
+
validateInstantiationLocation( ComponentFactory.WORKFLOW, filename );
|
|
176
233
|
}
|
|
177
234
|
|
|
178
235
|
// CommonJS requires: collect identifiers for fn body call checks
|
|
@@ -208,6 +265,12 @@ export default function workflowValidatorLoader( source, inputMap ) {
|
|
|
208
265
|
|
|
209
266
|
// Collect imported identifiers from require patterns
|
|
210
267
|
const reqType = getFileKind( toAbsolutePath( fileDir, req ) );
|
|
268
|
+
if ( [ ComponentFile.STEPS, ComponentFile.EVALUATORS ].includes( reqType ) && !isObjectPattern( path.node.id ) ) {
|
|
269
|
+
throw new Error(
|
|
270
|
+
`Invalid activity require from "${req}": use destructured requires only. ` +
|
|
271
|
+
'Default-style requires from steps/evaluators files cannot be rewritten.'
|
|
272
|
+
);
|
|
273
|
+
}
|
|
211
274
|
if ( reqType === ComponentFile.STEPS && isObjectPattern( path.node.id ) ) {
|
|
212
275
|
for ( const prop of path.node.id.properties ) {
|
|
213
276
|
if ( isObjectProperty( prop ) && isIdentifier( prop.value ) ) {
|
|
@@ -229,6 +292,10 @@ export default function workflowValidatorLoader( source, inputMap ) {
|
|
|
229
292
|
}
|
|
230
293
|
} );
|
|
231
294
|
|
|
295
|
+
validateActivityCallsAreInsideFunctions( {
|
|
296
|
+
ast, filename, localStepIds, localEvaluatorIds, importedStepIds, importedEvaluatorIds
|
|
297
|
+
} );
|
|
298
|
+
|
|
232
299
|
// Function-body call validations for steps/evaluators files
|
|
233
300
|
if ( [ ComponentFile.STEPS, ComponentFile.EVALUATORS ].includes( fileKind ) ) {
|
|
234
301
|
traverse( ast, {
|
|
@@ -248,9 +315,9 @@ export default function workflowValidatorLoader( source, inputMap ) {
|
|
|
248
315
|
const { name } = callee;
|
|
249
316
|
const fileLabel = getFileKindLabel( filename );
|
|
250
317
|
const violation = [
|
|
251
|
-
[
|
|
252
|
-
[
|
|
253
|
-
[
|
|
318
|
+
[ ComponentFactory.STEP, localStepIds.has( name ) || importedStepIds.has( name ) ],
|
|
319
|
+
[ ComponentFactory.EVALUATOR, localEvaluatorIds.has( name ) || importedEvaluatorIds.has( name ) ],
|
|
320
|
+
[ ComponentFactory.WORKFLOW, importedWorkflowIds.has( name ) ]
|
|
254
321
|
].find( v => v[1] )?.[0];
|
|
255
322
|
|
|
256
323
|
if ( violation ) {
|