docguard-cli 0.7.1 → 0.7.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.
@@ -89,7 +89,12 @@ export function runTrace(projectDir, config, flags) {
89
89
  console.log(`${c.dim} Directory: ${projectDir}${c.reset}`);
90
90
  console.log(`${c.dim} Generating requirements traceability matrix...${c.reset}\n`);
91
91
 
92
- // ── 1. Inventory canonical docs ──
92
+ // ── 1. Build set of required doc basenames from config ──
93
+ const requiredDocs = new Set(
94
+ (config.requiredFiles?.canonical || []).map(f => basename(f))
95
+ );
96
+
97
+ // ── 2. Inventory canonical docs ──
93
98
  const docsDir = resolve(projectDir, 'docs-canonical');
94
99
  const canonicalDocs = [];
95
100
  if (existsSync(docsDir)) {
@@ -98,16 +103,26 @@ export function runTrace(projectDir, config, flags) {
98
103
  }
99
104
  }
100
105
 
101
- // ── 2. Scan project files ──
106
+ // ── 3. Scan project files ──
102
107
  const projectFiles = [];
103
108
  scanDir(projectDir, projectDir, projectFiles);
104
109
 
105
- // ── 3. Build traceability matrix ──
110
+ // ── 4. Build traceability matrix (only required docs) ──
106
111
  const matrix = [];
112
+ const orphanedDocs = [];
107
113
 
108
114
  for (const [docName, traceInfo] of Object.entries(TRACE_MAP)) {
109
115
  const docPath = resolve(docsDir, docName);
110
116
  const docExists = existsSync(docPath);
117
+
118
+ // Check if this doc is excluded from config
119
+ if (!requiredDocs.has(docName)) {
120
+ if (docExists) {
121
+ orphanedDocs.push(docName);
122
+ }
123
+ continue; // Skip excluded docs from the matrix
124
+ }
125
+
111
126
  let lastModified = null;
112
127
  let docSize = 0;
113
128
 
@@ -152,15 +167,15 @@ export function runTrace(projectDir, config, flags) {
152
167
  });
153
168
  }
154
169
 
155
- // ── 4. Output ──
170
+ // ── 5. Output ──
156
171
  if (flags.format === 'json') {
157
- outputJSON(config.projectName, matrix);
172
+ outputJSON(config.projectName, matrix, orphanedDocs);
158
173
  } else {
159
- outputText(config.projectName, matrix, canonicalDocs);
174
+ outputText(config.projectName, matrix, canonicalDocs, orphanedDocs);
160
175
  }
161
176
  }
162
177
 
