@nisoku/sakko
v0.1.5
Published
Sakko, the modern DSL (Design Sub-Language)
Readme
Sakko
The modern DSL (Design Sub-Language) for describing UI trees.
Sakko is a bracket-based markup language that compiles to component trees. Write concise, readable markup. Get a structured AST. Use it with Sazami, build your own renderer, or create something entirely different.
What does it look like?
<card {
heading: "Hello, world"
text: "This compiles to an AST."
button: "Get Started"
}>That is the entire source. Sakko tokenizes it, parses it, and produces a structured AST. The AST can then be transformed into anything: Sazami web components, React VNodes, JSON, you name it.
Here is a more complex example:
<player {
card(row center) {
coverart(round): "album.jpg"
details {
text(bold): "Midnight City"
text(dim): "M83"
}
controls {
icon-btn: previous
icon-btn(accent large): play
icon-btn: next
}
}
}>Getting started
Install
npm install @nisoku/sakkoUse
import { parseSakko, tokenize } from "@nisoku/sakko";
// Tokenize source to tokens (useful for debugging)
const tokens = tokenize('button(accent): Click me');
// Parse to AST
const ast = parseSakko(`
<card {
heading: "Hello"
button: "Click"
}>
`);
console.log(ast);
// {
// type: 'root',
// name: 'card',
// children: [
// { type: 'inline', name: 'heading', modifiers: [], value: 'Hello' },
// { type: 'inline', name: 'button', modifiers: [], value: 'Click' }
// ]
// }AST Structure
The parser produces one of four node types:
| Type | Fields | Description |
|---|---|---|
| root | name, modifiers?, children | Top-level container |
| element | name, modifiers?, children | Block element with children |
| inline | name, modifiers?, value | Leaf element with text value |
| list | items | Comma-separated group |
Modifiers are either flags or key-value pairs:
{ type: 'flag', value: 'accent' }
{ type: 'pair', key: 'cols', value: '3' }Syntax overview
Root blocks
Every Sakko document has one root block wrapped in angle brackets:
<page {
...children
}>Block elements
Elements with children use curly braces:
card {
heading: "Title"
text: "Description"
}Inline elements
Elements without children use a colon:
text: Hello world
button(accent): Click me
icon: playModifiers
Parenthesized flags or key-value pairs after the element name:
button(primary large): Submit
grid(cols 3 gap medium): [...]
card(row center curved): { ... }
input(placeholder "Email"): ""Lists
Comma-separated elements in square brackets:
row: [button: A, button: B, button: C]Comments
Single-line comments with //:
// This is a comment
card {
text: Hello // inline comment
}Reactive State
Declare reactive state with @state:
<counter {
@state {
count = 0
step = 1
}
button @on:click { count++ }: "+"
text: "Count: {count}"
}>Compiles to Sairin signals. Read values with {name} interpolation.
Effects
Run side effects with @effect:
<app {
@state { count = 0 }
@effect {
console.log("Count changed:", count)
document.title = `Count: ${count}`
}
button @on:click { count++ }: "Increment"
}>Derived State
Compute derived values with @derived:
<app {
@state { items = [] }
@derived {
count = items.length
isEmpty = items.length === 0
}
text: "{count} items"
}>Event Handlers
Handle events with @on:event:
button @on:click { count++ }: "Click"
input @on:input { value = e.target.value }: ""
div @on:mouseenter { isHovered = true }: "Hover me"Two-way Binding
Bind inputs with @bind:
<form {
input @bind="username": ""
input(type password) @bind="password": ""
text: "Hello, {username}!"
}>Interpolation
Use {expression} in text values:
text: "Hello, {name}!"
text: "{a} + {b} = {a + b}"
text: "Items: {items.map(i => i.name).join(', ')}"Project structure
Build/ Library source code
src/
parser/ Tokenizer and parser
types/ TypeScript type definitions
tests/ Tests
Examples/ Example .sako files
Docs/ Documentation (powered by DocMD)Development
cd BuildInstall dependencies
npm installRun tests
npm testBuild
npm run buildDocumentation
| Document | Summary | | --- | --- | | Language Reference | Full Sakko syntax guide | | API Reference | Public API surface |
Run docs locally
cd Docs
npm install
npm run dev