Commit graph

64 commits

Author SHA1 Message Date
enzotar
fbbdeb0bc4 feat: add initial interactive compiler and ds-stream demos 2026-03-11 18:25:18 -07:00
enzotar
a65094c0d2 compiler: v0.8–v1.0 milestones — generics, traits, async/effects, production hardening
v0.8.0: Generics, Trait System, LSP Foundation (322 tests)
- ds-parser: GenericParam, TraitDecl, ImplBlock, WhereClause, DefaultParam, Destructure
- ds-types: GenericType, TraitRegistry, TypeExpander
- ds-analyzer: AdvancedAnalyzer (unused imports, memo, dep depth, hot paths)
- ds-codegen: CodeGenV2 (generic erasure, for-in/yield, tree shaking, minify)
- ds-layout: FlexLayout (gap, padding, margin, border, position, alignment)
- ds-diagnostic: LspDiagnostic, DiagnosticBatch (LSP format, suppression, dedup)
- ds-incremental: IncrementalV2 (content hash, compile queue, error cache)

v0.9.0: Async/Await, Effect System, Production Hardening (385 tests)
- ds-parser: AsyncFn, EffectDeclV2, TryCatch, PipelineExpr, Decorator
- ds-types: AsyncType (Promise/Future/Effect/Result), AdvancedType (intersection/mapped/conditional/branded)
- ds-analyzer: ProductionAnalyzer (async boundaries, purity, complexity, coverage)
- ds-codegen: CodeGenV3 (async/await, try/catch, pipeline, chunks, CSS, HMR)
- ds-layout: AdvancedLayout (scroll, sticky, flex grow/shrink, shadow, transition)
- ds-diagnostic: DiagnosticPipeline, DiagTag (file index, lint rules, escalation)
- ds-incremental: BuildPipeline (profiles, workers, artifacts, source maps)

v1.0.0: Production-Ready Compiler with Stable API (511 tests)
- ds-parser: ParseError1, PartialAst, VisibilityV2, Namespace, DocComment, Pragma, NumericLit, ParseStats
- ds-types: TypeInference (HM unification), SubtypeChecker, TypeSystemExt (opaque/existential/HKT)
- ds-analyzer: FullAnalyzer (call graph, dead code, tail call, borrow check, vectorize)
- ds-codegen: CodeGenFull (WASM, SSR, hydration, CSS modules, import maps, SIMD)
- ds-layout: Animation, TextLayout, MediaQuery, ColorSpace, Gradient, Filter, LayoutStats
- ds-diagnostic: DiagnosticSuite (SARIF, code frames, budgets, baselines, trending)
- ds-incremental: BuildSystem (remote cache, build graph, plugins, hermetic, signing)
2026-03-11 16:16:42 -07:00
enzotar
4a15e0b70c feat: Bump package versions, add physics body sleeping, revolute motor, and prismatic joints, and enhance type checker exhaustiveness. 2026-03-10 21:07:22 -07:00
enzotar
b0440e2e47 feat(compiler): v0.4 + v0.5 — CLI modularity, diagnostic pipeline, test suite
v0.4 — CLI Modularity:
- Split monolithic main.rs (2,038 lines) into 8 command modules + slim dispatch (107 lines)
- Add 12 JS codegen tests (signals, derived, views, events, loops, match, enums, components, interpolation, springs, tree-shaking)

v0.5 — Diagnostic Quality + Analyzer Confidence:
- Add From<ParseError> for Diagnostic (E0001) in ds-diagnostic
- Add errors_as_diagnostics() to TypeChecker (E0100–E0110)
- Wire Elm-style diagnostics through dreamstack check and build commands
- Switch incremental compiler to parse_program_resilient() for multi-error collection
- Add 12 analyzer tests (chains, fan-out, diamond deps, empty programs, conditionals, handlers, views)
- Add 2 diagnostic conversion tests

Test suite: 97 → 123 tests (26 new, 0 failures)
2026-03-10 09:09:02 -07:00
enzotar
878e55b962 chore: add per-package versioning, changesets, and clean changelogs
- Add cliff.toml for git-cliff changelog generation (one-line entries,
  no commit body dumps, improve/refine prefixes mapped)
- Add @changesets/cli config and README in .changeset/
- Add release.sh script with per-package version bumps from changesets,
  changeset-driven per-crate changelog updates, and --all/--dry-run flags
