@sungen/driver-data-factory 3.2.20 → 3.2.21-beta.2

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 (2) hide show
  1. package/package.json +2 -2
  2. package/src/crosscheck.ts +27 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sungen/driver-data-factory",
3
- "version": "3.2.20",
3
+ "version": "3.2.21-beta.2",
4
4
  "description": "Sungen Data Factory capability — standardized test-data generation from a field-type + security knowledge catalog (valid/boundary/invalid + traceability), the .overwrite merge layer, and (opt-in) @dataFactory runtime seeding. Design-time knowledge is runtime-free. Plugs into @sun-asterisk/sungen via the capability SPI.",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -14,7 +14,7 @@
14
14
  "author": "eqe team (engineer & quality) — Sun Asterisk",
15
15
  "license": "MIT",
16
16
  "dependencies": {
17
- "@sun-asterisk/sungen": "3.2.20",
17
+ "@sun-asterisk/sungen": "3.2.21-beta.2",
18
18
  "yaml": "^2.4.0"
19
19
  },
20
20
  "files": [
package/src/crosscheck.ts CHANGED
@@ -84,6 +84,29 @@ export function casesColumns(featureText: string, data: Record<string, any>): Se
84
84
  return cols;
85
85
  }
86
86
 
87
+ /**
88
+ * Variable names the feature BINDS at run time, so no test-data key can or should
89
+ * exist for them: values captured from the page (`remember [X] … as {{v}}`, which
90
+ * compiles to `testData.set()`) and values bound by a capability precondition tag
91
+ * (`@query:`/`@api:`/`@dataFactory:` bind their result under the endpoint/query/
92
+ * recipe name). Mirrors the compiler's DataResolver.registerCaptured and the
93
+ * delivery matrix's runtimeVarsOf — without this, every capture-compare scenario
94
+ * was a false-positive DANGLING_VAR, and the only way to silence it was to add a
95
+ * dummy key, i.e. to lie to the data file.
96
+ */
97
+ export function rememberedVars(featureText: string): Set<string> {
98
+ const out = new Set<string>();
99
+ for (const line of featureText.split('\n')) {
100
+ if (!/\bremember\b/i.test(line)) continue;
101
+ const m = line.match(/\bas\s+\{\{\s*([^}]+?)\s*\}\}/i);
102
+ if (m) out.add(m[1].trim().split('.')[0]);
103
+ }
104
+ for (const m of featureText.matchAll(/@(?:query|api|dataFactory):([^(\s]+)/g)) {
105
+ out.add(m[1]);
106
+ }
107
+ return out;
108
+ }
109
+
87
110
  /** Cross-check one unit's feature ↔ test-data. */
88
111
  export function crosscheckUnit(cwd: string, name: string): CrossFinding[] {
89
112
  const out: CrossFinding[] = [];
@@ -94,10 +117,12 @@ export function crosscheckUnit(cwd: string, name: string): CrossFinding[] {
94
117
  const data = loadYaml(paths.testData);
95
118
  const topKeys = new Set(Object.keys(data).filter((k) => !k.startsWith('_')));
96
119
  const caseCols = casesColumns(feature, data); // @cases row columns resolve per-row, not as top-level keys
120
+ const captured = rememberedVars(feature); // runtime-bound vars — no static key can exist
97
121
 
98
- // 1. Dangling vars — a {{var}} whose root key is absent from test-data (and not a @cases column).
122
+ // 1. Dangling vars — a {{var}} whose root key is absent from test-data (and not a @cases column
123
+ // or a runtime-captured binding).
99
124
  for (const v of referencedVars(feature)) {
100
- if (!topKeys.has(v) && !caseCols.has(v)) {
125
+ if (!topKeys.has(v) && !caseCols.has(v) && !captured.has(v)) {
101
126
  out.push({ unit: name, severity: 'error', code: 'DANGLING_VAR', message: `scenario references {{${v}}} but no "${v}" key exists in test-data/${name}.yaml` });
102
127
  }
103
128
  }