Nested Const Blocks
Starting with v0.1.4, WSL supports nested objects and arrays in const blocks, enabling complex hierarchical configurations.
Overview
Previously, const blocks only supported flat key-value pairs. Now you can define nested structures using objects and arrays, making it easier to organize related configuration.
Syntax
Nested Objects
Use curly braces {} to define nested objects:
const {
database: {
host: "localhost",
port: 5432,
name: "myapp"
}
}
Arrays
Use square brackets [] to define arrays:
const {
servers: ["server1", "server2", "server3"],
ports: [8080, 8081, 8082]
}
Mixed Nested Structures
Combine objects and arrays for complex configurations:
const {
event: "greet",
description: "A complex workflow example",
version: "1.0.0",
maxRetries: 3,
enabled: true,
cfg: {
apiEndpoint: "https://api.example.com",
timeout: 30000,
retries: 3,
headers: [
{ key: "Content-Type", value: "application/json" },
{ key: "Accept", value: "application/json" },
{ key: "Authorization", value: "Bearer token123" }
]
},
environments: {
development: {
apiUrl: "http://localhost:3000",
debug: true
},
production: {
apiUrl: "https://api.production.com",
debug: false
}
}
}
Supported Types
WSL automatically converts literals to appropriate Go types:
- Strings:
"hello"→string - Integers:
42→int64 - Floating-point:
3.14→float64 - Booleans:
true,false→bool - Null:
null→nil - Objects:
{ key: value }→map[string]interface{} - Arrays:
[item1, item2]→[]interface{}
Accessing Nested Values
Access nested constants in workflows using dot notation with $constants:
state ConfigureAPI {
action http.Request(
url: $constants.cfg.apiEndpoint,
timeout: $constants.cfg.timeout,
headers: $constants.cfg.headers
)
on success -> NextState
}
state ConnectDatabase {
action db.Connect(
host: $constants.database.host,
port: $constants.database.port,
database: $constants.database.name
)
on success -> Ready
}
Complete Example
module example
import services/common
const {
event: "process_data",
description: "Data processing workflow with complex configuration",
version: "2.0.0",
api: {
baseUrl: "https://api.example.com",
timeout: 30000,
endpoints: {
users: "/api/v1/users",
data: "/api/v1/data",
reports: "/api/v1/reports"
}
},
processing: {
batchSize: 100,
maxConcurrent: 5,
retryAttempts: 3,
stages: ["validate", "transform", "load"]
},
notifications: [
{ type: "email", enabled: true, recipients: ["admin@example.com"] },
{ type: "slack", enabled: true, webhook: "https://hooks.slack.com/..." },
{ type: "sms", enabled: false }
]
}
workflow data_processor {
start: Initialize
state Initialize {
action config.Load(
apiUrl: $constants.api.baseUrl,
batchSize: $constants.processing.batchSize,
stages: $constants.processing.stages
)
on success -> FetchData
}
state FetchData {
action http.Get(
url: "<<$constants.api.baseUrl>><<$constants.api.endpoints.data>>",
timeout: $constants.api.timeout
) as Data
on success -> ProcessData(Data)
}
state ProcessData(Data) {
action processor.Process(
data: $Data,
maxConcurrent: $constants.processing.maxConcurrent,
retries: $constants.processing.retryAttempts
)
on success -> Complete
on error -> NotifyError
}
state NotifyError {
action notifications.Send(
recipients: $constants.notifications
)
end error
}
state Complete {
action response/ResponseValue(
message: "Processing complete",
statusCode: 200
)
end ok
}
}
Benefits
1. Better Organization
Group related configuration values together hierarchically rather than using flat prefixes:
Before:
const {
db_host: "localhost",
db_port: 5432,
db_name: "myapp",
db_user: "admin",
api_url: "https://api.example.com",
api_timeout: 30000,
api_retries: 3
}
After:
const {
database: {
host: "localhost",
port: 5432,
name: "myapp",
user: "admin"
},
api: {
url: "https://api.example.com",
timeout: 30000,
retries: 3
}
}
2. Reduced Duplication
Define complex structures once and reference them throughout your workflow.
3. Type Safety
Automatic type conversion ensures correct data types are used.
4. Improved Readability
Clean, JSON-like syntax that's easy to read and maintain.
5. Unlimited Nesting
Support for arbitrarily deep nesting allows for any configuration complexity.
Backward Compatibility
This feature is fully backward compatible. Simple flat const blocks continue to work exactly as before:
const {
event: "my_event",
version: "1.0.0",
timeout: 5000
}
Migration Guide
If you have existing flat const blocks with prefixed keys, you can gradually migrate to nested structures:
Step 1: Identify related constants with common prefixes
const {
api_url: "https://api.example.com",
api_timeout: 30000,
api_key: "abc123"
}
Step 2: Group them into nested objects
const {
api: {
url: "https://api.example.com",
timeout: 30000,
key: "abc123"
}
}
Step 3: Update references in your workflow
// Before:
url: $constants.api_url
// After:
url: $constants.api.url
Best Practices
- Use descriptive nesting - Group related configuration logically
- Avoid excessive depth - 2-3 levels of nesting is usually sufficient
- Be consistent - Use the same structure patterns across workflows
- Document complex structures - Add comments explaining nested configuration
- Use arrays for lists - Prefer arrays over multiple similar keys
Related Features
- WSL Overview - Introduction to WSL syntax
- WSL Specification - Complete grammar reference
- Examples - More workflow examples