- Switch all crates from workspace version to independent version = "0.1.0"
- Generate clean root CHANGELOG.md and per-crate CHANGELOGs with [0.1.0]
- Retag v1.0.0 → v0.1.0 to match actual crate versions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 23:12:54 -07:00
enzotar
bf2b7c3cd5 feat: Implement Panel IR emitter to generate JSON UI descriptions for LVGL panels. 2026-03-06 20:06:33 -08:00
enzotar
cc6aac8697 feat: Add Waveshare P4 panel device integration with display streaming and touch input, alongside core streaming engine and compiler updates. 2026-03-02 16:08:49 -08:00
enzotar
003118ec10 refine: type system second pass — deeper unification throughout
Refinement pass:
- DotAccess: unwraps Signal/Derived before field lookup
- UnaryOp: uses unification instead of manual matching
- Call: unifies each arg with param type, applies subst to return
- List: unifies all element types (not just first)
- If/else: unifies both branches, checks condition is Bool
- When/else: unifies body with else body, checks condition
- Match: unifies all arm types for consistency
- Assign: checks assigned value compatible with variable type
- ForIn: binds iteration variable from Array element type

Tests: 39 ds-types (up from 34), 164 workspace total, 0 failures
2026-02-27 11:54:15 -08:00
enzotar
8fb2214ac0 feat: complete type system — HM unification, signal-aware types, effect scoping
Type System Completion:
- Add unify() with occurs check for proper type variable binding
- Add apply_subst() to chase type variables through substitution map
- Add SignalInfo/SignalClass for graph-based signal classification
- Add check_program_with_signals() accepting optional signal graph data
- Push Dom effect handler scope automatically when checking view blocks
- Wire unification into BinOp, comparison, and logical operator inference
- Include List/Record literals in source signal heuristic

Tests: 34 ds-types tests (up from 11), 159 workspace total, 0 failures
2026-02-27 11:36:28 -08:00
enzotar
d4c7ba2385 feat: core language & stream improvements
Language improvements:
- Reactive container class: prop (wraps in DS.effect when signal-dependent)
- Stream output filtering (_streamDiff skips non-output signals)
- Stream exponential reconnect backoff (2s → 4s → 8s, max 30s)
- Breakout game: classic row order with all 5 rows having collision

Verified: reactive text + derived signals already work.
All 48 examples compile, 136 tests pass
2026-02-27 11:03:53 -08:00
enzotar
4ac584c81e fix: reactive component props + breakout improvements
Compiler fixes:
- Component props with signal-dependent expressions now wrapped as
  reactive getters (() => expr) at call site
- Component declarations handle fn-typed props via
  { get value() { return props.x(); } } for live reactivity
- Container style: prop wrapped in DS.effect when expr contains .value
- Timer merging: all same-interval 'every' statements grouped into
  single setInterval with one DS.flush()

Breakout game improvements:
- Classic row order: blue top (far), red bottom (near paddle)
- All 5 rows have full collision detection (was only 2)
- Faster ball (4px/frame) and paddle (40px/keypress)
- Score/Lives badges now update in real-time

All 48 examples compile, 136 tests pass
2026-02-27 10:53:27 -08:00
enzotar
e8bbfcbcb7 perf: merge same-interval timers + breakout game + beats viewer
Performance:
- All every N statements with same interval now merge into one setInterval
- Pong: 24 timers → 1, Breakout: 38 timers → 1 (single DS.flush per frame)

New examples:
- game-breakout.ds: brick-breaker with 5×10 colored bricks, keyboard, audio
- beats-viewer.ds: step sequencer spectator via relay

Fixes:
- _playTone/_playNoise early-exit when freq/duration <= 0
- Breakout score race: score+bounce checks before brick destruction
- Score sound effects in pong (220Hz/440Hz sawtooth)

All 48 examples compile, 136 tests pass
2026-02-27 10:24:13 -08:00
enzotar
eb21aa2137 feat: beats viewer, score sounds, audio early-exit guards
- New beats-viewer.ds: step sequencer spectator via relay stream
- game-pong.ds: added score sound effects (220Hz/440Hz sawtooth)
- Runtime: _playTone skips when freq<=0, _playNoise skips when dur<=0
- All 47 examples compile, 136 tests pass
2026-02-27 10:05:32 -08:00
enzotar
25b960fa29 feat: pong spectator viewer + stream proxy reactivity fix
- New pong-viewer.ds: full visual court rendered from streamed state
- Extended container prop signal detection: js_val.contains('.value')
  fixes DotAccess on stream proxies (game.value.p1y) not being reactive
