@uipath/maestro-builder-sdk 6.52.1 → 6.53.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.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The case variable a human task's form output writes when the author gives no
3
+ * `value`. Shared by the serializer, which writes the row, and the build-time
4
+ * expression check, which must count that variable as declared.
5
+ *
6
+ * @module
7
+ */
8
+ /**
9
+ * The case variable an action output writes when the author gives no `value`:
10
+ * the Designer's camelCase of the field name (`Comment` → `comment`), or the
11
+ * name itself when that leaves nothing (a name of only punctuation).
12
+ */
13
+ export declare function defaultActionOutputVar(name: string): string;
14
+ /**
15
+ * The Designer's `camelizeDisplayName`: drop non-identifier characters, split on
16
+ * spaces/underscores, lower the first letter of the first word and upper the
17
+ * first letter of the rest (`APIOutput1` → `aPIOutput1`).
18
+ */
19
+ export declare function camelizeName(name: string): string;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The case variable a human task's form output writes when the author gives no
3
+ * `value`. Shared by the serializer, which writes the row, and the build-time
4
+ * expression check, which must count that variable as declared.
5
+ *
6
+ * @module
7
+ */
8
+ /**
9
+ * The case variable an action output writes when the author gives no `value`:
10
+ * the Designer's camelCase of the field name (`Comment` → `comment`), or the
11
+ * name itself when that leaves nothing (a name of only punctuation).
12
+ */
13
+ export function defaultActionOutputVar(name) {
14
+ return camelizeName(name) || name;
15
+ }
16
+ /**
17
+ * The Designer's `camelizeDisplayName`: drop non-identifier characters, split on
18
+ * spaces/underscores, lower the first letter of the first word and upper the
19
+ * first letter of the rest (`APIOutput1` → `aPIOutput1`).
20
+ */
21
+ export function camelizeName(name) {
22
+ const words = name.replace(/[^a-zA-Z0-9_ ]/g, '').split(/[\s_]+/).filter(Boolean);
23
+ return words.map((w, i) => (i === 0 ? w.charAt(0).toLowerCase() : w.charAt(0).toUpperCase()) + w.slice(1)).join('');
24
+ }
@@ -16,6 +16,7 @@
16
16
  * `case/check.ts`, not here.
17
17
  */
18
18
  import { checkExpression } from '../core/expr-check.js';
19
+ import { defaultActionOutputVar } from './action-output-var.js';
19
20
  const NOUN = 'case variable';
20
21
  const NAMESPACE = 'vars';
