Transpiler Usage Guide
Learn how the JSSON transpiler works, how to use it programmatically, and how to extend it for custom output formats.
The JSSON transpiler is the engine that converts your clean JSSON syntax into valid JSON, YAML, TOML, or TypeScript. Let's explore how it works and how to use it! ⚙️
How It Works
The transpiler follows a three-stage pipeline:
JSSON Source → Lexer → Parser → Transpiler → Output1. Lexer (Tokenization)
Breaks your JSSON into tokens:
name = JoãoBecomes:
IDENT("name") ASSIGN IDENT("João")2. Parser (AST Generation)
Creates an Abstract Syntax Tree:
Program
└── AssignmentStatement
├── name: "name"
└── value: StringLiteral("João")3. Transpiler (Code Generation)
Converts the AST to the target format (JSON, YAML, etc.):
{
"name": "João"
}Using the Transpiler
Command Line
The easiest way:
# Default (JSON)
jsson -i input.jsson -o output.json
# YAML
jsson -i input.jsson -f yaml
# TypeScript
jsson -i input.jsson -f tsProgrammatic Usage (Go)
Use JSSON as a library in your Go code:
package main
import (
"fmt"
"jsson/internal/lexer"
"jsson/internal/parser"
"jsson/internal/transpiler"
)
func main() {
// Your JSSON source
source := `
app {
name = "My App"
version = "1.0.0"
}
`
// Step 1: Lex
l := lexer.New(source)
// Step 2: Parse
p := parser.New(l)
program := p.ParseProgram()
// Check for parse errors
if len(p.Errors()) > 0 {
for _, err := range p.Errors() {
fmt.Println(err)
}
return
}
// Step 3: Transpile
// New(program, workingDir, includeMode, sourceFile)
t := transpiler.New(program, ".", "keep", "main.jsson")
// Transpile to JSON
json, err := t.Transpile()
if err != nil {
fmt.Println("Transpile error:", err)
return
}
fmt.Println(string(json))
}Reading from Files
package main
import (
"fmt"
"os"
"path/filepath"
"jsson/internal/lexer"
"jsson/internal/parser"
"jsson/internal/transpiler"
)
func transpileFile(inputPath, outputPath string) error {
// Read input file
content, err := os.ReadFile(inputPath)
if err != nil {
return err
}
// Lex and parse
l := lexer.New(string(content))
l.SetSourceFile(inputPath) // For better error messages
p := parser.New(l)
program := p.ParseProgram()
if len(p.Errors()) > 0 {
for _, err := range p.Errors() {
fmt.Println(err)
}
return fmt.Errorf("parse errors")
}
// Transpile
workingDir := filepath.Dir(inputPath)
t := transpiler.New(program, workingDir, "keep", inputPath)
json, err := t.Transpile()
if err != nil {
return err
}
// Write output
return os.WriteFile(outputPath, json, 0644)
}Output Formats
JSSON currently supports transpilation to:
- JSON (Default) — For APIs and general config
- YAML — For Kubernetes, CI/CD, and cloud infrastructure
- TOML — For Rust/Go/Python configuration
- TypeScript — For type-safe frontend constants
Selecting Format
In the Go API, use the specific method for your desired format:
// JSON
json, _ := t.Transpile()
// YAML
yaml, _ := t.TranspileToYAML()
// TOML
toml, _ := t.TranspileToTOML()
// TypeScript
ts, _ := t.TranspileToTypeScript()Performance Considerations
File Size
JSSON handles files efficiently:
- Small files (< 1KB): Instant
- Medium files (1-100KB): < 100ms
- Large files (> 100KB): < 1s
Memory Usage
The transpiler loads the entire file into memory. For very large files (> 10MB), consider:
- Splitting with includes
- Processing in chunks
Optimization Tips
1. Use includes for large configs:
// Instead of one 1000-line file
include "users.jsson" // 200 lines
include "products.jsson" // 300 lines
include "settings.jsson" // 500 lines2. Avoid deeply nested structures:
// This is fine
user {
profile {
settings {
theme = dark
}
}
}
// This might be slow (10+ levels deep)
a { b { c { d { e { f { g { h { i { j {
value = deep
}}}}}}}}}}3. Use template arrays efficiently:
// Good - 1000 users
users [
template { name, email }
// ... 1000 rows
]
// Better - split into multiple files
include "users-1-500.jsson"
include "users-501-1000.jsson"Error Handling
The transpiler provides detailed error messages:
Lex Errors
Lex goblin: config.jsson:15:8 — Illegal character: '@'Parse Errors
Parse wizard: config.jsson:20:5 — Unexpected token: expected '=', got '{'Transpile Errors
Transpiler gremlin: config.jsson:25:10 — Undefined reference: 'config.port'See the Errors & Debugging guide for details!
Extending the Transpiler
Custom Transformations
You can modify the AST before transpiling:
// Example: Add a timestamp to all objects
func addTimestamp(program *ast.Program) {
for _, stmt := range program.Statements {
if assign, ok := stmt.(*ast.AssignmentStatement); ok {
if obj, ok := assign.Value.(*ast.ObjectLiteral); ok {
// Add timestamp field
obj.Pairs["_timestamp"] = &ast.StringLiteral{
Value: time.Now().Format(time.RFC3339),
}
}
}
}
}
// Use it
program := p.ParseProgram()
addTimestamp(program)
t := transpiler.New(program, ".", "keep", "main.jsson")
json, _ := t.Transpile()Integration Examples
Web Server
package main
import (
"net/http"
"io"
"jsson/internal/lexer"
"jsson/internal/parser"
"jsson/internal/transpiler"
)
func transpileHandler(w http.ResponseWriter, r *http.Request) {
// Read JSSON from request body
body, _ := io.ReadAll(r.Body)
// Transpile
l := lexer.New(string(body))
p := parser.New(l)
program := p.ParseProgram()
if len(p.Errors()) > 0 {
http.Error(w, p.Errors()[0], http.StatusBadRequest)
return
}
t := transpiler.New(program, ".", "keep", "request.jsson")
json, err := t.Transpile()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(json)
}
func main() {
http.HandleFunc("/transpile", transpileHandler)
http.ListenAndServe(":8080", nil)
}What's Next?
- AST Reference — Understand the Abstract Syntax Tree
- Errors & Debugging — Handle errors gracefully
- CLI Guide — Master the command-line tool
The transpiler is the heart of JSSON — now you know how it works! ⚙️