- Verified two-tab relay demo: player → relay → viewer syncs in real-time
- All 46 examples compile, 136 tests pass
2026-02-27 09:59:34 -08:00
enzotar
bd926b9e0a feat: keyboard input, Web Audio synthesis, and multiplayer demo
Compiler changes:
- emit_handler: DOM events (keydown/keyup/etc) route to document.addEventListener
- emit_handler: handler params (ev) pushed into scope to prevent .value suffix
- play_tone(freq, dur, type) and play_noise(dur, vol) builtins
- Web Audio runtime: _playTone (oscillator) and _playNoise (filtered noise)
- Reactive textContent: signal-dependent If expressions wrapped in DS.effect

Example updates:
- game-pong.ds: Arrow Up/Down for paddle, Space for pause/resume, paddle-hit sounds
- step-sequencer.ds: 4 audio trigger timers (kick=60Hz, snare=noise, hihat=noise, bass=110Hz)

Verification:
- All 136 tests pass, 45 examples compile
- Relay connects successfully, multiplayer sync confirmed
- Keyboard controls and pause toggle verified in browser
2026-02-27 09:34:20 -08:00
enzotar
0e23ddd88b feat: game-pong.ds + two compiler improvements
- Native DreamStack pong game with visual court (stack container),
  CSS-positioned paddles/ball, 30fps game loop, AI tracking, auto-serve
- Parser: containers (column/row/stack) now support leading props
  e.g. column { style: '...' } [children]
- Codegen: fixed signal detection for container layout props
  (strip .value suffix for signal graph lookup)
- All 136 tests pass, 45 examples compile
2026-02-27 00:02:58 -08:00
enzotar
62830fa82a fix: for-in parser token mismatch + enhanced step sequencer
- Fix for...in parser: TokenKind::In → TokenKind::InKw (was using wrong token)
- Remove dead In variant from TokenKind enum
- Fix pre-existing test: When pattern match 2→3 fields
- Enhanced step-sequencer.ds: 16 steps, 4 instrument arrays, play/pause,
  BPM controls with limits, presets, dynamic variants, streaming output
- All 118 tests pass
2026-02-26 23:42:29 -08:00
enzotar
f4e5ace37c feat: *= /= operators + 6 new array methods
New assignment operators (full pipeline: lexer → parser → analyzer → codegen):
- *= (MulAssign): count *= 2
- /= (DivAssign): count /= 2

New array methods in event handler (all flush signal + stream diff):
- .clear()   → items = []
- .insert(i, v) → splice at index
- .sort()    → immutable sort
- .reverse() → immutable reverse
- .filter(fn) → filter in place
- .map(fn)   → map in place

New example: language-features.ds (65KB)
- Tests all assignment ops (+=, -=, *=, /=)
- Tests array methods (push, pop, sort, reverse, clear)
- Tests match expressions
- Tests comparison operators
- Tests derived signals (let doubled = count * 2)
- Browser-verified: zero console errors

All 11 examples pass.
2026-02-26 20:29:35 -08:00
enzotar
0125c6e714 feat: expanded variant system — 30+ new CSS class mappings
variant_to_css expanded for all 14 components:
- Button: outline, toggle, toggle-on/off, tab-active/inactive, select
- Text: card-title/subtitle/footer, input-label/error/helper,
  dialog-title, stat-*, separator-label, avatar-*
- Column: stat-card, dialog-panel/overlay, avatar, separator-*,
  progress-fill-*, toast-*, alert-*
- Row: tabs, separator, select-group
- Input: input-default, input-error

variant_map_js expanded for dynamic variant resolution

New CSS:
- ds-btn-outline (transparent with indigo border)
- ds-tab / ds-tab-active (tab switcher styles)
- ds-tabs (flex container with subtle bg)
- ds-select-group (flex wrap)
- ds-separator-row / ds-separator-v
- ds-toast-success/error/warning/info colors
- ds-avatar-status

All 10 examples pass. Build sizes: gallery 93KB, dashboard 60KB.
2026-02-26 19:17:49 -08:00
enzotar
08e36573a5 feat: HTTP /meta API, signal dedup, periodic auto-sync
Relay HTTP /meta endpoint:
- GET /meta → JSON with all channel stats
- GET /meta/{name} → JSON with specific channel stats, schema, current state
- Uses TCP peek to intercept raw HTTP before WS handshake
- CORS headers for browser access

