UNPKG

windmill-yaml-validator

Version:

YAML validator for Windmill flow, schedule, and trigger files

119 lines (118 loc) 4.38 kB
"use strict"; 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;