@uipath/maestro-builder-sdk 6.46.4 → 6.46.5
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/dist/case/check.js +12 -12
- package/dist/case/resource-identity.d.ts +45 -0
- package/dist/case/resource-identity.js +70 -0
- package/dist/case/serialize.js +10 -5
- package/package.json +2 -2
package/dist/case/check.js
CHANGED
|
@@ -5,6 +5,7 @@ import { caseJsonPreservation, caseJsonPreservationErrors } from './preserve.js'
|
|
|
5
5
|
import { EQUALS_EXPR_DIALECT, checkBindingLabels, checkConnectorContract, checkConnectorLookups, checkConnectorSchema, } from '../core/connector-checks.js';
|
|
6
6
|
import { checkEventResolution } from '../core/event-checks.js';
|
|
7
7
|
import { EXTERNAL_TASK_DESCRIPTOR_CONTRACT } from './external.js';
|
|
8
|
+
import { isResourceLabelRefusal, resolveResourceRef } from './resource-identity.js';
|
|
8
9
|
const TYPE_NAMES = new Set(Object.values(types));
|
|
9
10
|
// audit-case-coverage: rule-slot table start
|
|
10
11
|
// This runtime table must equal the committed matrix's rejected cells. The audit
|
|
@@ -257,7 +258,7 @@ export function check(built, opts = {}) {
|
|
|
257
258
|
// positive that blocks emit (this gate runs before serialization), so it must be
|
|
258
259
|
// re-derived from the serializer rather than from remembered probe results.
|
|
259
260
|
for (const stage of built.stages) {
|
|
260
|
-
checkStage(stage, diags, refStage, refPlacement);
|
|
261
|
+
checkStage(stage, diags, refStage, refPlacement, opts.bindings);
|
|
261
262
|
stage.slaRules.forEach((s, i) => checkSla(s, `stage "${stage.label}" SLA #${i + 1}`, diags));
|
|
262
263
|
}
|
|
263
264
|
built.slaRules.forEach((s, i) => checkSla(s, `case SLA #${i + 1}`, diags));
|
|
@@ -394,7 +395,7 @@ function isNilOrEmpty(value) {
|
|
|
394
395
|
return Object.keys(value).length === 0;
|
|
395
396
|
return false;
|
|
396
397
|
}
|
|
397
|
-
function checkStage(stage, diags, refStage, refPlacement) {
|
|
398
|
+
function checkStage(stage, diags, refStage, refPlacement, bindings) {
|
|
398
399
|
const where = `stage "${stage.label}"`;
|
|
399
400
|
if (stage.exception && stage.required !== false)
|
|
400
401
|
diags.push({
|
|
@@ -484,16 +485,15 @@ function checkStage(stage, diags, refStage, refPlacement) {
|
|
|
484
485
|
where: t.name,
|
|
485
486
|
});
|
|
486
487
|
// The builder binds a resource task itself: it mints the name/folderPath
|
|
487
|
-
// binding pair from the literal name and folder. A `=bindings.<
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
});
|
|
488
|
+
// binding pair from the literal name and folder. A `=bindings.<label>` name
|
|
489
|
+
// or folder is read through bindings.json first, the way a connector's
|
|
490
|
+
// `connection:` label is; one bindings.json cannot answer is refused with the
|
|
491
|
+
// same text serialize throws (`resolveResourceRef`).
|
|
492
|
+
if (t.ref) {
|
|
493
|
+
const resolved = resolveResourceRef(t.ref, bindings, `Task "${t.name}"`);
|
|
494
|
+
if (isResourceLabelRefusal(resolved))
|
|
495
|
+
diags.push({ level: 'error', code: resolved.code, message: resolved.message, where: t.name });
|
|
496
|
+
}
|
|
497
497
|
if (t.kind === 'business-rule') {
|
|
498
498
|
if (!t.ref || !t.ref.name.trim() || !t.ref.folderPath.trim())
|
|
499
499
|
diags.push({
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* `case-validate-service.ts` exempts that prefix from its key/folder agreement
|
|
24
24
|
* check.
|
|
25
25
|
*/
|
|
26
|
+
import { type BindingsView } from '../core/binding-messages.js';
|
|
26
27
|
export declare const SOLUTION_FOLDER = "solution_folder";
|
|
27
28
|
export interface ResourceIdentity {
|
|
28
29
|
/** The `resourceKey` both rows of the name/folderPath binding pair carry. */
|
|
@@ -42,3 +43,47 @@ export interface ResourceIdentity {
|
|
|
42
43
|
export declare function resourceIdentity(name: string, folder: string): ResourceIdentity;
|
|
43
44
|
/** True for the key of a resource built inside the same solution. */
|
|
44
45
|
export declare function isInSolutionKey(resourceKey: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Why a resource task's `=bindings.<label>` name or folder cannot be resolved.
|
|
48
|
+
*
|
|
49
|
+
* - `RESOURCE_REF_IS_BINDING`: there is no bindings.json (or it declares nothing),
|
|
50
|
+
* so the label names nothing compile can read.
|
|
51
|
+
* - `RESOURCE_BINDING_UNDECLARED`: bindings.json does not declare the label, or
|
|
52
|
+
* declares it with no value.
|
|
53
|
+
*/
|
|
54
|
+
export interface ResourceLabelRefusal {
|
|
55
|
+
code: 'RESOURCE_REF_IS_BINDING' | 'RESOURCE_BINDING_UNDECLARED';
|
|
56
|
+
message: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The literal name and folder of a resource task, with any `=bindings.<label>`
|
|
60
|
+
* resolved through the project's bindings.json, the way a connector task's
|
|
61
|
+
* `connection:` label is.
|
|
62
|
+
*
|
|
63
|
+
* bindings.json { "name": "agentName", "default": "Agent" }
|
|
64
|
+
* { "name": "agentFolder", "default": "Shared/Golden" }
|
|
65
|
+
* .agent('=bindings.agentName', { folder: '=bindings.agentFolder' })
|
|
66
|
+
* -> { name: 'Agent', folderPath: 'Shared/Golden' }
|
|
67
|
+
*
|
|
68
|
+
* The task then compiles exactly as `.agent('Agent', { folder: 'Shared/Golden' })`
|
|
69
|
+
* does: compile mints the name/folderPath binding pair keyed `<folder>.<name>`.
|
|
70
|
+
* Passing the label straight through instead keyed the pair
|
|
71
|
+
* `=bindings.f.=bindings.n`, which names no resource and dangles at deploy.
|
|
72
|
+
*
|
|
73
|
+
* @param ref - The authored name and folder.
|
|
74
|
+
* @param bindings - The project's bindings.json, if any.
|
|
75
|
+
* @param where - The task, as a diagnostic names it.
|
|
76
|
+
* @returns The literal pair, or the refusal.
|
|
77
|
+
*/
|
|
78
|
+
export declare function resolveResourceRef(ref: {
|
|
79
|
+
name: string;
|
|
80
|
+
folderPath: string;
|
|
81
|
+
}, bindings: BindingsView | undefined, where: string): {
|
|
82
|
+
name: string;
|
|
83
|
+
folderPath: string;
|
|
84
|
+
} | ResourceLabelRefusal;
|
|
85
|
+
/** True when {@link resolveResourceRef} refused. */
|
|
86
|
+
export declare function isResourceLabelRefusal(r: {
|
|
87
|
+
name: string;
|
|
88
|
+
folderPath: string;
|
|
89
|
+
} | ResourceLabelRefusal): r is ResourceLabelRefusal;
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* `case-validate-service.ts` exempts that prefix from its key/folder agreement
|
|
24
24
|
* check.
|
|
25
25
|
*/
|
|
26
|
+
import { GUID_RE } from '../core/binding-messages.js';
|
|
26
27
|
export const SOLUTION_FOLDER = 'solution_folder';
|
|
27
28
|
const SOLUTION_FOLDER_KEY_PREFIX = `${SOLUTION_FOLDER}.`;
|
|
28
29
|
/**
|
|
@@ -43,3 +44,72 @@ export function resourceIdentity(name, folder) {
|
|
|
43
44
|
export function isInSolutionKey(resourceKey) {
|
|
44
45
|
return resourceKey.startsWith(SOLUTION_FOLDER_KEY_PREFIX);
|
|
45
46
|
}
|
|
47
|
+
/** How a resource task's name or folder spells a bindings.json label. */
|
|
48
|
+
const BINDING_LABEL_PREFIX = '=bindings.';
|
|
49
|
+
/** The literal value bindings.json declares for `label`, or `undefined`. */
|
|
50
|
+
function declaredValue(bindings, label) {
|
|
51
|
+
const entry = bindings?.entry?.(label);
|
|
52
|
+
// `default` is the value a person reads (the resource's name, the folder
|
|
53
|
+
// path); `resourceKey` can be the resource's GUID. A map-form bindings.json
|
|
54
|
+
// puts the value in both. A GUID-shaped `resourceKey` is never a name or a
|
|
55
|
+
// folder: taking it would key the pair `<folder>.<guid>`, which dangles at
|
|
56
|
+
// deploy, so the label falls through to RESOURCE_BINDING_UNDECLARED.
|
|
57
|
+
const fallback = typeof entry?.resourceKey === 'string' && GUID_RE.test(entry.resourceKey.trim()) ? undefined : entry?.resourceKey;
|
|
58
|
+
const value = entry ? (entry.default ?? fallback) : bindings?.resolve(label);
|
|
59
|
+
return typeof value === 'string' && value.trim() && !value.trim().startsWith(BINDING_LABEL_PREFIX)
|
|
60
|
+
? value
|
|
61
|
+
: undefined;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The literal name and folder of a resource task, with any `=bindings.<label>`
|
|
65
|
+
* resolved through the project's bindings.json, the way a connector task's
|
|
66
|
+
* `connection:` label is.
|
|
67
|
+
*
|
|
68
|
+
* bindings.json { "name": "agentName", "default": "Agent" }
|
|
69
|
+
* { "name": "agentFolder", "default": "Shared/Golden" }
|
|
70
|
+
* .agent('=bindings.agentName', { folder: '=bindings.agentFolder' })
|
|
71
|
+
* -> { name: 'Agent', folderPath: 'Shared/Golden' }
|
|
72
|
+
*
|
|
73
|
+
* The task then compiles exactly as `.agent('Agent', { folder: 'Shared/Golden' })`
|
|
74
|
+
* does: compile mints the name/folderPath binding pair keyed `<folder>.<name>`.
|
|
75
|
+
* Passing the label straight through instead keyed the pair
|
|
76
|
+
* `=bindings.f.=bindings.n`, which names no resource and dangles at deploy.
|
|
77
|
+
*
|
|
78
|
+
* @param ref - The authored name and folder.
|
|
79
|
+
* @param bindings - The project's bindings.json, if any.
|
|
80
|
+
* @param where - The task, as a diagnostic names it.
|
|
81
|
+
* @returns The literal pair, or the refusal.
|
|
82
|
+
*/
|
|
83
|
+
export function resolveResourceRef(ref, bindings, where) {
|
|
84
|
+
const out = { name: ref.name, folderPath: ref.folderPath };
|
|
85
|
+
for (const attribute of ['name', 'folderPath']) {
|
|
86
|
+
const authored = ref[attribute].trim();
|
|
87
|
+
if (!authored.startsWith(BINDING_LABEL_PREFIX))
|
|
88
|
+
continue;
|
|
89
|
+
const label = authored.slice(BINDING_LABEL_PREFIX.length);
|
|
90
|
+
const what = attribute === 'name' ? 'resource name' : 'folder';
|
|
91
|
+
const literal = `e.g. .agent('Contract Analysis', { folder: 'Shared/Legal' })`;
|
|
92
|
+
const declared = bindings?.declared?.() ?? [];
|
|
93
|
+
if (declared.length === 0)
|
|
94
|
+
return {
|
|
95
|
+
code: 'RESOURCE_REF_IS_BINDING',
|
|
96
|
+
message: `${where} passes "${authored}" as its ${what}, and there is no bindings.json declaring "${label}". `
|
|
97
|
+
+ `Declare it in bindings.json ({ "name": "${label}", "default": "<the ${what}>" }), or pass the ${what} itself, ${literal}; `
|
|
98
|
+
+ `compile writes the name/folderPath binding pair keyed '<folder>.<name>' and points the task at it.`,
|
|
99
|
+
};
|
|
100
|
+
const value = declaredValue(bindings, label);
|
|
101
|
+
if (value === undefined)
|
|
102
|
+
return {
|
|
103
|
+
code: 'RESOURCE_BINDING_UNDECLARED',
|
|
104
|
+
message: `${where} passes "${authored}" as its ${what}, but bindings.json does not declare "${label}" with a value `
|
|
105
|
+
+ `(it declares: ${declared.join(', ')}). Use one of those labels, add "${label}" with its ${what} as "default", `
|
|
106
|
+
+ `or pass the ${what} itself, ${literal}.`,
|
|
107
|
+
};
|
|
108
|
+
out[attribute] = value;
|
|
109
|
+
}
|
|
110
|
+
return out;
|
|
111
|
+
}
|
|
112
|
+
/** True when {@link resolveResourceRef} refused. */
|
|
113
|
+
export function isResourceLabelRefusal(r) {
|
|
114
|
+
return 'code' in r;
|
|
115
|
+
}
|
package/dist/case/serialize.js
CHANGED
|
@@ -18,7 +18,7 @@ import { resolveEventWhere } from '../core/lookups.js';
|
|
|
18
18
|
import { resolveCaseSubscription } from './subscription.js';
|
|
19
19
|
import { externalDescriptorRefusal } from './external.js';
|
|
20
20
|
import { CASE_FORMAT_PROFILE, CASE_SCHEMA_VERSIONS } from './format-profile.js';
|
|
21
|
-
import { resourceIdentity } from './resource-identity.js';
|
|
21
|
+
import { isResourceLabelRefusal, resolveResourceRef, resourceIdentity } from './resource-identity.js';
|
|
22
22
|
import { ownEntry } from '../core/own-entry.js';
|
|
23
23
|
import { resolveSchemaVersion } from '../schema-version.js';
|
|
24
24
|
import { caseJsonPreservation, caseJsonPreservationErrors, } from './preserve.js';
|
|
@@ -914,7 +914,7 @@ function taskData(task, resolver, taskId, stageId, ids) {
|
|
|
914
914
|
// never literals: `validate` refuses a literal (CASE_MGMT_RESOURCE_TASK_
|
|
915
915
|
// LITERAL_BINDING), and deploy re-targets a resource only through its
|
|
916
916
|
// binding (#1240).
|
|
917
|
-
const { nameRef, folderRef } = referenceBindings(task.kind, task.ref, resolver, ids);
|
|
917
|
+
const { nameRef, folderRef } = referenceBindings(task.kind, task.ref, resolver, ids, task.name);
|
|
918
918
|
const data = { name: nameRef, folderPath: folderRef };
|
|
919
919
|
const elementId = `${stageId}-${taskId}`;
|
|
920
920
|
if (task.inputs?.length)
|
|
@@ -940,7 +940,7 @@ function taskData(task, resolver, taskId, stageId, ids) {
|
|
|
940
940
|
// The Action App the task opens, bound like any resource: an `app`
|
|
941
941
|
// name/folderPath pair keyed `<deployment folder>.<app>` (#1240).
|
|
942
942
|
if (task.ref) {
|
|
943
|
-
const { nameRef, folderRef } = referenceBindings('action', task.ref, resolver, ids);
|
|
943
|
+
const { nameRef, folderRef } = referenceBindings('action', task.ref, resolver, ids, task.name);
|
|
944
944
|
data.name = nameRef;
|
|
945
945
|
data.folderPath = folderRef;
|
|
946
946
|
}
|
|
@@ -1278,7 +1278,12 @@ function resourceBinding(resolver, ids, binding, resourceKey, propertyAttribute,
|
|
|
1278
1278
|
/** The binding `resource` an action task's Action App is bound by (no subtype). */
|
|
1279
1279
|
const ACTION_APP_RESOURCE = 'app';
|
|
1280
1280
|
/** The `=bindings.<id>` name/folderPath references of a published-resource task. */
|
|
1281
|
-
function referenceBindings(kind,
|
|
1281
|
+
function referenceBindings(kind, authored, resolver, ids, taskName) {
|
|
1282
|
+
// A `=bindings.<label>` name or folder reads through bindings.json to its
|
|
1283
|
+
// literal value, so the task binds exactly as the literal form does.
|
|
1284
|
+
const ref = resolveResourceRef(authored, resolver.bindings, `Task "${taskName}"`);
|
|
1285
|
+
if (isResourceLabelRefusal(ref))
|
|
1286
|
+
throw new Error(`[${ref.code}] ${ref.message}`);
|
|
1282
1287
|
const binding = kind === 'business-rule'
|
|
1283
1288
|
? { resource: BUSINESS_RULE_RESOURCE }
|
|
1284
1289
|
: kind === 'action'
|
|
@@ -1308,7 +1313,7 @@ function referenceBindings(kind, ref, resolver, ids) {
|
|
|
1308
1313
|
* (`=<Decision>.<column>`).
|
|
1309
1314
|
*/
|
|
1310
1315
|
function businessRuleTaskData(task, resolver, elementId, ids) {
|
|
1311
|
-
const { nameRef, folderRef } = referenceBindings(task.kind, task.ref, resolver, ids);
|
|
1316
|
+
const { nameRef, folderRef } = referenceBindings(task.kind, task.ref, resolver, ids, task.name);
|
|
1312
1317
|
const ownRow = (name, source, seed, extra = {}) => {
|
|
1313
1318
|
const slot = ids.make('v', 8, `${elementId}:${seed}`);
|
|
1314
1319
|
return { name, type: 'jsonSchema', id: slot, var: slot, value: slot, source, target: `=${slot}`, elementId, ...extra };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/maestro-builder-sdk",
|
|
3
|
-
"version": "6.46.
|
|
3
|
+
"version": "6.46.5",
|
|
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",
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"@types/node": "^22.7.0",
|
|
94
94
|
"esbuild": "^0.28.1"
|
|
95
95
|
},
|
|
96
|
-
"gitref": "
|
|
96
|
+
"gitref": "0edb50d70d9787a64a6c66ce37b5e1eed45d2a0d"
|
|
97
97
|
}
|