@uipath/maestro-builder-sdk 6.26.0 → 6.27.1
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/api-index.md +22 -21
- package/dist/api-members.md +87 -86
- package/dist/check.js +47 -5
- package/dist/cli/commands/bpmn.js +6 -6
- package/dist/cli/commands/case.js +5 -5
- package/dist/cli/commands/flow.js +5 -5
- package/dist/cli/commands/registry.js +7 -7
- package/dist/cli/common.d.ts +0 -3
- package/dist/cli/common.js +3 -3
- package/dist/cli-run.js +10 -0
- package/dist/core/sha.d.ts +16 -0
- package/dist/core/sha.js +118 -0
- package/dist/core/stable-id.js +5 -6
- package/dist/decompile.js +35 -45
- package/dist/flow-definitions.js +2 -4
- package/dist/flow-expr-check.js +6 -1
- package/dist/flow-sdk.d.ts +43 -12
- package/dist/flow-sdk.js +25 -6
- package/dist/sdk-resolve.d.ts +5 -3
- package/dist/sdk-resolve.js +15 -6
- package/dist/serialize.js +8 -7
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { addValue, inferCheckMode, invoke,
|
|
1
|
+
import { addValue, inferCheckMode, invoke, namedOrLegacySecond, retiredCompiledOption, refuse } from '../common.js';
|
|
2
2
|
export function registerBpmnCommands(program) {
|
|
3
3
|
const family = program.command('bpmn').description('Build, inspect, and merge BPMN artifacts.');
|
|
4
4
|
family.command('compile')
|
|
@@ -18,7 +18,7 @@ export function registerBpmnCommands(program) {
|
|
|
18
18
|
addValue(argv, '--library', options.library);
|
|
19
19
|
addValue(argv, '--bindings', options.bindings);
|
|
20
20
|
addValue(argv, '--connectors-local', options.connectorsLocal);
|
|
21
|
-
await invoke('bpmn compile', () =>
|
|
21
|
+
await invoke('bpmn compile', () => import('../../bpmn/compile-cli.js'), argv);
|
|
22
22
|
});
|
|
23
23
|
family.command('check')
|
|
24
24
|
.description('Check authored TypeScript. Check a .bpmn with `uip maestro bpmn validate`.')
|
|
@@ -51,7 +51,7 @@ export function registerBpmnCommands(program) {
|
|
|
51
51
|
addValue(argv, '--library', options.library);
|
|
52
52
|
addValue(argv, '--connectors-local', options.connectorsLocal);
|
|
53
53
|
addValue(argv, '--bindings', options.bindings);
|
|
54
|
-
await invoke('bpmn check', () =>
|
|
54
|
+
await invoke('bpmn check', () => import('../../bpmn/check-cli.js'), argv);
|
|
55
55
|
});
|
|
56
56
|
family.command('tidy')
|
|
57
57
|
.description('Add diagram layout to a compiled .bpmn artifact.')
|
|
@@ -60,7 +60,7 @@ export function registerBpmnCommands(program) {
|
|
|
60
60
|
.action(async (input, options) => {
|
|
61
61
|
const argv = [input];
|
|
62
62
|
addValue(argv, '-o', options.output);
|
|
63
|
-
await invoke('bpmn tidy', () =>
|
|
63
|
+
await invoke('bpmn tidy', () => import('../../bpmn/tidy-cli.js'), argv);
|
|
64
64
|
});
|
|
65
65
|
family
|
|
66
66
|
.command('decompile')
|
|
@@ -74,7 +74,7 @@ export function registerBpmnCommands(program) {
|
|
|
74
74
|
addValue(argv, '-o', options.output);
|
|
75
75
|
addValue(argv, '--import', options.import);
|
|
76
76
|
addValue(argv, '--style', options.style);
|
|
77
|
-
await invoke('bpmn decompile', () =>
|
|
77
|
+
await invoke('bpmn decompile', () => import('../../bpmn/decompile-cli.js'), argv);
|
|
78
78
|
});
|
|
79
79
|
family
|
|
80
80
|
.command('merge')
|
|
@@ -95,6 +95,6 @@ export function registerBpmnCommands(program) {
|
|
|
95
95
|
const argv = [original, edited];
|
|
96
96
|
addValue(argv, '-o', options.output);
|
|
97
97
|
addValue(argv, '--baseline', options.baseline);
|
|
98
|
-
await invoke('bpmn merge', () =>
|
|
98
|
+
await invoke('bpmn merge', () => import('../../bpmn/merge-cli.js'), argv);
|
|
99
99
|
});
|
|
100
100
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { addValue, inferCheckMode, invoke,
|
|
1
|
+
import { addValue, inferCheckMode, invoke, namedOrLegacySecond, retiredCompiledOption, refuse } from '../common.js';
|
|
2
2
|
export function registerCaseCommands(program) {
|
|
3
3
|
const family = program.command('case').description('Build, check, and merge Case artifacts.');
|
|
4
4
|
family.command('compile')
|
|
@@ -14,7 +14,7 @@ export function registerCaseCommands(program) {
|
|
|
14
14
|
addValue(argv, '--library', options.library);
|
|
15
15
|
addValue(argv, '--bindings', options.bindings);
|
|
16
16
|
addValue(argv, '--connectors-local', options.connectorsLocal);
|
|
17
|
-
await invoke('case compile', () =>
|
|
17
|
+
await invoke('case compile', () => import('../../case/compile-cli.js'), argv);
|
|
18
18
|
});
|
|
19
19
|
family.command('check')
|
|
20
20
|
.description('Check authored TypeScript. Check a caseplan.json with `uip maestro case validate`.')
|
|
@@ -45,7 +45,7 @@ export function registerCaseCommands(program) {
|
|
|
45
45
|
addValue(argv, '--library', options.library);
|
|
46
46
|
addValue(argv, '--connectors-local', options.connectorsLocal);
|
|
47
47
|
addValue(argv, '--bindings', options.bindings);
|
|
48
|
-
await invoke('case check', () =>
|
|
48
|
+
await invoke('case check', () => import('../../case/check-cli.js'), argv);
|
|
49
49
|
});
|
|
50
50
|
family.command('decompile')
|
|
51
51
|
.description('Convert a caseplan.json to authored TypeScript.')
|
|
@@ -64,7 +64,7 @@ export function registerCaseCommands(program) {
|
|
|
64
64
|
argv.push('--best-effort');
|
|
65
65
|
if (options.pipeline === false)
|
|
66
66
|
argv.push('--no-pipeline');
|
|
67
|
-
await invoke('case decompile', () =>
|
|
67
|
+
await invoke('case decompile', () => import('../../case/decompile-cli.js'), argv);
|
|
68
68
|
});
|
|
69
69
|
family.command('merge')
|
|
70
70
|
.description('Merge an edited case plan with its original caseplan.json.')
|
|
@@ -82,6 +82,6 @@ export function registerCaseCommands(program) {
|
|
|
82
82
|
const [edited, original] = pair;
|
|
83
83
|
const argv = [original, edited];
|
|
84
84
|
addValue(argv, '-o', options.output);
|
|
85
|
-
await invoke('case merge', () =>
|
|
85
|
+
await invoke('case merge', () => import('../../case/merge-cli.js'), argv);
|
|
86
86
|
});
|
|
87
87
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Option } from 'commander';
|
|
2
|
-
import { addValue, emitOnlyEnabled, inferCheckMode, invoke,
|
|
2
|
+
import { addValue, emitOnlyEnabled, inferCheckMode, invoke, namedOrLegacySecond, retiredCompiledOption, refuse } from '../common.js';
|
|
3
3
|
/** The retired compiled check's flags: `[commander flags, option key, description]`. One table, so hiding and warning cannot drift. */
|
|
4
4
|
const RETIRED_COMPILED_CHECK_FLAGS = [
|
|
5
5
|
['--uip', 'uip', 'retired: resolve missing schemas with the UiPath CLI'],
|
|
@@ -32,7 +32,7 @@ export function registerFlowCommands(program) {
|
|
|
32
32
|
addValue(argv, '--connectors-local', options.connectorsLocal);
|
|
33
33
|
if (options.check === false || emitOnlyEnabled())
|
|
34
34
|
argv.push('--no-check');
|
|
35
|
-
await invoke('flow compile', () =>
|
|
35
|
+
await invoke('flow compile', () => import('../../compile-cli.js'), argv);
|
|
36
36
|
});
|
|
37
37
|
const check = flow.command('check')
|
|
38
38
|
.description('Check authored TypeScript. Check a compiled .flow with `uip maestro flow validate`.')
|
|
@@ -69,7 +69,7 @@ export function registerFlowCommands(program) {
|
|
|
69
69
|
const argv = [input];
|
|
70
70
|
addValue(argv, '--library', options.library);
|
|
71
71
|
addValue(argv, '--connectors-local', options.connectorsLocal);
|
|
72
|
-
await invoke('flow check', () =>
|
|
72
|
+
await invoke('flow check', () => import('../../check-cli.js'), argv);
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
75
|
// The COMPILED-artifact analyser is gone: it was a standalone tool bundled into this
|
|
@@ -100,7 +100,7 @@ export function registerFlowCommands(program) {
|
|
|
100
100
|
argv.push('--strict');
|
|
101
101
|
if (options.pipeline === false)
|
|
102
102
|
argv.push('--no-pipeline');
|
|
103
|
-
await invoke('flow decompile', () =>
|
|
103
|
+
await invoke('flow decompile', () => import('../../decompile-cli.js'), argv);
|
|
104
104
|
});
|
|
105
105
|
flow.command('merge')
|
|
106
106
|
.description('Merge an edited flow with its original artifact.')
|
|
@@ -123,6 +123,6 @@ export function registerFlowCommands(program) {
|
|
|
123
123
|
addValue(argv, '--baseline', options.baseline);
|
|
124
124
|
if (options.strict)
|
|
125
125
|
argv.push('--strict');
|
|
126
|
-
await invoke('flow merge', () =>
|
|
126
|
+
await invoke('flow merge', () => import('../../merge-cli.js'), argv);
|
|
127
127
|
});
|
|
128
128
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { addValue, invoke,
|
|
1
|
+
import { addValue, invoke, namedOrLegacySecond } from '../common.js';
|
|
2
2
|
/** Commander hands a repeatable option one value at a time. */
|
|
3
3
|
function collect(value, previous) {
|
|
4
4
|
return [...previous, value];
|
|
@@ -49,7 +49,7 @@ export function registerRegistryCommands(program) {
|
|
|
49
49
|
addValue(argv, '--root', options.root);
|
|
50
50
|
addValue(argv, '--extractor', options.extractor);
|
|
51
51
|
addValue(argv, '--generator', options.generator);
|
|
52
|
-
await invoke('registry pull', () =>
|
|
52
|
+
await invoke('registry pull', () => import('../../registry/pull-cli.js'), argv);
|
|
53
53
|
});
|
|
54
54
|
family.command('materialize')
|
|
55
55
|
.description('Generate library-md and connectors/ from an extracted library-json.')
|
|
@@ -80,7 +80,7 @@ export function registerRegistryCommands(program) {
|
|
|
80
80
|
argv.push('--check-orphans');
|
|
81
81
|
addValue(argv, '--python', options.python);
|
|
82
82
|
addValue(argv, '--generator', options.generator);
|
|
83
|
-
await invoke('registry materialize', () =>
|
|
83
|
+
await invoke('registry materialize', () => import('../../registry/materialize-cli.js'), argv);
|
|
84
84
|
});
|
|
85
85
|
// The pipeline's generator, `generate_library_json.py`, flag for flag: the
|
|
86
86
|
// Azure YAML that calls it should only have to swap the executable.
|
|
@@ -119,7 +119,7 @@ export function registerRegistryCommands(program) {
|
|
|
119
119
|
addValue(argv, '--connectors', options.connectors);
|
|
120
120
|
addValue(argv, '--catalog-scope', options.catalogScope);
|
|
121
121
|
addValue(argv, '--concurrency', options.concurrency);
|
|
122
|
-
await invoke('registry build-library', () =>
|
|
122
|
+
await invoke('registry build-library', () => import('../../registry/library-build/cli.js'), argv);
|
|
123
123
|
});
|
|
124
124
|
family.command('prepare')
|
|
125
125
|
.description("Resolve one operation's schema against a live connection into ./.flow-sdk/connectors-local.")
|
|
@@ -200,7 +200,7 @@ export function registerRegistryCommands(program) {
|
|
|
200
200
|
argv.push('--no-source-rewrite');
|
|
201
201
|
addValue(argv, '--python', options.python);
|
|
202
202
|
addValue(argv, '--generator', options.generator);
|
|
203
|
-
await invoke('registry prepare', () =>
|
|
203
|
+
await invoke('registry prepare', () => import('../../registry/prepare-cli.js'), argv);
|
|
204
204
|
});
|
|
205
205
|
family.command('path')
|
|
206
206
|
.description('Print where the cached connector library is.')
|
|
@@ -216,7 +216,7 @@ export function registerRegistryCommands(program) {
|
|
|
216
216
|
if (options[key])
|
|
217
217
|
argv.push(`--${flag}`);
|
|
218
218
|
}
|
|
219
|
-
await invoke('registry path', () =>
|
|
219
|
+
await invoke('registry path', () => import('../../registry/path-cli.js'), argv);
|
|
220
220
|
});
|
|
221
221
|
family.command('search')
|
|
222
222
|
.description('Find connector operations in an extracted library.')
|
|
@@ -231,6 +231,6 @@ export function registerRegistryCommands(program) {
|
|
|
231
231
|
addValue(argv, '--library-md', options.libraryMd);
|
|
232
232
|
addValue(argv, '--connector', options.connector);
|
|
233
233
|
addValue(argv, '--limit', options.limit);
|
|
234
|
-
await invoke('registry search', () =>
|
|
234
|
+
await invoke('registry search', () => import('../../registry/search-cli.js'), argv);
|
|
235
235
|
});
|
|
236
236
|
}
|
package/dist/cli/common.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { type Command, Option } from 'commander';
|
|
2
2
|
export type ToolRun = (argv: string[]) => Promise<number> | number;
|
|
3
|
-
export declare function loadTool(baseUrl: string, relativePath: string): Promise<{
|
|
4
|
-
run: ToolRun;
|
|
5
|
-
}>;
|
|
6
3
|
export declare function invoke(label: string, load: () => Promise<{
|
|
7
4
|
run: ToolRun;
|
|
8
5
|
}>, argv: string[]): Promise<void>;
|
package/dist/cli/common.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join, resolve } from 'node:path';
|
|
3
3
|
import { Option } from 'commander';
|
|
4
|
-
export function loadTool(baseUrl, relativePath) {
|
|
5
|
-
return import(new URL(relativePath, baseUrl).href);
|
|
6
|
-
}
|
|
7
4
|
export async function invoke(label, load, argv) {
|
|
8
5
|
// In `--json` mode stdout carries exactly one JSON object, printed by
|
|
9
6
|
// `emitJsonResult` once the verb is done. The tool's own human lines go to
|
|
10
7
|
// stderr meanwhile, so they are still seen but never mixed into it.
|
|
11
8
|
const restore = jsonResultRequested() ? routeStdoutToStderr() : () => { };
|
|
9
|
+
globalThis[HOSTED_BY_CLI] = true;
|
|
12
10
|
try {
|
|
13
11
|
const code = await (await load()).run(argv);
|
|
14
12
|
if (code !== 0)
|
|
@@ -24,6 +22,8 @@ export async function invoke(label, load, argv) {
|
|
|
24
22
|
restore();
|
|
25
23
|
}
|
|
26
24
|
}
|
|
25
|
+
/** Tells `runWhenInvokedDirectly` (`src/cli-run.ts`) the tool is run by this CLI. */
|
|
26
|
+
const HOSTED_BY_CLI = Symbol.for('uipath.maestro-builder-sdk.cli-hosted');
|
|
27
27
|
/**
|
|
28
28
|
* The slot `src/cli-result.ts` writes (`reportResult`). Read here through the
|
|
29
29
|
* same `Symbol.for` key, since `dist/cli/` and `dist/` are separate builds.
|
package/dist/cli-run.js
CHANGED
|
@@ -14,7 +14,17 @@ function realOrAbsolute(path) {
|
|
|
14
14
|
return resolve(path);
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Set by the `flow-sdk` CLI before it imports a tool (`cli/common.ts`, read
|
|
19
|
+
* through the same `Symbol.for` key since `dist/cli/` is a separate build). A
|
|
20
|
+
* bundle gives every module the bundle's own `import.meta.url`, which matches
|
|
21
|
+
* `process.argv[1]` for whichever tool the CLI loads; without this the tool
|
|
22
|
+
* would run a second time, on the CLI's argv.
|
|
23
|
+
*/
|
|
24
|
+
const HOSTED_BY_CLI = Symbol.for('uipath.maestro-builder-sdk.cli-hosted');
|
|
17
25
|
export function runWhenInvokedDirectly(moduleUrl, label, run) {
|
|
26
|
+
if (globalThis[HOSTED_BY_CLI])
|
|
27
|
+
return;
|
|
18
28
|
const entry = process.argv[1];
|
|
19
29
|
if (!entry)
|
|
20
30
|
return;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHA-1 and SHA-256 of a string's UTF-8 bytes, in plain JavaScript.
|
|
3
|
+
*
|
|
4
|
+
* The ids built from them (`schemaId` in `serialize.ts`, `sha256Uuid` in
|
|
5
|
+
* `stable-id.ts`) are computed synchronously while a flow serializes, and must be
|
|
6
|
+
* byte-for-byte what `node:crypto` gives, since they are already in shipped
|
|
7
|
+
* artifacts. Owning the digest here keeps the authoring path free of `node:`
|
|
8
|
+
* imports, so a host without Node (a browser sandbox) runs it unshimmed; the
|
|
9
|
+
* browser's own `crypto.subtle.digest` is async-only. `tests/sha.test.ts` checks
|
|
10
|
+
* both against `node:crypto`. They derive ids, nothing secret: not for passwords,
|
|
11
|
+
* signatures or integrity checks.
|
|
12
|
+
*/
|
|
13
|
+
export declare function sha1(text: string): Uint8Array;
|
|
14
|
+
export declare function sha256(text: string): Uint8Array;
|
|
15
|
+
/** Lowercase hex of `bytes`, as `digest('hex')` writes it. */
|
|
16
|
+
export declare function bytesToHex(bytes: Uint8Array): string;
|
package/dist/core/sha.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHA-1 and SHA-256 of a string's UTF-8 bytes, in plain JavaScript.
|
|
3
|
+
*
|
|
4
|
+
* The ids built from them (`schemaId` in `serialize.ts`, `sha256Uuid` in
|
|
5
|
+
* `stable-id.ts`) are computed synchronously while a flow serializes, and must be
|
|
6
|
+
* byte-for-byte what `node:crypto` gives, since they are already in shipped
|
|
7
|
+
* artifacts. Owning the digest here keeps the authoring path free of `node:`
|
|
8
|
+
* imports, so a host without Node (a browser sandbox) runs it unshimmed; the
|
|
9
|
+
* browser's own `crypto.subtle.digest` is async-only. `tests/sha.test.ts` checks
|
|
10
|
+
* both against `node:crypto`. They derive ids, nothing secret: not for passwords,
|
|
11
|
+
* signatures or integrity checks.
|
|
12
|
+
*/
|
|
13
|
+
function utf8(text) {
|
|
14
|
+
return new TextEncoder().encode(text);
|
|
15
|
+
}
|
|
16
|
+
/** The message padded to a multiple of 64 bytes, with its bit length in the last 8, big-endian. */
|
|
17
|
+
function padded(message) {
|
|
18
|
+
const length = Math.ceil((message.length + 9) / 64) * 64;
|
|
19
|
+
const bytes = new Uint8Array(length);
|
|
20
|
+
bytes.set(message);
|
|
21
|
+
bytes[message.length] = 0x80;
|
|
22
|
+
const view = new DataView(bytes.buffer);
|
|
23
|
+
const bits = message.length * 8;
|
|
24
|
+
view.setUint32(length - 8, Math.floor(bits / 0x100000000));
|
|
25
|
+
view.setUint32(length - 4, bits >>> 0);
|
|
26
|
+
return view;
|
|
27
|
+
}
|
|
28
|
+
function digest(words) {
|
|
29
|
+
const out = new Uint8Array(words.length * 4);
|
|
30
|
+
const view = new DataView(out.buffer);
|
|
31
|
+
words.forEach((word, i) => view.setUint32(i * 4, word));
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
const rotl = (x, n) => (x << n) | (x >>> (32 - n));
|
|
35
|
+
const rotr = (x, n) => (x >>> n) | (x << (32 - n));
|
|
36
|
+
export function sha1(text) {
|
|
37
|
+
const view = padded(utf8(text));
|
|
38
|
+
const h = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
|
|
39
|
+
const w = new Array(80);
|
|
40
|
+
for (let block = 0; block < view.byteLength; block += 64) {
|
|
41
|
+
for (let i = 0; i < 16; i++)
|
|
42
|
+
w[i] = view.getUint32(block + i * 4);
|
|
43
|
+
for (let i = 16; i < 80; i++)
|
|
44
|
+
w[i] = rotl(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
|
|
45
|
+
let [a, b, c, d, e] = h;
|
|
46
|
+
for (let i = 0; i < 80; i++) {
|
|
47
|
+
const [f, k] = i < 20 ? [(b & c) | (~b & d), 0x5a827999]
|
|
48
|
+
: i < 40 ? [b ^ c ^ d, 0x6ed9eba1]
|
|
49
|
+
: i < 60 ? [(b & c) | (b & d) | (c & d), 0x8f1bbcdc]
|
|
50
|
+
: [b ^ c ^ d, 0xca62c1d6];
|
|
51
|
+
const t = (rotl(a, 5) + f + e + k + w[i]) | 0;
|
|
52
|
+
e = d;
|
|
53
|
+
d = c;
|
|
54
|
+
c = rotl(b, 30);
|
|
55
|
+
b = a;
|
|
56
|
+
a = t;
|
|
57
|
+
}
|
|
58
|
+
h[0] = (h[0] + a) | 0;
|
|
59
|
+
h[1] = (h[1] + b) | 0;
|
|
60
|
+
h[2] = (h[2] + c) | 0;
|
|
61
|
+
h[3] = (h[3] + d) | 0;
|
|
62
|
+
h[4] = (h[4] + e) | 0;
|
|
63
|
+
}
|
|
64
|
+
return digest(h);
|
|
65
|
+
}
|
|
66
|
+
const K256 = [
|
|
67
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
68
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
69
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
70
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
71
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
72
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
73
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
74
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
75
|
+
];
|
|
76
|
+
export function sha256(text) {
|
|
77
|
+
const view = padded(utf8(text));
|
|
78
|
+
const h = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19];
|
|
79
|
+
const w = new Array(64);
|
|
80
|
+
for (let block = 0; block < view.byteLength; block += 64) {
|
|
81
|
+
for (let i = 0; i < 16; i++)
|
|
82
|
+
w[i] = view.getUint32(block + i * 4);
|
|
83
|
+
for (let i = 16; i < 64; i++) {
|
|
84
|
+
const s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >>> 3);
|
|
85
|
+
const s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >>> 10);
|
|
86
|
+
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) | 0;
|
|
87
|
+
}
|
|
88
|
+
let [a, b, c, d, e, f, g, hh] = h;
|
|
89
|
+
for (let i = 0; i < 64; i++) {
|
|
90
|
+
const t1 = (hh + (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) + ((e & f) ^ (~e & g)) + K256[i] + w[i]) | 0;
|
|
91
|
+
const t2 = ((rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) + ((a & b) ^ (a & c) ^ (b & c))) | 0;
|
|
92
|
+
hh = g;
|
|
93
|
+
g = f;
|
|
94
|
+
f = e;
|
|
95
|
+
e = (d + t1) | 0;
|
|
96
|
+
d = c;
|
|
97
|
+
c = b;
|
|
98
|
+
b = a;
|
|
99
|
+
a = (t1 + t2) | 0;
|
|
100
|
+
}
|
|
101
|
+
h[0] = (h[0] + a) | 0;
|
|
102
|
+
h[1] = (h[1] + b) | 0;
|
|
103
|
+
h[2] = (h[2] + c) | 0;
|
|
104
|
+
h[3] = (h[3] + d) | 0;
|
|
105
|
+
h[4] = (h[4] + e) | 0;
|
|
106
|
+
h[5] = (h[5] + f) | 0;
|
|
107
|
+
h[6] = (h[6] + g) | 0;
|
|
108
|
+
h[7] = (h[7] + hh) | 0;
|
|
109
|
+
}
|
|
110
|
+
return digest(h);
|
|
111
|
+
}
|
|
112
|
+
/** Lowercase hex of `bytes`, as `digest('hex')` writes it. */
|
|
113
|
+
export function bytesToHex(bytes) {
|
|
114
|
+
let out = '';
|
|
115
|
+
for (const byte of bytes)
|
|
116
|
+
out += byte.toString(16).padStart(2, '0');
|
|
117
|
+
return out;
|
|
118
|
+
}
|
package/dist/core/stable-id.js
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* site uses; `tests/cli.test.ts` pins the Case entry point's `uniqueId`. Change one
|
|
37
37
|
* only deliberately, updating that table and any byte-lock fixture it moves.
|
|
38
38
|
*/
|
|
39
|
-
import {
|
|
39
|
+
import { bytesToHex, sha1, sha256 } from './sha.js';
|
|
40
40
|
/** A uuid-shaped id derived from `seed`. Every segment is unsigned, including the `>>> 0` fix explained above. */
|
|
41
41
|
export function stableId(seed) {
|
|
42
42
|
let h1 = 0x811c9dc5;
|
|
@@ -88,7 +88,7 @@ export function fnv1aX4Uuid(seed) {
|
|
|
88
88
|
* Consumer: a Case entry point's `uniqueId` in `entry-points.json` (`case/compile-cli.ts`).
|
|
89
89
|
*/
|
|
90
90
|
export function sha256Uuid(seed) {
|
|
91
|
-
const h =
|
|
91
|
+
const h = bytesToHex(sha256(seed));
|
|
92
92
|
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
|
|
93
93
|
}
|
|
94
94
|
/**
|
|
@@ -100,10 +100,9 @@ export function sha256Uuid(seed) {
|
|
|
100
100
|
* (SHA-1 based, version + variant bits set) because that is what the field holds.
|
|
101
101
|
*/
|
|
102
102
|
export function schemaId(flowId, nodeId) {
|
|
103
|
-
const
|
|
104
|
-
const b = Buffer.from(h.subarray(0, 16));
|
|
103
|
+
const b = sha1(`uipath.human-in-the-loop:${flowId}:${nodeId}`).slice(0, 16);
|
|
105
104
|
b[6] = (b[6] & 0x0f) | 0x50;
|
|
106
105
|
b[8] = (b[8] & 0x3f) | 0x80;
|
|
107
|
-
const
|
|
108
|
-
return `${
|
|
106
|
+
const h = bytesToHex(b);
|
|
107
|
+
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
|
|
109
108
|
}
|
package/dist/decompile.js
CHANGED
|
@@ -2629,6 +2629,11 @@ function parseSwitchCase(expr) {
|
|
|
2629
2629
|
* expression is `<discriminant> === <JSON-literal>`; the discriminant (shared by
|
|
2630
2630
|
* all cases) becomes `on`, and each RHS literal a case `value`. The case port is
|
|
2631
2631
|
* `case-<caseId>`; the optional default arm is the `default` port.
|
|
2632
|
+
*
|
|
2633
|
+
* A switch whose cases do NOT share that shape — the product's per-case form,
|
|
2634
|
+
* `amount > 100` / `amount <= 100`, first truthy case wins — decompiles to
|
|
2635
|
+
* `when:` cases with `on` left `undefined`, so each condition round-trips
|
|
2636
|
+
* as written (#1131).
|
|
2632
2637
|
*/
|
|
2633
2638
|
function emitSwitch(node, ipdom, scope, ctx, stop, refInto) {
|
|
2634
2639
|
const r = ipdom.get(node.id) ?? stop;
|
|
@@ -2636,70 +2641,55 @@ function emitSwitch(node, ipdom, scope, ctx, stop, refInto) {
|
|
|
2636
2641
|
let caseIndex = 0;
|
|
2637
2642
|
let disc;
|
|
2638
2643
|
let nonUniform = false; // a case whose expr isn't `<disc> === <literal>`, or a differing discriminant
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
if (parsed) {
|
|
2644
|
+
// First pass: is every case one shared `<disc> === <literal>`? If not, every
|
|
2645
|
+
// case is emitted as `when:` with its expression as written.
|
|
2646
|
+
const parsed = cases.map((c) => {
|
|
2647
|
+
const p = parseSwitchCase(String(c.expression ?? ''));
|
|
2648
|
+
if (p) {
|
|
2645
2649
|
if (disc === undefined)
|
|
2646
|
-
disc =
|
|
2647
|
-
else if (disc !==
|
|
2650
|
+
disc = p.lhs;
|
|
2651
|
+
else if (disc !== p.lhs)
|
|
2648
2652
|
nonUniform = true;
|
|
2649
|
-
valueLiteral = parsed.literal;
|
|
2650
|
-
value = parsed.value;
|
|
2651
2653
|
}
|
|
2652
2654
|
else {
|
|
2653
2655
|
nonUniform = true;
|
|
2654
|
-
// Keep the best-effort output the TODO comment points at.
|
|
2655
|
-
const m = String(c.expression ?? '').match(/^(.*?)\s*===?\s*(.*)$/);
|
|
2656
|
-
if (m && m[1].trim() && disc === undefined)
|
|
2657
|
-
disc = m[1].trim();
|
|
2658
|
-
if (m) {
|
|
2659
|
-
valueLiteral = m[2].trim();
|
|
2660
|
-
try {
|
|
2661
|
-
value = tsLiteral(JSON.parse(valueLiteral));
|
|
2662
|
-
}
|
|
2663
|
-
catch {
|
|
2664
|
-
const q = valueLiteral.match(/^'(.*)'$/);
|
|
2665
|
-
value = q ? tsLiteral(q[1]) : tsLiteral(valueLiteral);
|
|
2666
|
-
}
|
|
2667
|
-
}
|
|
2668
2656
|
}
|
|
2657
|
+
return { c, p };
|
|
2658
|
+
});
|
|
2659
|
+
const caseSrcs = parsed.map(({ c, p }) => {
|
|
2669
2660
|
const armSegs = forkRegion(portEdges(ctx.graph, node.id, `case-${c.id}`), r, scope, ipdom, ctx, refInto);
|
|
2670
|
-
|
|
2661
|
+
caseIndex += 1;
|
|
2662
|
+
const defaultLabel = nonUniform || !p ? `Case ${caseIndex}` : `Case ${p.literal}`;
|
|
2671
2663
|
const labelPart = c.label && c.label !== defaultLabel ? `, label: ${tsLiteral(c.label)}` : '';
|
|
2672
2664
|
// The file's case id comes back when it is not the positional one serialize
|
|
2673
2665
|
// derives (a designer-drawn switch uses `default-1`, …), so the recompiled
|
|
2674
2666
|
// edges leave from the ORIGINAL node's handles, which merge keeps (#1130).
|
|
2675
|
-
caseIndex += 1;
|
|
2676
2667
|
const idPart = typeof c.id === 'string' && c.id !== '' && c.id !== `case_${caseIndex}` ? `, id: ${tsLiteral(c.id)}` : '';
|
|
2677
|
-
|
|
2668
|
+
const head = nonUniform || !p
|
|
2669
|
+
? `when: ${emitBareExpr(String(c.expression ?? ''), ctx.imp, ctx.inputNames)}`
|
|
2670
|
+
: `value: ${p.value}`;
|
|
2671
|
+
return `{ ${head}${labelPart}${idPart}, body: ${armCb('b', armSegs)} }`;
|
|
2672
|
+
});
|
|
2673
|
+
// A case with no condition has no `when:` that compiles: emitting `js\`\``
|
|
2674
|
+
// would fail at compile ([EXPR_SYNTAX]) with no warning here.
|
|
2675
|
+
const empty = cases.filter((c) => String(c.expression ?? '').trim() === '');
|
|
2676
|
+
if (empty.length > 0) {
|
|
2677
|
+
const listing = empty.map((c) => tsLiteral(c.label ?? c.id)).join(', ');
|
|
2678
|
+
const message = `switch ${tsLiteral(node.id)} has a case with no condition (${listing}). `
|
|
2679
|
+
+ '`.switch()` needs a condition on every case, so the decompiled `when:` is empty and recompiling fails. '
|
|
2680
|
+
+ 'Give the case a condition in the .flow, or edit this switch in the .flow JSON directly.';
|
|
2681
|
+
if (runStrict)
|
|
2682
|
+
throw new Error(`decompile: ${message}`);
|
|
2683
|
+
warnOnce(message);
|
|
2678
2684
|
}
|
|
2679
|
-
const on = emitBareExpr(disc ?? '', ctx.imp, ctx.inputNames);
|
|
2685
|
+
const on = nonUniform ? 'undefined' : emitBareExpr(disc ?? '', ctx.imp, ctx.inputNames);
|
|
2680
2686
|
const hasDefault = (node.inputs ?? {}).hasDefault === true || portEdge(ctx.graph, node.id, 'default') !== undefined;
|
|
2681
2687
|
const defArm = hasDefault
|
|
2682
2688
|
? `, ${armCb('d', forkRegion(portEdges(ctx.graph, node.id, 'default'), r, scope, ipdom, ctx, refInto))}`
|
|
2683
2689
|
: '';
|
|
2684
2690
|
const caseList = `[\n${caseSrcs.map((c) => reindent(c, ' ')).join(',\n')},\n]`;
|
|
2685
|
-
// The builder's `.switch(on, [{value}])` models `on === value` only. A flow whose
|
|
2686
|
-
// cases carry arbitrary per-case boolean expressions (or a non-uniform
|
|
2687
|
-
// discriminant) cannot round-trip through it — flag it rather than emit silently
|
|
2688
|
-
// wrong values.
|
|
2689
|
-
if (nonUniform) {
|
|
2690
|
-
const listing = cases.map((c) => `${tsLiteral(c.label ?? c.id)}: ${tsLiteral(String(c.expression ?? ''))}`).join(', ');
|
|
2691
|
-
const message = `switch ${tsLiteral(node.id)} has per-case conditions that are not one shared \`<discriminant> === <value>\` `
|
|
2692
|
-
+ `(${listing}). \`.switch()\` models only that form, so the decompiled \`on\`/\`value\` are placeholders: `
|
|
2693
|
-
+ 'recompiling either fails or changes which case runs. Edit this switch in the .flow JSON directly.';
|
|
2694
|
-
if (runStrict)
|
|
2695
|
-
throw new Error(`decompile: ${message}`);
|
|
2696
|
-
warnOnce(message);
|
|
2697
|
-
}
|
|
2698
|
-
const warn = nonUniform
|
|
2699
|
-
? `\n/* TODO: this switch's case expressions are not a uniform \`<discriminant> === <value>\`; the recovered on/value are best-effort and need review. */`
|
|
2700
|
-
: '';
|
|
2701
2691
|
const ver = verArg(node);
|
|
2702
|
-
return `.switch(${tsLiteral(node.id)}, ${on}, ${caseList}${defArm}${ver && !defArm ? ', undefined' : ''}${ver})
|
|
2692
|
+
return `.switch(${tsLiteral(node.id)}, ${on}, ${caseList}${defArm}${ver && !defArm ? ', undefined' : ''}${ver})`;
|
|
2703
2693
|
}
|
|
2704
2694
|
/**
|
|
2705
2695
|
* Recover `.stickyNotes([...])` from the scope's `stickyNote` nodes.
|
package/dist/flow-definitions.js
CHANGED
|
@@ -6,15 +6,13 @@
|
|
|
6
6
|
* Kept apart from `serialize.ts` so the registry can depend on the bundle without
|
|
7
7
|
* importing the serializer that depends on the registry.
|
|
8
8
|
*/
|
|
9
|
-
import
|
|
10
|
-
import { dirname, join } from 'node:path';
|
|
11
|
-
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import coreDefinitions from './core-definitions.json' with { type: 'json' };
|
|
12
10
|
/**
|
|
13
11
|
* The bundled definitions, keyed `<nodeType>@<version>`. Deep-frozen: every reader
|
|
14
12
|
* shares this one copy, so a write meant for one node must clone first, and one
|
|
15
13
|
* that does not throws at its own site instead of leaking into another reader.
|
|
16
14
|
*/
|
|
17
|
-
export const BUNDLED_DEFINITIONS = deepFreeze(
|
|
15
|
+
export const BUNDLED_DEFINITIONS = deepFreeze(coreDefinitions);
|
|
18
16
|
function deepFreeze(value) {
|
|
19
17
|
if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
|
|
20
18
|
Object.freeze(value);
|
package/dist/flow-expr-check.js
CHANGED
|
@@ -147,7 +147,12 @@ function walk(steps, roots, out) {
|
|
|
147
147
|
walk(s.otherwise, roots, out);
|
|
148
148
|
break;
|
|
149
149
|
case 'switch': {
|
|
150
|
-
|
|
150
|
+
if (s.on)
|
|
151
|
+
pushExpr(s.on, s.name, roots, out);
|
|
152
|
+
// A `when` case's condition is read like a branch condition (#1131).
|
|
153
|
+
for (const c of s.cases)
|
|
154
|
+
if (c.when)
|
|
155
|
+
pushExpr(c.when, s.name, roots, out);
|
|
151
156
|
// Inside a case (or default) body the discriminant is bound to
|
|
152
157
|
// `$vars.value`, so it is a valid root only there.
|
|
153
158
|
const caseRoots = new Set(roots).add('value');
|
package/dist/flow-sdk.d.ts
CHANGED
|
@@ -338,9 +338,33 @@ export declare function conversationTrigger(): TriggerSpec;
|
|
|
338
338
|
export declare function voiceTrigger(): TriggerSpec;
|
|
339
339
|
/** A value a `.switch` case compares the discriminant against. */
|
|
340
340
|
export type CaseValue = string | number | boolean;
|
|
341
|
+
/**
|
|
342
|
+
* One case of `.switch(name, on, cases)`: either `{ value }`, taken when
|
|
343
|
+
* `on === value`, or `{ when }`, taken when its own condition is true (the
|
|
344
|
+
* product switch's per-case form, #1131). Cases are tried top to bottom and the
|
|
345
|
+
* first match wins.
|
|
346
|
+
*/
|
|
347
|
+
export type SwitchCase = ({
|
|
348
|
+
value: CaseValue;
|
|
349
|
+
when?: undefined;
|
|
350
|
+
} | {
|
|
351
|
+
when: Expr;
|
|
352
|
+
value?: undefined;
|
|
353
|
+
}) & {
|
|
354
|
+
body: (b: ArmBuilder) => void;
|
|
355
|
+
label?: string;
|
|
356
|
+
id?: string;
|
|
357
|
+
};
|
|
341
358
|
/** One arm of a built `.switch` (the serializer's view: body already collected). */
|
|
342
359
|
export interface SwitchArm {
|
|
343
|
-
value
|
|
360
|
+
/** The value `on` is compared against (`on === value`). Absent on a `when` case. */
|
|
361
|
+
value?: CaseValue;
|
|
362
|
+
/**
|
|
363
|
+
* The case's own boolean condition, instead of `on === value` — the product
|
|
364
|
+
* switch stores one condition per case and takes the first that is true
|
|
365
|
+
* (#1131). Exactly one of `value` / `when`.
|
|
366
|
+
*/
|
|
367
|
+
when?: Expr;
|
|
344
368
|
label?: string;
|
|
345
369
|
/**
|
|
346
370
|
* The case's wire id — `inputs.cases[].id`, and the `case-<id>` port its arm
|
|
@@ -500,7 +524,7 @@ export type Step = {
|
|
|
500
524
|
kind: 'switch';
|
|
501
525
|
name: string;
|
|
502
526
|
label?: string;
|
|
503
|
-
on
|
|
527
|
+
on?: Expr;
|
|
504
528
|
cases: SwitchArm[];
|
|
505
529
|
default?: Step[];
|
|
506
530
|
options?: NodeOptions;
|
|
@@ -984,23 +1008,30 @@ declare class StepList {
|
|
|
984
1008
|
* ], (other) => other.step('unknown', script({ code: 'return "Unknown";' })))
|
|
985
1009
|
* ```
|
|
986
1010
|
*
|
|
1011
|
+
* @example
|
|
1012
|
+
* **Cases with their own conditions** (`on` is `undefined`)
|
|
1013
|
+
* ```ts
|
|
1014
|
+
* .switch('route', undefined, [
|
|
1015
|
+
* { when: js`$vars.start.output.amount > 100`, label: 'High', body: (b) => b.step('review', script({ code: 'return 1;' })) },
|
|
1016
|
+
* { when: js`$vars.start.output.amount <= 100`, label: 'Low', body: (b) => b.step('auto', script({ code: 'return 2;' })) },
|
|
1017
|
+
* ])
|
|
1018
|
+
* ```
|
|
1019
|
+
*
|
|
987
1020
|
* @param name - The switch node's id.
|
|
988
|
-
* @param on - The value to compare each case against
|
|
989
|
-
*
|
|
990
|
-
*
|
|
991
|
-
*
|
|
1021
|
+
* @param on - The value to compare each `value` case against; `undefined`
|
|
1022
|
+
* when every case carries its own `when` condition.
|
|
1023
|
+
* @param cases - One entry per arm, evaluated top to bottom; the first match
|
|
1024
|
+
* wins. A case is `{ value }` (strict `on === value`) or `{ when }` (its own
|
|
1025
|
+
* boolean expression). `label` names the arm's outgoing edge. `id` keeps a
|
|
1026
|
+
* case's wire id (`inputs.cases[].id`, port `case-<id>`); omitted, it is
|
|
1027
|
+
* `case_<n>`.
|
|
992
1028
|
* @param defaultFn - Receives a sub-builder for the arm taken when nothing
|
|
993
1029
|
* matches. Omit it and an unmatched value simply continues.
|
|
994
1030
|
* @param options - Node options; `version` selects the exact definition
|
|
995
1031
|
* version (see {@link NodeOptions}).
|
|
996
1032
|
* @returns This builder, after every arm has rejoined.
|
|
997
1033
|
*/
|
|
998
|
-
switch(name: string, on: Expr, cases:
|
|
999
|
-
value: CaseValue;
|
|
1000
|
-
body: (b: ArmBuilder) => void;
|
|
1001
|
-
label?: string;
|
|
1002
|
-
id?: string;
|
|
1003
|
-
}[], defaultFn?: (b: StepList) => void, options?: NodeOptions): this;
|
|
1034
|
+
switch(name: string, on: Expr | undefined, cases: SwitchCase[], defaultFn?: (b: StepList) => void, options?: NodeOptions): this;
|
|
1004
1035
|
/**
|
|
1005
1036
|
* Run two or more arms **in parallel** from this point and join them back
|
|
1006
1037
|
* together on a Merge node — the one place the builder stops being a straight
|