@outputai/core 0.9.3-next.c318502.0 → 0.10.1-dev.b7b2fbe.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.
Files changed (33) hide show
  1. package/package.json +1 -1
  2. package/src/consts.js +2 -1
  3. package/src/helpers/object.js +45 -36
  4. package/src/helpers/object.spec.js +118 -75
  5. package/src/interface/workflow.js +92 -85
  6. package/src/interface/workflow.spec.js +135 -142
  7. package/src/sdk/helpers/objects.d.ts +24 -19
  8. package/src/worker/configs.js +4 -0
  9. package/src/worker/configs.spec.js +21 -0
  10. package/src/worker/configs_tuner_schema.js +81 -0
  11. package/src/worker/configs_tuner_schema.spec.js +127 -0
  12. package/src/worker/index.js +12 -3
  13. package/src/worker/index.spec.js +28 -0
  14. package/src/worker/interceptors/workflow.js +5 -5
  15. package/src/worker/interceptors/workflow.spec.js +7 -7
  16. package/src/worker/loader/activities.js +56 -40
  17. package/src/worker/loader/activities.spec.js +21 -22
  18. package/src/worker/loader/workflows.spec.js +1 -2
  19. package/src/worker/webpack_loaders/consts.js +6 -0
  20. package/src/worker/webpack_loaders/tools.js +1 -146
  21. package/src/worker/webpack_loaders/tools.spec.js +0 -23
  22. package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.js +24 -32
  23. package/src/worker/webpack_loaders/workflow_rewriter/collect_target_imports.spec.js +82 -279
  24. package/src/worker/webpack_loaders/workflow_rewriter/index.mjs +6 -7
  25. package/src/worker/webpack_loaders/workflow_rewriter/index.spec.js +57 -119
  26. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_activity_calls.js +88 -0
  27. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_activity_calls.spec.js +165 -0
  28. package/src/worker/webpack_loaders/workflow_validator/index.mjs +96 -29
  29. package/src/worker/webpack_loaders/workflow_validator/index.spec.js +110 -583
  30. package/src/worker/webpack_loaders/{npm_workflow_export_resolve.js → workflow_validator/npm_workflow_export_resolve.js} +1 -1
  31. package/src/worker/webpack_loaders/{npm_workflow_export_resolve.spec.js → workflow_validator/npm_workflow_export_resolve.spec.js} +1 -1
  32. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.js +0 -193
  33. package/src/worker/webpack_loaders/workflow_rewriter/rewrite_fn_bodies.spec.js +0 -123
@@ -2,27 +2,14 @@ import parser from '@babel/parser';
2
2
  import { resolve as resolvePath } from 'node:path';
3
3
  import { readFileSync } from 'node:fs';
4
4
  import {
5
- blockStatement,
6
- callExpression,
7
- functionExpression,
8
- identifier,
9
- isArrowFunctionExpression,
10
5
  isAssignmentPattern,
11
- isBlockStatement,
12
6
  isCallExpression,
13
7
  isExportNamedDeclaration,
14
- isFunctionExpression,
15
8
  isIdentifier,
16
- isVariableDeclarator,
17
9
  isStringLiteral,
18
10
  isVariableDeclaration,
19
11
  isObjectExpression,
20
- memberExpression,
21
- returnStatement,
22
- stringLiteral,
23
- thisExpression,
24
- isExportDefaultDeclaration,
25
- isFunctionDeclaration
12
+ isExportDefaultDeclaration
26
13
  } from '@babel/types';
27
14
  import { ComponentFile, NodeType } from './consts.js';
28
15
 
@@ -100,17 +87,6 @@ export const getLocalNameFromDestructuredProperty = prop => {
100
87
  return null;
101
88
  };
102
89
 
