@galaxy-tool-util/schema 0.1.0 → 0.2.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.
Files changed (81) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +14 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +14 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/workflow/clean.d.ts +27 -0
  7. package/dist/workflow/clean.d.ts.map +1 -1
  8. package/dist/workflow/clean.js +29 -0
  9. package/dist/workflow/clean.js.map +1 -1
  10. package/dist/workflow/coercions.d.ts +22 -0
  11. package/dist/workflow/coercions.d.ts.map +1 -0
  12. package/dist/workflow/coercions.js +67 -0
  13. package/dist/workflow/coercions.js.map +1 -0
  14. package/dist/workflow/index.d.ts +6 -1
  15. package/dist/workflow/index.d.ts.map +1 -1
  16. package/dist/workflow/index.js +6 -1
  17. package/dist/workflow/index.js.map +1 -1
  18. package/dist/workflow/normalized/index.d.ts +5 -2
  19. package/dist/workflow/normalized/index.d.ts.map +1 -1
  20. package/dist/workflow/normalized/index.js +2 -0
  21. package/dist/workflow/normalized/index.js.map +1 -1
  22. package/dist/workflow/normalized/stateful-runner.d.ts +82 -0
  23. package/dist/workflow/normalized/stateful-runner.d.ts.map +1 -0
  24. package/dist/workflow/normalized/stateful-runner.js +122 -0
  25. package/dist/workflow/normalized/stateful-runner.js.map +1 -0
  26. package/dist/workflow/normalized/toFormat2.d.ts +19 -1
  27. package/dist/workflow/normalized/toFormat2.d.ts.map +1 -1
  28. package/dist/workflow/normalized/toFormat2.js +47 -16
  29. package/dist/workflow/normalized/toFormat2.js.map +1 -1
  30. package/dist/workflow/normalized/toFormat2Stateful.d.ts +30 -0
  31. package/dist/workflow/normalized/toFormat2Stateful.d.ts.map +1 -0
  32. package/dist/workflow/normalized/toFormat2Stateful.js +58 -0
  33. package/dist/workflow/normalized/toFormat2Stateful.js.map +1 -0
  34. package/dist/workflow/normalized/toNative.d.ts +10 -1
  35. package/dist/workflow/normalized/toNative.d.ts.map +1 -1
  36. package/dist/workflow/normalized/toNative.js +24 -8
  37. package/dist/workflow/normalized/toNative.js.map +1 -1
  38. package/dist/workflow/normalized/toNativeStateful.d.ts +31 -0
  39. package/dist/workflow/normalized/toNativeStateful.d.ts.map +1 -0
  40. package/dist/workflow/normalized/toNativeStateful.js +55 -0
  41. package/dist/workflow/normalized/toNativeStateful.js.map +1 -0
  42. package/dist/workflow/precheck.d.ts +54 -0
  43. package/dist/workflow/precheck.d.ts.map +1 -0
  44. package/dist/workflow/precheck.js +91 -0
  45. package/dist/workflow/precheck.js.map +1 -0
  46. package/dist/workflow/raw/gxformat2.effect.d.ts +108 -332
  47. package/dist/workflow/raw/gxformat2.effect.d.ts.map +1 -1
  48. package/dist/workflow/raw/gxformat2.effect.js +106 -94
  49. package/dist/workflow/raw/gxformat2.effect.js.map +1 -1
  50. package/dist/workflow/raw/native.effect.d.ts +30 -177
  51. package/dist/workflow/raw/native.effect.d.ts.map +1 -1
  52. package/dist/workflow/raw/native.effect.js +43 -31
  53. package/dist/workflow/raw/native.effect.js.map +1 -1
  54. package/dist/workflow/roundtrip.d.ts +54 -0
  55. package/dist/workflow/roundtrip.d.ts.map +1 -0
  56. package/dist/workflow/roundtrip.js +516 -0
  57. package/dist/workflow/roundtrip.js.map +1 -0
  58. package/dist/workflow/runtime-markers.d.ts +20 -0
  59. package/dist/workflow/runtime-markers.d.ts.map +1 -0
  60. package/dist/workflow/runtime-markers.js +26 -0
  61. package/dist/workflow/runtime-markers.js.map +1 -0
  62. package/dist/workflow/stale-keys.d.ts +16 -0
  63. package/dist/workflow/stale-keys.d.ts.map +1 -0
  64. package/dist/workflow/stale-keys.js +43 -0
  65. package/dist/workflow/stale-keys.js.map +1 -0
  66. package/dist/workflow/state-merge.d.ts.map +1 -1
  67. package/dist/workflow/state-merge.js +5 -22
  68. package/dist/workflow/state-merge.js.map +1 -1
  69. package/dist/workflow/stateful-convert.d.ts +47 -0
  70. package/dist/workflow/stateful-convert.d.ts.map +1 -0
  71. package/dist/workflow/stateful-convert.js +151 -0
  72. package/dist/workflow/stateful-convert.js.map +1 -0
  73. package/dist/workflow/stateful-validate.d.ts +46 -0
  74. package/dist/workflow/stateful-validate.d.ts.map +1 -0
  75. package/dist/workflow/stateful-validate.js +96 -0
  76. package/dist/workflow/stateful-validate.js.map +1 -0
  77. package/dist/workflow/walker.d.ts +53 -0
  78. package/dist/workflow/walker.d.ts.map +1 -0
  79. package/dist/workflow/walker.js +189 -0
  80. package/dist/workflow/walker.js.map +1 -0
  81. package/package.json +18 -14
