@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.
- package/LICENSE +21 -0
- package/README.md +117 -0
- package/dist/evaluator/errors.d.ts +8 -0
- package/dist/evaluator/errors.d.ts.map +1 -0
- package/dist/evaluator/errors.js +13 -0
- package/dist/evaluator/errors.js.map +1 -0
- package/dist/evaluator/evaluate-workflow-expression.d.ts +11 -0
- package/dist/evaluator/evaluate-workflow-expression.d.ts.map +1 -0
- package/dist/evaluator/evaluate-workflow-expression.js +30 -0
- package/dist/evaluator/evaluate-workflow-expression.js.map +1 -0
- package/dist/evaluator/index.d.ts +3 -0
- package/dist/evaluator/index.d.ts.map +1 -0
- package/dist/evaluator/index.js +4 -0
- package/dist/evaluator/index.js.map +1 -0
- package/dist/expression/create-workflow-expression.d.ts +7 -0
- package/dist/expression/create-workflow-expression.d.ts.map +1 -0
- package/dist/expression/create-workflow-expression.js +156 -0
- package/dist/expression/create-workflow-expression.js.map +1 -0
- package/dist/expression/errors.d.ts +12 -0
- package/dist/expression/errors.d.ts.map +1 -0
- package/dist/expression/errors.js +13 -0
- package/dist/expression/errors.js.map +1 -0
- package/dist/expression/index.d.ts +4 -0
- package/dist/expression/index.d.ts.map +1 -0
- package/dist/expression/index.js +4 -0
- package/dist/expression/index.js.map +1 -0
- package/dist/expression/workflow-expression.d.ts +33 -0
- package/dist/expression/workflow-expression.d.ts.map +1 -0
- package/dist/expression/workflow-expression.js +3 -0
- package/dist/expression/workflow-expression.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/outputs/index.d.ts +2 -0
- package/dist/outputs/index.d.ts.map +1 -0
- package/dist/outputs/index.js +3 -0
- package/dist/outputs/index.js.map +1 -0
- package/dist/outputs/output-declarations.d.ts +39 -0
- package/dist/outputs/output-declarations.d.ts.map +1 -0
- package/dist/outputs/output-declarations.js +295 -0
- package/dist/outputs/output-declarations.js.map +1 -0
- package/dist/plan/bare-reference.d.ts +2 -0
- package/dist/plan/bare-reference.d.ts.map +1 -0
- package/dist/plan/bare-reference.js +23 -0
- package/dist/plan/bare-reference.js.map +1 -0
- package/dist/plan/context-key-access.d.ts +25 -0
- package/dist/plan/context-key-access.d.ts.map +1 -0
- package/dist/plan/context-key-access.js +249 -0
- package/dist/plan/context-key-access.js.map +1 -0
- package/dist/plan/evaluate-planned-predicate.d.ts +14 -0
- package/dist/plan/evaluate-planned-predicate.d.ts.map +1 -0
- package/dist/plan/evaluate-planned-predicate.js +31 -0
- package/dist/plan/evaluate-planned-predicate.js.map +1 -0
- package/dist/plan/evaluation-trace.d.ts +44 -0
- package/dist/plan/evaluation-trace.d.ts.map +1 -0
- package/dist/plan/evaluation-trace.js +95 -0
- package/dist/plan/evaluation-trace.js.map +1 -0
- package/dist/plan/extract-exact-context-roots.d.ts +2 -0
- package/dist/plan/extract-exact-context-roots.d.ts.map +1 -0
- package/dist/plan/extract-exact-context-roots.js +114 -0
- package/dist/plan/extract-exact-context-roots.js.map +1 -0
- package/dist/plan/fill.d.ts +3 -0
- package/dist/plan/fill.d.ts.map +1 -0
- package/dist/plan/fill.js +8 -0
- package/dist/plan/fill.js.map +1 -0
- package/dist/plan/freeze-run-command.d.ts +17 -0
- package/dist/plan/freeze-run-command.d.ts.map +1 -0
- package/dist/plan/freeze-run-command.js +33 -0
- package/dist/plan/freeze-run-command.js.map +1 -0
- package/dist/plan/freeze.d.ts +48 -0
- package/dist/plan/freeze.d.ts.map +1 -0
- package/dist/plan/freeze.js +148 -0
- package/dist/plan/freeze.js.map +1 -0
- package/dist/plan/plan-field.d.ts +26 -0
- package/dist/plan/plan-field.d.ts.map +1 -0
- package/dist/plan/plan-field.js +63 -0
- package/dist/plan/plan-field.js.map +1 -0
- package/dist/plan/predicate-shape.d.ts +2 -0
- package/dist/plan/predicate-shape.d.ts.map +1 -0
- package/dist/plan/predicate-shape.js +45 -0
- package/dist/plan/predicate-shape.js.map +1 -0
- package/dist/plan/resolved-field.d.ts +17 -0
- package/dist/plan/resolved-field.d.ts.map +1 -0
- package/dist/plan/resolved-field.js +3 -0
- package/dist/plan/resolved-field.js.map +1 -0
- package/dist/plan/route-expression.d.ts +9 -0
- package/dist/plan/route-expression.d.ts.map +1 -0
- package/dist/plan/route-expression.js +46 -0
- package/dist/plan/route-expression.js.map +1 -0
- package/dist/plan/validate-server-evaluable.d.ts +14 -0
- package/dist/plan/validate-server-evaluable.d.ts.map +1 -0
- package/dist/plan/validate-server-evaluable.js +20 -0
- package/dist/plan/validate-server-evaluable.js.map +1 -0
- package/dist/resolver/coerce-workflow-value-to-string.d.ts +2 -0
- package/dist/resolver/coerce-workflow-value-to-string.d.ts.map +1 -0
- package/dist/resolver/coerce-workflow-value-to-string.js +16 -0
- package/dist/resolver/coerce-workflow-value-to-string.js.map +1 -0
- package/dist/resolver/errors.d.ts +10 -0
- package/dist/resolver/errors.d.ts.map +1 -0
- package/dist/resolver/errors.js +12 -0
- package/dist/resolver/errors.js.map +1 -0
- package/dist/run/hoist-run-command.d.ts +33 -0
- package/dist/run/hoist-run-command.d.ts.map +1 -0
- package/dist/run/hoist-run-command.js +79 -0
- package/dist/run/hoist-run-command.js.map +1 -0
- package/dist/run/shell-quoting.d.ts +24 -0
- package/dist/run/shell-quoting.d.ts.map +1 -0
- package/dist/run/shell-quoting.js +364 -0
- package/dist/run/shell-quoting.js.map +1 -0
- package/dist/template/errors.d.ts +14 -0
- package/dist/template/errors.d.ts.map +1 -0
- package/dist/template/errors.js +14 -0
- package/dist/template/errors.js.map +1 -0
- package/dist/template/extract-cel-context-roots.d.ts +2 -0
- package/dist/template/extract-cel-context-roots.d.ts.map +1 -0
- package/dist/template/extract-cel-context-roots.js +110 -0
- package/dist/template/extract-cel-context-roots.js.map +1 -0
- package/dist/template/extract-cel-untrusted-path-accesses.d.ts +5 -0
- package/dist/template/extract-cel-untrusted-path-accesses.d.ts.map +1 -0
- package/dist/template/extract-cel-untrusted-path-accesses.js +140 -0
- package/dist/template/extract-cel-untrusted-path-accesses.js.map +1 -0
- package/dist/template/parse-workflow-template.d.ts +3 -0
- package/dist/template/parse-workflow-template.d.ts.map +1 -0
- package/dist/template/parse-workflow-template.js +111 -0
- package/dist/template/parse-workflow-template.js.map +1 -0
- package/dist/template/scan-cel-token.d.ts +3 -0
- package/dist/template/scan-cel-token.d.ts.map +1 -0
- package/dist/template/scan-cel-token.js +55 -0
- package/dist/template/scan-cel-token.js.map +1 -0
- package/dist/template/template-segment.d.ts +12 -0
- package/dist/template/template-segment.d.ts.map +1 -0
- package/dist/template/template-segment.js +3 -0
- package/dist/template/template-segment.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -0
- package/dist/workflow-context/workflow-context.d.ts +458 -0
- package/dist/workflow-context/workflow-context.d.ts.map +1 -0
- package/dist/workflow-context/workflow-context.js +664 -0
- package/dist/workflow-context/workflow-context.js.map +1 -0
- 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 @@
|
|
|
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 @@
|
|
|
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"}
|