@haibun/core 3.0.3 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/build/currentVersion.d.ts +1 -1
  2. package/build/currentVersion.js +1 -2
  3. package/build/lib/EventLogger.d.ts +22 -0
  4. package/build/lib/EventLogger.d.ts.map +1 -0
  5. package/build/lib/EventLogger.js +95 -0
  6. package/build/lib/EventLogger.js.map +1 -0
  7. package/build/lib/Logger.d.ts.map +1 -1
  8. package/build/lib/Logger.js +2 -1
  9. package/build/lib/Logger.js.map +1 -1
  10. package/build/lib/astepper.d.ts +11 -1
  11. package/build/lib/astepper.d.ts.map +1 -1
  12. package/build/lib/astepper.js +8 -0
  13. package/build/lib/astepper.js.map +1 -1
  14. package/build/lib/core/flow-runner.d.ts +25 -0
  15. package/build/lib/core/flow-runner.d.ts.map +1 -0
  16. package/build/lib/core/flow-runner.js +128 -0
  17. package/build/lib/core/flow-runner.js.map +1 -0
  18. package/build/lib/core/protocol.d.ts +58 -0
  19. package/build/lib/core/protocol.d.ts.map +1 -0
  20. package/build/lib/core/protocol.js +18 -0
  21. package/build/lib/core/protocol.js.map +1 -0
  22. package/build/lib/core-domains.d.ts +2 -16
  23. package/build/lib/core-domains.d.ts.map +1 -1
  24. package/build/lib/core-domains.js +46 -27
  25. package/build/lib/core-domains.js.map +1 -1
  26. package/build/lib/defs.d.ts +42 -11
  27. package/build/lib/defs.d.ts.map +1 -1
  28. package/build/lib/defs.js +6 -1
  29. package/build/lib/defs.js.map +1 -1
  30. package/build/lib/domain-types.d.ts +12 -1
  31. package/build/lib/domain-types.d.ts.map +1 -1
  32. package/build/lib/domain-types.js +63 -3
  33. package/build/lib/domain-types.js.map +1 -1
  34. package/build/lib/event-bridge.d.ts +28 -0
  35. package/build/lib/event-bridge.d.ts.map +1 -0
  36. package/build/lib/event-bridge.js +114 -0
  37. package/build/lib/event-bridge.js.map +1 -0
  38. package/build/lib/feature-variables.d.ts +14 -0
  39. package/build/lib/feature-variables.d.ts.map +1 -1
  40. package/build/lib/feature-variables.js +128 -6
  41. package/build/lib/feature-variables.js.map +1 -1
  42. package/build/lib/interfaces/logger.d.ts +19 -3
  43. package/build/lib/interfaces/logger.d.ts.map +1 -1
  44. package/build/lib/interfaces/logger.js +11 -1
  45. package/build/lib/interfaces/logger.js.map +1 -1
  46. package/build/lib/namedVars.d.ts.map +1 -1
  47. package/build/lib/namedVars.js +18 -10
  48. package/build/lib/namedVars.js.map +1 -1
  49. package/build/lib/populateActionArgs.d.ts +1 -1
  50. package/build/lib/populateActionArgs.d.ts.map +1 -1
  51. package/build/lib/populateActionArgs.js +11 -49
  52. package/build/lib/populateActionArgs.js.map +1 -1
  53. package/build/lib/test/TestSteps.d.ts +1 -0
  54. package/build/lib/test/TestSteps.d.ts.map +1 -1
  55. package/build/lib/test/TestStepsWithOptions.d.ts +1 -0
  56. package/build/lib/test/TestStepsWithOptions.d.ts.map +1 -1
  57. package/build/lib/test/lib.d.ts.map +1 -1
  58. package/build/lib/test/lib.js +2 -0
  59. package/build/lib/test/lib.js.map +1 -1
  60. package/build/lib/util/actualURI.js +1 -1
  61. package/build/lib/util/actualURI.js.map +1 -1
  62. package/build/lib/util/index.d.ts +11 -2
  63. package/build/lib/util/index.d.ts.map +1 -1
  64. package/build/lib/util/index.js +46 -2
  65. package/build/lib/util/index.js.map +1 -1
  66. package/build/lib/util/variables.d.ts +9 -0
  67. package/build/lib/util/variables.d.ts.map +1 -0
  68. package/build/lib/util/variables.js +40 -0
  69. package/build/lib/util/variables.js.map +1 -0
  70. package/build/lib/util/workspace-lib.d.ts.map +1 -1
  71. package/build/lib/util/workspace-lib.js +30 -3
  72. package/build/lib/util/workspace-lib.js.map +1 -1
  73. package/build/monitor/browser-stubs.d.ts +12 -0
  74. package/build/monitor/browser-stubs.d.ts.map +1 -0
  75. package/build/monitor/browser-stubs.js +20 -0
  76. package/build/monitor/browser-stubs.js.map +1 -0
  77. package/build/monitor/constants.d.ts +9 -0
  78. package/build/monitor/constants.d.ts.map +1 -0
  79. package/build/monitor/constants.js +9 -0
  80. package/build/monitor/constants.js.map +1 -0
  81. package/build/monitor/event-view.d.ts +40 -0
  82. package/build/monitor/event-view.d.ts.map +1 -0
  83. package/build/monitor/event-view.js +104 -0
  84. package/build/monitor/event-view.js.map +1 -0
  85. package/build/monitor/filters.d.ts +17 -0
  86. package/build/monitor/filters.d.ts.map +1 -0
  87. package/build/monitor/filters.js +32 -0
  88. package/build/monitor/filters.js.map +1 -0
  89. package/build/monitor/formatters.d.ts +27 -0
  90. package/build/monitor/formatters.d.ts.map +1 -0
  91. package/build/monitor/formatters.js +89 -0
  92. package/build/monitor/formatters.js.map +1 -0
  93. package/build/monitor/index.d.ts +11 -0
  94. package/build/monitor/index.d.ts.map +1 -0
  95. package/build/monitor/index.js +15 -0
  96. package/build/monitor/index.js.map +1 -0
  97. package/build/monitor/jit-serialization.d.ts +9 -0
  98. package/build/monitor/jit-serialization.d.ts.map +1 -0
  99. package/build/monitor/jit-serialization.js +73 -0
  100. package/build/monitor/jit-serialization.js.map +1 -0
  101. package/build/monitor/monitor-types.d.ts +119 -0
  102. package/build/monitor/monitor-types.d.ts.map +1 -0
  103. package/build/monitor/monitor-types.js +43 -0
  104. package/build/monitor/monitor-types.js.map +1 -0
  105. package/build/monitor/speculative-tracker.d.ts +20 -0
  106. package/build/monitor/speculative-tracker.d.ts.map +1 -0
  107. package/build/monitor/speculative-tracker.js +38 -0
  108. package/build/monitor/speculative-tracker.js.map +1 -0
  109. package/build/monitor/state.d.ts +31 -0
  110. package/build/monitor/state.d.ts.map +1 -0
  111. package/build/monitor/state.js +110 -0
  112. package/build/monitor/state.js.map +1 -0
  113. package/build/monitor/timer.d.ts +11 -0
  114. package/build/monitor/timer.d.ts.map +1 -0
  115. package/build/monitor/timer.js +13 -0
  116. package/build/monitor/timer.js.map +1 -0
  117. package/build/monitor/tree-builder.d.ts +25 -0
  118. package/build/monitor/tree-builder.d.ts.map +1 -0
  119. package/build/monitor/tree-builder.js +36 -0
  120. package/build/monitor/tree-builder.js.map +1 -0
  121. package/build/phases/Executor.d.ts.map +1 -1
  122. package/build/phases/Executor.js +102 -43
  123. package/build/phases/Executor.js.map +1 -1
  124. package/build/phases/Resolver.d.ts +2 -1
  125. package/build/phases/Resolver.d.ts.map +1 -1
  126. package/build/phases/Resolver.js +64 -1
  127. package/build/phases/Resolver.js.map +1 -1
  128. package/build/runner.d.ts.map +1 -1
  129. package/build/runner.js +5 -0
  130. package/build/runner.js.map +1 -1
  131. package/build/schema/events.d.ts +174 -0
  132. package/build/schema/events.d.ts.map +1 -0
  133. package/build/schema/events.js +55 -0
  134. package/build/schema/events.js.map +1 -0
  135. package/build/steps/activities-stepper.d.ts +55 -20
  136. package/build/steps/activities-stepper.d.ts.map +1 -1
  137. package/build/steps/activities-stepper.js +342 -207
  138. package/build/steps/activities-stepper.js.map +1 -1
  139. package/build/steps/conformance.d.ts +1 -0
  140. package/build/steps/conformance.d.ts.map +1 -1
  141. package/build/steps/console-monitor-stepper.d.ts +44 -0
  142. package/build/steps/console-monitor-stepper.d.ts.map +1 -0
  143. package/build/steps/console-monitor-stepper.js +106 -0
  144. package/build/steps/console-monitor-stepper.js.map +1 -0
  145. package/build/steps/debugger-stepper.d.ts +5 -3
  146. package/build/steps/debugger-stepper.d.ts.map +1 -1
  147. package/build/steps/debugger-stepper.js +35 -11
  148. package/build/steps/debugger-stepper.js.map +1 -1
  149. package/build/steps/haibun.d.ts +11 -18
  150. package/build/steps/haibun.d.ts.map +1 -1
  151. package/build/steps/haibun.js +51 -55
  152. package/build/steps/haibun.js.map +1 -1
  153. package/build/steps/lib/tts.d.ts.map +1 -1
  154. package/build/steps/lib/tts.js +2 -1
  155. package/build/steps/lib/tts.js.map +1 -1
  156. package/build/steps/logic-stepper.d.ts +42 -0
  157. package/build/steps/logic-stepper.d.ts.map +1 -0
  158. package/build/steps/logic-stepper.js +143 -0
  159. package/build/steps/logic-stepper.js.map +1 -0
  160. package/build/steps/narrator.d.ts.map +1 -1
  161. package/build/steps/narrator.js +1 -1
  162. package/build/steps/narrator.js.map +1 -1
  163. package/build/steps/parse.d.ts +1 -0
  164. package/build/steps/parse.d.ts.map +1 -1
  165. package/build/steps/variables-stepper.d.ts +11 -71
  166. package/build/steps/variables-stepper.d.ts.map +1 -1
  167. package/build/steps/variables-stepper.js +534 -84
  168. package/build/steps/variables-stepper.js.map +1 -1
  169. package/package.json +16 -3
  170. package/build/applyEffectFeatures.d.ts +0 -4
  171. package/build/applyEffectFeatures.d.ts.map +0 -1
  172. package/build/applyEffectFeatures.js +0 -31
  173. package/build/applyEffectFeatures.js.map +0 -1
  174. package/build/jsprolog/converter.d.ts +0 -9
  175. package/build/jsprolog/converter.d.ts.map +0 -1
  176. package/build/jsprolog/converter.js +0 -42
  177. package/build/jsprolog/converter.js.map +0 -1
  178. package/build/jsprolog/stepper-utils.d.ts +0 -8
  179. package/build/jsprolog/stepper-utils.d.ts.map +0 -1
  180. package/build/jsprolog/stepper-utils.js +0 -8
  181. package/build/jsprolog/stepper-utils.js.map +0 -1
  182. package/build/jsprolog/test.jsprolog.d.ts +0 -4
  183. package/build/jsprolog/test.jsprolog.d.ts.map +0 -1
  184. package/build/jsprolog/test.jsprolog.js +0 -19
  185. package/build/jsprolog/test.jsprolog.js.map +0 -1
  186. package/build/jsprolog/test.kireji.d.ts +0 -4
  187. package/build/jsprolog/test.kireji.d.ts.map +0 -1
  188. package/build/jsprolog/test.kireji.js +0 -19
  189. package/build/jsprolog/test.kireji.js.map +0 -1
  190. package/build/jsprolog/withAction.d.ts +0 -32
  191. package/build/jsprolog/withAction.d.ts.map +0 -1
  192. package/build/jsprolog/withAction.js +0 -65
  193. package/build/jsprolog/withAction.js.map +0 -1
  194. package/build/kireji/test.kireji.d.ts +0 -4
  195. package/build/kireji/test.kireji.d.ts.map +0 -1
  196. package/build/kireji/test.kireji.js +0 -19
  197. package/build/kireji/test.kireji.js.map +0 -1
  198. package/build/lib/errors.d.ts +0 -13
  199. package/build/lib/errors.d.ts.map +0 -1
  200. package/build/lib/errors.js +0 -18
  201. package/build/lib/errors.js.map +0 -1
  202. package/build/lib/util/featureStep-executor.d.ts +0 -7
  203. package/build/lib/util/featureStep-executor.d.ts.map +0 -1
  204. package/build/lib/util/featureStep-executor.js +0 -63
  205. package/build/lib/util/featureStep-executor.js.map +0 -1
  206. package/build/steps/conditions-stepper.d.ts +0 -27
  207. package/build/steps/conditions-stepper.d.ts.map +0 -1
  208. package/build/steps/conditions-stepper.js +0 -99
  209. package/build/steps/conditions-stepper.js.map +0 -1
