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, compile it to reactive JavaScript components, or use it as a standalone parser.
<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
}
}
}>
npm install @nisoku/sakkoimport { 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' }
// ]
// }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' }Every Sakko document has one root block wrapped in angle brackets:
<page {
...children
}>
Elements with children use curly braces:
card {
heading: "Title"
text: "Description"
}
Elements without children use a colon:
text: Hello world
button(accent): Click me
icon: play
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"): ""
Comma-separated elements in square brackets:
row: [button: A, button: B, button: C]
Single-line comments with //:
// This is a comment
card {
text: Hello // inline comment
}
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.
Run side effects with @effect:
<app {
@state { count = 0 }
@effect {
console.log("Count changed:", count)
document.title = `Count: ${count}`
}
button @on:click { count++ }: "Increment"
}>
Compute derived values with @derived:
<app {
@state { items = [] }
@derived {
count = items.length
isEmpty = items.length === 0
}
text: "{count} items"
}>
Handle events with @on:event:
button @on:click { count++ }: "Click"
input @on:input { value = e.target.value }: ""
div @on:mouseenter { isHovered = true }: "Hover me"
Bind inputs with @bind:
<form {
input @bind="username": ""
input(type password) @bind="password": ""
text: "Hello, {username}!"
}>
Use {expression} in text values:
text: "Hello, {name}!"
text: "{a} + {b} = {a + b}"
text: "Items: {items.map(i => i.name).join(', ')}"
Sakko includes a compiler and runtime for building reactive web components.
import { parseSakko, compileComponent } from '@nisoku/sakko';
const ast = parseSakko('<counter { @state { count = 0 } }>');
const js = compileComponent(ast, { sairinImport: 'global' });Sairin Modes:
'global'(default) - Useswindow.sairin(load via<script>tag)'esm'- ESM imports (use with a bundler)'cjs'- CommonJS requires (Node.js only)
import { parseSakko, registerSakkoComponent } from '@nisoku/sakko';
const ast = parseSakko('<my-counter { @state { count = 0 } }>');
await registerSakkoComponent(ast);
// Now <sakko-my-counter> is availableRequires sairin to be loaded globally:
<script src="sairin.js"></script>Build/ Library source code
src/
parser/ Tokenizer and parser
types/ TypeScript type definitions
tests/ Tests
Examples/ Example .sako files
Docs/ Documentation (powered by DocMD)
cd Buildnpm installnpm testnpm run build| Document | Summary |
|---|---|
| Language Reference | Full Sakko syntax guide |
| API Reference | Public API surface |
cd Docs
npm install
npm run dev