Signal deduplication:
- _lastSentValues tracks last-sent value per signal
- JSON.stringify comparison skips unchanged values
- Prevents redundant WS frames from derived signals

Periodic auto-sync:
- Every 50 diff batches, source sends full SignalSync (0x30)
- Relay can compact its cache instead of accumulating infinite diffs
- Resets pending_signal_diffs in relay cache

All 57 relay tests pass. All 9 examples pass.
2026-02-26 18:17:25 -08:00
enzotar
598ecde59c feat: comprehensive streaming improvements
Runtime _connectStream improvements:
- Connection status as reactive signals: _connected, _latency, _frames, _reconnects
  injected on stream proxy so UIs can show connection health
- Fixed RLE decoder: 2-byte LE count (was 1-byte, mismatched relay encoder)
- Schema caching: 0x32 SchemaAnnounce frames now parsed and cached
- RTT tracking: receivers send periodic pings (5s), measure round-trip latency
- Better reconnect logging: includes URL and attempt count

Relay tests (57 total):
- catchup_merges_multiple_diffs: sync + 3 diffs → 1 merged frame
- catchup_diffs_only_no_sync: diffs without sync → merged frame
- catchup_preserves_version_counters: conflict resolution versions kept

New example:
- timer-multi-action.ds: every timer + multi-action buttons verified

Documentation:
- STREAM_COMPOSITION.md: 4 new sections (Diff Batching, Connection Status, RTT, Relay Merging)
- Updated example table with streaming-dashboard.ds and timer-multi-action.ds

All 9 examples pass regression (44-70KB each)
2026-02-26 18:09:14 -08:00
enzotar
746b76fe4f perf: streaming core improvements — batched diffs, RTT tracking, relay merging
Runtime improvements:
- Diff batching: multiple signal changes coalesced into 1 WS frame
  via _pendingDiffs + microtask Promise.resolve()
- Connection status: _streamConnected, _streamLatency, _streamReconnects,
  _streamFrameCount, _streamByteCount tracked for stream health
- RTT tracking: periodic ping/pong every 5s measures round-trip latency
- Removed redundant _streamSync from flush() — diffs are already batched

Relay improvements:
- Diff merging: late joiners receive 1 consolidated sync frame instead
  of replaying hundreds of individual diffs
- Version counters merged: conflict resolution preserved across catchup
- Fallback: if JSON parse fails, falls back to raw sync + all diffs

Test updates:
- state_cache_signal_sync verifies merged payload (count: 1)
- All 54 relay tests pass
- All 8 examples pass regression
2026-02-26 18:02:31 -08:00
enzotar
c47852957f fix: merge duplicate click props + upgrade streaming examples
- Duplicate prop keys now merge into Block expressions
  click: a then click: b → Block([a, b])
