email-dns-tools/assets/scripts/tools/DnsTool.js
2026-01-14 15:46:37 +01:00

73 lines
1.6 KiB
JavaScript

import { ValidationError } from "../ValidationError.js";
export class DnsTool {
static allowWhitespaceAroundSeparator;
static fields = [];
constructor(text) {
this.text = text;
}
tokenize() {
throw new Error("Unimplemented");
}
getKeyValues() {
const result = [];
for (const token of this.tokenize()) {
const key = token.match(/^\w*/)[0];
const field = this.constructor.fields.find(f => f.key === key);
if (!field) {
throw new ValidationError(`Unknown field: ${key}`);
}
const wsp = this.constructor.allowWhitespaceAroundSeparator ? "\\s*" : "";
const separator = new RegExp(wsp + field.separator + wsp);
const value = token.split(separator)[1];
if (!value) {
throw new ValidationError(`Field "${key}" is missing a value`);
}
result.push({ key, value });
}
return result;
}
validate() {
const values = this.getKeyValues();
for (const field of this.constructor.fields) {
if (field.isRequired && !values.some(v => v.key === field.key)) {
throw new ValidationError(`Field "${field.key}" is required`);
}
}
let lastPos = 0;
for (let i = 0; i < values.length; i++) {
const input = values[i];
const field = this.constructor.fields.find(f => f.key === input.key);
if (!field) {
throw new ValidationError(`Unknown field: ${input.key}`);
}
if (field.position < lastPos) {
const lastField = this.constructor.fields.find(f => f.key === values[i-1].key);
throw new ValidationError(`Field "${lastField.key}" must come after "${field.key}"`);
}
field.validate(input.value);
lastPos = field.position;
}
return true;
}
}