@shipfox/expression 1.1.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 (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +117 -0
  3. package/dist/evaluator/errors.d.ts +8 -0
  4. package/dist/evaluator/errors.d.ts.map +1 -0
  5. package/dist/evaluator/errors.js +13 -0
  6. package/dist/evaluator/errors.js.map +1 -0
  7. package/dist/evaluator/evaluate-workflow-expression.d.ts +11 -0
  8. package/dist/evaluator/evaluate-workflow-expression.d.ts.map +1 -0
  9. package/dist/evaluator/evaluate-workflow-expression.js +30 -0
  10. package/dist/evaluator/evaluate-workflow-expression.js.map +1 -0
  11. package/dist/evaluator/index.d.ts +3 -0
  12. package/dist/evaluator/index.d.ts.map +1 -0
  13. package/dist/evaluator/index.js +4 -0
  14. package/dist/evaluator/index.js.map +1 -0
  15. package/dist/expression/create-workflow-expression.d.ts +7 -0
  16. package/dist/expression/create-workflow-expression.d.ts.map +1 -0
  17. package/dist/expression/create-workflow-expression.js +156 -0
  18. package/dist/expression/create-workflow-expression.js.map +1 -0
  19. package/dist/expression/errors.d.ts +12 -0
  20. package/dist/expression/errors.d.ts.map +1 -0
  21. package/dist/expression/errors.js +13 -0
  22. package/dist/expression/errors.js.map +1 -0
  23. package/dist/expression/index.d.ts +4 -0
  24. package/dist/expression/index.d.ts.map +1 -0
  25. package/dist/expression/index.js +4 -0
  26. package/dist/expression/index.js.map +1 -0
  27. package/dist/expression/workflow-expression.d.ts +33 -0
  28. package/dist/expression/workflow-expression.d.ts.map +1 -0
  29. package/dist/expression/workflow-expression.js +3 -0
  30. package/dist/expression/workflow-expression.js.map +1 -0
  31. package/dist/index.d.ts +27 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +25 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/outputs/index.d.ts +2 -0
  36. package/dist/outputs/index.d.ts.map +1 -0
  37. package/dist/outputs/index.js +3 -0
  38. package/dist/outputs/index.js.map +1 -0
  39. package/dist/outputs/output-declarations.d.ts +39 -0
  40. package/dist/outputs/output-declarations.d.ts.map +1 -0
  41. package/dist/outputs/output-declarations.js +295 -0
  42. package/dist/outputs/output-declarations.js.map +1 -0
  43. package/dist/plan/bare-reference.d.ts +2 -0
  44. package/dist/plan/bare-reference.d.ts.map +1 -0
  45. package/dist/plan/bare-reference.js +23 -0
  46. package/dist/plan/bare-reference.js.map +1 -0
  47. package/dist/plan/context-key-access.d.ts +25 -0
  48. package/dist/plan/context-key-access.d.ts.map +1 -0
  49. package/dist/plan/context-key-access.js +249 -0
  50. package/dist/plan/context-key-access.js.map +1 -0
  51. package/dist/plan/evaluate-planned-predicate.d.ts +14 -0
  52. package/dist/plan/evaluate-planned-predicate.d.ts.map +1 -0
  53. package/dist/plan/evaluate-planned-predicate.js +31 -0
  54. package/dist/plan/evaluate-planned-predicate.js.map +1 -0
  55. package/dist/plan/evaluation-trace.d.ts +44 -0
  56. package/dist/plan/evaluation-trace.d.ts.map +1 -0
  57. package/dist/plan/evaluation-trace.js +95 -0
  58. package/dist/plan/evaluation-trace.js.map +1 -0
  59. package/dist/plan/extract-exact-context-roots.d.ts +2 -0
  60. package/dist/plan/extract-exact-context-roots.d.ts.map +1 -0
  61. package/dist/plan/extract-exact-context-roots.js +114 -0
  62. package/dist/plan/extract-exact-context-roots.js.map +1 -0
  63. package/dist/plan/fill.d.ts +3 -0
  64. package/dist/plan/fill.d.ts.map +1 -0
  65. package/dist/plan/fill.js +8 -0
  66. package/dist/plan/fill.js.map +1 -0
  67. package/dist/plan/freeze-run-command.d.ts +17 -0
  68. package/dist/plan/freeze-run-command.d.ts.map +1 -0
  69. package/dist/plan/freeze-run-command.js +33 -0
  70. package/dist/plan/freeze-run-command.js.map +1 -0
  71. package/dist/plan/freeze.d.ts +48 -0
  72. package/dist/plan/freeze.d.ts.map +1 -0
  73. package/dist/plan/freeze.js +148 -0
  74. package/dist/plan/freeze.js.map +1 -0
  75. package/dist/plan/plan-field.d.ts +26 -0
  76. package/dist/plan/plan-field.d.ts.map +1 -0
  77. package/dist/plan/plan-field.js +63 -0
  78. package/dist/plan/plan-field.js.map +1 -0
  79. package/dist/plan/predicate-shape.d.ts +2 -0
  80. package/dist/plan/predicate-shape.d.ts.map +1 -0
  81. package/dist/plan/predicate-shape.js +45 -0
  82. package/dist/plan/predicate-shape.js.map +1 -0
  83. package/dist/plan/resolved-field.d.ts +17 -0
  84. package/dist/plan/resolved-field.d.ts.map +1 -0
  85. package/dist/plan/resolved-field.js +3 -0
  86. package/dist/plan/resolved-field.js.map +1 -0
  87. package/dist/plan/route-expression.d.ts +9 -0
  88. package/dist/plan/route-expression.d.ts.map +1 -0
  89. package/dist/plan/route-expression.js +46 -0
  90. package/dist/plan/route-expression.js.map +1 -0
  91. package/dist/plan/validate-server-evaluable.d.ts +14 -0
  92. package/dist/plan/validate-server-evaluable.d.ts.map +1 -0
  93. package/dist/plan/validate-server-evaluable.js +20 -0
  94. package/dist/plan/validate-server-evaluable.js.map +1 -0
  95. package/dist/resolver/coerce-workflow-value-to-string.d.ts +2 -0
  96. package/dist/resolver/coerce-workflow-value-to-string.d.ts.map +1 -0
  97. package/dist/resolver/coerce-workflow-value-to-string.js +16 -0
  98. package/dist/resolver/coerce-workflow-value-to-string.js.map +1 -0
  99. package/dist/resolver/errors.d.ts +10 -0
  100. package/dist/resolver/errors.d.ts.map +1 -0
  101. package/dist/resolver/errors.js +12 -0
  102. package/dist/resolver/errors.js.map +1 -0
  103. package/dist/run/hoist-run-command.d.ts +33 -0
  104. package/dist/run/hoist-run-command.d.ts.map +1 -0
  105. package/dist/run/hoist-run-command.js +79 -0
  106. package/dist/run/hoist-run-command.js.map +1 -0
  107. package/dist/run/shell-quoting.d.ts +24 -0
  108. package/dist/run/shell-quoting.d.ts.map +1 -0
  109. package/dist/run/shell-quoting.js +364 -0
  110. package/dist/run/shell-quoting.js.map +1 -0
  111. package/dist/template/errors.d.ts +14 -0
  112. package/dist/template/errors.d.ts.map +1 -0
  113. package/dist/template/errors.js +14 -0
  114. package/dist/template/errors.js.map +1 -0
  115. package/dist/template/extract-cel-context-roots.d.ts +2 -0
  116. package/dist/template/extract-cel-context-roots.d.ts.map +1 -0
  117. package/dist/template/extract-cel-context-roots.js +110 -0
  118. package/dist/template/extract-cel-context-roots.js.map +1 -0
  119. package/dist/template/extract-cel-untrusted-path-accesses.d.ts +5 -0
  120. package/dist/template/extract-cel-untrusted-path-accesses.d.ts.map +1 -0
  121. package/dist/template/extract-cel-untrusted-path-accesses.js +140 -0
  122. package/dist/template/extract-cel-untrusted-path-accesses.js.map +1 -0
  123. package/dist/template/parse-workflow-template.d.ts +3 -0
  124. package/dist/template/parse-workflow-template.d.ts.map +1 -0
  125. package/dist/template/parse-workflow-template.js +111 -0
  126. package/dist/template/parse-workflow-template.js.map +1 -0
  127. package/dist/template/scan-cel-token.d.ts +3 -0
  128. package/dist/template/scan-cel-token.d.ts.map +1 -0
  129. package/dist/template/scan-cel-token.js +55 -0
  130. package/dist/template/scan-cel-token.js.map +1 -0
  131. package/dist/template/template-segment.d.ts +12 -0
  132. package/dist/template/template-segment.d.ts.map +1 -0
  133. package/dist/template/template-segment.js +3 -0
  134. package/dist/template/template-segment.js.map +1 -0
  135. package/dist/tsconfig.test.tsbuildinfo +1 -0
  136. package/dist/workflow-context/workflow-context.d.ts +458 -0
  137. package/dist/workflow-context/workflow-context.d.ts.map +1 -0
  138. package/dist/workflow-context/workflow-context.js +664 -0
  139. package/dist/workflow-context/workflow-context.js.map +1 -0
  140. package/package.json +49 -0
@@ -0,0 +1,8 @@
1
+ import { availabilitySites } from '../workflow-context/workflow-context.js';
2
+ export function shouldFillAtSite(fillTarget, site) {
3
+ const fillTargetIndex = availabilitySites.indexOf(fillTarget);
4
+ if (fillTargetIndex < 0) return false;
5
+ return fillTargetIndex <= availabilitySites.indexOf(site);
6
+ }
7
+
8
+ //# sourceMappingURL=fill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plan/fill.ts"],"sourcesContent":["import {type AvailabilitySite, availabilitySites} from '../workflow-context/workflow-context.js';\n\nexport function shouldFillAtSite(fillTarget: string, site: AvailabilitySite): boolean {\n const fillTargetIndex = availabilitySites.indexOf(fillTarget as AvailabilitySite);\n if (fillTargetIndex < 0) return false;\n\n return fillTargetIndex <= availabilitySites.indexOf(site);\n}\n"],"names":["availabilitySites","shouldFillAtSite","fillTarget","site","fillTargetIndex","indexOf"],"mappings":"AAAA,SAA+BA,iBAAiB,QAAO,0CAA0C;AAEjG,OAAO,SAASC,iBAAiBC,UAAkB,EAAEC,IAAsB;IACzE,MAAMC,kBAAkBJ,kBAAkBK,OAAO,CAACH;IAClD,IAAIE,kBAAkB,GAAG,OAAO;IAEhC,OAAOA,mBAAmBJ,kBAAkBK,OAAO,CAACF;AACtD"}
@@ -0,0 +1,17 @@
1
+ import type { WorkflowExpressionEvaluationContext } from '../evaluator/evaluate-workflow-expression.js';
2
+ import type { AvailabilitySite, WorkflowInterpolationFailurePolicy } from '../workflow-context/workflow-context.js';
3
+ import { type WorkflowTemplateDiagnostic } from './freeze.js';
4
+ import type { ResolvedField } from './resolved-field.js';
5
+ export interface FrozenPlannedRunCommand {
6
+ readonly command: string;
7
+ readonly env: Readonly<Record<string, string>>;
8
+ readonly diagnostics: readonly WorkflowTemplateDiagnostic[];
9
+ }
10
+ export declare function freezePlannedRunCommandAtSite(params: {
11
+ readonly field: ResolvedField;
12
+ readonly site: AvailabilitySite;
13
+ readonly context: WorkflowExpressionEvaluationContext;
14
+ readonly failurePolicy: WorkflowInterpolationFailurePolicy;
15
+ readonly reservedNames?: Iterable<string>;
16
+ }): FrozenPlannedRunCommand;
17
+ //# sourceMappingURL=freeze-run-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freeze-run-command.d.ts","sourceRoot":"","sources":["../../src/plan/freeze-run-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,mCAAmC,EAAC,MAAM,8CAA8C,CAAC;AAEtG,OAAO,KAAK,EACV,gBAAgB,EAChB,kCAAkC,EACnC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAA4B,KAAK,0BAA0B,EAAC,MAAM,aAAa,CAAC;AACvF,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,QAAQ,CAAC,WAAW,EAAE,SAAS,0BAA0B,EAAE,CAAC;CAC7D;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE;IACpD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,mCAAmC,CAAC;IACtD,QAAQ,CAAC,aAAa,EAAE,kCAAkC,CAAC;IAC3D,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC3C,GAAG,uBAAuB,CAoB1B"}
@@ -0,0 +1,33 @@
1
+ import { hoistPlannedRunCommand } from '../run/hoist-run-command.js';
2
+ import { freezeResolvedFieldAtSite } from './freeze.js';
3
+ export function freezePlannedRunCommandAtSite(params) {
4
+ const hoisted = hoistPlannedRunCommand({
5
+ field: params.field,
6
+ ...params.reservedNames === undefined ? {} : {
7
+ reservedNames: params.reservedNames
8
+ }
9
+ });
10
+ const env = {};
11
+ const diagnostics = [];
12
+ for (const binding of hoisted.bindings){
13
+ const resolved = freezeResolvedFieldAtSite({
14
+ field: {
15
+ segments: [
16
+ binding.segment
17
+ ]
18
+ },
19
+ site: params.site,
20
+ context: params.context,
21
+ failurePolicy: params.failurePolicy
22
+ });
23
+ env[binding.name] = resolved.value;
24
+ diagnostics.push(...resolved.diagnostics);
25
+ }
26
+ return {
27
+ command: hoisted.command,
28
+ env,
29
+ diagnostics
30
+ };
31
+ }
32
+
33
+ //# sourceMappingURL=freeze-run-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plan/freeze-run-command.ts"],"sourcesContent":["import type {WorkflowExpressionEvaluationContext} from '../evaluator/evaluate-workflow-expression.js';\nimport {hoistPlannedRunCommand} from '../run/hoist-run-command.js';\nimport type {\n AvailabilitySite,\n WorkflowInterpolationFailurePolicy,\n} from '../workflow-context/workflow-context.js';\nimport {freezeResolvedFieldAtSite, type WorkflowTemplateDiagnostic} from './freeze.js';\nimport type {ResolvedField} from './resolved-field.js';\n\nexport interface FrozenPlannedRunCommand {\n readonly command: string;\n readonly env: Readonly<Record<string, string>>;\n readonly diagnostics: readonly WorkflowTemplateDiagnostic[];\n}\n\nexport function freezePlannedRunCommandAtSite(params: {\n readonly field: ResolvedField;\n readonly site: AvailabilitySite;\n readonly context: WorkflowExpressionEvaluationContext;\n readonly failurePolicy: WorkflowInterpolationFailurePolicy;\n readonly reservedNames?: Iterable<string>;\n}): FrozenPlannedRunCommand {\n const hoisted = hoistPlannedRunCommand({\n field: params.field,\n ...(params.reservedNames === undefined ? {} : {reservedNames: params.reservedNames}),\n });\n const env: Record<string, string> = {};\n const diagnostics: WorkflowTemplateDiagnostic[] = [];\n\n for (const binding of hoisted.bindings) {\n const resolved = freezeResolvedFieldAtSite({\n field: {segments: [binding.segment]},\n site: params.site,\n context: params.context,\n failurePolicy: params.failurePolicy,\n });\n env[binding.name] = resolved.value;\n diagnostics.push(...resolved.diagnostics);\n }\n\n return {command: hoisted.command, env, diagnostics};\n}\n"],"names":["hoistPlannedRunCommand","freezeResolvedFieldAtSite","freezePlannedRunCommandAtSite","params","hoisted","field","reservedNames","undefined","env","diagnostics","binding","bindings","resolved","segments","segment","site","context","failurePolicy","name","value","push","command"],"mappings":"AACA,SAAQA,sBAAsB,QAAO,8BAA8B;AAKnE,SAAQC,yBAAyB,QAAwC,cAAc;AASvF,OAAO,SAASC,8BAA8BC,MAM7C;IACC,MAAMC,UAAUJ,uBAAuB;QACrCK,OAAOF,OAAOE,KAAK;QACnB,GAAIF,OAAOG,aAAa,KAAKC,YAAY,CAAC,IAAI;YAACD,eAAeH,OAAOG,aAAa;QAAA,CAAC;IACrF;IACA,MAAME,MAA8B,CAAC;IACrC,MAAMC,cAA4C,EAAE;IAEpD,KAAK,MAAMC,WAAWN,QAAQO,QAAQ,CAAE;QACtC,MAAMC,WAAWX,0BAA0B;YACzCI,OAAO;gBAACQ,UAAU;oBAACH,QAAQI,OAAO;iBAAC;YAAA;YACnCC,MAAMZ,OAAOY,IAAI;YACjBC,SAASb,OAAOa,OAAO;YACvBC,eAAed,OAAOc,aAAa;QACrC;QACAT,GAAG,CAACE,QAAQQ,IAAI,CAAC,GAAGN,SAASO,KAAK;QAClCV,YAAYW,IAAI,IAAIR,SAASH,WAAW;IAC1C;IAEA,OAAO;QAACY,SAASjB,QAAQiB,OAAO;QAAEb;QAAKC;IAAW;AACpD"}
@@ -0,0 +1,48 @@
1
+ import { type WorkflowExpressionEvaluationContext } from '../evaluator/index.js';
2
+ import { type AvailabilitySite, type WorkflowInterpolationFailurePolicy } from '../workflow-context/workflow-context.js';
3
+ import { type EvaluationTraceEntry } from './evaluation-trace.js';
4
+ import type { ResolvedField } from './resolved-field.js';
5
+ export type WorkflowTemplateFailurePolicy = WorkflowInterpolationFailurePolicy;
6
+ export interface WorkflowTemplateDiagnostic {
7
+ readonly reason: 'missing-path';
8
+ readonly expression: string;
9
+ readonly contextRoots: readonly string[];
10
+ }
11
+ export interface FrozenResolvedField {
12
+ readonly value: string;
13
+ readonly diagnostics: readonly WorkflowTemplateDiagnostic[];
14
+ readonly trace: readonly EvaluationTraceEntry[];
15
+ }
16
+ export type SiteResolvedField = {
17
+ readonly kind: 'frozen';
18
+ readonly value: string;
19
+ readonly diagnostics: readonly WorkflowTemplateDiagnostic[];
20
+ readonly trace: readonly EvaluationTraceEntry[];
21
+ } | {
22
+ readonly kind: 'residual';
23
+ readonly field: ResolvedField;
24
+ readonly diagnostics: readonly WorkflowTemplateDiagnostic[];
25
+ readonly trace: readonly EvaluationTraceEntry[];
26
+ };
27
+ /**
28
+ * Segment lifecycle:
29
+ *
30
+ * `{expr}` -> plan -> `{deferred, fillTarget}` -> freeze at a site at or after
31
+ * `fillTarget` -> `{literal}`. Runner-fill segments are never filled server-side.
32
+ *
33
+ * Value fields follow their declared policy at their fill target. Predicates use
34
+ * the planned predicate entry point and fail closed when evaluation is deferred.
35
+ */
36
+ export declare function freezeResolvedFieldAtSite(params: {
37
+ readonly field: ResolvedField;
38
+ readonly failurePolicy: WorkflowInterpolationFailurePolicy;
39
+ readonly site: AvailabilitySite;
40
+ readonly context: WorkflowExpressionEvaluationContext;
41
+ }): FrozenResolvedField;
42
+ export declare function resolveFieldAtSite(params: {
43
+ readonly field: ResolvedField;
44
+ readonly failurePolicy: WorkflowInterpolationFailurePolicy;
45
+ readonly site: AvailabilitySite;
46
+ readonly context: WorkflowExpressionEvaluationContext;
47
+ }): SiteResolvedField;
48
+ //# sourceMappingURL=freeze.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freeze.d.ts","sourceRoot":"","sources":["../../src/plan/freeze.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mCAAmC,EAEzC,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,kCAAkC,EACxC,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAC,KAAK,oBAAoB,EAAuB,MAAM,uBAAuB,CAAC;AAEtF,OAAO,KAAK,EACV,aAAa,EAGd,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,6BAA6B,GAAG,kCAAkC,CAAC;AAE/E,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,SAAS,0BAA0B,EAAE,CAAC;IAC5D,QAAQ,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACjD;AAED,MAAM,MAAM,iBAAiB,GACzB;IACE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,SAAS,0BAA0B,EAAE,CAAC;IAC5D,QAAQ,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACjD,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,SAAS,0BAA0B,EAAE,CAAC;IAC5D,QAAQ,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACjD,CAAC;AAEN;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE;IAChD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,kCAAkC,CAAC;IAC3D,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,mCAAmC,CAAC;CACvD,GAAG,mBAAmB,CA4CtB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,kCAAkC,CAAC;IAC3D,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,mCAAmC,CAAC;CACvD,GAAG,iBAAiB,CAmDpB"}
@@ -0,0 +1,148 @@
1
+ import { evaluateWorkflowExpression, WorkflowExpressionEvaluationError } from '../evaluator/index.js';
2
+ import { coerceWorkflowValueToString } from '../resolver/coerce-workflow-value-to-string.js';
3
+ import { WorkflowTemplateResolutionError } from '../resolver/errors.js';
4
+ import { resolveContextRootAvailability } from '../workflow-context/workflow-context.js';
5
+ import { evaluationTraceEntry } from './evaluation-trace.js';
6
+ import { shouldFillAtSite } from './fill.js';
7
+ /**
8
+ * Segment lifecycle:
9
+ *
10
+ * `{expr}` -> plan -> `{deferred, fillTarget}` -> freeze at a site at or after
11
+ * `fillTarget` -> `{literal}`. Runner-fill segments are never filled server-side.
12
+ *
13
+ * Value fields follow their declared policy at their fill target. Predicates use
14
+ * the planned predicate entry point and fail closed when evaluation is deferred.
15
+ */ export function freezeResolvedFieldAtSite(params) {
16
+ let value = '';
17
+ const diagnostics = [];
18
+ const trace = [];
19
+ for (const segment of params.field.segments){
20
+ if (segment.kind === 'literal') {
21
+ value += segment.value;
22
+ continue;
23
+ }
24
+ if (!shouldFillAtSite(segment.fillTarget, params.site)) {
25
+ diagnostics.push(missingPathDiagnostic(segment));
26
+ continue;
27
+ }
28
+ try {
29
+ const literal = coerceWorkflowValueToString(evaluateWorkflowExpression(segment.expression, params.context));
30
+ value += literal;
31
+ trace.push(fillTraceEntry(segment, params.site, literal));
32
+ } catch (error) {
33
+ if (error instanceof WorkflowExpressionEvaluationError && error.reason === 'missing-path') {
34
+ if (missingPathRequiresFailure(segment, params.failurePolicy, params.site)) {
35
+ throw new WorkflowTemplateResolutionError({
36
+ source: segment.expression.source,
37
+ cause: error
38
+ });
39
+ }
40
+ diagnostics.push(missingPathDiagnostic(segment));
41
+ trace.push(fillTraceEntry(segment, params.site, '', true));
42
+ continue;
43
+ }
44
+ throw new WorkflowTemplateResolutionError({
45
+ source: segment.expression.source,
46
+ cause: error
47
+ });
48
+ }
49
+ }
50
+ return {
51
+ value,
52
+ diagnostics,
53
+ trace
54
+ };
55
+ }
56
+ export function resolveFieldAtSite(params) {
57
+ let value = '';
58
+ const diagnostics = [];
59
+ const trace = [];
60
+ const segments = [];
61
+ let hasResidual = false;
62
+ for (const segment of params.field.segments){
63
+ if (segment.kind === 'literal') {
64
+ value += segment.value;
65
+ segments.push(segment);
66
+ continue;
67
+ }
68
+ if (!shouldFillAtSite(segment.fillTarget, params.site)) {
69
+ hasResidual = true;
70
+ segments.push(segment);
71
+ continue;
72
+ }
73
+ try {
74
+ const literal = coerceWorkflowValueToString(evaluateWorkflowExpression(segment.expression, params.context));
75
+ value += literal;
76
+ segments.push({
77
+ kind: 'literal',
78
+ value: literal
79
+ });
80
+ trace.push(fillTraceEntry(segment, params.site, literal));
81
+ } catch (error) {
82
+ if (error instanceof WorkflowExpressionEvaluationError && error.reason === 'missing-path') {
83
+ if (missingPathRequiresFailure(segment, params.failurePolicy, params.site)) {
84
+ throw new WorkflowTemplateResolutionError({
85
+ source: segment.expression.source,
86
+ cause: error
87
+ });
88
+ }
89
+ diagnostics.push(missingPathDiagnostic(segment));
90
+ segments.push({
91
+ kind: 'literal',
92
+ value: ''
93
+ });
94
+ trace.push(fillTraceEntry(segment, params.site, '', true));
95
+ continue;
96
+ }
97
+ throw new WorkflowTemplateResolutionError({
98
+ source: segment.expression.source,
99
+ cause: error
100
+ });
101
+ }
102
+ }
103
+ if (hasResidual) return {
104
+ kind: 'residual',
105
+ field: {
106
+ segments
107
+ },
108
+ diagnostics,
109
+ trace
110
+ };
111
+ return {
112
+ kind: 'frozen',
113
+ value,
114
+ diagnostics,
115
+ trace
116
+ };
117
+ }
118
+ function fillTraceEntry(segment, site, value, degraded = false) {
119
+ return evaluationTraceEntry({
120
+ expression: segment.expression.source,
121
+ roots: segment.roots,
122
+ fillTarget: segment.fillTarget,
123
+ evaluatedAt: site,
124
+ value,
125
+ ...degraded ? {
126
+ degraded: true
127
+ } : {}
128
+ });
129
+ }
130
+ function missingPathDiagnostic(segment) {
131
+ return {
132
+ reason: 'missing-path',
133
+ expression: segment.expression.source,
134
+ contextRoots: segment.roots
135
+ };
136
+ }
137
+ function missingPathRequiresFailure(segment, failurePolicy, site) {
138
+ if (failurePolicy !== 'fail') return false;
139
+ const rootAvailabilities = segment.roots.flatMap((root)=>{
140
+ const availability = resolveContextRootAvailability(root);
141
+ return availability === undefined ? [] : [
142
+ availability
143
+ ];
144
+ });
145
+ return rootAvailabilities.length > 0 && rootAvailabilities.every((availability)=>shouldFillAtSite(availability, site));
146
+ }
147
+
148
+ //# sourceMappingURL=freeze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plan/freeze.ts"],"sourcesContent":["import {\n evaluateWorkflowExpression,\n type WorkflowExpressionEvaluationContext,\n WorkflowExpressionEvaluationError,\n} from '../evaluator/index.js';\nimport {coerceWorkflowValueToString} from '../resolver/coerce-workflow-value-to-string.js';\nimport {WorkflowTemplateResolutionError} from '../resolver/errors.js';\nimport {\n type AvailabilitySite,\n resolveContextRootAvailability,\n type WorkflowInterpolationFailurePolicy,\n} from '../workflow-context/workflow-context.js';\nimport {type EvaluationTraceEntry, evaluationTraceEntry} from './evaluation-trace.js';\nimport {shouldFillAtSite} from './fill.js';\nimport type {\n ResolvedField,\n ResolvedFieldDeferredSegment,\n ResolvedFieldSegment,\n} from './resolved-field.js';\n\nexport type WorkflowTemplateFailurePolicy = WorkflowInterpolationFailurePolicy;\n\nexport interface WorkflowTemplateDiagnostic {\n readonly reason: 'missing-path';\n readonly expression: string;\n readonly contextRoots: readonly string[];\n}\n\nexport interface FrozenResolvedField {\n readonly value: string;\n readonly diagnostics: readonly WorkflowTemplateDiagnostic[];\n readonly trace: readonly EvaluationTraceEntry[];\n}\n\nexport type SiteResolvedField =\n | {\n readonly kind: 'frozen';\n readonly value: string;\n readonly diagnostics: readonly WorkflowTemplateDiagnostic[];\n readonly trace: readonly EvaluationTraceEntry[];\n }\n | {\n readonly kind: 'residual';\n readonly field: ResolvedField;\n readonly diagnostics: readonly WorkflowTemplateDiagnostic[];\n readonly trace: readonly EvaluationTraceEntry[];\n };\n\n/**\n * Segment lifecycle:\n *\n * `{expr}` -> plan -> `{deferred, fillTarget}` -> freeze at a site at or after\n * `fillTarget` -> `{literal}`. Runner-fill segments are never filled server-side.\n *\n * Value fields follow their declared policy at their fill target. Predicates use\n * the planned predicate entry point and fail closed when evaluation is deferred.\n */\nexport function freezeResolvedFieldAtSite(params: {\n readonly field: ResolvedField;\n readonly failurePolicy: WorkflowInterpolationFailurePolicy;\n readonly site: AvailabilitySite;\n readonly context: WorkflowExpressionEvaluationContext;\n}): FrozenResolvedField {\n let value = '';\n const diagnostics: WorkflowTemplateDiagnostic[] = [];\n const trace: EvaluationTraceEntry[] = [];\n\n for (const segment of params.field.segments) {\n if (segment.kind === 'literal') {\n value += segment.value;\n continue;\n }\n\n if (!shouldFillAtSite(segment.fillTarget, params.site)) {\n diagnostics.push(missingPathDiagnostic(segment));\n continue;\n }\n\n try {\n const literal = coerceWorkflowValueToString(\n evaluateWorkflowExpression(segment.expression, params.context),\n );\n value += literal;\n trace.push(fillTraceEntry(segment, params.site, literal));\n } catch (error) {\n if (error instanceof WorkflowExpressionEvaluationError && error.reason === 'missing-path') {\n if (missingPathRequiresFailure(segment, params.failurePolicy, params.site)) {\n throw new WorkflowTemplateResolutionError({\n source: segment.expression.source,\n cause: error,\n });\n }\n\n diagnostics.push(missingPathDiagnostic(segment));\n trace.push(fillTraceEntry(segment, params.site, '', true));\n continue;\n }\n\n throw new WorkflowTemplateResolutionError({\n source: segment.expression.source,\n cause: error,\n });\n }\n }\n\n return {value, diagnostics, trace};\n}\n\nexport function resolveFieldAtSite(params: {\n readonly field: ResolvedField;\n readonly failurePolicy: WorkflowInterpolationFailurePolicy;\n readonly site: AvailabilitySite;\n readonly context: WorkflowExpressionEvaluationContext;\n}): SiteResolvedField {\n let value = '';\n const diagnostics: WorkflowTemplateDiagnostic[] = [];\n const trace: EvaluationTraceEntry[] = [];\n const segments: ResolvedFieldSegment[] = [];\n let hasResidual = false;\n\n for (const segment of params.field.segments) {\n if (segment.kind === 'literal') {\n value += segment.value;\n segments.push(segment);\n continue;\n }\n\n if (!shouldFillAtSite(segment.fillTarget, params.site)) {\n hasResidual = true;\n segments.push(segment);\n continue;\n }\n\n try {\n const literal = coerceWorkflowValueToString(\n evaluateWorkflowExpression(segment.expression, params.context),\n );\n value += literal;\n segments.push({kind: 'literal', value: literal});\n trace.push(fillTraceEntry(segment, params.site, literal));\n } catch (error) {\n if (error instanceof WorkflowExpressionEvaluationError && error.reason === 'missing-path') {\n if (missingPathRequiresFailure(segment, params.failurePolicy, params.site)) {\n throw new WorkflowTemplateResolutionError({\n source: segment.expression.source,\n cause: error,\n });\n }\n\n diagnostics.push(missingPathDiagnostic(segment));\n segments.push({kind: 'literal', value: ''});\n trace.push(fillTraceEntry(segment, params.site, '', true));\n continue;\n }\n\n throw new WorkflowTemplateResolutionError({\n source: segment.expression.source,\n cause: error,\n });\n }\n }\n\n if (hasResidual) return {kind: 'residual', field: {segments}, diagnostics, trace};\n return {kind: 'frozen', value, diagnostics, trace};\n}\n\nfunction fillTraceEntry(\n segment: ResolvedFieldDeferredSegment,\n site: AvailabilitySite,\n value: string,\n degraded = false,\n): EvaluationTraceEntry {\n return evaluationTraceEntry({\n expression: segment.expression.source,\n roots: segment.roots,\n fillTarget: segment.fillTarget,\n evaluatedAt: site,\n value,\n ...(degraded ? {degraded: true} : {}),\n });\n}\n\nfunction missingPathDiagnostic(segment: ResolvedFieldDeferredSegment): WorkflowTemplateDiagnostic {\n return {\n reason: 'missing-path',\n expression: segment.expression.source,\n contextRoots: segment.roots,\n };\n}\n\nfunction missingPathRequiresFailure(\n segment: ResolvedFieldDeferredSegment,\n failurePolicy: WorkflowInterpolationFailurePolicy,\n site: AvailabilitySite,\n): boolean {\n if (failurePolicy !== 'fail') return false;\n const rootAvailabilities = segment.roots.flatMap((root) => {\n const availability = resolveContextRootAvailability(root);\n return availability === undefined ? [] : [availability];\n });\n return (\n rootAvailabilities.length > 0 &&\n rootAvailabilities.every((availability) => shouldFillAtSite(availability, site))\n );\n}\n"],"names":["evaluateWorkflowExpression","WorkflowExpressionEvaluationError","coerceWorkflowValueToString","WorkflowTemplateResolutionError","resolveContextRootAvailability","evaluationTraceEntry","shouldFillAtSite","freezeResolvedFieldAtSite","params","value","diagnostics","trace","segment","field","segments","kind","fillTarget","site","push","missingPathDiagnostic","literal","expression","context","fillTraceEntry","error","reason","missingPathRequiresFailure","failurePolicy","source","cause","resolveFieldAtSite","hasResidual","degraded","roots","evaluatedAt","contextRoots","rootAvailabilities","flatMap","root","availability","undefined","length","every"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { WorkflowTemplateSegment } from '../template/template-segment.js';
2
+ import { type WorkflowInterpolationFailurePolicy, type WorkflowInterpolationField } from '../workflow-context/workflow-context.js';
3
+ import type { ResolvedField } from './resolved-field.js';
4
+ export type PlanViolation = {
5
+ readonly reason: 'runner-root-not-bare' | 'computed-context-key';
6
+ readonly source: string;
7
+ readonly runnerRoots?: readonly string[];
8
+ readonly contextRoots?: readonly string[];
9
+ readonly hint: string;
10
+ };
11
+ export interface FieldPlan {
12
+ readonly field: ResolvedField;
13
+ readonly failurePolicy: WorkflowInterpolationFailurePolicy;
14
+ }
15
+ export type FieldPlanResult = {
16
+ readonly ok: true;
17
+ readonly plan: FieldPlan;
18
+ } | {
19
+ readonly ok: false;
20
+ readonly violations: readonly PlanViolation[];
21
+ };
22
+ export declare function planInterpolationField(params: {
23
+ readonly field: WorkflowInterpolationField;
24
+ readonly segments: readonly WorkflowTemplateSegment[];
25
+ }): FieldPlanResult;
26
+ //# sourceMappingURL=plan-field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-field.d.ts","sourceRoot":"","sources":["../../src/plan/plan-field.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAML,KAAK,kCAAkC,EACvC,KAAK,0BAA0B,EAChC,MAAM,yCAAyC,CAAC;AAGjD,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAMvD,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,MAAM,EAAE,sBAAsB,GAAG,sBAAsB,CAAC;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,kCAAkC,CAAC;CAC5D;AAED,MAAM,MAAM,eAAe,GACvB;IAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAC,GAC7C;IAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,aAAa,EAAE,CAAA;CAAC,CAAC;AAExE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,QAAQ,CAAC,KAAK,EAAE,0BAA0B,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,CAAC;CACvD,GAAG,eAAe,CA2ClB"}
@@ -0,0 +1,63 @@
1
+ import { availabilitySites, getWorkflowInterpolationFieldFailurePolicy, getWorkflowInterpolationFieldMinimumFillTarget } from '../workflow-context/workflow-context.js';
2
+ import { isBareContextReference } from './bare-reference.js';
3
+ import { analyzeContextKeyAccess } from './context-key-access.js';
4
+ import { routeExpression } from './route-expression.js';
5
+ const templateExpressionOpen = '$' + '{{';
6
+ const runnerRootNotBareHint = `split runner-host references into their own adjacent ${templateExpressionOpen} }} segments`;
7
+ export function planInterpolationField(params) {
8
+ const violations = [];
9
+ const minimumFillTarget = getWorkflowInterpolationFieldMinimumFillTarget(params.field);
10
+ const resolvedSegments = params.segments.map((segment)=>{
11
+ if (segment.kind === 'literal') return {
12
+ kind: 'literal',
13
+ value: segment.text
14
+ };
15
+ const route = routeExpression(segment.expression);
16
+ const keyAccess = analyzeContextKeyAccess(segment.expression);
17
+ if (keyAccess.violations.length > 0) {
18
+ violations.push(...keyAccess.violations.map((violation)=>({
19
+ reason: 'computed-context-key',
20
+ source: violation.source,
21
+ contextRoots: [
22
+ violation.root
23
+ ],
24
+ hint: `${violation.root} references must use a literal dot key`
25
+ })));
26
+ } else if (route.runnerRoots.length > 0 && !isBareContextReference(segment.expression.source)) {
27
+ violations.push({
28
+ reason: 'runner-root-not-bare',
29
+ source: segment.expression.source,
30
+ runnerRoots: route.runnerRoots,
31
+ hint: runnerRootNotBareHint
32
+ });
33
+ }
34
+ return {
35
+ kind: 'deferred',
36
+ expression: segment.expression,
37
+ roots: route.roots,
38
+ fillTarget: applyMinimumFillTarget(route.fillTarget, minimumFillTarget)
39
+ };
40
+ });
41
+ if (violations.length > 0) return {
42
+ ok: false,
43
+ violations
44
+ };
45
+ return {
46
+ ok: true,
47
+ plan: {
48
+ field: {
49
+ segments: resolvedSegments
50
+ },
51
+ failurePolicy: getWorkflowInterpolationFieldFailurePolicy(params.field)
52
+ }
53
+ };
54
+ }
55
+ function applyMinimumFillTarget(fillTarget, minimumFillTarget) {
56
+ if (minimumFillTarget === undefined || fillTarget === 'runner-fill') return fillTarget;
57
+ const fillTargetIndex = availabilitySites.indexOf(fillTarget);
58
+ const minimumFillTargetIndex = availabilitySites.indexOf(minimumFillTarget);
59
+ if (fillTargetIndex < 0 || minimumFillTargetIndex < 0) return fillTarget;
60
+ return availabilitySites[Math.max(fillTargetIndex, minimumFillTargetIndex)] ?? fillTarget;
61
+ }
62
+
63
+ //# sourceMappingURL=plan-field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plan/plan-field.ts"],"sourcesContent":["import type {WorkflowTemplateSegment} from '../template/template-segment.js';\nimport {\n type AvailabilitySite,\n availabilitySites,\n type FillTarget,\n getWorkflowInterpolationFieldFailurePolicy,\n getWorkflowInterpolationFieldMinimumFillTarget,\n type WorkflowInterpolationFailurePolicy,\n type WorkflowInterpolationField,\n} from '../workflow-context/workflow-context.js';\nimport {isBareContextReference} from './bare-reference.js';\nimport {analyzeContextKeyAccess} from './context-key-access.js';\nimport type {ResolvedField} from './resolved-field.js';\nimport {routeExpression} from './route-expression.js';\n\nconst templateExpressionOpen = '$' + '{{';\nconst runnerRootNotBareHint = `split runner-host references into their own adjacent ${templateExpressionOpen} }} segments`;\n\nexport type PlanViolation = {\n readonly reason: 'runner-root-not-bare' | 'computed-context-key';\n readonly source: string;\n readonly runnerRoots?: readonly string[];\n readonly contextRoots?: readonly string[];\n readonly hint: string;\n};\n\nexport interface FieldPlan {\n readonly field: ResolvedField;\n readonly failurePolicy: WorkflowInterpolationFailurePolicy;\n}\n\nexport type FieldPlanResult =\n | {readonly ok: true; readonly plan: FieldPlan}\n | {readonly ok: false; readonly violations: readonly PlanViolation[]};\n\nexport function planInterpolationField(params: {\n readonly field: WorkflowInterpolationField;\n readonly segments: readonly WorkflowTemplateSegment[];\n}): FieldPlanResult {\n const violations: PlanViolation[] = [];\n const minimumFillTarget = getWorkflowInterpolationFieldMinimumFillTarget(params.field);\n const resolvedSegments: ResolvedField['segments'] = params.segments.map((segment) => {\n if (segment.kind === 'literal') return {kind: 'literal', value: segment.text};\n\n const route = routeExpression(segment.expression);\n const keyAccess = analyzeContextKeyAccess(segment.expression);\n if (keyAccess.violations.length > 0) {\n violations.push(\n ...keyAccess.violations.map((violation) => ({\n reason: 'computed-context-key' as const,\n source: violation.source,\n contextRoots: [violation.root],\n hint: `${violation.root} references must use a literal dot key`,\n })),\n );\n } else if (route.runnerRoots.length > 0 && !isBareContextReference(segment.expression.source)) {\n violations.push({\n reason: 'runner-root-not-bare',\n source: segment.expression.source,\n runnerRoots: route.runnerRoots,\n hint: runnerRootNotBareHint,\n });\n }\n\n return {\n kind: 'deferred',\n expression: segment.expression,\n roots: route.roots,\n fillTarget: applyMinimumFillTarget(route.fillTarget, minimumFillTarget),\n };\n });\n\n if (violations.length > 0) return {ok: false, violations};\n\n return {\n ok: true,\n plan: {\n field: {segments: resolvedSegments},\n failurePolicy: getWorkflowInterpolationFieldFailurePolicy(params.field),\n },\n };\n}\n\nfunction applyMinimumFillTarget(\n fillTarget: FillTarget,\n minimumFillTarget: AvailabilitySite | undefined,\n): FillTarget {\n if (minimumFillTarget === undefined || fillTarget === 'runner-fill') return fillTarget;\n\n const fillTargetIndex = availabilitySites.indexOf(fillTarget);\n const minimumFillTargetIndex = availabilitySites.indexOf(minimumFillTarget);\n if (fillTargetIndex < 0 || minimumFillTargetIndex < 0) return fillTarget;\n\n return availabilitySites[Math.max(fillTargetIndex, minimumFillTargetIndex)] ?? fillTarget;\n}\n"],"names":["availabilitySites","getWorkflowInterpolationFieldFailurePolicy","getWorkflowInterpolationFieldMinimumFillTarget","isBareContextReference","analyzeContextKeyAccess","routeExpression","templateExpressionOpen","runnerRootNotBareHint","planInterpolationField","params","violations","minimumFillTarget","field","resolvedSegments","segments","map","segment","kind","value","text","route","expression","keyAccess","length","push","violation","reason","source","contextRoots","root","hint","runnerRoots","roots","fillTarget","applyMinimumFillTarget","ok","plan","failurePolicy","undefined","fillTargetIndex","indexOf","minimumFillTargetIndex","Math","max"],"mappings":"AACA,SAEEA,iBAAiB,EAEjBC,0CAA0C,EAC1CC,8CAA8C,QAGzC,0CAA0C;AACjD,SAAQC,sBAAsB,QAAO,sBAAsB;AAC3D,SAAQC,uBAAuB,QAAO,0BAA0B;AAEhE,SAAQC,eAAe,QAAO,wBAAwB;AAEtD,MAAMC,yBAAyB,MAAM;AACrC,MAAMC,wBAAwB,CAAC,qDAAqD,EAAED,uBAAuB,YAAY,CAAC;AAmB1H,OAAO,SAASE,uBAAuBC,MAGtC;IACC,MAAMC,aAA8B,EAAE;IACtC,MAAMC,oBAAoBT,+CAA+CO,OAAOG,KAAK;IACrF,MAAMC,mBAA8CJ,OAAOK,QAAQ,CAACC,GAAG,CAAC,CAACC;QACvE,IAAIA,QAAQC,IAAI,KAAK,WAAW,OAAO;YAACA,MAAM;YAAWC,OAAOF,QAAQG,IAAI;QAAA;QAE5E,MAAMC,QAAQf,gBAAgBW,QAAQK,UAAU;QAChD,MAAMC,YAAYlB,wBAAwBY,QAAQK,UAAU;QAC5D,IAAIC,UAAUZ,UAAU,CAACa,MAAM,GAAG,GAAG;YACnCb,WAAWc,IAAI,IACVF,UAAUZ,UAAU,CAACK,GAAG,CAAC,CAACU,YAAe,CAAA;oBAC1CC,QAAQ;oBACRC,QAAQF,UAAUE,MAAM;oBACxBC,cAAc;wBAACH,UAAUI,IAAI;qBAAC;oBAC9BC,MAAM,GAAGL,UAAUI,IAAI,CAAC,sCAAsC,CAAC;gBACjE,CAAA;QAEJ,OAAO,IAAIT,MAAMW,WAAW,CAACR,MAAM,GAAG,KAAK,CAACpB,uBAAuBa,QAAQK,UAAU,CAACM,MAAM,GAAG;YAC7FjB,WAAWc,IAAI,CAAC;gBACdE,QAAQ;gBACRC,QAAQX,QAAQK,UAAU,CAACM,MAAM;gBACjCI,aAAaX,MAAMW,WAAW;gBAC9BD,MAAMvB;YACR;QACF;QAEA,OAAO;YACLU,MAAM;YACNI,YAAYL,QAAQK,UAAU;YAC9BW,OAAOZ,MAAMY,KAAK;YAClBC,YAAYC,uBAAuBd,MAAMa,UAAU,EAAEtB;QACvD;IACF;IAEA,IAAID,WAAWa,MAAM,GAAG,GAAG,OAAO;QAACY,IAAI;QAAOzB;IAAU;IAExD,OAAO;QACLyB,IAAI;QACJC,MAAM;YACJxB,OAAO;gBAACE,UAAUD;YAAgB;YAClCwB,eAAepC,2CAA2CQ,OAAOG,KAAK;QACxE;IACF;AACF;AAEA,SAASsB,uBACPD,UAAsB,EACtBtB,iBAA+C;IAE/C,IAAIA,sBAAsB2B,aAAaL,eAAe,eAAe,OAAOA;IAE5E,MAAMM,kBAAkBvC,kBAAkBwC,OAAO,CAACP;IAClD,MAAMQ,yBAAyBzC,kBAAkBwC,OAAO,CAAC7B;IACzD,IAAI4B,kBAAkB,KAAKE,yBAAyB,GAAG,OAAOR;IAE9D,OAAOjC,iBAAiB,CAAC0C,KAAKC,GAAG,CAACJ,iBAAiBE,wBAAwB,IAAIR;AACjF"}
@@ -0,0 +1,2 @@
1
+ export declare function predicateSourceIsBooleanShaped(source: string): boolean;
2
+ //# sourceMappingURL=predicate-shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predicate-shape.d.ts","sourceRoot":"","sources":["../../src/plan/predicate-shape.ts"],"names":[],"mappings":"AAcA,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAMtE"}
@@ -0,0 +1,45 @@
1
+ import { parse as parseCel } from '@marcbachmann/cel-js';
2
+ const comparisonOperators = new Set([
3
+ '!=',
4
+ '==',
5
+ 'in',
6
+ '<',
7
+ '<=',
8
+ '>',
9
+ '>='
10
+ ]);
11
+ const booleanReturningCalls = new Set([
12
+ 'all',
13
+ 'contains',
14
+ 'endsWith',
15
+ 'exists',
16
+ 'exists_one',
17
+ 'has',
18
+ 'matches',
19
+ 'startsWith'
20
+ ]);
21
+ export function predicateSourceIsBooleanShaped(source) {
22
+ try {
23
+ return nodeIsBooleanShaped(parseCel(source).ast);
24
+ } catch {
25
+ return false;
26
+ }
27
+ }
28
+ function nodeIsBooleanShaped(node) {
29
+ if (comparisonOperators.has(node.op)) return true;
30
+ if (node.op === '&&' || node.op === '||' || node.op === '!_') return true;
31
+ switch(node.op){
32
+ case 'value':
33
+ return typeof node.args === 'boolean';
34
+ case 'call':
35
+ return booleanReturningCalls.has(node.args[0]);
36
+ case 'rcall':
37
+ return booleanReturningCalls.has(node.args[0]);
38
+ case '?:':
39
+ return nodeIsBooleanShaped(node.args[1]) && nodeIsBooleanShaped(node.args[2]);
40
+ default:
41
+ return false;
42
+ }
43
+ }
44
+
45
+ //# sourceMappingURL=predicate-shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plan/predicate-shape.ts"],"sourcesContent":["import {type ASTNode, parse as parseCel} from '@marcbachmann/cel-js';\n\nconst comparisonOperators = new Set<string>(['!=', '==', 'in', '<', '<=', '>', '>=']);\nconst booleanReturningCalls = new Set([\n 'all',\n 'contains',\n 'endsWith',\n 'exists',\n 'exists_one',\n 'has',\n 'matches',\n 'startsWith',\n]);\n\nexport function predicateSourceIsBooleanShaped(source: string): boolean {\n try {\n return nodeIsBooleanShaped(parseCel(source).ast);\n } catch {\n return false;\n }\n}\n\nfunction nodeIsBooleanShaped(node: ASTNode): boolean {\n if (comparisonOperators.has(node.op)) return true;\n if (node.op === '&&' || node.op === '||' || node.op === '!_') return true;\n\n switch (node.op) {\n case 'value':\n return typeof node.args === 'boolean';\n case 'call':\n return booleanReturningCalls.has(node.args[0]);\n case 'rcall':\n return booleanReturningCalls.has(node.args[0]);\n case '?:':\n return nodeIsBooleanShaped(node.args[1]) && nodeIsBooleanShaped(node.args[2]);\n default:\n return false;\n }\n}\n"],"names":["parse","parseCel","comparisonOperators","Set","booleanReturningCalls","predicateSourceIsBooleanShaped","source","nodeIsBooleanShaped","ast","node","has","op","args"],"mappings":"AAAA,SAAsBA,SAASC,QAAQ,QAAO,uBAAuB;AAErE,MAAMC,sBAAsB,IAAIC,IAAY;IAAC;IAAM;IAAM;IAAM;IAAK;IAAM;IAAK;CAAK;AACpF,MAAMC,wBAAwB,IAAID,IAAI;IACpC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED,OAAO,SAASE,+BAA+BC,MAAc;IAC3D,IAAI;QACF,OAAOC,oBAAoBN,SAASK,QAAQE,GAAG;IACjD,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,SAASD,oBAAoBE,IAAa;IACxC,IAAIP,oBAAoBQ,GAAG,CAACD,KAAKE,EAAE,GAAG,OAAO;IAC7C,IAAIF,KAAKE,EAAE,KAAK,QAAQF,KAAKE,EAAE,KAAK,QAAQF,KAAKE,EAAE,KAAK,MAAM,OAAO;IAErE,OAAQF,KAAKE,EAAE;QACb,KAAK;YACH,OAAO,OAAOF,KAAKG,IAAI,KAAK;QAC9B,KAAK;YACH,OAAOR,sBAAsBM,GAAG,CAACD,KAAKG,IAAI,CAAC,EAAE;QAC/C,KAAK;YACH,OAAOR,sBAAsBM,GAAG,CAACD,KAAKG,IAAI,CAAC,EAAE;QAC/C,KAAK;YACH,OAAOL,oBAAoBE,KAAKG,IAAI,CAAC,EAAE,KAAKL,oBAAoBE,KAAKG,IAAI,CAAC,EAAE;QAC9E;YACE,OAAO;IACX;AACF"}
@@ -0,0 +1,17 @@
1
+ import type { WorkflowExpression } from '../expression/workflow-expression.js';
2
+ import type { FillTarget } from '../workflow-context/workflow-context.js';
3
+ export interface ResolvedFieldLiteralSegment {
4
+ readonly kind: 'literal';
5
+ readonly value: string;
6
+ }
7
+ export interface ResolvedFieldDeferredSegment {
8
+ readonly kind: 'deferred';
9
+ readonly expression: WorkflowExpression;
10
+ readonly roots: readonly string[];
11
+ readonly fillTarget: FillTarget;
12
+ }
13
+ export type ResolvedFieldSegment = ResolvedFieldLiteralSegment | ResolvedFieldDeferredSegment;
14
+ export interface ResolvedField {
15
+ readonly segments: readonly ResolvedFieldSegment[];
16
+ }
17
+ //# sourceMappingURL=resolved-field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolved-field.d.ts","sourceRoot":"","sources":["../../src/plan/resolved-field.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,sCAAsC,CAAC;AAC7E,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,yCAAyC,CAAC;AAExE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC;AAED,MAAM,MAAM,oBAAoB,GAAG,2BAA2B,GAAG,4BAA4B,CAAC;AAE9F,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACpD"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=resolved-field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plan/resolved-field.ts"],"sourcesContent":["import type {WorkflowExpression} from '../expression/workflow-expression.js';\nimport type {FillTarget} from '../workflow-context/workflow-context.js';\n\nexport interface ResolvedFieldLiteralSegment {\n readonly kind: 'literal';\n readonly value: string;\n}\n\nexport interface ResolvedFieldDeferredSegment {\n readonly kind: 'deferred';\n readonly expression: WorkflowExpression;\n readonly roots: readonly string[];\n readonly fillTarget: FillTarget;\n}\n\nexport type ResolvedFieldSegment = ResolvedFieldLiteralSegment | ResolvedFieldDeferredSegment;\n\nexport interface ResolvedField {\n readonly segments: readonly ResolvedFieldSegment[];\n}\n"],"names":[],"mappings":"AAiBA,WAEC"}
@@ -0,0 +1,9 @@
1
+ import type { WorkflowExpression } from '../expression/workflow-expression.js';
2
+ import { type FillTarget } from '../workflow-context/workflow-context.js';
3
+ export interface RoutedExpression {
4
+ readonly roots: readonly string[];
5
+ readonly runnerRoots: readonly string[];
6
+ readonly fillTarget: FillTarget;
7
+ }
8
+ export declare function routeExpression(expression: WorkflowExpression): RoutedExpression;
9
+ //# sourceMappingURL=route-expression.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-expression.d.ts","sourceRoot":"","sources":["../../src/plan/route-expression.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,sCAAsC,CAAC;AAC7E,OAAO,EAEL,KAAK,UAAU,EAIhB,MAAM,yCAAyC,CAAC;AAIjD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,kBAAkB,GAAG,gBAAgB,CAchF"}
@@ -0,0 +1,46 @@
1
+ import { availabilitySites, resolveContextRootAvailability, resolveContextRootHost, runnerFillTarget } from '../workflow-context/workflow-context.js';
2
+ import { analyzeContextRootKeyAccess } from './context-key-access.js';
3
+ import { extractExactContextRoots } from './extract-exact-context-roots.js';
4
+ export function routeExpression(expression) {
5
+ const roots = extractExactContextRoots(expression.source);
6
+ const knownRoots = roots.filter((root)=>resolveContextRootHost(root) !== undefined);
7
+ const runnerRoots = knownRoots.filter((root)=>resolveContextRootHost(root) === 'runner');
8
+ if (runnerRoots.length > 0) {
9
+ return {
10
+ roots,
11
+ runnerRoots,
12
+ fillTarget: runnerFillTarget
13
+ };
14
+ }
15
+ return {
16
+ roots,
17
+ runnerRoots,
18
+ fillTarget: expressionMinimumFillTarget(expression, maxAvailabilitySite(knownRoots))
19
+ };
20
+ }
21
+ function expressionMinimumFillTarget(expression, fillTarget) {
22
+ if (fillTarget === runnerFillTarget) return fillTarget;
23
+ if (!referencesExecutionFailed(expression)) return fillTarget;
24
+ return laterFillTarget(fillTarget, 'step-dispatch');
25
+ }
26
+ function referencesExecutionFailed(expression) {
27
+ const access = analyzeContextRootKeyAccess(expression, [
28
+ 'execution'
29
+ ]);
30
+ return access.references.some((reference)=>reference.key === 'failed');
31
+ }
32
+ function laterFillTarget(left, right) {
33
+ if (left === runnerFillTarget || right === runnerFillTarget) return runnerFillTarget;
34
+ return availabilitySites.indexOf(left) >= availabilitySites.indexOf(right) ? left : right;
35
+ }
36
+ function maxAvailabilitySite(roots) {
37
+ let maxIndex = 0;
38
+ for (const root of roots){
39
+ const availability = resolveContextRootAvailability(root);
40
+ if (availability === undefined) continue;
41
+ maxIndex = Math.max(maxIndex, availabilitySites.indexOf(availability));
42
+ }
43
+ return availabilitySites[maxIndex] ?? availabilitySites[0];
44
+ }
45
+
46
+ //# sourceMappingURL=route-expression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plan/route-expression.ts"],"sourcesContent":["import type {WorkflowExpression} from '../expression/workflow-expression.js';\nimport {\n availabilitySites,\n type FillTarget,\n resolveContextRootAvailability,\n resolveContextRootHost,\n runnerFillTarget,\n} from '../workflow-context/workflow-context.js';\nimport {analyzeContextRootKeyAccess} from './context-key-access.js';\nimport {extractExactContextRoots} from './extract-exact-context-roots.js';\n\nexport interface RoutedExpression {\n readonly roots: readonly string[];\n readonly runnerRoots: readonly string[];\n readonly fillTarget: FillTarget;\n}\n\nexport function routeExpression(expression: WorkflowExpression): RoutedExpression {\n const roots = extractExactContextRoots(expression.source);\n const knownRoots = roots.filter((root) => resolveContextRootHost(root) !== undefined);\n const runnerRoots = knownRoots.filter((root) => resolveContextRootHost(root) === 'runner');\n\n if (runnerRoots.length > 0) {\n return {roots, runnerRoots, fillTarget: runnerFillTarget};\n }\n\n return {\n roots,\n runnerRoots,\n fillTarget: expressionMinimumFillTarget(expression, maxAvailabilitySite(knownRoots)),\n };\n}\n\nfunction expressionMinimumFillTarget(\n expression: WorkflowExpression,\n fillTarget: FillTarget,\n): FillTarget {\n if (fillTarget === runnerFillTarget) return fillTarget;\n if (!referencesExecutionFailed(expression)) return fillTarget;\n return laterFillTarget(fillTarget, 'step-dispatch');\n}\n\nfunction referencesExecutionFailed(expression: WorkflowExpression): boolean {\n const access = analyzeContextRootKeyAccess(expression, ['execution']);\n return access.references.some((reference) => reference.key === 'failed');\n}\n\nfunction laterFillTarget(left: FillTarget, right: FillTarget): FillTarget {\n if (left === runnerFillTarget || right === runnerFillTarget) return runnerFillTarget;\n return availabilitySites.indexOf(left) >= availabilitySites.indexOf(right) ? left : right;\n}\n\nfunction maxAvailabilitySite(roots: readonly string[]): FillTarget {\n let maxIndex = 0;\n for (const root of roots) {\n const availability = resolveContextRootAvailability(root);\n if (availability === undefined) continue;\n maxIndex = Math.max(maxIndex, availabilitySites.indexOf(availability));\n }\n\n return availabilitySites[maxIndex] ?? availabilitySites[0];\n}\n"],"names":["availabilitySites","resolveContextRootAvailability","resolveContextRootHost","runnerFillTarget","analyzeContextRootKeyAccess","extractExactContextRoots","routeExpression","expression","roots","source","knownRoots","filter","root","undefined","runnerRoots","length","fillTarget","expressionMinimumFillTarget","maxAvailabilitySite","referencesExecutionFailed","laterFillTarget","access","references","some","reference","key","left","right","indexOf","maxIndex","availability","Math","max"],"mappings":"AACA,SACEA,iBAAiB,EAEjBC,8BAA8B,EAC9BC,sBAAsB,EACtBC,gBAAgB,QACX,0CAA0C;AACjD,SAAQC,2BAA2B,QAAO,0BAA0B;AACpE,SAAQC,wBAAwB,QAAO,mCAAmC;AAQ1E,OAAO,SAASC,gBAAgBC,UAA8B;IAC5D,MAAMC,QAAQH,yBAAyBE,WAAWE,MAAM;IACxD,MAAMC,aAAaF,MAAMG,MAAM,CAAC,CAACC,OAASV,uBAAuBU,UAAUC;IAC3E,MAAMC,cAAcJ,WAAWC,MAAM,CAAC,CAACC,OAASV,uBAAuBU,UAAU;IAEjF,IAAIE,YAAYC,MAAM,GAAG,GAAG;QAC1B,OAAO;YAACP;YAAOM;YAAaE,YAAYb;QAAgB;IAC1D;IAEA,OAAO;QACLK;QACAM;QACAE,YAAYC,4BAA4BV,YAAYW,oBAAoBR;IAC1E;AACF;AAEA,SAASO,4BACPV,UAA8B,EAC9BS,UAAsB;IAEtB,IAAIA,eAAeb,kBAAkB,OAAOa;IAC5C,IAAI,CAACG,0BAA0BZ,aAAa,OAAOS;IACnD,OAAOI,gBAAgBJ,YAAY;AACrC;AAEA,SAASG,0BAA0BZ,UAA8B;IAC/D,MAAMc,SAASjB,4BAA4BG,YAAY;QAAC;KAAY;IACpE,OAAOc,OAAOC,UAAU,CAACC,IAAI,CAAC,CAACC,YAAcA,UAAUC,GAAG,KAAK;AACjE;AAEA,SAASL,gBAAgBM,IAAgB,EAAEC,KAAiB;IAC1D,IAAID,SAASvB,oBAAoBwB,UAAUxB,kBAAkB,OAAOA;IACpE,OAAOH,kBAAkB4B,OAAO,CAACF,SAAS1B,kBAAkB4B,OAAO,CAACD,SAASD,OAAOC;AACtF;AAEA,SAAST,oBAAoBV,KAAwB;IACnD,IAAIqB,WAAW;IACf,KAAK,MAAMjB,QAAQJ,MAAO;QACxB,MAAMsB,eAAe7B,+BAA+BW;QACpD,IAAIkB,iBAAiBjB,WAAW;QAChCgB,WAAWE,KAAKC,GAAG,CAACH,UAAU7B,kBAAkB4B,OAAO,CAACE;IAC1D;IAEA,OAAO9B,iBAAiB,CAAC6B,SAAS,IAAI7B,iBAAiB,CAAC,EAAE;AAC5D"}
@@ -0,0 +1,14 @@
1
+ import type { WorkflowExpression } from '../expression/workflow-expression.js';
2
+ export type ServerEvaluabilityViolation = {
3
+ readonly reason: 'runner-root-in-server-expression';
4
+ readonly source: string;
5
+ readonly runnerRoots: readonly string[];
6
+ };
7
+ export type ServerEvaluabilityResult = {
8
+ readonly ok: true;
9
+ } | {
10
+ readonly ok: false;
11
+ readonly violations: readonly ServerEvaluabilityViolation[];
12
+ };
13
+ export declare function validateServerEvaluable(expression: WorkflowExpression): ServerEvaluabilityResult;
14
+ //# sourceMappingURL=validate-server-evaluable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-server-evaluable.d.ts","sourceRoot":"","sources":["../../src/plan/validate-server-evaluable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,sCAAsC,CAAC;AAI7E,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,CAAC,MAAM,EAAE,kCAAkC,CAAC;IACpD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAChC;IAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAC,GACnB;IAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,2BAA2B,EAAE,CAAA;CAAC,CAAC;AAEtF,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,kBAAkB,GAAG,wBAAwB,CAiBhG"}
@@ -0,0 +1,20 @@
1
+ import { resolveContextRootHost } from '../workflow-context/workflow-context.js';
2
+ import { extractExactContextRoots } from './extract-exact-context-roots.js';
3
+ export function validateServerEvaluable(expression) {
4
+ const runnerRoots = extractExactContextRoots(expression.source).filter((root)=>resolveContextRootHost(root) === 'runner');
5
+ if (runnerRoots.length === 0) return {
6
+ ok: true
7
+ };
8
+ return {
9
+ ok: false,
10
+ violations: [
11
+ {
12
+ reason: 'runner-root-in-server-expression',
13
+ source: expression.source,
14
+ runnerRoots
15
+ }
16
+ ]
17
+ };
18
+ }
19
+
20
+ //# sourceMappingURL=validate-server-evaluable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plan/validate-server-evaluable.ts"],"sourcesContent":["import type {WorkflowExpression} from '../expression/workflow-expression.js';\nimport {resolveContextRootHost} from '../workflow-context/workflow-context.js';\nimport {extractExactContextRoots} from './extract-exact-context-roots.js';\n\nexport type ServerEvaluabilityViolation = {\n readonly reason: 'runner-root-in-server-expression';\n readonly source: string;\n readonly runnerRoots: readonly string[];\n};\n\nexport type ServerEvaluabilityResult =\n | {readonly ok: true}\n | {readonly ok: false; readonly violations: readonly ServerEvaluabilityViolation[]};\n\nexport function validateServerEvaluable(expression: WorkflowExpression): ServerEvaluabilityResult {\n const runnerRoots = extractExactContextRoots(expression.source).filter(\n (root) => resolveContextRootHost(root) === 'runner',\n );\n\n if (runnerRoots.length === 0) return {ok: true};\n\n return {\n ok: false,\n violations: [\n {\n reason: 'runner-root-in-server-expression',\n source: expression.source,\n runnerRoots,\n },\n ],\n };\n}\n"],"names":["resolveContextRootHost","extractExactContextRoots","validateServerEvaluable","expression","runnerRoots","source","filter","root","length","ok","violations","reason"],"mappings":"AACA,SAAQA,sBAAsB,QAAO,0CAA0C;AAC/E,SAAQC,wBAAwB,QAAO,mCAAmC;AAY1E,OAAO,SAASC,wBAAwBC,UAA8B;IACpE,MAAMC,cAAcH,yBAAyBE,WAAWE,MAAM,EAAEC,MAAM,CACpE,CAACC,OAASP,uBAAuBO,UAAU;IAG7C,IAAIH,YAAYI,MAAM,KAAK,GAAG,OAAO;QAACC,IAAI;IAAI;IAE9C,OAAO;QACLA,IAAI;QACJC,YAAY;YACV;gBACEC,QAAQ;gBACRN,QAAQF,WAAWE,MAAM;gBACzBD;YACF;SACD;IACH;AACF"}