rip-lang 3.7.4 → 3.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,7 +7,112 @@ All notable changes to Rip will be documented in this file.
7
7
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
8
8
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
9
9
 
10
- ## [3.7.4] - 2026-02-11
10
+ ## [3.8.9] - 2026-02-16
11
+
12
+ ### Compiler — Grammar Desugaring & Cleanup
13
+
14
+ - **`until` desugared to `while`** — Grammar now emits `["while", ["!", cond], ...]` directly, eliminating `generateUntil` from the compiler. Also fixes the `until...when` guard bug where the guard expression was silently dropped.
15
+ - **`unless` desugared to `if`** — Grammar now emits `["if", ["!", cond], ...]` for all `unless` forms, removing ~20 `unless`-specific code paths from the compiler (dispatch table, postfix conditionals, assignment handlers, return/throw handlers, control flow analysis).
16
+ - **`toSearchable` renamed to `toMatchable`** — The regex helper name now matches the `.match()` API it wraps.
17
+ - **Added missing `%%=` handler** — The mathematical modulo assignment operator now works correctly instead of crashing during code generation.
18
+
19
+ ## [3.8.8] - 2026-02-16
20
+
21
+ ### Compiler — Refactoring & Cleanup
22
+
23
+ - **Comprehension generator deduplication** — Extracted shared `_forInHeader`, `_forOfHeader`, and `_forAsHeader` helpers, consolidating loop header construction across `generateComprehension`, `generateComprehensionWithTarget`, and `generateComprehensionAsLoop`.
24
+ - **Cleaner for-of loop output** — `for own k of obj` now generates flatter JavaScript using `continue` guard clauses instead of nested `if` blocks.
25
+ - **Component child deduplication** — Extracted `appendChildren` helper in `components.js`, consolidating duplicate child-processing logic from `generateTag` and `generateDynamicTag`. Also fixed a missing `componentMembers` check in `generateDynamicTag`.
26
+ - **Dead code removal** — Removed unused `break-if` and `continue-if` compiler handlers (the grammar handles these through the normal `if` path).
27
+
28
+ ### REPL — Bug Fix
29
+
30
+ - **Comprehension crash fix** — The REPL now correctly handles multi-line expressions (comprehensions, IIFEs). Previously, the result capture logic produced broken JavaScript by prepending `__result =` to the closing `})();` line instead of the expression start.
31
+
32
+ ### Documentation
33
+
34
+ - Fixed inaccurate content on the Rip UI demo About page (compiler/framework sizes, architecture description).
35
+
36
+ ## [3.8.7] - 2026-02-14
37
+
38
+ Rip UI loading optimization (combined bundle, build-time compilation, FOUC prevention). See `packages/ui/CHANGELOG.md` v0.3.2.
39
+
40
+ ## [3.8.6] - 2026-02-13
41
+
42
+ ### Compiler — Render Block Fix
43
+
44
+ - **Render block fix** — Identifiers matching HTML tag names (e.g., `title`) are no longer misclassified as template elements when preceded by control flow keywords (`if`, `unless`, `while`, `until`, `when`).
45
+
46
+ Rip UI hash routing and static demo. See `packages/ui/CHANGELOG.md` v0.3.1.
47
+
48
+ ## [3.8.5] - 2026-02-13
49
+
50
+ ### Build — GitHub Pages Fixes
51
+
52
+ - **Copy ui.rip instead of symlink** — `bun run browser` now copies `packages/ui/ui.rip` to `docs/dist/ui.rip` on every build. Symlinks return 404 on GitHub Pages.
53
+ - Fixed Async example to use clean chained `!` syntax now that precedence is correct.
54
+
55
+ ## [3.8.4] - 2026-02-13
56
+
57
+ ### Compiler — Chained Dammit Operator Fix
58
+
59
+ - **Chained `!` parenthesization** — `fetch!(url).json!` now correctly compiles to `await (await fetch(url)).json()` instead of `await await fetch(url).json()` which had wrong JS precedence. The `await` from `!` metadata is now parenthesized when used as a property access base.
60
+ - Playground Async example restored to clean `fetch!(url).json!` syntax.
61
+ - 2 new tests (1,241 total).
62
+
63
+ ## [3.8.3] - 2026-02-13
64
+
65
+ ### Lexer — Heregex Forward Slash Escaping
66
+
67
+ - **Auto-escape `/` in heregex** — Forward slashes inside `///...///` are now automatically escaped to `\/` in the compiled regex literal. Previously required manual `\/` escaping, defeating the purpose of heregex.
68
+ - 1 new test (1,239 total).
69
+
70
+ ## [3.8.2] - 2026-02-13
71
+
72
+ ### Compiler — Class Constructor Fixes
73
+
74
+ - **`@param` defaults in constructors** — `constructor: (@count = 0) ->` now correctly compiles to `constructor(count = 0) { this.count = count; }` instead of producing invalid `(.,this,count)` syntax.
75
+ - **`super` with `@param` in subclass constructors** — `constructor: (@name) -> super @name, "woof"` now compiles to `constructor(_name) { super(_name, "woof"); this.name = _name; }` using a temporary parameter to avoid illegal `this` access before `super()`.
76
+ - **Single-expression constructor autoAssignments** — `@param` assignments are now emitted in single-expression constructor bodies (previously only worked in block bodies).
77
+ - 3 new tests (1,238 total).
78
+
79
+ ## [3.8.1] - 2026-02-13
80
+
81
+ ### Playground — Fix Class Examples
82
+
83
+ - **Constructor syntax fix** — All playground examples now use `constructor: (@name) ->` instead of the bare `(@name) ->` shorthand, which produced invalid JS output.
84
+
85
+ ## [3.8.0] - 2026-02-12
86
+
87
+ ### Playground — Example Snippets & Source Persistence
88
+
89
+ - **Example snippets dropdown** — 6 curated examples (Basics, Reactive State, Classes, Regex & Strings, Async & Dammit, Full Demo) plus a Custom option for user code.
90
+ - **Source persistence** — Editor content saved to localStorage with 2-second debounce, restored on page load.
91
+ - **Auto-switch to Custom** — Editing code after selecting an example automatically switches the dropdown to Custom.
92
+ - Applied to all three playground versions (playground-rip.html, playground-js.html, playground-rip-ui.html).
93
+
94
+ ### Language — Raw Heredocs
95
+
96
+ - **Raw heredocs (`'''\` and `"""\`)** — Appending `\` to a heredoc opener keeps JS escape sequences (`\n`, `\t`, `\u`, `\x`, `\\`) literal in the output.
97
+ - **`.class` shorthand fix** — `div.foo` or `.foo` with indented children in render blocks now produces correct JS.
98
+
99
+ ### Parser — Recursive Descent Generator
100
+
101
+ - **Lunar grammar** (`src/grammar/lunar.rip`) — New recursive descent parser generator producing `src/parser-rd.js`.
102
+ - **98.3% test parity** — 1,162 of 1,182 tests passing with the generated parser.
103
+
104
+ ## [3.7.4] - 2026-02-12
105
+
106
+ ### Compiler — Reactive Scoping & Component Fixes
107
+
108
+ - **Effect cleanup** — `__effect` now captures return values as cleanup functions, run before re-execution and on disposal. Backward-compatible.
109
+ - **Component scope leak** — `collectProgramVariables` no longer recurses into component bodies. Inner `:=` variables don't pollute the outer scope.
110
+ - **Object key reactive transform** — Object literal keys are no longer transformed to `key.value` when the key name matches a reactive variable.
111
+ - **Component effect index** — Fixed `effect[1]` → `effect[2]` for the body of `~>` in components.
112
+ - **Component effect wrapping** — Effects now wrapped in `() => { expr; }` for proper reactivity.
113
+ - **Dot-chain property names** — `app.data.count` no longer transforms `count` as a reactive member when it's a property name in a dot chain.
114
+ - **Reactive prop passthrough** — `buildComponentProps` passes `:=` members as signals (not values) to child components. Child's `__state` returns the signal as-is.
115
+ - **Child unmounting** — `generateChildComponent` tracks child instances in `_children`. `__Component.unmount()` cascades depth-first.
11
116
 
12
117
  ### Compiler — Nested Function Scope Chain
13
118
 
package/README.md CHANGED
@@ -9,15 +9,15 @@
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.7.4-blue.svg" alt="Version"></a>
12
+ <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.8.9-blue.svg" alt="Version"></a>
13
13
  <a href="#zero-dependencies"><img src="https://img.shields.io/badge/dependencies-ZERO-brightgreen.svg" alt="Dependencies"></a>
14
- <a href="#"><img src="https://img.shields.io/badge/tests-1225%2F1225-brightgreen.svg" alt="Tests"></a>
14
+ <a href="#"><img src="https://img.shields.io/badge/tests-1%2C242%2F1%2C242-brightgreen.svg" alt="Tests"></a>
15
15
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
16
16
  </p>
17
17
 
18
18
  ---
19
19
 
20
- Rip is a modern language inspired by CoffeeScript. It compiles to **ES2022** (classes, `?.`, `??`, modules), adds about a **dozen new operators**, includes **built-in reactivity**, and sports a self-hosting compiler with **zero dependencies** — all in about 10,800 lines of code.
20
+ Rip is a modern language inspired by CoffeeScript. It compiles to **ES2022** (classes, `?.`, `??`, modules), adds about a **dozen new operators**, includes **built-in reactivity**, and sports a self-hosting compiler with **zero dependencies** — all in about 11,000 lines of code.
21
21
 
22
22
  > **No imports. No hooks. No dependency arrays. Just write code.**
23
23
 
@@ -146,9 +146,9 @@ State, computed values, and effects as language operators:
146
146
  | Operator | Mnemonic | Example | What it does |
147
147
  |----------|----------|---------|--------------|
148
148
  | `=` | "gets value" | `x = 5` | Regular assignment |
149
- | `:=` | "has state" | `count := 0` | Reactive state container |
149
+ | `:=` | "gets state" | `count := 0` | Reactive state container |
150
150
  | `~=` | "always equals" | `twice ~= count * 2` | Auto-updates on changes |
151
- | `~>` | "reacts to" | `~> log count` | Runs on dependency changes |
151
+ | `~>` | "always calls" | `~> log count` | Runs on dependency changes |
152
152
  | `=!` | "equals, dammit!" | `MAX =! 100` | Readonly constant |
153
153
 
154
154
  ---
@@ -227,6 +227,16 @@ html = '''
227
227
  # Result: " <div>\n <p>Hello</p>\n </div>"
228
228
  ```
229
229
 
230
+ **Raw heredoc** — Append `\` to the opening delimiter (`'''\` or `"""\`) to prevent escape processing. Backslash sequences like `\n`, `\t`, `\u` stay literal:
231
+
232
+ ```coffee
233
+ script = '''\
234
+ echo "hello\nworld"
235
+ sed 's/\t/ /g' file.txt
236
+ \'''
237
+ # \n and \t stay as literal characters, not newline/tab
238
+ ```
239
+
230
240
  **Heregex** — Extended regex with comments and whitespace:
231
241
 
232
242
  ```coffee
@@ -252,7 +262,7 @@ Rip's reactivity is framework-agnostic — use it with React, Vue, Svelte, or va
252
262
 
253
263
  ## Rip UI
254
264
 
255
- Ship the 40KB Rip compiler to the browser. Components are `.rip` source files, compiled on demand, rendered with fine-grained reactivity. No build step. No bundler.
265
+ Ship the ~47KB Rip compiler to the browser. Components are `.rip` source files, compiled on demand, rendered with fine-grained reactivity. No build step. No bundler.
256
266
 
257
267
  ```coffee
258
268
  Counter = component
@@ -267,7 +277,7 @@ Counter = component
267
277
 
268
278
  Two keywords — `component` and `render` — are all the language adds. Everything else (`:=` state, `~=` computed, methods, lifecycle) is standard Rip.
269
279
 
270
- See [@rip-lang/ui](packages/ui/) for the full framework: file-based router, reactive stash, component store, and renderer.
280
+ See [@rip-lang/ui](packages/ui/) for the full framework: file-based router, reactive stash, component store, and renderer. **[Try the demo](https://shreeve.github.io/rip-lang/demo.html)** — a complete app in one HTML file.
271
281
 
272
282
  ---
273
283
 
@@ -279,9 +289,9 @@ See [@rip-lang/ui](packages/ui/) for the full framework: file-based router, reac
279
289
  | **Reactivity** | None | Built-in |
280
290
  | **Dependencies** | Multiple | Zero |
281
291
  | **Self-hosting** | No | Yes |
282
- | **Lexer** | 3,558 LOC | 1,958 LOC |
283
- | **Compiler** | 10,346 LOC | 3,378 LOC |
284
- | **Total** | 17,760 LOC | ~10,800 LOC |
292
+ | **Lexer** | 3,558 LOC | 2,024 LOC |
293
+ | **Compiler** | 10,346 LOC | 3,289 LOC |
294
+ | **Total** | 17,760 LOC | ~11,000 LOC |
285
295
 
286
296
  Smaller codebase, modern output, built-in reactivity.
287
297
 
@@ -316,25 +326,25 @@ await rip("res = fetch! 'https://api.example.com/todos/1'; res.json!") // → {
316
326
 
317
327
  ```
318
328
  Source -> Lexer -> emitTypes -> Parser -> S-Expressions -> Codegen -> JavaScript
319
- (1,958) (types.js) (359) ["=", "x", 42] (3,378) + source map
329
+ (2,024) (types.js) (359) ["=", "x", 42] (3,431) + source map
320
330
  ```
321
331
 
322
332
  Simple arrays (with `.loc`) instead of AST node classes. The compiler is self-hosting — `bun run parser` rebuilds from source.
323
333
 
324
334
  | Component | File | Lines |
325
335
  |-----------|------|-------|
326
- | Lexer + Rewriter | `src/lexer.js` | 1,958 |
327
- | Compiler + Codegen | `src/compiler.js` | 3,378 |
336
+ | Lexer + Rewriter | `src/lexer.js` | 2,024 |
337
+ | Compiler + Codegen | `src/compiler.js` | 3,431 |
328
338
  | Type System | `src/types.js` | 1,099 |
329
- | Component System | `src/components.js` | 1,240 |
330
- | Source Maps | `src/sourcemaps.js` | 122 |
339
+ | Component System | `src/components.js` | 1,281 |
340
+ | Source Maps | `src/sourcemaps.js` | 121 |
331
341
  | Parser (generated) | `src/parser.js` | 359 |
332
- | Grammar | `src/grammar/grammar.rip` | 945 |
333
- | Parser Generator | `src/grammar/solar.rip` | 916 |
342
+ | Grammar | `src/grammar/grammar.rip` | 944 |
343
+ | Parser Generator | `src/grammar/solar.rip` | 929 |
334
344
  | REPL | `src/repl.js` | 582 |
335
- | Browser Entry | `src/browser.js` | 119 |
336
- | Tags | `src/tags.js` | 63 |
337
- | **Total** | | **~10,774** |
345
+ | Browser Entry | `src/browser.js` | 125 |
346
+ | Tags | `src/tags.js` | 62 |
347
+ | **Total** | | **~10,957** |
338
348
 
339
349
  ---
340
350
 
@@ -344,14 +354,14 @@ Rip includes optional packages for full-stack development:
344
354
 
345
355
  | Package | Version | Purpose |
346
356
  |---------|---------|---------|
347
- | [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.7.4 | Core language compiler |
348
- | [@rip-lang/api](packages/api/) | 1.1.4 | HTTP framework (Sinatra-style routing, 37 validators) |
349
- | [@rip-lang/server](packages/server/) | 1.1.3 | Multi-worker app server (hot reload, HTTPS, mDNS) |
350
- | [@rip-lang/db](packages/db/) | 1.1.2 | DuckDB server with official UI (pure Bun FFI) |
351
- | [@rip-lang/ui](packages/ui/) | 0.2.0 | Zero-build reactive web framework (stash, router, components) |
352
- | [@rip-lang/swarm](packages/swarm/) | 1.1.1 | Parallel job runner with worker pool |
353
- | [@rip-lang/csv](packages/csv/) | 1.1.1 | CSV parser + writer |
354
- | [@rip-lang/schema](packages/schema/) | 0.1.0 | ORM + validation |
357
+ | [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.8.9 | Core language compiler |
358
+ | [@rip-lang/api](packages/api/) | 1.1.6 | HTTP framework (Sinatra-style routing, 37 validators) |
359
+ | [@rip-lang/server](packages/server/) | 1.1.5 | Multi-worker app server (hot reload, HTTPS, mDNS) |
360
+ | [@rip-lang/db](packages/db/) | 1.1.4 | DuckDB server with official UI (pure Bun FFI) |
361
+ | [@rip-lang/ui](packages/ui/) | 0.3.2 | Zero-build reactive web framework (stash, router, hash routing) |
362
+ | [@rip-lang/swarm](packages/swarm/) | 1.1.3 | Parallel job runner with worker pool |
363
+ | [@rip-lang/csv](packages/csv/) | 1.1.3 | CSV parser + writer |
364
+ | [@rip-lang/schema](packages/schema/) | 0.1.1 | ORM + validation |
355
365
  | [VS Code Extension](packages/vscode/) | 0.3.1 | Syntax highlighting, type intelligence, source maps |
356
366
 
357
367
  ```bash
@@ -390,7 +400,7 @@ rip file.rip # Run
390
400
  rip -c file.rip # Compile
391
401
  rip -t file.rip # Tokens
392
402
  rip -s file.rip # S-expressions
393
- bun run test # 1225 tests
403
+ bun run test # 1241 tests
394
404
  bun run parser # Rebuild parser
395
405
  bun run browser # Build browser bundle
396
406
  ```
@@ -401,12 +411,10 @@ bun run browser # Build browser bundle
401
411
 
402
412
  | Guide | Description |
403
413
  |-------|-------------|
404
- | [docs/RIP-GUIDE.md](docs/RIP-GUIDE.md) | Users / AI practical guide for using Rip in projects |
414
+ | [docs/RIP-LANG.md](docs/RIP-LANG.md) | Full language reference (syntax, operators, reactivity, types, future ideas) |
415
+ | [docs/RIP-INTERNALS.md](docs/RIP-INTERNALS.md) | Compiler architecture (lexer, parser, codegen, S-expressions) |
416
+ | [docs/RIP-TYPES.md](docs/RIP-TYPES.md) | Type system specification |
405
417
  | [AGENT.md](AGENT.md) | AI agents — get up to speed for working on the compiler |
406
- | [docs/RIP-LANG.md](docs/RIP-LANG.md) | Users — full language reference |
407
- | [docs/RIP-TYPES.md](docs/RIP-TYPES.md) | Contributors — type system specification |
408
- | [docs/RIP-REACTIVITY.md](docs/RIP-REACTIVITY.md) | Users — reactivity deep dive |
409
- | [docs/RIP-INTERNALS.md](docs/RIP-INTERNALS.md) | Contributors — compiler architecture |
410
418
 
411
419
  ---
412
420
 
@@ -572,11 +572,9 @@ rip> .js # Toggle JS display
572
572
  ---
573
573
 
574
574
  **See Also:**
575
- - [RIP-GUIDE.md](RIP-GUIDE.md) — Practical guide for using Rip
576
- - [RIP-LANG.md](RIP-LANG.md) — Language reference
575
+ - [RIP-LANG.md](RIP-LANG.md) — Language reference (includes reactivity deep dive)
577
576
  - [RIP-TYPES.md](RIP-TYPES.md) — Type system specification
578
- - [RIP-REACTIVITY.md](RIP-REACTIVITY.md) — Reactivity deep dive
579
577
 
580
578
  ---
581
579
 
582
- *Rip 3.7 — 1,219 tests passing — Zero dependencies — Self-hosting — ~10,800 LOC*
580
+ *Rip 3.8 — 1,241 tests passing — Zero dependencies — Self-hosting — ~11,000 LOC*
package/docs/RIP-LANG.md CHANGED
@@ -23,6 +23,7 @@ Rip is a modern reactive language that compiles to ES2022 JavaScript. It combine
23
23
  13. [JavaScript Interop](#13-javascript-interop)
24
24
  14. [Common Patterns](#14-common-patterns)
25
25
  15. [Quick Reference](#15-quick-reference)
26
+ 16. [Future Ideas](#16-future-ideas)
26
27
 
27
28
  ---
28
29
 
@@ -84,6 +85,11 @@ multiline = """
84
85
  """
85
86
  # Result: "This is a\nmulti-line string" (closing """ at col 2 strips 2 spaces)
86
87
 
88
+ # Raw heredocs — append \ to keep escape sequences literal
89
+ script = '''\
90
+ echo "hello\nworld" # \n stays as \n, not a newline
91
+ \'''
92
+
87
93
  # Numbers
88
94
  count = 42
89
95
  price = 19.99
@@ -697,9 +703,9 @@ Rip's reactive features are **language-level operators**, not library imports.
697
703
  | Operator | Name | Read as | Purpose |
698
704
  |----------|------|---------|---------|
699
705
  | `=` | Assign | "gets value" | Regular assignment |
700
- | `:=` | State | "has state" | Reactive state variable |
706
+ | `:=` | State | "gets state" | Reactive state variable |
701
707
  | `~=` | Computed | "always equals" | Computed value (auto-updates) |
702
- | `~>` | Effect | "reacts to" | Side effect on dependency change |
708
+ | `~>` | Effect | "always calls" | Side effect on dependency change |
703
709
  | `=!` | Readonly | "equals, dammit!" | Constant (`const`) |
704
710
 
705
711
  ## State (`:=`)
@@ -829,6 +835,64 @@ __effect(() => { console.log(count.value); });
829
835
 
830
836
  The reactive runtime is **automatically inlined** when needed. Non-reactive code produces clean output with no runtime overhead.
831
837
 
838
+ ## Effect Cleanup
839
+
840
+ Effects may return a cleanup function that runs before re-execution and on disposal:
841
+
842
+ ```coffee
843
+ ~>
844
+ id = setInterval tick, 1000
845
+ -> clearInterval id # cleanup: returned arrow function
846
+ ```
847
+
848
+ This enables higher-level reactive utilities — without adding anything to the language.
849
+
850
+ ## Timing Primitives
851
+
852
+ Unlike React's `useTransition` or Vue's flush modes, Rip does not add timing to the framework. Timing composes from the triad:
853
+
854
+ ```coffee
855
+ # Delay — truthy after source is stable for N ms, falsy immediately
856
+ showLoading := delay 200 -> loading
857
+
858
+ # Debounce — propagates after value stops changing for N ms
859
+ debouncedQuery := debounce 300 -> query
860
+
861
+ # Throttle — at most one update per N ms
862
+ smoothScroll := throttle 100 -> scrollY
863
+
864
+ # Hold — once true, stays true for at least N ms
865
+ showSaved := hold 2000 -> saved
866
+ ```
867
+
868
+ All four are implemented using `:=` (output signal) + `~>` (watches source, manages timers) + effect cleanup (cancels pending timers). No new compiler features, no scheduler.
869
+
870
+ ### Writable Timing Signals
871
+
872
+ Timing utilities can wrap a source signal directly:
873
+
874
+ ```coffee
875
+ navigating = delay 100, __state(false)
876
+ ```
877
+
878
+ Reads return the delayed value; writes update the source immediately. A drop-in replacement for `__state` with asymmetric behavior.
879
+
880
+ ## Types and Reactivity
881
+
882
+ Reactive operators work with Rip's optional type system:
883
+
884
+ ```coffee
885
+ count:: number := 0 # Typed state
886
+ doubled:: number ~= count * 2 # Typed computed
887
+ ```
888
+
889
+ Type annotations are erased from `.js` output. In `.d.ts` output, reactive state emits `Signal<T>` and computed values emit `Computed<T>`:
890
+
891
+ ```ts
892
+ declare const count: Signal<number>;
893
+ declare const doubled: Computed<number>;
894
+ ```
895
+
832
896
  ---
833
897
 
834
898
  # 7. Async Patterns
@@ -1383,4 +1447,87 @@ count = 10 # Logs: "Count: 10, Doubled: 20"
1383
1447
 
1384
1448
  ---
1385
1449
 
1386
- *Rip 3.7 1,219 tests passing — Zero dependencies — Self-hosting — ~10,800 LOC*
1450
+ # 16. Future Ideas
1451
+
1452
+ Ideas and candidates that have been discussed but not yet implemented.
1453
+
1454
+ ## Standard Library (`stdlib`)
1455
+
1456
+ Rip is a zero-dependency language, but a small standard library of useful
1457
+ utilities would save users from writing the same one-liners in every project.
1458
+ These are **not** language features — they're plain functions that could ship
1459
+ as a prelude or optional import.
1460
+
1461
+ ### Candidates
1462
+
1463
+ ```coffee
1464
+ # Printing (Ruby's p)
1465
+ p = console.log
1466
+
1467
+ # Exit with optional code (uses implicit `it`)
1468
+ exit = -> process.exit(it)
1469
+
1470
+ # Tap — call a function for side effects, return the original value
1471
+ # Useful in pipe chains: data |> tap(console.log) |> process
1472
+ tap = (v, fn) -> fn(v); v
1473
+
1474
+ # Identity — returns its argument unchanged
1475
+ # Useful as a default callback: items.filter(id)
1476
+ id = -> it
1477
+
1478
+ # No-op — does nothing
1479
+ # Useful as a default handler: onClick ?= noop
1480
+ noop = ->
1481
+
1482
+ # String method aliases (shorter names for common checks)
1483
+ String::starts = String::startsWith
1484
+ String::ends = String::endsWith
1485
+ String::has = String::includes
1486
+
1487
+ # Clamp a value to a range
1488
+ clamp = (v, lo, hi) -> Math.min(Math.max(v, lo), hi)
1489
+
1490
+ # Sleep for N milliseconds (returns a Promise)
1491
+ sleep = (ms) -> new Promise (resolve) -> setTimeout resolve, ms
1492
+
1493
+ # Times helper — call a function N times, collect results
1494
+ times = (n, fn) -> (fn(i) for i in [0...n])
1495
+ ```
1496
+
1497
+ ### Design Questions
1498
+
1499
+ - **Prelude vs import?** Should these be injected automatically (like Go's
1500
+ `fmt` or Rip's reactive runtime), or explicitly imported (`import { p, tap }
1501
+ from '@rip-lang/std'`)? Leaning toward explicit — Rip's philosophy is zero
1502
+ magic in the output.
1503
+
1504
+ - **Scope?** Keep it tiny. A stdlib that grows to 500 functions defeats the
1505
+ purpose. Each entry should save real keystrokes on something people do
1506
+ constantly.
1507
+
1508
+ - **Node vs Browser?** Some helpers (like `exit`) are Node-only. Others (like
1509
+ `p`, `tap`, `sleep`) work everywhere. May want to split into `std` (universal)
1510
+ and `std/node` (server-only).
1511
+
1512
+ ## Future Syntax Ideas
1513
+
1514
+ Each would need design discussion before building.
1515
+
1516
+ - **`defer`** — Go-style cleanup that runs when the function exits. Compiles
1517
+ to try/finally. `defer file.close()`.
1518
+
1519
+ - **Pattern matching** — `match value` with destructuring arms. Big feature,
1520
+ needs careful design.
1521
+
1522
+ - **Reactive resource operator (`~>?`)** — Language-level `createResource`.
1523
+ `user ~>? fetch!("/api/users/#{id}").json!` gives `user.loading`,
1524
+ `user.error`, `user.data`. Park until real-world usage shows demand.
1525
+
1526
+ - **Pipe operator (`|>`) — Hack-style placeholder** — Currently Rip uses
1527
+ Elixir-style first-arg insertion. A `%` placeholder for arbitrary position
1528
+ (`data |> fn(1, %, 3)`) could be added later if needed. Current design
1529
+ covers 95%+ of cases.
1530
+
1531
+ ---
1532
+
1533
+ *Rip 3.8 — 1,241 tests passing — Zero dependencies — Self-hosting — ~11,000 LOC*
package/docs/RIP-TYPES.md CHANGED
@@ -1977,6 +1977,5 @@ The type system uses a two-phase approach:
1977
1977
  ---
1978
1978
 
1979
1979
  **See Also:**
1980
- - [RIP-LANG.md](RIP-LANG.md) — Language reference
1981
- - [RIP-REACTIVITY.md](RIP-REACTIVITY.md) — Reactive system details
1980
+ - [RIP-LANG.md](RIP-LANG.md) — Language reference (includes reactivity and types)
1982
1981
  - [RIP-INTERNALS.md](RIP-INTERNALS.md) — Compiler internals