@uipath/maestro-builder-sdk 6.18.10 → 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/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.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/serialize.js +138 -492
- package/package.json +2 -2
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Transform factory, `transform()`. Moved from core/actions.ts in Phase 4 of
|
|
3
|
+
* docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; the package entry re-exports it.
|
|
4
|
+
*/
|
|
5
|
+
import { type ActionSpec } from '../../../core/actions.js';
|
|
6
|
+
import type { TransformInputs } from './spec.js';
|
|
7
|
+
/**
|
|
8
|
+
* Declare a Transform action — a chain of declarative operations over a
|
|
9
|
+
* collection. Read the result downstream with `out('<step>')`.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* For a node that does ONE thing, name the variant — the emitted `.flow` then
|
|
13
|
+
* carries `core.action.transform.filter` and reads as `Filter` in the designer
|
|
14
|
+
* instead of a generic `Transform`:
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* .step('bigOrders', transform({
|
|
18
|
+
* variant: 'filter',
|
|
19
|
+
* collection: v('orders'),
|
|
20
|
+
* operations: [
|
|
21
|
+
* { type: 'filter', filters: [{ field: 'amount', condition: 'greater_equal', value: 100 }] },
|
|
22
|
+
* ],
|
|
23
|
+
* }))
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* **Filter a collection, then reshape what survives**
|
|
28
|
+
* ```ts
|
|
29
|
+
* .var('catalog', types.array, [
|
|
30
|
+
* { title: 'Deep Learning', author: 'Goodfellow', difficulty: 9, pages: 800 },
|
|
31
|
+
* { title: 'Information Theory', author: 'MacKay', difficulty: 7, pages: 540 },
|
|
32
|
+
* ])
|
|
33
|
+
* .step('curate', transform({
|
|
34
|
+
* collection: v('catalog'),
|
|
35
|
+
* operations: [
|
|
36
|
+
* { type: 'filter', operation: 'and', filters: [
|
|
37
|
+
* { field: 'difficulty', condition: 'greater_than', value: 5 },
|
|
38
|
+
* { field: 'pages', condition: 'less_than', value: 600 },
|
|
39
|
+
* ] },
|
|
40
|
+
* { type: 'map', keepOriginalFields: false, mappings: [
|
|
41
|
+
* { field: 'title', transformation: 'uppercase' },
|
|
42
|
+
* { field: 'author' },
|
|
43
|
+
* ] },
|
|
44
|
+
* ],
|
|
45
|
+
* }))
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @param inputs - The `collection` to transform and the chain of `operations` to
|
|
49
|
+
* run over it.
|
|
50
|
+
* @returns An action spec to pass to `.step(name, …)`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function transform(inputs: TransformInputs): ActionSpec;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Transform factory, `transform()`. Moved from core/actions.ts in Phase 4 of
|
|
3
|
+
* docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; the package entry re-exports it.
|
|
4
|
+
*/
|
|
5
|
+
import { builtinActionSpec } from '../../../core/actions.js';
|
|
6
|
+
/**
|
|
7
|
+
* Declare a Transform action — a chain of declarative operations over a
|
|
8
|
+
* collection. Read the result downstream with `out('<step>')`.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* For a node that does ONE thing, name the variant — the emitted `.flow` then
|
|
12
|
+
* carries `core.action.transform.filter` and reads as `Filter` in the designer
|
|
13
|
+
* instead of a generic `Transform`:
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* .step('bigOrders', transform({
|
|
17
|
+
* variant: 'filter',
|
|
18
|
+
* collection: v('orders'),
|
|
19
|
+
* operations: [
|
|
20
|
+
* { type: 'filter', filters: [{ field: 'amount', condition: 'greater_equal', value: 100 }] },
|
|
21
|
+
* ],
|
|
22
|
+
* }))
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* **Filter a collection, then reshape what survives**
|
|
27
|
+
* ```ts
|
|
28
|
+
* .var('catalog', types.array, [
|
|
29
|
+
* { title: 'Deep Learning', author: 'Goodfellow', difficulty: 9, pages: 800 },
|
|
30
|
+
* { title: 'Information Theory', author: 'MacKay', difficulty: 7, pages: 540 },
|
|
31
|
+
* ])
|
|
32
|
+
* .step('curate', transform({
|
|
33
|
+
* collection: v('catalog'),
|
|
34
|
+
* operations: [
|
|
35
|
+
* { type: 'filter', operation: 'and', filters: [
|
|
36
|
+
* { field: 'difficulty', condition: 'greater_than', value: 5 },
|
|
37
|
+
* { field: 'pages', condition: 'less_than', value: 600 },
|
|
38
|
+
* ] },
|
|
39
|
+
* { type: 'map', keepOriginalFields: false, mappings: [
|
|
40
|
+
* { field: 'title', transformation: 'uppercase' },
|
|
41
|
+
* { field: 'author' },
|
|
42
|
+
* ] },
|
|
43
|
+
* ],
|
|
44
|
+
* }))
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @param inputs - The `collection` to transform and the chain of `operations` to
|
|
48
|
+
* run over it.
|
|
49
|
+
* @returns An action spec to pass to `.step(name, …)`.
|
|
50
|
+
*/
|
|
51
|
+
export function transform(inputs) {
|
|
52
|
+
return builtinActionSpec({ kind: 'transform', inputs });
|
|
53
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FlowVersionedNodeType } from '../../../flow-node-type.js';
|
|
2
|
+
import { type TransformInputs } from './spec.js';
|
|
3
|
+
export type TransformSpec = {
|
|
4
|
+
kind: 'transform';
|
|
5
|
+
inputs: TransformInputs;
|
|
6
|
+
};
|
|
7
|
+
export declare const transformNodeTypes: FlowVersionedNodeType<TransformSpec>[];
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The four Transform node types: the generic chaining `core.action.transform`
|
|
3
|
+
* and its single-purpose `.filter`, `.map` and `.group-by` variants, each bundled
|
|
4
|
+
* at 1.0.0 and 1.1. They share the `transform` kind; `inputs.variant` picks one
|
|
5
|
+
* (`matches`). Moved from serialize.ts / check.ts / decompile.ts in Phase 4 of
|
|
6
|
+
* docs/NODE_TYPE_ARCHITECTURE_DESIGN.md; serialized output, printed source,
|
|
7
|
+
* codes and messages unchanged.
|
|
8
|
+
*/
|
|
9
|
+
import { Expr } from '../../../core/expr.js';
|
|
10
|
+
import { jsonClone } from '../../../core/json-file.js';
|
|
11
|
+
import { VARIANT_OPERATION } from './spec.js';
|
|
12
|
+
import { checkTransform } from './check.js';
|
|
13
|
+
/**
|
|
14
|
+
* Emit a transform's `inputs` in the canonical shape the node's runtime reads:
|
|
15
|
+
* `collection` as a BARE variable path (not `=js:`-prefixed — it is a path
|
|
16
|
+
* field, and the runtime turns the string into a lookup), and `operations` as
|
|
17
|
+
* the array of `{ id, type, config }` descriptors the designer writes.
|
|
18
|
+
*
|
|
19
|
+
* Ids are synthesized here rather than asked of the author, the same way switch
|
|
20
|
+
* case ids are: they identify a row in the designer's editor and carry no
|
|
21
|
+
* meaning for the author. Defaults are made explicit for the same reason the
|
|
22
|
+
* HTTP case spells out `method`/`contentType` — the emitted file should say
|
|
23
|
+
* what it does rather than rely on the runtime's fallbacks.
|
|
24
|
+
*/
|
|
25
|
+
function transformInputs(inputs, ctx) {
|
|
26
|
+
const operations = (inputs.operations ?? []).map((op, i) => {
|
|
27
|
+
const id = `op${i + 1}`;
|
|
28
|
+
if (op.type === 'filter') {
|
|
29
|
+
return {
|
|
30
|
+
id,
|
|
31
|
+
type: 'filter',
|
|
32
|
+
config: {
|
|
33
|
+
operation: op.operation ?? 'and',
|
|
34
|
+
filters: (op.filters ?? []).map((f, j) => ({
|
|
35
|
+
id: `f${j + 1}`,
|
|
36
|
+
field: f.field,
|
|
37
|
+
condition: f.condition,
|
|
38
|
+
// Value-free conditions (is_null, is_empty, …) legitimately omit it.
|
|
39
|
+
...(f.value !== undefined ? { value: f.value } : {}),
|
|
40
|
+
})),
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (op.type === 'map') {
|
|
45
|
+
return {
|
|
46
|
+
id,
|
|
47
|
+
type: 'map',
|
|
48
|
+
config: {
|
|
49
|
+
keepOriginalFields: op.keepOriginalFields ?? false,
|
|
50
|
+
mappings: (op.mappings ?? []).map((m, j) => ({
|
|
51
|
+
id: `m${j + 1}`,
|
|
52
|
+
field: m.field,
|
|
53
|
+
transformation: m.transformation ?? 'copy',
|
|
54
|
+
// '' is the runtime's "keep the original name" sentinel.
|
|
55
|
+
renameTo: m.renameTo ?? '',
|
|
56
|
+
})),
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
id,
|
|
62
|
+
type: 'groupBy',
|
|
63
|
+
config: {
|
|
64
|
+
groupByField: op.groupByField,
|
|
65
|
+
aggregations: (op.aggregations ?? []).map((a, j) => ({
|
|
66
|
+
id: `a${j + 1}`,
|
|
67
|
+
// `count` needs no field; the runtime expects the key present anyway.
|
|
68
|
+
field: a.field ?? '',
|
|
69
|
+
operation: a.operation,
|
|
70
|
+
alias: a.alias,
|
|
71
|
+
})),
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
return { collection: ctx.renameRefs(collectionPath(inputs.collection)), operations };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The `collection` string. A bare reference (`v('x')` / `out('s','p')`) is
|
|
79
|
+
* already the path the runtime wants, so it is emitted verbatim. Anything else
|
|
80
|
+
* cannot be expressed as a path — `check` rejects it (TRANSFORM_COLLECTION_*)
|
|
81
|
+
* before serialization, so reaching here with one means `compile` was called
|
|
82
|
+
* without a check; emit the raw text so the failure stays visible downstream
|
|
83
|
+
* rather than becoming a silently empty collection.
|
|
84
|
+
*/
|
|
85
|
+
function collectionPath(collection) {
|
|
86
|
+
if (collection instanceof Expr)
|
|
87
|
+
return collection.literal ? JSON.stringify(collection.value) : collection.js;
|
|
88
|
+
return String(collection);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* A transform node publishes a COLLECTION — always.
|
|
92
|
+
*
|
|
93
|
+
* All four transform definitions declare `output: {type: 'object', description:
|
|
94
|
+
* 'The transformed data result'}`, which makes the designer type
|
|
95
|
+
* `out('<step>')` as `Record<string, any>` and reject mapping it into an
|
|
96
|
+
* `array` flow output — the same defect as the script node's, one node type
|
|
97
|
+
* over, and it hits five of the shipped examples.
|
|
98
|
+
*
|
|
99
|
+
* Unlike a script this needs no inference and no author declaration, because it
|
|
100
|
+
* is not a property of the particular node: `filter` and `map` are array→array,
|
|
101
|
+
* and `group-by` is too — the engine's own implementation says so in as many
|
|
102
|
+
* words (`transform-operations.ts`: "Always return an array", returning
|
|
103
|
+
* `Array.from(groups.entries()).map(…)` rather than an object keyed by group).
|
|
104
|
+
* So the type is knowable from the node TYPE alone, and is simply written down.
|
|
105
|
+
*/
|
|
106
|
+
function transformOutputs(base) {
|
|
107
|
+
// An unrecognized `variant` resolves to no definition at all, so there are no
|
|
108
|
+
// outputs to refine — and `jsonClone(undefined)` throws ("undefined" is not valid
|
|
109
|
+
// JSON) rather than passing the node through.
|
|
110
|
+
if (!base || typeof base !== 'object')
|
|
111
|
+
return base;
|
|
112
|
+
const out = jsonClone(base);
|
|
113
|
+
if (out.output)
|
|
114
|
+
out.output.type = 'array';
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
// ─── The lift ──────────────────────────────────────────────────────────────────
|
|
118
|
+
/**
|
|
119
|
+
* A Transform node back as its spec: `collection` as the bare path the
|
|
120
|
+
* serializer writes (an Expr; absent when the node has none), and each operation
|
|
121
|
+
* from its `{ id, type, config }` descriptor. Values stay as the file has them —
|
|
122
|
+
* the printer decides what to write, exactly as the decompiler always did.
|
|
123
|
+
*/
|
|
124
|
+
function liftTransform(node, variant, ctx) {
|
|
125
|
+
const inputs = node.inputs ?? {};
|
|
126
|
+
const raw = ctx.sourceText(inputs.collection);
|
|
127
|
+
const ops = Array.isArray(inputs.operations) ? inputs.operations : [];
|
|
128
|
+
const operations = ops.map((op) => {
|
|
129
|
+
const cfg = op?.config ?? {};
|
|
130
|
+
if (op?.type === 'filter') {
|
|
131
|
+
return { type: 'filter', operation: cfg.operation, filters: (cfg.filters ?? []).map((f) => ({ field: f.field, condition: f.condition, ...(f.value !== undefined ? { value: f.value } : {}) })) };
|
|
132
|
+
}
|
|
133
|
+
if (op?.type === 'map') {
|
|
134
|
+
return { type: 'map', keepOriginalFields: cfg.keepOriginalFields, mappings: (cfg.mappings ?? []).map((m) => ({ field: m.field, transformation: m.transformation, renameTo: m.renameTo })) };
|
|
135
|
+
}
|
|
136
|
+
// Anything else prints as a groupBy, as the decompiler always read it.
|
|
137
|
+
return { type: 'groupBy', groupByField: cfg.groupByField, aggregations: (cfg.aggregations ?? []).map((a) => ({ operation: a.operation, alias: a.alias, field: a.field })) };
|
|
138
|
+
});
|
|
139
|
+
return {
|
|
140
|
+
kind: 'transform',
|
|
141
|
+
inputs: {
|
|
142
|
+
collection: (raw !== undefined ? new Expr(raw.startsWith('=js:') ? raw.slice(4) : raw) : undefined),
|
|
143
|
+
...(variant ? { variant } : {}),
|
|
144
|
+
operations: operations,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/** `{ k: v, … }` from entries (the decompiler's `objLit`): `''` when there are none. */
|
|
149
|
+
function obj(entries, ctx) {
|
|
150
|
+
return entries.length === 0 ? '' : `{ ${entries.map(([k, v]) => `${ctx.key(k)}: ${v}`).join(', ')} }`;
|
|
151
|
+
}
|
|
152
|
+
/** The spec as `transform({ collection, variant?, operations })`, as the decompiler wrote it. */
|
|
153
|
+
function printTransform({ inputs }, ctx) {
|
|
154
|
+
const s = (v) => ctx.string(v);
|
|
155
|
+
const opSrcs = (inputs.operations ?? []).map((op) => {
|
|
156
|
+
if (op.type === 'filter') {
|
|
157
|
+
const filters = (op.filters ?? []).map((f) => obj([
|
|
158
|
+
['field', s(f.field)],
|
|
159
|
+
['condition', s(f.condition)],
|
|
160
|
+
...(f.value !== undefined ? [['value', s(f.value)]] : []),
|
|
161
|
+
], ctx));
|
|
162
|
+
return obj([
|
|
163
|
+
['type', s('filter')],
|
|
164
|
+
...(op.operation !== undefined ? [['operation', s(op.operation)]] : []),
|
|
165
|
+
['filters', `[${filters.join(', ')}]`],
|
|
166
|
+
], ctx);
|
|
167
|
+
}
|
|
168
|
+
if (op.type === 'map') {
|
|
169
|
+
const mappings = (op.mappings ?? []).map((m) => obj([
|
|
170
|
+
['field', s(m.field)],
|
|
171
|
+
...(m.transformation && m.transformation !== 'copy' ? [['transformation', s(m.transformation)]] : []),
|
|
172
|
+
...(m.renameTo ? [['renameTo', s(m.renameTo)]] : []),
|
|
173
|
+
], ctx));
|
|
174
|
+
return obj([
|
|
175
|
+
['type', s('map')],
|
|
176
|
+
...(op.keepOriginalFields ? [['keepOriginalFields', op.keepOriginalFields ? 'true' : 'false']] : []),
|
|
177
|
+
['mappings', `[${mappings.join(', ')}]`],
|
|
178
|
+
], ctx);
|
|
179
|
+
}
|
|
180
|
+
const aggs = (op.aggregations ?? []).map((a) => obj([
|
|
181
|
+
['operation', s(a.operation)],
|
|
182
|
+
['alias', s(a.alias)],
|
|
183
|
+
...(a.field ? [['field', s(a.field)]] : []),
|
|
184
|
+
], ctx));
|
|
185
|
+
return obj([
|
|
186
|
+
['type', s('groupBy')],
|
|
187
|
+
['groupByField', s(op.groupByField)],
|
|
188
|
+
['aggregations', `[${aggs.join(', ')}]`],
|
|
189
|
+
], ctx);
|
|
190
|
+
});
|
|
191
|
+
const collection = inputs.collection !== undefined ? ctx.value(inputs.collection) : `${ctx.helper('lit')}([])`;
|
|
192
|
+
return {
|
|
193
|
+
factory: 'transform',
|
|
194
|
+
options: [
|
|
195
|
+
['collection', collection],
|
|
196
|
+
['variant', inputs.variant ? s(inputs.variant) : undefined],
|
|
197
|
+
['operations', `[${opSrcs.join(', ')}]`],
|
|
198
|
+
],
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
// ─── The four node types ───────────────────────────────────────────────────────
|
|
202
|
+
const VARIANTS = Object.keys(VARIANT_OPERATION);
|
|
203
|
+
function transformAt(typeName, variant, version, factory) {
|
|
204
|
+
return {
|
|
205
|
+
kind: 'transform', typeName, version, factory: 'transform', definition: 'bundled',
|
|
206
|
+
rawNode: { factory },
|
|
207
|
+
serialize: ({ inputs }, ctx) => {
|
|
208
|
+
// Only the generic type matches an UNKNOWN variant, so check reports it
|
|
209
|
+
// (TRANSFORM_VARIANT_UNKNOWN). A compile that skipped check refuses here
|
|
210
|
+
// rather than emit the generic node, which would run and be the wrong node.
|
|
211
|
+
if (variant === undefined && inputs?.variant !== undefined && inputs.variant !== null) {
|
|
212
|
+
throw new Error(`transform step "${ctx.step}": variant ${JSON.stringify(inputs.variant)} is not a Transform node type `
|
|
213
|
+
+ `(${VARIANTS.join(', ')}), so there is no node to emit. Fix the variant, or omit it for the generic Transform.`);
|
|
214
|
+
}
|
|
215
|
+
const base = ctx.definition(typeName, version)?.outputDefinition;
|
|
216
|
+
const typed = transformOutputs(base);
|
|
217
|
+
return { inputs: transformInputs(inputs, ctx), ...(typed !== base ? { outputs: typed } : {}) };
|
|
218
|
+
},
|
|
219
|
+
deserialize: (node, ctx) => liftTransform(node, variant, ctx),
|
|
220
|
+
print: printTransform,
|
|
221
|
+
check: ({ inputs }, ctx) => checkTransform(inputs, ctx),
|
|
222
|
+
// The only expression a transform carries is its collection; everything else
|
|
223
|
+
// is a literal or a field name (see checkTransform).
|
|
224
|
+
expressions: ({ inputs }) => [{ value: inputs.collection }],
|
|
225
|
+
output: () => ({ kind: 'opaque' }),
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
function transformType(typeName, variant, factory) {
|
|
229
|
+
return {
|
|
230
|
+
kind: 'transform', typeName, factory: 'transform', defaultVersion: '1.0.0',
|
|
231
|
+
versions: { '1.0.0': transformAt(typeName, variant, '1.0.0', factory), '1.1': transformAt(typeName, variant, '1.1', factory) },
|
|
232
|
+
// The generic type is the one for any spec without a KNOWN variant — an unknown
|
|
233
|
+
// one included, so check still reports it (see serialize above).
|
|
234
|
+
matches: ({ inputs }) => (variant === undefined
|
|
235
|
+
? !VARIANTS.includes(inputs?.variant)
|
|
236
|
+
: inputs?.variant === variant),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
export const transformNodeTypes = [
|
|
240
|
+
transformType('core.action.transform', undefined, 'transform()'),
|
|
241
|
+
transformType('core.action.transform.filter', 'filter', "transform({ variant: 'filter' })"),
|
|
242
|
+
transformType('core.action.transform.map', 'map', "transform({ variant: 'map' })"),
|
|
243
|
+
transformType('core.action.transform.group-by', 'group-by', "transform({ variant: 'group-by' })"),
|
|
244
|
+
];
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Transform family's authoring types (`core.action.transform` and its
|
|
3
|
+
* `.filter`, `.map`, `.group-by` variants), and its kind's entry in
|
|
4
|
+
* `FlowActionSpecs`. Moved from core/actions.ts in Phase 4 of
|
|
5
|
+
* docs/NODE_TYPE_ARCHITECTURE_DESIGN.md.
|
|
6
|
+
*/
|
|
7
|
+
import type { Expr } from '../../../core/expr.js';
|
|
8
|
+
/** How a filter combines its rules: every rule must match, or any one. */
|
|
9
|
+
export type FilterMatch = 'and' | 'or';
|
|
10
|
+
/** Comparison a filter rule applies to a field. */
|
|
11
|
+
export type FilterCondition = 'equals' | 'not_equals' | 'greater_than' | 'less_than' | 'greater_equal' | 'less_equal' | 'contains' | 'not_contains' | 'starts_with' | 'not_starts_with' | 'ends_with' | 'not_ends_with' | 'matches_regex' | 'in' | 'not_in' | 'is_null' | 'is_not_null' | 'is_empty' | 'is_not_empty';
|
|
12
|
+
export interface FilterRule {
|
|
13
|
+
/** Field on each item. Dot-paths reach nested fields (`'order.amount'`). */
|
|
14
|
+
field: string;
|
|
15
|
+
condition: FilterCondition;
|
|
16
|
+
/**
|
|
17
|
+
* What to compare against — a LITERAL only. The transform runtime reads this
|
|
18
|
+
* value as-is and evaluates nothing, so an expression here would compare every
|
|
19
|
+
* item against that text and match nothing. Hence `Expr` is not accepted: for
|
|
20
|
+
* a dynamic threshold, filter in a `script` step instead.
|
|
21
|
+
* Omit for the value-free conditions (`is_null`, `is_empty`, …).
|
|
22
|
+
*/
|
|
23
|
+
value?: string | number | boolean | null;
|
|
24
|
+
}
|
|
25
|
+
/** What a map does to a field's value. Only `copy` is meaningful for non-text. */
|
|
26
|
+
export type Transformation = 'copy' | 'uppercase' | 'lowercase' | 'trim';
|
|
27
|
+
export interface FieldMapping {
|
|
28
|
+
/** Field to carry into the output. Must exist on the item, or it is skipped. */
|
|
29
|
+
field: string;
|
|
30
|
+
/** Defaults to `'copy'` (the value unchanged). */
|
|
31
|
+
transformation?: Transformation;
|
|
32
|
+
/** Output field name. Omit to keep `field`'s own name. */
|
|
33
|
+
renameTo?: string;
|
|
34
|
+
}
|
|
35
|
+
export type AggregationOperation = 'count' | 'sum' | 'average' | 'min' | 'max' | 'first' | 'last' | 'collect';
|
|
36
|
+
export interface Aggregation {
|
|
37
|
+
operation: AggregationOperation;
|
|
38
|
+
/** Output field name for the aggregate. Required. */
|
|
39
|
+
alias: string;
|
|
40
|
+
/** Field to aggregate. Required for every operation except `count`. */
|
|
41
|
+
field?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* One link in the chain. Operations run in the order given, and each one's
|
|
45
|
+
* result is the next one's input — so a `map` that drops a field puts it out of
|
|
46
|
+
* reach of a later `filter`.
|
|
47
|
+
*/
|
|
48
|
+
export type TransformOperation = {
|
|
49
|
+
type: 'filter';
|
|
50
|
+
filters: FilterRule[];
|
|
51
|
+
operation?: FilterMatch;
|
|
52
|
+
} | {
|
|
53
|
+
type: 'map';
|
|
54
|
+
mappings: FieldMapping[];
|
|
55
|
+
keepOriginalFields?: boolean;
|
|
56
|
+
} | {
|
|
57
|
+
type: 'groupBy';
|
|
58
|
+
groupByField: string;
|
|
59
|
+
aggregations?: Aggregation[];
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Which Transform node type to emit.
|
|
63
|
+
*
|
|
64
|
+
* @remarks
|
|
65
|
+
* The platform ships four: the generic `core.action.transform`, which chains N
|
|
66
|
+
* operations, plus three single-purpose variants that each run exactly one.
|
|
67
|
+
* They share ONE runtime — flow-v1 routes all four node types through the same
|
|
68
|
+
* script generators and dispatches on the OPERATION's `type`, never the node's
|
|
69
|
+
* (`bpmn-to-xml.ts`'s `DATA_TRANSFORM_NODE_TYPES` / `generateDataTransformScript`).
|
|
70
|
+
* So a variant is the generic constrained to one operation, wearing a
|
|
71
|
+
* self-describing node type and its own editor in the designer.
|
|
72
|
+
*
|
|
73
|
+
* Note the spelling: the node type is `core.action.transform.group-by`
|
|
74
|
+
* (hyphen), while the operation it carries is `type: 'groupBy'` (camelCase) —
|
|
75
|
+
* that mismatch is the platform's, not ours.
|
|
76
|
+
*/
|
|
77
|
+
export type TransformVariant = 'map' | 'filter' | 'group-by';
|
|
78
|
+
/**
|
|
79
|
+
* The operation `type` each variant node must carry — one of, and only.
|
|
80
|
+
*
|
|
81
|
+
* @internal Serializer plumbing; an author states the variant, not the mapping.
|
|
82
|
+
*/
|
|
83
|
+
export declare const VARIANT_OPERATION: Record<TransformVariant, TransformOperation['type']>;
|
|
84
|
+
export interface TransformInputs {
|
|
85
|
+
/**
|
|
86
|
+
* The array to transform, as a REFERENCE: `v('catalog')` or
|
|
87
|
+
* `out('fetchOrders', 'body.items')`.
|
|
88
|
+
*
|
|
89
|
+
* This is a variable PATH, not a value field — the runtime turns the string
|
|
90
|
+
* into a lookup. An inline array or a computed `js` expression therefore
|
|
91
|
+
* resolves to nothing, which is why the type is `Expr` and `check` rejects
|
|
92
|
+
* anything that is not a bare `$vars.…` path. Keep static data in a
|
|
93
|
+
* `.var(name, types.array, [...])` default and point here.
|
|
94
|
+
*/
|
|
95
|
+
collection: Expr;
|
|
96
|
+
/**
|
|
97
|
+
* Emit a single-purpose variant node instead of the generic Transform.
|
|
98
|
+
* Omit it for the generic (the default).
|
|
99
|
+
*
|
|
100
|
+
* With a variant, `operations` must hold exactly ONE operation of the
|
|
101
|
+
* matching type — `'filter'` → `type: 'filter'`, `'map'` → `type: 'map'`,
|
|
102
|
+
* `'group-by'` → `type: 'groupBy'`. `check` rejects anything else, naming
|
|
103
|
+
* both the variant and the operation it found.
|
|
104
|
+
*/
|
|
105
|
+
variant?: TransformVariant;
|
|
106
|
+
/** At least one operation — an empty chain is a no-op node. */
|
|
107
|
+
operations: TransformOperation[];
|
|
108
|
+
}
|
|
109
|
+
declare module '../../../core/actions.js' {
|
|
110
|
+
interface FlowActionSpecs {
|
|
111
|
+
/** The spec {@link transform} builds. */
|
|
112
|
+
transform: {
|
|
113
|
+
inputs: TransformInputs;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The operation `type` each variant node must carry — one of, and only.
|
|
3
|
+
*
|
|
4
|
+
* @internal Serializer plumbing; an author states the variant, not the mapping.
|
|
5
|
+
*/
|
|
6
|
+
export const VARIANT_OPERATION = {
|
|
7
|
+
map: 'map',
|
|
8
|
+
filter: 'filter',
|
|
9
|
+
'group-by': 'groupBy',
|
|
10
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { FlowNodeType } from './flow-node-type.js';
|
|
2
|
+
/**
|
|
3
|
+
* The registered node type a raw node of `nodeType@version` is, at that version
|
|
4
|
+
* when it is registered and at the default otherwise (a raw node is often how an
|
|
5
|
+
* author reaches an unregistered version); undefined for an unregistered type.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registeredRawType(nodeType: unknown, version: string): {
|
|
8
|
+
impl: FlowNodeType<unknown>;
|
|
9
|
+
} | undefined;
|
|
10
|
+
/** An input a registered node type never reads, as RAW_NODE_UNKNOWN_INPUT reports it; undefined otherwise. */
|
|
11
|
+
export declare function rawNodeInputProblem(nodeType: unknown, version: string, inputs: unknown): {
|
|
12
|
+
severity: 'error' | 'warning';
|
|
13
|
+
message: string;
|
|
14
|
+
} | undefined;
|
|
15
|
+
/** RAW_NODE_TYPED_FAMILY for a raw node of a type with a typed factory — registered, or not yet ported. */
|
|
16
|
+
export declare function rawNodeTypedFamilyWarning(nodeType: string): string | undefined;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What `rawNode` and the serializer ask about a raw node: whether its type is
|
|
3
|
+
* registered, an input that type never reads, and the typed factory to prefer.
|
|
4
|
+
* Internal — kept apart from raw-node.ts so the package entry, which re-exports
|
|
5
|
+
* that module, exports only `rawNode` itself.
|
|
6
|
+
*/
|
|
7
|
+
import { typedFactoryWarning, typedFamilyRawNodeWarning as tableWarning } from './core/typed-raw-node.js';
|
|
8
|
+
import { hasBundledDefinition } from './flow-definitions.js';
|
|
9
|
+
import { FLOW_NODE_TYPES } from './flow-node-registry.js';
|
|
10
|
+
/**
|
|
11
|
+
* The registered node type a raw node of `nodeType@version` is, at that version
|
|
12
|
+
* when it is registered and at the default otherwise (a raw node is often how an
|
|
13
|
+
* author reaches an unregistered version); undefined for an unregistered type.
|
|
14
|
+
*/
|
|
15
|
+
export function registeredRawType(nodeType, version) {
|
|
16
|
+
const entry = typeof nodeType === 'string' ? FLOW_NODE_TYPES.byTypeName(nodeType) : undefined;
|
|
17
|
+
if (!entry)
|
|
18
|
+
return undefined;
|
|
19
|
+
const registered = Object.hasOwn(entry.type.versions, version);
|
|
20
|
+
const impl = (registered ? entry.type.versions[version] : entry.type.versions[entry.type.defaultVersion]);
|
|
21
|
+
return { impl };
|
|
22
|
+
}
|
|
23
|
+
/** An input a registered node type never reads, as RAW_NODE_UNKNOWN_INPUT reports it; undefined otherwise. */
|
|
24
|
+
export function rawNodeInputProblem(nodeType, version, inputs) {
|
|
25
|
+
const found = registeredRawType(nodeType, version);
|
|
26
|
+
// `bundled` is the bundle's answer, not the registry's: a version the SDK ships
|
|
27
|
+
// but no node type lists yet still has a known key set (and an error).
|
|
28
|
+
return found?.impl.rawNode?.inputProblem?.(inputs, version, hasBundledDefinition(nodeType, version));
|
|
29
|
+
}
|
|
30
|
+
/** RAW_NODE_TYPED_FAMILY for a raw node of a type with a typed factory — registered, or not yet ported. */
|
|
31
|
+
export function rawNodeTypedFamilyWarning(nodeType) {
|
|
32
|
+
const advice = registeredRawType(nodeType, '')?.impl.rawNode;
|
|
33
|
+
if (advice)
|
|
34
|
+
return typedFactoryWarning(nodeType, advice.factory, advice.hint);
|
|
35
|
+
return tableWarning(nodeType);
|
|
36
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
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
|
+
/**
|
|
10
|
+
* Place a node this SDK has no factory for, carrying its definition verbatim
|
|
11
|
+
* (`uipath.exotic.thing@2.1` and the manifest the platform served for it).
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* This is the escape hatch the coverage plan requires: an unknown registry
|
|
15
|
+
* definition is expressible without bypassing serializer invariants. The
|
|
16
|
+
* serializer still owns the node's id, label, `typeVersion` and edge wiring; you
|
|
17
|
+
* supply which definition and which inputs, exactly as a hand-written
|
|
18
|
+
* {@link FlowAction} subclass would.
|
|
19
|
+
*
|
|
20
|
+
* It is also what `decompile` emits for a node type it cannot name, so a
|
|
21
|
+
* round trip preserves the node's TYPE and VERSION instead of degrading it to a
|
|
22
|
+
* placeholder:
|
|
23
|
+
*
|
|
24
|
+
* ```ts
|
|
25
|
+
* .step('exotic', rawNode({
|
|
26
|
+
* nodeType: 'uipath.exotic.thing',
|
|
27
|
+
* version: '2.1',
|
|
28
|
+
* manifest: exoticManifest, // exactly what `registry get` returned
|
|
29
|
+
* inputs: { where: input('scope') },
|
|
30
|
+
* }))
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* `manifest` must be a real definition — an exact copy of what the registry or
|
|
34
|
+
* Workbench serves for that `nodeType@version`. It is not permission to invent
|
|
35
|
+
* one: the platform resolves the node against its own catalog at run time, so a
|
|
36
|
+
* hand-written manifest validates locally and fails on the tenant.
|
|
37
|
+
*
|
|
38
|
+
* Prefer a typed factory when one exists — it carries the family's checks, its
|
|
39
|
+
* defaults, and its output contract, none of which a raw node can know.
|
|
40
|
+
*
|
|
41
|
+
* **Never for a connector.** A `uipath.connector.*` node type is refused by
|
|
42
|
+
* `check` and `compile`: a raw node carries the author's inputs verbatim, so the
|
|
43
|
+
* emitted node has no `inputs.detail` and no connection binding — `validate`
|
|
44
|
+
* only warns ("Connector is not configured") and the run can never reach
|
|
45
|
+
* Integration Service. Use {@link connector}, and `registry prepare` when
|
|
46
|
+
* compile reports an input the static library does not carry; use
|
|
47
|
+
* {@link onEvent} for a connector event trigger.
|
|
48
|
+
*
|
|
49
|
+
* **Prefer the typed factory** for a node type that has one: `check` warns
|
|
50
|
+
* (`RAW_NODE_TYPED_FAMILY`), because `validate` cannot see an input the
|
|
51
|
+
* registry definition does not declare. For a `core.datafabric.*` type, a key
|
|
52
|
+
* the product never reads (an invented `_sortOptions` in place of `_sort`) is
|
|
53
|
+
* an error at a version the SDK bundles (`RAW_NODE_UNKNOWN_INPUT`); the
|
|
54
|
+
* canvas's snapshots, such as the `_entityFields` a related-path filter
|
|
55
|
+
* needs, stay legal.
|
|
56
|
+
*
|
|
57
|
+
* @param spec - The definition to compile against, plus the node's inputs.
|
|
58
|
+
* @returns A node to pass to `.step(...)`.
|
|
59
|
+
*/
|
|
60
|
+
export declare function rawNode(spec: {
|
|
61
|
+
/** The definition's `nodeType`, verbatim. */
|
|
62
|
+
nodeType: string;
|
|
63
|
+
/** The exact definition version; also becomes the node's `typeVersion`. */
|
|
64
|
+
version: string;
|
|
65
|
+
/** The complete node manifest, exactly as the platform serves it. */
|
|
66
|
+
manifest: unknown;
|
|
67
|
+
/** The node's `inputs`. `Expr` values render through the usual pipeline. */
|
|
68
|
+
inputs?: Record<string, unknown>;
|
|
69
|
+
/** Overrides for the node's `outputs`; rarely needed. */
|
|
70
|
+
outputs?: Record<string, unknown>;
|
|
71
|
+
}): FlowAction;
|