@noyrax/documentation-system-plugin 1.0.4-beta.1 → 1.0.4-beta.3

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 (84) hide show
  1. package/docs/index/symbols.jsonl +78 -31
  2. package/docs/modules/mcp__src__tools__drift.ts.md +6 -2
  3. package/docs/modules/mcp__src__tools__impact.ts.md +3 -0
  4. package/docs/modules/package.json.md +10 -11
  5. package/docs/modules/scripts__verify-adrs.js.md +2 -2
  6. package/docs/modules/src__core__consolidation.ts.md +0 -1
  7. package/docs/modules/src__core__scanner.ts.md +0 -1
  8. package/docs/modules/src__index__index.ts.md +18 -0
  9. package/docs/modules/src__parsers__json-yaml.ts.md +16 -1
  10. package/docs/modules/src__parsers__types.ts.md +18 -0
  11. package/docs/system/CHANGE_REPORT.md +14 -7
  12. package/docs/system/DEPENDENCIES.md +0 -27
  13. package/docs/system/DEPENDENCY_GRAPH.md +267 -299
  14. package/docs/system/SYSTEM_METADATA.json +37 -0
  15. package/package.json +3 -4
  16. package/noyrax-5d-database-plugin-0.1.8.tgz +0 -0
  17. package/out/cache/ast-cache.js +0 -69
  18. package/out/cache/ast-cache.js.map +0 -1
  19. package/out/cache/dependencies-cache.js +0 -73
  20. package/out/cache/dependencies-cache.js.map +0 -1
  21. package/out/cache/output-cache.js +0 -69
  22. package/out/cache/output-cache.js.map +0 -1
  23. package/out/cache/signature-cache.js +0 -60
  24. package/out/cache/signature-cache.js.map +0 -1
  25. package/out/cli/generate-cli.js +0 -330
  26. package/out/cli/generate-cli.js.map +0 -1
  27. package/out/cli/scan-cli.js +0 -151
  28. package/out/cli/scan-cli.js.map +0 -1
  29. package/out/cli/validate-cli.js +0 -258
  30. package/out/cli/validate-cli.js.map +0 -1
  31. package/out/core/async.js +0 -38
  32. package/out/core/async.js.map +0 -1
  33. package/out/core/consolidation.js +0 -230
  34. package/out/core/consolidation.js.map +0 -1
  35. package/out/core/git.js +0 -48
  36. package/out/core/git.js.map +0 -1
  37. package/out/core/language-detection.js +0 -29
  38. package/out/core/language-detection.js.map +0 -1
  39. package/out/core/scanner.js +0 -179
  40. package/out/core/scanner.js.map +0 -1
  41. package/out/core/signature-formatter.js +0 -162
  42. package/out/core/signature-formatter.js.map +0 -1
  43. package/out/core/symbol-classifier.js +0 -96
  44. package/out/core/symbol-classifier.js.map +0 -1
  45. package/out/core/symbols.js +0 -24
  46. package/out/core/symbols.js.map +0 -1
  47. package/out/drift/index.js +0 -28
  48. package/out/drift/index.js.map +0 -1
  49. package/out/extension.js +0 -984
  50. package/out/extension.js.map +0 -1
  51. package/out/generator/adr-linker.js +0 -216
  52. package/out/generator/adr-linker.js.map +0 -1
  53. package/out/generator/change-report.js +0 -124
  54. package/out/generator/change-report.js.map +0 -1
  55. package/out/generator/dependency-graph.js +0 -98
  56. package/out/generator/dependency-graph.js.map +0 -1
  57. package/out/generator/index.js +0 -117
  58. package/out/generator/index.js.map +0 -1
  59. package/out/generator/module-doc.js +0 -438
  60. package/out/generator/module-doc.js.map +0 -1
  61. package/out/index/index.js +0 -147
  62. package/out/index/index.js.map +0 -1
  63. package/out/logging/index.js +0 -24
  64. package/out/logging/index.js.map +0 -1
  65. package/out/parsers/dependencies.js +0 -126
  66. package/out/parsers/dependencies.js.map +0 -1
  67. package/out/parsers/json-yaml.js +0 -90
  68. package/out/parsers/json-yaml.js.map +0 -1
  69. package/out/parsers/python.js +0 -160
  70. package/out/parsers/python.js.map +0 -1
  71. package/out/parsers/ts-js.js +0 -397
  72. package/out/parsers/ts-js.js.map +0 -1
  73. package/out/parsers/types.js +0 -3
  74. package/out/parsers/types.js.map +0 -1
  75. package/out/ui/commands-provider.js +0 -91
  76. package/out/ui/commands-provider.js.map +0 -1
  77. package/out/ui/status-bar.js +0 -85
  78. package/out/ui/status-bar.js.map +0 -1
  79. package/out/validator/index.js +0 -185
  80. package/out/validator/index.js.map +0 -1
  81. package/out/validator/signature-matching.js +0 -261
  82. package/out/validator/signature-matching.js.map +0 -1
  83. package/out/validator/status.js +0 -38
  84. package/out/validator/status.js.map +0 -1
