Skip to content

Validation Rules

Validation ensures that Wire-DSL files are unambiguous and renderable. Validations occur in multiple phases during processing.

Checks the structure of the DSL itself during parsing.

Phase 2: Semantic Validation (IR Generator)

Section titled “Phase 2: Semantic Validation (IR Generator)”

Checks the logic and consistency after parsing.

Phase 3: Layout Validation (Layout Engine)

Section titled “Phase 3: Layout Validation (Layout Engine)”

Checks constraints and sizing validity during layout calculation.


Performed by the Parser during tokenization and parsing.

  • ✅ A project block can include one style block (optional)
  • ✅ A project block must have at least one screen
  • ✅ A screen block must have exactly one root layout
  • ✅ All layout blocks must be properly closed with braces
  • ✅ All properties must follow the key: value format

Invalid Example:

project "App" {
// ERROR: missing screen block
}

Valid Example:

project "App" {
style {
density: "normal"
spacing: "md"
radius: "md"
stroke: "normal"
font: "base"
}
screen Home {
layout stack { }
}
}
  • ✅ All properties must use format key: value
  • ✅ String values must be quoted: "value"
  • ✅ Numeric values must be unquoted: 12
  • ✅ Enum values must be unquoted: primary, vertical, md
  • ✅ Boolean values must be unquoted: true, false

Valid:

component Button text: "Click me" variant: primary checked: true
component Input label: "Email" placeholder: "your@email.com"
component Separate size: md

Invalid:

component Button "Click me" // ❌ Missing `text:` key
component Button text: Click // ❌ String not quoted
component Input label: "Email" placeholder: @ // ❌ Invalid character
  • ✅ Component names must exist in the catalog (built-in types)
  • ✅ Property names must be valid for that component
  • ✅ Property values must match expected types

Valid:

component Heading text: "Dashboard"
component Button text: "Submit" variant: primary
component Badge text: "New" variant: success

Invalid:

component FakeComponent { ... } // ❌ Component doesn't exist
component Button unknownProp: "val" // ❌ Invalid property
component Input text: 123 // ❌ Expected string, got number
  • ✅ Layouts must contain at least one child (component or nested layout)
  • split layout must have exactly 2 children
  • grid layout must have at least one cell
  • ✅ All braces must be properly matched
  • ✅ Layout nesting depth recommended ≤ 5 levels

Invalid:

layout split(sidebar: 260) {
layout stack { }
// ERROR: split requires exactly 2 children
}

Valid:

layout split(sidebar: 260, gap: md) {
layout stack { } // Child 1: sidebar
layout stack { } // Child 2: content
}
  • ✅ Screen names must be in CamelCase
  • ✅ All identifiers must be unique within project scope
  • ✅ Names cannot contain special characters or spaces

Valid:

screen UserDashboard { ... }
screen AdminPanel { ... }

Invalid:

screen user-dashboard { ... } // ❌ Should be CamelCase
screen User Dashboard { ... } // ❌ Spaces not allowed
screen UserDashboard { ... }
screen UserDashboard { ... } // ❌ Duplicate name

Performed by the IR Generator after parsing.

  • ✅ Custom components (define Component) and custom layouts (define Layout) can be composed
  • ✅ Circular references across components and layouts are rejected
  • ✅ All referenced components/layouts should exist
  • ✅ Defining before first use is recommended (late definition may emit warnings)

Invalid:

project "App" {
style { ... }
screen Home {
layout stack {
component CustomButton // ERROR: not defined
}
}
}

Valid:

project "App" {
style { ... }
define Component "CustomButton" {
layout stack(direction: horizontal, gap: md) {
component Icon type: "star"
component Button text: "Action" variant: primary
}
}
screen Home {
layout stack {
component CustomButton // OK: defined above
}
}
}
  • ✅ Layout name must match ^[a-z][a-z0-9_]*$
  • ✅ Body must contain exactly one root layout
  • ✅ Body must contain exactly one component Children placeholder
  • component Children cannot be used outside define Layout
  • ✅ Every use of a defined layout must provide exactly one child block

