> █
desca.dev v3.2.0
Descendent Architecture Toolkit
Type help for available commands
Install the desca CLI to scaffold and manage descendent architecture projects. The toolkit handles dependency graphs, lifecycle hooks, and hierarchical state propagation.
$ npm install -g @desca/cli $ desca init my-project
The init command creates a new project with the default descendent tree structure. Each node inherits configuration from its parent unless explicitly overridden.
Desca uses a tree-based architecture where each component is a descendent of a parent node. State flows downward. Events bubble upward. The tree is the single source of truth.
import { createTree } from '@desca/core' const root = createTree({ state: { theme: 'dark' }, children: [header(), main(), footer()] }) root.mount(document.body)
When a parent updates its state, all descendents receive the change through the propagation pipeline. Override any inherited value at any level of the tree.
Each node in the descendent tree has a lifecycle. Hooks fire at each stage, giving you control over initialization, updates, and teardown.
const node = root.spawn({ onMount() { // Node attached to tree }, onInherit(k, v) { // Received value from ancestor }, onUpdate(s) { // State changed }, onEvent(e) { // Event bubbled from descendent }, onDestroy() { // Node removed from tree } }) node.emit('ready')
> desca --help█
createTree(config) // Create root node node.spawn(child) // Add descendent node.emit(event) // Bubble event upward node.inherit(key) // Read from ancestor node.destroy() // Remove and cleanup node.update(state) // Merge state changes node.traverse(visitor) // Walk descendent tree
All methods return the node instance for chaining. The inherit method traverses the ancestor chain until the key is found or the root is reached.
Pass a configuration object to createTree to define root state, middleware, and plugins.
const tree = createTree({ state: { locale: 'en', theme: 'dark' }, middleware: [logger(), devtools()], plugins: [router(), store()], propagation: 'depth-first', strict: true }) // Strict mode warns on unregistered keys tree.update({ locale: 'ja' })
Walk the descendent tree with the traverse method. Visitors receive each node and its depth.
tree.traverse(function(node, depth) { if (depth > 3) return 'skip' node.update({ visited: true }) }) // Returns array of visited nodes
> desca run examples/█
import { createTree } from '@desca/core' const counter = createTree({ state: { count: 0 }, children: [ display({ inherit: 'count' }), button({ label: '+', onClick: 'increment' }), button({ label: '-', onClick: 'decrement' }) ] }) counter.mount('#app')
$ desca run examples/counter Building tree... done (14ms) Server running at http://localhost:3000
const todos = createTree({ state: { items: [] }, children: [ input({ onSubmit: function(text) { this.parent().update({ items: [...this.inherit('items'), { text, done: false }] }) } }), list({ inherit: 'items' }) ] })
$ desca run examples/todo Building tree... done (22ms) Watching for changes... Server running at http://localhost:3000
Demonstrates state flowing downward through the descendent tree. Changing the root theme updates every child automatically.
const app = createTree({ state: { theme: 'dark' } }) // All descendents inherit theme app.spawn(sidebar()) // theme: 'dark' app.spawn(content()) // theme: 'dark' app.update({ theme: 'light' }) // All update
> exit
Process completed successfully.