@@ -0,0 +1,516 @@
1
+ import { ensureNative } from "./normalized/ensure.js";
2
+ import { toFormat2Stateful } from "./normalized/toFormat2Stateful.js";
3
+ import { toNativeStateful } from "./normalized/toNativeStateful.js";
4
+ import { isConnectedValue, isRuntimeValue } from "./runtime-markers.js";
5
+ import { STALE_KEYS as SKIP_KEYS, isRuntimeLeakKey } from "./stale-keys.js";
6
+ import { stripStaleKeysToolAware } from "./clean.js";
7
+ // --- Bookkeeping / internal helpers ---
8
+ /** Compare two scalar values with format2↔native type-equivalence. */
9
+ function scalarsEquivalent(a, b) {
10
+ if (a === b)
11
+ return true;
12
+ // Nullish equivalence: null, undefined, and the string "null" all
13
+ // represent "no value" in serialized workflow state. JSON has no
14
+ // undefined, so a JS undefined reaching the differ means a key was
15
+ // present-but-unset or missing entirely — equivalent to an explicit
16
+ // null on the other side. Matches Python roundtrip.py's
17
+ // `orig_val in (None, "null")` treatment.
18
+ const isNullish = (v) => v === null || v === undefined || v === "null";
19
+ if (isNullish(a) && isNullish(b))
20
+ return true;
21
+ if (a == null || b == null)
22
+ return false;
23
+ // Booleans ↔ "true"/"false"/"yes"/"no"
24
+ const asBool = (v) => {
25
+ if (typeof v === "boolean")
26
+ return v;
27
+ if (typeof v === "string") {
28
+ const s = v.toLowerCase();
29
+ if (s === "true" || s === "yes")
30
+ return true;
31
+ if (s === "false" || s === "no")
32
+ return false;
33
+ }
34
+ return undefined;
35
+ };
36
+ const ab = asBool(a);
37
+ const bb = asBool(b);
38
+ if (ab !== undefined && bb !== undefined)
39
+ return ab === bb;
40
+ // Numbers ↔ strings
41
+ const asNum = (v) => {
42
+ if (typeof v === "number")
43
+ return v;
44
+ if (typeof v === "string" && v.trim() !== "") {
45
+ const n = Number(v);
46
+ return Number.isFinite(n) ? n : undefined;
47
+ }
48
+ return undefined;
49
+ };
50
+ const an = asNum(a);
51
+ const bn = asNum(b);
52
+ if (an !== undefined && bn !== undefined)
53
+ return an === bn;
54
+ return false;
55
+ }
56
+ function isPlainObject(v) {
57
+ return v != null && typeof v === "object" && !Array.isArray(v);
58
+ }
59
+ /**
60
+ * All leaf values are null / "null". Format2 export drops these sections,
61
+ * so their absence in the reimported state is benign.
62
+ */
63
+ function isAllNullDict(v) {
64
+ if (v === null || v === "null")
65
+ return true;
66
+ if (Array.isArray(v))
67
+ return v.every(isAllNullDict);
68
+ if (isPlainObject(v)) {
69
+ for (const [k, val] of Object.entries(v)) {
70
+ if (SKIP_KEYS.has(k))
71
+ continue;
72
+ if (!isAllNullDict(val))
73
+ return false;
74
+ }
75
+ return true;
76
+ }
77
+ return false;
78
+ }
79
+ /**
80
+ * Empty-repeat placeholder: empty arrays + null leaves. Requires at least
81
+ * one empty list to be present, matching Python's `_is_empty_container_dict`
82
+ * in `roundtrip.py` — otherwise a plain `{}` would be classified as this
83
+ * kind when `all_null_section_omitted` is more accurate.
84
+ */
85
+ function isEmptyContainerDict(v) {
86
+ let sawEmptyList = false;
87
+ const walk = (x) => {
88
+ if (x === null)
89
+ return true;
90
+ if (Array.isArray(x)) {
91
+ if (x.length === 0) {
92
+ sawEmptyList = true;
93
+ return true;
94
+ }
95
+ return x.every(walk);
96
+ }
97
+ if (isPlainObject(x)) {
98
+ for (const [k, val] of Object.entries(x)) {
99
+ if (SKIP_KEYS.has(k))
100
+ continue;
101
+ if (!walk(val))
102
+ return false;
103
+ }
104
+ return true;
105
+ }
106
+ return false;
107
+ };
108
+ const ok = walk(v);
109
+ return ok && sawEmptyList;
110
+ }
111
+ /** Contains only connection/runtime markers (moved to `in` block). */
112
+ function isConnectionOnlyDict(v) {
113
+ if (v == null)
114
+ return true;
115
+ if (isConnectedValue(v) || isRuntimeValue(v))
116
+ return true;
117
+ if (Array.isArray(v))
118
+ return v.every(isConnectionOnlyDict);
119
+ if (isPlainObject(v)) {
120
+ let sawMarker = false;
121
+ for (const [k, val] of Object.entries(v)) {
122
+ if (SKIP_KEYS.has(k))
123
+ continue;
124
+ if (val == null)
125
+ continue;
126
+ if (!isConnectionOnlyDict(val))
127
+ return false;
128
+ sawMarker = true;
129
+ }
130
+ return sawMarker;
131
+ }
132
+ return false;
133
+ }
134
+ function classifyMissing(value) {
135
+ if (value === null || value === undefined || value === "null") {
136
+ return "all_null_section_omitted";
137
+ }
138
+ if (isConnectedValue(value) || isRuntimeValue(value)) {
139
+ return "connection_only_section_omitted";
140
+ }
141
+ if (isConnectionOnlyDict(value))
142
+ return "connection_only_section_omitted";
143
+ if (isAllNullDict(value))
144
+ return "all_null_section_omitted";
145
+ if (isEmptyContainerDict(value))
146
+ return "empty_container_omitted";
147
+ return undefined;
148
+ }
149
+ /**
150
+ * Multi-select equivalence: `"a,b"`, `["a","b"]`, and a bare scalar
151
+ * compared against a 1-element list are all considered equivalent.
152
+ */
153
+ function multiSelectEquivalent(a, b) {
154
+ const norm = (v) => {
155
+ if (Array.isArray(v))
156
+ return v.map((x) => String(x));
157
+ if (typeof v === "string")
158
+ return v.split(",").map((s) => s.trim());
159
+ if (typeof v === "number" || typeof v === "boolean")
160
+ return [String(v)];
161
+ return undefined;
162
+ };
163
+ const na = norm(a);
164
+ const nb = norm(b);
165
+ if (!na || !nb)
166
+ return false;
167
+ if (na.length !== nb.length)
168
+ return false;
169
+ for (let i = 0; i < na.length; i++)
170
+ if (na[i] !== nb[i])
171
+ return false;
172
+ return true;
173
+ }
174
+ // --- Recursive diff ---
175
+ /**
176
+ * Recursive lockstep diff of two `tool_state` trees. Intentionally does
177
+ * not use `walker.ts` — that module is a single-tree leaf-callback walker
178
+ * keyed by parameter model, whereas this traverses two plain dicts in
179
+ * parallel without a tool-inputs context. Also intentionally does NOT
180
+ * JSON-decode string leaves (cf. Python's `_try_json_decode`): this port
181
+ * treats containers as proper dicts/lists end-to-end, matching the
182
+ * walker's "no legacy decode" principle.
183
+ */
184
+ function compareTree(orig, after, path, diffs) {
185
+ // Exact equivalence
186
+ if (scalarsEquivalent(orig, after))
187
+ return;
188
+ // Multi-select normalization: only when exactly one side is an array
189
+ // (scalar ↔ list, comma-string ↔ list). Two arrays fall through to the
190
+ // element-wise recursion below so identical arrays don't get flagged.
191
+ if (Array.isArray(orig) !== Array.isArray(after) && multiSelectEquivalent(orig, after)) {
192
+ diffs.push({
193
+ path,
194
+ severity: "benign",
195
+ kind: "multi_select_normalized",
196
+ message: `multi-select representation differs: ${JSON.stringify(orig)} vs ${JSON.stringify(after)}`,
197
+ });
198
+ return;
199
+ }
200
+ // Scalar mismatch after coercion rules → error
201
+ if (!isPlainObject(orig) &&
202
+ !isPlainObject(after) &&
203
+ !Array.isArray(orig) &&
204
+ !Array.isArray(after)) {
205
+ diffs.push({
206
+ path,
207
+ severity: "error",
208
+ message: `value changed: ${JSON.stringify(orig)} → ${JSON.stringify(after)}`,
209
+ });
210
+ return;
211
+ }
212
+ // Arrays: compare lengths, recurse element-wise
213
+ if (Array.isArray(orig) && Array.isArray(after)) {
214
+ if (orig.length !== after.length) {
215
+ diffs.push({
216
+ path,
217
+ severity: "error",
218
+ message: `array length ${orig.length} → ${after.length}`,
219
+ });
220
+ return;
221
+ }
222
+ for (let i = 0; i < orig.length; i++) {
223
+ compareTree(orig[i], after[i], `${path}[${i}]`, diffs);
224
+ }
225
+ return;
226
+ }
227
+ // Dict mismatch with non-dict other side
228
+ if (!isPlainObject(orig) || !isPlainObject(after)) {
229
+ // One side might be an omitted section represented by null/absent on the other
230
+ const benign = classifyMissing(orig) ?? classifyMissing(after);
231
+ if (benign) {
232
+ diffs.push({
233
+ path,
234
+ severity: "benign",
235
+ kind: benign,
236
+ message: `type change tolerated as ${benign}`,
237
+ });
238
+ return;
239
+ }
240
+ diffs.push({
241
+ path,
242
+ severity: "error",
243
+ message: `structural mismatch: ${typeof orig} vs ${typeof after}`,
244
+ });
245
+ return;
246
+ }
247
+ // Both plain objects → key-wise compare
248
+ const keys = new Set([...Object.keys(orig), ...Object.keys(after)]);
249
+ for (const key of keys) {
250
+ if (SKIP_KEYS.has(key)) {
251
+ // Presence on either side is benign bookkeeping (only report if orig had
252
+ // it — avoids noise from reimported state never having it)
253
+ if (key in orig && !(key in after)) {
254
+ diffs.push({
255
+ path: `${path}.${key}`,
256
+ severity: "benign",
257
+ kind: "bookkeeping_stripped",
258
+ message: `stale key ${key} stripped`,
259
+ });
260
+ }
261
+ continue;
262
+ }
263
+ if (isRuntimeLeakKey(key)) {
264
+ // Walker drops runtime-leak keys (`__workflow_invocation_uuid__`,
265
+ // `*|__identifier__`) during stateful conversion — neither side of the
266
+ // roundtrip keeps them. Mirrors Galaxy's `RUNTIME_LEAK` classification
267
+ // in `stale_keys.py`; `for_export` allows them but they don't survive
268
+ // format2 round-trip. Treat any drop/appearance as benign.
269
+ const hasOrig = key in orig;
270
+ const hasAfter = key in after;
271
+ if (hasOrig !== hasAfter) {
272
+ diffs.push({
273
+ path: path ? `${path}.${key}` : key,
274
+ severity: "benign",
275
+ kind: "runtime_leak_stripped",
276
+ message: `runtime leak ${key} ${hasOrig ? "stripped" : "appeared"}`,
277
+ });
278
+ }
279
+ continue;
280
+ }
281
+ const subPath = path ? `${path}.${key}` : key;
282
+ const hasOrig = key in orig;
283
+ const hasAfter = key in after;
284
+ if (hasOrig && hasAfter) {
285
+ compareTree(orig[key], after[key], subPath, diffs);
286
+ continue;
287
+ }
288
+ // Missing on one side — classify
289
+ const presentValue = hasOrig ? orig[key] : after[key];
290
+ // Null/"null" leaves: matches Python roundtrip.py where
291
+ // `orig_val in (None, "null", [])` short-circuits with no diff. This
292
+ // keeps `clean=true` aligned with the Python reference's "ok" status.
293
+ if (presentValue === null ||
294
+ presentValue === undefined ||
295
+ presentValue === "null" ||
296
+ (Array.isArray(presentValue) && presentValue.length === 0)) {
297
+ continue;
298
+ }
299
+ const benign = classifyMissing(presentValue);
300
+ if (benign) {
301
+ diffs.push({
302
+ path: subPath,
303
+ severity: "benign",
304
+ kind: benign,
305
+ message: `key ${hasOrig ? "dropped" : "added"} (${benign})`,
306
+ });
307
+ }
308
+ else {
309
+ diffs.push({
310
+ path: subPath,
311
+ severity: "error",
312
+ message: `key ${hasOrig ? "missing after roundtrip" : "appeared after roundtrip"}`,
313
+ });
314
+ }
315
+ }
316
+ }
317
+ /**
318
+ * Walk a native workflow collecting tool steps and subworkflow references.
319
+ *
320
+ * Tool step ids are prefixed with their parent chain separated by `.` so
321
+ * nested ids don't collide with top-level ids (e.g. `3.0` = step 0 inside
322
+ * the subworkflow at top-level id 3). Depth tracks nesting for reporters.
323
+ * External (URL/TRS) subworkflow refs are recorded but not recursed into.
324
+ */
325
+ function collectSteps(wf, prefix = "", depth = 0) {
326
+ const tools = new Map();
327
+ const subworkflows = [];
328
+ for (const [key, step] of Object.entries(wf.steps)) {
329
+ const localId = String(step.id ?? key);
330
+ const fullId = prefix ? `${prefix}.${localId}` : localId;
331
+ if (step.type === "tool") {
332
+ tools.set(fullId, { step, depth });
333
+ }
334
+ else if (step.type === "subworkflow") {
335
+ subworkflows.push({ stepId: fullId, depth, workflow: step.subworkflow ?? null });
336
+ if (step.subworkflow != null) {
337
+ const nested = collectSteps(step.subworkflow, fullId, depth + 1);
338
+ for (const [k, v] of nested.tools)
339
+ tools.set(k, v);
340
+ subworkflows.push(...nested.subworkflows);
341
+ }
342
+ }
343
+ }
344
+ return { tools, subworkflows };
345
+ }
346
+ // --- Public entry point ---
347
+ /**
348
+ * Roundtrip a native workflow through format2 and back, diffing each
349
+ * tool step's `tool_state`. Benign diffs (type coercion, connection
350
+ * moves, stale-key stripping) are reported but don't count as failures.
351
+ *
352
+ * Returns `success=true` iff no error-severity diffs and no conversion
353
+ * failures. `clean=true` iff there are zero diffs of any severity.
354
+ */
355
+ export function roundtripValidate(nativeRaw, toolInputsResolver) {
356
+ const original = ensureNative(nativeRaw);
357
+ const { tools: originalSteps, subworkflows: originalSubworkflows } = collectSteps(original);
358
+ // Pre-clean: strip undeclared keys from each tool step's `tool_state`
359
+ // using the tool definition. Mirrors Galaxy's
360
+ // `roundtrip_validate(clean_stale=True)` default, which runs
361
+ // `clean_stale_state` before diffing so runtime leaks, stale-branch
362
+ // params, and tool-upgrade residue are removed from the original.
363
+ // Without this pass, the diff flags asymmetries between the raw
364
+ // original and the walker-produced reimport as errors.
365
+ for (const entry of originalSteps.values()) {
366
+ const step = entry.step;
367
+ if (step.type !== "tool" || !step.tool_id)
368
+ continue;
369
+ const inputs = toolInputsResolver(step.tool_id, step.tool_version ?? null);
370
+ if (!inputs)
371
+ continue;
372
+ // Deep clone via JSON round-trip — tool_state is JSON-compatible by
373
+ // design (parsed from a JSON string), and ES2022 lib doesn't include
374
+ // structuredClone.
375
+ const stateClone = JSON.parse(JSON.stringify(step.tool_state));
376
+ const cleaned = stripStaleKeysToolAware(stateClone, inputs, (step.input_connections ?? {}));
377
+ // Mutate the collected step's tool_state in place. `original` was
378
+ // produced fresh by `ensureNative(nativeRaw)` so mutation is local.
379
+ step.tool_state = cleaned;
380
+ }
381
+ let forwardSteps = [];
382
+ let reverseSteps = [];
383
+ let reimported;
384
+ const stepResults = [];
385
+ // Forward: native → format2
386
+ let forward;
387
+ try {
388
+ forward = toFormat2Stateful(nativeRaw, toolInputsResolver);
389
+ }
390
+ catch (err) {
391
+ // Total failure — attribute to all tool steps (including nested)
392
+ const error = err instanceof Error ? err.message : String(err);
393
+ for (const [stepId, { step, depth }] of originalSteps) {
394
+ stepResults.push({
395
+ stepId,
396
+ toolId: step.tool_id ?? undefined,
397
+ success: false,
398
+ failureClass: "conversion_error",
399
+ error,
400
+ diffs: [],
401
+ depth,
402
+ });
403
+ }
404
+ return {
405
+ stepResults,
406
+ forwardSteps,
407
+ reverseSteps,
408
+ success: false,
409
+ clean: false,
410
+ };
411
+ }
412
+ forwardSteps = forward.steps;
413
+ // Reverse: format2 → native
414
+ try {
415
+ const reverse = toNativeStateful(forward.workflow, toolInputsResolver);
416
+ reverseSteps = reverse.steps;
417
+ reimported = reverse.workflow;
418
+ }
419
+ catch (err) {
420
+ const error = err instanceof Error ? err.message : String(err);
421
+ for (const [stepId, { step, depth }] of originalSteps) {
422
+ stepResults.push({
423
+ stepId,
424
+ toolId: step.tool_id ?? undefined,
425
+ success: false,
426
+ failureClass: "reimport_error",
427
+ error,
428
+ diffs: [],
429
+ depth,
430
+ });
431
+ }
432
+ return {
433
+ stepResults,
434
+ forwardSteps,
435
+ reverseSteps,
436
+ success: false,
437
+ clean: false,
438
+ };
439
+ }
440
+ const { tools: reimportedSteps } = collectSteps(reimported);
441
+ // Per-step comparison (top-level + recursively-collected nested tools)
442
+ for (const [stepId, { step: origStep, depth }] of originalSteps) {
443
+ const afterEntry = reimportedSteps.get(stepId);
444
+ if (!afterEntry) {
445
+ stepResults.push({
446
+ stepId,
447
+ toolId: origStep.tool_id ?? undefined,
448
+ success: false,
449
+ failureClass: "roundtrip_mismatch",
450
+ error: `step ${stepId} missing after roundtrip`,
451
+ diffs: [],
452
+ depth,
453
+ });
454
+ continue;
455
+ }
456
+ // Per-step forward failure → propagate. Note: forwardSteps from
457
+ // `makeStepConversionRunner` uses unprefixed step ids. Nested steps
458
+ // with the same local id as a top-level step can collide; we match
459
+ // by suffix (localId) and tool_id as a best-effort disambiguation.
460
+ const localId = stepId.includes(".") ? stepId.slice(stepId.lastIndexOf(".") + 1) : stepId;
461
+ const forwardFailure = forwardSteps.find((s) => s.stepId === localId && !s.converted && s.toolId === (origStep.tool_id ?? undefined));
462
+ if (forwardFailure) {
463
+ stepResults.push({
464
+ stepId,
465
+ toolId: origStep.tool_id ?? undefined,
466
+ success: false,
467
+ failureClass: "conversion_error",
468
+ error: forwardFailure.error,
469
+ diffs: [],
470
+ depth,
471
+ });
472
+ continue;
473
+ }
474
+ const diffs = [];
475
+ compareTree(origStep.tool_state, afterEntry.step.tool_state, "", diffs);
476
+ const hasError = diffs.some((d) => d.severity === "error");
477
+ stepResults.push({
478
+ stepId,
479
+ toolId: origStep.tool_id ?? undefined,
480
+ success: !hasError,
481
+ failureClass: hasError ? "roundtrip_mismatch" : undefined,
482
+ diffs,
483
+ depth,
484
+ });
485
+ }
486
+ // External (URL/TRS) subworkflow refs: surface an informational entry
487
+ // so callers can see the step exists and was deliberately skipped.
488
+ // Inline subworkflows are handled by the recursive collection above.
489
+ for (const sw of originalSubworkflows) {
490
+ if (sw.workflow != null)
491
+ continue;
492
+ stepResults.push({
493
+ stepId: sw.stepId,
494
+ toolId: undefined,
495
+ success: true,
496
+ failureClass: "subworkflow_external_ref",
497
+ error: "external subworkflow reference (URL/TRS) — inline steps not available for diff",
498
+ diffs: [],
499
+ depth: sw.depth,
500
+ });
501
+ }
502
+ // Only tool-step results contribute to overall verdicts; external-ref
503
+ // entries are informational.
504
+ const toolResults = stepResults.filter((s) => s.failureClass !== "subworkflow_external_ref");
505
+ const anyError = toolResults.some((s) => !s.success);
506
+ const anyDiff = toolResults.some((s) => s.diffs.length > 0);
507
+ return {
508
+ workflowName: (original.name ?? undefined) || undefined,
509
+ stepResults,
510
+ forwardSteps,
511
+ reverseSteps,
512
+ success: !anyError,
513
+ clean: !anyDiff && !anyError,
514
+ };
515
+ }
516
+ //# sourceMappingURL=roundtrip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roundtrip.js","sourceRoot":"","sources":["../../src/workflow/roundtrip.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Runtime value markers used inside workflow tool_state.
3
+ *
4
+ * Galaxy has two in-band markers indicating a parameter value is not a
5
+ * literal but will be supplied at invocation time:
6
+ * - `ConnectedValue`: value comes from an upstream step output
7
+ * - `RuntimeValue`: value is supplied by the user at workflow runtime
8
+ *
9
+ * Both are encoded as `{ __class__: "ConnectedValue" | "RuntimeValue" }`
10
+ * inside native tool_state dicts. Matches Galaxy Python terminology.
11
+ */
12
+ export declare const CONNECTED_VALUE: {
13
+ readonly __class__: "ConnectedValue";
14
+ };
15
+ export declare const RUNTIME_VALUE: {
16
+ readonly __class__: "RuntimeValue";
17
+ };
18
+ export declare function isConnectedValue(value: unknown): boolean;
19
+ export declare function isRuntimeValue(value: unknown): boolean;
20
+ //# sourceMappingURL=runtime-markers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-markers.d.ts","sourceRoot":"","sources":["../../src/workflow/runtime-markers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,eAAe;;CAA2C,CAAC;AACxE,eAAO,MAAM,aAAa;;CAAyC,CAAC;AAEpE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOxD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOtD"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Runtime value markers used inside workflow tool_state.
3
+ *
4
+ * Galaxy has two in-band markers indicating a parameter value is not a
5
+ * literal but will be supplied at invocation time:
6
+ * - `ConnectedValue`: value comes from an upstream step output
7
+ * - `RuntimeValue`: value is supplied by the user at workflow runtime
8
+ *
9
+ * Both are encoded as `{ __class__: "ConnectedValue" | "RuntimeValue" }`
10
+ * inside native tool_state dicts. Matches Galaxy Python terminology.
11
+ */
12
+ export const CONNECTED_VALUE = { __class__: "ConnectedValue" };
13
+ export const RUNTIME_VALUE = { __class__: "RuntimeValue" };
14
+ export function isConnectedValue(value) {
15
+ return (value != null &&
16
+ typeof value === "object" &&
17
+ !Array.isArray(value) &&
18
+ value.__class__ === "ConnectedValue");
19
+ }
20
+ export function isRuntimeValue(value) {
21
+ return (value != null &&
22
+ typeof value === "object" &&
23
+ !Array.isArray(value) &&
24
+ value.__class__ === "RuntimeValue");
25
+ }
26
+ //# sourceMappingURL=runtime-markers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-markers.js","sourceRoot":"","sources":["../../src/workflow/runtime-markers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,SAAS,EAAE,gBAAgB,EAAW,CAAC;AACxE,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,SAAS,EAAE,cAAc,EAAW,CAAC;AAEpE,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,CACL,KAAK,IAAI,IAAI;QACb,OAAO,KAAK,KAAK,QAAQ;QACzB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACpB,KAAiC,CAAC,SAAS,KAAK,gBAAgB,CAClE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,CACL,KAAK,IAAI,IAAI;QACb,OAAO,KAAK,KAAK,QAAQ;QACzB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACpB,KAAiC,CAAC,SAAS,KAAK,cAAc,CAChE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Stale/bookkeeping key set for workflow tool_state.
3
+ *
4
+ * Mirrors Python's `galaxy.tool_util.workflow_state.stale_keys` set — keys
5
+ * that Galaxy injects into tool_state for runtime bookkeeping and that are
6
+ * not real parameter values. The state walker allows them through unknown-
7
+ * key detection, and the roundtrip differ ignores them when diffing.
8
+ *
9
+ * Future work: classify into BOOKKEEPING / RUNTIME_LEAK / STALE_ROOT /
10
+ * STALE_BRANCH / UNKNOWN to mirror Python's `stale_keys.py` and drive an
11
+ * `--allow` / `--deny` policy for stateful export.
12
+ */
13
+ /** Keys injected by Galaxy's runtime/UI; safe to ignore during conversion. */
14
+ export declare const STALE_KEYS: ReadonlySet<string>;
15
+ export declare function isRuntimeLeakKey(key: string): boolean;
16
+ //# sourceMappingURL=stale-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stale-keys.d.ts","sourceRoot":"","sources":["../../src/workflow/stale-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,MAAM,CAQzC,CAAC;AAoBH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErD"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Stale/bookkeeping key set for workflow tool_state.
3
+ *
4
+ * Mirrors Python's `galaxy.tool_util.workflow_state.stale_keys` set — keys
5
+ * that Galaxy injects into tool_state for runtime bookkeeping and that are
6
+ * not real parameter values. The state walker allows them through unknown-
7
+ * key detection, and the roundtrip differ ignores them when diffing.
8
+ *
9
+ * Future work: classify into BOOKKEEPING / RUNTIME_LEAK / STALE_ROOT /
10
+ * STALE_BRANCH / UNKNOWN to mirror Python's `stale_keys.py` and drive an
11
+ * `--allow` / `--deny` policy for stateful export.
12
+ */
13
+ /** Keys injected by Galaxy's runtime/UI; safe to ignore during conversion. */
14
+ export const STALE_KEYS = new Set([
15
+ "__current_case__",
16
+ "__input_ext",
17
+ "__page__",
18
+ "__rerun_remap_job_id__",
19
+ "__index__",
20
+ "__job_resource",
21
+ "chromInfo",
22
+ ]);
23
+ /**
24
+ * Runtime-leak key detection.
25
+ *
26
+ * These keys leak from job execution into persisted `tool_state` and are not
27
+ * real parameter values. Galaxy classifies them as `RUNTIME_LEAK` in
28
+ * `stale_keys.py`; its `for_export` policy preserves them through format2
29
+ * export while `for_validate` flags them. Our walker silently drops them
30
+ * during stateful conversion (neither side of the roundtrip keeps them), so
31
+ * the roundtrip differ treats drops/appearances as benign.
32
+ *
33
+ * - Exact match: `__workflow_invocation_uuid__`
34
+ * - Suffix match: `|__identifier__` (e.g. `input|__identifier__`,
35
+ * `dadaF|__identifier__` — collection element identifier, attached to
36
+ * whichever param received the collection)
37
+ */
38
+ const RUNTIME_LEAK_EXACT = new Set(["__workflow_invocation_uuid__"]);
39
+ const RUNTIME_LEAK_SUFFIX = "|__identifier__";
40
+ export function isRuntimeLeakKey(key) {
41
+ return RUNTIME_LEAK_EXACT.has(key) || key.endsWith(RUNTIME_LEAK_SUFFIX);
42
+ }
43
+ //# sourceMappingURL=stale-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stale-keys.js","sourceRoot":"","sources":["../../src/workflow/stale-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,8EAA8E;AAC9E,MAAM,CAAC,MAAM,UAAU,GAAwB,IAAI,GAAG,CAAC;IACrD,kBAAkB;IAClB,aAAa;IACb,UAAU;IACV,wBAAwB;IACxB,WAAW;IACX,gBAAgB;IAChB,WAAW;CACZ,CAAC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC;AAC1F,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAE9C,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,OAAO,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;AAC1E,CAAC"}