Declarations
A Spine file consists of namespace blocks (optional nesting), imports, and declarations. Names declared inside a namespace are qualified with that namespace.
Namespace
namespace qualified.name { ... }
qualified.nameis one or more identifiers separated by..- Nested
namespaceblocks prefix the inner names with the outer dotted name.
Imports
Imports end with ;.
-
Namespace alias
import namespace com.example.api as Api; -
Glob
import com.example.models.*; -
Entity (optionally aliased)
import com.example.models.User;
import com.example.models.User as Person;
For entity imports, the last segment is the type name; the rest is the namespace.
Struct
Struct Name [ @version ]? '{' properties conversion_clauses* '}'
- Fields: optional annotations, then
name : Type, or an anonymous nested groupname ':'? '{' properties '}'. - Enum variant names may be spelled
Struct,Enum, orAnnotationwhere the grammar allows a variant identifier. fromclauses andintoclauses appear after properties (see Conversions below).
Enum
Enum Name [ @version ]? '{' variant ( ',' variant )* ','? conversion_clauses* '}'
Variants:
- Unit:
VariantName - Tuple:
VariantName '(' Type ( ',' Type )* ')' - Struct-like:
VariantName '{' properties '}' from/intoclauses appear after variants (see Conversions below).
Annotation
Annotation Name [ @version ]? '{' properties '}'
Defines an annotation type for use as @AnnotationName(...) on fields.
Singleton (Singleton keyword form)
Singleton Name [ @version ]? ':' Type '=' expression
Alternate singleton (ingests, outlets, config)
Type Name [ @version ]? [ ':' Type ]? ( '=' expression | expression )
- Leading type is any type reference (e.g.
Ingest,Outlet,KeyValueApi<String, Item>). - Optional second
: Typecan refine the type when a value is given. - The value is
= expror a direct expression (often{ ... }).
Wired ingest example:
Ingest EventIngest {
name: "EventIngest",
type: Event,
}
Constant (module-level)
identifier [ @version ]? '=' expression
At namespace scope, a bare name = expression (without the const keyword) declares a named constant. That is how flow = … and joined = … bindings are written: they are constants whose value is a stream expression. Inside functions and closures, use const or let statements instead (Statements).
Function
function Name [ @version ]? '(' parameters ')' [ ':' returnType ] '{' statements '}'
- Parameters:
name [ ':' Type ], comma-separated. - The body uses the same rules as a multi-statement closure (
return,let,if,for, …).
Conversions
Conversion clauses appear inside Struct and Enum declarations, after the properties/variants list. They declare how a type can be converted to or from another type.
from clause (on the target type)
from SourceType [ @version ]? '(' binding ')' '{' statements '}'
bindingreceives a value ofSourceType.- The body must evaluate to a value of the enclosing type.
- Declares that the enclosing type can be constructed from
SourceType.
Example — struct versioning:
Struct Event @2 {
id: String
payload: String
from com.example.Event @1 (v) {
Event @2 { id: v.id, payload: "" }
}
}
Example — enum versioning:
Enum Status @2 {
Active,
Inactive,
Archived
from com.example.Status @1 (v) {
match v {
Active -> Status @2.Active,
Disabled -> Status @2.Inactive,
}
}
}
into clause (on the source type)
into TargetType [ @version ]? '(' binding ')' '{' statements '}'
- Used when the target type is a library type or any type you cannot add a
fromclause to. bindingreceives a value of the enclosing type.- The body must evaluate to a value of
TargetType.
Example:
Struct MyDto @1 {
count: UnsignedInteger32
into com.example.library.Counter (v) {
Counter.new(value: v.count)
}
}
Multiple clauses
A single type can declare multiple from / into clauses. Duplicate directed pairs (same source and target) are rejected.
Call site
Use .into(TargetType) to apply an explicit conversion, or .into() when the target can be inferred from context:
let newEvent: Event @2 = oldEvent.into(Event @2)
let newEvent: Event @2 = oldEvent.into() // inferred from type annotation
See Operators for precedence details.