windmill-yaml-validator
v1.1.1
Published
YAML validator for Windmill flow, schedule, and trigger files
Downloads
2,186
Readme
Windmill YAML Validator
A TypeScript-based YAML validator for Windmill flow, schedule, and trigger files.
Overview
The windmill-yaml-validator provides runtime validation for Windmill YAML files. It is used by editor integrations to show validation errors while editing:
flow.yaml/flow.yml*.schedule.yaml/*.schedule.yml*.{http|websocket|kafka|nats|postgres|mqtt|sqs|gcp}_trigger.yaml(or.yml)
Features
- Unified validation API: One validator class for flow/schedule/trigger files
- Schema-based validation: Uses OpenFlow and backend OpenAPI-derived schemas
- Detailed error reporting: Returns comprehensive error information with specific paths to invalid fields
Installation
npm install windmill-yaml-validatorUsage
Basic Validation
import { WindmillYamlValidator } from "windmill-yaml-validator";
const validator = new WindmillYamlValidator();
const flowYaml = `
summary: Test Flow
value:
modules: []
`;
const flowResult = validator.validate(flowYaml, { type: "flow" });
const scheduleYaml = `
schedule: "0 0 12 * * *"
timezone: "UTC"
enabled: true
script_path: "f/jobs/daily_sync"
is_flow: false
`;
const scheduleResult = validator.validate(scheduleYaml, { type: "schedule" });
const triggerYaml = `
script_path: "f/triggers/http_handler"
is_flow: false
route_path: "api/webhook"
request_type: "sync"
authentication_method: "none"
http_method: "post"
is_static_website: false
workspaced_route: false
wrap_body: false
raw_string: false
`;
const triggerResult = validator.validate(triggerYaml, {
type: "trigger",
triggerKind: "http",
});
console.log(flowResult.errors, scheduleResult.errors, triggerResult.errors);Target Inference by Filename
import {
WindmillYamlValidator,
getValidationTargetFromFilename,
} from "windmill-yaml-validator";
const validator = new WindmillYamlValidator();
const target = getValidationTargetFromFilename(
"f/webhooks/order_created.http_trigger.yaml"
);
if (target) {
const result = validator.validate(fileContents, target);
console.log(result.errors);
}Error Handling
const invalidYaml = `
summary: 123 # Should be a string
value:
modules:
- id: step1
value:
type: rawscript
language: invalid_language # Invalid enum value
`;
const result = validator.validate(invalidYaml, { type: "flow" });
result.errors.forEach((error) => {
console.log(`Error at ${error.instancePath}: ${error.message}`);
// Example output:
// Error at /summary: must be string
// Error at /value/modules/0/value/language: must be equal to one of the allowed values
});API
WindmillYamlValidator
Main validator class for Windmill YAML validation.
Constructor
new WindmillYamlValidator();Initializes AJV validators for flow, schedule, and trigger schemas.
Methods
validate(doc: string, target: ValidationTarget)
Validates a YAML document against the selected target schema.
Parameters:
doc(string): YAML document stringtarget(ValidationTarget):{ type: "flow" }{ type: "schedule" }{ type: "trigger", triggerKind: "http" | "websocket" | "kafka" | "nats" | "postgres" | "mqtt" | "sqs" | "gcp" }
Returns:
{
parsed: YamlParserResult<unknown>; // Parsed YAML with source pointers
errors: ErrorObject[]; // Array of validation errors (empty if valid)
}Throws:
- Error if
docis not a string
getValidationTargetFromFilename(path: string)
Infers validation target from file naming conventions. Returns null for unsupported files.
Development
Building
npm run buildThe build process:
- Runs
gen_openflow_schema.shto generate:src/gen/openflow.jsonsrc/gen/schedule.jsonsrc/gen/triggers/*.json
- Removes discriminator mappings (not supported by AJV)
- Compiles TypeScript to JavaScript
Testing
npm testRun tests in watch mode:
npm test:watchTesting locally with the CLI
The Windmill CLI (cli/) is Deno-based and imports this package via npm:[email protected]. Since Deno's npm: specifier always resolves from the npm registry, local testing requires a compatibility script that makes the TypeScript sources directly importable by Deno.
The deno-compat.sh script handles two Deno requirements:
- Adding
.tsextensions to relative imports - Adding
with { type: "json" }assertions to JSON imports
Steps:
- Apply Deno compatibility:
./deno-compat.sh- Add the following entries to
cli/deno.jsonimports:
"npm:[email protected]": "../windmill-yaml-validator/src/index.ts",
"ajv": "npm:ajv@^8.17.1",
"@stoplight/yaml": "npm:@stoplight/yaml@^4.3.0"- Run the CLI directly with Deno:
cd ../cli
deno run -A src/main.ts lint- When done, restore everything:
./deno-compat.sh -r # restore original imports
# Remove the 3 import map lines from cli/deno.jsonSchema Generation
The validator uses a JSON schema generated from the OpenAPI specification:
./gen_openflow_schema.shThis script:
- Converts
openflow.openapi.yamlandbackend/windmill-api/openapi.yamlinto JSON - Removes discriminator mappings for AJV compatibility
- Removes the
ToolValuediscriminator entirely (see below) - Generates standalone schedule/trigger schemas for CLI file shape
Why Remove Discriminators?
The OpenFlow schema uses OpenAPI discriminators for efficient type resolution in oneOf schemas. However, AJV's discriminator support has limitations:
- Discriminator Mappings: Not fully supported by AJV, so they are removed from all schemas
- ToolValue Discriminator: Completely removed because
FlowModuleToolusesallOfcomposition, which prevents AJV from finding the discriminator property (tool_type) at the expected location
Impact: Without discriminators, AJV falls back to standard oneOf validation, which:
- Tests each alternative until one matches
- Is slightly slower but still performant for our use case
- Provides the same validation correctness
- Works correctly with complex schema compositions like
allOf
Breaking Change
FlowValidator and validateFlow() were replaced by WindmillYamlValidator and validate(doc, target).