103
- /**
104
- * Convert an ArrowFunctionExpression to a FunctionExpression.
105
- * Wraps expression bodies in a block with a return statement.
106
- * @param {import('@babel/types').ArrowFunctionExpression} arrow - Arrow function.
107
- * @returns {import('@babel/types').FunctionExpression} Function expression.
108
- */
109
- export const toFunctionExpression = arrow => {
110
- const body = isBlockStatement( arrow.body ) ? arrow.body : blockStatement( [ returnStatement( arrow.body ) ] );
111
- return functionExpression( null, arrow.params, body, arrow.generator ?? false, arrow.async ?? false );
112
- };
113
-
114
90
  /**
115
91
  * Check if a module specifier or request string points to steps.js or is in a steps folder.
116
92
  * Matches: steps.js, /steps.js, /steps/*.js
@@ -231,38 +207,6 @@ export const getFileKind = path => {
231
207
  return null;
232
208
  };
233
209
 
234
- /**
235
- * Create a `this.method(literalName, ...args)` CallExpression.
236
- * @param {string} method - Method name on `this`.
237
- * @param {string} literalName - First string literal argument.
238
- * @param {import('@babel/types').Expression[]} args - Remaining call arguments.
239
- * @returns {import('@babel/types').CallExpression} Call expression node.
240
- */
241
- export const createThisMethodCall = ( method, literalName, args ) =>
242
- callExpression( memberExpression( thisExpression(), identifier( method ) ), [ stringLiteral( literalName ), ...args ] );
243
-
244
- /**
245
- * Build a CallExpression that binds `this` at the call site:
246
- * fn(arg1, arg2) -> fn.call(this, arg1, arg2)
247
- *
248
- * When to use:
249
- * - Inside workflow `fn` rewriting, local call-chain functions must receive the dynamic `this`
250
- * so that emitted `this.invokeStep(...)` and similar calls inside them operate correctly.
251
- *
252
- * Example:
253
- * // Input AST intent:
254
- * foo(a, b);
255
- *
256
- * // Rewritten AST:
257
- * foo.call(this, a, b);
258
- *
259
- * @param {string} calleeName - Identifier name of the function being called (e.g., 'foo').
260
- * @param {import('@babel/types').Expression[]} args - Original call arguments.
261
- * @returns {import('@babel/types').CallExpression} CallExpression node representing `callee.call(this, ...args)`.
262
- */
263
- export const bindThisAtCallSite = ( calleeName, args ) =>
264
- callExpression( memberExpression( identifier( calleeName ), identifier( 'call' ) ), [ thisExpression(), ...args ] );
265
-
266
210
  /**
267
211
  * Resolve an options object's name property to a string.
268
212
  * Accepts literal strings or top-level const string identifiers.
@@ -466,92 +410,3 @@ export const buildWorkflowNameMap = ( path, cache ) => {
466
410
  return result;
467
411
  };
468
412
 
469
- /**
470
- * Determine whether a node represents a function body usable as a workflow `fn`.
471
- *
472
- * Why this matters:
473
- * - Workflow `fn` needs a dynamic `this` so the rewriter can emit calls like `this.invokeStep(...)`.
474
- * - Arrow functions do not have their own `this`; they capture `this` lexically, which breaks the runtime contract.
475
- *
476
- * Accepts:
477
- * - FunctionExpression (possibly async/generator), e.g.:
478
- * const obj = {
479
- * fn: async function (input) {
480
- * return input;
481
- * }
482
- * };
483
- *
484
- * Rejects:
485
- * - ArrowFunctionExpression, e.g.:
486
- * const obj = {
487
- * fn: async (input) => input
488
- * };
489
- *
490
- * - Any other non-function expression.
491
- *
492
- * Notes:
493
- * - The rewriter will proactively convert arrow `fn` to a FunctionExpression before further processing.
494
- *
495
- * @param {import('@babel/types').Expression} v - Candidate node for `fn` value.
496
- * @returns {boolean} True if `v` is a FunctionExpression and not an arrow function.
497
- */
498
- export const isFunction = v => isFunctionExpression( v ) && !isArrowFunctionExpression( v );
499
-
500
- /**
501
- * Determine whether a variable declarator represents a function-like value.
502
- *
503
- * Use case:
504
- * - When `fn` calls a locally-declared function (directly or transitively), we need to:
505
- * - propagate `this` to that function call (`callee.call(this, ...)`)
506
- * - traverse into that function's body to rewrite imported step/workflow/evaluator calls.
507
- *
508
- * Matches patterns like:
509
- * - Function expression:
510
- * const foo = function (x) { return x + 1; };
511
- *
512
- * - Async/generator function expression:
513
- * const foo = async function (x) { return await work(x); };
514
- *
515
- * - Arrow function (will be normalized to FunctionExpression by the rewriter):
516
- * const foo = (x) => x + 1;
517
- * const foo = async (x) => await work(x);
518
- *
519
- * Does not match:
520
- * - Non-function initializers:
521
- * const foo = 42;
522
- * const foo = someIdentifier;
523
- *
524
- * @param {import('@babel/types').Node} v - AST node (typically a VariableDeclarator).
525
- * @returns {boolean} True if the declarator's initializer is a function (arrow or function expression).
526
- */
527
- export const isVarFunction = v =>
528
- isVariableDeclarator( v ) && ( isFunctionExpression( v.init ) || isArrowFunctionExpression( v.init ) );
529
-
530
- /**
531
- * Determine whether a binding node corresponds to a function-like declaration usable
532
- * as a call-chain function target during workflow rewriting.
533
- *
534
- * Matches:
535
- * - FunctionDeclaration:
536
- * function foo(x) { return x + 1; }
537
- *
538
- * - VariableDeclarator initialized with a function or arrow (normalized later):
539
- * const foo = function (x) { return x + 1; };
540
- * const foo = (x) => x + 1;
541
- *
542
- * Non-matches:
543
- * - Any binding that is not a function declaration nor a variable declarator with a function initializer.
544
- *
545
- * Why this matters:
546
- * - The rewriter traverses call chains from the workflow `fn`. It must recognize which local
547
- * callees are valid function bodies to rewrite and into which it can propagate `this`.
548
- *
549
- * @param {import('@babel/types').Node} node - Binding path node (FunctionDeclaration or VariableDeclarator).
550
- * @returns {boolean} True if the node represents a function-like binding.
551
- */
552
- export const isFunctionLikeBinding = node =>
553
- isFunctionDeclaration( node ) ||
554
- (
555
- isVariableDeclarator( node ) &&
556
- ( isFunctionExpression( node.init ) || isArrowFunctionExpression( node.init ) )
557
- );
@@ -9,7 +9,6 @@ import {
9
9
  extractTopLevelStringConsts,
10
10
  getObjectKeyName,
11
11
  getLocalNameFromDestructuredProperty,
12
- toFunctionExpression,
13
12
  isStepsPath,
14
13
  isSharedStepsPath,
15
14
  isAnyStepsPath,
@@ -17,7 +16,6 @@ import {
17
16
  isSharedEvaluatorsPath,
18
17
  isWorkflowPath,
19
18
  isAbsoluteWorkflowJsResource,
20
- createThisMethodCall,
21
19
  resolveNameFromArg,
22
20
  resolveNameFromOptions,
23
21
  buildStepsNameMap,
@@ -130,17 +128,6 @@ describe( 'workflow_rewriter tools', () => {
130
128
  rmSync( dir, { recursive: true, force: true } );
131
129
  } );
132
130
 
133
- it( 'toFunctionExpression: converts arrow, wraps expression bodies', () => {
134
- const arrowExprBody = t.arrowFunctionExpression( [ t.identifier( 'x' ) ], t.identifier( 'x' ) );
135
- const arrowBlockBody = t.arrowFunctionExpression( [], t.blockStatement( [ t.returnStatement( t.numericLiteral( 1 ) ) ] ) );
136
- const fn1 = toFunctionExpression( arrowExprBody );
137
- const fn2 = toFunctionExpression( arrowBlockBody );
138
- expect( t.isFunctionExpression( fn1 ) ).toBe( true );
139
- expect( t.isBlockStatement( fn1.body ) ).toBe( true );
140
- expect( t.isReturnStatement( fn1.body.body[0] ) ).toBe( true );
141
- expect( t.isFunctionExpression( fn2 ) ).toBe( true );
142
- } );
143
-
144
131
  it( 'isStepsPath: matches LOCAL steps.js (no path traversal)', () => {
145
132
  // Local steps (without ../ or /shared/)
146
133
  expect( isStepsPath( 'steps.js' ) ).toBe( true );
@@ -226,16 +213,6 @@ describe( 'workflow_rewriter tools', () => {
226
213
  expect( isSharedEvaluatorsPath( 'steps.js' ) ).toBe( false );
227
214
  } );
228
215
 
229
- it( 'createThisMethodCall: builds this.method(\'name\', ...args) call', () => {
230
- const call = createThisMethodCall( 'invoke', 'n', [ t.numericLiteral( 1 ), t.identifier( 'x' ) ] );
231
- expect( t.isCallExpression( call ) ).toBe( true );
232
- expect( t.isMemberExpression( call.callee ) ).toBe( true );
233
- expect( t.isThisExpression( call.callee.object ) ).toBe( true );
234
- expect( t.isIdentifier( call.callee.property, { name: 'invoke' } ) ).toBe( true );
235
- expect( t.isStringLiteral( call.arguments[0], { value: 'n' } ) ).toBe( true );
236
- expect( call.arguments.length ).toBe( 3 );
237
- } );
238
-
239
216
  it( 'buildSharedStepsNameMap: reads names from shared steps module and caches result', () => {
240
217
  const dir = mkdtempSync( join( tmpdir(), 'tools-shared-steps-' ) );
241
218
  mkdirSync( join( dir, 'shared', 'steps' ), { recursive: true } );
@@ -43,7 +43,7 @@ const removeRequireDeclarator = path => {
43
43
 
44
44
  const collectDestructuredRequires = ( path, absolutePath, req, descriptors ) => {
45
45
  const propFilter = p => isObjectProperty( p ) && isIdentifier( p.key );
46
- for ( const { match, buildMap, cache, target, valueKey, label } of descriptors ) {
46
+ for ( const { match, buildMap, cache, label, target } of descriptors ) {
47
47
  if ( !match( req ) ) {
48
48
  continue;
49
49
  }
@@ -54,7 +54,7 @@ const collectDestructuredRequires = ( path, absolutePath, req, descriptors ) =>
54
54
  if ( localName ) {
55
55
  const resolved = nameMap.get( importedName );
56
56
  if ( resolved ) {
57
- target.push( { localName, [valueKey]: resolved } );
57
+ target.push( { localName, activityName: resolved } );
58
58
  } else {
59
59
  throw unresolvedImportError( importedName, label, absolutePath );
60
60
  }
@@ -67,25 +67,26 @@ const collectDestructuredRequires = ( path, absolutePath, req, descriptors ) =>
67
67
 
68
68
  /**
69
69
  * Collect and strip target imports and requires from an AST, producing
70
- * step/evaluator import mappings for later rewrites.
70
+ * activity import mappings for later rewrites.
71
71
  *
72
72
  * Mutates the AST by removing matching import declarations and require declarators.
73
73
  *
74
74
  * @param {import('@babel/types').File} ast - Parsed file AST.
75
75
  * @param {string} fileDir - Absolute directory of the file represented by `ast`.
76
- * @param {{ stepsNameCache: Map<string,Map<string,string>> }} caches
76
+ * @param {{
77
+ * stepsNameCache: Map<string,Map<string,string>>,
78
+ * evaluatorsNameCache: Map<string,Map<string,string>>,
79
+ * sharedStepsNameCache: Map<string,Map<string,string>>,
80
+ * sharedEvaluatorsNameCache: Map<string,Map<string,string>>
81
+ * }} caches
77
82
  * Resolved-name caches to avoid re-reading same modules.
78
- * @returns {{ stepImports: Array<{localName:string,stepName:string}>,
79
- * evaluatorImports: Array<{localName:string,evaluatorName:string}> }} Collected info mappings.
83
+ * @returns {{ activityImports: Array<{localName:string,activityName:string}> }} Collected import mappings.
80
84
  */
81
85
  export default function collectTargetImports(
82
86
  ast, fileDir,
83
87
  { stepsNameCache, evaluatorsNameCache, sharedStepsNameCache, sharedEvaluatorsNameCache }
84
88
  ) {
85
- const stepImports = [];
86
- const sharedStepImports = [];
87
- const evaluatorImports = [];
88
- const sharedEvaluatorImports = [];
89
+ const activityImports = [];
89
90
 
90
91
  traverse( ast, {
91
92
  ImportDeclaration: path => {
@@ -98,7 +99,7 @@ export default function collectTargetImports(
98
99
  }
99
100
 
100
101
  const absolutePath = toAbsolutePath( fileDir, src );
101
- const collectNamedImports = ( match, buildMapFn, cache, targetArr, valueKey, fileLabel ) => {
102
+ const collectNamedImports = ( match, buildMapFn, cache, fileLabel ) => {
102
103
  if ( !match ) {
103
104
  return;
104
105
  }
@@ -108,22 +109,17 @@ export default function collectTargetImports(
108
109
  const localName = s.local.name;
109
110
  const value = nameMap.get( importedName );
110
111
  if ( value ) {
111
- const entry = { localName };
112
- entry[valueKey] = value;
113
- targetArr.push( entry );
112
+ activityImports.push( { localName, activityName: value } );
114
113
  } else {
115
114
  throw unresolvedImportError( importedName, fileLabel, absolutePath );
116
115
  }
117
116
  }
118
117
  };
119
118
 
120
- collectNamedImports( isStepsPath( src ), buildStepsNameMap, stepsNameCache, stepImports, 'stepName', 'steps' );
121
- collectNamedImports( isSharedStepsPath( src ), buildSharedStepsNameMap, sharedStepsNameCache, sharedStepImports, 'stepName', 'shared steps' );
122
- collectNamedImports( isEvaluatorsPath( src ), buildEvaluatorsNameMap, evaluatorsNameCache, evaluatorImports, 'evaluatorName', 'evaluators' );
123
- collectNamedImports(
124
- isSharedEvaluatorsPath( src ), buildSharedEvaluatorsNameMap,
125
- sharedEvaluatorsNameCache, sharedEvaluatorImports, 'evaluatorName', 'shared evaluators'
126
- );
119
+ collectNamedImports( isStepsPath( src ), buildStepsNameMap, stepsNameCache, 'steps' );
120
+ collectNamedImports( isSharedStepsPath( src ), buildSharedStepsNameMap, sharedStepsNameCache, 'shared steps' );
121
+ collectNamedImports( isEvaluatorsPath( src ), buildEvaluatorsNameMap, evaluatorsNameCache, 'evaluators' );
122
+ collectNamedImports( isSharedEvaluatorsPath( src ), buildSharedEvaluatorsNameMap, sharedEvaluatorsNameCache, 'shared evaluators' );
127
123
  path.remove();
128
124
  },
129
125
  VariableDeclarator: path => {
@@ -153,25 +149,21 @@ export default function collectTargetImports(
153
149
  const cjsDescriptors = [
154
150
  {
155
151
  match: isStepsPath, buildMap: buildStepsNameMap,
156
- cache: stepsNameCache, target: stepImports,
157
- valueKey: 'stepName', label: 'steps'
152
+ cache: stepsNameCache, target: activityImports, label: 'steps'
158
153
  },
159
154
  {
160
155
  match: isSharedStepsPath, buildMap: buildSharedStepsNameMap,
161
- cache: sharedStepsNameCache ?? stepsNameCache,
162
- target: sharedStepImports,
163
- valueKey: 'stepName', label: 'shared steps'
156
+ cache: sharedStepsNameCache,
157
+ target: activityImports, label: 'shared steps'
164
158
  },
165
159
  {
166
160
  match: isEvaluatorsPath, buildMap: buildEvaluatorsNameMap,
167
- cache: evaluatorsNameCache, target: evaluatorImports,
168
- valueKey: 'evaluatorName', label: 'evaluators'
161
+ cache: evaluatorsNameCache, target: activityImports, label: 'evaluators'
169
162
  },
170
163
  {
171
164
  match: isSharedEvaluatorsPath, buildMap: buildSharedEvaluatorsNameMap,
172
- cache: sharedEvaluatorsNameCache ?? evaluatorsNameCache,
173
- target: sharedEvaluatorImports,
174
- valueKey: 'evaluatorName', label: 'shared evaluators'
165
+ cache: sharedEvaluatorsNameCache,
166
+ target: activityImports, label: 'shared evaluators'
175
167
  }
176
168
  ];
177
169
  collectDestructuredRequires(
@@ -182,5 +174,5 @@ export default function collectTargetImports(
182
174
  }
183
175
  } );
184
176
 
185
- return { stepImports, sharedStepImports, evaluatorImports, sharedEvaluatorImports };
177
+ return { activityImports };
186
178
  }