- All actions fire in one click (was silently overwriting)
- streaming-mood.ds upgraded to semicolons
- streaming-stats.ds upgraded to semicolons
- Browser-verified: Happy button fires 3 actions (mood+color+energy)
- All 7 examples pass regression
2026-02-26 17:44:21 -08:00
enzotar
10b2717281 feat: multi-statement event handlers with semicolons
- Added Semicolon token to lexer
- Enables: click: items.push(x); input = ""
- Push-and-clear, increment-and-reset, clear-all patterns
- Browser-verified: both actions fire in one click
- All existing examples pass regression
2026-02-26 17:29:47 -08:00
enzotar
6c9d109ebd fix: match parser allows container bodies in arms
- Added can_be_pattern() with look-ahead disambiguation
- Ident only treated as pattern if followed by -> or (
- Keywords (row/column/when/each) correctly terminate match
- Match arms now support: "active" -> row [ Badge + text ]
- Siblings after match (text, button, row) no longer consumed
- Project Manager updated with rich row/Badge match arms
- All 6 existing examples pass regression
2026-02-26 17:19:50 -08:00
enzotar
f63ff52e2a feat: upgrade init starter app to showcase all DreamStack features
- Imports Card, Badge, Button from components/
- Counter with callback props, Greeting with when/else
- Mood match expression with Badge, Todo dynamic lists
- Full init → build flow verified (51,401 bytes, 0 errors)
2026-02-26 16:57:08 -08:00
enzotar
9d01f1b702 feat: component event callbacks + function prop forwarding
- ComponentUse wraps Assign/MethodCall/Block props as arrow functions
- Component prop wrapper preserves function props (typeof check)
- Event handler fallthrough calls function-type identifiers
- New: examples/callback-demo.ds with Button onClick callbacks
- All existing examples build successfully
2026-02-26 16:51:58 -08:00
enzotar
cbd6dfc7a6 feat: dynamic lists (push/remove/pop) + TodoMVC demo
- MethodCall AST node: obj.method(args) parsing
- Array push: items.push(x) → immutable spread+append
- Array remove: items.remove(idx) → filter by index
- Array pop: items.pop() → slice(0, -1)
- Fix: loop vars (todo, _idx) emitted without .value via is_local_var()
- Fix: _idx added to each loop scope for index-based event handlers
- New: examples/todomvc.ds — add, remove, clear all, fully reactive
2026-02-26 16:46:06 -08:00
enzotar
a7af39e900 fix: when/else parentNode null guard for slot context + match parser boundaries + showcase demo
- When/else inside slots: anchor parentNode is null during initial effect
  Fixed with named effect function + requestAnimationFrame retry
- Match parser now terminates on ] } else tokens (works inside containers)
- Updated Progress/Badge components
- Added examples/showcase.ds: 5-section demo exercising all features
2026-02-26 16:34:45 -08:00
enzotar
5425d7768c feat: dev server improvements - recursive watching, auto-open browser
- Recursive file watching: catches imported file changes from registry/
- Auto-detect project root: walks up to find registry/ or examples/ dir
- Auto-open browser on startup (xdg-open/open/cmd)
- Verified HMR live reload: 0ms recompile on file save
2026-02-26 16:19:33 -08:00
enzotar
76bb1bb3a2 feat: slot/children composition for components
- AST: added Expr::Slot variant
- Parser: 'slot' keyword renders children, [...] bracket children after ComponentUse
- Codegen: DS_{name}(props, __children) factory pattern
- Type checker: Slot => Type::View
- Updated Card component with slot for children
- Added examples/slot-demo.ds
2026-02-26 16:14:35 -08:00
enzotar
bb65e10f5c feat: when/else conditional branching
- AST: When(cond, body) -> When(cond, body, Option<else_body>)
- Parser: optional 'else -> expr' after when body
- Codegen: reactive DOM swap with anchor comments
- Signal graph + type checker updated for 3-arg When
- Component prop signal wrapping: .value compatible accessors
- Added examples/when-else-demo.ds
2026-02-26 16:03:29 -08:00
enzotar
55dc24eecc fix: component prop signal wrapping + import demo
- emit_component_decl now wraps props in signal-like accessors
- Props use { get value() { return props.X; } } pattern
- Missing props default to empty string instead of null
- Added examples/import-demo.ds demonstrating 3-component import
- Zero console errors when rendering imported Card, Badge, Button
2026-02-26 15:46:55 -08:00
enzotar
8a318e380e fix: integer division + streaming restart
Codegen: BinOp::Div now emits Math.trunc(l / r)
- Clock displays 0:1:30 instead of 0.016:1.5:30
- Affects both emit_expr and predicate_to_js

Lexer: removed duplicate 'in' keyword mapping
- InKw at line 312 is canonical, removed old In at line 338

Examples: added project-tracker.ds (each loops + cards)
2026-02-26 15:22:54 -08:00
enzotar
008f164ae7 feat: each loop, dreamstack init, expanded registry
Language:
- each item in list -> template (reactive list rendering)
- each/in tokens in lexer, Expr::Each in AST
- Reactive forEach codegen with scope push/pop
- Container trailing props: column [...] { variant: card }

CLI:
- dreamstack init [name] - scaffold new project
- Generates app.ds, components/, dreamstack.json
- 4 starter components (button, card, badge, input)

Registry expanded to 11 components:
- NEW: progress, alert, separator, toggle, avatar
- All embedded via include_str!

CSS: progress bar, avatar, separator, alert variants,
toggle switch, stat values (230+ lines design system)

Examples:
- each-demo.ds: list rendering demo
- dashboard.ds: glassmorphism cards with container variant
2026-02-26 14:42:00 -08:00
enzotar
a290bc1891 feat: container variant props, 11-component registry, rich dashboard
Parser:
- column/row/stack now parse trailing { props } after ]
- Enables: column [...] { variant: "card" }

