import * as vscode from 'vscode'; import { LinterContext } from './LinterContext'; import { LinterRule } from './rules/LinterRule'; import { SyntaxRule } from './rules/SyntaxRule'; import { BlockRule } from './rules/BlockRule'; export function validateTplDocument(document: vscode.TextDocument, collection: vscode.DiagnosticCollection) { if (document.languageId !== 'tpl') { return; } const ctx = new LinterContext(); const config = vscode.workspace.getConfiguration('tpl'); ctx.configuredTplVersion = config.get('version', 23); const text = document.getText(); const lines = text.split('\n'); // 1. Version prüfen const versionMatch = text.match(/tpl\s+1\.(\d+)\s+module/); if (versionMatch) { ctx.tplVersion = parseInt(versionMatch[1], 10); if (ctx.tplVersion < ctx.configuredTplVersion) { const linesToSearch = text.substring(0, versionMatch.index! + 30).split('\n'); ctx.addDiag(linesToSearch.length - 1, 0, versionMatch[0].length, `Das Modul nutzt eine alte TPL Version (1.${ctx.tplVersion}). Aktuell in den Settings definiert ist 1.${ctx.configuredTplVersion}.`, vscode.DiagnosticSeverity.Warning); } } // 2. Regeln laden const rules: LinterRule[] = [ new SyntaxRule(), new BlockRule() ]; // 3. Zeilenweise iterieren for (let i = 0; i < lines.length; i++) { const rawLine = lines[i]; const line = rawLine.trim(); ctx.resetLineStates(); // Basis-Lexer: Strings & Kommentare tracken (läuft vor den Regeln!) trackStrings(rawLine, line, ctx); if (ctx.isInternalStringLine && (ctx.inTripleDouble || ctx.inTripleSingle)) { continue; } if (line.startsWith('//') || line.startsWith('/*')) { if (line.startsWith('/*')) { ctx.inMultiLineComment = true; } continue; } if (ctx.inMultiLineComment) { if (line.includes('*/')) { ctx.inMultiLineComment = false; } continue; } if (line.length === 0) { continue; } // Regeln anwenden for (const rule of rules) { rule.checkLine(line, rawLine, i, ctx, lines); // Hier 'lines' ergänzen! } } // 4. Abschluss-Prüfungen durchführen for (const rule of rules) { if (rule.checkEnd) { rule.checkEnd(lines, ctx); } } // Diagnostics an VS Code übergeben collection.set(document.uri, ctx.diagnostics); } // Interne Hilfsfunktion für den Parser function trackStrings(rawLine: string, line: string, ctx: LinterContext) { const tripleDoubleCount = (rawLine.match(/"""/g) || []).length; const tripleSingleCount = (rawLine.match(/'''/g) || []).length; if (ctx.inTripleDouble) { ctx.isInternalStringLine = true; if (tripleDoubleCount % 2 !== 0) { ctx.inTripleDouble = false; ctx.isClosingString = true; } } else if (tripleDoubleCount % 2 !== 0) { ctx.inTripleDouble = true; ctx.justOpenedString = true; } if (ctx.inTripleSingle) { ctx.isInternalStringLine = true; if (tripleSingleCount % 2 !== 0) { ctx.inTripleSingle = false; ctx.isClosingString = true; } } else if (tripleSingleCount % 2 !== 0 && !ctx.justOpenedString) { ctx.inTripleSingle = true; ctx.justOpenedString = true; } if (ctx.justOpenedString) { ctx.stringNeedsSemicolon = !line.startsWith('"""') && !line.startsWith("'''"); } }