Skip to main content

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​

  1. Use descriptive nesting - Group related configuration logically
  2. Avoid excessive depth - 2-3 levels of nesting is usually sufficient
  3. Be consistent - Use the same structure patterns across workflows
  4. Document complex structures - Add comments explaining nested configuration
  5. Use arrays for lists - Prefer arrays over multiple similar keys