Codegen:
- Container props dispatch: variant, class, click, style, layout
- variant_to_css() maps (tag, variant) → CSS class
- variant_map_js() for dynamic variants via inline JS map
- 230+ lines design system CSS (button/badge/card/dialog/toast/
  progress/alert/separator/toggle/avatar/stat)

Registry (11 components):
- button, input, card, badge, dialog, toast
- NEW: progress, alert, separator, toggle, avatar
- All embedded via include_str! for offline use

Examples:
- showcase.ds: component gallery with variant prop
- dashboard.ds: admin dashboard with glassmorphism cards
2026-02-26 13:58:33 -08:00
enzotar
7805b94704 feat: component registry with styled variants, dreamstack add/convert CLI, and showcase
- Phase 1: Component parser + codegen (emit_component_decl, emit_component_use, emit_match)
- Phase 2: 6 registry components (button, input, card, badge, dialog, toast)
- Phase 3: dreamstack add CLI with dependency resolution and --list/--all
- Phase 4: dreamstack convert TSX→DS transpiler with --shadcn GitHub fetch
- Phase 5: 120+ lines variant CSS (buttons, badges, cards, dialog, toast, input)
- New example: showcase.ds demonstrating all component styles
2026-02-26 13:27:49 -08:00
enzotar
61c26acfa7 improve: dependent types review — cycle detection, precision, error quality
- Fix ast_to_pred_expr silent Value fallback → opaque Call prevents false positives
- check_refinement now handles BoolLit/StringLit with human-readable display
- Integer equality/inequality uses exact i64 via try_resolve_ints (no f64 loss)
- Type::Refined handled in unwrap_reactive + new unwrap_refined() utility
- Type alias cycle detection via type_expr_references in Pass 0
- 9 new tests: predicate display, evaluate_static (int/compound/eq_precision),
  unwrap_refined, refined type display, cycle detection, readable violations

127 workspace tests pass (25 in ds-types), 0 failures
2026-02-26 11:21:43 -08:00
enzotar
9ef28bb53a feat: dependent types — refinement types, type aliases, type annotations
- Lexer: added 'type' and 'where' keywords
- AST: TypeExpr::Refined, Declaration::TypeAlias, LetDecl.type_annotation
- Parser: parse_type_alias_decl, parse_type_expr (Named, Generic, where)
- Type system: Type::Refined, Predicate/PredicateExpr with evaluate_static()
- Errors: RefinementViolation, TypeAliasCycle (Elm-style messages)
- Checker: type alias registry, resolve_type_expr, ast_to_predicate,
  static refinement checking for literal values
- Codegen: Phase 1b runtime guards, predicate_to_js helper

Syntax: type PositiveInt = Int where value > 0
        let count: PositiveInt = 5  -- static check passes
        let count: PositiveInt = -1 -- compile error

118 tests pass (16 in ds-types, 5 new for refinements)
2026-02-26 11:09:33 -08:00
enzotar
a8235c48b3 feat: stream composition API — select, schema, relay filtering
1. Receiver-side `select` clause:
   - `stream from "url" { select: field1, field2 }`
   - Parser, AST, codegen all updated
   - Emits: `_connectStream(url, ["field1","field2"])`
   - Client-side _csFilter strips unwanted fields

2. Schema announcement (0x32):
   - Sources send output schema on connect
   - Lists registered signal names and mode

3. Relay schema cache:
   - ChannelState stores schema from 0x32
   - Forwarded to late-joining receivers

4. Relay-side subscribe filter (0x33):
   - Receivers send wanted fields after connecting
   - Relay strips unwanted JSON keys from 0x30/0x31
     frames before forwarding — saves bandwidth

Protocol: SchemaAnnounce=0x32, SubscribeFilter=0x33
54 tests pass, all crates build clean.
2026-02-26 10:07:47 -08:00
enzotar
627ee44275 feat: explicit signal output API for stream declarations
Add 'output: field1, field2' syntax to stream declarations to control
which signals are exposed over the relay. Only listed signals are
registered in _signalRegistry (and thus streamed). Omitting output
streams all signals (backwards-compatible).

Also strips internal sync metadata (_pid, _v) from receiver state
so composition consumers only see clean signal values.

