Refresh Configs with browser editing and source inspection
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
export interface ConfigSource {
|
||||
id: number | null;
|
||||
name: string;
|
||||
version: number | null;
|
||||
kind: 'baseline' | 'config' | 'map';
|
||||
draft?: boolean;
|
||||
}
|
||||
|
||||
export interface ConfigAssignment {
|
||||
value: string;
|
||||
source: ConfigSource;
|
||||
line: number;
|
||||
}
|
||||
|
||||
export interface ConfigSetting {
|
||||
key: string;
|
||||
value: string;
|
||||
source: ConfigSource;
|
||||
history: ConfigAssignment[];
|
||||
}
|
||||
|
||||
export interface ConfigInspection {
|
||||
text: string;
|
||||
settings: ConfigSetting[];
|
||||
sources: ConfigSource[];
|
||||
warnings: string[];
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
export interface ConfigServer { name: string; game: string | null; map: string | null; }
|
||||
|
||||
/** The same lowercase `set` grammar that the overlay composer accepts. */
|
||||
export function configLines(text: string) {
|
||||
return text.split(/\r?\n/).flatMap((line, index) => {
|
||||
const match = /^(\s*set\s+)(\S+)(\s+)(.*)$/.exec(line);
|
||||
return match ? [{ index, key: match[2], value: match[4], prefix: match[1] + match[2] + match[3] }] : [];
|
||||
});
|
||||
}
|
||||
|
||||
export function changeConfigValue(text: string, index: number, value: string): string {
|
||||
// Keep every separator, comment and unrelated line byte-for-byte intact.
|
||||
const parts = text.split(/(\r?\n)/);
|
||||
const entry = configLines(text).find(line => line.index === index);
|
||||
if (entry) parts[index * 2] = entry.prefix + value.replace(/[\r\n]/g, '');
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
export function configWarnings(text: string, overlay: boolean): string[] {
|
||||
const warnings: string[] = [];
|
||||
const seen = new Map<string, number>();
|
||||
for (const entry of configLines(text)) {
|
||||
const key = entry.key.toLowerCase();
|
||||
if (seen.has(key)) warnings.push(`Line ${entry.index + 1}: ${entry.key} is also assigned on line ${seen.get(key)}.`);
|
||||
seen.set(key, entry.index + 1);
|
||||
if (!entry.value.trim() || entry.value.trim().startsWith('//')) warnings.push(`Line ${entry.index + 1}: ${entry.key} has no value.`);
|
||||
}
|
||||
if (overlay) text.split(/\r?\n/).forEach((line, index) => {
|
||||
if (line.trim() && !/^\s*\/\//.test(line) && !/^\s*set\s+\S+\s+/.test(line)) {
|
||||
warnings.push(`Line ${index + 1} is ignored by overlays. Use set KEY VALUE.`);
|
||||
}
|
||||
});
|
||||
if (/^\s*(?:(?:set|seta)\s+)?sv_maprotation\s+/im.test(text)) {
|
||||
warnings.push('For recognized maps, the server’s selected map overrides sv_maprotation.');
|
||||
}
|
||||
return warnings;
|
||||
}
|
||||
Reference in New Issue
Block a user