@nac3/forge-cli 0.2.0-alpha.13 → 0.2.0-alpha.15

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.
@@ -0,0 +1,138 @@
1
+ /**
2
+ * `yf coverage structural` -- Phase V step 15 acceptance gate.
3
+ *
4
+ * Checks that every NAC-3 manifest element is exercised by at
5
+ * least one e2e test. Required by SQ Sec 14 + PRODUCT_WORKFLOW
6
+ * step 15 for any block to enter "green" status.
7
+ *
8
+ * Strategy:
9
+ * 1. Read the manifest from src/nac/manifest.ts (parsed
10
+ * heuristically for element ids).
11
+ * 2. Scan tests/ for occurrences of each id (data-nac-id
12
+ * assertions, locator strings, etc).
13
+ * 3. Compute (covered ids) / (total ids) ratio.
14
+ * 4. Exit 0 iff coverage === 100%; exit 1 otherwise so CI
15
+ * can gate on it.
16
+ *
17
+ * Pure read-only. Output: counts + missing ids. Optional
18
+ * --if-failing-exit-1 flag so CI fails the job (default true).
19
+ *
20
+ * ASCII-only.
21
+ */
22
+ import path from 'node:path';
23
+ import { promises as fs } from 'node:fs';
24
+ import { c, header } from '../ui/colors.js';
25
+ const TEST_FILE_RE = /\.(test|spec|e2e)\.(t|j)sx?$/;
26
+ const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', 'coverage', '.cache']);
27
+ async function readManifest(p) {
28
+ try {
29
+ const src = await fs.readFile(p, 'utf-8');
30
+ /* Heuristic id grep. Matches:
31
+ * "checkout.confirm_button"
32
+ * id: "checkout.confirm_button"
33
+ * data-nac-id="checkout.confirm_button" */
34
+ const idRegex = /["'`]([a-z][a-z0-9_]*(?:\.[a-z0-9_]+)+)["'`]/g;
35
+ const ids = new Set();
36
+ let m;
37
+ while ((m = idRegex.exec(src)) !== null) {
38
+ if (m[1])
39
+ ids.add(m[1]);
40
+ }
41
+ return [...ids];
42
+ }
43
+ catch {
44
+ return [];
45
+ }
46
+ }
47
+ async function walkTestFiles(root, out) {
48
+ let entries;
49
+ try {
50
+ entries = await fs.readdir(root, { withFileTypes: true });
51
+ }
52
+ catch {
53
+ return;
54
+ }
55
+ for (const e of entries) {
56
+ if (SKIP_DIRS.has(e.name))
57
+ continue;
58
+ const p = path.join(root, e.name);
59
+ if (e.isDirectory())
60
+ await walkTestFiles(p, out);
61
+ else if (e.isFile() && TEST_FILE_RE.test(e.name))
62
+ out.push(p);
63
+ }
64
+ }
65
+ export async function runCoverage(opts) {
66
+ header('Yujin Forge -- coverage structural');
67
+ console.log('');
68
+ const projectRoot = opts.cwd ? path.resolve(opts.cwd) : process.cwd();
69
+ const manifestPath = path.resolve(projectRoot, opts.manifest || 'src/nac/manifest.ts');
70
+ const ids = await readManifest(manifestPath);
71
+ if (ids.length === 0) {
72
+ console.log(c.warn('Manifest no encontrado o vacio: ' + manifestPath));
73
+ console.log(c.dim('Si no tenes manifest todavia, este check no aplica.'));
74
+ return;
75
+ }
76
+ const testRoots = [
77
+ path.join(projectRoot, 'tests'),
78
+ path.join(projectRoot, 'src', '__tests__'),
79
+ path.join(projectRoot, 'e2e'),
80
+ ];
81
+ const testFiles = [];
82
+ for (const r of testRoots)
83
+ await walkTestFiles(r, testFiles);
84
+ /* For each id, check if it appears in ANY test file. */
85
+ const filesContent = [];
86
+ for (const f of testFiles) {
87
+ try {
88
+ filesContent.push({ path: f, text: await fs.readFile(f, 'utf-8') });
89
+ }
90
+ catch { /* skip */ }
91
+ }
92
+ const covered = [];
93
+ const missing = [];
94
+ for (const id of ids) {
95
+ const hit = filesContent.some(({ text }) => text.includes(id));
96
+ if (hit)
97
+ covered.push(id);
98
+ else
99
+ missing.push(id);
100
+ }
101
+ const pct = ids.length === 0 ? 100 : Math.round((covered.length / ids.length) * 100);
102
+ console.log(c.dim('Manifest: ') + manifestPath);
103
+ console.log(c.dim('Total ids: ') + c.brand(String(ids.length)));
104
+ console.log(c.dim('Covered: ') + c.success(String(covered.length)));
105
+ console.log(c.dim('Missing: ') + (missing.length > 0 ? c.error(String(missing.length)) : c.success('0')));
106
+ console.log(c.dim('Coverage: ') + (pct === 100 ? c.success(pct + '%') : c.error(pct + '%')));
107
+ if (missing.length > 0) {
108
+ console.log('');
109
+ console.log(c.warn('IDs sin test:'));
110
+ for (const m of missing.slice(0, 30))
111
+ console.log(' - ' + m);
112
+ if (missing.length > 30)
113
+ console.log(c.dim(' ... y ' + (missing.length - 30) + ' mas'));
114
+ }
115
+ /* CI gate: exit 1 when coverage < 100% AND the flag is on. */
116
+ if (pct < 100 && (opts.ifFailingExit1 !== false)) {
117
+ process.exitCode = 1;
118
+ }
119
+ }
120
+ export function registerCoverageCommand(program) {
121
+ const coverage = program.command('coverage')
122
+ .description('Phase V acceptance: verify NAC-3 structural coverage.');
123
+ coverage.command('structural')
124
+ .description('100% of manifest ids must be exercised by at least one test.')
125
+ .option('--cwd <path>', 'project root')
126
+ .option('--manifest <path>', 'manifest source (default src/nac/manifest.ts)')
127
+ .option('--if-failing-exit-1', 'exit 1 when coverage < 100% (default true)', true)
128
+ .action(async (opts) => {
129
+ try {
130
+ await runCoverage(opts);
131
+ }
132
+ catch (err) {
133
+ console.error(c.error(String(err instanceof Error ? err.message : err)));
134
+ process.exitCode = 1;
135
+ }
136
+ });
137
+ }
138
+ //# sourceMappingURL=workflow-coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-coverage.js","sourceRoot":"","sources":["../../src/commands/workflow-coverage.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -4,5 +4,5 @@
4
4
  * into the npm metadata) so we don't end up with two versions
5
5
  * drifting.
6
6
  */
7
- export declare const VERSION = "0.2.0-alpha.13";
7
+ export declare const VERSION = "0.2.0-alpha.15";
8
8
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -4,5 +4,5 @@
4
4
  * into the npm metadata) so we don't end up with two versions
5
5
  * drifting.
6
6
  */
7
- export const VERSION = '0.2.0-alpha.13';
7
+ export const VERSION = '0.2.0-alpha.15';
8
8
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nac3/forge-cli",
3
- "version": "0.2.0-alpha.13",
3
+ "version": "0.2.0-alpha.15",
4
4
  "description": "Yujin Forge -- voice-first NAC-3 React development framework. CLI + chat panel + spec ingest + 10-format document reader + voice loop.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Pablo Kuschnirof <pablo@rpaforce.com>",