rip-lang 3.0.2 → 3.2.0
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 +47 -5
- package/README.md +48 -3
- package/bin/rip +24 -2
- package/docs/RIP-INTERNALS.md +22 -14
- package/docs/RIP-LANG.md +48 -8
- package/docs/RIP-REACTIVITY.md +21 -0
- package/docs/RIP-TYPES.md +1345 -595
- package/docs/dist/rip.browser.js +2281 -345
- package/docs/dist/rip.browser.min.js +283 -207
- package/docs/dist/rip.browser.min.js.br +0 -0
- package/package.json +6 -2
- package/src/browser.js +1 -1
- package/src/compiler.js +80 -9
- package/src/components.js +1239 -0
- package/src/grammar/grammar.rip +47 -1
- package/src/grammar/solar.rip +11 -11
- package/src/lexer.js +300 -4
- package/src/parser.js +217 -214
- package/src/repl.js +53 -1
- package/src/tags.js +62 -0
- package/src/types.js +718 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,49 @@ 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.1.0] - 2026-02-08
|
|
11
|
+
|
|
12
|
+
### Rip UI — Zero-Build Reactive Web Framework
|
|
13
|
+
|
|
14
|
+
Rip UI inverts the traditional web development model. Instead of building and
|
|
15
|
+
bundling on the server, the 40KB Rip compiler ships to the browser. Components
|
|
16
|
+
are delivered as `.rip` source files, stored in a browser-local Virtual File
|
|
17
|
+
System, compiled on demand, and rendered with fine-grained DOM updates.
|
|
18
|
+
|
|
19
|
+
**Component model** — Two keywords added to the language:
|
|
20
|
+
|
|
21
|
+
- `component` — Declares an anonymous ES6 class with reactive props, computed
|
|
22
|
+
values, effects, methods, and lifecycle hooks. `@` properties become props
|
|
23
|
+
the parent can set. `:=` creates signals, `~=` creates computed values.
|
|
24
|
+
- `render` — Defines a Pug/Jade-like template DSL inside a component. Tags are
|
|
25
|
+
bare identifiers, classes use dot notation (`div.card.active`), dynamic
|
|
26
|
+
classes use dot-parens (`div.("active" if @selected)`), and events use
|
|
27
|
+
`@click: handler`. No virtual DOM — each reactive binding creates a direct
|
|
28
|
+
effect that updates exactly the DOM nodes it touches.
|
|
29
|
+
|
|
30
|
+
**Framework modules** (all in `packages/ui/`):
|
|
31
|
+
|
|
32
|
+
| Module | Role |
|
|
33
|
+
|--------|------|
|
|
34
|
+
| `stash.js` | Deep reactive state tree with path-based navigation |
|
|
35
|
+
| `vfs.js` | Browser-local Virtual File System with file watchers |
|
|
36
|
+
| `router.js` | File-based router (URL ↔ VFS paths, History API) |
|
|
37
|
+
| `renderer.js` | Component lifecycle, layout nesting, route transitions |
|
|
38
|
+
| `ui.js` | `createApp` entry point, re-exports everything |
|
|
39
|
+
|
|
40
|
+
**Compiler changes** (`src/components.js`, 1,193 lines):
|
|
41
|
+
|
|
42
|
+
- 22 methods installed on `CodeGenerator.prototype` via `installComponentSupport()`
|
|
43
|
+
- Categorizes component body into state, computed, readonly, methods, effects, render
|
|
44
|
+
- Emits fine-grained DOM creation (`_create()`) and reactive setup (`_setup()`)
|
|
45
|
+
- Block factories for conditionals and loops with disposable effects
|
|
46
|
+
- Keyed reconciliation for list rendering
|
|
47
|
+
- Component runtime emitted only when `component` keyword is used
|
|
48
|
+
|
|
49
|
+
**No build step. No bundler. No configuration files.**
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
10
53
|
## [3.0.0] - 2026-02-07
|
|
11
54
|
|
|
12
55
|
### Complete Rewrite
|
|
@@ -27,8 +70,6 @@ Rip 3.0 is a ground-up rewrite of the entire compiler pipeline. Every component
|
|
|
27
70
|
#### Removed
|
|
28
71
|
- Postfix spread/rest (`x...`) — use prefix `...x` (ES6)
|
|
29
72
|
- Prototype access (`x::y`, `x?::y`) — use `.prototype` or class syntax
|
|
30
|
-
- Soak call sugar (`fn?(arg)`) — use `fn?.(arg)` (ES6 optional call)
|
|
31
|
-
- Soak index sugar (`arr?[i]`) — use `arr?.[i]` (ES6 optional index)
|
|
32
73
|
- `is not` contraction — use `isnt`
|
|
33
74
|
|
|
34
75
|
#### Added
|
|
@@ -37,15 +78,16 @@ Rip 3.0 is a ground-up rewrite of the entire compiler pipeline. Every component
|
|
|
37
78
|
- `as!` async shorthand: `for x as! iterable` (shorthand for `for await x as iterable`)
|
|
38
79
|
|
|
39
80
|
#### Kept
|
|
40
|
-
- Existence check: `x?` compiles to `(x != null)`
|
|
81
|
+
- Existence check: `x?` compiles to `(x != null)` — works after any expression
|
|
41
82
|
- All reactive operators: `:=`, `~=`, `~>`, `=!`
|
|
42
83
|
- Dammit operator: `x!` compiles to `await x()`
|
|
43
|
-
- Optional chaining: `?.`, `?.[]`, `?.()` (ES6 dot-form
|
|
84
|
+
- Optional chaining: `?.`, `?.[]`, `?.()` (ES6 dot-form)
|
|
85
|
+
- Optional chaining shorthand: `?[]`, `?()` (compiles to `?.[]`, `?.()`)
|
|
44
86
|
- Nullish coalescing: `??`
|
|
45
87
|
- All other CoffeeScript-compatible syntax
|
|
46
88
|
|
|
47
89
|
### Tests
|
|
48
|
-
- 1,
|
|
90
|
+
- 1,073 tests passing (100%)
|
|
49
91
|
- 25 test files across all language features
|
|
50
92
|
|
|
51
93
|
---
|
package/README.md
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.
|
|
12
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.1.0-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-
|
|
14
|
+
<a href="#"><img src="https://img.shields.io/badge/tests-1130%2F1130-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
|
|
|
@@ -40,6 +40,7 @@ get '/users/:id' -> # RESTful API endpoint, comma-less
|
|
|
40
40
|
- **Modern output** — ES2022 with native classes, `?.`, `??`, modules
|
|
41
41
|
- **New operators** — `!`, `!?`, `//`, `%%`, `=~`, `.new()`, and more
|
|
42
42
|
- **Reactive operators** — `:=`, `~=`, `~>` as language syntax
|
|
43
|
+
- **Optional types** — `::` annotations, `::=` aliases, `.d.ts` emission
|
|
43
44
|
- **Zero dependencies** — everything included, even the parser generator
|
|
44
45
|
- **Self-hosting** — `bun run parser` rebuilds the compiler from source
|
|
45
46
|
|
|
@@ -137,6 +138,27 @@ State, computed values, and effects as language operators:
|
|
|
137
138
|
|
|
138
139
|
---
|
|
139
140
|
|
|
141
|
+
### Types (Optional)
|
|
142
|
+
|
|
143
|
+
Type annotations are erased at compile time — zero runtime cost:
|
|
144
|
+
|
|
145
|
+
```coffee
|
|
146
|
+
def greet(name:: string):: string # Typed function
|
|
147
|
+
"Hello, #{name}!"
|
|
148
|
+
|
|
149
|
+
User ::= type # Structural type
|
|
150
|
+
id: number
|
|
151
|
+
name: string
|
|
152
|
+
|
|
153
|
+
enum HttpCode # Runtime enum
|
|
154
|
+
ok = 200
|
|
155
|
+
notFound = 404
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Compiles to `.js` (types erased) + `.d.ts` (types preserved) — full IDE support via TypeScript Language Server. See [docs/RIP-TYPES.md](docs/RIP-TYPES.md).
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
140
162
|
## Operators
|
|
141
163
|
|
|
142
164
|
| Operator | Example | What it does |
|
|
@@ -147,6 +169,7 @@ State, computed values, and effects as language operators:
|
|
|
147
169
|
| `?` (existence) | `x?` | True if `x != null` |
|
|
148
170
|
| `?:` (ternary) | `x > 0 ? 'yes' : 'no'` | JS-style ternary expression |
|
|
149
171
|
| `?.` `?.[]` `?.()` | `a?.b` `a?.[0]` `a?.()` | Optional chaining (ES6) |
|
|
172
|
+
| `?[]` `?()` | `a?[0]` `a?(x)` | Optional chaining shorthand |
|
|
150
173
|
| `??` | `a ?? b` | Nullish coalescing |
|
|
151
174
|
| `...` (spread) | `[...items, last]` | Prefix spread (ES6) |
|
|
152
175
|
| `//` | `7 // 2` | Floor division |
|
|
@@ -202,6 +225,27 @@ Rip's reactivity is framework-agnostic — use it with React, Vue, Svelte, or va
|
|
|
202
225
|
|
|
203
226
|
---
|
|
204
227
|
|
|
228
|
+
## Rip UI
|
|
229
|
+
|
|
230
|
+
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.
|
|
231
|
+
|
|
232
|
+
```coffee
|
|
233
|
+
Counter = component
|
|
234
|
+
@count := 0
|
|
235
|
+
|
|
236
|
+
render
|
|
237
|
+
div.counter
|
|
238
|
+
h1 "Count: #{@count}"
|
|
239
|
+
button @click: (-> @count++), "+"
|
|
240
|
+
button @click: (-> @count--), "-"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Two keywords — `component` and `render` — are all the language adds. Everything else (`:=` state, `~=` computed, methods, lifecycle) is standard Rip.
|
|
244
|
+
|
|
245
|
+
See [@rip-lang/ui](packages/ui/) for the full framework: Virtual File System, file-based router, reactive stash, and component renderer.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
205
249
|
## vs CoffeeScript
|
|
206
250
|
|
|
207
251
|
| Feature | CoffeeScript | Rip |
|
|
@@ -263,6 +307,7 @@ Rip includes optional packages for full-stack development:
|
|
|
263
307
|
|
|
264
308
|
| Package | Purpose | Lines |
|
|
265
309
|
|---------|---------|-------|
|
|
310
|
+
| [@rip-lang/ui](packages/ui/) | Zero-build reactive web framework (VFS, router, components) | ~1,300 |
|
|
266
311
|
| [@rip-lang/api](packages/api/) | HTTP framework (Sinatra-style routing, 37 validators) | ~1,050 |
|
|
267
312
|
| [@rip-lang/server](packages/server/) | Multi-worker app server (hot reload, HTTPS, mDNS) | ~1,210 |
|
|
268
313
|
| [@rip-lang/db](packages/db/) | DuckDB server with official UI (pure Bun FFI) | ~1,740 |
|
|
@@ -303,7 +348,7 @@ rip file.rip # Run
|
|
|
303
348
|
rip -c file.rip # Compile
|
|
304
349
|
rip -t file.rip # Tokens
|
|
305
350
|
rip -s file.rip # S-expressions
|
|
306
|
-
bun run test #
|
|
351
|
+
bun run test # 1073 tests
|
|
307
352
|
bun run parser # Rebuild parser
|
|
308
353
|
bun run browser # Build browser bundle
|
|
309
354
|
```
|
package/bin/rip
CHANGED
|
@@ -25,6 +25,7 @@ Usage:
|
|
|
25
25
|
|
|
26
26
|
Options:
|
|
27
27
|
-c, --compile Show compiled JavaScript output
|
|
28
|
+
-d, --dts Generate .d.ts type declaration file
|
|
28
29
|
-h, --help Show this help message
|
|
29
30
|
-o, --output <file> Write JavaScript to file
|
|
30
31
|
-q, --quiet Suppress headers
|
|
@@ -44,6 +45,8 @@ Examples:
|
|
|
44
45
|
rip -t example.rip # Show ONLY tokens
|
|
45
46
|
rip -s -c example.rip # Show s-expressions AND JavaScript
|
|
46
47
|
rip -s -t -c example.rip # Show everything (full debug mode)
|
|
48
|
+
rip -d example.rip # Generate example.d.ts
|
|
49
|
+
rip -cd example.rip # Compile JS and generate .d.ts
|
|
47
50
|
rip -q -c example.rip # Just the JS, no headers (for piping)
|
|
48
51
|
rip -w # Launch browser REPL (auto-opens)
|
|
49
52
|
echo 'x = 1 + 2' | rip -c # Compile from stdin
|
|
@@ -142,12 +145,14 @@ async function main() {
|
|
|
142
145
|
const showTokens = ripOptions.includes('-t') || ripOptions.includes('--tokens');
|
|
143
146
|
const showSExpr = ripOptions.includes('-s') || ripOptions.includes('--sexpr');
|
|
144
147
|
const showCompiled = ripOptions.includes('-c') || ripOptions.includes('--compile');
|
|
148
|
+
const generateDts = ripOptions.includes('-d') || ripOptions.includes('--dts');
|
|
145
149
|
const quiet = ripOptions.includes('-q') || ripOptions.includes('--quiet');
|
|
146
150
|
|
|
147
151
|
const options = {
|
|
148
152
|
showTokens,
|
|
149
153
|
showSExpr,
|
|
150
|
-
quiet
|
|
154
|
+
quiet,
|
|
155
|
+
types: generateDts ? 'emit' : undefined
|
|
151
156
|
};
|
|
152
157
|
|
|
153
158
|
// Find input file and output file from ripOptions only
|
|
@@ -162,7 +167,7 @@ async function main() {
|
|
|
162
167
|
}
|
|
163
168
|
|
|
164
169
|
// If .rip file without compile flags → execute instead of compile
|
|
165
|
-
const hasCompileFlag = showCompiled || showTokens || showSExpr || outputFile;
|
|
170
|
+
const hasCompileFlag = showCompiled || showTokens || showSExpr || generateDts || outputFile;
|
|
166
171
|
if (inputFile && inputFile.endsWith('.rip') && !hasCompileFlag) {
|
|
167
172
|
// Check if file exists
|
|
168
173
|
if (!existsSync(inputFile)) {
|
|
@@ -255,6 +260,23 @@ async function main() {
|
|
|
255
260
|
}
|
|
256
261
|
console.log(result.code);
|
|
257
262
|
}
|
|
263
|
+
|
|
264
|
+
// Write .d.ts file
|
|
265
|
+
if (generateDts && result.dts) {
|
|
266
|
+
if (inputFile) {
|
|
267
|
+
let dtsFile = inputFile.replace(/\.rip$/, '.d.ts');
|
|
268
|
+
writeFileSync(dtsFile, result.dts, 'utf-8');
|
|
269
|
+
if (!options.quiet) {
|
|
270
|
+
console.log(`Generated ${dtsFile}`);
|
|
271
|
+
}
|
|
272
|
+
} else {
|
|
273
|
+
// stdin — print .d.ts to stdout
|
|
274
|
+
if (!options.quiet) {
|
|
275
|
+
console.log(`// == Type declarations == //\n`);
|
|
276
|
+
}
|
|
277
|
+
console.log(result.dts);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
258
280
|
} catch (error) {
|
|
259
281
|
console.error('Compilation Error:', error.message);
|
|
260
282
|
if (error.stack) {
|
package/docs/RIP-INTERNALS.md
CHANGED
|
@@ -63,7 +63,7 @@ console.log(code);
|
|
|
63
63
|
|
|
64
64
|
| Feature | CoffeeScript | Rip |
|
|
65
65
|
|---------|-------------|------|
|
|
66
|
-
| Optional chaining | 4 soak operators | ES6 `?.` / `?.[]` / `?.()` |
|
|
66
|
+
| Optional chaining | 4 soak operators | ES6 `?.` / `?.[]` / `?.()` + shorthand `?[]` / `?()` |
|
|
67
67
|
| Ternary | No | `x ? a : b` |
|
|
68
68
|
| Regex features | Basic | Ruby-style (`=~`, indexing, captures in `_`) |
|
|
69
69
|
| Async shorthand | No | Dammit operator (`!`) |
|
|
@@ -90,18 +90,22 @@ console.log(code);
|
|
|
90
90
|
## The Pipeline
|
|
91
91
|
|
|
92
92
|
```
|
|
93
|
-
Source Code → Lexer → Parser → S-Expressions → Codegen → JavaScript
|
|
94
|
-
(1,
|
|
93
|
+
Source Code → Lexer → emitTypes → Parser → S-Expressions → Codegen → JavaScript
|
|
94
|
+
(1,866) (types.js) (356) (simple arrays) (3,219) (ES2022)
|
|
95
|
+
↓
|
|
96
|
+
file.d.ts (when types: "emit")
|
|
95
97
|
```
|
|
96
98
|
|
|
97
99
|
## Key Files
|
|
98
100
|
|
|
99
101
|
| File | Purpose | Lines | Modify? |
|
|
100
102
|
|------|---------|-------|---------|
|
|
101
|
-
| `src/lexer.js` | Lexer + Rewriter | 1,
|
|
102
|
-
| `src/compiler.js` | Compiler + Code Generator | 3,
|
|
103
|
-
| `src/
|
|
104
|
-
| `src/
|
|
103
|
+
| `src/lexer.js` | Lexer + Rewriter | 1,866 | Yes |
|
|
104
|
+
| `src/compiler.js` | Compiler + Code Generator | 3,219 | Yes |
|
|
105
|
+
| `src/types.js` | Type System (lexer sidecar) | 718 | Yes |
|
|
106
|
+
| `src/components.js` | Component System (compiler sidecar) | ~1,240 | Yes |
|
|
107
|
+
| `src/parser.js` | Generated parser | 356 | No (auto-gen) |
|
|
108
|
+
| `src/grammar/grammar.rip` | Grammar specification | 934 | Yes (carefully) |
|
|
105
109
|
| `src/grammar/solar.rip` | Parser generator | 1,001 | No |
|
|
106
110
|
|
|
107
111
|
## Example Flow
|
|
@@ -240,6 +244,12 @@ S-expressions are simple arrays that serve as Rip's intermediate representation
|
|
|
240
244
|
['class', name, parent?, ...members]
|
|
241
245
|
```
|
|
242
246
|
|
|
247
|
+
### Types
|
|
248
|
+
```javascript
|
|
249
|
+
['enum', name, body] // Enum declaration (runtime JS)
|
|
250
|
+
// Type aliases, interfaces → handled by rewriter, never reach parser
|
|
251
|
+
```
|
|
252
|
+
|
|
243
253
|
### Ranges & Slicing
|
|
244
254
|
```javascript
|
|
245
255
|
['..', from, to] // Inclusive range
|
|
@@ -298,8 +308,6 @@ The `!` suffix on `as` in for-loops (`as!`) emits `FORASAWAIT` instead of `FORAS
|
|
|
298
308
|
|---------|-----------|-------------|
|
|
299
309
|
| Postfix spread/rest | `x...` | `...x` (ES6 prefix only) |
|
|
300
310
|
| Prototype access | `x::y`, `x?::y` | Direct `.prototype` or class syntax; `::` reserved for type annotations |
|
|
301
|
-
| Soak call sugar | `x?(args)` | `x?.(args)` (ES6 optional call) |
|
|
302
|
-
| Soak index sugar | `x?[i]` | `x?.[i]` (ES6 optional index) |
|
|
303
311
|
| `is not` contraction | `x is not y` | `x isnt y` |
|
|
304
312
|
|
|
305
313
|
### Added
|
|
@@ -395,13 +403,15 @@ counter = ->
|
|
|
395
403
|
| `x ?? y` | `x ?? y` |
|
|
396
404
|
| `x ??= 10` | `x ??= 10` |
|
|
397
405
|
|
|
398
|
-
Optional chaining uses ES6 syntax:
|
|
406
|
+
Optional chaining uses ES6 syntax (both forms supported):
|
|
399
407
|
|
|
400
408
|
| Syntax | Compiles To |
|
|
401
409
|
|--------|-------------|
|
|
402
410
|
| `obj?.prop` | `obj?.prop` |
|
|
403
411
|
| `arr?.[0]` | `arr?.[0]` |
|
|
404
412
|
| `fn?.(x)` | `fn?.(x)` |
|
|
413
|
+
| `arr?[0]` | `arr?.[0]` |
|
|
414
|
+
| `fn?(x)` | `fn?.(x)` |
|
|
405
415
|
|
|
406
416
|
## Range Optimization
|
|
407
417
|
|
|
@@ -458,8 +468,6 @@ The `Compiler` class's lexer adapter reconstructs `new String()` wrapping from t
|
|
|
458
468
|
|-----------|--------|--------|
|
|
459
469
|
| `generatePrototype` | `::` | Feature removed from lexer |
|
|
460
470
|
| `generateOptionalPrototype` | `?::` | Feature removed from lexer |
|
|
461
|
-
| `generateSoakIndex` | `?[]` | Replaced by `optindex` / `?.[]` |
|
|
462
|
-
| `generateSoakCall` | `?call` | Replaced by `optcall` / `?.()` |
|
|
463
471
|
|
|
464
472
|
## Renamed: `for-from` → `for-as`
|
|
465
473
|
|
|
@@ -560,7 +568,6 @@ bun src/compare-compilers.js
|
|
|
560
568
|
|
|
561
569
|
# 9. Future Work
|
|
562
570
|
|
|
563
|
-
- `::` token for type annotations (see `docs/RIP-TYPES.md`)
|
|
564
571
|
- Comment preservation for source maps
|
|
565
572
|
- Parser update to read `.data` directly instead of `new String()` properties
|
|
566
573
|
- Once parser supports `.data`, the `meta()`/`str()` helpers become trivial to update
|
|
@@ -569,8 +576,9 @@ bun src/compare-compilers.js
|
|
|
569
576
|
|
|
570
577
|
**See Also:**
|
|
571
578
|
- [RIP-LANG.md](RIP-LANG.md) — Language reference
|
|
579
|
+
- [RIP-TYPES.md](RIP-TYPES.md) — Type system specification
|
|
572
580
|
- [RIP-REACTIVITY.md](RIP-REACTIVITY.md) — Reactivity deep dive
|
|
573
581
|
|
|
574
582
|
---
|
|
575
583
|
|
|
576
|
-
*Rip 3.0
|
|
584
|
+
*Rip 3.0 — 1,130 tests passing — Zero dependencies — Self-hosting — ~8,800 LOC*
|
package/docs/RIP-LANG.md
CHANGED
|
@@ -17,9 +17,10 @@ Rip is a modern reactive language that compiles to ES2022 JavaScript. It combine
|
|
|
17
17
|
9. [Regex Features](#9-regex-features)
|
|
18
18
|
10. [Server-Side Development](#10-server-side-development)
|
|
19
19
|
11. [CLI Tools & Scripts](#11-cli-tools--scripts)
|
|
20
|
-
12. [
|
|
21
|
-
13. [
|
|
22
|
-
14. [
|
|
20
|
+
12. [Types](#12-types)
|
|
21
|
+
13. [JavaScript Interop](#13-javascript-interop)
|
|
22
|
+
14. [Common Patterns](#14-common-patterns)
|
|
23
|
+
15. [Quick Reference](#15-quick-reference)
|
|
23
24
|
|
|
24
25
|
---
|
|
25
26
|
|
|
@@ -273,6 +274,7 @@ Multiple lines
|
|
|
273
274
|
| `?` (postfix) | `a?` | Existence check (`a != null`) |
|
|
274
275
|
| `?` (ternary) | `a ? b : c` | Ternary conditional |
|
|
275
276
|
| `?.` `?.[]` `?.()` | `a?.b` `a?.[0]` `a?.()` | Optional chaining (ES6) |
|
|
277
|
+
| `?[]` `?()` | `a?[0]` `a?(x)` | Optional chaining shorthand |
|
|
276
278
|
| `??` | `a ?? b` | Nullish coalescing |
|
|
277
279
|
|
|
278
280
|
## Rip-Specific Operators
|
|
@@ -311,10 +313,14 @@ x ||= val # x = x || val
|
|
|
311
313
|
## Optional Chaining
|
|
312
314
|
|
|
313
315
|
```coffee
|
|
314
|
-
# ES6 optional chaining (dot
|
|
316
|
+
# ES6 optional chaining (with dot)
|
|
315
317
|
user?.profile?.name
|
|
316
318
|
arr?.[0]
|
|
317
319
|
fn?.(arg)
|
|
320
|
+
|
|
321
|
+
# Shorthand (without dot — same behavior)
|
|
322
|
+
arr?[0] # Compiles to arr?.[0]
|
|
323
|
+
fn?(arg) # Compiles to fn?.(arg)
|
|
318
324
|
```
|
|
319
325
|
|
|
320
326
|
## Ternary Operator
|
|
@@ -919,7 +925,41 @@ for filename in files
|
|
|
919
925
|
|
|
920
926
|
---
|
|
921
927
|
|
|
922
|
-
# 12.
|
|
928
|
+
# 12. Types
|
|
929
|
+
|
|
930
|
+
Rip supports an optional, compile-time-only type system. Types are erased from
|
|
931
|
+
`.js` output and preserved in `.d.ts` declaration files.
|
|
932
|
+
|
|
933
|
+
```coffee
|
|
934
|
+
# Type annotations (::)
|
|
935
|
+
count:: number = 0
|
|
936
|
+
def greet(name:: string):: string
|
|
937
|
+
"Hello, #{name}!"
|
|
938
|
+
|
|
939
|
+
# Type aliases (::=)
|
|
940
|
+
ID ::= number
|
|
941
|
+
User ::= type
|
|
942
|
+
id: number
|
|
943
|
+
name: string
|
|
944
|
+
|
|
945
|
+
# Interfaces
|
|
946
|
+
interface Animal
|
|
947
|
+
name: string
|
|
948
|
+
|
|
949
|
+
# Enums (emit runtime JS)
|
|
950
|
+
enum HttpCode
|
|
951
|
+
ok = 200
|
|
952
|
+
notFound = 404
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
Types use `=>` for function type arrows and `->` for code arrows. This
|
|
956
|
+
disambiguates type expressions from function bodies cleanly.
|
|
957
|
+
|
|
958
|
+
For the complete type system specification, see [RIP-TYPES.md](RIP-TYPES.md).
|
|
959
|
+
|
|
960
|
+
---
|
|
961
|
+
|
|
962
|
+
# 13. JavaScript Interop
|
|
923
963
|
|
|
924
964
|
```coffee
|
|
925
965
|
# Import any npm package
|
|
@@ -949,7 +989,7 @@ const { code } = compile('x = 42');
|
|
|
949
989
|
|
|
950
990
|
---
|
|
951
991
|
|
|
952
|
-
#
|
|
992
|
+
# 14. Common Patterns
|
|
953
993
|
|
|
954
994
|
## Error Handling
|
|
955
995
|
|
|
@@ -1031,7 +1071,7 @@ class EventEmitter
|
|
|
1031
1071
|
|
|
1032
1072
|
---
|
|
1033
1073
|
|
|
1034
|
-
#
|
|
1074
|
+
# 15. Quick Reference
|
|
1035
1075
|
|
|
1036
1076
|
## Syntax Cheat Sheet
|
|
1037
1077
|
|
|
@@ -1123,4 +1163,4 @@ count = 10 # Logs: "Count: 10, Doubled: 20"
|
|
|
1123
1163
|
|
|
1124
1164
|
---
|
|
1125
1165
|
|
|
1126
|
-
*Rip 3.0
|
|
1166
|
+
*Rip 3.0 — 1,073 tests passing — Zero dependencies — Self-hosting — ~7,700 LOC*
|
package/docs/RIP-REACTIVITY.md
CHANGED
|
@@ -286,3 +286,24 @@ Rip's reactivity system:
|
|
|
286
286
|
✅ **Extra utilities** — `.lock()`, `.read()`, `.kill()` that others lack <br>
|
|
287
287
|
|
|
288
288
|
**On par with Vue/Solid. Better than React. A fraction of the size.**
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Types and Reactivity
|
|
293
|
+
|
|
294
|
+
Reactive operators work with Rip's optional type system:
|
|
295
|
+
|
|
296
|
+
```coffee
|
|
297
|
+
count:: number := 0 # Typed state
|
|
298
|
+
doubled:: number ~= count * 2 # Typed computed
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Type annotations are erased from `.js` output. In `.d.ts` output, reactive
|
|
302
|
+
state emits `Signal<T>` and computed values emit `Computed<T>`:
|
|
303
|
+
|
|
304
|
+
```ts
|
|
305
|
+
declare const count: Signal<number>;
|
|
306
|
+
declare const doubled: Computed<number>;
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
See [RIP-TYPES.md](RIP-TYPES.md) for the complete type system specification.
|