@noyrax/documentation-system-plugin 1.0.4-beta.12 → 1.0.4-beta.14
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/package.json +1 -1
- package/scripts/verify-adrs.js +129 -23
- package/scripts/verify-architecture.js +50 -0
- package/scripts/verify-imports.js +81 -7
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@noyrax/documentation-system-plugin",
|
|
3
3
|
"displayName": "Noyrax",
|
|
4
4
|
"description": "Documentation that never drifts. Automatic documentation generation with validation and drift detection. Generates 5-dimensional documentation structure (modules, symbols, dependencies, ADRs, changes) for codebases.",
|
|
5
|
-
"version": "1.0.4-beta.
|
|
5
|
+
"version": "1.0.4-beta.14",
|
|
6
6
|
"publisher": "noyrax",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
package/scripts/verify-adrs.js
CHANGED
|
@@ -154,56 +154,162 @@ function extractClaimsFromAdr(adrPath) {
|
|
|
154
154
|
return claims;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Lädt die Path-Alias-Map aus .database-plugin/path-aliases.json
|
|
159
|
+
*/
|
|
160
|
+
function loadAliasMap(workspaceRoot) {
|
|
161
|
+
const aliasMapPath = path.join(workspaceRoot, '.database-plugin', 'path-aliases.json');
|
|
162
|
+
if (fs.existsSync(aliasMapPath)) {
|
|
163
|
+
try {
|
|
164
|
+
const content = fs.readFileSync(aliasMapPath, 'utf-8');
|
|
165
|
+
return JSON.parse(content);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
// Ignore errors loading alias map
|
|
168
|
+
return {};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return {};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Resolved einen Pfad mit Hilfe der Alias-Map
|
|
176
|
+
*/
|
|
177
|
+
function resolvePathWithAlias(filePath, workspaceRoot, aliasMap) {
|
|
178
|
+
// Normalisiere den Pfad (forward slashes)
|
|
179
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
180
|
+
|
|
181
|
+
// Prüfe ob es einen Alias gibt
|
|
182
|
+
if (aliasMap[normalized]) {
|
|
183
|
+
return path.join(workspaceRoot, aliasMap[normalized]);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Fallback: Original-Pfad
|
|
187
|
+
return path.join(workspaceRoot, filePath);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Findet alle src/ Verzeichnisse (und app/ für Next.js) mit Hilfe der Alias-Map
|
|
192
|
+
*/
|
|
193
|
+
function findAllSourceDirectories(workspaceRoot, aliasMap) {
|
|
194
|
+
const sourceDirs = [];
|
|
195
|
+
|
|
196
|
+
// Standard: src/ im Workspace-Root
|
|
197
|
+
const standardSrc = path.join(workspaceRoot, 'src');
|
|
198
|
+
if (fs.existsSync(standardSrc)) {
|
|
199
|
+
sourceDirs.push(standardSrc);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Suche in Alias-Map nach src/ Pfaden
|
|
203
|
+
for (const [alias, target] of Object.entries(aliasMap)) {
|
|
204
|
+
if (alias.startsWith('src/') || alias.includes('/src/')) {
|
|
205
|
+
// Extrahiere das Plugin-Root aus dem Target
|
|
206
|
+
const targetParts = target.split('/');
|
|
207
|
+
const srcIndex = targetParts.indexOf('src');
|
|
208
|
+
if (srcIndex > 0) {
|
|
209
|
+
const pluginRoot = targetParts.slice(0, srcIndex).join('/');
|
|
210
|
+
const srcDir = path.join(workspaceRoot, pluginRoot, 'src');
|
|
211
|
+
if (fs.existsSync(srcDir) && !sourceDirs.includes(srcDir)) {
|
|
212
|
+
sourceDirs.push(srcDir);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Suche rekursiv nach src/ Verzeichnissen (max. 2 Ebenen tief)
|
|
219
|
+
try {
|
|
220
|
+
const searchDirs = [
|
|
221
|
+
workspaceRoot,
|
|
222
|
+
...fs.readdirSync(workspaceRoot, { withFileTypes: true })
|
|
223
|
+
.filter(dirent => dirent.isDirectory() && !dirent.name.startsWith('.') && dirent.name !== 'node_modules')
|
|
224
|
+
.map(dirent => path.join(workspaceRoot, dirent.name))
|
|
225
|
+
];
|
|
226
|
+
|
|
227
|
+
for (const searchDir of searchDirs) {
|
|
228
|
+
// src/ Verzeichnisse
|
|
229
|
+
const srcDir = path.join(searchDir, 'src');
|
|
230
|
+
if (fs.existsSync(srcDir) && !sourceDirs.includes(srcDir)) {
|
|
231
|
+
sourceDirs.push(srcDir);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// app/ Verzeichnisse (Next.js)
|
|
235
|
+
const appDir = path.join(searchDir, 'app');
|
|
236
|
+
if (fs.existsSync(appDir) && !sourceDirs.includes(appDir)) {
|
|
237
|
+
sourceDirs.push(appDir);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
} catch (error) {
|
|
241
|
+
// Ignore errors
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return sourceDirs.length > 0 ? sourceDirs : null;
|
|
245
|
+
}
|
|
246
|
+
|
|
157
247
|
/**
|
|
158
248
|
* Verifiziert einen Claim
|
|
159
249
|
*/
|
|
160
250
|
function verifyClaim(claim, workspaceRoot) {
|
|
251
|
+
// Lade Alias-Map
|
|
252
|
+
const aliasMap = loadAliasMap(workspaceRoot);
|
|
253
|
+
|
|
161
254
|
if (claim.type === 'file-exists') {
|
|
162
|
-
|
|
163
|
-
const
|
|
255
|
+
// Versuche zuerst mit Alias-Map
|
|
256
|
+
const resolvedPath = resolvePathWithAlias(claim.file, workspaceRoot, aliasMap);
|
|
257
|
+
const exists = fs.existsSync(resolvedPath);
|
|
164
258
|
|
|
165
259
|
if (!exists) {
|
|
166
|
-
//
|
|
167
|
-
const
|
|
168
|
-
const
|
|
260
|
+
// Fallback: Original-Pfad
|
|
261
|
+
const fullPath = path.join(workspaceRoot, claim.file);
|
|
262
|
+
const existsOriginal = fs.existsSync(fullPath);
|
|
169
263
|
|
|
170
|
-
if (
|
|
171
|
-
|
|
264
|
+
if (!existsOriginal) {
|
|
265
|
+
// Prüfe ob es als .js in out/ existiert (kompilierte Version)
|
|
266
|
+
const jsPath = fullPath.replace(/^src\//, 'out/').replace(/\.ts$/, '.js');
|
|
267
|
+
const jsExists = fs.existsSync(path.join(workspaceRoot, jsPath));
|
|
268
|
+
|
|
269
|
+
if (jsExists) {
|
|
270
|
+
warnings.push({
|
|
271
|
+
adr: claim.adr,
|
|
272
|
+
line: claim.line,
|
|
273
|
+
claim: `File ${claim.file} exists as compiled ${jsPath}, but source not found`,
|
|
274
|
+
type: 'file-exists'
|
|
275
|
+
});
|
|
276
|
+
return true; // Akzeptabel
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
errors.push({
|
|
172
280
|
adr: claim.adr,
|
|
173
281
|
line: claim.line,
|
|
174
|
-
claim: `File ${claim.file}
|
|
282
|
+
claim: `File ${claim.file} does not exist`,
|
|
175
283
|
type: 'file-exists'
|
|
176
284
|
});
|
|
177
|
-
return
|
|
285
|
+
return false;
|
|
178
286
|
}
|
|
179
|
-
|
|
180
|
-
errors.push({
|
|
181
|
-
adr: claim.adr,
|
|
182
|
-
line: claim.line,
|
|
183
|
-
claim: `File ${claim.file} does not exist`,
|
|
184
|
-
type: 'file-exists'
|
|
185
|
-
});
|
|
186
|
-
return false;
|
|
187
287
|
}
|
|
188
288
|
return true;
|
|
189
289
|
}
|
|
190
290
|
|
|
191
291
|
if (claim.type === 'function-exists') {
|
|
192
292
|
try {
|
|
193
|
-
//
|
|
194
|
-
const
|
|
195
|
-
if (!
|
|
293
|
+
// Finde alle src/ und app/ Verzeichnisse mit Hilfe der Alias-Map
|
|
294
|
+
const sourceDirs = findAllSourceDirectories(workspaceRoot, aliasMap);
|
|
295
|
+
if (!sourceDirs || sourceDirs.length === 0) {
|
|
196
296
|
warnings.push({
|
|
197
297
|
adr: claim.adr,
|
|
198
298
|
line: claim.line,
|
|
199
|
-
claim: `Could not verify function ${claim.name} (src/ directory not found)`,
|
|
299
|
+
claim: `Could not verify function ${claim.name} (src/ or app/ directory not found)`,
|
|
200
300
|
type: 'function-exists'
|
|
201
301
|
});
|
|
202
302
|
return true;
|
|
203
303
|
}
|
|
204
304
|
|
|
205
|
-
// Rekursive Suche in TypeScript-Dateien
|
|
206
|
-
|
|
305
|
+
// Rekursive Suche in allen TypeScript-Dateien (src/ und app/)
|
|
306
|
+
let found = false;
|
|
307
|
+
for (const srcDir of sourceDirs) {
|
|
308
|
+
if (searchInDirectory(srcDir, claim.name)) {
|
|
309
|
+
found = true;
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
207
313
|
|
|
208
314
|
if (!found) {
|
|
209
315
|
if (claim.explicit || claim.autoGenerated) {
|
|
@@ -16,6 +16,39 @@ const { execSync } = require('child_process');
|
|
|
16
16
|
const errors = [];
|
|
17
17
|
const warnings = [];
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Lädt die Path-Alias-Map aus .database-plugin/path-aliases.json
|
|
21
|
+
*/
|
|
22
|
+
function loadAliasMap(workspaceRoot) {
|
|
23
|
+
const aliasMapPath = path.join(workspaceRoot, '.database-plugin', 'path-aliases.json');
|
|
24
|
+
if (fs.existsSync(aliasMapPath)) {
|
|
25
|
+
try {
|
|
26
|
+
const content = fs.readFileSync(aliasMapPath, 'utf-8');
|
|
27
|
+
return JSON.parse(content);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
// Ignore errors loading alias map
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Resolved einen Pfad mit Hilfe der Alias-Map
|
|
38
|
+
*/
|
|
39
|
+
function resolvePathWithAlias(filePath, workspaceRoot, aliasMap) {
|
|
40
|
+
// Normalisiere den Pfad (forward slashes)
|
|
41
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
42
|
+
|
|
43
|
+
// Prüfe ob es einen Alias gibt
|
|
44
|
+
if (aliasMap[normalized]) {
|
|
45
|
+
return path.join(workspaceRoot, aliasMap[normalized]);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Fallback: Original-Pfad
|
|
49
|
+
return path.join(workspaceRoot, filePath);
|
|
50
|
+
}
|
|
51
|
+
|
|
19
52
|
/**
|
|
20
53
|
* Findet ein Verzeichnis durch intelligente Suche.
|
|
21
54
|
* Sucht im gegebenen Verzeichnis und in Parent-Verzeichnissen (max. 5 Ebenen).
|
|
@@ -55,8 +88,25 @@ function findDirectoryOrFile(startDir, targetPath, maxDepth = 5) {
|
|
|
55
88
|
function checkMcpToSrcImports(workspaceRoot) {
|
|
56
89
|
console.log('🔍 Checking for invalid imports from mcp/ to src/...');
|
|
57
90
|
|
|
91
|
+
// Lade Alias-Map
|
|
92
|
+
const aliasMap = loadAliasMap(workspaceRoot);
|
|
93
|
+
|
|
58
94
|
// Suche mcp/src relativ zu workspaceRoot
|
|
59
95
|
let mcpSrcDir = findDirectoryOrFile(workspaceRoot, 'mcp/src');
|
|
96
|
+
if (!mcpSrcDir) {
|
|
97
|
+
// Versuche mit Alias-Map
|
|
98
|
+
const aliasKeys = Object.keys(aliasMap);
|
|
99
|
+
for (const alias of aliasKeys) {
|
|
100
|
+
if (alias.includes('mcp/src') || alias.includes('/mcp/src')) {
|
|
101
|
+
const resolved = resolvePathWithAlias(alias, workspaceRoot, aliasMap);
|
|
102
|
+
if (fs.existsSync(resolved)) {
|
|
103
|
+
mcpSrcDir = resolved;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
60
110
|
if (!mcpSrcDir) {
|
|
61
111
|
// Fallback: Versuche __dirname + '/..' (Plugin-interne Suche)
|
|
62
112
|
const fallbackRoot = path.join(__dirname, '..');
|
|
@@ -15,6 +15,69 @@ const { execSync } = require('child_process');
|
|
|
15
15
|
const errors = [];
|
|
16
16
|
const warnings = [];
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Lädt die Path-Alias-Map aus .database-plugin/path-aliases.json
|
|
20
|
+
*/
|
|
21
|
+
function loadAliasMap(workspaceRoot) {
|
|
22
|
+
const aliasMapPath = path.join(workspaceRoot, '.database-plugin', 'path-aliases.json');
|
|
23
|
+
if (fs.existsSync(aliasMapPath)) {
|
|
24
|
+
try {
|
|
25
|
+
const content = fs.readFileSync(aliasMapPath, 'utf-8');
|
|
26
|
+
return JSON.parse(content);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
// Ignore errors loading alias map
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Resolved einen Pfad mit Hilfe der Alias-Map
|
|
37
|
+
*/
|
|
38
|
+
function resolvePathWithAlias(filePath, workspaceRoot, aliasMap) {
|
|
39
|
+
// Normalisiere den Pfad (forward slashes)
|
|
40
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
41
|
+
|
|
42
|
+
// Prüfe ob es einen Alias gibt
|
|
43
|
+
if (aliasMap[normalized]) {
|
|
44
|
+
return path.join(workspaceRoot, aliasMap[normalized]);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Fallback: Original-Pfad
|
|
48
|
+
return path.join(workspaceRoot, filePath);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Findet src/ Verzeichnis mit Hilfe der Alias-Map
|
|
53
|
+
*/
|
|
54
|
+
function findSrcDirectoryWithAlias(startDir, workspaceRoot, aliasMap, maxDepth = 5) {
|
|
55
|
+
// Standard: src/ im Workspace-Root
|
|
56
|
+
const standardSrc = path.join(workspaceRoot, 'src');
|
|
57
|
+
if (fs.existsSync(standardSrc)) {
|
|
58
|
+
return standardSrc;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Suche in Alias-Map nach src/ Pfaden
|
|
62
|
+
for (const [alias, target] of Object.entries(aliasMap)) {
|
|
63
|
+
if (alias.startsWith('src/') || alias.includes('/src/')) {
|
|
64
|
+
// Extrahiere das Plugin-Root aus dem Target
|
|
65
|
+
const targetParts = target.split('/');
|
|
66
|
+
const srcIndex = targetParts.indexOf('src');
|
|
67
|
+
if (srcIndex > 0) {
|
|
68
|
+
const pluginRoot = targetParts.slice(0, srcIndex).join('/');
|
|
69
|
+
const srcDir = path.join(workspaceRoot, pluginRoot, 'src');
|
|
70
|
+
if (fs.existsSync(srcDir)) {
|
|
71
|
+
return srcDir;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Fallback: Original findSrcDirectory
|
|
78
|
+
return findSrcDirectory(startDir, maxDepth);
|
|
79
|
+
}
|
|
80
|
+
|
|
18
81
|
/**
|
|
19
82
|
* Sammelt alle TypeScript-Dateien rekursiv
|
|
20
83
|
*/
|
|
@@ -126,7 +189,7 @@ function findSrcDirectory(startDir, maxDepth = 5) {
|
|
|
126
189
|
/**
|
|
127
190
|
* Prüft ob ein Import verfügbar ist
|
|
128
191
|
*/
|
|
129
|
-
function checkImport(importPath, importedName, fromFile, workspaceRoot) {
|
|
192
|
+
function checkImport(importPath, importedName, fromFile, workspaceRoot, aliasMap) {
|
|
130
193
|
|
|
131
194
|
// Resolve import path
|
|
132
195
|
let targetFile;
|
|
@@ -148,6 +211,14 @@ function checkImport(importPath, importedName, fromFile, workspaceRoot) {
|
|
|
148
211
|
targetFile = path.join(targetFile, 'index.js');
|
|
149
212
|
}
|
|
150
213
|
}
|
|
214
|
+
|
|
215
|
+
// Versuche mit Alias-Map, wenn Datei nicht gefunden wurde
|
|
216
|
+
if (!fs.existsSync(targetFile) && aliasMap) {
|
|
217
|
+
const relativePath = path.relative(workspaceRoot, targetFile).replace(/\\/g, '/');
|
|
218
|
+
if (aliasMap[relativePath]) {
|
|
219
|
+
targetFile = path.join(workspaceRoot, aliasMap[relativePath]);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
151
222
|
} else {
|
|
152
223
|
// Node module import - skip for now
|
|
153
224
|
return true;
|
|
@@ -187,7 +258,7 @@ function checkImport(importPath, importedName, fromFile, workspaceRoot) {
|
|
|
187
258
|
/**
|
|
188
259
|
* Prüft alle Imports in einer Datei
|
|
189
260
|
*/
|
|
190
|
-
function checkFileImports(filePath, workspaceRoot) {
|
|
261
|
+
function checkFileImports(filePath, workspaceRoot, aliasMap) {
|
|
191
262
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
192
263
|
const lines = content.split('\n');
|
|
193
264
|
|
|
@@ -230,7 +301,7 @@ function checkFileImports(filePath, workspaceRoot) {
|
|
|
230
301
|
|
|
231
302
|
// Check each imported name
|
|
232
303
|
importedNames.forEach(name => {
|
|
233
|
-
checkImport(importPath, name, filePath, workspaceRoot);
|
|
304
|
+
checkImport(importPath, name, filePath, workspaceRoot, aliasMap);
|
|
234
305
|
});
|
|
235
306
|
}
|
|
236
307
|
}
|
|
@@ -267,14 +338,17 @@ function main() {
|
|
|
267
338
|
}
|
|
268
339
|
}
|
|
269
340
|
|
|
270
|
-
//
|
|
271
|
-
const
|
|
341
|
+
// Lade Alias-Map
|
|
342
|
+
const aliasMap = loadAliasMap(workspaceRoot);
|
|
343
|
+
|
|
344
|
+
// src/ Verzeichnis finden (intelligente Suche mit Alias-Map)
|
|
345
|
+
const srcDir = findSrcDirectoryWithAlias(workspaceRoot, workspaceRoot, aliasMap);
|
|
272
346
|
if (!srcDir) {
|
|
273
347
|
console.log('⚠️ src/ directory not found, skipping verification');
|
|
274
348
|
console.log(` Searched from: ${workspaceRoot}`);
|
|
275
349
|
process.exit(0);
|
|
276
350
|
}
|
|
277
|
-
|
|
351
|
+
|
|
278
352
|
// workspaceRoot auf Basis des gefundenen src/ korrigieren
|
|
279
353
|
workspaceRoot = path.dirname(srcDir);
|
|
280
354
|
|
|
@@ -285,7 +359,7 @@ function main() {
|
|
|
285
359
|
|
|
286
360
|
let checkedFiles = 0;
|
|
287
361
|
for (const file of files) {
|
|
288
|
-
checkFileImports(file, workspaceRoot);
|
|
362
|
+
checkFileImports(file, workspaceRoot, aliasMap);
|
|
289
363
|
checkedFiles++;
|
|
290
364
|
|
|
291
365
|
if (checkedFiles % 10 === 0) {
|