@@ -1,8 +1,9 @@
1
+ import { z } from 'zod';
1
2
  import { OK, Origin } from '../lib/defs.js';
2
3
  import { AStepper } from '../lib/astepper.js';
3
- import { actionNotOK, actionOK } from '../lib/util/index.js';
4
+ import { actionOK, actionNotOK, getStepTerm, isLiteralValue } from '../lib/util/index.js';
4
5
  import { FeatureVariables } from '../lib/feature-variables.js';
5
- import { DOMAIN_STRING } from '../lib/domain-types.js';
6
+ import { DOMAIN_STATEMENT, DOMAIN_STRING, normalizeDomainKey, createEnumDomainDefinition, registerDomains } from '../lib/domain-types.js';
6
7
  import { EExecutionMessageType } from '../lib/interfaces/logger.js';
7
8
  const clearVars = (vars) => () => {
8
9
  vars.getWorld().shared.clear();
@@ -10,8 +11,8 @@ const clearVars = (vars) => () => {
10
11
  };
11
12
  const cycles = (variablesStepper) => ({
12
13
  startFeature: clearVars(variablesStepper),
13
- startScenario: ({ featureVars }) => {
14
- variablesStepper.getWorld().shared = new FeatureVariables(variablesStepper.getWorld(), { ...featureVars.all() });
14
+ startScenario: ({ scopedVars }) => {
15
+ variablesStepper.getWorld().shared = new FeatureVariables(variablesStepper.getWorld(), { ...scopedVars.all() });
15
16
  return Promise.resolve();
16
17
  },
17
18
  });
@@ -23,65 +24,107 @@ class VariablesStepper extends AStepper {
23
24
  this.steppers = steppers;
24
25
  await Promise.resolve();
25
26
  }
26
- checkIsSet(what) {
27
- return this.getVarValue(what) !== undefined;
28
- }
29
- // FIXME provide explicit mapping to more carefully handle env, etc.
30
- getVarValue(what) {
31
- const envVal = this.getWorld().options.envVariables[what];
32
- if (envVal !== undefined) {
33
- return envVal;
34
- }
35
- return this.getWorld().shared.get(what);
36
- }
37
- isSet(what) {
38
- if (this.checkIsSet(what)) {
39
- return OK;
40
- }
41
- return actionNotOK(`${what} not set`);
42
- }
43
27
  steps = {
44
- combineAs: {
45
- gwta: 'combine {p1} and {p2} as {domain} to {what}',
46
- precludes: [`${VariablesStepper.name}.combine`],
47
- action: ({ p1, p2, domain }, featureStep) => {
28
+ defineOpenSet: {
29
+ gwta: `set of {domain: string} as {superdomains: ${DOMAIN_STATEMENT}}`,
30
+ handlesUndefined: ['domain'],
31
+ action: ({ domain, superdomains }, featureStep) => this.registerSubdomainFromStatement(domain, superdomains, featureStep)
32
+ },
33
+ defineOrderedSet: {
34
+ precludes: [`${VariablesStepper.name}.defineValuesSet`, `${VariablesStepper.name}.defineSet`],
35
+ handlesUndefined: ['domain'],
36
+ gwta: `ordered set of {domain: string} is {values:${DOMAIN_STATEMENT}}`,
37
+ action: ({ domain, values }, featureStep) => this.registerValuesDomainFromStatement(domain, values, featureStep, { ordered: true, label: 'ordered set' })
38
+ },
39
+ defineValuesSet: {
40
+ gwta: `set of {domain: string} is {values:${DOMAIN_STATEMENT}}`,
41
+ handlesUndefined: ['domain'],
42
+ action: ({ domain, values }, featureStep) => this.registerValuesDomainFromStatement(domain, values, featureStep, { ordered: false, label: 'set' })
43
+ },
44
+ statementSetValues: {
45
+ expose: false,
46
+ gwta: '\\[{items: string}\\]',
47
+ action: () => OK,
48
+ },
49
+ composeAs: {
50
+ gwta: 'compose {what} as {domain} with {template}',
51
+ handlesUndefined: ['what', 'template'],
52
+ precludes: [`${VariablesStepper.name}.compose`],
53
+ action: ({ domain }, featureStep) => {
48
54
  const { term } = featureStep.action.stepValuesMap.what;
49
- this.getWorld().shared.set({ term: String(term), value: `${p1}${p2}`, domain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
50
- return Promise.resolve(OK);
55
+ const templateVal = featureStep.action.stepValuesMap.template;
56
+ if (!templateVal?.term)
57
+ return actionNotOK('template not provided');
58
+ const result = this.interpolateTemplate(templateVal.term, featureStep);
59
+ if (result.error)
60
+ return actionNotOK(result.error);
61
+ return trySetVariable(this.getWorld().shared, { term: String(term), value: result.value, domain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
51
62
  }
52
63
  },
53
- combine: {
54
- gwta: 'combine {p1} and {p2} to {what}',
55
- action: ({ p1, p2 }, featureStep) => {
64
+ compose: {
65
+ gwta: 'compose {what} with {template}',
66
+ handlesUndefined: ['what', 'template'],
67
+ action: (_, featureStep) => {
56
68
  const { term } = featureStep.action.stepValuesMap.what;
57
- this.getWorld().shared.set({ term: String(term), value: `${p1}${p2}`, domain: DOMAIN_STRING, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
58
- return Promise.resolve(OK);
69
+ const templateVal = featureStep.action.stepValuesMap.template;
70
+ if (!templateVal?.term)
71
+ return actionNotOK('template not provided');
72
+ const result = this.interpolateTemplate(templateVal.term, featureStep);
73
+ if (result.error)
74
+ return actionNotOK(result.error);
75
+ return trySetVariable(this.getWorld().shared, { term: String(term), value: result.value, domain: DOMAIN_STRING, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
59
76
  }
60
77
  },
61
78
  increment: {
62
79
  gwta: 'increment {what}',
63
- action: ({ what }, featureStep) => {
64
- void what; // used for type checking
65
- const { term, domain } = featureStep.action.stepValuesMap.what;
66
- const presentVal = this.getVarValue(term);
67
- let newVal;
80
+ handlesUndefined: ['what'],
81
+ action: (_, featureStep) => {
82
+ const { term: rawTerm, domain } = featureStep.action.stepValuesMap.what;
83
+ const interpolated = this.interpolateTemplate(rawTerm, featureStep);
84
+ if (interpolated.error)
85
+ return actionNotOK(interpolated.error);
86
+ const term = interpolated.value;
87
+ const resolved = this.getWorld().shared.resolveVariable({ term, origin: Origin.var, domain }, featureStep);
88
+ const presentVal = resolved.value;
89
+ const effectiveDomain = resolved.domain;
68
90
  if (presentVal === undefined) {
69
- newVal = 0;
91
+ return actionNotOK(`${term} not set`);
70
92
  }
71
- else {
72
- const numVal = Number(presentVal);
73
- if (isNaN(numVal)) {
74
- return actionNotOK(`cannot increment non-numeric variable ${term} with value "${presentVal}"`);
93
+ // If domain is an ordered enum, advance to the next enum value
94
+ const domainKey = effectiveDomain ? normalizeDomainKey(effectiveDomain) : undefined;
95
+ const registered = domainKey ? this.getWorld().domains[domainKey] : undefined;
96
+ if (registered?.comparator && Array.isArray(registered.values) && registered.values.length) {
97
+ const enumValues = registered.values;
98
+ const idx = enumValues.indexOf(String(presentVal));
99
+ if (idx === -1) {
100
+ return actionNotOK(`${term} has value "${presentVal}" which is not in domain values`);
101
+ }
102
+ const nextIdx = Math.min(enumValues.length - 1, idx + 1);
103
+ const nextVal = enumValues[nextIdx];
104
+ if (nextVal === presentVal) {
105
+ return OK;
75
106
  }
76
- newVal = numVal + 1;
107
+ this.getWorld().shared.set({ term: String(term), value: nextVal, domain: effectiveDomain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
108
+ return OK;
109
+ }
110
+ // Fallback: numeric increment
111
+ const numVal = Number(presentVal);
112
+ if (isNaN(numVal)) {
113
+ return actionNotOK(`cannot increment non-numeric variable ${term} with value "${presentVal}"`);
77
114
  }
78
- this.getWorld().shared.set({ term: String(term), value: newVal, domain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
79
- const messageContext = {
115
+ const newNum = numVal + 1;
116
+ this.getWorld().shared.set({ term: String(term), value: String(newNum), domain: effectiveDomain, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
117
+ this.getWorld().logger.info(`incremented ${term} to ${newNum}`, {
80
118
  incident: EExecutionMessageType.ACTION,
81
- incidentDetails: { json: { incremented: { [term]: newVal } } },
82
- };
83
- this.getWorld().logger.info(`incremented ${term} to ${newVal}`, messageContext);
84
- return Promise.resolve(OK);
119
+ incidentDetails: { json: { incremented: { [term]: newNum } } },
120
+ });
121
+ this.getWorld().eventLogger.log(featureStep, 'info', `incremented ${term} to ${newNum}`, {
122
+ variable: term,
123
+ oldValue: presentVal,
124
+ newValue: newNum,
125
+ operation: 'increment'
126
+ });
127
+ return OK;
85
128
  }
86
129
  },
87
130
  showEnv: {
@@ -96,91 +139,417 @@ class VariablesStepper extends AStepper {
96
139
  showVars: {
97
140
  gwta: 'show vars',
98
141
  action: () => {
99
- console.info('vars', this.getWorld().shared.all());
100
- return Promise.resolve(actionOK({ artifact: { artifactType: 'json', json: { vars: this.getWorld().shared.all() } } }));
142
+ const displayVars = Object.fromEntries(Object.entries(this.getWorld().shared.all()).map(([k, v]) => [k, v.value]));
143
+ console.info('vars', displayVars);
144
+ return actionOK({ artifact: { artifactType: 'json', json: { vars: displayVars } } });
101
145
  },
102
146
  },
103
147
  set: {
104
148
  gwta: 'set( empty)? {what: string} to {value: string}',
149
+ handlesUndefined: ['what', 'value'],
105
150
  precludes: ['Haibun.prose'],
106
151
  action: (args, featureStep) => {
107
- const emptyOnly = !!featureStep.in.match(/set empty /);
108
- const { term, domain, origin } = featureStep.action.stepValuesMap.what;
109
- if (emptyOnly && this.getWorld().shared.get(term) !== undefined) {
110
- return OK;
152
+ const { term: rawTerm, domain, origin } = featureStep.action.stepValuesMap.what;
153
+ const parsedValue = this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep);
154
+ if (parsedValue.value === undefined)
155
+ return actionNotOK(`Variable ${featureStep.action.stepValuesMap.value.term} not found`);
156
+ const resolved = { value: String(parsedValue.value) };
157
+ const interpolated = this.interpolateTemplate(rawTerm, featureStep);
158
+ if (interpolated.error)
159
+ return actionNotOK(interpolated.error);
160
+ const term = interpolated.value;
161
+ const skip = shouldSkipEmpty(featureStep, term, this.getWorld().shared);
162
+ if (skip)
163
+ return skip;
164
+ // Inherit domain from existing variable if not explicitly specified
165
+ const existing = this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep);
166
+ const effectiveDomain = (domain === DOMAIN_STRING && existing?.domain) ? existing.domain : (domain || DOMAIN_STRING);
167
+ const result = trySetVariable(this.getWorld().shared, { term, value: resolved.value, domain: effectiveDomain, origin }, provenanceFromFeatureStep(featureStep));
168
+ if (result.ok) {
169
+ this.getWorld().eventLogger.log(featureStep, 'info', `set ${term} to ${resolved.value}`, {
170
+ variable: term,
171
+ newValue: resolved.value,
172
+ domain: effectiveDomain,
173
+ operation: 'set'
174
+ });
111
175
  }
112
- this.getWorld().shared.set({ term: String(term), value: args.value, domain, origin }, provenanceFromFeatureStep(featureStep));
113
- return Promise.resolve(OK);
176
+ return result;
114
177
  }
115
178
  },
116
179
  setAs: {
117
- gwta: 'set( empty)? {what: string} as {domain: string} to {value: string}',
180
+ gwta: 'set( empty)? {what} as {domain} to {value}',
181
+ handlesUndefined: ['what', 'domain', 'value'],
118
182
  precludes: [`${VariablesStepper.name}.set`],
119
183
  action: ({ value, domain }, featureStep) => {
120
- const emptyOnly = !!featureStep.in.match(/set empty /);
121
- const { term, origin } = featureStep.action.stepValuesMap.what;
122
- if (emptyOnly && this.getWorld().shared.get(term) !== undefined) {
123
- return OK;
184
+ const readonly = !!featureStep.in.match(/ as read-only /);
185
+ const { term: rawTerm, origin } = featureStep.action.stepValuesMap.what;
186
+ const parsedValue = this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep);
187
+ if (parsedValue.value === undefined)
188
+ return actionNotOK(`Variable ${featureStep.action.stepValuesMap.value.term} not found`);
189
+ const resolved = { value: String(parsedValue.value) };
190
+ const interpolated = this.interpolateTemplate(rawTerm, featureStep);
191
+ if (interpolated.error)
192
+ return actionNotOK(interpolated.error);
193
+ const term = interpolated.value;
194
+ const skip = shouldSkipEmpty(featureStep, term, this.getWorld().shared);
195
+ if (skip)
196
+ return skip;
197
+ // Fallback for unquoted domain names (e.g. 'as number') that resolve to undefined
198
+ let effectiveDomain = domain ?? getStepTerm(featureStep, 'domain');
199
+ if (effectiveDomain) {
200
+ if (effectiveDomain.startsWith('read-only ')) {
201
+ effectiveDomain = effectiveDomain.replace('read-only ', '');
202
+ }
203
+ if (effectiveDomain.startsWith('"') && effectiveDomain.endsWith('"')) {
204
+ effectiveDomain = effectiveDomain.slice(1, -1);
205
+ }
206
+ }
207
+ let finalValue = resolved.value;
208
+ if (typeof finalValue === 'string' && finalValue.startsWith('"') && finalValue.endsWith('"')) {
209
+ finalValue = finalValue.slice(1, -1);
124
210
  }
125
- this.getWorld().shared.set({ term: String(term), value: value, domain, origin }, provenanceFromFeatureStep(featureStep));
211
+ return trySetVariable(this.getWorld().shared, { term, value: finalValue, domain: effectiveDomain, origin, readonly }, provenanceFromFeatureStep(featureStep));
212
+ }
213
+ },
214
+ unset: {
215
+ gwta: 'unset {what: string}',
216
+ action: ({ what }, featureStep) => {
217
+ const { term } = featureStep.action.stepValuesMap.what;
218
+ this.getWorld().shared.unset(term);
126
219
  return Promise.resolve(OK);
127
220
  }
128
221
  },
129
222
  setRandom: {
130
223
  precludes: [`${VariablesStepper.name}.set`],
131
224
  gwta: `set( empty)? {what: string} to {length: number} random characters`,
225
+ handlesUndefined: ['what'],
132
226
  action: ({ length }, featureStep) => {
133
- const emptyOnly = !!featureStep.in.match(/set empty /);
134
227
  const { term } = featureStep.action.stepValuesMap.what;
135
228
  if (length < 1 || length > 100) {
136
229
  return actionNotOK(`length ${length} must be between 1 and 100`);
137
230
  }
138
- if (emptyOnly && this.getWorld().shared.get(term) !== undefined) {
139
- return OK;
140
- }
231
+ const skip = shouldSkipEmpty(featureStep, term, this.getWorld().shared);
232
+ if (skip)
233
+ return skip;
141
234
  let rand = '';
142
235
  while (rand.length < length) {
143
236
  rand += Math.random().toString(36).substring(2, 2 + length);
144
237
  }
145
238
  rand = rand.substring(0, length);
146
- this.getWorld().shared.set({ term: String(term), value: rand, domain: DOMAIN_STRING, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
147
- return Promise.resolve(OK);
239
+ return trySetVariable(this.getWorld().shared, { term, value: rand, domain: DOMAIN_STRING, origin: Origin.var }, provenanceFromFeatureStep(featureStep));
148
240
  }
149
241
  },
150
242
  is: {
151
243
  gwta: 'variable {what} is {value}',
244
+ handlesUndefined: ['what', 'value'],
245
+ action: (args, featureStep) => {
246
+ const { term: rawTerm } = featureStep.action.stepValuesMap.what;
247
+ const interpolated = this.interpolateTemplate(rawTerm, featureStep);
248
+ if (interpolated.error)
249
+ return actionNotOK(interpolated.error);
250
+ const term = interpolated.value;
251
+ const resolved = this.getWorld().shared.resolveVariable({ term, origin: Origin.defined }, featureStep);
252
+ if (resolved.value === undefined) {
253
+ return actionNotOK(`${term} is not set`);
254
+ }
255
+ const storedVal = resolved.value;
256
+ const parsedValue = this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep);
257
+ if (parsedValue.value === undefined)
258
+ return actionNotOK(`Variable ${featureStep.action.stepValuesMap.value.term} not found`);
259
+ const value = String(parsedValue.value);
260
+ const domainKey = normalizeDomainKey(resolved.domain);
261
+ const compareVal = this.getWorld().domains[domainKey].coerce({ term: '_cmp', value, domain: domainKey, origin: Origin.quoted }, featureStep, this.steppers);
262
+ return JSON.stringify(storedVal) === JSON.stringify(compareVal) ? OK : actionNotOK(`${term} is ${JSON.stringify(storedVal)}, not ${JSON.stringify(compareVal)}`);
263
+ }
264
+ },
265
+ isLessThan: {
266
+ gwta: 'variable {what} is less than {value}',
267
+ handlesUndefined: ['what', 'value'],
268
+ precludes: ['VariablesStepper.is'],
152
269
  action: ({ what, value }, featureStep) => {
153
- void what; // used for type checking
154
- const { term, domain } = featureStep.action.stepValuesMap.what;
155
- const val = this.getVarValue(term);
156
- const asDomain = this.getWorld().domains[domain].coerce({ domain, value, term, origin: 'quoted' });
157
- return JSON.stringify(val) === JSON.stringify(asDomain) ? OK : actionNotOK(`${term} is ${JSON.stringify(val)}, not ${JSON.stringify(value)}`);
270
+ const term = getStepTerm(featureStep, 'what') ?? what;
271
+ return this.compareValues(featureStep, term, value, '<');
158
272
  }
159
273
  },
160
- isSet: {
274
+ isMoreThan: {
275
+ gwta: 'variable {what} is more than {value}',
276
+ handlesUndefined: ['what', 'value'],
161
277
  precludes: ['VariablesStepper.is'],
162
- gwta: 'variable {what: string} is set',
278
+ action: ({ what, value }, featureStep) => {
279
+ const term = getStepTerm(featureStep, 'what') ?? what;
280
+ return this.compareValues(featureStep, term, value, '>');
281
+ }
282
+ },
283
+ exists: {
284
+ gwta: 'variable {what} exists',
285
+ handlesUndefined: ['what'],
163
286
  action: ({ what }, featureStep) => {
164
- // Use term from stepValuesMap when available (normal execution), fall back to what for kireji
165
- const term = featureStep?.action?.stepValuesMap?.what?.term ?? what;
166
- return this.isSet(term);
287
+ const term = (getStepTerm(featureStep, 'what') ?? what);
288
+ const resolved = this.getWorld().shared.resolveVariable({ term, origin: Origin.defined }, featureStep);
289
+ return resolved && (resolved.origin === Origin.var || resolved.origin === Origin.env) ? OK : actionNotOK(`${what} not set`);
167
290
  }
168
291
  },
169
292
  showVar: {
170
293
  gwta: 'show var {what}',
171
- action: (args, featureStep) => {
172
- const { term } = featureStep.action.stepValuesMap.what;
173
- const stepValue = this.getWorld().shared.all()[term];
174
- if (!stepValue) {
294
+ handlesUndefined: ['what'],
295
+ action: (_, featureStep) => {
296
+ const rawTerm = getStepTerm(featureStep, 'what');
297
+ if (rawTerm === undefined)
298
+ return actionNotOK('variable not provided');
299
+ const interpolated = this.interpolateTemplate(rawTerm, featureStep);
300
+ if (interpolated.error)
301
+ return actionNotOK(interpolated.error);
302
+ const term = interpolated.value;
303
+ const stepValue = this.getWorld().shared.resolveVariable({ term, origin: Origin.defined }, featureStep);
304
+ if (stepValue.value === undefined) {
175
305
  this.getWorld().logger.info(`is undefined`);
176
306
  }
177
307
  else {
178
- this.getWorld().logger.info(`is ${JSON.stringify({ ...stepValue, provenance: stepValue.provenance.map((p, i) => ({ [i]: { in: p.in, seq: p.seq.join(','), when: p.when } })) }, null, 2)}`);
308
+ const provenance = featureStep.action.stepValuesMap.what.provenance?.map((p, i) => ({ [i]: { in: p.in, seq: p.seq.join(','), when: p.when } }));
309
+ this.getWorld().logger.info(`is ${JSON.stringify({ ...stepValue, provenance }, null, 2)}`);
179
310
  }
180
311
  return actionOK({ artifact: { artifactType: 'json', json: { json: stepValue } } });
181
312
  }
182
313
  },
314
+ showDomains: {
315
+ gwta: 'show domains',
316
+ action: () => {
317
+ const domains = this.getWorld().domains;
318
+ const allVars = this.getWorld().shared.all();
319
+ const summary = {};
320
+ for (const [name, def] of Object.entries(domains)) {
321
+ // Count variables in this domain
322
+ let members = 0;
323
+ for (const variable of Object.values(allVars)) {
324
+ if (variable.domain && normalizeDomainKey(variable.domain) === name) {
325
+ members++;
326
+ }
327
+ }
328
+ // Determine type from schema or values
329
+ let type = 'schema';
330
+ if (def.values) {
331
+ type = def.values;
332
+ }
333
+ else if (def.description) {
334
+ type = def.description;
335
+ }
336
+ summary[name] = {
337
+ type,
338
+ members,
339
+ ordered: !!def.comparator
340
+ };
341
+ }
342
+ this.getWorld().logger.info(`Domains: ${JSON.stringify(summary, null, 2)}`);
343
+ return OK;
344
+ }
345
+ },
346
+ showDomain: {
347
+ gwta: 'show domain {name}',
348
+ handlesUndefined: ['name'],
349
+ action: (_, featureStep) => {
350
+ const name = getStepTerm(featureStep, 'name');
351
+ const domain = this.getWorld().domains[name];
352
+ if (!domain) {
353
+ return actionNotOK(`Domain "${name}" not found`);
354
+ }
355
+ const allVars = this.getWorld().shared.all();
356
+ const members = {};
357
+ for (const [key, variable] of Object.entries(allVars)) {
358
+ if (variable.domain && normalizeDomainKey(variable.domain) === name) {
359
+ members[key] = variable.value;
360
+ }
361
+ }
362
+ this.getWorld().logger.info(`Domain "${name}": ${JSON.stringify({ ...domain, members }, null, 2)}`);
363
+ return OK;
364
+ }
365
+ },
366
+ // Membership check: value is in domain (enum or member values)
367
+ // Handles quoted ("value"), braced ({var}), or bare (value) forms
368
+ // fallback: true lets quantifiers take precedence when both match
369
+ isIn: {
370
+ match: /^(.+) is in ([a-zA-Z][a-zA-Z0-9 ]*)$/,
371
+ fallback: true,
372
+ action: (_, featureStep) => {
373
+ const matchResult = featureStep.in.match(/^(.+) is in ([a-zA-Z][a-zA-Z0-9 ]*)$/);
374
+ if (!matchResult) {
375
+ return actionNotOK('Invalid "is in" syntax');
376
+ }
377
+ let valueTerm = matchResult[1].trim();
378
+ // Strip quotes if present
379
+ if ((valueTerm.startsWith('"') && valueTerm.endsWith('"')) ||
380
+ (valueTerm.startsWith('`') && valueTerm.endsWith('`'))) {
381
+ valueTerm = valueTerm.slice(1, -1);
382
+ }
383
+ // Strip braces if present and resolve variable
384
+ if (valueTerm.startsWith('{') && valueTerm.endsWith('}')) {
385
+ valueTerm = valueTerm.slice(1, -1);
386
+ }
387
+ // Try to resolve as variable, fall back to literal
388
+ const resolved = this.getWorld().shared.resolveVariable({ term: valueTerm, origin: Origin.defined });
389
+ const actualValue = resolved?.value !== undefined ? String(resolved.value) : valueTerm;
390
+ const domainName = matchResult[2].trim();
391
+ const domainKey = normalizeDomainKey(domainName);
392
+ const domainDef = this.getWorld().domains[domainKey];
393
+ if (!domainDef) {
394
+ return actionNotOK(`Domain "${domainName}" is not defined`);
395
+ }
396
+ // Check enum values first
397
+ if (Array.isArray(domainDef.values) && domainDef.values.includes(actualValue)) {
398
+ return OK;
399
+ }
400
+ // Check member values
401
+ const allVars = this.getWorld().shared.all();
402
+ const memberValues = Object.values(allVars)
403
+ .filter(v => v.domain && normalizeDomainKey(v.domain) === domainKey)
404
+ .map(v => String(v.value));
405
+ return memberValues.includes(actualValue)
406
+ ? OK
407
+ : actionNotOK(`"${actualValue}" is not in ${domainName}`);
408
+ }
409
+ },
410
+ // Starts with: predicate for prefix checking
411
+ // Starts with literal 'that' for unambiguous parsing in compositions
412
+ // Usage: that {page} starts with {prefix}
413
+ startsWith: {
414
+ gwta: 'that {value} starts with {prefix}',
415
+ action: ({ value, prefix }) => {
416
+ const actualValue = String(value);
417
+ const actualPrefix = String(prefix);
418
+ return actualValue.startsWith(actualPrefix)
419
+ ? OK
420
+ : actionNotOK(`"${actualValue}" does not start with "${actualPrefix}"`);
421
+ }
422
+ },
183
423
  };
424
+ compareValues(featureStep, rawTerm, value, operator) {
425
+ const interpolated = this.interpolateTemplate(rawTerm, featureStep);
426
+ if (interpolated.error)
427
+ return actionNotOK(interpolated.error);
428
+ const term = interpolated.value;
429
+ const stored = this.getWorld().shared.resolveVariable({ term, origin: Origin.var }, featureStep);
430
+ if (!stored) {
431
+ return actionNotOK(`${term} is not set`);
432
+ }
433
+ const domainKey = normalizeDomainKey(stored.domain);
434
+ const domainEntry = this.getWorld().domains[domainKey];
435
+ if (!domainEntry) {
436
+ throw new Error(`No domain coercer found for domain "${domainKey}"`);
437
+ }
438
+ const left = domainEntry.coerce({ ...stored, domain: domainKey }, featureStep, this.steppers);
439
+ let rightValue = value;
440
+ if (rightValue === undefined) {
441
+ const parsed = this.getWorld().shared.resolveVariable(featureStep.action.stepValuesMap.value, featureStep);
442
+ if (parsed.value === undefined)
443
+ return actionNotOK(`Variable ${featureStep.action.stepValuesMap.value.term} not found`);
444
+ rightValue = String(parsed.value);
445
+ }
446
+ if (typeof rightValue === 'string' && rightValue.startsWith('"') && rightValue.endsWith('"')) {
447
+ rightValue = rightValue.slice(1, -1);
448
+ }
449
+ const right = domainEntry.coerce({ term: `${term}__comparison`, value: rightValue, domain: domainKey, origin: Origin.quoted }, featureStep, this.steppers);
450
+ const comparison = compareDomainValues(domainEntry, left, right, stored.domain);
451
+ if (operator === '>') {
452
+ return comparison > 0 ? OK : actionNotOK(`${term} is ${JSON.stringify(left)}, not ${JSON.stringify(right)}`);
453
+ }
454
+ if (operator === '<') {
455
+ return comparison < 0 ? OK : actionNotOK(`${term} is ${JSON.stringify(left)}, not ${JSON.stringify(right)}`);
456
+ }
457
+ return actionNotOK(`Unsupported operator: ${operator}`);
458
+ }
459
+ /**
460
+ * Interpolates a template string by replacing {varName} placeholders with variable values.
461
+ * Returns the interpolated string or an error if a variable is not found.
462
+ */
463
+ interpolateTemplate(template, featureStep) {
464
+ const placeholderRegex = /\{([^}]+)\}/g;
465
+ let result = template;
466
+ let match;
467
+ while ((match = placeholderRegex.exec(template)) !== null) {
468
+ const varName = match[1];
469
+ // Origin.defined checks runtimeArgs -> env -> literal fallback?
470
+ // We want strict. If resolves to literal, that's fine if user quoted it?
471
+ // But {unknown} resolves to undefined if not found?
472
+ // In feature-variables.ts, resolveVariable defaults to input.term if isLiteralValue.
473
+ // {unknown} is NOT literal value (braces).
474
+ // So resolveVariable returns undefined.
475
+ const resolved = this.getWorld().shared.resolveVariable({ term: varName, origin: Origin.defined }, featureStep);
476
+ if (resolved.value === undefined) {
477
+ return { error: `Variable ${varName} not found` };
478
+ }
479
+ result = result.replace(match[0], String(resolved.value));
480
+ }
481
+ return { value: result };
482
+ }
483
+ registerSubdomainFromStatement(domain, superdomains, featureStep) {
484
+ try {
485
+ const fallback = getStepTerm(featureStep, 'superdomains') ?? featureStep.in;
486
+ const superdomainNames = extractValuesFromFragments(superdomains, fallback);
487
+ if (!superdomainNames.length) {
488
+ throw new Error('Superdomain set must specify at least one superdomain');
489
+ }
490
+ const uniqueNames = Array.from(new Set(superdomainNames));
491
+ const effectiveDomain = domain ?? getStepTerm(featureStep, 'domain');
492
+ if (!effectiveDomain)
493
+ return actionNotOK('Domain name must be provided');
494
+ const domainKey = normalizeDomainKey(effectiveDomain);
495
+ if (this.getWorld().domains[domainKey]) {
496
+ return actionNotOK(`Domain "${domainKey}" already exists`);
497
+ }
498
+ const superdomainDefs = uniqueNames.map((name) => {
499
+ const normalized = normalizeDomainKey(name);
500
+ const registered = this.getWorld().domains[normalized];
501
+ if (!registered) {
502
+ throw new Error(`Superdomain "${name}" not registered`);
503
+ }
504
+ return registered;
505
+ });
506
+ const enumSources = superdomainDefs.filter((entry) => Array.isArray(entry.values) && entry.values.length);
507
+ const uniqueValues = Array.from(new Set(enumSources.flatMap((entry) => entry.values)));
508
+ const description = `Values inherited from ${uniqueNames.join(', ')}`;
509
+ if (enumSources.length === superdomainDefs.length && uniqueValues.length) {
510
+ const definition = createEnumDomainDefinition({ name: domainKey, values: uniqueValues, description });
511
+ registerDomains(this.getWorld(), [[definition]]);
512
+ return OK;
513
+ }
514
+ const schemaList = superdomainDefs.map((entry) => entry.schema);
515
+ if (!schemaList.length) {
516
+ throw new Error('Superdomains did not expose any schema to derive from');
517
+ }
518
+ let mergedSchema = schemaList[0];
519
+ for (let i = 1; i < schemaList.length; i++) {
520
+ mergedSchema = z.union([mergedSchema, schemaList[i]]);
521
+ }
522
+ const definition = {
523
+ selectors: [domainKey],
524
+ schema: mergedSchema,
525
+ coerce: (proto) => mergedSchema.parse(proto.value),
526
+ description,
527
+ };
528
+ registerDomains(this.getWorld(), [[definition]]);
529
+ return OK;
530
+ }
531
+ catch (error) {
532
+ return actionNotOK(error instanceof Error ? error.message : String(error));
533
+ }
534
+ }
535
+ registerValuesDomainFromStatement(domain, valueFragments, featureStep, options) {
536
+ try {
537
+ const values = extractValuesFromFragments(valueFragments, getStepTerm(featureStep, 'values') ?? featureStep.in);
538
+ const effectiveDomain = domain ?? getStepTerm(featureStep, 'domain');
539
+ if (!effectiveDomain)
540
+ return actionNotOK('Domain name must be provided');
541
+ const domainKey = normalizeDomainKey(effectiveDomain);
542
+ if (this.getWorld().domains[domainKey]) {
543
+ return actionNotOK(`Domain "${domainKey}" already exists`);
544
+ }
545
+ const definition = createEnumDomainDefinition({ name: domainKey, values, description: options?.description, ordered: options?.ordered });
546
+ registerDomains(this.getWorld(), [[definition]]);
547
+ return OK;
548
+ }
549
+ catch (error) {
550
+ return actionNotOK(error instanceof Error ? error.message : String(error));
551
+ }
552
+ }
184
553
  }
185
554
  export default VariablesStepper;
186
555
  export const didNotOverwrite = (what, present, value) => ({
@@ -193,4 +562,85 @@ export function provenanceFromFeatureStep(featureStep) {
193
562
  when: `${featureStep.action.stepperName}.steps.${featureStep.action.actionName}`
194
563
  };
195
564
  }
565
+ const QUOTED_STRING = /"([^"]+)"/g;
566
+ const extractValuesFromFragments = (valueFragments, fallback) => {
567
+ if (valueFragments?.length) {
568
+ const innerChunks = valueFragments.map(fragment => {
569
+ const raw = fragment.in ?? fragment.action?.stepValuesMap?.items?.term ?? '';
570
+ const trimmed = raw.trim();
571
+ if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
572
+ return trimmed.slice(1, -1).trim();
573
+ }
574
+ return trimmed;
575
+ }).filter(Boolean);
576
+ const inner = innerChunks.join(' ').trim();
577
+ if (!inner) {
578
+ throw new Error('Set values cannot be empty');
579
+ }
580
+ return parseQuotedOrWordList(inner);
581
+ }
582
+ if (fallback) {
583
+ return parseBracketedValues(fallback);
584
+ }
585
+ throw new Error('Set statement missing values');
586
+ };
587
+ const parseBracketedValues = (raw) => {
588
+ const trimmed = raw.trim();
589
+ const start = trimmed.indexOf('[');
590
+ const end = trimmed.lastIndexOf(']');
591
+ if (start === -1 || end === -1 || end <= start) {
592
+ throw new Error('Set values must include [ ]');
593
+ }
594
+ const inner = trimmed.substring(start + 1, end).trim();
595
+ return parseQuotedOrWordList(inner);
596
+ };
597
+ const parseQuotedOrWordList = (value) => {
598
+ const quoted = [...value.matchAll(QUOTED_STRING)].map(match => match[1].trim()).filter(Boolean);
599
+ if (quoted.length) {
600
+ return quoted;
601
+ }
602
+ return value.split(/[\s,]+/).map(token => token.trim()).filter(Boolean);
603
+ };
604
+ const compareDomainValues = (domain, left, right, domainName) => {
605
+ if (domain.comparator) {
606
+ return domain.comparator(left, right);
607
+ }
608
+ if (typeof left === 'number' && typeof right === 'number') {
609
+ return left - right;
610
+ }
611
+ if (left instanceof Date && right instanceof Date) {
612
+ return left.getTime() - right.getTime();
613
+ }
614
+ throw new Error(`Domain ${domainName} does not support magnitude comparison`);
615
+ };
616
+ const renderComparable = (value) => {
617
+ if (value instanceof Date) {
618
+ return value.toISOString();
619
+ }
620
+ return JSON.stringify(value);
621
+ };
622
+ // ======== Helpers ========
623
+ // Resolves undefined value to literal if it looks like a string
624
+ function resolveValueOrLiteral(valMap, value) {
625
+ if (valMap && valMap.origin === Origin.defined && value === undefined) {
626
+ return isLiteralValue(valMap.term)
627
+ ? { value: String(valMap.term) }
628
+ : { value: undefined, error: `Variable ${valMap.term} is not defined` };
629
+ }
630
+ return { value };
631
+ }
632
+ // Returns OK if "set empty" and variable exists
633
+ function shouldSkipEmpty(featureStep, term, shared) {
634
+ return (featureStep.in.includes('set empty ') && shared.get(term) !== undefined) ? OK : undefined;
635
+ }
636
+ // Wraps shared.set in try/catch
637
+ function trySetVariable(shared, opts, provenance) {
638
+ try {
639
+ shared.set({ term: String(opts.term), value: opts.value, domain: opts.domain, origin: opts.origin, readonly: opts.readonly }, provenance);
640
+ return OK;
641
+ }
642
+ catch (e) {
643
+ return actionNotOK(e.message);
644
+ }
645
+ }
196
646
  //# sourceMappingURL=variables-stepper.js.map