21
22
  function checkExpr(expr, where, roots, out) {
@@ -44,12 +45,12 @@ export function checkCaseExpressions(built) {
44
45
  roots.add(o.var);
45
46
  // A human task's form outputs declare one too: the field's `value` is the
46
47
  // variable the assignee's answer lands in (`.action({ outputs: [{ name:
47
- // 'Action', value: 'decision' }] })` → `vars.decision`). The serializer
48
- // registers exactly that companion (`emitActionField`), so a gate on it
49
- // is a declared read, not a typo.
48
+ // 'Action', value: 'decision' }] })` → `vars.decision`). With no `value`
49
+ // the serializer writes the field's camelCased name (`approved` →
50
+ // `vars.approved`, builder-sdk#1422). Either way `emitActionField` writes
51
+ // that variable, so a gate on it is a declared read, not a typo.
50
52
  for (const f of task.action?.outputs ?? [])
51
- if (f.value)
52
- roots.add(f.value);
53
+ roots.add(f.value ?? defaultActionOutputVar(f.name));
53
54
  }
54
55
  // Event-trigger payload extractions declare readable case variables too.
55
56
  for (const t of built.triggers)
@@ -381,8 +381,13 @@ export interface BuiltCaseExitCondition {
381
381
  rules: CaseRule[][];
382
382
  }
383
383
  export type TaskKind = 'process' | 'agent' | 'rpa' | 'api-workflow' | 'case-management' | 'flow-process' | 'function' | 'business-rule' | 'external-agent' | 'external-workflow' | 'action' | 'connector' | 'wait-for-timer' | 'wait-for-connector';
384
- /** Published-resource task kinds that the Case schema permits as unresolved skeletons. */
385
- export type UnresolvedReferenceTaskKind = 'process' | 'agent' | 'rpa' | 'api-workflow' | 'case-management' | 'function';
384
+ /**
385
+ * Task kinds that the Case schema permits as unresolved skeletons: the
386
+ * published-resource kinds, and `action` (a human task whose Action App or form
387
+ * is not known yet). Each compiles to a task whose `data` is `{}`, which
388
+ * `uip maestro case validate` reports as a `TASK_NOT_CONFIGURED` warning.
389
+ */
390
+ export type UnresolvedReferenceTaskKind = 'process' | 'agent' | 'rpa' | 'api-workflow' | 'case-management' | 'function' | 'action';
386
391
  /**
387
392
  * A `wait-for-connector` subscription: suspend on an Integration Service event.
388
393
  * Omit `connectorKey`/`operation` for a bare **placeholder** (for a connector not
@@ -514,7 +519,14 @@ export interface ActionField {
514
519
  subType?: string;
515
520
  /** Human-facing label (defaults to `name` in the UI when omitted). */
516
521
  displayName?: string;
517
- /** Input literal/expression, or the readable variable name for an output field. */
522
+ /**
523
+ * Input literal/expression, or the case variable an output field writes. An
524
+ * output without `value` writes the camelCased field name, made unique across
525
+ * the plan (`Comment` → `comment`, a second `Comment` → `comment2`), as the
526
+ * Case Designer does. Set `value` on any output another step reads: the
527
+ * default suffix depends on task order, so adding an earlier task with the
528
+ * same output name would move the unsuffixed variable to that task.
529
+ */
518
530
  value?: string;
519
531
  /** Require `value` to be non-empty at validation time. */
520
532
  required?: boolean;
@@ -846,15 +858,18 @@ declare class TaskBuilder {
846
858
  folder?: string;
847
859
  }): this;
848
860
  /**
849
- * Preserve an explicitly unresolved published-resource task as a typed
850
- * skeleton whose serialized `data` is `{}`.
861
+ * Preserve an explicitly unresolved task as a typed skeleton whose serialized
862
+ * `data` is `{}`.
851
863
  *
852
864
  * @remarks
853
865
  * Use this only when the requested resource identity cannot be resolved.
854
866
  * Do not invent a name or folder. An unresolved task cannot declare input or
855
867
  * output bindings because there is no referenced contract to bind against.
868
+ * `unresolved('action')` is the human-task skeleton: no Action App, title,
869
+ * recipient or form fields, for an app that is not published yet. Use
870
+ * `.action({ ... })` instead once the form is known.
856
871
  *
857
- * @param kind - The published-resource family to preserve.
872
+ * @param kind - The task kind to preserve: a published-resource family, or `'action'` for a human task.
858
873
  * @returns This builder, so calls chain.
859
874
  */
860
875
  unresolved(kind: UnresolvedReferenceTaskKind): this;
@@ -197,15 +197,18 @@ class TaskBuilder {
197
197
  return this.reference('process', name, opts);
198
198
  }
199
199
  /**
200
- * Preserve an explicitly unresolved published-resource task as a typed
201
- * skeleton whose serialized `data` is `{}`.
200
+ * Preserve an explicitly unresolved task as a typed skeleton whose serialized
201
+ * `data` is `{}`.
202
202
  *
203
203
  * @remarks
204
204
  * Use this only when the requested resource identity cannot be resolved.
205
205
  * Do not invent a name or folder. An unresolved task cannot declare input or
206
206
  * output bindings because there is no referenced contract to bind against.
207
+ * `unresolved('action')` is the human-task skeleton: no Action App, title,
208
+ * recipient or form fields, for an app that is not published yet. Use
209
+ * `.action({ ... })` instead once the form is known.
207
210
  *
208
- * @param kind - The published-resource family to preserve.
211
+ * @param kind - The task kind to preserve: a published-resource family, or `'action'` for a human task.
209
212
  * @returns This builder, so calls chain.
210
213
  */