Parser: parse comma-separated idents after 'output:' key
AST: Vec<String> output field on StreamDecl
Codegen: conditional _registerSignal, delete _pid/_v on receive

Example: stream counter on 'ws://...' { mode: signal, output: count, doubled }
2026-02-26 08:56:32 -08:00
enzotar
b0e7de3b2e fix: signal composition — stream derived signals, fix identity check, correct relay routing
- Register derived signals in _signalRegistry so _streamSync includes them
- Auto-sync all signals (source + derived) after flush() recomputes effects
- Fix Object.assign identity check: create new object so signal setter detects changes
- Change _connectStream receiver path from /signal/main to /stream/default
- Initialize stream state with {} instead of null to prevent crashes
- Emit StreamFrom bindings directly without double-wrapping in signal()

Verified: static build shows Count: 9, Doubled: 18 on composition page.
HMR interference with WebSocket connections is a separate issue.
2026-02-25 23:55:05 -08:00
enzotar
e5ff612197 feat: per-signal version counters for conflict resolution
- _signalVersions: monotonic counter per signal, incremented on each local mutation
- Diffs include _v: {name: version} for version comparison
- _applyRemoteDiff only applies if remote version >= local version
- Prevents stale overwrites when both devices edit simultaneously
- onopen snapshot includes version map for late-joiner consistency
2026-02-25 21:58:14 -08:00
enzotar
0290ed464a fix: streaming polish — bind diff, state snapshot, dead code cleanup
- bind: input handler now emits _streamDiff so typed text syncs
- Peers broadcast full state snapshot on WS open (late joiners sync)
- Removed dead _handleRemoteInput 0x31 case (old source/receiver model)
- Preserved scroll (0x50), pointer, and key handlers
2026-02-25 21:55:49 -08:00
enzotar
8c9f5e8bfb fix: add _streamDiff to push/pop/reverse built-ins
Array-mutating built-in functions now emit DS._streamDiff() for
streaming sync. Previously only signal assignments emitted diffs.
2026-02-25 21:47:50 -08:00
enzotar
a943d2e2e9 feat: peer mode relay + self-echo filtering for true bidirectional sync
- Added /peer/{name} route to relay: all clients are equal peers
- handle_peer: binary broadcast to all other peers, catchup for late joiners
- Simplified runtime: single /peer/ WS replaces dual source+receiver
- _peerId: random 8-char ID prevents self-echo from broadcast
- _pid in each diff JSON, filtered in _applyRemoteDiff
2026-02-25 21:37:17 -08:00
enzotar
5f09886c3c fix: bidirectional streaming sync — phone→laptop now works
- Fix URL routing: /source/default and /stream/default paths
- _streamDiff sends via both source WS and receiver WS (INPUT flag)
- Source rebroadcasts 0x31 diffs from receivers to all other receivers
- Echo loop guard prevents infinite rebroadcast
2026-02-25 21:11:12 -08:00
enzotar
69c7ff1e22 feat: bidirectional signal streaming sync
- _signalRegistry: maps signal names → signal objects
- _registerSignal: called after each DS.signal() declaration
- _applyRemoteDiff: JSON diff → update local signals + flush
- _initStreamReceiver: parallel receiver WS for incoming diffs
- Echo loop guard: _applyingRemoteDiff prevents re-broadcasting
- 0x31 handler in _handleRemoteInput for signal diff frames

Changes sync both directions: laptop → phone, phone → laptop.
2026-02-25 21:00:57 -08:00
enzotar
55ec9353ae feat: v2 codegen hardening — scoped local variables
Replace flat HashSet<String> local_vars with Vec<HashSet<String>> scope
stack. For-in loops push/pop scopes for loop variables. Nested loops
no longer clobber outer loop variable visibility.

Methods: push_scope(), pop_scope(), is_local_var()
110 tests, 0 failures.
2026-02-25 20:39:41 -08:00
enzotar
6368b798cf feat: v2 module system — import/export with multi-file compilation
Syntax:
  import { Counter, shared_count } from "./shared"
  export let shared_count = 0
  export component Counter = ...

Implementation:
- Lexer: Import, Export keywords
- AST: ImportDecl(names, source), Export(name, inner_decl)
- Parser: parse_import_decl, parse_export_decl
- CLI: resolve_imports() — recursive file resolution, dedup, inline

Resolves relative paths, adds .ds extension, handles transitive imports.
110 tests, 0 failures.
2026-02-25 20:36:18 -08:00