package/out/extension.js DELETED
@@ -1,984 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.deactivate = exports.activate = void 0;
27
- const vscode = __importStar(require("vscode"));
28
- const path = __importStar(require("path"));
29
- const fs = __importStar(require("fs"));
30
- const commands_provider_1 = require("./ui/commands-provider");
31
- const status_bar_1 = require("./ui/status-bar");
32
- const scanner_1 = require("./core/scanner");
33
- const ts_js_1 = require("./parsers/ts-js");
34
- const json_yaml_1 = require("./parsers/json-yaml");
35
- const python_1 = require("./parsers/python");
36
- const index_1 = require("./generator/index");
37
- const change_report_1 = require("./generator/change-report");
38
- const dependency_graph_1 = require("./generator/dependency-graph");
39
- const index_2 = require("./validator/index");
40
- const status_1 = require("./validator/status");
41
- const signature_cache_1 = require("./cache/signature-cache");
42
- const index_3 = require("./drift/index");
43
- const output_cache_1 = require("./cache/output-cache");
44
- const index_4 = require("./index/index");
45
- const ast_cache_1 = require("./cache/ast-cache");
46
- const dependencies_cache_1 = require("./cache/dependencies-cache");
47
- const consolidation_1 = require("./core/consolidation");
48
- const async_1 = require("./core/async");
49
- const git_1 = require("./core/git");
50
- const dependencies_1 = require("./parsers/dependencies");
51
- let globalOutput;
52
- let globalStatusBar;
53
- function getConfig() {
54
- const config = vscode.workspace.getConfiguration('noyrax');
55
- const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '';
56
- return {
57
- workspaceRoot,
58
- outputPath: config.get('outputPath') || 'docs',
59
- };
60
- }
61
- class DocumentationItem extends vscode.TreeItem {
62
- constructor(label, collapsibleState, filePath, size) {
63
- super(label, collapsibleState);
64
- this.label = label;
65
- this.collapsibleState = collapsibleState;
66
- this.filePath = filePath;
67
- this.size = size;
68
- if (filePath) {
69
- this.tooltip = `${this.label}\n${filePath}\n${size ? `Größe: ${size} Bytes` : ''}`;
70
- this.command = {
71
- command: 'vscode.open',
72
- title: 'Datei öffnen',
73
- arguments: [vscode.Uri.file(filePath)]
74
- };
75
- this.iconPath = new vscode.ThemeIcon('file-text');
76
- }
77
- else {
78
- this.iconPath = new vscode.ThemeIcon('info');
79
- }
80
- }
81
- }
82
- class DocumentationProvider {
83
- constructor() {
84
- this._onDidChangeTreeData = new vscode.EventEmitter();
85
- this.onDidChangeTreeData = this._onDidChangeTreeData.event;
86
- }
87
- refresh() {
88
- this._onDidChangeTreeData.fire();
89
- }
90
- getTreeItem(element) {
91
- return element;
92
- }
93
- getChildren(element) {
94
- if (!element) {
95
- return this.getDocumentationFiles();
96
- }
97
- return Promise.resolve([]);
98
- }
99
- async getDocumentationFiles() {
100
- const config = getConfig();
101
- const docsPath = path.join(config.workspaceRoot, config.outputPath, 'modules');
102
- if (!fs.existsSync(docsPath)) {
103
- return [new DocumentationItem('Keine Dokumentation gefunden', vscode.TreeItemCollapsibleState.None)];
104
- }
105
- try {
106
- const files = fs.readdirSync(docsPath)
107
- .filter(f => f.endsWith('.md'))
108
- .map(f => {
109
- const filePath = path.join(docsPath, f);
110
- const stat = fs.statSync(filePath);
111
- return new DocumentationItem(f.replace('.md', ''), vscode.TreeItemCollapsibleState.None, filePath, stat.size);
112
- });
113
- return files.length > 0 ? files : [new DocumentationItem('Keine Dokumentationsdateien', vscode.TreeItemCollapsibleState.None)];
114
- }
115
- catch (error) {
116
- return [new DocumentationItem('Fehler beim Lesen der Dokumentation', vscode.TreeItemCollapsibleState.None)];
117
- }
118
- }
119
- }
120
- function activate(context) {
121
- try {
122
- console.log('Documentation System Plugin wurde aktiviert');
123
- if (!globalOutput) {
124
- globalOutput = vscode.window.createOutputChannel('Documentation System');
125
- }
126
- globalOutput.appendLine('Extension aktiviert');
127
- // Status Bar Manager
128
- try {
129
- const statusBarManager = new status_bar_1.StatusBarManager(context);
130
- globalStatusBar = statusBarManager;
131
- }
132
- catch (error) {
133
- globalOutput.appendLine(`[ERROR] Fehler beim Erstellen des Status Bar Managers: ${error}`);
134
- console.error('Fehler beim Erstellen des Status Bar Managers:', error);
135
- }
136
- // Commands registrieren (noyrax.* für Rebranding ADR-018)
137
- try {
138
- registerCommand(context, 'noyrax.generate', 'Dokumentation generieren', async () => { globalOutput.show(true); await generateDocumentationTs(); });
139
- registerCommand(context, 'noyrax.scan', 'System vollständig scannen', async () => { globalOutput.show(true); await scanSystemTs(); });
140
- registerCommand(context, 'noyrax.search', 'In Dokumentation suchen', searchDocumentation);
141
- registerCommand(context, 'noyrax.validate', 'Dokumentation validieren', async () => { globalOutput.show(true); await validateDocumentationTs(); });
142
- registerCommand(context, 'noyrax.drift', 'Drift-Erkennung ausführen', async () => { globalOutput.show(true); await checkDriftTs(); });
143
- registerCommand(context, 'noyrax.sync', 'Dokumentation synchronisieren', syncDocumentation);
144
- registerCommand(context, 'noyrax.open', 'Dokumentationsdatei öffnen', openDocumentationFile);
145
- registerCommand(context, 'noyrax.overview', 'Systemübersicht anzeigen', showSystemOverview);
146
- registerCommand(context, 'noyrax.fullCycle', 'Vollständiger Lauf', async () => {
147
- await scanSystemTs();
148
- await generateDocumentationTs();
149
- await validateDocumentationTs();
150
- });
151
- globalOutput.appendLine('[OK] Alle Commands registriert');
152
- }
153
- catch (error) {
154
- globalOutput.appendLine(`[ERROR] Fehler beim Registrieren der Commands: ${error}`);
155
- console.error('Fehler beim Registrieren der Commands:', error);
156
- vscode.window.showErrorMessage(`Fehler beim Registrieren der Noyrax Commands: ${error}`);
157
- }
158
- // TreeView Provider registrieren
159
- try {
160
- const docsProvider = new DocumentationProvider();
161
- vscode.window.registerTreeDataProvider('noyraxExplorer', docsProvider);
162
- // Commands Panel Provider
163
- const commandsProvider = new commands_provider_1.CommandsProvider();
164
- vscode.window.registerTreeDataProvider('noyraxCommands', commandsProvider);
165
- // Refresh-Command für TreeView
166
- registerCommand(context, 'noyrax.refresh', 'Dokumentation aktualisieren', () => {
167
- docsProvider.refresh();
168
- commandsProvider.refresh();
169
- });
170
- globalOutput.appendLine('[OK] TreeView Provider registriert');
171
- }
172
- catch (error) {
173
- globalOutput.appendLine(`[ERROR] Fehler beim Registrieren der TreeView Provider: ${error}`);
174
- console.error('Fehler beim Registrieren der TreeView Provider:', error);
175
- vscode.window.showErrorMessage(`Fehler beim Registrieren der Noyrax TreeView Provider: ${error}`);
176
- }
177
- globalOutput.appendLine('[OK] Extension erfolgreich aktiviert');
178
- }
179
- catch (error) {
180
- const errorMessage = `Kritischer Fehler bei der Extension-Aktivierung: ${error}`;
181
- console.error(errorMessage, error);
182
- if (globalOutput) {
183
- globalOutput.appendLine(`[CRITICAL ERROR] ${errorMessage}`);
184
- globalOutput.show(true);
185
- }
186
- else {
187
- vscode.window.showErrorMessage(errorMessage);
188
- }
189
- }
190
- }
191
- exports.activate = activate;
192
- function registerCommand(context, command, title, callback) {
193
- const disposable = vscode.commands.registerCommand(command, callback);
194
- context.subscriptions.push(disposable);
195
- }
196
- async function generateDocumentationTs() {
197
- const config = getConfig();
198
- const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
199
- statusBar.text = "$(sync~spin) Generiere Dokumentation...";
200
- statusBar.show();
201
- try {
202
- const t0 = Date.now();
203
- const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
204
- if (!workspaceRoot) {
205
- throw new Error('Kein Workspace geöffnet');
206
- }
207
- const includeBackups = vscode.workspace.getConfiguration('noyrax').get('includeBackups') ?? false;
208
- const scannedAll = (0, scanner_1.scanWorkspace)({ workspaceRoot }, includeBackups);
209
- let scanned = scannedAll;
210
- let changed = null;
211
- const useGit = (vscode.workspace.getConfiguration('noyrax').get('useGitDiff') ?? false);
212
- // Prüfe, ob AST-Cache existiert (für ersten Lauf)
213
- const cacheDir = path.join(workspaceRoot, config.outputPath, '.cache');
214
- const astCacheFile = path.join(cacheDir, 'ast-hashes.json');
215
- const prevAst = (0, ast_cache_1.loadAstHashCache)(astCacheFile);
216
- const isFirstRun = !prevAst || prevAst.entries.length === 0;
217
- // BEIM ERSTEN LAUF: IMMER VOLLSCAN, KEIN GIT-FILTER
218
- if (isFirstRun) {
219
- globalOutput.appendLine(`[cache] Erster Lauf erkannt, verwende Vollscan (${scannedAll.length} Dateien)`);
220
- scanned = scannedAll;
221
- }
222
- else if (useGit) {
223
- changed = (0, git_1.getChangedFiles)(workspaceRoot);
224
- if (changed && changed.size > 0) {
225
- const filtered = scannedAll.filter(f => changed.has(f.repositoryRelativePath));
226
- // Nur filtern, wenn genug Dateien gefunden wurden (mindestens 10% der Gesamtanzahl)
227
- if (filtered.length > 0 && filtered.length >= Math.max(1, scannedAll.length * 0.1)) {
228
- scanned = filtered;
229
- globalOutput.appendLine(`[git] Inkrementeller Modus: ${filtered.length}/${scannedAll.length} Dateien`);
230
- }
231
- else {
232
- globalOutput.appendLine(`[git] Zu wenige geänderte Dateien (${filtered.length}), verwende Vollscan`);
233
- scanned = scannedAll;
234
- }
235
- }
236
- else {
237
- globalOutput.appendLine(`[git] Keine geänderten Dateien erkannt, verwende Vollscan`);
238
- scanned = scannedAll;
239
- }
240
- }
241
- else {
242
- globalOutput.appendLine(`[git] Git-Filter deaktiviert, verwende Vollscan`);
243
- scanned = scannedAll;
244
- }
245
- const parsers = [new ts_js_1.TsJsParser(), new json_yaml_1.JsonYamlParser(), new python_1.PythonParser()];
246
- const allSymbols = [];
247
- const allDependencies = [];
248
- // AST-Hash-Cache bereits oben geladen, hier nur Map erstellen
249
- const astMap = new Map((prevAst?.entries ?? []).map(e => [e.path, e.hash]));
250
- let nextAstEntries = [];
251
- const concurrency = (vscode.workspace.getConfiguration('noyrax').get('concurrency') ?? 4);
252
- // Parallelisiertes Parsen mit Dependency-Extraktion
253
- // Track welche Dateien tatsächlich geparst wurden (nicht übersprungen)
254
- const actuallyParsedFiles = new Set();
255
- const parseResults = await (0, async_1.mapLimit)(scanned, Math.max(1, concurrency), async (f) => {
256
- const content = fs.readFileSync(f.absolutePath, 'utf8');
257
- const fileHash = (0, ast_cache_1.computeFileHash)(content);
258
- nextAstEntries.push({ path: f.repositoryRelativePath, hash: fileHash });
259
- // BEIM ERSTEN LAUF: IMMER PARSEN
260
- if (!isFirstRun) {
261
- const unchanged = astMap.get(f.repositoryRelativePath) === fileHash;
262
- if (unchanged) {
263
- globalOutput.appendLine(`[debug] ${f.repositoryRelativePath}: übersprungen (unchanged)`);
264
- return { symbols: [], dependencies: [], wasParsed: false };
265
- }
266
- }
267
- // Datei wird tatsächlich geparst
268
- actuallyParsedFiles.add(f.repositoryRelativePath);
269
- globalOutput.appendLine(`[debug] ${f.repositoryRelativePath}: wird geparst (${f.language})`);
270
- let symbols = [];
271
- let dependencies = [];
272
- if (f.language === 'ts' || f.language === 'js') {
273
- const tsParser = parsers[0];
274
- symbols = tsParser.parse(f.absolutePath, content).map(s => ({ ...s, filePath: f.repositoryRelativePath }));
275
- // SourceFile nach dem Parse verfügbar machen
276
- const sourceFile = tsParser.project.getSourceFile(f.absolutePath);
277
- if (sourceFile) {
278
- dependencies = (0, dependencies_1.extractTsJsDependencies)(sourceFile, f.repositoryRelativePath);
279
- globalOutput.appendLine(`[debug] ${f.repositoryRelativePath}: ${dependencies.length} dependencies gefunden`);
280
- }
281
- else {
282
- globalOutput.appendLine(`[debug] ${f.repositoryRelativePath}: SourceFile nicht gefunden`);
283
- }
284
- }
285
- else if (f.language === 'json' || f.language === 'yaml' || f.language === 'markdown') {
286
- symbols = parsers[1].parse(f.absolutePath, content).map(s => ({ ...s, filePath: f.repositoryRelativePath }));
287
- }
288
- else if (f.language === 'python') {
289
- symbols = parsers[2].parse(f.absolutePath, content).map(s => ({ ...s, filePath: f.repositoryRelativePath }));
290
- dependencies = (0, dependencies_1.extractPythonDependencies)(content, f.repositoryRelativePath);
291
- globalOutput.appendLine(`[debug] ${f.repositoryRelativePath}: ${dependencies.length} Python dependencies gefunden`);
292
- }
293
- return { symbols, dependencies, wasParsed: true };
294
- });
295
- parseResults.forEach(result => {
296
- allSymbols.push(...result.symbols);
297
- allDependencies.push(...result.dependencies);
298
- });
299
- // Logging für Debugging
300
- globalOutput.appendLine(`[parse] ${allSymbols.length} Symbole und ${allDependencies.length} Dependencies gefunden (${actuallyParsedFiles.size} Dateien geparst, ${scanned.length - actuallyParsedFiles.size} übersprungen)`);
301
- // Fallback nur als letzte Rettung: Wenn beim ersten Lauf keine Symbole gefunden wurden
302
- // (könnte auf Parser-Fehler oder leeres Projekt hinweisen)
303
- if (allSymbols.length === 0 && isFirstRun) {
304
- globalOutput.appendLine('[warn] Keine Symbole beim ersten Lauf gefunden. Möglicherweise Parser-Fehler oder leeres Projekt.');
305
- }
306
- // ========== PHASE 1.3: UNION-BILDUNG (ADDITIVE_DOCUMENTATION_PLAN.md, Abschnitt 6.2-6.3) ==========
307
- // 1. Dependencies-Union: Cache laden und mit neuen Dependencies mergen
308
- const depCacheFile = path.join(cacheDir, 'dependencies.json');
309
- const depCachePrev = (0, dependencies_cache_1.loadDependenciesCache)(depCacheFile);
310
- // WICHTIG: Nur Dateien, die tatsächlich geparst wurden (nicht übersprungen)
311
- const parsedFiles = actuallyParsedFiles;
312
- // Git-gelöschte Dateien erkennen (optional; leer wenn Git nicht verfügbar)
313
- const deletedFilesFromGit = (0, git_1.getDeletedFiles)(workspaceRoot) ?? new Set();
314
- if (deletedFilesFromGit.size > 0) {
315
- globalOutput.appendLine(`[git] ${deletedFilesFromGit.size} gelöschte Dateien erkannt`);
316
- }
317
- // Debug: Zeige welche Dateien als "geparst" markiert sind
318
- const parsedFilesList = Array.from(parsedFiles).slice(0, 10);
319
- globalOutput.appendLine(`[union] parsedFiles.size: ${parsedFiles.size}, deletedFilesFromGit.size: ${deletedFilesFromGit.size}`);
320
- if (parsedFiles.size > 0) {
321
- globalOutput.appendLine(`[union] Geparste Dateien (erste 10): ${parsedFilesList.join(', ')}`);
322
- }
323
- // Verwende buildDependenciesUnionWithDebug, um Debug-Info direkt zu erhalten
324
- const unionResult = (0, consolidation_1.buildDependenciesUnionWithDebug)(allDependencies, depCachePrev?.entries ?? [], parsedFiles, deletedFilesFromGit);
325
- const dependenciesUnion = unionResult.dependencies;
326
- const debug = unionResult.debug;
327
- const prevDepCount = (depCachePrev?.entries ?? []).length;
328
- globalOutput.appendLine(`[union] Dependencies: ${debug.newDeps} neu + ${prevDepCount} gecacht → ${dependenciesUnion.length} Union`);
329
- globalOutput.appendLine(`[union] - Beibehalten von ungeparsten: ${debug.keptFromUnparsed}`);
330
- globalOutput.appendLine(`[union] - Übersprungen (geparst): ${debug.skippedFromParsed}`);
331
- globalOutput.appendLine(`[union] - Übersprungen (gelöscht): ${debug.skippedFromDeleted}`);
332
- // 2. Symbol-Union: Index laden und mit neuen Symbolen mergen
333
- const indexFile = path.join(workspaceRoot, config.outputPath, 'index', 'symbols.jsonl');
334
- let symbolsPrev = [];
335
- if (fs.existsSync(indexFile)) {
336
- try {
337
- const lines = fs.readFileSync(indexFile, 'utf8').split(/\r?\n/).filter(Boolean);
338
- symbolsPrev = lines.map(l => {
339
- try {
340
- const row = JSON.parse(l);
341
- return {
342
- language: 'unknown',
343
- filePath: row.path,
344
- fullyQualifiedName: row.name,
345
- kind: row.kind,
346
- signature: row.signature ?? { name: row.name, parameters: [], returnType: '', visibility: 'public' }
347
- };
348
- }
349
- catch {
350
- return null;
351
- }
352
- }).filter(Boolean);
353
- }
354
- catch {
355
- // Index-Fehler: Fallback auf leere Liste
356
- symbolsPrev = [];
357
- }
358
- }
359
- // Build set of all scanned files (for union logic to exclude non-scanned files)
360
- // WICHTIG: Für die Union nehmen wir den vollen aktuellen Scan-Scope (scannedAll),
361
- // nicht die ggf. durch Git/Cache gefilterte Teilmenge (scanned). Dadurch gelten
362
- // produktive Dateien aus src/, die weiterhin vom Scanner gefunden werden, nicht
363
- // fälschlich als „deleted“ und bleiben im Symbol-Index, in docs/modules und
364
- // in den Dependency-Artefakten erhalten.
365
- const scannedFilesSet = new Set(scannedAll.map(f => f.repositoryRelativePath));
366
- const symbolsUnion = (0, consolidation_1.buildSymbolsUnion)(allSymbols, symbolsPrev, parsedFiles, deletedFilesFromGit, scannedFilesSet);
367
- globalOutput.appendLine(`[union] Symbole: ${allSymbols.length} neu + ${symbolsPrev.length} gecacht → ${symbolsUnion.length} Union`);
368
- // Von jetzt an: dependenciesUnion und symbolsUnion verwenden statt allDependencies/allSymbols
369
- // ========== ENDE UNION-BILDUNG ==========
370
- // AST-Cache speichern (nur wenn wir Einträge haben)
371
- if (nextAstEntries.length > 0) {
372
- (0, ast_cache_1.saveAstHashCache)(cacheDir, { version: 1, entries: nextAstEntries });
373
- }
374
- const outDir = path.join(workspaceRoot, config.outputPath, 'modules');
375
- if (!fs.existsSync(outDir))
376
- fs.mkdirSync(outDir, { recursive: true });
377
- // Load existing documentation for merge
378
- const existingDocs = new Map();
379
- if (fs.existsSync(outDir)) {
380
- const existingFiles = fs.readdirSync(outDir).filter(f => f.endsWith('.md'));
381
- for (const file of existingFiles) {
382
- const filePath = path.join(outDir, file);
383
- const content = fs.readFileSync(filePath, 'utf8');
384
- // Reverse safe file name to get original path
385
- const originalPath = file.replace(/__/g, '/').replace(/\.md$/, '');
386
- existingDocs.set(originalPath, content);
387
- }
388
- }
389
- const files = (0, index_1.generatePerFileDocs)(symbolsUnion, outDir, existingDocs);
390
- // Output-Hash-Cache laden
391
- const outHashFile = path.join(cacheDir, 'output-hashes.json');
392
- const prevOut = (0, output_cache_1.loadOutputHashCache)(outHashFile);
393
- const prevMap = new Map((prevOut?.entries ?? []).map(e => [e.path, e.hash]));
394
- const newEntries = [];
395
- for (const [repoRel, content] of files.entries()) {
396
- const safe = repoRel.replace(/[^a-zA-Z0-9_\-./]/g, '_').replace(/\//g, '__');
397
- const target = path.join(outDir, `${safe}.md`);
398
- const hash = (0, output_cache_1.computeContentHash)(content);
399
- newEntries.push({ path: safe + '.md', hash });
400
- const before = prevMap.get(safe + '.md');
401
- if (before !== hash || !fs.existsSync(target)) {
402
- fs.writeFileSync(target, content, 'utf8');
403
- }
404
- }
405
- // Output-Hash-Cache nur speichern, wenn wir Einträge erzeugt haben
406
- if (newEntries.length > 0) {
407
- (0, output_cache_1.saveOutputHashCache)(cacheDir, { version: 1, entries: newEntries });
408
- }
409
- // Symbol-Index mit Dependencies erzeugen (aus Union)
410
- const indexRows = (0, index_4.buildIndexFromSymbols)(symbolsUnion, dependenciesUnion);
411
- // Index nur überschreiben, wenn wir auch Symbole haben, sonst alten Index behalten
412
- if (symbolsUnion.length > 0) {
413
- (0, index_4.writeJsonlIndex)(indexRows, path.join(workspaceRoot, config.outputPath, 'index', 'symbols.jsonl'));
414
- }
415
- // Abhängigkeitsgraph generieren (aus Union)
416
- const systemDir = path.join(workspaceRoot, config.outputPath, 'system');
417
- if (!fs.existsSync(systemDir))
418
- fs.mkdirSync(systemDir, { recursive: true });
419
- const mermaidGraph = (0, dependency_graph_1.generateMermaidGraph)(dependenciesUnion);
420
- const depOverview = (0, dependency_graph_1.generateDependencyOverview)(dependenciesUnion);
421
- fs.writeFileSync(path.join(systemDir, 'DEPENDENCY_GRAPH.md'), mermaidGraph, 'utf8');
422
- fs.writeFileSync(path.join(systemDir, 'DEPENDENCIES.md'), depOverview, 'utf8');
423
- // Dependencies-Cache speichern (nur wenn Einträge vorhanden)
424
- if (dependenciesUnion.length > 0) {
425
- (0, dependencies_cache_1.saveDependenciesCache)(cacheDir, { version: 1, entries: dependenciesUnion });
426
- }
427
- // Signatur-Cache aktualisieren
428
- const prev = (0, signature_cache_1.loadSignatureCache)(path.join(cacheDir, 'signatures.json'));
429
- const entries = (0, index_3.computeCacheEntries)(symbolsUnion);
430
- // Signatur-Cache nur speichern, wenn wir Einträge haben
431
- if (entries.length > 0) {
432
- (0, signature_cache_1.saveSignatureCache)(cacheDir, { version: 1, entries });
433
- }
434
- const drift = (0, index_3.detectDrift)(prev, entries);
435
- if (drift.staleSymbols.length > 0) {
436
- vscode.window.showWarningMessage(`⚠️ Drift erkannt: ${drift.staleSymbols.length} Symbole mit geänderter Signatur.`);
437
- }
438
- // CHANGE_REPORT generieren (Phase 4)
439
- const changes = (0, change_report_1.extractChangesFromModuleDocs)(files);
440
- // prevDepCount bereits oben deklariert
441
- const depAdded = dependenciesUnion.length > prevDepCount ? dependenciesUnion.length - prevDepCount : 0;
442
- const depRemoved = prevDepCount > dependenciesUnion.length ? prevDepCount - dependenciesUnion.length : 0;
443
- // Validation-Status (vereinfacht, könnte aus validateDocumentationTs kommen)
444
- const validationErrors = 0; // Wird später aus Validator-Ergebnissen kommen
445
- const validationWarnings = drift.staleSymbols.length;
446
- const validationDetails = drift.staleSymbols.length > 0
447
- ? drift.staleSymbols.slice(0, 5).map(id => `Signatur-Abweichung: ${id}`)
448
- : [];
449
- const changeReport = (0, change_report_1.generateChangeReport)({
450
- runType: changed && changed.size > 0 ? 'incremental' : 'full',
451
- parsedFiles: scanned.length,
452
- skippedFiles: 0,
453
- symbolsAdded: changes.symbolsAdded,
454
- symbolsRemoved: changes.symbolsRemoved,
455
- symbolsChanged: changes.symbolsChanged,
456
- dependenciesAdded: depAdded,
457
- dependenciesRemoved: depRemoved,
458
- totalDependencies: dependenciesUnion.length,
459
- validationErrors,
460
- validationWarnings,
461
- validationDetails
462
- });
463
- fs.writeFileSync(path.join(systemDir, 'CHANGE_REPORT.md'), changeReport, 'utf8');
464
- globalOutput.appendLine(`[report] CHANGE_REPORT.md erstellt`);
465
- statusBar.text = "$(check) Dokumentation generiert";
466
- const dt = Date.now() - t0;
467
- globalOutput.appendLine(`[generate] Gescannt: ${scanned.length}, Symbole: ${symbolsUnion.length}, Dependencies: ${dependenciesUnion.length}, Dateien: ${files.size}, Dauer: ${dt}ms`);
468
- vscode.window.showInformationMessage(`✅ Dokumentation erfolgreich generiert! ${symbolsUnion.length} Symbole in ${files.size} Dateien (${dt}ms).`);
469
- vscode.commands.executeCommand('noyrax.refresh');
470
- }
471
- catch (error) {
472
- statusBar.text = "$(error) Fehler";
473
- vscode.window.showErrorMessage(`❌ Fehler bei der Dokumentations-Generierung: ${error}`);
474
- }
475
- finally {
476
- setTimeout(() => statusBar.dispose(), 3000);
477
- }
478
- }
479
- async function scanSystemTs() {
480
- const config = getConfig();
481
- const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
482
- statusBar.text = "$(sync~spin) Scanne System...";
483
- statusBar.show();
484
- try {
485
- const t0 = Date.now();
486
- const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
487
- if (!workspaceRoot) {
488
- throw new Error('Kein Workspace geöffnet');
489
- }
490
- const includeBackups = vscode.workspace.getConfiguration('noyrax').get('includeBackups') ?? false;
491
- const scanned = (0, scanner_1.scanWorkspace)({ workspaceRoot }, includeBackups);
492
- statusBar.text = "$(check) System gescannt";
493
- const dt = Date.now() - t0;
494
- globalOutput.appendLine(`[scan] Dateien: ${scanned.length}, Dauer: ${dt}ms`);
495
- vscode.window.showInformationMessage(`✅ System gescannt: ${scanned.length} Dateien (${dt}ms).`);
496
- vscode.commands.executeCommand('noyrax.refresh');
497
- }
498
- catch (error) {
499
- statusBar.text = "$(error) Fehler";
500
- vscode.window.showErrorMessage(`❌ Fehler beim System-Scan: ${error}`);
501
- }
502
- finally {
503
- setTimeout(() => statusBar.dispose(), 3000);
504
- }
505
- }
506
- async function searchDocumentation() {
507
- const query = await vscode.window.showInputBox({
508
- prompt: 'Suchbegriff eingeben',
509
- placeHolder: 'z.B. "function", "class", "import"'
510
- });
511
- if (!query) {
512
- return;
513
- }
514
- const searchType = await vscode.window.showQuickPick([
515
- { label: 'Volltext', value: 'content' },
516
- { label: 'Titel', value: 'title' },
517
- { label: 'Funktionen', value: 'function' }
518
- ], { placeHolder: 'Suchtyp wählen' });
519
- if (!searchType) {
520
- return;
521
- }
522
- const config = getConfig();
523
- const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
524
- statusBar.text = "$(search) Suche...";
525
- statusBar.show();
526
- try {
527
- const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '';
528
- const indexFile = path.join(workspaceRoot, config.outputPath, 'index', 'symbols.jsonl');
529
- if (!fs.existsSync(indexFile)) {
530
- throw new Error('Index nicht gefunden. Bitte erst Generierung ausführen.');
531
- }
532
- const lines = fs.readFileSync(indexFile, 'utf8').split(/\r?\n/).filter(Boolean);
533
- const rows = lines.map(l => { try {
534
- return JSON.parse(l);
535
- }
536
- catch {
537
- return null;
538
- } }).filter(Boolean);
539
- const filtered = rows.filter(r => String(r.name || '').toLowerCase().includes(query.toLowerCase()));
540
- const results = filtered.slice(0, 100).map(r => ({
541
- file: r.path,
542
- module: r.path,
543
- matches: [{ line: 1, content: r.name, context: r.kind }],
544
- score: 1
545
- }));
546
- showSearchResults(results, query);
547
- statusBar.text = "$(check) Suche abgeschlossen";
548
- }
549
- catch (error) {
550
- statusBar.text = "$(error) Fehler";
551
- vscode.window.showErrorMessage(`❌ Suchfehler: ${error}`);
552
- }
553
- finally {
554
- setTimeout(() => statusBar.dispose(), 3000);
555
- }
556
- }
557
- async function checkDriftTs() {
558
- const config = getConfig();
559
- const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
560
- statusBar.text = "$(sync~spin) Prüfe Drift...";
561
- statusBar.show();
562
- try {
563
- const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
564
- if (!workspaceRoot) {
565
- throw new Error('Kein Workspace geöffnet');
566
- }
567
- const cacheDir = path.join(workspaceRoot, config.outputPath, '.cache');
568
- // Lade vorherigen Signatur-Cache
569
- const prev = (0, signature_cache_1.loadSignatureCache)(path.join(cacheDir, 'signatures.json'));
570
- if (!prev) {
571
- globalOutput.appendLine('⚠️ Kein Signatur-Cache vorhanden. Führe zuerst "Generate" aus.');
572
- vscode.window.showWarningMessage('Kein Signatur-Cache vorhanden. Führe zuerst "Noyrax: Generate Documentation" aus.');
573
- statusBar.text = "$(warning) Kein Cache";
574
- return;
575
- }
576
- // Scanne aktuelle Symbole
577
- const includeBackups = vscode.workspace.getConfiguration('noyrax').get('includeBackups') ?? false;
578
- const scanned = (0, scanner_1.scanWorkspace)({ workspaceRoot }, includeBackups);
579
- const parsers = [new ts_js_1.TsJsParser(), new json_yaml_1.JsonYamlParser(), new python_1.PythonParser()];
580
- const allSymbols = [];
581
- for (const f of scanned) {
582
- const content = fs.readFileSync(f.absolutePath, 'utf8');
583
- if (f.language === 'ts' || f.language === 'js') {
584
- const parsed = parsers[0].parse(f.absolutePath, content).map(s => ({ ...s, filePath: f.repositoryRelativePath }));
585
- allSymbols.push(...parsed);
586
- }
587
- else if (f.language === 'json' || f.language === 'yaml' || f.language === 'markdown') {
588
- const parsed = parsers[1].parse(f.absolutePath, content).map(s => ({ ...s, filePath: f.repositoryRelativePath }));
589
- allSymbols.push(...parsed);
590
- }
591
- else if (f.language === 'python') {
592
- const parsed = parsers[2].parse(f.absolutePath, content).map(s => ({ ...s, filePath: f.repositoryRelativePath }));
593
- allSymbols.push(...parsed);
594
- }
595
- }
596
- const currentEntries = (0, index_3.computeCacheEntries)(allSymbols);
597
- // Drift-Erkennung
598
- const drift = (0, index_3.detectDrift)(prev, currentEntries);
599
- globalOutput.appendLine(`\n=== Drift-Analyse ===`);
600
- globalOutput.appendLine(`Geprüfte Symbole: ${currentEntries.length}`);
601
- globalOutput.appendLine(`Symbole mit Signatur-Abweichung: ${drift.staleSymbols.length}`);
602
- if (drift.staleSymbols.length === 0) {
603
- globalOutput.appendLine(`\n✅ Kein Drift erkannt - Dokumentation ist aktuell.`);
604
- vscode.window.showInformationMessage('✅ Kein Drift erkannt - Dokumentation ist aktuell.');
605
- statusBar.text = "$(check) Kein Drift";
606
- }
607
- else {
608
- globalOutput.appendLine(`\n⚠️ Signatur-Abweichungen:`);
609
- drift.staleSymbols.slice(0, 20).forEach(id => globalOutput.appendLine(` - ${id}`));
610
- if (drift.staleSymbols.length > 20) {
611
- globalOutput.appendLine(` ... und ${drift.staleSymbols.length - 20} weitere`);
612
- }
613
- vscode.window.showWarningMessage(`⚠️ Drift erkannt: ${drift.staleSymbols.length} Symbole mit geänderter Signatur. Führe "Generate" aus um zu synchronisieren.`);
614
- statusBar.text = `$(warning) ${drift.staleSymbols.length} Drift`;
615
- }
616
- }
617
- catch (error) {
618
- globalOutput.appendLine(`❌ Drift-Prüfung fehlgeschlagen: ${error}`);
619
- vscode.window.showErrorMessage(`❌ Drift-Prüfung fehlgeschlagen: ${error}`);
620
- statusBar.text = "$(error) Fehler";
621
- }
622
- finally {
623
- setTimeout(() => statusBar.dispose(), 5000);
624
- }
625
- }
626
- async function validateDocumentationTs() {
627
- const config = getConfig();
628
- const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
629
- statusBar.text = "$(sync~spin) Validiere Dokumentation...";
630
- statusBar.show();
631
- try {
632
- // Validiere alle Modul-Dateien und liefere Dateizahl korrekt aus
633
- const root = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '';
634
- const modulesDir = path.join(root, config.outputPath, 'modules');
635
- const exists = fs.existsSync(modulesDir);
636
- const fileCount = exists ? fs.readdirSync(modulesDir).filter(f => f.endsWith('.md')).length : 0;
637
- const cacheDir = path.join(vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '', config.outputPath, '.cache');
638
- const prev = (0, signature_cache_1.loadSignatureCache)(path.join(cacheDir, 'signatures.json'));
639
- // Versuch 1 (Sync-Modus): Symbole aus bestehendem Index lesen
640
- const indexFile = path.join(root, config.outputPath, 'index', 'symbols.jsonl');
641
- let allSymbols = [];
642
- if (fs.existsSync(indexFile)) {
643
- try {
644
- allSymbols = (0, index_4.readSymbolsFromIndex)(indexFile);
645
- globalOutput.appendLine(`[validate] Verwende ${allSymbols.length} Symbole aus Index (Sync-Modus)`);
646
- }
647
- catch (e) {
648
- const msg = e instanceof Error ? e.message : String(e);
649
- globalOutput.appendLine(`[validate] Konnte Index nicht lesen (${indexFile}), fallback auf Re-Parse: ${msg}`);
650
- allSymbols = [];
651
- }
652
- }
653
- // Fallback (Drift-Modus): Reparse für echte Coverage/Drift-Erkennung
654
- if (allSymbols.length === 0) {
655
- const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '';
656
- const includeBackups = vscode.workspace.getConfiguration('noyrax').get('includeBackups') ?? false;
657
- const scanned = (0, scanner_1.scanWorkspace)({ workspaceRoot }, includeBackups);
658
- const parsers = [new ts_js_1.TsJsParser(), new json_yaml_1.JsonYamlParser(), new python_1.PythonParser()];
659
- for (const f of scanned) {
660
- const content = fs.readFileSync(f.absolutePath, 'utf8');
661
- if (f.language === 'ts' || f.language === 'js') {
662
- const parsed = parsers[0].parse(f.absolutePath, content).map(s => ({ ...s, filePath: f.repositoryRelativePath }));
663
- allSymbols.push(...parsed);
664
- }
665
- else if (f.language === 'json' || f.language === 'yaml' || f.language === 'markdown') {
666
- const parsed = parsers[1].parse(f.absolutePath, content).map(s => ({ ...s, filePath: f.repositoryRelativePath }));
667
- allSymbols.push(...parsed);
668
- }
669
- else if (f.language === 'python') {
670
- const parsed = parsers[2].parse(f.absolutePath, content).map(s => ({ ...s, filePath: f.repositoryRelativePath }));
671
- allSymbols.push(...parsed);
672
- }
673
- }
674
- globalOutput.appendLine(`[validate] Parsed ${allSymbols.length} Symbole im Drift-Modus`);
675
- }
676
- const cfg = vscode.workspace.getConfiguration('noyrax');
677
- const thresholds = {
678
- classes: cfg.get('coverageThresholds.classes') ?? 0.9,
679
- interfaces: cfg.get('coverageThresholds.interfaces') ?? 0.9,
680
- methods: cfg.get('coverageThresholds.methods') ?? 0.9,
681
- functions: cfg.get('coverageThresholds.functions') ?? 0.8,
682
- };
683
- const coverage = (0, index_2.computeCoverage)(allSymbols, modulesDir, thresholds);
684
- const mdReport = (0, index_2.validateMarkdownDir)(modulesDir, allSymbols);
685
- // Drift-Erkennung: Signatur-Cache mit aktuellen Symbolen vergleichen
686
- const currentEntries = (0, index_3.computeCacheEntries)(allSymbols);
687
- const drift = (0, index_3.detectDrift)(prev, currentEntries);
688
- // Drift-Warnungen zu Validierungs-Warnungen hinzufügen
689
- const driftWarnings = [];
690
- if (drift.staleSymbols.length > 0) {
691
- driftWarnings.push(`Drift erkannt: ${drift.staleSymbols.length} Symbole mit geänderter Signatur`);
692
- drift.staleSymbols.slice(0, 10).forEach(id => {
693
- driftWarnings.push(` - Signatur-Abweichung: ${id}`);
694
- });
695
- if (drift.staleSymbols.length > 10) {
696
- driftWarnings.push(` ... und ${drift.staleSymbols.length - 10} weitere`);
697
- }
698
- }
699
- // Status-Klassifizierung (inkl. Drift)
700
- const signatureMismatches = mdReport.warnings.filter(w => w.includes('Signatur-Abweichung')).length;
701
- const totalSignatureMismatches = signatureMismatches + drift.staleSymbols.length;
702
- const statusReport = (0, status_1.computeValidationStatus)([...mdReport.errors, ...coverage.errors], [...(prev ? [] : ['Kein vorheriger Signatur-Cache vorhanden']), ...mdReport.warnings, ...driftWarnings], coverage.errors, totalSignatureMismatches, mdReport.errors);
703
- const results = {
704
- total_files: fileCount,
705
- valid_files: exists && mdReport.errors.length === 0 && coverage.errors.length === 0 ? fileCount : Math.max(0, fileCount - (mdReport.errors.length > 0 || coverage.errors.length > 0 ? 1 : 0)),
706
- invalid_files: (mdReport.errors.length > 0 || coverage.errors.length > 0) ? 1 : 0,
707
- warnings: [...(prev ? [] : ['Kein vorheriger Signatur-Cache vorhanden']), ...mdReport.warnings, ...driftWarnings],
708
- errors: exists ? [...mdReport.errors, ...coverage.errors] : ['modules/ fehlt'],
709
- status: statusReport,
710
- file_results: [
711
- { file: modulesDir, valid: exists && mdReport.errors.length === 0 && coverage.errors.length === 0, warnings: prev ? [...mdReport.warnings, ...driftWarnings] : ['Kein Cache', ...mdReport.warnings, ...driftWarnings], errors: exists ? [...mdReport.errors, ...coverage.errors] : ['Fehlend'], checks: { coverage } }
712
- ]
713
- };
714
- showValidationResults(results);
715
- if (globalStatusBar) {
716
- globalStatusBar.updateStatus(statusReport.status, statusReport.message);
717
- }
718
- if (!exists) {
719
- throw new Error('modules/ fehlt');
720
- }
721
- statusBar.text = "$(check) Validierung abgeschlossen";
722
- }
723
- catch (error) {
724
- statusBar.text = "$(error) Fehler";
725
- vscode.window.showErrorMessage(`❌ Validierungsfehler: ${error}`);
726
- }
727
- finally {
728
- setTimeout(() => statusBar.dispose(), 3000);
729
- }
730
- }
731
- async function syncDocumentation() {
732
- // Für jetzt nur eine Info-Nachricht
733
- vscode.window.showInformationMessage('🔄 Synchronisation wird in einer zukünftigen Version implementiert');
734
- }
735
- async function openDocumentationFile() {
736
- const config = getConfig();
737
- const docsPath = path.join(vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '', config.outputPath, 'modules');
738
- if (!fs.existsSync(docsPath)) {
739
- vscode.window.showErrorMessage('❌ Dokumentationsverzeichnis existiert nicht. Führen Sie zuerst "Docs: Scan System" aus.');
740
- return;
741
- }
742
- const files = fs.readdirSync(docsPath).filter(f => f.endsWith('.md'));
743
- if (files.length === 0) {
744
- vscode.window.showErrorMessage('❌ Keine Dokumentationsdateien gefunden.');
745
- return;
746
- }
747
- const selectedFile = await vscode.window.showQuickPick(files.map(f => ({
748
- label: f.replace('.md', ''),
749
- description: path.join(docsPath, f)
750
- })), { placeHolder: 'Dokumentationsdatei auswählen' });
751
- if (selectedFile) {
752
- const doc = await vscode.workspace.openTextDocument(selectedFile.description);
753
- await vscode.window.showTextDocument(doc);
754
- }
755
- }
756
- async function showSystemOverview() {
757
- const config = getConfig();
758
- const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '';
759
- const overviewDir = path.join(workspaceRoot, config.outputPath, 'system');
760
- // Zeige Auswahl für verschiedene Systemdokumente
761
- const options = [
762
- { label: 'Systemübersicht', value: 'SYSTEM_OVERVIEW.md' },
763
- { label: 'Abhängigkeitsgraph (Mermaid)', value: 'DEPENDENCY_GRAPH.md' },
764
- { label: 'Abhängigkeitsdetails', value: 'DEPENDENCIES.md' }
765
- ];
766
- const selected = await vscode.window.showQuickPick(options, {
767
- placeHolder: 'Systemdokument auswählen'
768
- });
769
- if (!selected)
770
- return;
771
- const overviewPath = path.join(overviewDir, selected.value);
772
- if (!fs.existsSync(overviewPath)) {
773
- if (selected.value === 'SYSTEM_OVERVIEW.md') {
774
- // Erzeuge minimale Systemübersicht on-the-fly
775
- if (!fs.existsSync(overviewDir))
776
- fs.mkdirSync(overviewDir, { recursive: true });
777
- const doc = `# Systemübersicht\n\n- Workspace: ${workspaceRoot}\n- Generiert: ${new Date().toISOString()}\n\nFühren Sie "Docs: Generate Documentation" aus, um Abhängigkeitsgraphen zu erstellen.\n`;
778
- fs.writeFileSync(overviewPath, doc, 'utf8');
779
- }
780
- else {
781
- vscode.window.showErrorMessage(`❌ ${selected.label} existiert nicht. Führen Sie zuerst "Docs: Generate Documentation" aus.`);
782
- return;
783
- }
784
- }
785
- const doc = await vscode.workspace.openTextDocument(overviewPath);
786
- await vscode.window.showTextDocument(doc);
787
- }
788
- function findSourceDirectories(workspaceRoot) {
789
- const srcDirs = [];
790
- function findSrcDirs(dir) {
791
- const entries = fs.readdirSync(dir, { withFileTypes: true });
792
- for (const entry of entries) {
793
- const fullPath = path.join(dir, entry.name);
794
- if (entry.isDirectory()) {
795
- if (entry.name === 'src') {
796
- srcDirs.push(fullPath);
797
- }
798
- else if (!entry.name.startsWith('.') && entry.name !== 'node_modules') {
799
- findSrcDirs(fullPath);
800
- }
801
- }
802
- }
803
- }
804
- findSrcDirs(workspaceRoot);
805
- return srcDirs;
806
- }
807
- function loadEnv(envFile) {
808
- const envPath = path.join(vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || '', envFile);
809
- if (fs.existsSync(envPath)) {
810
- const envContent = fs.readFileSync(envPath, 'utf8');
811
- const envVars = {};
812
- envContent.split('\n').forEach(line => {
813
- const [key, ...valueParts] = line.split('=');
814
- if (key && valueParts.length > 0) {
815
- envVars[key.trim()] = valueParts.join('=').trim();
816
- }
817
- });
818
- return envVars;
819
- }
820
- return {};
821
- }
822
- // Python-Runner entfernt (MVP ohne Python-Abhängigkeit)
823
- function showSearchResults(results, query) {
824
- const panel = vscode.window.createWebviewPanel('searchResults', `Suchergebnisse: "${query}"`, vscode.ViewColumn.One, { enableScripts: true });
825
- let html = `
826
- <!DOCTYPE html>
827
- <html>
828
- <head>
829
- <meta charset="UTF-8">
830
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
831
- <title>Suchergebnisse</title>
832
- <style>
833
- body { font-family: var(--vscode-font-family); padding: 20px; }
834
- .result { margin-bottom: 20px; padding: 15px; border: 1px solid var(--vscode-panel-border); border-radius: 5px; }
835
- .module-name { font-weight: bold; color: var(--vscode-textLink-foreground); }
836
- .match { margin: 10px 0; padding: 10px; background: var(--vscode-textCodeBlock-background); border-radius: 3px; }
837
- .line-number { color: var(--vscode-textPreformat-foreground); font-size: 0.9em; }
838
- .context { font-family: monospace; font-size: 0.9em; color: var(--vscode-textPreformat-foreground); }
839
- .score { float: right; color: var(--vscode-textLink-foreground); }
840
- </style>
841
- </head>
842
- <body>
843
- <h1>🔍 Suchergebnisse für "${query}"</h1>
844
- <p>${results.length} Module gefunden</p>
845
- `;
846
- for (const result of results) {
847
- html += `
848
- <div class="result">
849
- <div class="module-name">
850
- 📄 ${result.module}
851
- <span class="score">Score: ${result.score}</span>
852
- </div>
853
- <div style="font-size: 0.9em; color: var(--vscode-descriptionForeground);">
854
- ${result.file}
855
- </div>
856
- `;
857
- for (const match of result.matches.slice(0, 5)) { // Max 5 Matches pro Modul
858
- html += `
859
- <div class="match">
860
- <div class="line-number">Zeile ${match.line}:</div>
861
- <div>${escapeHtml(match.content)}</div>
862
- ${match.context ? `<div class="context">${escapeHtml(match.context)}</div>` : ''}
863
- </div>
864
- `;
865
- }
866
- if (result.matches.length > 5) {
867
- html += `<div style="font-style: italic;">... und ${result.matches.length - 5} weitere Treffer</div>`;
868
- }
869
- html += `</div>`;
870
- }
871
- html += `
872
- </body>
873
- </html>
874
- `;
875
- panel.webview.html = html;
876
- }
877
- function showValidationResults(results) {
878
- const panel = vscode.window.createWebviewPanel('validationResults', 'Dokumentations-Validierung', vscode.ViewColumn.One, { enableScripts: true });
879
- let html = `
880
- <!DOCTYPE html>
881
- <html>
882
- <head>
883
- <meta charset="UTF-8">
884
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
885
- <title>Validierungsergebnisse</title>
886
- <style>
887
- body { font-family: var(--vscode-font-family); padding: 20px; }
888
- .summary { margin-bottom: 20px; padding: 15px; border-radius: 5px; }
889
- .success { background: var(--vscode-testing-iconPassed); color: white; }
890
- .warning { background: var(--vscode-testing-iconQueued); color: white; }
891
- .error { background: var(--vscode-testing-iconFailed); color: white; }
892
- .file-result { margin: 10px 0; padding: 10px; border: 1px solid var(--vscode-panel-border); border-radius: 3px; }
893
- .error-list, .warning-list { margin: 5px 0; }
894
- .error-item, .warning-item { margin: 2px 0; padding: 2px 5px; border-radius: 3px; }
895
- .error-item { background: var(--vscode-inputValidation-errorBackground); }
896
- .warning-item { background: var(--vscode-inputValidation-warningBackground); }
897
- </style>
898
- </head>
899
- <body>
900
- <h1>📊 Dokumentations-Validierung</h1>
901
-
902
- <div class="summary ${results.status?.status === 'green' ? 'success' : results.status?.status === 'yellow' ? 'warning' : 'error'}">
903
- <h2>Status: ${results.status?.status === 'green' ? '🟢 GRÜN' : results.status?.status === 'yellow' ? '🟡 GELB' : '🔴 ROT'}</h2>
904
- <p><strong>Meldung:</strong> ${results.status?.message || 'Unbekannt'}</p>
905
- <hr>
906
- <p><strong>Gesamt:</strong> ${results.total_files} Dateien</p>
907
- <p><strong>✅ Gültig:</strong> ${results.valid_files}</p>
908
- <p><strong>❌ Ungültig:</strong> ${results.invalid_files}</p>
909
- <p><strong>⚠️ Warnungen:</strong> ${results.warnings.length}</p>
910
- <p><strong>❌ Fehler:</strong> ${results.errors.length}</p>
911
- ${results.status ? `
912
- <h3>Details</h3>
913
- <ul>
914
- <li>Coverage-Probleme: ${results.status.details.coverageIssues}</li>
915
- <li>Signatur-Abweichungen: ${results.status.details.signatureMismatches}</li>
916
- <li>Markdown-Probleme: ${results.status.details.markdownIssues}</li>
917
- </ul>
918
- ` : ''}
919
- </div>
920
- `;
921
- if (results.errors.length > 0) {
922
- html += `
923
- <div class="error">
924
- <h3>❌ Fehler</h3>
925
- <div class="error-list">
926
- `;
927
- for (const error of results.errors) {
928
- html += `<div class="error-item">${escapeHtml(error)}</div>`;
929
- }
930
- html += `</div></div>`;
931
- }
932
- if (results.warnings.length > 0) {
933
- html += `
934
- <div class="warning">
935
- <h3>⚠️ Warnungen</h3>
936
- <div class="warning-list">
937
- `;
938
- for (const warning of results.warnings) {
939
- html += `<div class="warning-item">${escapeHtml(warning)}</div>`;
940
- }
941
- html += `</div></div>`;
942
- }
943
- // Datei-spezifische Ergebnisse
944
- for (const fileResult of results.file_results) {
945
- if (!fileResult.valid || fileResult.warnings.length > 0) {
946
- html += `
947
- <div class="file-result">
948
- <h4>📄 ${path.basename(fileResult.file)}</h4>
949
- <p>Status: ${fileResult.valid ? '✅ Gültig' : '❌ Ungültig'}</p>
950
- `;
951
- if (fileResult.errors.length > 0) {
952
- html += `<div class="error-list">`;
953
- for (const error of fileResult.errors) {
954
- html += `<div class="error-item">${escapeHtml(error)}</div>`;
955
- }
956
- html += `</div>`;
957
- }
958
- if (fileResult.warnings.length > 0) {
959
- html += `<div class="warning-list">`;
960
- for (const warning of fileResult.warnings) {
961
- html += `<div class="warning-item">${escapeHtml(warning)}</div>`;
962
- }
963
- html += `</div>`;
964
- }
965
- html += `</div>`;
966
- }
967
- }
968
- html += `
969
- </body>
970
- </html>
971
- `;
972
- panel.webview.html = html;
973
- }
974
- function escapeHtml(text) {
975
- return text
976
- .replace(/&/g, '&amp;')
977
- .replace(/</g, '&lt;')
978
- .replace(/>/g, '&gt;')
979
- .replace(/"/g, '&quot;')
980
- .replace(/'/g, '&#39;');
981
- }
982
- function deactivate() { }
983
- exports.deactivate = deactivate;
984
- //# sourceMappingURL=extension.js.map