Add Prettier and ESLint tooling (Refs #77)

This commit is contained in:
2026-10-09 15:56:13 -04:00
parent 8ed059b8d3
commit 16469e2d43
711 changed files with 99737 additions and 28286 deletions
+69 -20
View File
@@ -1,34 +1,61 @@
import { describe, expect, it } from 'vitest';
import { inspectConfig, type ConfigLayer } from '../../src/lib/server/fleet/config-inspect.js';
import { composeServerCfg } from '../../src/lib/server/fleet/config-compose.js';
import { addConfigSetting, changeConfigValue, configWarnings } from '../../src/lib/config-workbench.js';
import {
addConfigSetting,
changeConfigValue,
configWarnings
} from '../../src/lib/config-workbench.js';
const base = (text: string): ConfigLayer => ({ text, source: { id: 1, name: 'Base', version: 2, kind: 'baseline' } });
const overlay = (id: number, text: string): ConfigLayer => ({ text, source: { id, name: `Overlay ${id}`, version: 3, kind: 'config' } });
const base = (text: string): ConfigLayer => ({
text,
source: { id: 1, name: 'Base', version: 2, kind: 'baseline' }
});
const overlay = (id: number, text: string): ConfigLayer => ({
text,
source: { id, name: `Overlay ${id}`, version: 3, kind: 'config' }
});
describe('config source inspection', () => {
it('traces the baseline and every override in actual ID order', () => {
const baseline = base('set g_inactivity "190"\r\nset sv_voice "1"\r\n');
const overlays = [overlay(5, 'set g_inactivity "60"'), overlay(2, 'set g_inactivity "0"')];
const result = inspectConfig(baseline, overlays, 't5', 'zombie_theater');
expect(result.text).toBe(composeServerCfg(baseline.text, overlays.map(o => ({ id: o.source.id!, text: o.text })), 't5', 'zombie_theater'));
const setting = result.settings.find(s => s.key === 'g_inactivity')!;
expect(result.text).toBe(
composeServerCfg(
baseline.text,
overlays.map((o) => ({ id: o.source.id!, text: o.text })),
't5',
'zombie_theater'
)
);
const setting = result.settings.find((s) => s.key === 'g_inactivity')!;
expect(setting.value).toBe('"60"');
expect(setting.source.id).toBe(5);
expect(setting.history.map(h => h.source.id)).toEqual([1, 2, 5]);
expect(result.settings.find(s => s.key === 'sv_voice')?.source.id).toBe(1);
expect(setting.history.map((h) => h.source.id)).toEqual([1, 2, 5]);
expect(result.settings.find((s) => s.key === 'sv_voice')?.source.id).toBe(1);
});
it('explains duplicates within baselines and within overlays', () => {
const result = inspectConfig(base('set x 1\nset x 2'), [overlay(2, 'set x 3\nset x 4')], null, null);
const result = inspectConfig(
base('set x 1\nset x 2'),
[overlay(2, 'set x 3\nset x 4')],
null,
null
);
expect(result.text).toBe('set x 1\nset x 4\n');
expect(result.settings[0].history.map(h => h.value)).toEqual(['1', '2', '3', '4']);
expect(result.settings[0].history.map((h) => h.value)).toEqual(['1', '2', '3', '4']);
expect(result.settings[0].value).toBe('4');
expect(result.warnings.filter(w => w.includes('also assigned'))).toHaveLength(2);
expect(result.warnings.filter((w) => w.includes('also assigned'))).toHaveLength(2);
});
it('uses final file order for differently cased keys rather than assuming layer order', () => {
const result = inspectConfig(base('set X 1'), [overlay(2, 'set x 2'), overlay(3, 'set X 3')], null, null);
const result = inspectConfig(
base('set X 1'),
[overlay(2, 'set x 2'), overlay(3, 'set X 3')],
null,
null
);
expect(result.text).toContain('set X 3');
expect(result.settings).toHaveLength(1);
expect(result.settings[0].value).toBe('2');
@@ -36,35 +63,55 @@ describe('config source inspection', () => {
});
it('traces map overrides across set, seta, and bare assignments', () => {
const result = inspectConfig(base('set sv_maprotation "old"\nseta SV_MAPROTATION "older"\nsv_maprotation "last"'), [overlay(2, 'set sv_maprotation "overlay"')], 't5', 'zombie_theater');
const result = inspectConfig(
base('set sv_maprotation "old"\nseta SV_MAPROTATION "older"\nsv_maprotation "last"'),
[overlay(2, 'set sv_maprotation "overlay"')],
't5',
'zombie_theater'
);
const setting = result.settings[0];
expect(setting.key).toBe('sv_maprotation');
expect(setting.value).toBe('"map zombie_theater"');
expect(setting.source.kind).toBe('map');
expect(setting.history.map(h => h.value)).toEqual(['"old"', '"overlay"', '"older"', '"last"', '"map zombie_theater"']);
expect(setting.history.map((h) => h.value)).toEqual([
'"old"',
'"overlay"',
'"older"',
'"last"',
'"map zombie_theater"'
]);
expect(result.text.match(/set sv_maprotation/g)).toHaveLength(1);
});
it('preserves T6 map variants and does not invent map selection for unknown maps', () => {
const t6 = inspectConfig(base('set sv_voice 1'), [], 't6', 'zm_transit', 'town');
expect(t6.settings.find(s => s.key === 'sv_maprotation')?.value).toContain('execgts zm_standard_town.cfg');
expect(t6.settings.find((s) => s.key === 'sv_maprotation')?.value).toContain(
'execgts zm_standard_town.cfg'
);
const legacy = inspectConfig(base('set sv_maprotation "custom"'), [], 't5', 'unknown');
expect(legacy.settings[0].source.kind).toBe('baseline');
expect(legacy.text).toBe('set sv_maprotation "custom"\n');
});
it('reports ignored overlay commands while retaining raw baseline commands', () => {
const result = inspectConfig(base('exec custom.cfg\nset a 1'), [overlay(2, 'seta a 2\nSET a 3\n// note\nset b 4')], null, null);
expect(result.warnings.filter(w => w.includes('ignored'))).toHaveLength(2);
const result = inspectConfig(
base('exec custom.cfg\nset a 1'),
[overlay(2, 'seta a 2\nSET a 3\n// note\nset b 4')],
null,
null
);
expect(result.warnings.filter((w) => w.includes('ignored'))).toHaveLength(2);
expect(result.text).toContain('exec custom.cfg');
expect(result.settings.find(s => s.key === 'a')?.value).toBe('1');
expect(result.settings.find(s => s.key === 'b')?.source.id).toBe(2);
expect(result.settings.find((s) => s.key === 'a')?.value).toBe('1');
expect(result.settings.find((s) => s.key === 'b')?.source.id).toBe(2);
});
});
describe('config settings editor', () => {
it('adds a structured value without altering existing content or line endings', () => {
expect(addConfigSetting('// comment\r\nset x 1', 'sv_hostname', 'Cherry lobby')).toBe('// comment\r\nset x 1\r\nset sv_hostname "Cherry lobby"\r\n');
expect(addConfigSetting('// comment\r\nset x 1', 'sv_hostname', 'Cherry lobby')).toBe(
'// comment\r\nset x 1\r\nset sv_hostname "Cherry lobby"\r\n'
);
expect(addConfigSetting('', 'g_inactivity', '0')).toBe('set g_inactivity 0\n');
});
@@ -76,7 +123,9 @@ describe('config settings editor', () => {
});
it('changes only the selected assignment, preserving CRLF, spacing and raw commands', () => {
const text = '// note\r\n set a "1" // original\r\nexec other.cfg\r\nset a 5\n';
expect(changeConfigValue(text, 1, '"2" // changed')).toBe('// note\r\n set a "2" // changed\r\nexec other.cfg\r\nset a 5\n');
expect(changeConfigValue(text, 1, '"2" // changed')).toBe(
'// note\r\n set a "2" // changed\r\nexec other.cfg\r\nset a 5\n'
);
});
it('does not silently rewrite unsupported lines and reports missing values', () => {
expect(changeConfigValue('seta a 1', 0, '2')).toBe('seta a 1');