windmill-yaml-validator
Version:
YAML validator for Windmill flow, schedule, and trigger files
119 lines (118 loc) • 4.38 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WindmillYamlValidator = exports.SUPPORTED_TRIGGER_KINDS = void 0;
exports.getValidationTargetFromFilename = getValidationTargetFromFilename;
const ajv_1 = __importDefault(require("ajv"));
const yaml_1 = require("@stoplight/yaml");
const openflow_json_1 = __importDefault(require("../gen/openflow.json"));
const schedule_json_1 = __importDefault(require("../gen/schedule.json"));
const gcp_json_1 = __importDefault(require("../gen/triggers/gcp.json"));
const http_json_1 = __importDefault(require("../gen/triggers/http.json"));
const kafka_json_1 = __importDefault(require("../gen/triggers/kafka.json"));
const mqtt_json_1 = __importDefault(require("../gen/triggers/mqtt.json"));
const nats_json_1 = __importDefault(require("../gen/triggers/nats.json"));
const postgres_json_1 = __importDefault(require("../gen/triggers/postgres.json"));
const sqs_json_1 = __importDefault(require("../gen/triggers/sqs.json"));
const websocket_json_1 = __importDefault(require("../gen/triggers/websocket.json"));
const email_json_1 = __importDefault(require("../gen/triggers/email.json"));
exports.SUPPORTED_TRIGGER_KINDS = [
"http",
"websocket",
"kafka",
"nats",
"postgres",
"mqtt",
"sqs",
"gcp",
"email",
];
const TRIGGER_SCHEMAS = {
http: http_json_1.default,
websocket: websocket_json_1.default,
kafka: kafka_json_1.default,
nats: nats_json_1.default,
postgres: postgres_json_1.default,
mqtt: mqtt_json_1.default,
sqs: sqs_json_1.default,
gcp: gcp_json_1.default,
email: email_json_1.default,
};
/**
* Infers validation target from file name conventions used by Windmill sync.
*/
function getValidationTargetFromFilename(filePath) {
const path = filePath.toLowerCase();
if (/[/\\]flow\.ya?ml$/.test(path) || /^flow\.ya?ml$/.test(path)) {
return { type: "flow" };
}
if (/\.schedule\.ya?ml$/.test(path)) {
return { type: "schedule" };
}
const triggerMatch = path.match(/\.(http|websocket|kafka|nats|postgres|mqtt|sqs|gcp|email)_trigger\.ya?ml$/);
if (triggerMatch) {
return {
type: "trigger",
triggerKind: triggerMatch[1],
};
}
return null;
}
/**
* Unified YAML validator for Windmill flow, schedule, and trigger files.
*/
class WindmillYamlValidator {
validateFlow;
validateSchedule;
validateTrigger;
constructor() {
const ajv = new ajv_1.default({
strict: false,
allErrors: true,
discriminator: true,
validateFormats: false,
});
for (const [name, schema] of Object.entries(openflow_json_1.default.components.schemas)) {
ajv.addSchema(schema, `#/components/schemas/${name}`);
}
this.validateFlow = ajv.getSchema("#/components/schemas/OpenFlow");
this.validateSchedule = ajv.compile(schedule_json_1.default);
this.validateTrigger = Object.fromEntries(exports.SUPPORTED_TRIGGER_KINDS.map((kind) => [kind, ajv.compile(TRIGGER_SCHEMAS[kind])]));
}
/**
* Validates a Windmill YAML document based on the selected target.
* @param doc - The YAML document as string
* @param target - Which Windmill schema to validate against
*/
validate(doc, target) {
if (typeof doc !== "string") {
throw new Error("Document must be a string");
}
const parsed = (0, yaml_1.parseWithPointers)(doc);
const { data } = parsed;
let validator;
if (target.type === "flow") {
validator = this.validateFlow;
}
else if (target.type === "schedule") {
validator = this.validateSchedule;
}
else {
validator = this.validateTrigger[target.triggerKind];
if (!validator) {
throw new Error(`Unsupported trigger kind: ${target.triggerKind}`);
}
}
const ok = validator(data);
if (ok) {
return { parsed, errors: [] };
}
return {
parsed,
errors: validator.errors || [],
};
}
}
exports.WindmillYamlValidator = WindmillYamlValidator;