@uipath/maestro-builder-sdk 6.18.9 → 6.19.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/dist/api-index.md +185 -184
- package/dist/api-members.md +504 -473
- package/dist/bpmn/uipath-moddle.v1.json +5 -0
- package/dist/case/decompile-cli.js +2 -8
- package/dist/check.js +177 -650
- package/dist/core/actions.d.ts +119 -760
- package/dist/core/actions.js +0 -306
- package/dist/core/error-port.d.ts +6 -0
- package/dist/core/error-port.js +9 -0
- package/dist/core/node-classes.d.ts +4 -63
- package/dist/core/node-classes.js +0 -112
- package/dist/core/nodes/family.d.ts +36 -0
- package/dist/core/nodes/family.js +1 -0
- package/dist/core/nodes/node-type.d.ts +136 -0
- package/dist/core/nodes/node-type.js +1 -0
- package/dist/core/nodes/registry.d.ts +57 -0
- package/dist/core/nodes/registry.js +122 -0
- package/dist/core/nodes/versioned.d.ts +50 -0
- package/dist/core/nodes/versioned.js +46 -0
- package/dist/core/typed-raw-node.d.ts +13 -62
- package/dist/core/typed-raw-node.js +40 -154
- package/dist/decompile-cli.js +2 -9
- package/dist/decompile.js +92 -271
- package/dist/flow-definitions.d.ts +10 -0
- package/dist/flow-definitions.js +35 -0
- package/dist/flow-node-registry.d.ts +13 -0
- package/dist/flow-node-registry.js +19 -0
- package/dist/flow-node-type.d.ts +192 -0
- package/dist/flow-node-type.js +1 -0
- package/dist/flow-sdk.d.ts +7 -0
- package/dist/flow-sdk.js +8 -0
- package/dist/nodes/data-fabric/flow/check.d.ts +13 -0
- package/dist/nodes/data-fabric/flow/check.js +164 -0
- package/dist/nodes/data-fabric/flow/factories.d.ts +113 -0
- package/dist/nodes/data-fabric/flow/factories.js +134 -0
- package/dist/nodes/data-fabric/flow/family.d.ts +7 -0
- package/dist/nodes/data-fabric/flow/family.js +9 -0
- package/dist/nodes/data-fabric/flow/index.d.ts +8 -0
- package/dist/nodes/data-fabric/flow/index.js +8 -0
- package/dist/nodes/data-fabric/flow/raw.d.ts +32 -0
- package/dist/nodes/data-fabric/flow/raw.js +100 -0
- package/dist/nodes/data-fabric/flow/shared.d.ts +77 -0
- package/dist/nodes/data-fabric/flow/shared.js +174 -0
- package/dist/nodes/data-fabric/flow/spec.d.ts +238 -0
- package/dist/nodes/data-fabric/flow/spec.js +1 -0
- package/dist/nodes/data-fabric/flow/verbs.d.ts +29 -0
- package/dist/nodes/data-fabric/flow/verbs.js +239 -0
- package/dist/nodes/delay/flow/check.d.ts +16 -0
- package/dist/nodes/delay/flow/check.js +86 -0
- package/dist/nodes/delay/flow/factories.d.ts +28 -0
- package/dist/nodes/delay/flow/factories.js +38 -0
- package/dist/nodes/delay/flow/family.d.ts +3 -0
- package/dist/nodes/delay/flow/family.js +8 -0
- package/dist/nodes/delay/flow/index.d.ts +3 -0
- package/dist/nodes/delay/flow/index.js +3 -0
- package/dist/nodes/delay/flow/node-type.d.ts +13 -0
- package/dist/nodes/delay/flow/node-type.js +71 -0
- package/dist/nodes/delay/flow/spec.d.ts +43 -0
- package/dist/nodes/delay/flow/spec.js +16 -0
- package/dist/nodes/document/flow/factories.d.ts +27 -0
- package/dist/nodes/document/flow/factories.js +30 -0
- package/dist/nodes/document/flow/family.d.ts +3 -0
- package/dist/nodes/document/flow/family.js +7 -0
- package/dist/nodes/document/flow/index.d.ts +3 -0
- package/dist/nodes/document/flow/index.js +3 -0
- package/dist/nodes/document/flow/node-type.d.ts +14 -0
- package/dist/nodes/document/flow/node-type.js +150 -0
- package/dist/nodes/document/flow/spec.d.ts +65 -0
- package/dist/nodes/document/flow/spec.js +1 -0
- package/dist/nodes/mock/flow/factories.d.ts +51 -0
- package/dist/nodes/mock/flow/factories.js +47 -0
- package/dist/nodes/mock/flow/family.d.ts +3 -0
- package/dist/nodes/mock/flow/family.js +7 -0
- package/dist/nodes/mock/flow/index.d.ts +2 -0
- package/dist/nodes/mock/flow/index.js +2 -0
- package/dist/nodes/mock/flow/node-type.d.ts +11 -0
- package/dist/nodes/mock/flow/node-type.js +51 -0
- package/dist/nodes/script/flow/check.d.ts +19 -0
- package/dist/nodes/script/flow/check.js +49 -0
- package/dist/nodes/script/flow/factories.d.ts +14 -0
- package/dist/nodes/script/flow/factories.js +15 -0
- package/dist/nodes/script/flow/family.d.ts +3 -0
- package/dist/nodes/script/flow/family.js +8 -0
- package/dist/nodes/script/flow/index.d.ts +3 -0
- package/dist/nodes/script/flow/index.js +3 -0
- package/dist/nodes/script/flow/node-type.d.ts +7 -0
- package/dist/nodes/script/flow/node-type.js +125 -0
- package/dist/nodes/script/flow/spec.d.ts +52 -0
- package/dist/nodes/script/flow/spec.js +1 -0
- package/dist/nodes/transform/flow/check.d.ts +6 -0
- package/dist/nodes/transform/flow/check.js +229 -0
- package/dist/nodes/transform/flow/factories.d.ts +52 -0
- package/dist/nodes/transform/flow/factories.js +53 -0
- package/dist/nodes/transform/flow/family.d.ts +3 -0
- package/dist/nodes/transform/flow/family.js +8 -0
- package/dist/nodes/transform/flow/index.d.ts +3 -0
- package/dist/nodes/transform/flow/index.js +3 -0
- package/dist/nodes/transform/flow/node-type.d.ts +7 -0
- package/dist/nodes/transform/flow/node-type.js +244 -0
- package/dist/nodes/transform/flow/spec.d.ts +116 -0
- package/dist/nodes/transform/flow/spec.js +10 -0
- package/dist/raw-node-advice.d.ts +16 -0
- package/dist/raw-node-advice.js +36 -0
- package/dist/raw-node.d.ts +71 -0
- package/dist/raw-node.js +116 -0
- package/dist/registry/uip/launch.d.ts +11 -1
- package/dist/registry/uip/launch.js +50 -43
- package/dist/registry/uip/pipeline-front-door.d.ts +2 -0
- package/dist/registry/uip/pipeline-front-door.js +88 -0
- package/dist/serialize.js +138 -492
- package/package.json +2 -2
package/dist/raw-node.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `rawNode` — place a node this SDK has no factory for, carrying its definition
|
|
3
|
+
* verbatim. Moved from core/node-classes.ts in Phase 3 of
|
|
4
|
+
* docs/NODE_TYPE_ARCHITECTURE_DESIGN.md so its diagnostics can ask the node-type
|
|
5
|
+
* registry what a registered type says about a raw node of it; the package entry
|
|
6
|
+
* re-exports it, so authors import it exactly as before.
|
|
7
|
+
*/
|
|
8
|
+
import { FlowAction, } from './core/node-classes.js';
|
|
9
|
+
import { connectorRawNodeRefusal } from './core/connector-raw-node.js';
|
|
10
|
+
import { rawNodeInputProblem, rawNodeTypedFamilyWarning } from './raw-node-advice.js';
|
|
11
|
+
/**
|
|
12
|
+
* Place a node this SDK has no factory for, carrying its definition verbatim
|
|
13
|
+
* (`uipath.exotic.thing@2.1` and the manifest the platform served for it).
|
|
14
|
+
*
|
|
15
|
+
* @remarks
|
|
16
|
+
* This is the escape hatch the coverage plan requires: an unknown registry
|
|
17
|
+
* definition is expressible without bypassing serializer invariants. The
|
|
18
|
+
* serializer still owns the node's id, label, `typeVersion` and edge wiring; you
|
|
19
|
+
* supply which definition and which inputs, exactly as a hand-written
|
|
20
|
+
* {@link FlowAction} subclass would.
|
|
21
|
+
*
|
|
22
|
+
* It is also what `decompile` emits for a node type it cannot name, so a
|
|
23
|
+
* round trip preserves the node's TYPE and VERSION instead of degrading it to a
|
|
24
|
+
* placeholder:
|
|
25
|
+
*
|
|
26
|
+
* ```ts
|
|
27
|
+
* .step('exotic', rawNode({
|
|
28
|
+
* nodeType: 'uipath.exotic.thing',
|
|
29
|
+
* version: '2.1',
|
|
30
|
+
* manifest: exoticManifest, // exactly what `registry get` returned
|
|
31
|
+
* inputs: { where: input('scope') },
|
|
32
|
+
* }))
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* `manifest` must be a real definition — an exact copy of what the registry or
|
|
36
|
+
* Workbench serves for that `nodeType@version`. It is not permission to invent
|
|
37
|
+
* one: the platform resolves the node against its own catalog at run time, so a
|
|
38
|
+
* hand-written manifest validates locally and fails on the tenant.
|
|
39
|
+
*
|
|
40
|
+
* Prefer a typed factory when one exists — it carries the family's checks, its
|
|
41
|
+
* defaults, and its output contract, none of which a raw node can know.
|
|
42
|
+
*
|
|
43
|
+
* **Never for a connector.** A `uipath.connector.*` node type is refused by
|
|
44
|
+
* `check` and `compile`: a raw node carries the author's inputs verbatim, so the
|
|
45
|
+
* emitted node has no `inputs.detail` and no connection binding — `validate`
|
|
46
|
+
* only warns ("Connector is not configured") and the run can never reach
|
|
47
|
+
* Integration Service. Use {@link connector}, and `registry prepare` when
|
|
48
|
+
* compile reports an input the static library does not carry; use
|
|
49
|
+
* {@link onEvent} for a connector event trigger.
|
|
50
|
+
*
|
|
51
|
+
* **Prefer the typed factory** for a node type that has one: `check` warns
|
|
52
|
+
* (`RAW_NODE_TYPED_FAMILY`), because `validate` cannot see an input the
|
|
53
|
+
* registry definition does not declare. For a `core.datafabric.*` type, a key
|
|
54
|
+
* the product never reads (an invented `_sortOptions` in place of `_sort`) is
|
|
55
|
+
* an error at a version the SDK bundles (`RAW_NODE_UNKNOWN_INPUT`); the
|
|
56
|
+
* canvas's snapshots, such as the `_entityFields` a related-path filter
|
|
57
|
+
* needs, stay legal.
|
|
58
|
+
*
|
|
59
|
+
* @param spec - The definition to compile against, plus the node's inputs.
|
|
60
|
+
* @returns A node to pass to `.step(...)`.
|
|
61
|
+
*/
|
|
62
|
+
export function rawNode(spec) {
|
|
63
|
+
return new RawNode(spec);
|
|
64
|
+
}
|
|
65
|
+
/** The {@link rawNode} implementation — a snapshot-backed contribution. */
|
|
66
|
+
class RawNode extends FlowAction {
|
|
67
|
+
spec;
|
|
68
|
+
constructor(spec) {
|
|
69
|
+
super();
|
|
70
|
+
this.spec = spec;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* `check` surfaces the connector refusal as an error, a typed family as a
|
|
74
|
+
* warning, and an input a registered node type never reads as an error at a
|
|
75
|
+
* bundled version (a warning at any other); `compile` throws the errors
|
|
76
|
+
* (see {@link contribute}).
|
|
77
|
+
*/
|
|
78
|
+
diagnostics() {
|
|
79
|
+
const refusal = connectorRawNodeRefusal(this.spec.nodeType);
|
|
80
|
+
if (refusal)
|
|
81
|
+
return [{ code: 'RAW_NODE_CONNECTOR', severity: 'error', message: refusal }];
|
|
82
|
+
const out = [];
|
|
83
|
+
const unknown = rawNodeInputProblem(this.spec.nodeType, this.spec.version, this.spec.inputs);
|
|
84
|
+
if (unknown)
|
|
85
|
+
out.push({ code: 'RAW_NODE_UNKNOWN_INPUT', ...unknown });
|
|
86
|
+
const typed = rawNodeTypedFamilyWarning(this.spec.nodeType);
|
|
87
|
+
if (typed)
|
|
88
|
+
out.push({ code: 'RAW_NODE_TYPED_FAMILY', severity: 'warning', message: typed });
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
contribute(context) {
|
|
92
|
+
// compile does not run diagnostics(); refuse here too so the escape hatch
|
|
93
|
+
// cannot emit an unconfigured connector node. (An input a registered node
|
|
94
|
+
// type never reads is refused by the serializer, for every contribution.)
|
|
95
|
+
const refusal = connectorRawNodeRefusal(this.spec.nodeType);
|
|
96
|
+
if (refusal)
|
|
97
|
+
throw new Error(refusal);
|
|
98
|
+
const version = context.requestedVersion ?? this.spec.version;
|
|
99
|
+
if (context.requestedVersion !== undefined && context.requestedVersion !== this.spec.version) {
|
|
100
|
+
// Versions are exact everywhere in this SDK: a contributor may not
|
|
101
|
+
// substitute its own for an explicit request (design §2.6).
|
|
102
|
+
throw new Error(`rawNode("${this.spec.nodeType}") carries version ${this.spec.version}, but the step requests `
|
|
103
|
+
+ `${context.requestedVersion}. Pass the manifest for the requested version, or drop { version }.`);
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
definition: {
|
|
107
|
+
source: 'snapshot',
|
|
108
|
+
nodeType: this.spec.nodeType,
|
|
109
|
+
version,
|
|
110
|
+
manifest: this.spec.manifest,
|
|
111
|
+
},
|
|
112
|
+
...(this.spec.inputs !== undefined ? { inputs: this.spec.inputs } : {}),
|
|
113
|
+
...(this.spec.outputs !== undefined ? { outputs: this.spec.outputs } : {}),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { win32 } from "node:path";
|
|
1
2
|
export interface Launch {
|
|
2
3
|
file: string;
|
|
3
4
|
args: string[];
|
|
@@ -13,12 +14,21 @@ export interface LaunchHost {
|
|
|
13
14
|
execPath: string;
|
|
14
15
|
isFile(path: string): boolean;
|
|
15
16
|
readFile(path: string): string;
|
|
17
|
+
/** Windows path operations (`node:path`'s `win32`), passed in so {@link resolveLaunch} imports nothing. */
|
|
18
|
+
win32: Pick<typeof win32, "join" | "dirname" | "extname">;
|
|
16
19
|
}
|
|
20
|
+
/** The host this process runs on. */
|
|
21
|
+
export declare function ambientLaunchHost(): LaunchHost;
|
|
17
22
|
/**
|
|
18
|
-
* The file and arguments to spawn for `executable args`, without a shell.
|
|
23
|
+
* The file and arguments to spawn for `executable args` on `host`, without a shell.
|
|
24
|
+
*
|
|
25
|
+
* Self-contained on purpose (see the module comment): generated scripts embed
|
|
26
|
+
* `resolveLaunch.toString()`.
|
|
19
27
|
*
|
|
20
28
|
* @throws when, on Windows, the name resolves to a batch shim this cannot read
|
|
21
29
|
* a script out of — naming the shim, so the remedy is not "put uip on PATH"
|
|
22
30
|
* for a `uip` that is on PATH.
|
|
23
31
|
*/
|
|
32
|
+
export declare function resolveLaunch(executable: string, args: readonly string[], host: LaunchHost): Launch;
|
|
33
|
+
/** {@link resolveLaunch} on this process's host. */
|
|
24
34
|
export declare function launchFor(executable: string, args: readonly string[], host?: LaunchHost): Launch;
|
|
@@ -22,6 +22,13 @@
|
|
|
22
22
|
* A name that is not bare (a path, or one with an extension) is spawned as
|
|
23
23
|
* given, and so is anything on another platform.
|
|
24
24
|
*
|
|
25
|
+
* The rules live in ONE self-contained function, {@link resolveLaunch}, because
|
|
26
|
+
* a second copy runs outside this package: the brownfield pipeline scripts that
|
|
27
|
+
* `flow decompile` and `case decompile` write embed its source text
|
|
28
|
+
* (`pipeline-front-door.ts`, flow-builder-sdk#1120). So it may reference only
|
|
29
|
+
* its parameters and globals — no module constant, no import — and a test runs
|
|
30
|
+
* its source text in an empty context to hold that.
|
|
31
|
+
*
|
|
25
32
|
* Example, on Windows with npm's global bin on PATH:
|
|
26
33
|
* launchFor("uip", ["--version"])
|
|
27
34
|
* // -> { file: "C:\\Program Files\\nodejs\\node.exe",
|
|
@@ -29,14 +36,8 @@
|
|
|
29
36
|
*/
|
|
30
37
|
import { readFileSync, statSync } from "node:fs";
|
|
31
38
|
import { win32 } from "node:path";
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
* The script an npm (`cmd-shim`) or pnpm shim hands its arguments to: the last
|
|
35
|
-
* quoted `%dp0%\…` / `%~dp0\…` path followed by `%*`. Only a JavaScript target
|
|
36
|
-
* counts; a shim around something else is not one this module can run directly.
|
|
37
|
-
*/
|
|
38
|
-
const SHIM_TARGET = /"%~?dp0%?\\([^"]+\.[cm]?js)"\s+%\*/g;
|
|
39
|
-
function ambientHost() {
|
|
39
|
+
/** The host this process runs on. */
|
|
40
|
+
export function ambientLaunchHost() {
|
|
40
41
|
return {
|
|
41
42
|
platform: process.platform,
|
|
42
43
|
path: process.env.PATH,
|
|
@@ -51,55 +52,61 @@ function ambientHost() {
|
|
|
51
52
|
}
|
|
52
53
|
},
|
|
53
54
|
readFile: (path) => readFileSync(path, "utf8"),
|
|
55
|
+
win32,
|
|
54
56
|
};
|
|
55
57
|
}
|
|
56
|
-
/** True for a name `PATH` lookup applies to: no directory part and no extension. */
|
|
57
|
-
function isBareName(executable) {
|
|
58
|
-
return executable !== "" && !/[\\/]/.test(executable) && win32.extname(executable) === "";
|
|
59
|
-
}
|
|
60
|
-
/** The first `<dir>\<executable><ext>` on PATH, in cmd.exe's order, or undefined. */
|
|
61
|
-
function findOnPath(executable, host) {
|
|
62
|
-
const extensions = (host.pathExt || DEFAULT_PATHEXT).split(";").filter(Boolean);
|
|
63
|
-
for (const dir of (host.path ?? "").split(";")) {
|
|
64
|
-
const trimmed = dir.trim().replace(/^"(.*)"$/, "$1");
|
|
65
|
-
if (trimmed === "")
|
|
66
|
-
continue;
|
|
67
|
-
for (const ext of extensions) {
|
|
68
|
-
const candidate = win32.join(trimmed, executable + ext.toLowerCase());
|
|
69
|
-
if (host.isFile(candidate))
|
|
70
|
-
return candidate;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
|
-
/** The script a `.cmd`/`.bat` shim runs, as an absolute path, or undefined. */
|
|
76
|
-
function shimTarget(shim, host) {
|
|
77
|
-
const matches = [...host.readFile(shim).matchAll(SHIM_TARGET)];
|
|
78
|
-
const last = matches.at(-1);
|
|
79
|
-
return last ? win32.join(win32.dirname(shim), last[1]) : undefined;
|
|
80
|
-
}
|
|
81
58
|
/**
|
|
82
|
-
* The file and arguments to spawn for `executable args`, without a shell.
|
|
59
|
+
* The file and arguments to spawn for `executable args` on `host`, without a shell.
|
|
60
|
+
*
|
|
61
|
+
* Self-contained on purpose (see the module comment): generated scripts embed
|
|
62
|
+
* `resolveLaunch.toString()`.
|
|
83
63
|
*
|
|
84
64
|
* @throws when, on Windows, the name resolves to a batch shim this cannot read
|
|
85
65
|
* a script out of — naming the shim, so the remedy is not "put uip on PATH"
|
|
86
66
|
* for a `uip` that is on PATH.
|
|
87
67
|
*/
|
|
88
|
-
export function
|
|
89
|
-
|
|
68
|
+
export function resolveLaunch(executable, args, host) {
|
|
69
|
+
const path = host.win32;
|
|
70
|
+
// Bare: no directory part and no extension. Only a bare name is looked up.
|
|
71
|
+
const bare = executable !== "" && !/[\\/]/.test(executable) && path.extname(executable) === "";
|
|
72
|
+
if (host.platform !== "win32" || !bare)
|
|
90
73
|
return { file: executable, args: [...args] };
|
|
91
|
-
|
|
74
|
+
// The first `<dir>\<executable><ext>` on PATH, in cmd.exe's PATHEXT order.
|
|
75
|
+
const extensions = (host.pathExt || ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean);
|
|
76
|
+
let found;
|
|
77
|
+
search: for (const dir of (host.path ?? "").split(";")) {
|
|
78
|
+
const trimmed = dir.trim().replace(/^"(.*)"$/, "$1");
|
|
79
|
+
if (trimmed === "")
|
|
80
|
+
continue;
|
|
81
|
+
for (const ext of extensions) {
|
|
82
|
+
const candidate = path.join(trimmed, executable + ext.toLowerCase());
|
|
83
|
+
if (host.isFile(candidate)) {
|
|
84
|
+
found = candidate;
|
|
85
|
+
break search;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
92
89
|
// Not on PATH: spawn the bare name and let the ENOENT say so.
|
|
93
|
-
if (
|
|
90
|
+
if (found === undefined)
|
|
94
91
|
return { file: executable, args: [...args] };
|
|
95
|
-
const ext =
|
|
92
|
+
const ext = path.extname(found).toLowerCase();
|
|
96
93
|
if (ext !== ".cmd" && ext !== ".bat")
|
|
97
94
|
return { file: found, args: [...args] };
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
// The script an npm (cmd-shim) or pnpm shim hands its arguments to: the last
|
|
96
|
+
// quoted `%dp0%\…` / `%~dp0\…` JavaScript path followed by `%*`.
|
|
97
|
+
const matches = [...host.readFile(found).matchAll(/"%~?dp0%?\\([^"]+\.[cm]?js)"\s+%\*/g)];
|
|
98
|
+
const last = matches[matches.length - 1];
|
|
99
|
+
const script = last ? path.join(path.dirname(found), last[1]) : undefined;
|
|
100
|
+
if (script === undefined || !host.isFile(script)) {
|
|
100
101
|
throw new Error(`Could not start ${executable}: ${found} is a batch file, which Node cannot run without a shell, ` +
|
|
101
|
-
(script
|
|
102
|
-
|
|
102
|
+
(script !== undefined
|
|
103
|
+
? `and the script it names (${script}) does not exist.`
|
|
104
|
+
: "and it names no JavaScript entry point to run instead.") +
|
|
105
|
+
" Reinstall it with npm (for the UiPath CLI, `npm install -g @uipath/cli`).");
|
|
103
106
|
}
|
|
104
107
|
return { file: host.execPath, args: [script, ...args] };
|
|
105
108
|
}
|
|
109
|
+
/** {@link resolveLaunch} on this process's host. */
|
|
110
|
+
export function launchFor(executable, args, host = ambientLaunchHost()) {
|
|
111
|
+
return resolveLaunch(executable, args, host);
|
|
112
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The "front door" block of a generated brownfield pipeline script: how the
|
|
3
|
+
* script finds a CLI to run `compile`, `decompile` and `merge` with.
|
|
4
|
+
*
|
|
5
|
+
* `flow decompile` and `case decompile` each write a `<Name>.pipeline.mjs`
|
|
6
|
+
* beside the source. Both used to carry their own copy of this block, and both
|
|
7
|
+
* spawned the bare names `uip` and `npx` without a shell. On Windows both are
|
|
8
|
+
* `.cmd` shims, which Node cannot start that way, so the probe for `uip` failed,
|
|
9
|
+
* the `npx` fallback failed too, and the pipeline could not run at all
|
|
10
|
+
* (flow-builder-sdk#1120, the same defect as #940 in the registry).
|
|
11
|
+
*
|
|
12
|
+
* Now there is one block, and it starts programs through the same rules the
|
|
13
|
+
* registry uses: it embeds the source text of `resolveLaunch`
|
|
14
|
+
* (`registry/uip/launch.ts`), so a fix there reaches every pipeline written
|
|
15
|
+
* after it. The order is unchanged:
|
|
16
|
+
* 1. `uip maestro <kind>`, when `uip maestro <kind> compile --help` exits 0
|
|
17
|
+
* (a CLI that carries the authoring commands);
|
|
18
|
+
* 2. otherwise the SDK's own `flow-sdk` bin, found the way
|
|
19
|
+
* `npx --no-install flow-sdk` found it: `node_modules/.bin` in the script's
|
|
20
|
+
* folder and every folder above it, then `PATH`.
|
|
21
|
+
*
|
|
22
|
+
* The block brings its own imports, `existsSync` among them, and defines
|
|
23
|
+
* `run(verb, args)`; the pipeline body uses both. Nothing in it names a path on
|
|
24
|
+
* the machine that generated it, so a pipeline stays relocatable.
|
|
25
|
+
*
|
|
26
|
+
* Example, for `kind = 'flow'` on a machine whose `uip` has the commands:
|
|
27
|
+
* run('compile', ['A.flow.ts', '-o', 'A.edited.flow'])
|
|
28
|
+
* // POSIX: uip maestro flow compile A.flow.ts -o A.edited.flow
|
|
29
|
+
* // Windows: node.exe <npm>\node_modules\@uipath\cli\dist\index.js maestro flow compile …
|
|
30
|
+
*/
|
|
31
|
+
import { resolveLaunch } from './launch.js';
|
|
32
|
+
/** The script text: imports, the embedded resolver, `frontDoor`, and `run(verb, args)`. */
|
|
33
|
+
export function pipelineFrontDoor(kind) {
|
|
34
|
+
return `import { execFileSync, spawnSync } from 'node:child_process';
|
|
35
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
36
|
+
import { dirname, join, win32 } from 'node:path';
|
|
37
|
+
import { fileURLToPath } from 'node:url';
|
|
38
|
+
|
|
39
|
+
const KIND = ${JSON.stringify(kind)};
|
|
40
|
+
|
|
41
|
+
// How to start a program by name without a shell, Windows .cmd shims included.
|
|
42
|
+
// Copied from the SDK's registry/uip/launch.ts when this file was generated.
|
|
43
|
+
${resolveLaunch.toString()}
|
|
44
|
+
|
|
45
|
+
const launchHost = (path) => ({
|
|
46
|
+
platform: process.platform,
|
|
47
|
+
path,
|
|
48
|
+
pathExt: process.env.PATHEXT,
|
|
49
|
+
execPath: process.execPath,
|
|
50
|
+
isFile: (p) => { try { return statSync(p).isFile(); } catch { return false; } },
|
|
51
|
+
readFile: (p) => readFileSync(p, 'utf8'),
|
|
52
|
+
win32,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// 1. \`uip maestro <kind>\`, when this CLI carries the authoring commands.
|
|
56
|
+
function uipFrontDoor() {
|
|
57
|
+
let uip;
|
|
58
|
+
try {
|
|
59
|
+
uip = resolveLaunch('uip', [], launchHost(process.env.PATH));
|
|
60
|
+
} catch {
|
|
61
|
+
return undefined; // a uip shim that cannot be read: use the SDK instead
|
|
62
|
+
}
|
|
63
|
+
const probe = spawnSync(uip.file, [...uip.args, 'maestro', KIND, 'compile', '--help'], { stdio: 'ignore' });
|
|
64
|
+
return !probe.error && probe.status === 0 ? { file: uip.file, prefix: [...uip.args, 'maestro', KIND] } : undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 2. The SDK's flow-sdk bin, where \`npx --no-install flow-sdk\` looked for it.
|
|
68
|
+
function sdkFrontDoor() {
|
|
69
|
+
const bins = [];
|
|
70
|
+
for (let dir = dirname(fileURLToPath(import.meta.url)); ; dir = dirname(dir)) {
|
|
71
|
+
bins.push(join(dir, 'node_modules', '.bin'));
|
|
72
|
+
if (dirname(dir) === dir) break;
|
|
73
|
+
}
|
|
74
|
+
let sdk;
|
|
75
|
+
if (process.platform === 'win32') {
|
|
76
|
+
sdk = resolveLaunch('flow-sdk', [], launchHost([...bins, process.env.PATH ?? ''].join(';')));
|
|
77
|
+
} else {
|
|
78
|
+
const local = bins.map((bin) => join(bin, 'flow-sdk')).find((p) => existsSync(p));
|
|
79
|
+
sdk = { file: local ?? 'flow-sdk', args: [] };
|
|
80
|
+
}
|
|
81
|
+
return { file: sdk.file, prefix: [...sdk.args, KIND] };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const frontDoor = uipFrontDoor() ?? sdkFrontDoor();
|
|
85
|
+
const run = (verb, args) =>
|
|
86
|
+
execFileSync(frontDoor.file, [...frontDoor.prefix, verb, ...args], { stdio: 'inherit' });
|
|
87
|
+
`;
|
|
88
|
+
}
|