Architecture Overview
Compilation Pipeline
Sassy uses a phase-based compilation pipeline to transform YAML theme
definitions into VS Code .color-theme.json files:
- Import Resolution — load and merge modular theme files. Objects (palette, vars, colours, semanticTokenColors) are deep-merged; arrays (tokenColors) are appended. The main file is applied last, giving it override semantics.
- Palette Alias Expansion — expand
$$nameshorthand to$palette.namein all values before resolution begins. - Palette Decomposition & Evaluation — flatten the
paletteobject (prefixed aspalette.*) and resolve it in isolation. Palette cannot referencevarsortheme— only its own entries. - Variable Decomposition & Evaluation — flatten
varsand resolve against the union of palette and variables. - Token Evaluation — resolve
$(variable)references via the ThemePool registry. Theme entries (colours, tokenColors, semanticTokenColors) resolve against the union of palette, variables, and other theme entries. - Function Application — execute colour functions (
lighten,darken,mix, etc.) backed by Culori. - Dependency Resolution — the ThemePool builds a token dependency graph and resolves values in order, tracking resolution trails for debugging.
- Theme Assembly — recompose flat paths into the nested VS Code theme JSON structure.
Class Relationships
CLI → Session → Theme → Compiler → Evaluator
↓ ↓ ↓
Theme.js YamlSource ThemePool ← ThemeToken
↓ ↓
chokidar Colour.js
YamlSource
YamlSource parses YAML files using yaml-eslint-parser and builds a map from
dotted paths to source locations (file, line, column). During import resolution,
each YAML dependency receives a YamlSource instance stored on its Dependency
object. When the Evaluator encounters an error, it asks the Theme to look up
the originating source location via findSourceLocation(dottedPath), enriching
error messages with precise file:line:col references.
Session
Session orchestrates the processing of multiple theme entry files. It uses
Promise.allSettled so that one theme failing does not halt the others. Each
Theme instance manages its own lifecycle independently — loading, compiling,
writing, and watching are all self-contained per entry file.
Error Propagation
Errors are wrapped in Sass instances (from @gesslar/toolkit) with trace
context chains that accumulate as errors propagate up through the pipeline.
This gives structured, multi-layer error reports rather than bare stack traces.