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: 42int64
  • Floating-point: 3.14float64
  • Booleans: true, falsebool
  • Null: nullnil
  • 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