@haibun/core 4.0.0-alpha.2 → 4.0.0-alpha.3
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/build/currentVersion.d.ts +1 -1
- package/build/currentVersion.js +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/kireji/converter.d.ts +2 -2
- package/build/kireji/converter.d.ts.map +1 -1
- package/build/kireji/converter.js +12 -9
- package/build/kireji/converter.js.map +1 -1
- package/build/kireji/withAction.d.ts +16 -4
- package/build/kireji/withAction.d.ts.map +1 -1
- package/build/kireji/withAction.js +40 -11
- package/build/kireji/withAction.js.map +1 -1
- package/build/lib/EventLogger.d.ts +5 -5
- package/build/lib/EventLogger.d.ts.map +1 -1
- package/build/lib/EventLogger.js +39 -37
- package/build/lib/EventLogger.js.map +1 -1
- package/build/lib/PhaseRunner.d.ts +3 -3
- package/build/lib/PhaseRunner.d.ts.map +1 -1
- package/build/lib/PhaseRunner.js +7 -5
- package/build/lib/PhaseRunner.js.map +1 -1
- package/build/lib/astepper.d.ts +90 -13
- package/build/lib/astepper.d.ts.map +1 -1
- package/build/lib/astepper.js +35 -6
- package/build/lib/astepper.js.map +1 -1
- package/build/lib/base-prompt-manager.d.ts +1 -1
- package/build/lib/base-prompt-manager.d.ts.map +1 -1
- package/build/lib/base-prompt-manager.js.map +1 -1
- package/build/lib/capture-locator.d.ts +1 -1
- package/build/lib/capture-locator.d.ts.map +1 -1
- package/build/lib/capture-locator.js +5 -5
- package/build/lib/capture-locator.js.map +1 -1
- package/build/lib/core/flow-runner.d.ts +8 -7
- package/build/lib/core/flow-runner.d.ts.map +1 -1
- package/build/lib/core/flow-runner.js +42 -71
- package/build/lib/core/flow-runner.js.map +1 -1
- package/build/lib/core-domains.d.ts +2 -2
- package/build/lib/core-domains.d.ts.map +1 -1
- package/build/lib/core-domains.js +17 -18
- package/build/lib/core-domains.js.map +1 -1
- package/build/lib/defs.d.ts +2 -13
- package/build/lib/defs.d.ts.map +1 -1
- package/build/lib/defs.js.map +1 -1
- package/build/lib/document-content.d.ts +18 -0
- package/build/lib/document-content.d.ts.map +1 -0
- package/build/lib/document-content.js +158 -0
- package/build/lib/document-content.js.map +1 -0
- package/build/lib/domains.d.ts +31 -0
- package/build/lib/domains.d.ts.map +1 -0
- package/build/lib/domains.js +105 -0
- package/build/lib/domains.js.map +1 -0
- package/build/lib/execution.d.ts +304 -0
- package/build/lib/execution.d.ts.map +1 -0
- package/build/lib/execution.js +23 -0
- package/build/lib/execution.js.map +1 -0
- package/build/lib/feature-variables.d.ts +21 -50
- package/build/lib/feature-variables.d.ts.map +1 -1
- package/build/lib/feature-variables.js +122 -232
- package/build/lib/feature-variables.js.map +1 -1
- package/build/lib/features.d.ts +2 -2
- package/build/lib/features.d.ts.map +1 -1
- package/build/lib/features.js +13 -17
- package/build/lib/features.js.map +1 -1
- package/build/lib/fixme.d.ts.map +1 -1
- package/build/lib/host-id.d.ts +44 -0
- package/build/lib/host-id.d.ts.map +1 -0
- package/build/lib/host-id.js +51 -0
- package/build/lib/host-id.js.map +1 -0
- package/build/lib/http-observations.d.ts +15 -2
- package/build/lib/http-observations.d.ts.map +1 -1
- package/build/lib/http-observations.js +40 -23
- package/build/lib/http-observations.js.map +1 -1
- package/build/lib/hypermedia.d.ts +62 -0
- package/build/lib/hypermedia.d.ts.map +1 -0
- package/build/lib/hypermedia.js +228 -0
- package/build/lib/hypermedia.js.map +1 -0
- package/build/lib/namedVars.d.ts +2 -2
- package/build/lib/namedVars.d.ts.map +1 -1
- package/build/lib/namedVars.js +25 -30
- package/build/lib/namedVars.js.map +1 -1
- package/build/lib/node-http-events.d.ts +3 -3
- package/build/lib/node-http-events.d.ts.map +1 -1
- package/build/lib/node-http-events.js +26 -26
- package/build/lib/node-http-events.js.map +1 -1
- package/build/lib/populateActionArgs.d.ts +4 -4
- package/build/lib/populateActionArgs.d.ts.map +1 -1
- package/build/lib/populateActionArgs.js +4 -6
- package/build/lib/populateActionArgs.js.map +1 -1
- package/build/lib/prompter.d.ts.map +1 -1
- package/build/lib/prompter.js +10 -7
- package/build/lib/prompter.js.map +1 -1
- package/build/lib/quad-store.d.ts +34 -10
- package/build/lib/quad-store.d.ts.map +1 -1
- package/build/lib/quad-store.js +169 -21
- package/build/lib/quad-store.js.map +1 -1
- package/build/lib/quad-types.d.ts +80 -9
- package/build/lib/quad-types.d.ts.map +1 -1
- package/build/lib/quad-types.js +46 -2
- package/build/lib/quad-types.js.map +1 -1
- package/build/lib/readline-prompter.d.ts +1 -1
- package/build/lib/readline-prompter.js +4 -4
- package/build/lib/remote-stepper-proxy.d.ts +56 -0
- package/build/lib/remote-stepper-proxy.d.ts.map +1 -0
- package/build/lib/remote-stepper-proxy.js +123 -0
- package/build/lib/remote-stepper-proxy.js.map +1 -0
- package/build/lib/resolver-features.d.ts +1 -1
- package/build/lib/resolver-features.d.ts.map +1 -1
- package/build/lib/resolver-features.js +2 -2
- package/build/lib/resolver-features.js.map +1 -1
- package/build/lib/resources.d.ts +461 -0
- package/build/lib/resources.d.ts.map +1 -0
- package/build/lib/resources.js +249 -0
- package/build/lib/resources.js.map +1 -0
- package/build/lib/rpc-client.d.ts +68 -0
- package/build/lib/rpc-client.d.ts.map +1 -0
- package/build/lib/rpc-client.js +186 -0
- package/build/lib/rpc-client.js.map +1 -0
- package/build/lib/sse-subscriber.d.ts +57 -0
- package/build/lib/sse-subscriber.d.ts.map +1 -0
- package/build/lib/sse-subscriber.js +110 -0
- package/build/lib/sse-subscriber.js.map +1 -0
- package/build/lib/step-dispatch.d.ts +92 -28
- package/build/lib/step-dispatch.d.ts.map +1 -1
- package/build/lib/step-dispatch.js +331 -75
- package/build/lib/step-dispatch.js.map +1 -1
- package/build/lib/step-validation.d.ts +3 -3
- package/build/lib/step-validation.d.ts.map +1 -1
- package/build/lib/step-validation.js +2 -2
- package/build/lib/step-validation.js.map +1 -1
- package/build/lib/stepper-cycles.d.ts +5 -0
- package/build/lib/stepper-cycles.d.ts.map +1 -0
- package/build/lib/stepper-cycles.js +31 -0
- package/build/lib/stepper-cycles.js.map +1 -0
- package/build/lib/stepper-registry.d.ts +6 -3
- package/build/lib/stepper-registry.d.ts.map +1 -1
- package/build/lib/stepper-registry.js +9 -8
- package/build/lib/stepper-registry.js.map +1 -1
- package/build/lib/subprocess-runner.d.ts +35 -0
- package/build/lib/subprocess-runner.d.ts.map +1 -0
- package/build/lib/subprocess-runner.js +60 -0
- package/build/lib/subprocess-runner.js.map +1 -0
- package/build/lib/subprocess-transport.d.ts +37 -0
- package/build/lib/subprocess-transport.d.ts.map +1 -0
- package/build/lib/subprocess-transport.js +113 -0
- package/build/lib/subprocess-transport.js.map +1 -0
- package/build/lib/test/EventCollectorStepper.d.ts +3 -3
- package/build/lib/test/EventCollectorStepper.d.ts.map +1 -1
- package/build/lib/test/EventCollectorStepper.js +3 -3
- package/build/lib/test/EventCollectorStepper.js.map +1 -1
- package/build/lib/test/SetTimeStepper.d.ts +3 -3
- package/build/lib/test/SetTimeStepper.d.ts.map +1 -1
- package/build/lib/test/SetTimeStepper.js +7 -7
- package/build/lib/test/SetTimeStepper.js.map +1 -1
- package/build/lib/test/TestSteps.d.ts +7 -7
- package/build/lib/test/TestSteps.d.ts.map +1 -1
- package/build/lib/test/TestSteps.js +7 -7
- package/build/lib/test/TestSteps.js.map +1 -1
- package/build/lib/test/TestStepsWithOptions.d.ts +6 -6
- package/build/lib/test/TestStepsWithOptions.js +7 -7
- package/build/lib/test/lib.d.ts +3 -3
- package/build/lib/test/lib.d.ts.map +1 -1
- package/build/lib/test/lib.js +27 -21
- package/build/lib/test/lib.js.map +1 -1
- package/build/lib/test/resolvedTestFeatures.d.ts +6 -6
- package/build/lib/test/resolvedTestFeatures.d.ts.map +1 -1
- package/build/lib/test/resolvedTestFeatures.js +5 -5
- package/build/lib/test/subprocess-fixture.d.ts +8 -0
- package/build/lib/test/subprocess-fixture.d.ts.map +1 -0
- package/build/lib/test/subprocess-fixture.js +27 -0
- package/build/lib/test/subprocess-fixture.js.map +1 -0
- package/build/lib/ttag.d.ts +7 -1
- package/build/lib/ttag.d.ts.map +1 -1
- package/build/lib/ttag.js +5 -4
- package/build/lib/ttag.js.map +1 -1
- package/build/lib/util/dot-path.d.ts +2 -2
- package/build/lib/util/dot-path.d.ts.map +1 -1
- package/build/lib/util/dot-path.js +8 -7
- package/build/lib/util/dot-path.js.map +1 -1
- package/build/lib/util/index.d.ts +10 -24
- package/build/lib/util/index.d.ts.map +1 -1
- package/build/lib/util/index.js +43 -93
- package/build/lib/util/index.js.map +1 -1
- package/build/lib/util/node/actualURI.d.ts +4 -0
- package/build/lib/util/node/actualURI.d.ts.map +1 -0
- package/build/lib/util/node/actualURI.js +10 -0
- package/build/lib/util/node/actualURI.js.map +1 -0
- package/build/lib/util/node/module-loader.d.ts +14 -0
- package/build/lib/util/node/module-loader.d.ts.map +1 -0
- package/build/lib/util/node/module-loader.js +51 -0
- package/build/lib/util/node/module-loader.js.map +1 -0
- package/build/lib/util/node/workspace-lib.d.ts +15 -0
- package/build/lib/util/node/workspace-lib.d.ts.map +1 -0
- package/build/lib/util/node/workspace-lib.js +119 -0
- package/build/lib/util/node/workspace-lib.js.map +1 -0
- package/build/lib/util/secret-utils.d.ts.map +1 -1
- package/build/lib/util/secret-utils.js +2 -2
- package/build/lib/util/secret-utils.js.map +1 -1
- package/build/lib/vertex-crud.d.ts +22 -0
- package/build/lib/vertex-crud.d.ts.map +1 -0
- package/build/lib/vertex-crud.js +73 -0
- package/build/lib/vertex-crud.js.map +1 -0
- package/build/lib/workspace-discovery.d.ts +1 -1
- package/build/lib/workspace-discovery.d.ts.map +1 -1
- package/build/lib/workspace-discovery.js +10 -10
- package/build/lib/workspace-discovery.js.map +1 -1
- package/build/lib/zcap-like-authority.d.ts +38 -0
- package/build/lib/zcap-like-authority.d.ts.map +1 -0
- package/build/lib/zcap-like-authority.js +56 -0
- package/build/lib/zcap-like-authority.js.map +1 -0
- package/build/monitor/index.d.ts +1 -1
- package/build/monitor/index.d.ts.map +1 -1
- package/build/monitor/index.js +1 -1
- package/build/monitor/index.js.map +1 -1
- package/build/phases/Executor.d.ts +31 -7
- package/build/phases/Executor.d.ts.map +1 -1
- package/build/phases/Executor.js +201 -219
- package/build/phases/Executor.js.map +1 -1
- package/build/phases/Resolver.d.ts +2 -2
- package/build/phases/Resolver.d.ts.map +1 -1
- package/build/phases/Resolver.js +35 -30
- package/build/phases/Resolver.js.map +1 -1
- package/build/phases/collector.d.ts +3 -3
- package/build/phases/collector.d.ts.map +1 -1
- package/build/phases/collector.js +19 -17
- package/build/phases/collector.js.map +1 -1
- package/build/run-policy/run-policy-schema.d.ts +3 -5
- package/build/run-policy/run-policy-schema.d.ts.map +1 -1
- package/build/run-policy/run-policy-schema.js +41 -37
- package/build/run-policy/run-policy-schema.js.map +1 -1
- package/build/run-policy/run-policy-types.d.ts +1 -1
- package/build/run-policy/run-policy-types.d.ts.map +1 -1
- package/build/run-policy/run-policy-types.js +19 -16
- package/build/run-policy/run-policy-types.js.map +1 -1
- package/build/runner.d.ts +4 -4
- package/build/runner.d.ts.map +1 -1
- package/build/runner.js +15 -13
- package/build/runner.js.map +1 -1
- package/build/schema/protocol.d.ts +153 -61
- package/build/schema/protocol.d.ts.map +1 -1
- package/build/schema/protocol.js +177 -148
- package/build/schema/protocol.js.map +1 -1
- package/build/steps/activities-stepper.d.ts +13 -13
- package/build/steps/activities-stepper.d.ts.map +1 -1
- package/build/steps/activities-stepper.js +105 -79
- package/build/steps/activities-stepper.js.map +1 -1
- package/build/steps/conformance.d.ts +5 -5
- package/build/steps/conformance.js +4 -4
- package/build/steps/console-monitor-stepper.d.ts +2 -2
- package/build/steps/console-monitor-stepper.d.ts.map +1 -1
- package/build/steps/console-monitor-stepper.js +22 -22
- package/build/steps/console-monitor-stepper.js.map +1 -1
- package/build/steps/debugger-stepper.d.ts +11 -11
- package/build/steps/debugger-stepper.d.ts.map +1 -1
- package/build/steps/debugger-stepper.js +65 -64
- package/build/steps/debugger-stepper.js.map +1 -1
- package/build/steps/finalizer-stepper.d.ts +3 -4
- package/build/steps/finalizer-stepper.d.ts.map +1 -1
- package/build/steps/finalizer-stepper.js +16 -19
- package/build/steps/finalizer-stepper.js.map +1 -1
- package/build/steps/haibun.d.ts +27 -20
- package/build/steps/haibun.d.ts.map +1 -1
- package/build/steps/haibun.js +76 -67
- package/build/steps/haibun.js.map +1 -1
- package/build/steps/lib/tts.d.ts +1 -1
- package/build/steps/lib/tts.d.ts.map +1 -1
- package/build/steps/lib/tts.js +28 -28
- package/build/steps/lib/tts.js.map +1 -1
- package/build/steps/logic-stepper.d.ts +5 -5
- package/build/steps/logic-stepper.d.ts.map +1 -1
- package/build/steps/logic-stepper.js +76 -76
- package/build/steps/logic-stepper.js.map +1 -1
- package/build/steps/narrator.d.ts +9 -9
- package/build/steps/narrator.d.ts.map +1 -1
- package/build/steps/narrator.js +32 -28
- package/build/steps/narrator.js.map +1 -1
- package/build/steps/resources-stepper.d.ts +47 -0
- package/build/steps/resources-stepper.d.ts.map +1 -0
- package/build/steps/resources-stepper.js +100 -0
- package/build/steps/resources-stepper.js.map +1 -0
- package/build/steps/variables-stepper.d.ts +57 -57
- package/build/steps/variables-stepper.d.ts.map +1 -1
- package/build/steps/variables-stepper.js +252 -224
- package/build/steps/variables-stepper.js.map +1 -1
- package/build/steps/zcap-like-stepper.d.ts +50 -0
- package/build/steps/zcap-like-stepper.d.ts.map +1 -0
- package/build/steps/zcap-like-stepper.js +113 -0
- package/build/steps/zcap-like-stepper.js.map +1 -0
- package/package.json +1 -1
- package/build/lib/consts.d.ts +0 -5
- package/build/lib/consts.d.ts.map +0 -1
- package/build/lib/consts.js +0 -5
- package/build/lib/consts.js.map +0 -1
- package/build/lib/step-helpers.d.ts +0 -10
- package/build/lib/step-helpers.d.ts.map +0 -1
- package/build/lib/step-helpers.js +0 -16
- package/build/lib/step-helpers.js.map +0 -1
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
import { z } from
|
|
2
|
-
import { OK, Origin } from
|
|
3
|
-
import { AStepper } from
|
|
4
|
-
import { actionOK, actionNotOK, actionOKWithProducts, getStepTerm } from
|
|
5
|
-
import { FlowRunner } from
|
|
6
|
-
import { FeatureVariables, OBSCURED_VALUE } from
|
|
7
|
-
import { sanitizeObjectSecrets } from
|
|
8
|
-
import { DOMAIN_STATEMENT, DOMAIN_STRING, normalizeDomainKey, createEnumDomainDefinition, registerDomains } from
|
|
9
|
-
const clearVars = (vars) => () => {
|
|
10
|
-
vars.getWorld().shared.clear();
|
|
11
|
-
return;
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { OK, Origin } from "../schema/protocol.js";
|
|
3
|
+
import { AStepper } from "../lib/astepper.js";
|
|
4
|
+
import { actionOK, actionNotOK, actionOKWithProducts, getStepTerm } from "../lib/util/index.js";
|
|
5
|
+
import { FlowRunner } from "../lib/core/flow-runner.js";
|
|
6
|
+
import { FeatureVariables, OBSCURED_VALUE } from "../lib/feature-variables.js";
|
|
7
|
+
import { sanitizeObjectSecrets } from "../lib/util/secret-utils.js";
|
|
8
|
+
import { DOMAIN_STATEMENT, DOMAIN_STRING, normalizeDomainKey, createEnumDomainDefinition, registerDomains, } from "../lib/domains.js";
|
|
9
|
+
const clearVars = (vars) => async () => {
|
|
10
|
+
await vars.getWorld().shared.getStore().clear();
|
|
12
11
|
};
|
|
13
12
|
const cycles = (variablesStepper) => ({
|
|
14
13
|
startFeature: clearVars(variablesStepper),
|
|
15
|
-
startScenario: ({ scopedVars }) => {
|
|
16
|
-
variablesStepper.getWorld().shared = new FeatureVariables(variablesStepper.getWorld(), { ...scopedVars.all() });
|
|
17
|
-
return Promise.resolve();
|
|
14
|
+
startScenario: async ({ scopedVars }) => {
|
|
15
|
+
variablesStepper.getWorld().shared = new FeatureVariables(variablesStepper.getWorld(), { ...(await scopedVars.all()) });
|
|
18
16
|
},
|
|
19
17
|
});
|
|
20
18
|
class VariablesStepper extends AStepper {
|
|
21
|
-
description =
|
|
19
|
+
description = "Set, get, and compare variables; define domains and check membership";
|
|
22
20
|
cycles = cycles(this);
|
|
23
21
|
steppers;
|
|
24
22
|
runner;
|
|
@@ -31,49 +29,49 @@ class VariablesStepper extends AStepper {
|
|
|
31
29
|
steps = {
|
|
32
30
|
defineOpenSet: {
|
|
33
31
|
gwta: `set of {domain: string} as {superdomains: ${DOMAIN_STATEMENT}}`,
|
|
34
|
-
handlesUndefined: [
|
|
35
|
-
action: ({ domain, superdomains }, featureStep) => this.registerSubdomainFromStatement(domain, superdomains, featureStep)
|
|
32
|
+
handlesUndefined: ["domain"],
|
|
33
|
+
action: ({ domain, superdomains }, featureStep) => this.registerSubdomainFromStatement(domain, superdomains, featureStep),
|
|
36
34
|
},
|
|
37
35
|
defineOrderedSet: {
|
|
38
36
|
precludes: [`${VariablesStepper.name}.defineValuesSet`, `${VariablesStepper.name}.defineSet`],
|
|
39
|
-
handlesUndefined: [
|
|
37
|
+
handlesUndefined: ["domain"],
|
|
40
38
|
gwta: `ordered set of {domain: string} is {values:${DOMAIN_STATEMENT}}`,
|
|
41
|
-
action: ({ domain, values }, featureStep) => this.registerValuesDomainFromStatement(domain, values, featureStep, { ordered: true, label:
|
|
39
|
+
action: ({ domain, values }, featureStep) => this.registerValuesDomainFromStatement(domain, values, featureStep, { ordered: true, label: "ordered set" }),
|
|
42
40
|
},
|
|
43
41
|
defineValuesSet: {
|
|
44
42
|
gwta: `set of {domain: string} is {values:${DOMAIN_STATEMENT}}`,
|
|
45
|
-
handlesUndefined: [
|
|
46
|
-
action: ({ domain, values }, featureStep) => this.registerValuesDomainFromStatement(domain, values, featureStep, { ordered: false, label:
|
|
43
|
+
handlesUndefined: ["domain"],
|
|
44
|
+
action: ({ domain, values }, featureStep) => this.registerValuesDomainFromStatement(domain, values, featureStep, { ordered: false, label: "set" }),
|
|
47
45
|
},
|
|
48
46
|
statementSetValues: {
|
|
49
|
-
|
|
50
|
-
gwta:
|
|
47
|
+
exposeMCP: false,
|
|
48
|
+
gwta: "\\[{items: string}\\]",
|
|
51
49
|
action: () => OK,
|
|
52
50
|
},
|
|
53
51
|
composeAs: {
|
|
54
|
-
gwta:
|
|
55
|
-
handlesUndefined: [
|
|
52
|
+
gwta: "compose {what} as {domain} with {template}",
|
|
53
|
+
handlesUndefined: ["what", "template"],
|
|
56
54
|
precludes: [`${VariablesStepper.name}.compose`],
|
|
57
|
-
action: ({ domain }, featureStep) => {
|
|
55
|
+
action: async ({ domain }, featureStep) => {
|
|
58
56
|
const { term } = featureStep.action.stepValuesMap.what;
|
|
59
57
|
const templateVal = featureStep.action.stepValuesMap.template;
|
|
60
58
|
if (!templateVal?.term)
|
|
61
|
-
return actionNotOK(
|
|
62
|
-
const result = this.interpolateTemplate(templateVal.term, featureStep);
|
|
59
|
+
return actionNotOK("template not provided");
|
|
60
|
+
const result = await this.interpolateTemplate(templateVal.term, featureStep);
|
|
63
61
|
if (result.error)
|
|
64
62
|
return actionNotOK(result.error);
|
|
65
63
|
return trySetVariable(this.getWorld().shared, { term: String(term), value: result.value, domain, origin: Origin.var, secret: result.secret }, provenanceFromFeatureStep(featureStep));
|
|
66
|
-
}
|
|
64
|
+
},
|
|
67
65
|
},
|
|
68
66
|
compose: {
|
|
69
|
-
gwta:
|
|
70
|
-
handlesUndefined: [
|
|
71
|
-
action: (_, featureStep) => {
|
|
67
|
+
gwta: "compose {what} with {template}",
|
|
68
|
+
handlesUndefined: ["what", "template"],
|
|
69
|
+
action: async (_, featureStep) => {
|
|
72
70
|
const { term } = featureStep.action.stepValuesMap.what;
|
|
73
71
|
const templateVal = featureStep.action.stepValuesMap.template;
|
|
74
72
|
if (!templateVal?.term)
|
|
75
|
-
return actionNotOK(
|
|
76
|
-
const result = this.interpolateTemplate(templateVal.term, featureStep);
|
|
73
|
+
return actionNotOK("template not provided");
|
|
74
|
+
const result = await this.interpolateTemplate(templateVal.term, featureStep);
|
|
77
75
|
if (result.error)
|
|
78
76
|
return actionNotOK(result.error);
|
|
79
77
|
return trySetVariable(this.getWorld().shared, { term: String(term), value: result.value, domain: DOMAIN_STRING, origin: Origin.var, secret: result.secret }, provenanceFromFeatureStep(featureStep));
|
|
@@ -81,31 +79,27 @@ class VariablesStepper extends AStepper {
|
|
|
81
79
|
},
|
|
82
80
|
setFromStatement: {
|
|
83
81
|
gwta: `set {what: string} from {statement: ${DOMAIN_STATEMENT}}`,
|
|
84
|
-
handlesUndefined: [
|
|
82
|
+
handlesUndefined: ["what"],
|
|
85
83
|
precludes: [`${VariablesStepper.name}.set`],
|
|
86
84
|
action: async ({ statement }, featureStep) => {
|
|
87
85
|
const { term } = featureStep.action.stepValuesMap.what;
|
|
88
|
-
const result = await this.runner.runSteps(statement, { intent: { mode:
|
|
89
|
-
if (result.
|
|
90
|
-
return actionNotOK(`set from statement failed: ${result.
|
|
91
|
-
|
|
92
|
-
const products = stepActionResult && 'products' in stepActionResult
|
|
93
|
-
? stepActionResult.products
|
|
94
|
-
: stepActionResult ?? {};
|
|
95
|
-
this.getWorld().shared.setJSON(String(term), products, Origin.var, featureStep);
|
|
86
|
+
const result = await this.runner.runSteps(statement, { intent: { mode: "authoritative" }, parentStep: featureStep });
|
|
87
|
+
if (!result.ok)
|
|
88
|
+
return actionNotOK(`set from statement failed: ${result.errorMessage}`);
|
|
89
|
+
await this.getWorld().shared.setJSON(String(term), result.products ?? {}, Origin.var, featureStep);
|
|
96
90
|
return actionOK();
|
|
97
91
|
},
|
|
98
92
|
},
|
|
99
93
|
increment: {
|
|
100
|
-
gwta:
|
|
101
|
-
handlesUndefined: [
|
|
102
|
-
action: (_, featureStep) => {
|
|
94
|
+
gwta: "increment {what}",
|
|
95
|
+
handlesUndefined: ["what"],
|
|
96
|
+
action: async (_, featureStep) => {
|
|
103
97
|
const { term: rawTerm } = featureStep.action.stepValuesMap.what;
|
|
104
|
-
const interpolated = this.interpolateTemplate(rawTerm, featureStep);
|
|
98
|
+
const interpolated = await this.interpolateTemplate(rawTerm, featureStep);
|
|
105
99
|
if (interpolated.error)
|
|
106
100
|
return actionNotOK(interpolated.error);
|
|
107
101
|
const term = interpolated?.value;
|
|
108
|
-
const resolved = this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep);
|
|
102
|
+
const resolved = await this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep);
|
|
109
103
|
const presentVal = resolved.value;
|
|
110
104
|
const effectiveDomain = resolved.domain;
|
|
111
105
|
if (presentVal === undefined) {
|
|
@@ -125,7 +119,7 @@ class VariablesStepper extends AStepper {
|
|
|
125
119
|
if (nextVal === presentVal) {
|
|
126
120
|
return OK;
|
|
127
121
|
}
|
|
128
|
-
this.getWorld().shared.set({ term: String(term), value: nextVal, domain: effectiveDomain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
|
|
122
|
+
await this.getWorld().shared.set({ term: String(term), value: nextVal, domain: effectiveDomain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
|
|
129
123
|
return OK;
|
|
130
124
|
}
|
|
131
125
|
// Fallback: numeric increment
|
|
@@ -134,252 +128,267 @@ class VariablesStepper extends AStepper {
|
|
|
134
128
|
return actionNotOK(`cannot increment non-numeric variable ${term} with value "${presentVal}"`);
|
|
135
129
|
}
|
|
136
130
|
const newNum = numVal + 1;
|
|
137
|
-
this.getWorld().shared.set({ term: String(term), value: String(newNum), domain: effectiveDomain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
|
|
138
|
-
this.getWorld().eventLogger.log(featureStep,
|
|
131
|
+
await this.getWorld().shared.set({ term: String(term), value: String(newNum), domain: effectiveDomain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
|
|
132
|
+
this.getWorld().eventLogger.log(featureStep, "info", `incremented ${term} to ${newNum}`, {
|
|
139
133
|
variable: term,
|
|
140
134
|
oldValue: presentVal,
|
|
141
135
|
newValue: newNum,
|
|
142
|
-
operation:
|
|
136
|
+
operation: "increment",
|
|
143
137
|
});
|
|
144
138
|
return OK;
|
|
145
|
-
}
|
|
139
|
+
},
|
|
146
140
|
},
|
|
147
141
|
showEnv: {
|
|
148
|
-
gwta:
|
|
149
|
-
|
|
142
|
+
gwta: "show env",
|
|
143
|
+
exposeMCP: false,
|
|
150
144
|
action: () => {
|
|
151
|
-
// Obscure secret environment variables (matching /password/i)
|
|
152
145
|
const envVars = this.world.options.envVariables || {};
|
|
153
146
|
const shared = this.getWorld().shared;
|
|
154
147
|
const safeEnv = sanitizeObjectSecrets(envVars, (key) => shared.isSecret(key));
|
|
155
|
-
|
|
156
|
-
return
|
|
157
|
-
}
|
|
148
|
+
const count = Object.keys(safeEnv).length;
|
|
149
|
+
return actionOKWithProducts({ _type: "Environment", _summary: `${count} environment variables`, env: safeEnv });
|
|
150
|
+
},
|
|
158
151
|
},
|
|
159
152
|
showVars: {
|
|
160
|
-
gwta:
|
|
161
|
-
action: () => {
|
|
153
|
+
gwta: "show vars",
|
|
154
|
+
action: async () => {
|
|
162
155
|
const shared = this.getWorld().shared;
|
|
163
|
-
const displayVars = Object.fromEntries(Object.entries(shared.all()).map(([key, variable]) => [key, variable.value]));
|
|
156
|
+
const displayVars = Object.fromEntries(Object.entries(await shared.all()).map(([key, variable]) => [key, variable.value]));
|
|
164
157
|
const safeVars = sanitizeObjectSecrets(displayVars, (key) => shared.isSecret(key));
|
|
165
|
-
|
|
166
|
-
return
|
|
158
|
+
const count = Object.keys(safeVars).length;
|
|
159
|
+
return actionOKWithProducts({ _type: "Variables", _summary: `${count} variables`, vars: safeVars });
|
|
167
160
|
},
|
|
168
161
|
},
|
|
169
162
|
set: {
|
|
170
|
-
gwta:
|
|
171
|
-
handlesUndefined: [
|
|
172
|
-
precludes: [
|
|
173
|
-
action: (
|
|
163
|
+
gwta: "set( empty)? {what: string} to {value: string}",
|
|
164
|
+
handlesUndefined: ["what", "value"],
|
|
165
|
+
precludes: ["Haibun.prose"],
|
|
166
|
+
action: async (_, featureStep) => {
|
|
174
167
|
const { term: rawTerm, domain, origin } = featureStep.action.stepValuesMap.what;
|
|
175
|
-
const parsedValue = this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep, undefined, {
|
|
168
|
+
const parsedValue = await this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep, undefined, {
|
|
169
|
+
secure: true,
|
|
170
|
+
});
|
|
176
171
|
if (parsedValue.value === undefined)
|
|
177
172
|
return actionNotOK(`Variable ${featureStep.action.stepValuesMap.value.term} not found`);
|
|
178
173
|
const resolved = { value: String(parsedValue.value) };
|
|
179
|
-
const interpolated = this.interpolateTemplate(rawTerm, featureStep);
|
|
174
|
+
const interpolated = await this.interpolateTemplate(rawTerm, featureStep);
|
|
180
175
|
if (interpolated.error)
|
|
181
176
|
return actionNotOK(interpolated.error);
|
|
182
177
|
const term = interpolated?.value;
|
|
183
|
-
const skip = shouldSkipEmpty(featureStep, term, this.getWorld().shared);
|
|
178
|
+
const skip = await shouldSkipEmpty(featureStep, term, this.getWorld().shared);
|
|
184
179
|
if (skip)
|
|
185
180
|
return skip;
|
|
186
181
|
// Inherit domain from existing variable if not explicitly specified
|
|
187
|
-
const existing = this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep);
|
|
188
|
-
const effectiveDomain =
|
|
182
|
+
const existing = await this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep);
|
|
183
|
+
const effectiveDomain = domain === DOMAIN_STRING && existing?.domain ? existing.domain : domain || DOMAIN_STRING;
|
|
189
184
|
const result = trySetVariable(this.getWorld().shared, { term, value: resolved.value, domain: effectiveDomain, origin, secret: interpolated.secret || parsedValue.secret }, provenanceFromFeatureStep(featureStep));
|
|
190
185
|
return result;
|
|
191
|
-
}
|
|
186
|
+
},
|
|
192
187
|
},
|
|
193
188
|
setAs: {
|
|
194
|
-
gwta:
|
|
195
|
-
handlesUndefined: [
|
|
189
|
+
gwta: "set( empty)? {what} as {domain} to {value}",
|
|
190
|
+
handlesUndefined: ["what", "domain", "value"],
|
|
196
191
|
precludes: [`${VariablesStepper.name}.set`],
|
|
197
|
-
action: ({
|
|
192
|
+
action: async ({ domain }, featureStep) => {
|
|
198
193
|
const readonly = !!featureStep.in.match(/ as read-only /);
|
|
199
194
|
const { term: rawTerm, origin } = featureStep.action.stepValuesMap.what;
|
|
200
|
-
const parsedValue = this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep, undefined, {
|
|
195
|
+
const parsedValue = await this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep, undefined, {
|
|
196
|
+
secure: true,
|
|
197
|
+
});
|
|
201
198
|
if (parsedValue.value === undefined)
|
|
202
199
|
return actionNotOK(`Variable ${featureStep.action.stepValuesMap.value.term} not found`);
|
|
203
200
|
const resolved = { value: String(parsedValue.value) };
|
|
204
|
-
const interpolated = this.interpolateTemplate(rawTerm, featureStep);
|
|
201
|
+
const interpolated = await this.interpolateTemplate(rawTerm, featureStep);
|
|
205
202
|
if (interpolated.error)
|
|
206
203
|
return actionNotOK(interpolated.error);
|
|
207
204
|
const term = interpolated.value;
|
|
208
|
-
const skip = shouldSkipEmpty(featureStep, term, this.getWorld().shared);
|
|
205
|
+
const skip = await shouldSkipEmpty(featureStep, term, this.getWorld().shared);
|
|
209
206
|
if (skip)
|
|
210
207
|
return skip;
|
|
211
208
|
// Fallback for unquoted domain names (e.g. 'as number') that resolve to undefined
|
|
212
|
-
let effectiveDomain = domain ?? getStepTerm(featureStep,
|
|
209
|
+
let effectiveDomain = domain ?? getStepTerm(featureStep, "domain");
|
|
213
210
|
if (effectiveDomain) {
|
|
214
|
-
if (effectiveDomain.startsWith(
|
|
215
|
-
effectiveDomain = effectiveDomain.replace(
|
|
211
|
+
if (effectiveDomain.startsWith("read-only ")) {
|
|
212
|
+
effectiveDomain = effectiveDomain.replace("read-only ", "");
|
|
216
213
|
}
|
|
217
214
|
if (effectiveDomain.startsWith('"') && effectiveDomain.endsWith('"')) {
|
|
218
215
|
effectiveDomain = effectiveDomain.slice(1, -1);
|
|
219
216
|
}
|
|
220
217
|
}
|
|
221
218
|
let finalValue = resolved.value;
|
|
222
|
-
if (typeof finalValue ===
|
|
219
|
+
if (typeof finalValue === "string" && finalValue.startsWith('"') && finalValue.endsWith('"')) {
|
|
223
220
|
finalValue = finalValue.slice(1, -1);
|
|
224
221
|
}
|
|
225
222
|
return trySetVariable(this.getWorld().shared, { term, value: finalValue, domain: effectiveDomain, origin, readonly, secret: interpolated.secret || parsedValue.secret }, provenanceFromFeatureStep(featureStep));
|
|
226
|
-
}
|
|
223
|
+
},
|
|
227
224
|
},
|
|
228
225
|
unset: {
|
|
229
|
-
gwta:
|
|
230
|
-
action: (
|
|
226
|
+
gwta: "unset {what: string}",
|
|
227
|
+
action: async (_, featureStep) => {
|
|
231
228
|
const { term } = featureStep.action.stepValuesMap.what;
|
|
232
|
-
this.getWorld().shared.unset(term);
|
|
233
|
-
return
|
|
234
|
-
}
|
|
229
|
+
await this.getWorld().shared.unset(term);
|
|
230
|
+
return OK;
|
|
231
|
+
},
|
|
235
232
|
},
|
|
236
233
|
setRandom: {
|
|
237
234
|
precludes: [`${VariablesStepper.name}.set`],
|
|
238
235
|
gwta: `set( empty)? {what: string} to {length: number} random characters`,
|
|
239
|
-
handlesUndefined: [
|
|
240
|
-
action: ({ length }, featureStep) => {
|
|
236
|
+
handlesUndefined: ["what"],
|
|
237
|
+
action: async ({ length }, featureStep) => {
|
|
241
238
|
const { term } = featureStep.action.stepValuesMap.what;
|
|
242
239
|
if (length < 1 || length > 100) {
|
|
243
240
|
return actionNotOK(`length ${length} must be between 1 and 100`);
|
|
244
241
|
}
|
|
245
|
-
const skip = shouldSkipEmpty(featureStep, term, this.getWorld().shared);
|
|
242
|
+
const skip = await shouldSkipEmpty(featureStep, term, this.getWorld().shared);
|
|
246
243
|
if (skip)
|
|
247
244
|
return skip;
|
|
248
|
-
let rand =
|
|
245
|
+
let rand = "";
|
|
249
246
|
while (rand.length < length) {
|
|
250
|
-
rand += Math.random()
|
|
247
|
+
rand += Math.random()
|
|
248
|
+
.toString(36)
|
|
249
|
+
.substring(2, 2 + length);
|
|
251
250
|
}
|
|
252
251
|
rand = rand.substring(0, length);
|
|
253
252
|
return trySetVariable(this.getWorld().shared, { term, value: rand, domain: DOMAIN_STRING, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
|
|
254
|
-
}
|
|
253
|
+
},
|
|
255
254
|
},
|
|
256
255
|
is: {
|
|
257
|
-
gwta:
|
|
258
|
-
handlesUndefined: [
|
|
259
|
-
action: (_, featureStep) => {
|
|
256
|
+
gwta: "variable {what} is {value}",
|
|
257
|
+
handlesUndefined: ["what", "value"],
|
|
258
|
+
action: async (_, featureStep) => {
|
|
260
259
|
const { term: rawTerm } = featureStep.action.stepValuesMap.what;
|
|
261
|
-
const interpolated = this.interpolateTemplate(rawTerm, featureStep);
|
|
260
|
+
const interpolated = await this.interpolateTemplate(rawTerm, featureStep);
|
|
262
261
|
if (interpolated.error)
|
|
263
262
|
return actionNotOK(interpolated.error);
|
|
264
263
|
const term = interpolated.value;
|
|
265
|
-
const resolved = this.getWorld().shared.resolveVariable({ term, origin: Origin.defined }, featureStep, undefined, {
|
|
264
|
+
const resolved = await this.getWorld().shared.resolveVariable({ term, origin: Origin.defined }, featureStep, undefined, {
|
|
265
|
+
secure: true,
|
|
266
|
+
});
|
|
266
267
|
if (resolved.value === undefined || (resolved.origin !== Origin.var && resolved.origin !== Origin.env)) {
|
|
267
268
|
return actionNotOK(`${term} is not set`);
|
|
268
269
|
}
|
|
269
|
-
const parsedValue = this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep, undefined, {
|
|
270
|
+
const parsedValue = await this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep, undefined, {
|
|
271
|
+
secure: true,
|
|
272
|
+
});
|
|
270
273
|
if (parsedValue.value === undefined)
|
|
271
274
|
return actionNotOK(`Variable ${featureStep.action.stepValuesMap.value.term} not found`);
|
|
272
275
|
const value = String(parsedValue.value);
|
|
273
276
|
const domainKey = normalizeDomainKey(resolved.domain);
|
|
274
|
-
const compareVal = this.getWorld().domains[domainKey].coerce({ term:
|
|
275
|
-
return JSON.stringify(resolved.value) === JSON.stringify(compareVal)
|
|
276
|
-
|
|
277
|
+
const compareVal = this.getWorld().domains[domainKey].coerce({ term: "_cmp", value, domain: domainKey, origin: Origin.quoted }, featureStep, this.steppers);
|
|
278
|
+
return JSON.stringify(resolved.value) === JSON.stringify(compareVal)
|
|
279
|
+
? OK
|
|
280
|
+
: actionNotOK(`${term} is ${JSON.stringify(resolved.value)}, not ${JSON.stringify(compareVal)}`);
|
|
281
|
+
},
|
|
277
282
|
},
|
|
278
283
|
isLessThan: {
|
|
279
|
-
gwta:
|
|
280
|
-
handlesUndefined: [
|
|
281
|
-
precludes: [
|
|
284
|
+
gwta: "variable {what} is less than {value}",
|
|
285
|
+
handlesUndefined: ["what", "value"],
|
|
286
|
+
precludes: ["VariablesStepper.is"],
|
|
282
287
|
action: ({ what, value }, featureStep) => {
|
|
283
|
-
const term = getStepTerm(featureStep,
|
|
284
|
-
return this.compareValues(featureStep, term, value,
|
|
285
|
-
}
|
|
288
|
+
const term = getStepTerm(featureStep, "what") ?? what;
|
|
289
|
+
return this.compareValues(featureStep, term, value, "<");
|
|
290
|
+
},
|
|
286
291
|
},
|
|
287
292
|
isMoreThan: {
|
|
288
|
-
gwta:
|
|
289
|
-
handlesUndefined: [
|
|
290
|
-
precludes: [
|
|
293
|
+
gwta: "variable {what} is more than {value}",
|
|
294
|
+
handlesUndefined: ["what", "value"],
|
|
295
|
+
precludes: ["VariablesStepper.is"],
|
|
291
296
|
action: ({ what, value }, featureStep) => {
|
|
292
|
-
const term = getStepTerm(featureStep,
|
|
293
|
-
return this.compareValues(featureStep, term, value,
|
|
294
|
-
}
|
|
297
|
+
const term = getStepTerm(featureStep, "what") ?? what;
|
|
298
|
+
return this.compareValues(featureStep, term, value, ">");
|
|
299
|
+
},
|
|
295
300
|
},
|
|
296
301
|
exists: {
|
|
297
|
-
gwta:
|
|
298
|
-
handlesUndefined: [
|
|
299
|
-
action: ({ what }, featureStep) => {
|
|
300
|
-
const term = (getStepTerm(featureStep,
|
|
301
|
-
const sharedVars = this.getWorld().shared.all();
|
|
302
|
+
gwta: "variable {what} exists",
|
|
303
|
+
handlesUndefined: ["what"],
|
|
304
|
+
action: async ({ what }, featureStep) => {
|
|
305
|
+
const term = (getStepTerm(featureStep, "what") ?? what);
|
|
306
|
+
const sharedVars = await this.getWorld().shared.all();
|
|
302
307
|
if (sharedVars[term])
|
|
303
308
|
return OK;
|
|
304
309
|
const envVars = this.getWorld().options.envVariables || {};
|
|
305
310
|
return envVars[term] !== undefined ? OK : actionNotOK(`${what} not set`);
|
|
306
|
-
}
|
|
311
|
+
},
|
|
307
312
|
},
|
|
308
313
|
showVar: {
|
|
309
|
-
gwta:
|
|
310
|
-
handlesUndefined: [
|
|
314
|
+
gwta: "show var {what}",
|
|
315
|
+
handlesUndefined: ["what"],
|
|
311
316
|
outputSchema: z.object({ term: z.string(), value: z.unknown(), domain: z.string().optional() }),
|
|
312
|
-
action: (_, featureStep) => {
|
|
313
|
-
const rawTerm = getStepTerm(featureStep,
|
|
317
|
+
action: async (_, featureStep) => {
|
|
318
|
+
const rawTerm = getStepTerm(featureStep, "what");
|
|
314
319
|
if (rawTerm === undefined)
|
|
315
|
-
return actionNotOK(
|
|
316
|
-
const interpolated = this.interpolateTemplate(rawTerm, featureStep);
|
|
320
|
+
return actionNotOK("variable not provided");
|
|
321
|
+
const interpolated = await this.interpolateTemplate(rawTerm, featureStep);
|
|
317
322
|
if (interpolated.error)
|
|
318
323
|
return actionNotOK(interpolated.error);
|
|
319
|
-
const term = interpolated.value ||
|
|
324
|
+
const term = interpolated.value || "";
|
|
320
325
|
const shared = this.getWorld().shared;
|
|
321
|
-
const stepValue = shared.resolveVariable({ term, origin: Origin.defined }, featureStep);
|
|
326
|
+
const stepValue = await shared.resolveVariable({ term, origin: Origin.defined }, featureStep);
|
|
322
327
|
const isSecret = shared.isSecret(term) || stepValue.secret === true;
|
|
323
328
|
if (stepValue.value === undefined) {
|
|
324
329
|
this.getWorld().eventLogger.info(`${term} is undefined`);
|
|
325
330
|
return actionOKWithProducts({ term, value: undefined, domain: stepValue.domain });
|
|
326
331
|
}
|
|
327
|
-
const displayValue = isSecret ?
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
+
const displayValue = isSecret ? OBSCURED_VALUE : stepValue.value;
|
|
333
|
+
const summary = `${term} = ${typeof displayValue === "object" ? JSON.stringify(displayValue) : String(displayValue)}`;
|
|
334
|
+
return actionOKWithProducts({ _type: "Variable", _summary: summary, term, value: stepValue.value, domain: stepValue.domain });
|
|
335
|
+
},
|
|
332
336
|
},
|
|
333
337
|
showDomains: {
|
|
334
|
-
gwta:
|
|
335
|
-
action: () => {
|
|
338
|
+
gwta: "show domains",
|
|
339
|
+
action: async () => {
|
|
336
340
|
const domains = this.getWorld().domains;
|
|
337
|
-
const allVars = this.getWorld().shared.all();
|
|
338
|
-
const
|
|
341
|
+
const allVars = await this.getWorld().shared.all();
|
|
342
|
+
const items = [];
|
|
343
|
+
// Collect vertexLabel→name mapping for base type edge targets
|
|
344
|
+
const labelToDomain = new Map();
|
|
345
|
+
for (const [dname, ddef] of Object.entries(domains)) {
|
|
346
|
+
const vl = ddef.topology?.vertexLabel;
|
|
347
|
+
labelToDomain.set(vl || dname, vl || dname);
|
|
348
|
+
}
|
|
339
349
|
for (const [name, def] of Object.entries(domains)) {
|
|
340
350
|
let members = 0;
|
|
341
351
|
for (const variable of Object.values(allVars)) {
|
|
342
|
-
if (variable.domain && normalizeDomainKey(variable.domain) === name)
|
|
352
|
+
if (variable.domain && normalizeDomainKey(variable.domain) === name)
|
|
343
353
|
members++;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
let type = 'schema';
|
|
347
|
-
if (def.values) {
|
|
348
|
-
type = def.values;
|
|
349
354
|
}
|
|
350
|
-
|
|
351
|
-
|
|
355
|
+
const description = def.values || def.description || "schema";
|
|
356
|
+
const topology = def.topology;
|
|
357
|
+
const vertexLabel = topology?.vertexLabel;
|
|
358
|
+
const _edges = [];
|
|
359
|
+
// Edges from topology (vertex→vertex relationships like Email→Contact)
|
|
360
|
+
const topologyEdges = topology?.edges;
|
|
361
|
+
if (topologyEdges) {
|
|
362
|
+
for (const [edgeName, edge] of Object.entries(topologyEdges)) {
|
|
363
|
+
if (edge.range && edge.range !== vertexLabel)
|
|
364
|
+
_edges.push({ type: edgeName, targetId: edge.range });
|
|
365
|
+
}
|
|
352
366
|
}
|
|
353
|
-
|
|
354
|
-
type,
|
|
355
|
-
members,
|
|
356
|
-
ordered: !!def.comparator
|
|
357
|
-
};
|
|
367
|
+
items.push({ name, description, members, ...(vertexLabel ? { vertexLabel } : {}), ...(_edges.length ? { _edges } : {}) });
|
|
358
368
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
369
|
+
return actionOKWithProducts({ _type: "Domain", _summary: `${items.length} domains`, items });
|
|
370
|
+
},
|
|
362
371
|
},
|
|
363
372
|
showDomain: {
|
|
364
|
-
gwta:
|
|
365
|
-
handlesUndefined: [
|
|
366
|
-
action: (_, featureStep) => {
|
|
367
|
-
const name = getStepTerm(featureStep,
|
|
373
|
+
gwta: "show domain {name}",
|
|
374
|
+
handlesUndefined: ["name"],
|
|
375
|
+
action: async (_, featureStep) => {
|
|
376
|
+
const name = getStepTerm(featureStep, "name");
|
|
368
377
|
const domain = this.getWorld().domains[name];
|
|
369
378
|
if (!domain) {
|
|
370
379
|
return actionNotOK(`Domain "${name}" not found`);
|
|
371
380
|
}
|
|
372
381
|
const shared = this.getWorld().shared;
|
|
373
|
-
const allVars = shared.all();
|
|
382
|
+
const allVars = await shared.all();
|
|
374
383
|
const members = {};
|
|
375
384
|
for (const [key, variable] of Object.entries(allVars)) {
|
|
376
385
|
if (variable.domain && normalizeDomainKey(variable.domain) === name) {
|
|
377
386
|
members[key] = shared.isSecret(key) ? OBSCURED_VALUE : variable.value;
|
|
378
387
|
}
|
|
379
388
|
}
|
|
380
|
-
|
|
381
|
-
return
|
|
382
|
-
}
|
|
389
|
+
const memberCount = Object.keys(members).length;
|
|
390
|
+
return actionOKWithProducts({ _type: "Domain", _summary: `${name}: ${memberCount} members`, domain: name, ...domain, members });
|
|
391
|
+
},
|
|
383
392
|
},
|
|
384
393
|
// Membership check: value is in domain (enum or member values)
|
|
385
394
|
// Handles quoted ("value"), braced ({var}), or bare (value) forms
|
|
@@ -387,23 +396,22 @@ class VariablesStepper extends AStepper {
|
|
|
387
396
|
isIn: {
|
|
388
397
|
match: /^(.+) is in ([a-zA-Z][a-zA-Z0-9 ]*)$/,
|
|
389
398
|
fallback: true,
|
|
390
|
-
action: (_, featureStep) => {
|
|
399
|
+
action: async (_, featureStep) => {
|
|
391
400
|
const matchResult = featureStep.in.match(/^(.+) is in ([a-zA-Z][a-zA-Z0-9 ]*)$/);
|
|
392
401
|
if (!matchResult) {
|
|
393
402
|
return actionNotOK('Invalid "is in" syntax');
|
|
394
403
|
}
|
|
395
404
|
let valueTerm = matchResult[1].trim();
|
|
396
405
|
// Strip quotes if present
|
|
397
|
-
if ((valueTerm.startsWith('"') && valueTerm.endsWith('"')) ||
|
|
398
|
-
(valueTerm.startsWith('`') && valueTerm.endsWith('`'))) {
|
|
406
|
+
if ((valueTerm.startsWith('"') && valueTerm.endsWith('"')) || (valueTerm.startsWith("`") && valueTerm.endsWith("`"))) {
|
|
399
407
|
valueTerm = valueTerm.slice(1, -1);
|
|
400
408
|
}
|
|
401
409
|
// Strip braces if present and resolve variable
|
|
402
|
-
if (valueTerm.startsWith(
|
|
410
|
+
if (valueTerm.startsWith("{") && valueTerm.endsWith("}")) {
|
|
403
411
|
valueTerm = valueTerm.slice(1, -1);
|
|
404
412
|
}
|
|
405
413
|
// Try to resolve as variable, fall back to literal
|
|
406
|
-
const resolvedValue = this.getWorld().shared.get(valueTerm, true);
|
|
414
|
+
const resolvedValue = await this.getWorld().shared.get(valueTerm, true);
|
|
407
415
|
const actualValue = resolvedValue !== undefined ? String(resolvedValue) : valueTerm;
|
|
408
416
|
const domainName = matchResult[2].trim();
|
|
409
417
|
const domainKey = normalizeDomainKey(domainName);
|
|
@@ -416,14 +424,12 @@ class VariablesStepper extends AStepper {
|
|
|
416
424
|
return OK;
|
|
417
425
|
}
|
|
418
426
|
// Check member values
|
|
419
|
-
const allVars = this.getWorld().shared.all();
|
|
427
|
+
const allVars = await this.getWorld().shared.all();
|
|
420
428
|
const memberValues = Object.values(allVars)
|
|
421
|
-
.filter(v => v.domain && normalizeDomainKey(v.domain) === domainKey)
|
|
422
|
-
.map(v => String(v.value));
|
|
423
|
-
return memberValues.includes(actualValue)
|
|
424
|
-
|
|
425
|
-
: actionNotOK(`"${actualValue}" is not in ${domainName}`);
|
|
426
|
-
}
|
|
429
|
+
.filter((v) => v.domain && normalizeDomainKey(v.domain) === domainKey)
|
|
430
|
+
.map((v) => String(v.value));
|
|
431
|
+
return memberValues.includes(actualValue) ? OK : actionNotOK(`"${actualValue}" is not in ${domainName}`);
|
|
432
|
+
},
|
|
427
433
|
},
|
|
428
434
|
// Pattern matching: glob-style patterns for human-readable matching
|
|
429
435
|
// Usage: matches {host} with "*.wikipedia.org"
|
|
@@ -432,40 +438,40 @@ class VariablesStepper extends AStepper {
|
|
|
432
438
|
// Supports * as wildcard (matches any characters)
|
|
433
439
|
// Variables in pattern are interpolated: "{counter URI}*" resolves to actual value
|
|
434
440
|
matches: {
|
|
435
|
-
gwta:
|
|
436
|
-
action: ({ value, pattern }, featureStep) => {
|
|
441
|
+
gwta: "matches {value} with {pattern}",
|
|
442
|
+
action: async ({ value, pattern }, featureStep) => {
|
|
437
443
|
// Interpolate value (e.g. "{request}/url" -> "req-1/url")
|
|
438
|
-
const interpolatedValue = this.interpolateTemplate(value, featureStep);
|
|
444
|
+
const interpolatedValue = await this.interpolateTemplate(value, featureStep);
|
|
439
445
|
if (interpolatedValue.error)
|
|
440
446
|
return actionNotOK(interpolatedValue.error);
|
|
441
447
|
const term = interpolatedValue.value;
|
|
442
448
|
// Resolve value as a variable (e.g., "WebPlaywright/currentURI" -> actual URL)
|
|
443
|
-
const resolvedValue = this.getWorld().shared.get(term, true);
|
|
449
|
+
const resolvedValue = await this.getWorld().shared.get(term, true);
|
|
444
450
|
const actualValue = resolvedValue !== undefined ? String(resolvedValue) : String(term);
|
|
445
451
|
// Interpolate variables in pattern (e.g., "{counter URI}*" -> "http://localhost:8123/*")
|
|
446
|
-
const interpolated = this.interpolateTemplate(pattern, featureStep);
|
|
452
|
+
const interpolated = await this.interpolateTemplate(pattern, featureStep);
|
|
447
453
|
if (interpolated.error)
|
|
448
454
|
return actionNotOK(interpolated.error);
|
|
449
455
|
const actualPattern = interpolated.value;
|
|
450
456
|
// Convert glob pattern to regex
|
|
451
457
|
// Escape regex special chars except *, then replace * with .*
|
|
452
|
-
const escaped = actualPattern.replace(/[.+?^${}()|[\]\\]/g,
|
|
453
|
-
const regexPattern = escaped.replace(/\*/g,
|
|
458
|
+
const escaped = actualPattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
459
|
+
const regexPattern = escaped.replace(/\*/g, ".*");
|
|
454
460
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
455
461
|
const isMatch = regex.test(actualValue);
|
|
456
|
-
return isMatch
|
|
457
|
-
|
|
458
|
-
: actionNotOK(`"${actualValue}" does not match pattern "${actualPattern}"`);
|
|
459
|
-
}
|
|
462
|
+
return isMatch ? OK : actionNotOK(`"${actualValue}" does not match pattern "${actualPattern}"`);
|
|
463
|
+
},
|
|
460
464
|
},
|
|
461
465
|
};
|
|
462
466
|
typedSteps = this.steps;
|
|
463
|
-
compareValues(featureStep, rawTerm, value, operator) {
|
|
464
|
-
const interpolated = this.interpolateTemplate(rawTerm, featureStep);
|
|
467
|
+
async compareValues(featureStep, rawTerm, value, operator) {
|
|
468
|
+
const interpolated = await this.interpolateTemplate(rawTerm, featureStep);
|
|
465
469
|
if (interpolated.error)
|
|
466
470
|
return actionNotOK(interpolated.error);
|
|
467
471
|
const term = interpolated.value;
|
|
468
|
-
const stored = this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep, this.steppers, {
|
|
472
|
+
const stored = await this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep, this.steppers, {
|
|
473
|
+
secure: true,
|
|
474
|
+
});
|
|
469
475
|
if (!stored) {
|
|
470
476
|
return actionNotOK(`${term} is not set`);
|
|
471
477
|
}
|
|
@@ -477,20 +483,20 @@ class VariablesStepper extends AStepper {
|
|
|
477
483
|
const left = domainEntry.coerce({ ...stored, domain: domainKey }, featureStep, this.steppers);
|
|
478
484
|
let rightValue = value;
|
|
479
485
|
if (rightValue === undefined) {
|
|
480
|
-
const parsed = this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep);
|
|
486
|
+
const parsed = await this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep);
|
|
481
487
|
if (parsed.value === undefined)
|
|
482
488
|
return actionNotOK(`Variable ${featureStep.action.stepValuesMap.value.term} not found`);
|
|
483
489
|
rightValue = String(parsed.value);
|
|
484
490
|
}
|
|
485
|
-
if (typeof rightValue ===
|
|
491
|
+
if (typeof rightValue === "string" && rightValue.startsWith('"') && rightValue.endsWith('"')) {
|
|
486
492
|
rightValue = rightValue.slice(1, -1);
|
|
487
493
|
}
|
|
488
494
|
const right = domainEntry.coerce({ term: `${term}__comparison`, value: rightValue, domain: domainKey, origin: Origin.quoted }, featureStep, this.steppers);
|
|
489
495
|
const comparison = compareDomainValues(domainEntry, left, right, stored.domain);
|
|
490
|
-
if (operator ===
|
|
496
|
+
if (operator === ">") {
|
|
491
497
|
return comparison > 0 ? OK : actionNotOK(`${term} is ${JSON.stringify(left)}, not ${JSON.stringify(right)}`);
|
|
492
498
|
}
|
|
493
|
-
if (operator ===
|
|
499
|
+
if (operator === "<") {
|
|
494
500
|
return comparison < 0 ? OK : actionNotOK(`${term} is ${JSON.stringify(left)}, not ${JSON.stringify(right)}`);
|
|
495
501
|
}
|
|
496
502
|
return actionNotOK(`Unsupported operator: ${operator}`);
|
|
@@ -499,7 +505,7 @@ class VariablesStepper extends AStepper {
|
|
|
499
505
|
* Interpolates a template string by replacing {varName} placeholders with variable values.
|
|
500
506
|
* Returns the interpolated string or an error if a variable is not found.
|
|
501
507
|
*/
|
|
502
|
-
interpolateTemplate(template, featureStep) {
|
|
508
|
+
async interpolateTemplate(template, featureStep) {
|
|
503
509
|
const placeholderRegex = /\{([^}]+)\}/g;
|
|
504
510
|
let result = template;
|
|
505
511
|
let match;
|
|
@@ -510,7 +516,9 @@ class VariablesStepper extends AStepper {
|
|
|
510
516
|
if (this.getWorld().shared.isSecret(varName)) {
|
|
511
517
|
secret = true;
|
|
512
518
|
}
|
|
513
|
-
const resolved = this.getWorld().shared.resolveVariable({ term: varName, origin: Origin.defined }, featureStep, undefined, {
|
|
519
|
+
const resolved = await this.getWorld().shared.resolveVariable({ term: varName, origin: Origin.defined }, featureStep, undefined, {
|
|
520
|
+
secure: true,
|
|
521
|
+
});
|
|
514
522
|
if (resolved.value === undefined) {
|
|
515
523
|
return { error: `Variable ${varName} not found` };
|
|
516
524
|
}
|
|
@@ -520,15 +528,15 @@ class VariablesStepper extends AStepper {
|
|
|
520
528
|
}
|
|
521
529
|
registerSubdomainFromStatement(domain, superdomains, featureStep) {
|
|
522
530
|
try {
|
|
523
|
-
const fallback = getStepTerm(featureStep,
|
|
531
|
+
const fallback = getStepTerm(featureStep, "superdomains") ?? featureStep.in;
|
|
524
532
|
const superdomainNames = extractValuesFromFragments(superdomains, fallback);
|
|
525
533
|
if (!superdomainNames.length) {
|
|
526
|
-
throw new Error(
|
|
534
|
+
throw new Error("Superdomain set must specify at least one superdomain");
|
|
527
535
|
}
|
|
528
536
|
const uniqueNames = Array.from(new Set(superdomainNames));
|
|
529
|
-
const effectiveDomain = domain ?? getStepTerm(featureStep,
|
|
537
|
+
const effectiveDomain = domain ?? getStepTerm(featureStep, "domain");
|
|
530
538
|
if (!effectiveDomain)
|
|
531
|
-
return actionNotOK(
|
|
539
|
+
return actionNotOK("Domain name must be provided");
|
|
532
540
|
const domainKey = normalizeDomainKey(effectiveDomain);
|
|
533
541
|
if (this.getWorld().domains[domainKey]) {
|
|
534
542
|
return actionNotOK(`Domain "${domainKey}" already exists`);
|
|
@@ -543,7 +551,7 @@ class VariablesStepper extends AStepper {
|
|
|
543
551
|
});
|
|
544
552
|
const enumSources = superdomainDefs.filter((entry) => Array.isArray(entry.values) && entry.values.length);
|
|
545
553
|
const uniqueValues = Array.from(new Set(enumSources.flatMap((entry) => entry.values)));
|
|
546
|
-
const description = `Values inherited from ${uniqueNames.join(
|
|
554
|
+
const description = `Values inherited from ${uniqueNames.join(", ")}`;
|
|
547
555
|
if (enumSources.length === superdomainDefs.length && uniqueValues.length) {
|
|
548
556
|
const definition = createEnumDomainDefinition({ name: domainKey, values: uniqueValues, description });
|
|
549
557
|
registerDomains(this.getWorld(), [[definition]]);
|
|
@@ -551,7 +559,7 @@ class VariablesStepper extends AStepper {
|
|
|
551
559
|
}
|
|
552
560
|
const schemaList = superdomainDefs.map((entry) => entry.schema);
|
|
553
561
|
if (!schemaList.length) {
|
|
554
|
-
throw new Error(
|
|
562
|
+
throw new Error("Superdomains did not expose any schema to derive from");
|
|
555
563
|
}
|
|
556
564
|
let mergedSchema = schemaList[0];
|
|
557
565
|
for (let i = 1; i < schemaList.length; i++) {
|
|
@@ -572,15 +580,20 @@ class VariablesStepper extends AStepper {
|
|
|
572
580
|
}
|
|
573
581
|
registerValuesDomainFromStatement(domain, valueFragments, featureStep, options) {
|
|
574
582
|
try {
|
|
575
|
-
const values = extractValuesFromFragments(valueFragments, getStepTerm(featureStep,
|
|
576
|
-
const effectiveDomain = domain ?? getStepTerm(featureStep,
|
|
583
|
+
const values = extractValuesFromFragments(valueFragments, getStepTerm(featureStep, "values") ?? featureStep.in);
|
|
584
|
+
const effectiveDomain = domain ?? getStepTerm(featureStep, "domain");
|
|
577
585
|
if (!effectiveDomain)
|
|
578
|
-
return actionNotOK(
|
|
586
|
+
return actionNotOK("Domain name must be provided");
|
|
579
587
|
const domainKey = normalizeDomainKey(effectiveDomain);
|
|
580
588
|
if (this.getWorld().domains[domainKey]) {
|
|
581
589
|
return actionNotOK(`Domain "${domainKey}" already exists`);
|
|
582
590
|
}
|
|
583
|
-
const definition = createEnumDomainDefinition({
|
|
591
|
+
const definition = createEnumDomainDefinition({
|
|
592
|
+
name: domainKey,
|
|
593
|
+
values,
|
|
594
|
+
description: options?.description,
|
|
595
|
+
ordered: options?.ordered,
|
|
596
|
+
});
|
|
584
597
|
registerDomains(this.getWorld(), [[definition]]);
|
|
585
598
|
return OK;
|
|
586
599
|
}
|
|
@@ -597,53 +610,58 @@ export function provenanceFromFeatureStep(featureStep) {
|
|
|
597
610
|
return {
|
|
598
611
|
in: featureStep.in,
|
|
599
612
|
seq: featureStep.seqPath,
|
|
600
|
-
when: `${featureStep.action.stepperName}.steps.${featureStep.action.actionName}
|
|
613
|
+
when: `${featureStep.action.stepperName}.steps.${featureStep.action.actionName}`,
|
|
601
614
|
};
|
|
602
615
|
}
|
|
603
616
|
const QUOTED_STRING = /"([^"]+)"/g;
|
|
604
617
|
const extractValuesFromFragments = (valueFragments, fallback) => {
|
|
605
618
|
if (valueFragments?.length) {
|
|
606
|
-
const innerChunks = valueFragments
|
|
607
|
-
|
|
619
|
+
const innerChunks = valueFragments
|
|
620
|
+
.map((fragment) => {
|
|
621
|
+
const raw = fragment.in ?? fragment.action?.stepValuesMap?.items?.term ?? "";
|
|
608
622
|
const trimmed = raw.trim();
|
|
609
|
-
if (trimmed.startsWith(
|
|
623
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
610
624
|
return trimmed.slice(1, -1).trim();
|
|
611
625
|
}
|
|
612
626
|
return trimmed;
|
|
613
|
-
})
|
|
614
|
-
|
|
627
|
+
})
|
|
628
|
+
.filter(Boolean);
|
|
629
|
+
const inner = innerChunks.join(" ").trim();
|
|
615
630
|
if (!inner) {
|
|
616
|
-
throw new Error(
|
|
631
|
+
throw new Error("Set values cannot be empty");
|
|
617
632
|
}
|
|
618
633
|
return parseQuotedOrWordList(inner);
|
|
619
634
|
}
|
|
620
635
|
if (fallback) {
|
|
621
636
|
return parseBracketedValues(fallback);
|
|
622
637
|
}
|
|
623
|
-
throw new Error(
|
|
638
|
+
throw new Error("Set statement missing values");
|
|
624
639
|
};
|
|
625
640
|
const parseBracketedValues = (raw) => {
|
|
626
641
|
const trimmed = raw.trim();
|
|
627
|
-
const start = trimmed.indexOf(
|
|
628
|
-
const end = trimmed.lastIndexOf(
|
|
642
|
+
const start = trimmed.indexOf("[");
|
|
643
|
+
const end = trimmed.lastIndexOf("]");
|
|
629
644
|
if (start === -1 || end === -1 || end <= start) {
|
|
630
|
-
throw new Error(
|
|
645
|
+
throw new Error("Set values must include [ ]");
|
|
631
646
|
}
|
|
632
647
|
const inner = trimmed.substring(start + 1, end).trim();
|
|
633
648
|
return parseQuotedOrWordList(inner);
|
|
634
649
|
};
|
|
635
650
|
const parseQuotedOrWordList = (value) => {
|
|
636
|
-
const quoted = [...value.matchAll(QUOTED_STRING)].map(match => match[1].trim()).filter(Boolean);
|
|
651
|
+
const quoted = [...value.matchAll(QUOTED_STRING)].map((match) => match[1].trim()).filter(Boolean);
|
|
637
652
|
if (quoted.length) {
|
|
638
653
|
return quoted;
|
|
639
654
|
}
|
|
640
|
-
return value
|
|
655
|
+
return value
|
|
656
|
+
.split(/[\s,]+/)
|
|
657
|
+
.map((token) => token.trim())
|
|
658
|
+
.filter(Boolean);
|
|
641
659
|
};
|
|
642
660
|
const compareDomainValues = (domain, left, right, domainName) => {
|
|
643
661
|
if (domain.comparator) {
|
|
644
662
|
return domain.comparator(left, right);
|
|
645
663
|
}
|
|
646
|
-
if (typeof left ===
|
|
664
|
+
if (typeof left === "number" && typeof right === "number") {
|
|
647
665
|
return left - right;
|
|
648
666
|
}
|
|
649
667
|
if (left instanceof Date && right instanceof Date) {
|
|
@@ -653,13 +671,23 @@ const compareDomainValues = (domain, left, right, domainName) => {
|
|
|
653
671
|
};
|
|
654
672
|
// ======== Helpers ========
|
|
655
673
|
// Returns OK if "set empty" and variable exists
|
|
656
|
-
function shouldSkipEmpty(featureStep, term, shared) {
|
|
657
|
-
|
|
674
|
+
async function shouldSkipEmpty(featureStep, term, shared) {
|
|
675
|
+
if (!featureStep.in.includes("set empty "))
|
|
676
|
+
return undefined;
|
|
677
|
+
const resolved = await shared.resolveVariable({ term, origin: Origin.var }, featureStep, undefined, { secure: true });
|
|
678
|
+
return resolved.value !== undefined ? OK : undefined;
|
|
658
679
|
}
|
|
659
680
|
// Wraps shared.set in try/catch
|
|
660
|
-
function trySetVariable(shared, opts, provenance) {
|
|
681
|
+
async function trySetVariable(shared, opts, provenance) {
|
|
661
682
|
try {
|
|
662
|
-
shared.set({
|
|
683
|
+
await shared.set({
|
|
684
|
+
term: opts.term,
|
|
685
|
+
value: opts.value,
|
|
686
|
+
domain: opts.domain,
|
|
687
|
+
origin: opts.origin,
|
|
688
|
+
readonly: opts.readonly,
|
|
689
|
+
secret: opts.secret,
|
|
690
|
+
}, provenance);
|
|
663
691
|
return OK;
|
|
664
692
|
}
|
|
665
693
|
catch (e) {
|