163
- function outputJSON(projectName, matrix) {
178
+ function outputJSON(projectName, matrix, orphanedDocs) {
164
179
  const result = {
165
180
  project: projectName,
166
181
  traceability: matrix.map(m => ({
@@ -173,19 +188,21 @@ function outputJSON(projectName, matrix) {
173
188
  tests: m.relatedTests.length,
174
189
  traces: m.traces,
175
190
  })),
191
+ orphanedDocs,
176
192
  summary: {
177
193
  total: matrix.length,
178
194
  traced: matrix.filter(m => m.coverageSignal === 'TRACED').length,
179
195
  partial: matrix.filter(m => m.coverageSignal === 'PARTIAL').length,
180
196
  unlinked: matrix.filter(m => m.coverageSignal === 'UNLINKED').length,
181
197
  missing: matrix.filter(m => m.coverageSignal === 'MISSING').length,
198
+ orphaned: orphanedDocs.length,
182
199
  },
183
200
  timestamp: new Date().toISOString(),
184
201
  };
185
202
  console.log(JSON.stringify(result, null, 2));
186
203
  }
187
204
 
188
- function outputText(projectName, matrix, canonicalDocs) {
205
+ function outputText(projectName, matrix, canonicalDocs, orphanedDocs) {
189
206
  // Header table
190
207
  console.log(` ${c.bold}Traceability Matrix${c.reset}\n`);
191
208
  console.log(` ${c.dim}${'Document'.padEnd(22)} ${'Standard'.padEnd(28)} ${'Status'.padEnd(10)} ${'Sources'.padEnd(9)} ${'Tests'.padEnd(7)} ${'Last Modified'}${c.reset}`);
@@ -257,6 +274,16 @@ function outputText(projectName, matrix, canonicalDocs) {
257
274
  console.log(` ${c.dim}Run ${c.cyan}docguard diagnose${c.dim} to fix coverage gaps.${c.reset}`);
258
275
  }
259
276
 
277
+ // ── Orphaned docs warning ──
278
+ if (orphanedDocs.length > 0) {
279
+ console.log(`\n ${c.yellow}⚠️ Orphaned Files (${orphanedDocs.length})${c.reset}`);
280
+ console.log(` ${c.dim}These files exist in docs-canonical/ but are excluded from your config:${c.reset}`);
281
+ for (const doc of orphanedDocs) {
282
+ console.log(` ${c.yellow}→${c.reset} ${doc}`);
283
+ }
284
+ console.log(` ${c.dim}Delete them or add to .docguard.json requiredFiles.canonical${c.reset}`);
285
+ }
286
+
260
287
  console.log(`\n ${c.dim}Traceability methodology: ISO/IEC/IEEE 29119 (Lopez et al., AITPG, IEEE TSE 2026)${c.reset}\n`);
261
288
  }
262
289
 
@@ -67,6 +67,8 @@ const TRACE_MAP = {
67
67
 
68
68
  /**
69
69
  * Validate traceability — ensures canonical docs have corresponding source artifacts.
70
+ * Respects config.requiredFiles.canonical — only checks docs the user requires.
71
+ * Also warns about orphaned files (exist but excluded from config).
70
72
  * @returns {{ errors: string[], warnings: string[], passed: number, total: number }}
71
73
  */
72
74
  export function validateTraceability(projectDir, config) {
@@ -81,23 +83,26 @@ export function validateTraceability(projectDir, config) {
81
83
  return { errors, warnings, passed: 0, total: 0 };
82
84
  }
83
85
 
86
+ // Build set of required doc basenames from config
87
+ const requiredDocs = new Set(
88
+ (config.requiredFiles?.canonical || []).map(f => basename(f))
89
+ );
90
+
84
91
  // Scan project files once
85
92
  const projectFiles = [];
86
93
  scanDir(projectDir, projectDir, projectFiles);
87
94
 
95
+ // ── Check required docs for traceability ──
88
96
  for (const [docName, traceInfo] of Object.entries(TRACE_MAP)) {
97
+ // Skip docs not in the user's required list
98
+ if (!requiredDocs.has(docName)) continue;
99
+
89
100
  total++;
90
101
  const docPath = resolve(docsDir, docName);
91
102
  const docExists = existsSync(docPath);
92
103
 
93
104
  if (!docExists) {
94
- // Only warn for API-REFERENCE.md (not all projects have APIs)
95
- if (docName === 'API-REFERENCE.md') {
96
- // Don't count API-REFERENCE as missing — it's optional
97
- total--;
98
- } else {
99
- warnings.push(`${docName} — document missing, no traceability possible`);
100
- }
105
+ warnings.push(`${docName} required but missing, no traceability possible`);
101
106
  continue;
102
107
  }
103
108
 
@@ -115,6 +120,16 @@ export function validateTraceability(projectDir, config) {
115
120
  }
116
121
  }
117
122
 
123
+ // ── Detect orphaned files (exist but not required) ──
124
+ try {
125
+ const existingDocs = readdirSync(docsDir).filter(f => f.endsWith('.md'));
126
+ for (const docFile of existingDocs) {
127
+ if (!requiredDocs.has(docFile) && TRACE_MAP[docFile]) {
128
+ warnings.push(`${docFile} — file exists in docs-canonical/ but is not in your requiredFiles config. Consider deleting it or adding it to .docguard.json requiredFiles.canonical`);
129
+ }
130
+ }
131
+ } catch { /* ignore */ }
132
+
118
133
  return { errors, warnings, passed, total };
119
134
  }
120
135
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docguard-cli",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "The enforcement tool for Canonical-Driven Development (CDD). Audit, generate, and guard your project documentation.",
5
5
  "type": "module",
6
6
  "bin": {