bmc-tpl-code-all-around/src/core/rules/MetadataRule.ts

80 lines
3.8 KiB
TypeScript
Raw Normal View History

import * as vscode from 'vscode';
import { LinterRule } from './LinterRule';
import { LinterContext } from '../LinterContext';
export class MetadataRule implements LinterRule {
public checkLine(line: string, rawLine: string, lineIdx: number, ctx: LinterContext, lines: string[]): void {
if (line.startsWith('metadata') && ctx.inBlock === 'none') {
ctx.inModuleMetadata = true;
ctx.hasModuleMetadata = true;
ctx.moduleMetadataBlockLine = lineIdx;
ctx.foundModuleMetadata.clear();
return;
}
if (ctx.inModuleMetadata) {
const config = vscode.workspace.getConfiguration('tpl');
// Felder erfassen
if (line.match(/^origin\b/)) ctx.foundModuleMetadata.add('origin');
if (line.match(/^author\b/)) ctx.foundModuleMetadata.add('author');
if (line.match(/^products\b/)) ctx.foundModuleMetadata.add('products');
if (line.match(/^publishers\b/)) ctx.foundModuleMetadata.add('publishers');
// Tree-Path Sonderprüfung
if (line.match(/^tree_path\b/)) {
ctx.foundModuleMetadata.add('tree_path');
if (config.get<boolean>('metadata.require.treePath', true)) {
this.checkTreePath(line, rawLine, lineIdx, ctx, config);
}
}
// Block-Ende: Pflichtfelder abgleichen
if (line.startsWith('end metadata')) {
ctx.inModuleMetadata = false;
this.checkRequiredFields(ctx, config);
}
}
}
private checkTreePath(line: string, rawLine: string, lineIdx: number, ctx: LinterContext, config: vscode.WorkspaceConfiguration) {
const minLevels = config.get<number>('metadata.treePath.minLevels', 3);
const staticNodes = config.get<string[]>('metadata.treePath.staticNodes', ['Grafing']);
// Extrahiert die Strings aus tree_path := 'A', 'B';
const match = line.match(/tree_path\s*:=\s*(.*);/);
if (match) {
const paths = match[1].split(',').map(s => s.trim().replace(/^['"]|['"]$/g, ''));
if (paths.length < minLevels) {
ctx.addDiag(lineIdx, 0, rawLine.length, `Der tree_path muss mindestens ${minLevels} Ebenen haben!`, vscode.DiagnosticSeverity.Error);
}
for (let i = 0; i < staticNodes.length; i++) {
if (paths[i] !== staticNodes[i]) {
ctx.addDiag(lineIdx, 0, rawLine.length, `Die tree_path Ebene ${i + 1} muss zwingend '${staticNodes[i]}' lauten!`, vscode.DiagnosticSeverity.Error);
}
}
}
}
private checkRequiredFields(ctx: LinterContext, config: vscode.WorkspaceConfiguration) {
const requiredFields: string[] = [];
if (config.get<boolean>('metadata.require.origin', true)) requiredFields.push('origin');
if (config.get<boolean>('metadata.require.author', true)) requiredFields.push('author');
if (config.get<boolean>('metadata.require.products', true)) requiredFields.push('products');
if (config.get<boolean>('metadata.require.publishers', true)) requiredFields.push('publishers');
if (config.get<boolean>('metadata.require.treePath', true)) requiredFields.push('tree_path');
const missing = requiredFields.filter(f => !ctx.foundModuleMetadata.has(f));
if (missing.length > 0 && ctx.moduleMetadataBlockLine !== -1) {
const diag = ctx.addDiag(ctx.moduleMetadataBlockLine, 0, 8, `Fehlende Pflicht-Metadaten (Modul-Ebene): ${missing.join(', ')}`, vscode.DiagnosticSeverity.Error);
diag.code = 'missing_module_metadata';
}
}
public checkEnd(lines: string[], ctx: LinterContext): void {
// empty
}
}