211
214
  unresolved(kind) {
@@ -708,6 +708,11 @@ function emitTaskKind(task, refs, library) {
708
708
  if (isAuthorableBusinessRule(task))
709
709
  return businessRuleCall(task, refs);
710
710
  if (kind === 'action') {
711
+ // The skeleton human task (v1's placeholder, validate's TASK_NOT_CONFIGURED):
712
+ // nothing configured, so `.action({})` would recompile with a default
713
+ // `priority` the source never had.
714
+ if (Object.keys(data).length === 0)
715
+ return `.unresolved(${tsLiteral('action')})`;
711
716
  let recipient;
712
717
  if (data.recipient) {
713
718
  const type = Number(data.recipient.Type);
@@ -11,6 +11,7 @@
11
11
  import { IdGen, offlineBindingSeed } from './ids.js';
12
12
  import { isUnrestorableSlotId } from './preserve.js';
13
13
  import { v31TaskSets } from './task-sets.js';
14
+ import { camelizeName, defaultActionOutputVar } from './action-output-var.js';
14
15
  import { buildConnectorInputs, nestConnectorBody, replayInputsOf, transportHttpMethod } from '../core/connector-inputs.js';
15
16
  import { buildEssentialConfiguration } from '../core/connector-configuration.js';
16
17
  import { EQUALS_EXPR_DIALECT } from '../core/connector-checks.js';
@@ -961,6 +962,11 @@ function taskData(task, resolver, taskId, stageId, ids) {
961
962
  case 'business-rule':
962
963
  return businessRuleTaskData(task, resolver, `${stageId}-${taskId}`, ids);
963
964
  case 'action': {
965
+ // `.unresolved('action')`: the skeleton human task, `data: {}` like an
966
+ // unresolved resource task (validate warns TASK_NOT_CONFIGURED). `.action()`
967
+ // always sets `task.action`, so only the skeleton reaches here without one.
968
+ if (!task.action && !task.ref)
969
+ return {};
964
970
  const a = task.action ?? {};
965
971
  const data = {};
966
972
  if (a.title)
@@ -1167,10 +1173,17 @@ function stableUuid(seed) {
1167
1173
  // extracts a result field (`source`) into a case variable (`var`), registering a
1168
1174
  // root `inputOutputs` companion (`id === var`) so `=vars.<var>` resolves.
1169
1175
  /**
1170
- * One action-task form field → a schema `InputOutput` row. Unlike reference-mode
1171
- * io-binding, most form fields carry only a name + type plus optional Action
1172
- * Center metadata. A designer output with `value` names its readable case
1173
- * variable and therefore also carries the standard output identity fields.
1176
+ * One action-task form field → a schema `InputOutput` row. Inputs carry only a
1177
+ * name + type plus optional Action Center metadata. Every OUTPUT also carries
1178
+ * the standard output identity fields (`id`, `var`, `source`, `target`,
1179
+ * `elementId`): the Designer writes them on every output it saves, and
1180
+ * `uip maestro case validate` refuses an output without an id
1181
+ * (`CASE_MGMT_OUTPUT_ID_MISSING`).
1182
+ *
1183
+ * An output's `value` names the case variable it writes. With no `value`, the
1184
+ * variable is the Designer's default: the camelCased field name, made unique
1185
+ * across the plan (`Comment` → `comment`, a second `Comment` → `comment2`), as
1186
+ * its own variable — never a reassignment of the first one.
1174
1187
  */
1175
1188
  function emitActionField(f, outputElementId, resolver) {
1176
1189
  const row = { name: f.name, type: f.type ?? 'string' };
@@ -1178,27 +1191,33 @@ function emitActionField(f, outputElementId, resolver) {
1178
1191
  row.subType = f.subType;
1179
1192
  if (f.displayName !== undefined)
1180
1193
  row.displayName = f.displayName;
1181
- if (f.value !== undefined)
1182
- row.value = f.value;
1183
- if (outputElementId !== undefined && f.value !== undefined) {
1184
- // `id == var` like the Designer; a second form output into the same case
1185
- // variable takes a suffixed id and becomes a reassigned row (`originalVar`).
1186
- const id = resolver ? claimOutputId(resolver, f.value) : f.value;
1194
+ if (outputElementId === undefined) {
1195
+ if (f.value !== undefined)
1196
+ row.value = f.value;
1197
+ }
1198
+ else {
1199
+ // An explicit `value` keeps its variable: `id == var` like the Designer, and
1200
+ // a second form output into the same case variable takes a suffixed id and
1201
+ // becomes a reassigned row (`originalVar`). A defaulted one claims its own.
1202
+ const base = f.value ?? defaultActionOutputVar(f.name);
1203
+ const id = resolver ? claimOutputId(resolver, base) : base;
1204
+ const variable = f.value ?? id;
1205
+ row.value = variable;
1187
1206
  row.id = id;
1188
- row.var = f.value;
1189
- if (id !== f.value)
1207
+ row.var = variable;
1208
+ if (id !== variable)
1190
1209
  row.originalVar = id;
1191
1210
  row.source = `=${f.name}`;
1192
1211
  row.target = `=${id}`;
1193
1212
  row.elementId = outputElementId;
1194
- // `id == value`: the row is the variable (the Designer writes no root entry
1213
+ // `id == var`: the row is the variable (the Designer writes no root entry
1195
1214
  // for it). Only a suffixed, reassigned row needs the readable companion.
1196
- if (resolver && id === f.value)
1197
- addOwnNameRow(resolver, f.value, row);
1198
- else if (resolver && !resolver.varCompanions.has(f.value)) {
1199
- resolver.varCompanions.set(f.value, {
1200
- id: f.value,
1201
- name: f.value,
1215
+ if (resolver && id === variable)
1216
+ addOwnNameRow(resolver, variable, row);
1217
+ else if (resolver && !resolver.varCompanions.has(variable)) {
1218
+ resolver.varCompanions.set(variable, {
1219
+ id: variable,
1220
+ name: variable,
1202
1221
  type: f.type ?? 'string',
1203
1222
  elementId: 'root',
1204
1223
  custom: true,
@@ -1704,8 +1723,7 @@ function ownOutputVars(built) {
1704
1723
  if (isOwnNameOutput(o))
1705
1724
  vars.add(o.var);
1706
1725
  for (const f of task.action?.outputs ?? [])
1707
- if (f.value !== undefined)
1708
- vars.add(f.value);
1726
+ vars.add(f.value ?? defaultActionOutputVar(f.name));
1709
1727
  }
1710
1728
  return vars;
1711
1729
  }
@@ -1726,15 +1744,6 @@ function keepsOwnName(name, field) {
1726
1744
  return false;
1727
1745
  return [field, camelizeName(field)].some((base) => name === base || (name.startsWith(base) && /^(?:[2-9]|[1-9]\d+)$/.test(name.slice(base.length))));
1728
1746
  }
1729
- /**
1730
- * The Designer's `camelizeDisplayName`: drop non-identifier characters, split on
1731
- * spaces/underscores, lower the first letter of the first word and upper the
1732
- * first letter of the rest (`APIOutput1` → `aPIOutput1`).
1733
- */
1734
- function camelizeName(name) {
1735
- const words = name.replace(/[^a-zA-Z0-9_ ]/g, '').split(/[\s_]+/).filter(Boolean);
1736
- return words.map((w, i) => (i === 0 ? w.charAt(0).toLowerCase() : w.charAt(0).toUpperCase()) + w.slice(1)).join('');
1737
- }
1738
1747
  /** The `Error` output's schema: the designer's (and the CLI's) `ERROR_OUTPUT_SCHEMA`. */
1739
1748
  const ERROR_OUTPUT_SCHEMA = {
1740
1749
  type: 'object',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/maestro-builder-sdk",
3
- "version": "6.52.1",
3
+ "version": "6.53.0",
4
4
  "description": "Build UiPath Flow, Case, and BPMN artifacts by writing TypeScript.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://docs.uipath.com/maestro",
@@ -96,5 +96,5 @@
96
96
  "@types/node": "^22.7.0",
97
97
  "esbuild": "^0.28.1"
98
98
  },
99
- "gitref": "d3566b616cb3addce005fe0b6962aa504adb79a3"
99
+ "gitref": "b271a259a3f380839348c118f296f9ec060f1598"
100
100
  }