Invalid:

define Layout "ScreenDefault" { // ❌ invalid name (uppercase)
layout stack {
component Children
}
}
define Layout "screen_default" {
layout stack {
component Heading text: "No slot" // ❌ missing Children
}
}
  • prop_* values in definitions are treated as invocation bindings
  • ✅ Missing required bound value -> semantic error
  • ✅ Missing optional bound value -> warning + property/param omitted
  • ✅ Unused invocation arguments -> warning

Example:

define Component "MyMenu" {
component SidebarMenu
active: prop_active
}
screen Main {
layout stack {
component MyMenu active: 1
}
}
  • ✅ Style block is optional but highly recommended
  • ✅ When included, style values must be valid strings with quotes
  • ✅ If omitted, sensible defaults are applied

Minimal (style optional):

project "App" {
// style omitted - defaults will be applied
screen Home {
layout stack {
component Heading text: "Hello"
}
}
}

With style (recommended):

project "App" {
style {
density: "normal"
spacing: "md"
radius: "md"
stroke: "normal"
font: "base"
}
screen Home {
layout stack {
component Heading text: "Hello"
}
}
}
  • ✅ Layout properties must be valid for that layout type
  • gap must be valid spacing value: xs, sm, md, lg, xl
  • padding must be valid spacing value
  • grid layout requires columns property
  • split layout requires sidebar property (numeric pixel value)

Invalid:

layout stack(direction: invalid) { } // ❌ Invalid direction
layout grid { } // ❌ Missing columns property
layout split(gap: md) { } // ❌ Missing sidebar property

Valid:

layout stack(direction: vertical, gap: md)
layout grid(columns: 12, gap: md)
layout split(sidebar: 260, gap: md)

All components validate their specific properties:

ComponentRequired PropsOptional Props
Headingtextlevel, spacing
Buttontextvariant
Inputlabelplaceholder
Tablecolumnsrows
Imageplaceholdericon, height
Icon-type
And 17 more…--

See Components Reference for complete property list.


Performed by the Layout Engine during layout calculation.

  • ✅ Container width/height must be positive integers
  • ✅ Padding values must be valid spacing units
  • ✅ Gap values must be valid spacing units
  • ✅ Children sized based on constraints
  • ✅ Overflow is handled (clipping or scrolling)
  • ✅ Negative margins/padding not allowed
  • ✅ Cell span must be between 1 and 12
  • ✅ Cell align must be valid: start, center, end
  • ✅ Total span doesn’t need to equal columns (wrapping not supported)

All validation errors include:

  • Message: What went wrong
  • Location: Line and column number (where applicable)
  • Severity: Error or warning
  • Context: Surrounding code snippet
  • Suggestion: How to fix (when applicable)

Example Error Output:

Error: Unknown component "CustomButton"
at line 12, column 20
layout stack {
component CustomButton ← Unknown component
}
Suggestion: Define the component first with:
define Component "CustomButton" { ... }
Or use one of the built-in components:
Heading, Text, Button, Input, ...

✅ Validate files before rendering
✅ Fix syntax errors first
✅ Check component property names against reference
✅ Ensure unique screen names
✅ Define custom components before use
✅ Use valid values

❌ Use unquoted string values
❌ Reference undefined components
❌ Use invalid spacing units
❌ Leave containers empty
❌ Skip style block
❌ Use duplicate screen names


Terminal window
wire validate myfile.wire

Shows all errors and warnings with detailed messages.

The web editor validates in real-time as you type, showing:

  • Syntax errors in red
  • Error location with line number
  • Helpful suggestions
import { parseWireDSL, generateIR } from '@wire-dsl/engine';
const content = `...wire file content...`;
try {
const ast = parseWireDSL(content);
const ir = generateIR(ast);
console.log('Valid!', ir);
} catch (error) {
console.error('Validation failed:', error.message);
}

For complete technical specification including all validation rules, see: