2026-10-11 02:31:12 +00:00
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 < number > ( '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 ) {
2026-10-11 04:11:11 +00:00
rule . checkLine ( line , rawLine , i , ctx , lines ) ; // Hier 'lines' ergänzen!
2026-10-11 02:31:12 +00:00
}
}
// 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 ( "'''" ) ;
}
}