@uipath/maestro-builder-sdk 6.17.5 → 6.18.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/bindings-v2.js +15 -17
- package/dist/bpmn/bpmn-sdk.js +3 -2
- package/dist/bpmn/check.js +3 -2
- package/dist/bpmn/decompile.js +123 -137
- package/dist/bpmn/intsvc.js +7 -2
- package/dist/bpmn/serialize.js +1 -1
- package/dist/bpmn/typed-node.js +5 -4
- package/dist/case/compile-cli.js +1 -3
- package/dist/case/decompile.js +103 -109
- package/dist/case/entry-points.js +2 -1
- package/dist/case/merge.js +3 -5
- package/dist/case/serialize.js +1 -1
- package/dist/check.js +26 -10
- package/dist/core/ceql.js +5 -2
- package/dist/core/connector-inputs.js +4 -4
- package/dist/core/event-checks.js +17 -2
- package/dist/core/event-filters.d.ts +38 -4
- package/dist/core/event-filters.js +63 -7
- package/dist/core/expr.d.ts +1 -1
- package/dist/core/expr.js +3 -3
- package/dist/core/json-file.d.ts +2 -0
- package/dist/core/json-file.js +4 -0
- package/dist/core/library.js +2 -1
- package/dist/core/node-envelope.d.ts +1 -0
- package/dist/core/node-envelope.js +1 -1
- package/dist/core/own-entry.d.ts +9 -0
- package/dist/core/own-entry.js +11 -0
- package/dist/core/ts-literal.d.ts +22 -0
- package/dist/core/ts-literal.js +37 -0
- package/dist/core/typed-raw-node.js +4 -3
- package/dist/decompile.js +272 -300
- package/dist/merge.js +10 -12
- package/dist/registry/compat/pystr.d.ts +2 -0
- package/dist/registry/compat/pystr.js +35 -0
- package/dist/registry/compat/pyvalue.d.ts +16 -0
- package/dist/registry/compat/pyvalue.js +35 -0
- package/dist/registry/generators/markdown/pyvalue.d.ts +1 -4
- package/dist/registry/generators/markdown/pyvalue.js +2 -30
- package/dist/registry/generators/markdown/sections/inputs.js +3 -2
- package/dist/registry/generators/type-tree.d.ts +1 -7
- package/dist/registry/generators/type-tree.js +5 -22
- package/dist/registry/library-build/build.js +6 -6
- package/dist/registry/library-build/canonical.js +25 -25
- package/dist/registry/library-build/context.js +5 -5
- package/dist/registry/library-build/enrich.js +18 -18
- package/dist/registry/library-build/events.js +25 -24
- package/dist/registry/library-build/generic-expand.js +21 -20
- package/dist/registry/library-build/plan.js +8 -8
- package/dist/registry/library-build/py.d.ts +3 -10
- package/dist/registry/library-build/py.js +9 -52
- package/dist/registry/library-build/schema-action.js +6 -6
- package/dist/registry/prepare/event.js +2 -2
- package/dist/registry/prepare/source-import.js +2 -9
- package/dist/registry/prepare/source-labels.js +2 -9
- package/dist/registry/prepare/support.d.ts +2 -6
- package/dist/registry/prepare/support.js +3 -58
- package/dist/registry/pull-cli.js +6 -14
- package/dist/registry/search-cli.js +2 -2
- package/dist/schema-version.js +0 -1
- package/dist/serialize.js +86 -76
- package/package.json +2 -2
package/dist/decompile.js
CHANGED
|
@@ -36,6 +36,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
36
36
|
import { inferScriptShape } from './core/script-return.js';
|
|
37
37
|
import { DEFAULT_TRIGGER_ID } from './core/expr.js';
|
|
38
38
|
import { commentText } from './core/comment-text.js';
|
|
39
|
+
import { tsLiteral, tsNumber, tsText } from './core/ts-literal.js';
|
|
39
40
|
import { parseIxpProjectType } from './core/actions.js';
|
|
40
41
|
import { readFlowGlobals } from './flow-variables.js';
|
|
41
42
|
import { missingBindingLabels } from './core/binding-messages.js';
|
|
@@ -127,11 +128,11 @@ function verClause(node) {
|
|
|
127
128
|
const shipped = [...CORE_DEFINITION_KEYS]
|
|
128
129
|
.filter((k) => k.startsWith(`${node.type}@`))
|
|
129
130
|
.map((k) => k.slice(node.type.length + 1));
|
|
130
|
-
warnOnce(`node ${
|
|
131
|
-
+ `\`compile\` will refuse the emitted { version: ${
|
|
131
|
+
warnOnce(`node ${tsLiteral(node.id)} pins ${node.type}@${tv}, but this SDK bundles ${node.type}@${shipped.join(', ') || '<none>'} only; `
|
|
132
|
+
+ `\`compile\` will refuse the emitted { version: ${tsLiteral(tv)} } (versions resolve exactly, flow-builder-sdk#71). `
|
|
132
133
|
+ `The source keeps the file's pair; to recompile, drop that { version } and the node takes the SDK's pinned version.`);
|
|
133
134
|
}
|
|
134
|
-
return `version: ${
|
|
135
|
+
return `version: ${tsLiteral(tv)}`;
|
|
135
136
|
}
|
|
136
137
|
function verArg(node) {
|
|
137
138
|
const clause = verClause(node);
|
|
@@ -148,7 +149,7 @@ function triggerOptParts(node) {
|
|
|
148
149
|
parts.push(ver);
|
|
149
150
|
const label = node.display?.label;
|
|
150
151
|
if (typeof label === 'string' && label !== definitionLabel(node))
|
|
151
|
-
parts.push(`label: ${
|
|
152
|
+
parts.push(`label: ${tsLiteral(label)}`);
|
|
152
153
|
return parts;
|
|
153
154
|
}
|
|
154
155
|
/** `triggerOptParts` as the `.trigger(spec, { ... })` options argument. */
|
|
@@ -176,7 +177,7 @@ function optsArgWith(node, ctx, extra) {
|
|
|
176
177
|
// compile. Equal-to-default is omitted so ordinary flows stay quiet.
|
|
177
178
|
const label = node.display?.label;
|
|
178
179
|
if (typeof label === 'string' && label !== node.id)
|
|
179
|
-
parts.push(`label: ${
|
|
180
|
+
parts.push(`label: ${tsLiteral(label)}`);
|
|
180
181
|
const updates = ctx.flow.variables?.variableUpdates?.[node.id] ?? [];
|
|
181
182
|
if (updates.length) {
|
|
182
183
|
const entries = updates.map((u) => `${key(u.variableId)}: ${emitVal(u.expression, ctx.imp, ctx.inputNames)}`);
|
|
@@ -233,27 +234,13 @@ function isTrigger(type) {
|
|
|
233
234
|
return type.startsWith('core.trigger.') || type.startsWith('uipath.connector.event.') || type.startsWith('uipath.connector.trigger.');
|
|
234
235
|
}
|
|
235
236
|
// ─── Injection-safe source emitters (ported verbatim from case/decompile.ts) ──
|
|
236
|
-
/**
|
|
237
|
-
* A JS/TS string literal (double-quoted, correctly escaped). `JSON.stringify`
|
|
238
|
-
* escapes quotes, backslashes and control chars — so untrusted `.flow` values
|
|
239
|
-
* (labels, expressions, code) can never break out of the literal. We also escape
|
|
240
|
-
* U+2028/U+2029 (legal in JSON, historically illegal in JS string literals).
|
|
241
|
-
* Non-string input still serializes to inert JSON (never executable).
|
|
242
|
-
*/
|
|
243
|
-
function str(s) {
|
|
244
|
-
return JSON.stringify(s).replace(/[\u2028\u2029]/g, (c) => '\\u' + c.charCodeAt(0).toString(16));
|
|
245
|
-
}
|
|
246
237
|
/** A boolean literal, coerced so an untrusted non-boolean can never reach source verbatim. */
|
|
247
238
|
function boolLit(v) {
|
|
248
239
|
return v ? 'true' : 'false';
|
|
249
240
|
}
|
|
250
241
|
/** An object key: a bare identifier when legal, otherwise a quoted string. */
|
|
251
242
|
function key(k) {
|
|
252
|
-
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(k) ? k :
|
|
253
|
-
}
|
|
254
|
-
/** An arbitrary JSON-serializable value as a TS literal (used for var defaults). */
|
|
255
|
-
function literal(v) {
|
|
256
|
-
return JSON.stringify(v);
|
|
243
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(k) ? k : tsLiteral(k);
|
|
257
244
|
}
|
|
258
245
|
/** Render an options object from present entries; '' when nothing is present. */
|
|
259
246
|
function opts(entries) {
|
|
@@ -283,7 +270,7 @@ class Imports {
|
|
|
283
270
|
}
|
|
284
271
|
line(specifier) {
|
|
285
272
|
const names = [...this.used].sort();
|
|
286
|
-
return `import { ${names.join(', ')} } from ${
|
|
273
|
+
return `import { ${names.join(', ')} } from ${tsLiteral(specifier)};`;
|
|
287
274
|
}
|
|
288
275
|
}
|
|
289
276
|
// ─── Expression inversion ─────────────────────────────────────────────────────
|
|
@@ -344,7 +331,7 @@ function emitRef(jsBody, imp, inputNames) {
|
|
|
344
331
|
const PATH = '[A-Za-z_]\\w*(?:\\.[A-Za-z_]\\w*|\\[\\d+\\])*';
|
|
345
332
|
// !!$vars.<step>.output → ran('step')
|
|
346
333
|
if ((m = body.match(/^!!\$vars\.([A-Za-z_]\w*)\.output$/)))
|
|
347
|
-
return `${imp.use('ran')}(${
|
|
334
|
+
return `${imp.use('ran')}(${tsLiteral(m[1])})`;
|
|
348
335
|
// $vars.<step>.output[.<path>] → out('step'[, 'path'])
|
|
349
336
|
if ((m = body.match(new RegExp(`^\\$vars\\.([A-Za-z_]\\w*)\\.output(?:\\.(${PATH}))?$`)))) {
|
|
350
337
|
// A flow INPUT is published as the trigger's output, so
|
|
@@ -352,20 +339,20 @@ function emitRef(jsBody, imp, inputNames) {
|
|
|
352
339
|
// Recover the author's spelling rather than the mechanical `out('start', …)`;
|
|
353
340
|
// both re-serialize identically, but only one reads like the source.
|
|
354
341
|
if (m[1] === currentTriggerId && m[2] !== undefined && inputNames.has(m[2])) {
|
|
355
|
-
return `${imp.use('input')}(${
|
|
342
|
+
return `${imp.use('input')}(${tsLiteral(m[2])})`;
|
|
356
343
|
}
|
|
357
|
-
return m[2] === undefined ? `${imp.use('out')}(${
|
|
344
|
+
return m[2] === undefined ? `${imp.use('out')}(${tsLiteral(m[1])})` : `${imp.use('out')}(${tsLiteral(m[1])}, ${tsLiteral(m[2])})`;
|
|
358
345
|
}
|
|
359
346
|
// $vars.<step>.error[.<field>] → err('step'[, 'field'])
|
|
360
347
|
if ((m = body.match(new RegExp(`^\\$vars\\.([A-Za-z_]\\w*)\\.error(?:\\.(${PATH}))?$`)))) {
|
|
361
|
-
return m[2] === undefined ? `${imp.use('err')}(${
|
|
348
|
+
return m[2] === undefined ? `${imp.use('err')}(${tsLiteral(m[1])})` : `${imp.use('err')}(${tsLiteral(m[1])}, ${tsLiteral(m[2])})`;
|
|
362
349
|
}
|
|
363
350
|
// $vars.<name> → input('name') for a declared input, else v('name').
|
|
364
351
|
// The bare spelling predates flow inputs moving to `<trigger>.output.<name>`;
|
|
365
352
|
// still read it so an older artifact decompiles.
|
|
366
353
|
if ((m = body.match(/^\$vars\.([A-Za-z_]\w*)$/))) {
|
|
367
354
|
const name = m[1];
|
|
368
|
-
return inputNames.has(name) ? `${imp.use('input')}(${
|
|
355
|
+
return inputNames.has(name) ? `${imp.use('input')}(${tsLiteral(name)})` : `${imp.use('v')}(${tsLiteral(name)})`;
|
|
369
356
|
}
|
|
370
357
|
// Composite / unrecognized: a raw JS expression template.
|
|
371
358
|
return `${imp.use('js')}${jsTemplate(body)}`;
|
|
@@ -380,14 +367,17 @@ function emitRef(jsBody, imp, inputNames) {
|
|
|
380
367
|
* builder takes `Expr | string | unknown` (bare values pass through `toExpr`).
|
|
381
368
|
*/
|
|
382
369
|
function emitVal(v, imp, inputNames) {
|
|
370
|
+
// a present-but-undefined value stays the TS expression `undefined` (the behaviour this branch shipped; opts() drops an entry whose value is undefined before it reaches here)
|
|
371
|
+
if (v === undefined)
|
|
372
|
+
return 'undefined';
|
|
383
373
|
const raw = unwrapSource(v);
|
|
384
374
|
if (raw !== undefined && !Array.isArray(v)) {
|
|
385
375
|
if (raw.startsWith('=js:'))
|
|
386
376
|
return emitRef(raw.slice(4), imp, inputNames);
|
|
387
|
-
return
|
|
377
|
+
return tsLiteral(raw); // a literal string (valid as Expr via toExpr, or as a raw string input)
|
|
388
378
|
}
|
|
389
379
|
// A raw JSON literal (number / boolean / null / array / object).
|
|
390
|
-
return
|
|
380
|
+
return tsLiteral(v);
|
|
391
381
|
}
|
|
392
382
|
/** A bare (unprefixed) JS expression, as decision/switch nodes store it. */
|
|
393
383
|
function emitBareExpr(raw, imp, inputNames) {
|
|
@@ -530,7 +520,7 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
530
520
|
// infers from the body first (see `scriptOutputs`), so a script whose type
|
|
531
521
|
// is already plain in its code round-trips without it — emitting one there
|
|
532
522
|
// would add an argument the author never wrote to every such step.
|
|
533
|
-
return `${imp.use('script')}(${opts([['code',
|
|
523
|
+
return `${imp.use('script')}(${opts([['code', tsLiteral(code)], ...scriptReturnsOpt(node, code)])})`;
|
|
534
524
|
}
|
|
535
525
|
case T.delay: {
|
|
536
526
|
// serialize's `delayInputs` writes `{timerType, timerPreset, timerValue?}`
|
|
@@ -538,18 +528,18 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
538
528
|
// wait. Invert all three spellings.
|
|
539
529
|
if (inputs.timerType === 'timeDate') {
|
|
540
530
|
const until = typeof inputs.timerDate === 'string' ? inputs.timerDate : '';
|
|
541
|
-
return `${imp.use('delay')}(${opts([['until',
|
|
531
|
+
return `${imp.use('delay')}(${opts([['until', tsLiteral(until)]])})`;
|
|
542
532
|
}
|
|
543
533
|
const duration = inputs.timerPreset === 'custom'
|
|
544
534
|
? (typeof inputs.timerValue === 'string' ? inputs.timerValue : '')
|
|
545
535
|
: (typeof inputs.timerPreset === 'string' ? inputs.timerPreset : '');
|
|
546
|
-
return `${imp.use('delay')}(${opts([['duration',
|
|
536
|
+
return `${imp.use('delay')}(${opts([['duration', tsLiteral(duration)]])})`;
|
|
547
537
|
}
|
|
548
538
|
case T.documentClassify:
|
|
549
539
|
case T.dynamicExtract: {
|
|
550
540
|
const fr = unwrapSource(inputs.fileRef) ?? '';
|
|
551
|
-
const fileSrc = fr.startsWith('=js:') ? emitBareExpr(fr.slice(4), imp, inputNames) :
|
|
552
|
-
const pageRange = typeof inputs.pageRange === 'string' && inputs.pageRange !== '' ?
|
|
541
|
+
const fileSrc = fr.startsWith('=js:') ? emitBareExpr(fr.slice(4), imp, inputNames) : tsLiteral(fr);
|
|
542
|
+
const pageRange = typeof inputs.pageRange === 'string' && inputs.pageRange !== '' ? tsLiteral(inputs.pageRange) : undefined;
|
|
553
543
|
if (node.type === T.documentClassify) {
|
|
554
544
|
const split = unwrapPlain(inputs.splitPages);
|
|
555
545
|
return `${imp.use('documentClassify')}(${opts([
|
|
@@ -558,7 +548,7 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
558
548
|
['splitPages', split === true ? 'true' : undefined],
|
|
559
549
|
])})`;
|
|
560
550
|
}
|
|
561
|
-
const schema = inputs.schemaDocument !== undefined ?
|
|
551
|
+
const schema = inputs.schemaDocument !== undefined ? tsLiteral(inputs.schemaDocument) : undefined;
|
|
562
552
|
return `${imp.use('dynamicExtract')}(${opts([
|
|
563
553
|
['fileRef', fileSrc],
|
|
564
554
|
['schema', schema],
|
|
@@ -570,9 +560,9 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
570
560
|
case T.dataFabricUpdate:
|
|
571
561
|
case T.dataFabricDelete: {
|
|
572
562
|
const cfg = (inputs.entityConfig ?? {});
|
|
573
|
-
const entity =
|
|
574
|
-
const folder = typeof cfg._folderKey === 'string' ?
|
|
575
|
-
const resourceKey = typeof cfg._resourceKey === 'string' ?
|
|
563
|
+
const entity = tsText(cfg.entityName);
|
|
564
|
+
const folder = typeof cfg._folderKey === 'string' ? tsLiteral(cfg._folderKey) : undefined;
|
|
565
|
+
const resourceKey = typeof cfg._resourceKey === 'string' ? tsLiteral(cfg._resourceKey) : undefined;
|
|
576
566
|
const val = (v) => {
|
|
577
567
|
// 1.3 let `recordId` and a create's field value be a `{ type:
|
|
578
568
|
// 'jsExpression', expression }` object as well as a `=js:` string. A
|
|
@@ -582,14 +572,14 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
582
572
|
return emitBareExpr(String(obj.expression ?? ''), imp, inputNames);
|
|
583
573
|
}
|
|
584
574
|
const raw = typeof v === 'string' ? v : String(v ?? '');
|
|
585
|
-
return raw.startsWith('=js:') ? emitBareExpr(raw.slice(4), imp, inputNames) :
|
|
575
|
+
return raw.startsWith('=js:') ? emitBareExpr(raw.slice(4), imp, inputNames) : tsLiteral(raw);
|
|
586
576
|
};
|
|
587
577
|
const fieldObject = (rows) => {
|
|
588
578
|
const list = Array.isArray(rows) ? rows : [];
|
|
589
579
|
return `{ ${list.map((r) => `${key(String(r.field ?? ''))}: ${val(r.value)}`).join(', ')} }`;
|
|
590
580
|
};
|
|
591
581
|
const record = cfg.recordSource === 'fromRead'
|
|
592
|
-
? `{ fromRead: ${
|
|
582
|
+
? `{ fromRead: ${tsText(cfg.readEntityNodeId)} }`
|
|
593
583
|
: `{ byId: ${val(cfg.recordId)} }`;
|
|
594
584
|
if (node.type === T.dataFabricRead) {
|
|
595
585
|
// The array is what the platform serializer reads and what compile
|
|
@@ -597,8 +587,8 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
597
587
|
// here so a canvas-authored file still decompiles. Both flatten to the
|
|
598
588
|
// builder's row list, where `or: true` marks each new OR alternative.
|
|
599
589
|
const filterRow = (r, or = false) => opts([
|
|
600
|
-
['field',
|
|
601
|
-
['operator', r.operator !== undefined && r.operator !== '=' ?
|
|
590
|
+
['field', tsText(r.field)],
|
|
591
|
+
['operator', r.operator !== undefined && r.operator !== '=' ? tsLiteral(String(r.operator)) : undefined],
|
|
602
592
|
['value', val(r.value)],
|
|
603
593
|
['or', or ? 'true' : undefined],
|
|
604
594
|
]);
|
|
@@ -621,15 +611,15 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
621
611
|
// `resultMode` only exists from 1.4, and recovering it re-selects 1.4 on
|
|
622
612
|
// the way back out — so a 1.0 node stays a 1.0 node through the round trip.
|
|
623
613
|
const mode = cfg.resultMode === 'single' || cfg.resultMode === 'multiple'
|
|
624
|
-
?
|
|
614
|
+
? tsLiteral(cfg.resultMode) : undefined;
|
|
625
615
|
const sort = cfg._sort && typeof cfg._sort === 'object'
|
|
626
616
|
? opts([
|
|
627
|
-
['field',
|
|
628
|
-
['direction', cfg._sort.direction === 'desc' ?
|
|
617
|
+
['field', tsText(cfg._sort.field)],
|
|
618
|
+
['direction', cfg._sort.direction === 'desc' ? tsLiteral('desc') : undefined],
|
|
629
619
|
])
|
|
630
620
|
: undefined;
|
|
631
621
|
const fields = Array.isArray(cfg._selectedFieldNames) && cfg._selectedFieldNames.length
|
|
632
|
-
? `[${cfg._selectedFieldNames.map((f) =>
|
|
622
|
+
? `[${cfg._selectedFieldNames.map((f) => tsLiteral(String(f))).join(', ')}]`
|
|
633
623
|
: undefined;
|
|
634
624
|
return `${imp.use('dataFabricRead')}(${opts([
|
|
635
625
|
['entity', entity], ['filters', filters], ['resultMode', mode],
|
|
@@ -661,7 +651,7 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
661
651
|
const raw = typeof x === 'string' ? x : String(x?.expression ?? x ?? '');
|
|
662
652
|
return raw.startsWith('=js:') ? emitBareExpr(raw.slice(4), imp, inputNames)
|
|
663
653
|
: raw.startsWith('$vars.') ? emitBareExpr(raw, imp, inputNames)
|
|
664
|
-
:
|
|
654
|
+
: tsLiteral(raw);
|
|
665
655
|
};
|
|
666
656
|
if (node.type === T.createOutgoingCall) {
|
|
667
657
|
return `${imp.use('createOutgoingCall')}(${opts([['from', v(i.from)], ['to', v(i.to)]])})`;
|
|
@@ -690,16 +680,16 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
690
680
|
// value, so it must not come back as one.
|
|
691
681
|
if (raw === undefined || raw === '')
|
|
692
682
|
return undefined;
|
|
693
|
-
return raw.startsWith('=js:') ? emitBareExpr(raw.slice(4), imp, inputNames) :
|
|
683
|
+
return raw.startsWith('=js:') ? emitBareExpr(raw.slice(4), imp, inputNames) : tsLiteral(raw);
|
|
694
684
|
};
|
|
695
685
|
const priority = unwrapPlain(inputs.priority);
|
|
696
686
|
return `${imp.use('queueItem')}(${opts([
|
|
697
|
-
['queue',
|
|
698
|
-
['folderPath',
|
|
699
|
-
['key',
|
|
687
|
+
['queue', tsText(q.name)],
|
|
688
|
+
['folderPath', tsText(q.folderPath)],
|
|
689
|
+
['key', tsText(q.key)],
|
|
700
690
|
['item', rows.length ? objLit(rows) : '{}'],
|
|
701
691
|
// `Normal` is the definition's default — only a departure was authored.
|
|
702
|
-
['priority', typeof priority === 'string' && priority !== 'Normal' ?
|
|
692
|
+
['priority', typeof priority === 'string' && priority !== 'Normal' ? tsLiteral(priority) : undefined],
|
|
703
693
|
['reference', optStr('reference')],
|
|
704
694
|
['deferDate', optStr('deferDate')],
|
|
705
695
|
['dueDate', optStr('dueDate')],
|
|
@@ -741,7 +731,7 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
741
731
|
const raw = typeof x === 'string' ? x : String(x?.expression ?? x ?? '');
|
|
742
732
|
return raw.startsWith('=js:') ? emitBareExpr(raw.slice(4), imp, inputNames)
|
|
743
733
|
: raw.startsWith('$vars.') ? emitBareExpr(raw, imp, inputNames)
|
|
744
|
-
:
|
|
734
|
+
: tsLiteral(raw);
|
|
745
735
|
};
|
|
746
736
|
const num = (x) => {
|
|
747
737
|
if (x === undefined || x === null)
|
|
@@ -813,16 +803,16 @@ function emitStepSpec(node, imp, inputNames, o, graph) {
|
|
|
813
803
|
const model = (i.model ?? {});
|
|
814
804
|
const nested = (k) => typeof model[k] === 'string' && model[k] !== '' ? model[k] : undefined;
|
|
815
805
|
return `${imp.use('ixpExtract')}(${opts([
|
|
816
|
-
['project',
|
|
806
|
+
['project', tsLiteral(node.type)],
|
|
817
807
|
// `modelName`/`projectName` are one value in two fields; either recovers it.
|
|
818
|
-
['modelName',
|
|
819
|
-
['name',
|
|
820
|
-
['folderName',
|
|
821
|
-
['fileRef', fr.startsWith('=js:') ? emitBareExpr(fr.slice(4), imp, inputNames) :
|
|
822
|
-
['pageRange', plain('pageRange') !== undefined ?
|
|
823
|
-
['versionTag', plain('versionTag') !== undefined ?
|
|
808
|
+
['modelName', tsLiteral(plain('modelName') ?? plain('projectName') ?? nested('modelName') ?? '')],
|
|
809
|
+
['name', tsLiteral(nested('modelDisplayName') ?? plain('modelName') ?? '')],
|
|
810
|
+
['folderName', tsLiteral(plain('folderName') ?? nested('folderName') ?? '')],
|
|
811
|
+
['fileRef', fr.startsWith('=js:') ? emitBareExpr(fr.slice(4), imp, inputNames) : tsLiteral(fr)],
|
|
812
|
+
['pageRange', plain('pageRange') !== undefined ? tsLiteral(plain('pageRange')) : undefined],
|
|
813
|
+
['versionTag', plain('versionTag') !== undefined ? tsLiteral(plain('versionTag')) : undefined],
|
|
824
814
|
['description', plain('description') ?? nested('description') !== undefined
|
|
825
|
-
?
|
|
815
|
+
? tsLiteral((plain('description') ?? nested('description'))) : undefined],
|
|
826
816
|
])})`;
|
|
827
817
|
}
|
|
828
818
|
// Every family this SDK AUTHORS is recovered above — a guard test asserts
|
|
@@ -866,23 +856,16 @@ function scriptReturnsOpt(node, code) {
|
|
|
866
856
|
// A field map is the richer statement, so it wins when there is one.
|
|
867
857
|
const entries = Object.entries(props)
|
|
868
858
|
.filter(([, v]) => typeof v?.type === 'string')
|
|
869
|
-
.map(([k, v]) => [k,
|
|
859
|
+
.map(([k, v]) => [k, tsLiteral(v.type)]);
|
|
870
860
|
if (entries.length > 0)
|
|
871
861
|
return [['returns', opts(entries)]];
|
|
872
862
|
}
|
|
873
|
-
return [['returns',
|
|
863
|
+
return [['returns', tsLiteral(declared)]];
|
|
874
864
|
}
|
|
875
865
|
/** Key-sorted copy, so a property map compares by content and not by order. */
|
|
876
866
|
function sortKeys(o) {
|
|
877
867
|
return Object.fromEntries(Object.entries(o).sort(([a], [b]) => a.localeCompare(b)));
|
|
878
868
|
}
|
|
879
|
-
/** A validated numeric literal — never emit a raw JSON value that could carry code. */
|
|
880
|
-
function numLit(v) {
|
|
881
|
-
const n = Number(v);
|
|
882
|
-
if (!Number.isFinite(n))
|
|
883
|
-
throw new Error(`decompile: expected a number, got ${JSON.stringify(v)}.`);
|
|
884
|
-
return String(n);
|
|
885
|
-
}
|
|
886
869
|
/**
|
|
887
870
|
* Invert an HTTP node. The plain node (`core.action.http`) keeps its request at
|
|
888
871
|
* the top level (`url` / `method` / `headers` / `queryParams` / `body` /
|
|
@@ -907,28 +890,28 @@ function emitHttp(node, managed, imp, inputNames) {
|
|
|
907
890
|
const headersSrc = emitValMap(headers, imp, inputNames) || undefined;
|
|
908
891
|
const querySrc = emitValMap(query, imp, inputNames) || undefined;
|
|
909
892
|
const contentType = !managed && typeof inputs.contentType === 'string' && inputs.contentType !== 'application/json'
|
|
910
|
-
?
|
|
911
|
-
const timeout = typeof inputs.timeout === 'string' && inputs.timeout !== 'PT15M' ?
|
|
912
|
-
const retry = inputs.retryCount !== undefined && Number(inputs.retryCount) !== 0 ?
|
|
893
|
+
? tsLiteral(inputs.contentType) : undefined;
|
|
894
|
+
const timeout = typeof inputs.timeout === 'string' && inputs.timeout !== 'PT15M' ? tsLiteral(inputs.timeout) : undefined;
|
|
895
|
+
const retry = inputs.retryCount !== undefined && Number(inputs.retryCount) !== 0 ? tsNumber(inputs.retryCount) : undefined;
|
|
913
896
|
const branchRows = Array.isArray(inputs.branches) ? inputs.branches : [];
|
|
914
897
|
const branchesSrc = branchRows.length
|
|
915
898
|
? `[${branchRows.map((b) => {
|
|
916
899
|
const cond = unwrapSource(b.conditionExpression) ?? '';
|
|
917
900
|
const expr = emitBareExpr(cond.startsWith('=js:') ? cond.slice(4) : cond, imp, inputNames);
|
|
918
|
-
return `{ name: ${
|
|
901
|
+
return `{ name: ${tsText(b.name ?? b.id)}, condition: ${expr} }`;
|
|
919
902
|
}).join(', ')}]`
|
|
920
903
|
: undefined;
|
|
921
904
|
const connectionValue = detail.connectionId ?? detail.connectionResourceId ?? req.connection;
|
|
922
905
|
const connection = managed && typeof connectionValue === 'string' && connectionValue !== 'ImplicitConnection'
|
|
923
|
-
?
|
|
906
|
+
? tsLiteral(connectionValue) : undefined;
|
|
924
907
|
const folder = managed && typeof detail.connectionFolderKey === 'string' && detail.connectionFolderKey.length > 0
|
|
925
|
-
?
|
|
908
|
+
? tsLiteral(detail.connectionFolderKey) : undefined;
|
|
926
909
|
const targetConnector = managed && typeof req.targetConnector === 'string'
|
|
927
910
|
&& req.targetConnector !== 'uipath-uipath-http'
|
|
928
|
-
?
|
|
911
|
+
? tsLiteral(req.targetConnector) : undefined;
|
|
929
912
|
const spec = opts([
|
|
930
913
|
['url', emitVal(req.url ?? '', imp, inputNames)],
|
|
931
|
-
['method', method !== 'GET' ?
|
|
914
|
+
['method', method !== 'GET' ? tsLiteral(method) : undefined],
|
|
932
915
|
['headers', headersSrc],
|
|
933
916
|
['query', querySrc],
|
|
934
917
|
['body', bodySrc],
|
|
@@ -964,43 +947,43 @@ function emitTransform(node, imp, inputNames) {
|
|
|
964
947
|
const cfg = op?.config ?? {};
|
|
965
948
|
if (op?.type === 'filter') {
|
|
966
949
|
const filters = (cfg.filters ?? []).map((f) => objLit([
|
|
967
|
-
['field',
|
|
968
|
-
['condition',
|
|
969
|
-
...(f.value !== undefined ? [['value',
|
|
950
|
+
['field', tsLiteral(f.field)],
|
|
951
|
+
['condition', tsLiteral(f.condition)],
|
|
952
|
+
...(f.value !== undefined ? [['value', tsLiteral(f.value)]] : []),
|
|
970
953
|
]));
|
|
971
954
|
return objLit([
|
|
972
|
-
['type',
|
|
973
|
-
...(cfg.operation !== undefined ? [['operation',
|
|
955
|
+
['type', tsLiteral('filter')],
|
|
956
|
+
...(cfg.operation !== undefined ? [['operation', tsLiteral(cfg.operation)]] : []),
|
|
974
957
|
['filters', `[${filters.join(', ')}]`],
|
|
975
958
|
]);
|
|
976
959
|
}
|
|
977
960
|
if (op?.type === 'map') {
|
|
978
961
|
const mappings = (cfg.mappings ?? []).map((m) => objLit([
|
|
979
|
-
['field',
|
|
980
|
-
...(m.transformation && m.transformation !== 'copy' ? [['transformation',
|
|
981
|
-
...(m.renameTo ? [['renameTo',
|
|
962
|
+
['field', tsLiteral(m.field)],
|
|
963
|
+
...(m.transformation && m.transformation !== 'copy' ? [['transformation', tsLiteral(m.transformation)]] : []),
|
|
964
|
+
...(m.renameTo ? [['renameTo', tsLiteral(m.renameTo)]] : []),
|
|
982
965
|
]));
|
|
983
966
|
return objLit([
|
|
984
|
-
['type',
|
|
967
|
+
['type', tsLiteral('map')],
|
|
985
968
|
...(cfg.keepOriginalFields ? [['keepOriginalFields', boolLit(cfg.keepOriginalFields)]] : []),
|
|
986
969
|
['mappings', `[${mappings.join(', ')}]`],
|
|
987
970
|
]);
|
|
988
971
|
}
|
|
989
972
|
// groupBy
|
|
990
973
|
const aggs = (cfg.aggregations ?? []).map((a) => objLit([
|
|
991
|
-
['operation',
|
|
992
|
-
['alias',
|
|
993
|
-
...(a.field ? [['field',
|
|
974
|
+
['operation', tsLiteral(a.operation)],
|
|
975
|
+
['alias', tsLiteral(a.alias)],
|
|
976
|
+
...(a.field ? [['field', tsLiteral(a.field)]] : []),
|
|
994
977
|
]));
|
|
995
978
|
return objLit([
|
|
996
|
-
['type',
|
|
997
|
-
['groupByField',
|
|
979
|
+
['type', tsLiteral('groupBy')],
|
|
980
|
+
['groupByField', tsLiteral(cfg.groupByField)],
|
|
998
981
|
['aggregations', `[${aggs.join(', ')}]`],
|
|
999
982
|
]);
|
|
1000
983
|
});
|
|
1001
984
|
const spec = opts([
|
|
1002
985
|
['collection', collection],
|
|
1003
|
-
['variant', variant ?
|
|
986
|
+
['variant', variant ? tsLiteral(variant) : undefined],
|
|
1004
987
|
['operations', `[${opSrcs.join(', ')}]`],
|
|
1005
988
|
]);
|
|
1006
989
|
return `${imp.use('transform')}(${spec})`;
|
|
@@ -1180,7 +1163,7 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1180
1163
|
};
|
|
1181
1164
|
const promptSrc = (v) => {
|
|
1182
1165
|
const raw = plain(v);
|
|
1183
|
-
return raw === undefined ? undefined :
|
|
1166
|
+
return raw === undefined ? undefined : tsLiteral(unrender(raw));
|
|
1184
1167
|
};
|
|
1185
1168
|
const inputRows = refs
|
|
1186
1169
|
// Emit in the file's own order, not the length-sorted one.
|
|
@@ -1192,7 +1175,7 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1192
1175
|
});
|
|
1193
1176
|
const outVars = (Array.isArray(i.agentOutputVariables) ? i.agentOutputVariables : []);
|
|
1194
1177
|
const returns = outVars.length
|
|
1195
|
-
? objLit(outVars.map((v) => [String(v.id ?? ''),
|
|
1178
|
+
? objLit(outVars.map((v) => [String(v.id ?? ''), tsLiteral(String(v.type ?? 'string'))]))
|
|
1196
1179
|
: undefined;
|
|
1197
1180
|
// The resources, from the agent's own artifact edges.
|
|
1198
1181
|
const resource = (port) => (graph?.outEdges(node.id) ?? [])
|
|
@@ -1212,12 +1195,12 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1212
1195
|
const props = v?.properties;
|
|
1213
1196
|
if (!props || Object.keys(props).length === 0)
|
|
1214
1197
|
return undefined;
|
|
1215
|
-
return objLit(Object.entries(props).map(([k, x]) => [k,
|
|
1198
|
+
return objLit(Object.entries(props).map(([k, x]) => [k, tsLiteral(String(x?.type ?? 'string'))]));
|
|
1216
1199
|
};
|
|
1217
1200
|
return opts([
|
|
1218
|
-
['kind',
|
|
1219
|
-
['name',
|
|
1220
|
-
['description', rPlain(t, 'description') !== undefined ?
|
|
1201
|
+
['kind', tsLiteral('clientside')],
|
|
1202
|
+
['name', tsLiteral(rPlain(t, 'name') ?? '')],
|
|
1203
|
+
['description', rPlain(t, 'description') !== undefined ? tsLiteral(rPlain(t, 'description')) : undefined],
|
|
1221
1204
|
['inputs', schemaTypes(ti.inputSchema)],
|
|
1222
1205
|
['returns', schemaTypes(ti.outputSchema)],
|
|
1223
1206
|
]);
|
|
@@ -1229,10 +1212,10 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1229
1212
|
if (!row || row.mode !== 'text-builder')
|
|
1230
1213
|
return undefined;
|
|
1231
1214
|
const v = row.textValue;
|
|
1232
|
-
return typeof v === 'number' ? String(v) : typeof v === 'string' ?
|
|
1215
|
+
return typeof v === 'number' ? String(v) : typeof v === 'string' ? tsLiteral(v) : JSON.stringify(v);
|
|
1233
1216
|
};
|
|
1234
1217
|
return opts([
|
|
1235
|
-
['kind',
|
|
1218
|
+
['kind', tsLiteral('httpRequest')],
|
|
1236
1219
|
['url', fixed('url')], ['method', fixed('method')],
|
|
1237
1220
|
['headers', fixed('headers')], ['params', fixed('params')],
|
|
1238
1221
|
['body', fixed('body')], ['timeout', fixed('timeout')],
|
|
@@ -1240,37 +1223,37 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1240
1223
|
}
|
|
1241
1224
|
if (type.startsWith('uipath.agent.resource.tool.mcp.')) {
|
|
1242
1225
|
return opts([
|
|
1243
|
-
['kind',
|
|
1244
|
-
['name',
|
|
1245
|
-
['key',
|
|
1226
|
+
['kind', tsLiteral('mcp')],
|
|
1227
|
+
['name', tsLiteral(rPlain(t, 'name') ?? '')],
|
|
1228
|
+
['key', tsLiteral(rPlain(t, 'referenceKey') ?? '')],
|
|
1246
1229
|
// The mapper's field name for the canonical server slug.
|
|
1247
|
-
['slug', rPlain(t, 'serverUrl') !== undefined ?
|
|
1248
|
-
['folderPath', rPlain(t, 'folderPath') !== undefined ?
|
|
1249
|
-
['mcpType', rPlain(t, 'mcpType') !== undefined ?
|
|
1230
|
+
['slug', rPlain(t, 'serverUrl') !== undefined ? tsLiteral(rPlain(t, 'serverUrl')) : undefined],
|
|
1231
|
+
['folderPath', rPlain(t, 'folderPath') !== undefined ? tsLiteral(rPlain(t, 'folderPath')) : undefined],
|
|
1232
|
+
['mcpType', rPlain(t, 'mcpType') !== undefined ? tsLiteral(rPlain(t, 'mcpType')) : undefined],
|
|
1250
1233
|
]);
|
|
1251
1234
|
}
|
|
1252
1235
|
if (type.startsWith('uipath.agent.resource.tool.a2a.')) {
|
|
1253
1236
|
return opts([
|
|
1254
|
-
['kind',
|
|
1255
|
-
['name',
|
|
1256
|
-
['key',
|
|
1257
|
-
['slug',
|
|
1258
|
-
['folderPath', rPlain(t, 'folderPath') !== undefined ?
|
|
1237
|
+
['kind', tsLiteral('a2a')],
|
|
1238
|
+
['name', tsLiteral(rPlain(t, 'name') ?? '')],
|
|
1239
|
+
['key', tsLiteral(rPlain(t, 'referenceKey') ?? '')],
|
|
1240
|
+
['slug', tsLiteral(rPlain(t, 'slug') ?? '')],
|
|
1241
|
+
['folderPath', rPlain(t, 'folderPath') !== undefined ? tsLiteral(rPlain(t, 'folderPath')) : undefined],
|
|
1259
1242
|
]);
|
|
1260
1243
|
}
|
|
1261
1244
|
if (type.startsWith('uipath.agent.resource.tool.builtin.')) {
|
|
1262
1245
|
return opts([
|
|
1263
|
-
['kind',
|
|
1264
|
-
['tool',
|
|
1265
|
-
['description', rPlain(t, 'description') !== undefined ?
|
|
1246
|
+
['kind', tsLiteral('builtin')],
|
|
1247
|
+
['tool', tsLiteral(type.slice('uipath.agent.resource.tool.builtin.'.length))],
|
|
1248
|
+
['description', rPlain(t, 'description') !== undefined ? tsLiteral(rPlain(t, 'description')) : undefined],
|
|
1266
1249
|
]);
|
|
1267
1250
|
}
|
|
1268
1251
|
if (type.startsWith('uipath.agent.resource.tool.ixp.')) {
|
|
1269
1252
|
const tail = type.slice('uipath.agent.resource.tool.ixp.'.length);
|
|
1270
1253
|
return opts([
|
|
1271
|
-
['kind',
|
|
1272
|
-
['projectId',
|
|
1273
|
-
['name',
|
|
1254
|
+
['kind', tsLiteral('ixp')],
|
|
1255
|
+
['projectId', tsLiteral(tail.slice(tail.indexOf('.') + 1))],
|
|
1256
|
+
['name', tsLiteral(rPlain(t, 'name') ?? '')],
|
|
1274
1257
|
]);
|
|
1275
1258
|
}
|
|
1276
1259
|
// The per-instance resource kinds (process / api / flow / maestro / agent /
|
|
@@ -1292,13 +1275,13 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1292
1275
|
return typeof row?.default === 'string' ? row.default : undefined;
|
|
1293
1276
|
};
|
|
1294
1277
|
return opts([
|
|
1295
|
-
['kind',
|
|
1296
|
-
['key',
|
|
1297
|
-
['name',
|
|
1298
|
-
['folderPath',
|
|
1278
|
+
['kind', tsLiteral(ns[1])],
|
|
1279
|
+
['key', tsLiteral(type.slice(ns[0].length))],
|
|
1280
|
+
['name', tsLiteral(bound('name') ?? rPlain(t, 'name') ?? '')],
|
|
1281
|
+
['folderPath', tsLiteral(bound('folderPath') ?? '')],
|
|
1299
1282
|
]);
|
|
1300
1283
|
}
|
|
1301
|
-
return opts([['kind',
|
|
1284
|
+
return opts([['kind', tsLiteral('builtin')], ['tool', tsLiteral('summarize')]]); // unreachable in practice
|
|
1302
1285
|
});
|
|
1303
1286
|
const contextSrc = resource('context').map((c) => {
|
|
1304
1287
|
// `query` is a MODE TRIPLE, not a string: the author's value lands in
|
|
@@ -1310,17 +1293,17 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1310
1293
|
: typeof q === 'string' && q !== '' ? q
|
|
1311
1294
|
: undefined;
|
|
1312
1295
|
return opts([
|
|
1313
|
-
['name',
|
|
1314
|
-
['id',
|
|
1315
|
-
['folderPath', rPlain(c, 'folderPath') !== undefined ?
|
|
1316
|
-
['folderKey', rPlain(c, 'folderKey') !== undefined ?
|
|
1317
|
-
['query', queryText !== undefined ?
|
|
1296
|
+
['name', tsLiteral(rPlain(c, 'indexName') ?? String(c.display?.label ?? ''))],
|
|
1297
|
+
['id', tsLiteral(rPlain(c, 'indexId') ?? '')],
|
|
1298
|
+
['folderPath', rPlain(c, 'folderPath') !== undefined ? tsLiteral(rPlain(c, 'folderPath')) : undefined],
|
|
1299
|
+
['folderKey', rPlain(c, 'folderKey') !== undefined ? tsLiteral(rPlain(c, 'folderKey')) : undefined],
|
|
1300
|
+
['query', queryText !== undefined ? tsLiteral(queryText) : undefined],
|
|
1318
1301
|
]);
|
|
1319
1302
|
});
|
|
1320
1303
|
const escalationSrc = resource('escalation').map((e) => {
|
|
1321
1304
|
const ei = rInputs(e);
|
|
1322
1305
|
const recipients = Array.isArray(ei.recipients)
|
|
1323
|
-
? ei.recipients.map((r) =>
|
|
1306
|
+
? ei.recipients.map((r) => tsText(r.value))
|
|
1324
1307
|
: [];
|
|
1325
1308
|
const outcomeNames = Object.keys((ei.outcomeMapping ?? {}));
|
|
1326
1309
|
const isQuickForm = e.type === 'uipath.agent.resource.escalation.quick-form';
|
|
@@ -1330,24 +1313,24 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1330
1313
|
const app = ei.app;
|
|
1331
1314
|
const extra = (ei._additionalProps ?? {});
|
|
1332
1315
|
return opts([
|
|
1333
|
-
['variant', isQuickForm ?
|
|
1334
|
-
['name',
|
|
1335
|
-
['description', rPlain(e, 'description') !== undefined ?
|
|
1316
|
+
['variant', isQuickForm ? tsLiteral('quick-form') : undefined],
|
|
1317
|
+
['name', tsLiteral(rPlain(e, 'name') ?? '')],
|
|
1318
|
+
['description', rPlain(e, 'description') !== undefined ? tsLiteral(rPlain(e, 'description')) : undefined],
|
|
1336
1319
|
['fields', rows.length ? `[${rows.map((f) => opts([
|
|
1337
|
-
['id',
|
|
1338
|
-
['type',
|
|
1339
|
-
['direction',
|
|
1320
|
+
['id', tsText(f.id)],
|
|
1321
|
+
['type', tsLiteral(String(f.type ?? 'text'))],
|
|
1322
|
+
['direction', tsLiteral(String(f.direction ?? 'output'))],
|
|
1340
1323
|
])).join(', ')}]` : undefined],
|
|
1341
1324
|
['app', app === undefined ? undefined : opts([
|
|
1342
|
-
['key',
|
|
1343
|
-
['name',
|
|
1344
|
-
['folderPath', typeof app.folderPath === 'string' && app.folderPath !== '' ?
|
|
1325
|
+
['key', tsText(app.key)],
|
|
1326
|
+
['name', tsText(app.name)],
|
|
1327
|
+
['folderPath', typeof app.folderPath === 'string' && app.folderPath !== '' ? tsLiteral(app.folderPath) : undefined],
|
|
1345
1328
|
])],
|
|
1346
1329
|
['recipients', recipients.length ? `[${recipients.join(', ')}]` : undefined],
|
|
1347
|
-
['outcomes', outcomeNames.length ? `[${outcomeNames.map((o) =>
|
|
1348
|
-
['taskTitle', typeof extra.taskTitle === 'string' && extra.taskTitle !== '' ?
|
|
1330
|
+
['outcomes', outcomeNames.length ? `[${outcomeNames.map((o) => tsLiteral(o)).join(', ')}]` : undefined],
|
|
1331
|
+
['taskTitle', typeof extra.taskTitle === 'string' && extra.taskTitle !== '' ? tsLiteral(extra.taskTitle) : undefined],
|
|
1349
1332
|
// 'medium' is the platform default.
|
|
1350
|
-
['priority', typeof extra.priority === 'string' && extra.priority !== 'medium' ?
|
|
1333
|
+
['priority', typeof extra.priority === 'string' && extra.priority !== 'medium' ? tsLiteral(extra.priority) : undefined],
|
|
1351
1334
|
]);
|
|
1352
1335
|
});
|
|
1353
1336
|
const mem = resource('memory')[0];
|
|
@@ -1357,15 +1340,15 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1357
1340
|
const id = tail.slice(tail.indexOf('.') + 1);
|
|
1358
1341
|
const mi = rInputs(mem);
|
|
1359
1342
|
return opts([
|
|
1360
|
-
['name',
|
|
1361
|
-
['id',
|
|
1362
|
-
['description', rPlain(mem, 'description') !== undefined ?
|
|
1343
|
+
['name', tsLiteral(rPlain(mem, 'name') ?? '')],
|
|
1344
|
+
['id', tsLiteral(id)],
|
|
1345
|
+
['description', rPlain(mem, 'description') !== undefined ? tsLiteral(rPlain(mem, 'description')) : undefined],
|
|
1363
1346
|
// The platform defaults: few-shot on, similarity 0, k 3, hybrid search.
|
|
1364
1347
|
['dynamicFewShotLearning', unwrapPlain(mi.dynamicFewShotLearning) === false ? 'false' : undefined],
|
|
1365
1348
|
['semanticSimilarity', num(mi.semanticSimilarity) !== undefined && num(mi.semanticSimilarity) !== '0' ? num(mi.semanticSimilarity) : undefined],
|
|
1366
1349
|
['kValue', num(mi.kValue) !== undefined && num(mi.kValue) !== '3' ? num(mi.kValue) : undefined],
|
|
1367
1350
|
['searchMode', rPlain(mem, 'searchMode') !== undefined && rPlain(mem, 'searchMode') !== 'hybrid'
|
|
1368
|
-
?
|
|
1351
|
+
? tsLiteral(rPlain(mem, 'searchMode')) : undefined],
|
|
1369
1352
|
]);
|
|
1370
1353
|
})();
|
|
1371
1354
|
const guardrails = Array.isArray(i.guardrails) && i.guardrails.length > 0
|
|
@@ -1375,22 +1358,22 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1375
1358
|
if (node.type === T.voiceAgent) {
|
|
1376
1359
|
const v = (i.voice ?? {});
|
|
1377
1360
|
const voiceSrc = Object.keys(v).length === 0 ? undefined : opts([
|
|
1378
|
-
['model', typeof v.model === 'string' ?
|
|
1379
|
-
['persona', typeof v.persona === 'string' ?
|
|
1361
|
+
['model', typeof v.model === 'string' ? tsLiteral(v.model) : undefined],
|
|
1362
|
+
['persona', typeof v.persona === 'string' ? tsLiteral(v.persona) : undefined],
|
|
1380
1363
|
['temperature', num(v.temperature)],
|
|
1381
1364
|
['maxTokens', num(v.maxTokens)],
|
|
1382
1365
|
]);
|
|
1383
1366
|
return `${imp.use('voiceAgent')}(${opts([
|
|
1384
|
-
['systemPrompt', promptSrc(i.systemPrompt) ??
|
|
1367
|
+
['systemPrompt', promptSrc(i.systemPrompt) ?? tsLiteral('')],
|
|
1385
1368
|
['inputs', inputRows.length ? objLit(inputRows) : undefined],
|
|
1386
1369
|
['callContext', (() => {
|
|
1387
1370
|
const raw = plain(i.callContext) ?? '';
|
|
1388
1371
|
const js = raw.startsWith('=js:') ? raw.slice(4) : raw;
|
|
1389
|
-
return js.startsWith('$vars.') ? emitBareExpr(js, imp, inputNames) :
|
|
1372
|
+
return js.startsWith('$vars.') ? emitBareExpr(js, imp, inputNames) : tsLiteral(js);
|
|
1390
1373
|
})()],
|
|
1391
1374
|
['voice', voiceSrc],
|
|
1392
1375
|
['maxIterations', num(i.maxIterations)],
|
|
1393
|
-
['source',
|
|
1376
|
+
['source', tsLiteral(plain(i.source) ?? '')],
|
|
1394
1377
|
])})`;
|
|
1395
1378
|
}
|
|
1396
1379
|
if (node.type === T.conversationalAgent) {
|
|
@@ -1407,7 +1390,7 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1407
1390
|
// `out(...)` and anything composite to a `js` template. Any other string
|
|
1408
1391
|
// is literal text, as the product reads it (flow-schema
|
|
1409
1392
|
// `coerceToExpressionValue`), even when it looks like `$vars.…`.
|
|
1410
|
-
return raw.startsWith('=js:') ? emitRef(raw.slice(4), imp, inputNames) :
|
|
1393
|
+
return raw.startsWith('=js:') ? emitRef(raw.slice(4), imp, inputNames) : tsLiteral(raw);
|
|
1411
1394
|
};
|
|
1412
1395
|
// `'simple'` mode DERIVES the four runtime fields from `context`, so only
|
|
1413
1396
|
// the context binding is the author's; recovering the derived ones would
|
|
@@ -1415,7 +1398,7 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1415
1398
|
const mode = typeof st.mode === 'string' ? st.mode : 'simple';
|
|
1416
1399
|
const settingsSrc = mode === 'custom'
|
|
1417
1400
|
? opts([
|
|
1418
|
-
['mode',
|
|
1401
|
+
['mode', tsLiteral('custom')],
|
|
1419
1402
|
['conversationId', settingExpr('conversationId')],
|
|
1420
1403
|
['exchangeId', settingExpr('exchangeId')],
|
|
1421
1404
|
['messages', settingExpr('messages')],
|
|
@@ -1423,8 +1406,8 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1423
1406
|
])
|
|
1424
1407
|
: opts([['context', settingExpr('context')]]);
|
|
1425
1408
|
return `${imp.use('conversationalAgent')}(${opts([
|
|
1426
|
-
['model',
|
|
1427
|
-
['systemPrompt', promptSrc(i.systemPrompt) ??
|
|
1409
|
+
['model', tsLiteral(plain(i.model) ?? '')],
|
|
1410
|
+
['systemPrompt', promptSrc(i.systemPrompt) ?? tsLiteral('')],
|
|
1428
1411
|
// `settings` is required on ConversationalAgentInputs, so an empty one
|
|
1429
1412
|
// stays as `{}`, which check then reports as CONV_AGENT_NO_TURN.
|
|
1430
1413
|
['settings', settingsSrc || '{}'],
|
|
@@ -1432,19 +1415,19 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1432
1415
|
['maxTokenPerResponse', num(i.maxTokenPerResponse)],
|
|
1433
1416
|
['maxIterations', num(i.maxIterations)],
|
|
1434
1417
|
['guardrails', guardrails],
|
|
1435
|
-
['source',
|
|
1418
|
+
['source', tsLiteral(plain(i.source) ?? '')],
|
|
1436
1419
|
])})`;
|
|
1437
1420
|
}
|
|
1438
1421
|
return `${imp.use('inlineAgent')}(${opts([
|
|
1439
|
-
['model',
|
|
1440
|
-
['systemPrompt', promptSrc(i.systemPrompt) ??
|
|
1441
|
-
['userPrompt', promptSrc(i.userPrompt) ??
|
|
1422
|
+
['model', tsLiteral(plain(i.model) ?? '')],
|
|
1423
|
+
['systemPrompt', promptSrc(i.systemPrompt) ?? tsLiteral('')],
|
|
1424
|
+
['userPrompt', promptSrc(i.userPrompt) ?? tsLiteral('')],
|
|
1442
1425
|
['inputs', inputRows.length ? objLit(inputRows) : undefined],
|
|
1443
1426
|
['returns', returns],
|
|
1444
1427
|
['temperature', num(i.temperature)],
|
|
1445
1428
|
['maxTokenPerResponse', num(i.maxTokenPerResponse)],
|
|
1446
1429
|
['maxIterations', num(i.maxIterations)],
|
|
1447
|
-
['mode', plain(i.mode) !== undefined ?
|
|
1430
|
+
['mode', plain(i.mode) !== undefined ? tsLiteral(plain(i.mode)) : undefined],
|
|
1448
1431
|
['guardrails', guardrails],
|
|
1449
1432
|
['context', list(contextSrc)],
|
|
1450
1433
|
['tools', list(toolSrc)],
|
|
@@ -1453,7 +1436,7 @@ function emitAgentCluster(node, imp, inputNames, graph) {
|
|
|
1453
1436
|
// The agent's directory uuid is derived from the flow and step ids, but a
|
|
1454
1437
|
// decompiled flow must keep the ORIGINAL — the sidecar lives at
|
|
1455
1438
|
// `<source>/agent.json`, so a re-derived one would point at nothing.
|
|
1456
|
-
['source',
|
|
1439
|
+
['source', tsLiteral(plain(i.source) ?? '')],
|
|
1457
1440
|
])})`;
|
|
1458
1441
|
}
|
|
1459
1442
|
/**
|
|
@@ -1496,11 +1479,11 @@ function emitHitl(node, imp, inputNames, graph) {
|
|
|
1496
1479
|
const id = String(f.id ?? '');
|
|
1497
1480
|
const direction = String(f.direction ?? 'output');
|
|
1498
1481
|
return opts([
|
|
1499
|
-
['id',
|
|
1482
|
+
['id', tsLiteral(id)],
|
|
1500
1483
|
// serialize defaults a row's label to its id.
|
|
1501
|
-
['label', typeof f.label === 'string' && f.label !== id ?
|
|
1502
|
-
['type',
|
|
1503
|
-
['direction',
|
|
1484
|
+
['label', typeof f.label === 'string' && f.label !== id ? tsLiteral(f.label) : undefined],
|
|
1485
|
+
['type', tsLiteral(String(f.type ?? 'text'))],
|
|
1486
|
+
['direction', tsLiteral(direction)],
|
|
1504
1487
|
['value', direction === 'input' || direction === 'inOut' ? bindingExpr(f.binding) : undefined],
|
|
1505
1488
|
['required', f.required === true ? 'true' : undefined],
|
|
1506
1489
|
]);
|
|
@@ -1509,7 +1492,7 @@ function emitHitl(node, imp, inputNames, graph) {
|
|
|
1509
1492
|
const outcomes = outcomeRows.map((o) => {
|
|
1510
1493
|
const name = String(o.name ?? '');
|
|
1511
1494
|
// A bare string is the shorthand; only `action: 'End'` needs the object.
|
|
1512
|
-
return o.action === 'End' ? opts([['name',
|
|
1495
|
+
return o.action === 'End' ? opts([['name', tsLiteral(name)], ['action', tsLiteral('End')]]) : tsLiteral(name);
|
|
1513
1496
|
});
|
|
1514
1497
|
// Delivery: only an override comes back. The definition's own default is what
|
|
1515
1498
|
// serialize emits when the author wrote nothing.
|
|
@@ -1521,11 +1504,11 @@ function emitHitl(node, imp, inputNames, graph) {
|
|
|
1521
1504
|
const assignee = (rec.assignee ?? {});
|
|
1522
1505
|
const channels = Array.isArray(rec.channels) ? rec.channels : undefined;
|
|
1523
1506
|
recipientSrc = opts([
|
|
1524
|
-
['channels', channels ? `[${channels.map((c) =>
|
|
1507
|
+
['channels', channels ? `[${channels.map((c) => tsLiteral(c)).join(', ')}]` : undefined],
|
|
1525
1508
|
['assignee', opts([
|
|
1526
|
-
['type',
|
|
1527
|
-
['value', typeof assignee.value === 'string' ?
|
|
1528
|
-
['displayName', typeof assignee.displayName === 'string' ?
|
|
1509
|
+
['type', tsLiteral(String(assignee.type ?? 'user'))],
|
|
1510
|
+
['value', typeof assignee.value === 'string' ? tsLiteral(assignee.value) : undefined],
|
|
1511
|
+
['displayName', typeof assignee.displayName === 'string' ? tsLiteral(assignee.displayName) : undefined],
|
|
1529
1512
|
])],
|
|
1530
1513
|
]);
|
|
1531
1514
|
}
|
|
@@ -1540,15 +1523,15 @@ function emitHitl(node, imp, inputNames, graph) {
|
|
|
1540
1523
|
const bindings = (i.appInputBindings ?? {});
|
|
1541
1524
|
const appInputs = Object.keys(bindings).length === 0 ? undefined : objLit(Object.entries(bindings).map(([k, v]) => {
|
|
1542
1525
|
const raw = String(v ?? '');
|
|
1543
|
-
return [k, raw.startsWith('=') ? emitBareExpr(`$${raw.slice(1)}`, imp, inputNames) :
|
|
1526
|
+
return [k, raw.startsWith('=') ? emitBareExpr(`$${raw.slice(1)}`, imp, inputNames) : tsLiteral(raw)];
|
|
1544
1527
|
}));
|
|
1545
1528
|
const appSrc = app === undefined ? undefined : opts([
|
|
1546
1529
|
// `displayName` is serialize's echo of `name`; only `name` is authored.
|
|
1547
|
-
['name',
|
|
1548
|
-
['key',
|
|
1549
|
-
['folderPath', typeof app.folderPath === 'string' && app.folderPath !== '' ?
|
|
1530
|
+
['name', tsText(app.name)],
|
|
1531
|
+
['key', tsText(app.key)],
|
|
1532
|
+
['folderPath', typeof app.folderPath === 'string' && app.folderPath !== '' ? tsLiteral(app.folderPath) : undefined],
|
|
1550
1533
|
['appSystemName', app.appSystemName === null ? 'null'
|
|
1551
|
-
: typeof app.appSystemName === 'string' ?
|
|
1534
|
+
: typeof app.appSystemName === 'string' ? tsLiteral(app.appSystemName) : undefined],
|
|
1552
1535
|
['inputs', appInputs],
|
|
1553
1536
|
]);
|
|
1554
1537
|
// The validation station's own inputs ride as PLAIN `$vars.…` paths.
|
|
@@ -1557,15 +1540,15 @@ function emitHitl(node, imp, inputNames, graph) {
|
|
|
1557
1540
|
if (raw === undefined)
|
|
1558
1541
|
return undefined;
|
|
1559
1542
|
const js = raw.startsWith('=js:') ? raw.slice(4) : raw;
|
|
1560
|
-
return js.startsWith('$vars.') ? emitBareExpr(js, imp, inputNames) :
|
|
1543
|
+
return js.startsWith('$vars.') ? emitBareExpr(js, imp, inputNames) : tsLiteral(js);
|
|
1561
1544
|
};
|
|
1562
1545
|
const render = plain(i.validationRenderType);
|
|
1563
1546
|
const documentSrc = node.type !== T.hitlDocValidation ? undefined : opts([
|
|
1564
|
-
['extractionResult', stationExpr(i.extractionResult) ??
|
|
1565
|
-
['storageBucket', plain(i.storageBucket) !== undefined ?
|
|
1566
|
-
['documentId', plain(i.documentId) !== undefined ?
|
|
1547
|
+
['extractionResult', stationExpr(i.extractionResult) ?? tsLiteral('')],
|
|
1548
|
+
['storageBucket', plain(i.storageBucket) !== undefined ? tsLiteral(plain(i.storageBucket)) : undefined],
|
|
1549
|
+
['documentId', plain(i.documentId) !== undefined ? tsLiteral(plain(i.documentId)) : undefined],
|
|
1567
1550
|
// 'standard' is the definition's default.
|
|
1568
|
-
['render', render !== undefined && render !== 'standard' ?
|
|
1551
|
+
['render', render !== undefined && render !== 'standard' ? tsLiteral(render) : undefined],
|
|
1569
1552
|
['taxonomy', stationExpr(i.taxonomy)],
|
|
1570
1553
|
]);
|
|
1571
1554
|
// On the base node the VERSION says it: 1.1 routes per outcome, 1.2 adds the
|
|
@@ -1596,7 +1579,7 @@ function emitHitl(node, imp, inputNames, graph) {
|
|
|
1596
1579
|
const fanOut = !outcomePorts && derivesHandles && !versionRoutesHitl(node) && outcomeIdsOfNode(node).length > 1
|
|
1597
1580
|
&& (legacyCompleted || graph?.convergedFanOut(node.id) === true);
|
|
1598
1581
|
if (legacyCompleted) {
|
|
1599
|
-
warnOnce(`human task ${
|
|
1582
|
+
warnOnce(`human task ${tsLiteral(node.id)} leaves on the legacy 'completed' handle, which Studio Web no longer draws `
|
|
1600
1583
|
+ `once a task has outcomes (it reads the edge as the primary outcome only). Recompiling emits one `
|
|
1601
1584
|
+ `outcome-<id> edge per outcome to the same step, so every outcome continues — what the edge meant `
|
|
1602
1585
|
+ `before flow-workbench #3512.`);
|
|
@@ -1604,11 +1587,11 @@ function emitHitl(node, imp, inputNames, graph) {
|
|
|
1604
1587
|
const title = plain(i.title);
|
|
1605
1588
|
const priority = plain(i.priority);
|
|
1606
1589
|
return `${imp.use('hitl')}(${opts([
|
|
1607
|
-
['variant', variant !== undefined ?
|
|
1590
|
+
['variant', variant !== undefined ? tsLiteral(variant) : undefined],
|
|
1608
1591
|
// serialize defaults the title to the step's own name.
|
|
1609
|
-
['title', title !== undefined && title !== node.id ?
|
|
1610
|
-
['priority', priority !== undefined && priority !== 'Low' ?
|
|
1611
|
-
['labels', plain(i.labels) !== undefined ?
|
|
1592
|
+
['title', title !== undefined && title !== node.id ? tsLiteral(title) : undefined],
|
|
1593
|
+
['priority', priority !== undefined && priority !== 'Low' ? tsLiteral(priority) : undefined],
|
|
1594
|
+
['labels', plain(i.labels) !== undefined ? tsLiteral(plain(i.labels)) : undefined],
|
|
1612
1595
|
['recipient', recipientSrc],
|
|
1613
1596
|
['app', appSrc],
|
|
1614
1597
|
['document', documentSrc],
|
|
@@ -1645,7 +1628,7 @@ function unboundMarker(node, labels, key, action) {
|
|
|
1645
1628
|
if (missing.length === 0)
|
|
1646
1629
|
return '';
|
|
1647
1630
|
const names = missing.join(' and ');
|
|
1648
|
-
warnOnce(`node ${
|
|
1631
|
+
warnOnce(`node ${tsLiteral(node.id)} (${node.type}) has no ${missing.join(' or ')} in the .flow (an unbound draft). `
|
|
1649
1632
|
+ `The source leaves ${missing.length > 1 ? 'them' : 'it'} out, and compile refuses the node (BINDING_MISSING) `
|
|
1650
1633
|
+ `until it names both labels: run \`${prepareCommand(key, action ?? '<action>')}\`, then pass `
|
|
1651
1634
|
+ `\`connection\` and \`folder\`.`);
|
|
@@ -1685,8 +1668,8 @@ function emitEventSubscription(node, imp, inputNames) {
|
|
|
1685
1668
|
.map((f) => eventFilterFromTreeLeaf(f))
|
|
1686
1669
|
.filter((f) => f !== undefined)
|
|
1687
1670
|
.map((f) => opts([
|
|
1688
|
-
['field',
|
|
1689
|
-
[f.operator, typeof f.value === 'string' ?
|
|
1671
|
+
['field', tsLiteral(f.field)],
|
|
1672
|
+
[f.operator, typeof f.value === 'string' ? tsLiteral(f.value) : JSON.stringify(f.value)],
|
|
1690
1673
|
]));
|
|
1691
1674
|
}
|
|
1692
1675
|
catch {
|
|
@@ -1701,13 +1684,13 @@ function emitEventSubscription(node, imp, inputNames) {
|
|
|
1701
1684
|
const conn = typeof detail?.connectionId === 'string' ? detail.connectionId : undefined;
|
|
1702
1685
|
const folder = typeof detail?.connectionFolderKey === 'string' ? detail.connectionFolderKey : undefined;
|
|
1703
1686
|
return opts([
|
|
1704
|
-
['connector',
|
|
1705
|
-
['event',
|
|
1687
|
+
['connector', tsLiteral(connector)],
|
|
1688
|
+
['event', tsLiteral(event)],
|
|
1706
1689
|
['where', whereRows.length ? objLit(whereRows) : undefined],
|
|
1707
|
-
['object', object !== undefined ?
|
|
1690
|
+
['object', object !== undefined ? tsLiteral(object) : undefined],
|
|
1708
1691
|
['filters', filterRows.length ? `[${filterRows.join(', ')}]` : undefined],
|
|
1709
|
-
['connection', conn !== undefined ?
|
|
1710
|
-
['folder', folder !== undefined ?
|
|
1692
|
+
['connection', conn !== undefined ? tsLiteral(conn) : undefined],
|
|
1693
|
+
['folder', folder !== undefined ? tsLiteral(folder) : undefined],
|
|
1711
1694
|
]) + unboundMarker(node, { connection: conn, folder }, connector, event);
|
|
1712
1695
|
}
|
|
1713
1696
|
/**
|
|
@@ -1780,18 +1763,18 @@ function emitPublishedResource(node, imp, inputNames) {
|
|
|
1780
1763
|
.map(([k, v]) => [k, emitVal(v, imp, inputNames)]);
|
|
1781
1764
|
const schema = def?.outputDefinition?.output?.schema?.properties;
|
|
1782
1765
|
const returns = schema && Object.keys(schema).length > 0
|
|
1783
|
-
? objLit(Object.entries(schema).map(([k, v]) => [k,
|
|
1766
|
+
? objLit(Object.entries(schema).map(([k, v]) => [k, tsLiteral(String(v?.type ?? 'string'))]))
|
|
1784
1767
|
: undefined;
|
|
1785
1768
|
return `${imp.use(family.factory)}(${opts([
|
|
1786
|
-
['key',
|
|
1787
|
-
['name', name !== undefined ?
|
|
1788
|
-
['location', inSolution ?
|
|
1789
|
-
['folderPath', !inSolution && folderPath !== undefined ?
|
|
1790
|
-
['projectId', inSolution && projectId !== undefined ?
|
|
1769
|
+
['key', tsLiteral(key)],
|
|
1770
|
+
['name', name !== undefined ? tsLiteral(name) : undefined],
|
|
1771
|
+
['location', inSolution ? tsLiteral('in-solution') : undefined],
|
|
1772
|
+
['folderPath', !inSolution && folderPath !== undefined ? tsLiteral(folderPath) : undefined],
|
|
1773
|
+
['projectId', inSolution && projectId !== undefined ? tsLiteral(projectId) : undefined],
|
|
1791
1774
|
['inputs', inputRows.length ? objLit(inputRows) : undefined],
|
|
1792
1775
|
['returns', returns],
|
|
1793
|
-
['form', family.form !== undefined ?
|
|
1794
|
-
['completion', fireAndForget ?
|
|
1776
|
+
['form', family.form !== undefined ? tsLiteral(family.form) : undefined],
|
|
1777
|
+
['completion', fireAndForget ? tsLiteral('fire-and-forget') : undefined],
|
|
1795
1778
|
])})`;
|
|
1796
1779
|
}
|
|
1797
1780
|
function emitConnector(node, imp, inputNames, o) {
|
|
@@ -1820,12 +1803,12 @@ function emitConnector(node, imp, inputNames, o) {
|
|
|
1820
1803
|
const folder = typeof detail.connectionFolderKey === 'string' ? detail.connectionFolderKey : undefined;
|
|
1821
1804
|
const object = connectorObjectName(detail.configuration);
|
|
1822
1805
|
const optsSrc = opts([
|
|
1823
|
-
['connection', connection !== undefined ?
|
|
1824
|
-
['folder', folder !== undefined ?
|
|
1825
|
-
['object', object !== undefined ?
|
|
1806
|
+
['connection', connection !== undefined ? tsLiteral(connection) : undefined],
|
|
1807
|
+
['folder', folder !== undefined ? tsLiteral(folder) : undefined],
|
|
1808
|
+
['object', object !== undefined ? tsLiteral(object) : undefined],
|
|
1826
1809
|
]);
|
|
1827
1810
|
const inputsSrc = objLit(flat) || '{}';
|
|
1828
|
-
const args = [
|
|
1811
|
+
const args = [tsLiteral(split.key), tsLiteral(split.action), inputsSrc, ...(optsSrc ? [optsSrc] : [])];
|
|
1829
1812
|
return `${imp.use('connector')}(${args.join(', ')})`
|
|
1830
1813
|
+ unboundMarker(node, { connection, folder }, split.key, split.action);
|
|
1831
1814
|
}
|
|
@@ -1847,8 +1830,8 @@ function unsupportedSpec(node, imp, o) {
|
|
|
1847
1830
|
const inputs = node.inputs ?? {};
|
|
1848
1831
|
const inputsSrc = Object.keys(inputs).length > 0 ? JSON.stringify(inputs, null, 2) : undefined;
|
|
1849
1832
|
return `${imp.use('rawNode')}(${opts([
|
|
1850
|
-
['nodeType',
|
|
1851
|
-
['version',
|
|
1833
|
+
['nodeType', tsLiteral(node.type)],
|
|
1834
|
+
['version', tsText(node.typeVersion)],
|
|
1852
1835
|
['manifest', constName],
|
|
1853
1836
|
['inputs', inputsSrc],
|
|
1854
1837
|
])})`;
|
|
@@ -1879,7 +1862,7 @@ const TYPE_NAMES = new Set([
|
|
|
1879
1862
|
function typeExpr(type, imp) {
|
|
1880
1863
|
if (TYPE_NAMES.has(type))
|
|
1881
1864
|
return `${imp.use('types')}.${type}`;
|
|
1882
|
-
return
|
|
1865
|
+
return tsLiteral(type);
|
|
1883
1866
|
}
|
|
1884
1867
|
/**
|
|
1885
1868
|
* A global carrying metadata decompiles to the rich VarSpec spelling
|
|
@@ -1889,15 +1872,15 @@ function typeExpr(type, imp) {
|
|
|
1889
1872
|
function declExpr(g, withDefault, imp, shared) {
|
|
1890
1873
|
const meta = [];
|
|
1891
1874
|
if (withDefault && g.defaultValue !== undefined)
|
|
1892
|
-
meta.push(`default: ${
|
|
1875
|
+
meta.push(`default: ${tsLiteral(g.defaultValue)}`);
|
|
1893
1876
|
if (g.description !== undefined)
|
|
1894
|
-
meta.push(`description: ${
|
|
1877
|
+
meta.push(`description: ${tsLiteral(g.description)}`);
|
|
1895
1878
|
if (g.subType !== undefined)
|
|
1896
|
-
meta.push(`subType: ${
|
|
1879
|
+
meta.push(`subType: ${tsLiteral(g.subType)}`);
|
|
1897
1880
|
if (g.schema !== undefined)
|
|
1898
|
-
meta.push(`schema: ${
|
|
1881
|
+
meta.push(`schema: ${tsLiteral(g.schema)}`);
|
|
1899
1882
|
if (shared !== undefined)
|
|
1900
|
-
meta.push(`shared: ${
|
|
1883
|
+
meta.push(`shared: ${tsLiteral(shared)}`);
|
|
1901
1884
|
if (meta.length === 0)
|
|
1902
1885
|
return typeExpr(g.type, imp);
|
|
1903
1886
|
return `{ type: ${typeExpr(g.type, imp)}, ${meta.join(', ')} }`;
|
|
@@ -1954,50 +1937,49 @@ function emitVariables(e, depth, flow, imp, epTriggers = new Set(), shared) {
|
|
|
1954
1937
|
e.line(depth, `.output(${shape(outputs, true)})`);
|
|
1955
1938
|
for (const g of inouts) {
|
|
1956
1939
|
const rich = declExpr(g, false, imp);
|
|
1957
|
-
const def = g.defaultValue !== undefined ? `, ${
|
|
1958
|
-
e.line(depth, `.var(${
|
|
1940
|
+
const def = g.defaultValue !== undefined ? `, ${tsLiteral(g.defaultValue)}` : '';
|
|
1941
|
+
e.line(depth, `.var(${tsLiteral(g.name ?? g.id)}, ${rich}${def})`);
|
|
1959
1942
|
}
|
|
1960
1943
|
}
|
|
1961
1944
|
// ─── Trigger ──────────────────────────────────────────────────────────────────
|
|
1945
|
+
/**
|
|
1946
|
+
* The trigger factory call for a root trigger node, or `undefined` for a type
|
|
1947
|
+
* this file cannot read back. Both the default root (`.trigger(...)`) and every
|
|
1948
|
+
* extra root (`.entryPoint(id, ...)`) read it.
|
|
1949
|
+
*/
|
|
1950
|
+
function triggerFactory(t, imp, inputNames) {
|
|
1951
|
+
// Decompiled source spells the default `manual()` out on purpose: it is more
|
|
1952
|
+
// explicit than hand-authored source so the node's exact definition version
|
|
1953
|
+
// survives recompilation (design §5.3).
|
|
1954
|
+
if (t.type === T.triggerManual)
|
|
1955
|
+
return `${imp.use('manual')}()`;
|
|
1956
|
+
if (t.type === T.triggerScheduled)
|
|
1957
|
+
return `${imp.use('scheduled')}(${opts([['every', tsLiteral(scheduleEvery(t))]])})`;
|
|
1958
|
+
// The form schema is DERIVED from the root's inputs at compile time, so
|
|
1959
|
+
// nothing of it needs recovering — the factory takes no arguments.
|
|
1960
|
+
if (t.type === T.triggerForm)
|
|
1961
|
+
return `${imp.use('formTrigger')}()`;
|
|
1962
|
+
if (t.type === T.triggerConversation)
|
|
1963
|
+
return `${imp.use('conversationTrigger')}()`;
|
|
1964
|
+
if (t.type === T.triggerVoice)
|
|
1965
|
+
return `${imp.use('voiceTrigger')}()`;
|
|
1966
|
+
// A connector EVENT trigger — the same subscription body as a mid-flow wait.
|
|
1967
|
+
const sub = emitEventSubscription(t, imp, inputNames);
|
|
1968
|
+
if (sub !== undefined)
|
|
1969
|
+
return `${imp.use('onEvent')}(${sub})`;
|
|
1970
|
+
return undefined;
|
|
1971
|
+
}
|
|
1962
1972
|
function emitTrigger(e, depth, trigger, imp, o, inputNames = new Set()) {
|
|
1963
1973
|
// The trigger's id is addressable — a flow's inputs are published as its
|
|
1964
1974
|
// output — so a renamed one has to survive the round trip. `start` is the
|
|
1965
1975
|
// default and stays implicit.
|
|
1966
1976
|
if (trigger.id && trigger.id !== DEFAULT_TRIGGER_ID)
|
|
1967
|
-
e.line(depth, `.triggerId(${
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
// survives recompilation (design §5.3).
|
|
1972
|
-
e.line(depth, `.trigger(${imp.use('manual')}()${triggerOptsArg(trigger)})`);
|
|
1973
|
-
return;
|
|
1974
|
-
}
|
|
1975
|
-
if (trigger.type === T.triggerScheduled) {
|
|
1976
|
-
e.line(depth, `.trigger(${imp.use('scheduled')}(${opts([['every', str(scheduleEvery(trigger))]])})${triggerOptsArg(trigger)})`);
|
|
1977
|
+
e.line(depth, `.triggerId(${tsLiteral(trigger.id)})`);
|
|
1978
|
+
const factory = triggerFactory(trigger, imp, inputNames);
|
|
1979
|
+
if (factory !== undefined) {
|
|
1980
|
+
e.line(depth, `.trigger(${factory}${triggerOptsArg(trigger)})`);
|
|
1977
1981
|
return;
|
|
1978
1982
|
}
|
|
1979
|
-
if (trigger.type === T.triggerForm) {
|
|
1980
|
-
// The schema is DERIVED from the flow's inputs at compile time, so nothing
|
|
1981
|
-
// of it needs recovering — the factory takes no arguments.
|
|
1982
|
-
e.line(depth, `.trigger(${imp.use('formTrigger')}()${triggerOptsArg(trigger)})`);
|
|
1983
|
-
return;
|
|
1984
|
-
}
|
|
1985
|
-
if (trigger.type === T.triggerConversation) {
|
|
1986
|
-
e.line(depth, `.trigger(${imp.use('conversationTrigger')}()${triggerOptsArg(trigger)})`);
|
|
1987
|
-
return;
|
|
1988
|
-
}
|
|
1989
|
-
if (trigger.type === T.triggerVoice) {
|
|
1990
|
-
e.line(depth, `.trigger(${imp.use('voiceTrigger')}()${triggerOptsArg(trigger)})`);
|
|
1991
|
-
return;
|
|
1992
|
-
}
|
|
1993
|
-
// A connector EVENT trigger — the same subscription body as a mid-flow wait.
|
|
1994
|
-
{
|
|
1995
|
-
const sub = emitEventSubscription(trigger, imp, inputNames);
|
|
1996
|
-
if (sub !== undefined) {
|
|
1997
|
-
e.line(depth, `.trigger(${imp.use('onEvent')}(${sub})${triggerOptsArg(trigger)})`);
|
|
1998
|
-
return;
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
1983
|
if (o.bestEffort === false) {
|
|
2002
1984
|
throw new Error(`decompile: unsupported trigger type "${trigger.type}".`);
|
|
2003
1985
|
}
|
|
@@ -2183,14 +2165,14 @@ function isIdentityEndSource(raw, name) {
|
|
|
2183
2165
|
function returnOptsArg(node) {
|
|
2184
2166
|
const parts = [];
|
|
2185
2167
|
if (node.id !== 'end')
|
|
2186
|
-
parts.push(`name: ${
|
|
2168
|
+
parts.push(`name: ${tsLiteral(node.id)}`);
|
|
2187
2169
|
const ver = verClause(node);
|
|
2188
2170
|
if (ver)
|
|
2189
2171
|
parts.push(ver);
|
|
2190
2172
|
// The serializer labels an unlabelled End `End`, so that needs no carrying.
|
|
2191
2173
|
const label = node.display?.label;
|
|
2192
2174
|
if (typeof label === 'string' && label !== 'End')
|
|
2193
|
-
parts.push(`label: ${
|
|
2175
|
+
parts.push(`label: ${tsLiteral(label)}`);
|
|
2194
2176
|
return parts.length ? `, { ${parts.join(', ')} }` : '';
|
|
2195
2177
|
}
|
|
2196
2178
|
/**
|
|
@@ -2229,7 +2211,7 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
|
|
|
2229
2211
|
while (cursor !== undefined && cursor !== stop && cursor !== EXIT) {
|
|
2230
2212
|
// A ref forward: this path re-enters a step the main path reaches later.
|
|
2231
2213
|
if (refInto?.has(cursor)) {
|
|
2232
|
-
segs.push(`.stepToRef(${
|
|
2214
|
+
segs.push(`.stepToRef(${tsLiteral(cursor)})`);
|
|
2233
2215
|
return segs;
|
|
2234
2216
|
}
|
|
2235
2217
|
const node = ctx.graph.byId.get(cursor);
|
|
@@ -2241,7 +2223,7 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
|
|
|
2241
2223
|
// terminates are excluded: they are not named steps, so there is nothing a ref
|
|
2242
2224
|
// could resolve against, and each path emitting its own is already correct.
|
|
2243
2225
|
if (ctx.emitted.has(cursor) && node.type !== T.end && node.type !== T.terminate) {
|
|
2244
|
-
segs.push(`.stepToRef(${
|
|
2226
|
+
segs.push(`.stepToRef(${tsLiteral(cursor)})`);
|
|
2245
2227
|
return segs;
|
|
2246
2228
|
}
|
|
2247
2229
|
ctx.emitted.add(cursor);
|
|
@@ -2250,7 +2232,7 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
|
|
|
2250
2232
|
return segs;
|
|
2251
2233
|
}
|
|
2252
2234
|
if (node.type === T.terminate) {
|
|
2253
|
-
segs.push(`.terminate(${
|
|
2235
|
+
segs.push(`.terminate(${tsLiteral(node.id)}, undefined${optsArg(node, ctx)})`);
|
|
2254
2236
|
return segs;
|
|
2255
2237
|
}
|
|
2256
2238
|
if (node.type === T.merge) {
|
|
@@ -2266,10 +2248,10 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
|
|
|
2266
2248
|
const elseSegs = region(portTarget(ctx.graph, node.id, 'false'), r, scope, ipdom, ctx, refInto);
|
|
2267
2249
|
const labels = armLabels(node);
|
|
2268
2250
|
if (labels.trueLabel)
|
|
2269
|
-
thenSegs.unshift(`.label(${
|
|
2251
|
+
thenSegs.unshift(`.label(${tsLiteral(labels.trueLabel)})`);
|
|
2270
2252
|
if (labels.falseLabel)
|
|
2271
|
-
elseSegs.unshift(`.label(${
|
|
2272
|
-
segs.push(`.branch(${
|
|
2253
|
+
elseSegs.unshift(`.label(${tsLiteral(labels.falseLabel)})`);
|
|
2254
|
+
segs.push(`.branch(${tsLiteral(node.id)}, ${cond},\n${reindent(armCb('t', thenSegs), ' ')},\n${reindent(armCb('e', elseSegs), ' ')}${verArg(node)})`);
|
|
2273
2255
|
cursor = r === EXIT ? undefined : r;
|
|
2274
2256
|
continue;
|
|
2275
2257
|
}
|
|
@@ -2313,14 +2295,14 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
|
|
|
2313
2295
|
const cond = typeof condRaw === 'string' && condRaw.length
|
|
2314
2296
|
? emitBareExpr(condRaw.startsWith('=js:') ? condRaw.slice(4) : condRaw, ctx.imp, ctx.inputNames)
|
|
2315
2297
|
: `${ctx.imp.use('lit')}(true)`;
|
|
2316
|
-
segs.push(`.doWhile(${
|
|
2298
|
+
segs.push(`.doWhile(${tsLiteral(node.id)}, ${cond}, ${armCb('b', bodySegs)}${opts})`);
|
|
2317
2299
|
}
|
|
2318
2300
|
else {
|
|
2319
2301
|
const collRaw = unwrapSource(inputs.collection);
|
|
2320
2302
|
const collection = collRaw !== undefined
|
|
2321
2303
|
? emitBareExpr(collRaw.startsWith('=js:') ? collRaw.slice(4) : collRaw, ctx.imp, ctx.inputNames)
|
|
2322
2304
|
: `${ctx.imp.use('lit')}([])`;
|
|
2323
|
-
segs.push(`.loop(${
|
|
2305
|
+
segs.push(`.loop(${tsLiteral(node.id)}, ${collection}, ${armCb('b', bodySegs)}${opts})`);
|
|
2324
2306
|
}
|
|
2325
2307
|
// A container can carry an error handler too — `core.logic.loop` declares
|
|
2326
2308
|
// the handle, and `.onError()` after `.loop(...)` authors it. Without this
|
|
@@ -2334,7 +2316,7 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
|
|
|
2334
2316
|
continue;
|
|
2335
2317
|
}
|
|
2336
2318
|
if (node.type === T.subflow) {
|
|
2337
|
-
segs.push(`.step(${
|
|
2319
|
+
segs.push(`.step(${tsLiteral(node.id)}, ${emitSubflow(node, ctx)}${optsArg(node, ctx)})`);
|
|
2338
2320
|
cursor = scopeSucc(ctx.graph, node.id, scope)[0];
|
|
2339
2321
|
continue;
|
|
2340
2322
|
}
|
|
@@ -2352,14 +2334,14 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
|
|
|
2352
2334
|
const r = ipdom.get(node.id) ?? stop;
|
|
2353
2335
|
const armSrcs = exitPorts.map(({ value, port }) => {
|
|
2354
2336
|
const armSegs = region(portTarget(ctx.graph, node.id, port), r, scope, ipdom, ctx, refInto);
|
|
2355
|
-
return `{ value: ${
|
|
2337
|
+
return `{ value: ${tsLiteral(value)}, body: ${armCb('b', armSegs)} }`;
|
|
2356
2338
|
});
|
|
2357
2339
|
const armList = `[\n${armSrcs.map((a) => reindent(a, ' ')).join(',\n')},\n]`;
|
|
2358
|
-
segs.push(`.stepSwitch(${
|
|
2340
|
+
segs.push(`.stepSwitch(${tsLiteral(node.id)}, ${spec}, ${armList}${optsArg(node, ctx)})`);
|
|
2359
2341
|
cursor = r === EXIT ? undefined : r;
|
|
2360
2342
|
continue;
|
|
2361
2343
|
}
|
|
2362
|
-
segs.push(`.step(${
|
|
2344
|
+
segs.push(`.step(${tsLiteral(node.id)}, ${spec}${optsArg(node, ctx)})`);
|
|
2363
2345
|
// An error handler on this step (source port `error` + `errorHandlingEnabled`).
|
|
2364
2346
|
const succ = scopeSucc(ctx.graph, node.id, scope);
|
|
2365
2347
|
const handler = errorHandlerSeg(node.id, succ, scope, ipdom, ctx);
|
|
@@ -2373,7 +2355,7 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
|
|
|
2373
2355
|
const branchSegs = region(be.targetNodeId, EXIT, scope, ipdom, ctx, mainReach);
|
|
2374
2356
|
if (branchSegs.length === 0)
|
|
2375
2357
|
branchSegs.push('.return({})');
|
|
2376
|
-
segs.push(`.stepToList(${
|
|
2358
|
+
segs.push(`.stepToList(${tsLiteral(be.sourcePort)}, ${armCb('p', branchSegs)})`);
|
|
2377
2359
|
}
|
|
2378
2360
|
// A per-outcome human task routes each NON-primary outcome from its own
|
|
2379
2361
|
// `outcome-<slug>` exit; the primary one continues the main path, so it is
|
|
@@ -2388,7 +2370,7 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
|
|
|
2388
2370
|
const outSegs = region(oe.targetNodeId, EXIT, scope, ipdom, ctx, mainReach);
|
|
2389
2371
|
if (outSegs.length === 0)
|
|
2390
2372
|
outSegs.push('.return({})');
|
|
2391
|
-
segs.push(`.stepToList(${
|
|
2373
|
+
segs.push(`.stepToList(${tsLiteral(oe.sourcePort)}, ${armCb('p', outSegs)})`);
|
|
2392
2374
|
}
|
|
2393
2375
|
}
|
|
2394
2376
|
// A body edge into the enclosing container's break handle: the path exits
|
|
@@ -2410,7 +2392,7 @@ function region(cursor, stop, scope, ipdom, ctx, refInto) {
|
|
|
2410
2392
|
const join = ipdom.get(node.id);
|
|
2411
2393
|
if (join && join !== EXIT && ctx.graph.byId.get(join)?.type === T.merge) {
|
|
2412
2394
|
const arms = succ.map((t, i) => armCb(`a${i}`, region(t, join, scope, ipdom, ctx, refInto)));
|
|
2413
|
-
segs.push(`.parallel(${
|
|
2395
|
+
segs.push(`.parallel(${tsLiteral(join)}, [\n${arms.map((a) => reindent(a, ' ')).join(',\n')},\n]${verArg(ctx.graph.byId.get(join))})`);
|
|
2414
2396
|
cursor = portTarget(ctx.graph, join, 'output');
|
|
2415
2397
|
continue;
|
|
2416
2398
|
}
|
|
@@ -2534,12 +2516,12 @@ function emitSwitch(node, ipdom, scope, ctx, stop, refInto) {
|
|
|
2534
2516
|
if (m) {
|
|
2535
2517
|
valueLiteral = m[2].trim();
|
|
2536
2518
|
try {
|
|
2537
|
-
value =
|
|
2519
|
+
value = tsLiteral(JSON.parse(valueLiteral));
|
|
2538
2520
|
}
|
|
2539
2521
|
catch {
|
|
2540
2522
|
// A non-JSON literal (e.g. single-quoted) — strip matching quotes if any.
|
|
2541
2523
|
const q = valueLiteral.match(/^'(.*)'$/);
|
|
2542
|
-
value = q ?
|
|
2524
|
+
value = q ? tsLiteral(q[1]) : tsLiteral(valueLiteral);
|
|
2543
2525
|
}
|
|
2544
2526
|
}
|
|
2545
2527
|
else {
|
|
@@ -2547,7 +2529,7 @@ function emitSwitch(node, ipdom, scope, ctx, stop, refInto) {
|
|
|
2547
2529
|
}
|
|
2548
2530
|
const armSegs = region(portTarget(ctx.graph, node.id, `case-${c.id}`), r, scope, ipdom, ctx, refInto);
|
|
2549
2531
|
const defaultLabel = `Case ${valueLiteral}`;
|
|
2550
|
-
const labelPart = c.label && c.label !== defaultLabel ? `, label: ${
|
|
2532
|
+
const labelPart = c.label && c.label !== defaultLabel ? `, label: ${tsLiteral(c.label)}` : '';
|
|
2551
2533
|
caseSrcs.push(`{ value: ${value}${labelPart}, body: ${armCb('b', armSegs)} }`);
|
|
2552
2534
|
}
|
|
2553
2535
|
const on = emitBareExpr(disc ?? '', ctx.imp, ctx.inputNames);
|
|
@@ -2564,7 +2546,7 @@ function emitSwitch(node, ipdom, scope, ctx, stop, refInto) {
|
|
|
2564
2546
|
? `\n/* TODO: this switch's case expressions are not a uniform \`<discriminant> === <value>\`; the recovered on/value are best-effort and need review. */`
|
|
2565
2547
|
: '';
|
|
2566
2548
|
const ver = verArg(node);
|
|
2567
|
-
return `.switch(${
|
|
2549
|
+
return `.switch(${tsLiteral(node.id)}, ${on}, ${caseList}${defArm}${ver && !defArm ? ', undefined' : ''}${ver})${warn}`;
|
|
2568
2550
|
}
|
|
2569
2551
|
/** The manifest-less annotation node type — the only annotation `.flow` has. */
|
|
2570
2552
|
const STICKY_NOTE_TYPE = 'stickyNote';
|
|
@@ -2588,14 +2570,14 @@ function stickyNotesSeg(nodes, flow) {
|
|
|
2588
2570
|
const ui = { ...(n.ui ?? {}), ...(hoisted[n.id] ?? {}) };
|
|
2589
2571
|
const pos = ui.position ?? { x: 0, y: 0 };
|
|
2590
2572
|
const fields = [
|
|
2591
|
-
`id: ${
|
|
2592
|
-
`content: ${
|
|
2573
|
+
`id: ${tsLiteral(n.id)}`,
|
|
2574
|
+
`content: ${tsLiteral(typeof i.content === 'string' ? i.content : '')}`,
|
|
2593
2575
|
];
|
|
2594
2576
|
if (typeof i.color === 'string' && i.color !== 'yellow')
|
|
2595
|
-
fields.push(`color: ${
|
|
2596
|
-
fields.push(`x: ${
|
|
2577
|
+
fields.push(`color: ${tsLiteral(i.color)}`);
|
|
2578
|
+
fields.push(`x: ${tsNumber(pos.x)}`, `y: ${tsNumber(pos.y)}`);
|
|
2597
2579
|
if (ui.size && typeof ui.size.width === 'number' && typeof ui.size.height === 'number') {
|
|
2598
|
-
fields.push(`width: ${
|
|
2580
|
+
fields.push(`width: ${tsNumber(ui.size.width)}`, `height: ${tsNumber(ui.size.height)}`);
|
|
2599
2581
|
}
|
|
2600
2582
|
return ` { ${fields.join(', ')} },`;
|
|
2601
2583
|
});
|
|
@@ -2645,9 +2627,9 @@ function layoutSeg(flow, nodes, edges) {
|
|
|
2645
2627
|
const pos = ui.position;
|
|
2646
2628
|
if (!pos || typeof pos.x !== 'number' || typeof pos.y !== 'number')
|
|
2647
2629
|
continue;
|
|
2648
|
-
const fields = [`position: { x: ${
|
|
2630
|
+
const fields = [`position: { x: ${tsNumber(pos.x)}, y: ${tsNumber(pos.y)} }`];
|
|
2649
2631
|
if (ui.size && typeof ui.size.width === 'number' && typeof ui.size.height === 'number') {
|
|
2650
|
-
fields.push(`size: { width: ${
|
|
2632
|
+
fields.push(`size: { width: ${tsNumber(ui.size.width)}, height: ${tsNumber(ui.size.height)} }`);
|
|
2651
2633
|
}
|
|
2652
2634
|
if (typeof ui.collapsed === 'boolean')
|
|
2653
2635
|
fields.push(`collapsed: ${boolLit(ui.collapsed)}`);
|
|
@@ -2671,7 +2653,7 @@ function layoutSeg(flow, nodes, edges) {
|
|
|
2671
2653
|
continue;
|
|
2672
2654
|
const rendered = pts
|
|
2673
2655
|
.filter((p) => p && typeof p.x === 'number' && typeof p.y === 'number')
|
|
2674
|
-
.map((p) => `{ x: ${
|
|
2656
|
+
.map((p) => `{ x: ${tsNumber(p.x)}, y: ${tsNumber(p.y)}${typeof p.id === 'string' ? `, id: ${tsLiteral(p.id)}` : ''} }`);
|
|
2675
2657
|
if (rendered.length)
|
|
2676
2658
|
parts.push(`${which}: [${rendered.join(', ')}]`);
|
|
2677
2659
|
}
|
|
@@ -2680,7 +2662,7 @@ function layoutSeg(flow, nodes, edges) {
|
|
|
2680
2662
|
const pair = `${e.sourceNodeId}->${e.targetNodeId}`;
|
|
2681
2663
|
if ((pairCount.get(pair) ?? 0) !== 1)
|
|
2682
2664
|
continue; // ambiguous — see the note above
|
|
2683
|
-
edgeEntries.push(`${
|
|
2665
|
+
edgeEntries.push(`${tsLiteral(pair)}: { ${parts.join(', ')} }`);
|
|
2684
2666
|
}
|
|
2685
2667
|
if (!nodeEntries.length && !edgeEntries.length)
|
|
2686
2668
|
return undefined;
|
|
@@ -2725,7 +2707,7 @@ function emitChildFlow(name, child, ctx) {
|
|
|
2725
2707
|
emitted: new Set(),
|
|
2726
2708
|
o: ctx.o,
|
|
2727
2709
|
};
|
|
2728
|
-
const parts = [`${ctx.imp.use('flow')}(${
|
|
2710
|
+
const parts = [`${ctx.imp.use('flow')}(${tsLiteral(name)})`];
|
|
2729
2711
|
// Variables.
|
|
2730
2712
|
const shape = (dir) => `{ ${globals.filter((g) => g.direction === dir).map((g) => `${key(g.name ?? g.id)}: ${declExpr(g, dir !== 'inout', ctx.imp)}`).join(', ')} }`;
|
|
2731
2713
|
if (globals.some((g) => g.direction === 'in'))
|
|
@@ -2733,8 +2715,8 @@ function emitChildFlow(name, child, ctx) {
|
|
|
2733
2715
|
if (globals.some((g) => g.direction === 'out'))
|
|
2734
2716
|
parts.push(`.output(${shape('out')})`);
|
|
2735
2717
|
for (const g of globals.filter((g) => g.direction === 'inout')) {
|
|
2736
|
-
const def = g.defaultValue !== undefined ? `, ${
|
|
2737
|
-
parts.push(`.var(${
|
|
2718
|
+
const def = g.defaultValue !== undefined ? `, ${tsLiteral(g.defaultValue)}` : '';
|
|
2719
|
+
parts.push(`.var(${tsLiteral(g.name ?? g.id)}, ${declExpr(g, false, ctx.imp)}${def})`);
|
|
2738
2720
|
}
|
|
2739
2721
|
// Body: the child's trigger is its own manual Start; walk from its successor.
|
|
2740
2722
|
const trigger = (child.nodes ?? []).find((n) => isTrigger(n.type) && !(child.edges ?? []).some((e) => e.targetNodeId === n.id));
|
|
@@ -2788,7 +2770,7 @@ export function decompile(flow, options = {}) {
|
|
|
2788
2770
|
(flow.nodes ?? []).find((n) => String(n.type ?? '').startsWith('core.trigger.'))?.id ??
|
|
2789
2771
|
DEFAULT_TRIGGER_ID;
|
|
2790
2772
|
const e = new Emit();
|
|
2791
|
-
e.line(0, `export default ${imp.use('flow')}(${
|
|
2773
|
+
e.line(0, `export default ${imp.use('flow')}(${tsLiteral(slugId(flow))})`);
|
|
2792
2774
|
const d = 1;
|
|
2793
2775
|
// The file-format version FIRST, mirroring the order the file itself carries
|
|
2794
2776
|
// it (`id`, `version`, `name`) — and emitted even when it equals this SDK's
|
|
@@ -2806,9 +2788,9 @@ export function decompile(flow, options = {}) {
|
|
|
2806
2788
|
e.line(d, `// TODO: ${commentText(schema.problem)}`);
|
|
2807
2789
|
}
|
|
2808
2790
|
if (flow.name !== undefined && flow.name !== flow.id)
|
|
2809
|
-
e.line(d, `.name(${
|
|
2791
|
+
e.line(d, `.name(${tsLiteral(flow.name)})`);
|
|
2810
2792
|
if (typeof flow.description === 'string') {
|
|
2811
|
-
e.line(d, `.description(${
|
|
2793
|
+
e.line(d, `.description(${tsLiteral(flow.description)})`);
|
|
2812
2794
|
}
|
|
2813
2795
|
// Trigger nodes. One root is the default: the isDefaultEntryPoint carrier
|
|
2814
2796
|
// when the file marks one (a multi-root flow always does), else `start`.
|
|
@@ -2831,7 +2813,7 @@ export function decompile(flow, options = {}) {
|
|
|
2831
2813
|
const detached = detachedTopLevelNodes(flow.nodes ?? [], graph, triggerNodes, trigger);
|
|
2832
2814
|
const detachedIds = new Set(detached.map((n) => n.id));
|
|
2833
2815
|
if (detached.length > 0) {
|
|
2834
|
-
const listing = detached.map((n) => `${
|
|
2816
|
+
const listing = detached.map((n) => `${tsLiteral(n.id)} (${n.type})`).join(', ');
|
|
2835
2817
|
const message = `${detached.length} node(s) are not reachable from any trigger — no edge leads to them: ${listing}. `
|
|
2836
2818
|
+ 'The builder has no detached-node construct, so this source omits them and recompiling drops them. '
|
|
2837
2819
|
+ 'Connect each one with an edge in the .flow first, or edit that node\'s JSON directly.';
|
|
@@ -2839,14 +2821,14 @@ export function decompile(flow, options = {}) {
|
|
|
2839
2821
|
throw new Error(`decompile: ${message}`);
|
|
2840
2822
|
warnOnce(message);
|
|
2841
2823
|
for (const n of detached) {
|
|
2842
|
-
e.line(d, `// TODO: node ${commentText(
|
|
2824
|
+
e.line(d, `// TODO: node ${commentText(tsLiteral(n.id))} (${commentText(n.type)}) is not reachable from any trigger and is NOT in this source; recompiling drops it. Connect it in the .flow or edit its JSON directly.`);
|
|
2843
2825
|
}
|
|
2844
2826
|
}
|
|
2845
2827
|
// `{ shared }` input copies on the roots (#924). Any other trigger-level
|
|
2846
2828
|
// update has no builder spelling: say so instead of dropping it.
|
|
2847
2829
|
const shared = sharedCopies(flow, triggerNodes);
|
|
2848
2830
|
if (shared.unrecognized.length) {
|
|
2849
|
-
const listing = shared.unrecognized.map((u) => `${
|
|
2831
|
+
const listing = shared.unrecognized.map((u) => `${tsLiteral(u.variableId)} on ${tsLiteral(u.trigger)}`).join(', ');
|
|
2850
2832
|
const message = `${shared.unrecognized.length} variable update(s) on a trigger node are not a { shared } input copy: ${listing}. `
|
|
2851
2833
|
+ 'The builder writes a trigger-level update only for { type, shared: \'<var>\' } (the row `<var> ← $vars.<trigger>.output.<input>`), '
|
|
2852
2834
|
+ 'so this source omits them and recompiling drops them.';
|
|
@@ -2930,21 +2912,11 @@ function scheduleEvery(t) {
|
|
|
2930
2912
|
}
|
|
2931
2913
|
/** One `.entryPoint(id, trigger, { inputs, version }, prefix)` segment for a non-default root. */
|
|
2932
2914
|
function entryPointSeg(t, scope, ipdom, ctx) {
|
|
2933
|
-
const
|
|
2934
|
-
|
|
2935
|
-
: t.type
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
? `${ctx.imp.use('conversationTrigger')}()`
|
|
2939
|
-
: t.type === T.triggerVoice
|
|
2940
|
-
? `${ctx.imp.use('voiceTrigger')}()`
|
|
2941
|
-
: t.type === T.triggerManual
|
|
2942
|
-
? `${ctx.imp.use('manual')}()`
|
|
2943
|
-
: (() => {
|
|
2944
|
-
if (ctx.o.bestEffort === false)
|
|
2945
|
-
throw new Error(`decompile: unsupported entry-point trigger type "${t.type}".`);
|
|
2946
|
-
return `${ctx.imp.use('manual')}() /* TODO: unsupported trigger type ${commentText(t.type)} */`;
|
|
2947
|
-
})();
|
|
2915
|
+
const known = triggerFactory(t, ctx.imp, ctx.inputNames);
|
|
2916
|
+
if (known === undefined && ctx.o.bestEffort === false) {
|
|
2917
|
+
throw new Error(`decompile: unsupported entry-point trigger type "${t.type}".`);
|
|
2918
|
+
}
|
|
2919
|
+
const factory = known ?? `${ctx.imp.use('manual')}() /* TODO: unsupported trigger type ${commentText(t.type)} */`;
|
|
2948
2920
|
const scoped = readFlowGlobals(ctx.flow.variables, runStrict)
|
|
2949
2921
|
.filter((g) => g.direction === 'in' && g.triggerNodeId === t.id);
|
|
2950
2922
|
const optParts = [];
|
|
@@ -2957,5 +2929,5 @@ function entryPointSeg(t, scope, ipdom, ctx) {
|
|
|
2957
2929
|
const prefixSegs = first !== undefined ? region(first, EXIT, scope, ipdom, ctx) : [];
|
|
2958
2930
|
const optArgText = optParts.length ? `, { ${optParts.join(', ')} }` : (prefixSegs.length ? ', undefined' : '');
|
|
2959
2931
|
const prefix = prefixSegs.length ? `, ${armCb('b', prefixSegs)}` : '';
|
|
2960
|
-
return `.entryPoint(${
|
|
2932
|
+
return `.entryPoint(${tsLiteral(t.id)}, ${factory}${optArgText}${prefix})`;
|
|
2961
2933
|
}
|