rip-lang 3.13.92 → 3.13.94

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.
Files changed (74) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/README.md +3 -3
  3. package/bin/rip +11 -1
  4. package/docs/AGENTS.md +43 -0
  5. package/docs/RIP-LANG.md +3 -3
  6. package/docs/RIP-TYPES.md +72 -91
  7. package/docs/charts.html +15 -15
  8. package/docs/dist/rip.js +142 -38
  9. package/docs/dist/rip.min.js +174 -174
  10. package/docs/dist/rip.min.js.br +0 -0
  11. package/docs/index.html +2 -2
  12. package/package.json +1 -1
  13. package/src/AGENTS.md +456 -0
  14. package/src/lexer.js +1 -2
  15. package/src/typecheck.js +188 -6
  16. package/src/types.js +63 -38
  17. package/src/ui.rip +65 -0
  18. package/docs/ui/accordion.rip +0 -113
  19. package/docs/ui/alert-dialog.rip +0 -96
  20. package/docs/ui/autocomplete.rip +0 -141
  21. package/docs/ui/avatar.rip +0 -37
  22. package/docs/ui/badge.rip +0 -15
  23. package/docs/ui/breadcrumb.rip +0 -46
  24. package/docs/ui/button-group.rip +0 -26
  25. package/docs/ui/button.rip +0 -23
  26. package/docs/ui/card.rip +0 -25
  27. package/docs/ui/carousel.rip +0 -110
  28. package/docs/ui/checkbox-group.rip +0 -65
  29. package/docs/ui/checkbox.rip +0 -33
  30. package/docs/ui/collapsible.rip +0 -50
  31. package/docs/ui/combobox.rip +0 -155
  32. package/docs/ui/context-menu.rip +0 -105
  33. package/docs/ui/date-picker.rip +0 -214
  34. package/docs/ui/dialog.rip +0 -107
  35. package/docs/ui/drawer.rip +0 -79
  36. package/docs/ui/editable-value.rip +0 -80
  37. package/docs/ui/field.rip +0 -53
  38. package/docs/ui/fieldset.rip +0 -22
  39. package/docs/ui/form.rip +0 -39
  40. package/docs/ui/grid.rip +0 -901
  41. package/docs/ui/hljs-rip.js +0 -209
  42. package/docs/ui/index.css +0 -1772
  43. package/docs/ui/index.html +0 -2433
  44. package/docs/ui/input-group.rip +0 -28
  45. package/docs/ui/input.rip +0 -36
  46. package/docs/ui/label.rip +0 -16
  47. package/docs/ui/menu.rip +0 -162
  48. package/docs/ui/menubar.rip +0 -155
  49. package/docs/ui/meter.rip +0 -36
  50. package/docs/ui/multi-select.rip +0 -158
  51. package/docs/ui/native-select.rip +0 -32
  52. package/docs/ui/nav-menu.rip +0 -129
  53. package/docs/ui/number-field.rip +0 -162
  54. package/docs/ui/otp-field.rip +0 -89
  55. package/docs/ui/pagination.rip +0 -123
  56. package/docs/ui/popover.rip +0 -143
  57. package/docs/ui/preview-card.rip +0 -73
  58. package/docs/ui/progress.rip +0 -25
  59. package/docs/ui/radio-group.rip +0 -67
  60. package/docs/ui/resizable.rip +0 -123
  61. package/docs/ui/scroll-area.rip +0 -145
  62. package/docs/ui/select.rip +0 -184
  63. package/docs/ui/separator.rip +0 -17
  64. package/docs/ui/skeleton.rip +0 -22
  65. package/docs/ui/slider.rip +0 -165
  66. package/docs/ui/spinner.rip +0 -17
  67. package/docs/ui/table.rip +0 -27
  68. package/docs/ui/tabs.rip +0 -124
  69. package/docs/ui/textarea.rip +0 -48
  70. package/docs/ui/toast.rip +0 -87
  71. package/docs/ui/toggle-group.rip +0 -78
  72. package/docs/ui/toggle.rip +0 -24
  73. package/docs/ui/toolbar.rip +0 -46
  74. package/docs/ui/tooltip.rip +0 -115
package/CHANGELOG.md CHANGED
@@ -386,13 +386,13 @@ Rip UI hash routing and static demo. See `packages/ui/CHANGELOG.md` v0.3.1.
386
386
  ### Rip Types — Optional Type System
387
387
 
388
388
  - **Type annotations** (`::`) on variables, parameters, and return types — compile-time only, stripped from JS output.
389
- - **Type aliases** (`::=`) for named types, structural types, union types.
389
+ - **Type aliases** (`type Name =`) for named types, structural types, union types.
390
390
  - **Interfaces** with `extends` support.
391
391
  - **Enums** with runtime JS generation and `.d.ts` emission.
392
392
  - **Generics** (`<T>`) for reusable type definitions.
393
393
  - **`.d.ts` emission** — `emitTypes()` generates TypeScript declaration files directly from annotated token stream.
394
394
  - **CLI flag** — `-d`/`--dts` generates `.d.ts` files alongside compiled JS.
395
- - **Architecture** — All type logic consolidated in `src/types.js` (lexer sidecar), minimal changes to lexer and compiler. Added `::` and `::=` operators to lexer.
395
+ - **Architecture** — All type logic consolidated in `src/types.js` (lexer sidecar), minimal changes to lexer and compiler. Added `::` annotations and `type` keyword to lexer.
396
396
 
397
397
  ## [3.1.0] - 2026-02-08
398
398
 
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.13.92-blue.svg" alt="Version"></a>
12
+ <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.13.94-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
14
  <a href="#"><img src="https://img.shields.io/badge/tests-1%2C436%2F1%2C436-brightgreen.svg" alt="Tests"></a>
15
15
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
@@ -40,7 +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
+ - **Optional types** — `::` annotations, `type` aliases, `.d.ts` emission
44
44
  - **Zero dependencies** — everything included, even the parser generator
45
45
  - **Self-hosting** — `bun run parser` rebuilds the compiler from source
46
46
 
@@ -162,7 +162,7 @@ Type annotations are erased at compile time — zero runtime cost:
162
162
  def greet(name:: string):: string # Typed function
163
163
  "Hello, #{name}!"
164
164
 
165
- User ::= type # Structural type
165
+ type User = # Structural type
166
166
  id: number
167
167
  name: string
168
168
 
package/bin/rip CHANGED
@@ -40,6 +40,7 @@ Options:
40
40
  -s, --sexpr Show s-expressions (only, unless -c also specified)
41
41
  -t, --tokens Show token stream (only, unless -c also specified)
42
42
  -v, --version Show version number
43
+ --shadow Show virtual TypeScript content (what rip check sees)
43
44
 
44
45
  Subcommands:
45
46
  rip server [flags] [app] Start server (watches *.rip, HTTPS, mDNS)
@@ -68,6 +69,7 @@ Examples:
68
69
  rip -d example.rip # Show type declarations
69
70
  rip -m example.rip # Compile with inline source map
70
71
  rip -cd example.rip # Show compiled JS and type declarations
72
+ rip --shadow example.rip # Show shadow TypeScript (for type-check debugging)
71
73
  rip -q -c example.rip # Just the JS, no headers (for piping)
72
74
  echo 'p 1 + 2' | rip # Execute from stdin
73
75
  echo 'x = 1 + 2' | rip -c # Compile from stdin
@@ -167,6 +169,7 @@ async function main() {
167
169
  const showCompiled = ripOptions.includes('-c') || ripOptions.includes('--compile');
168
170
  const generateDts = ripOptions.includes('-d') || ripOptions.includes('--dts');
169
171
  const generateMap = ripOptions.includes('-m') || ripOptions.includes('--map');
172
+ const showShadow = ripOptions.includes('--shadow');
170
173
  const quiet = ripOptions.includes('-q') || ripOptions.includes('--quiet');
171
174
 
172
175
  let inputFile = scriptFileIndex === -1 ? null : args[scriptFileIndex];
@@ -179,7 +182,7 @@ async function main() {
179
182
  }
180
183
 
181
184
  // Stdin handling — read into memory; only write temp file for the execute path
182
- const hasCompileFlag = showCompiled || showTokens || showSExpr || generateDts || generateMap || outputFile;
185
+ const hasCompileFlag = showCompiled || showTokens || showSExpr || generateDts || generateMap || showShadow || outputFile;
183
186
  let source;
184
187
 
185
188
  if (!inputFile) {
@@ -277,6 +280,13 @@ async function main() {
277
280
  if (!quiet) console.log(`// == Type declarations == //\n`);
278
281
  console.log(result.dts);
279
282
  }
283
+
284
+ if (showShadow) {
285
+ const { compileForCheck } = await import('../src/typecheck.js');
286
+ const entry = compileForCheck(inputFile || '<stdin>', source, new Compiler());
287
+ if (!quiet) console.log(`// == Shadow TypeScript (what \`rip check\` sees) == //\n`);
288
+ console.log(entry.tsContent);
289
+ }
280
290
  } catch (error) {
281
291
  console.error('Compilation Error:', error.message);
282
292
  if (error.stack) console.error(error.stack);
package/docs/AGENTS.md ADDED
@@ -0,0 +1,43 @@
1
+ # Browser Runtime — Agent Guide
2
+
3
+ These HTML files use Rip's browser runtime. The bundle is an IIFE loaded with `<script defer>`, not `type="module"`, so `file://` demos work without CORS issues.
4
+
5
+ ## Shared-Scope Model
6
+
7
+ All `<script type="text/rip">` tags, inline or external, compile and run together in one shared async IIFE.
8
+
9
+ - `export` makes components visible across tags
10
+ - `skipExports` strips those exports to plain `const` declarations in the shared scope
11
+
12
+ ## Runtime Script Attributes
13
+
14
+ | Attribute | Purpose |
15
+ | -------------- | --------------------------------------------------------- |
16
+ | `data-src` | whitespace-separated source URLs or bundle URLs |
17
+ | `data-mount` | component to mount after compilation |
18
+ | `data-target` | CSS selector for mount target |
19
+ | `data-state` | JSON stash seed |
20
+ | `data-router` | enables history mode or `"hash"` routing |
21
+ | `data-persist` | persists stash in session storage or `"local"` storage |
22
+ | `data-reload` | connects to `/watch`; CSS changes can refresh styles only |
23
+
24
+ ## Component Mounting
25
+
26
+ Every component has a static `mount(target)` helper:
27
+
28
+ ```coffee
29
+ App.mount '#app'
30
+ App.mount()
31
+ ```
32
+
33
+ `data-mount` is declarative; `App.mount(...)` is the code-based alternative.
34
+
35
+ ## Playground and Demos
36
+
37
+ - `index.html` — playground
38
+ - `demo.html` and `charts.html` — dashboard demos
39
+ - `sierpinski.html` — CDN demo
40
+ - `example/index.html` and `results/index.html` — app launchers / examples
41
+ - `ui/index.html` — widget gallery
42
+
43
+ Static demos can be opened via `file://`. The playground and example app require `bun run serve`.
package/docs/RIP-LANG.md CHANGED
@@ -1813,9 +1813,9 @@ count:: number = 0
1813
1813
  def greet(name:: string):: string
1814
1814
  "Hello, #{name}!"
1815
1815
 
1816
- # Type aliases (::=)
1817
- ID ::= number
1818
- User ::= type
1816
+ # Type aliases (type keyword)
1817
+ type ID = number
1818
+ type User =
1819
1819
  id: number
1820
1820
  name: string
1821
1821
 
package/docs/RIP-TYPES.md CHANGED
@@ -35,7 +35,7 @@ Both compile to identical JavaScript.
35
35
 
36
36
  1. [Type Sigil Reference](#type-sigil-reference)
37
37
  2. [Type Annotations (`::`)](#type-annotations-)
38
- 3. [Type Aliases (`::=`)](#type-aliases-)
38
+ 3. [Type Aliases (`type`)](#type-aliases-type)
39
39
  4. [Structural Types](#structural-types)
40
40
  5. [Optionality Modifiers](#optionality-modifiers)
41
41
  6. [Union Types](#union-types)
@@ -58,7 +58,7 @@ Both compile to identical JavaScript.
58
58
  | Sigil | Meaning | Example |
59
59
  |-------|---------|---------|
60
60
  | `::` | Type annotation | `count:: number = 0` |
61
- | `::=` | Type alias | `ID ::= number` |
61
+ | `type` | Type alias | `type ID = number` |
62
62
  | `?` | Optional value (`T \| undefined`) | `email:: string?` |
63
63
  | `??` | Nullable value (`T \| null \| undefined`) | `middle:: string??` |
64
64
  | `!` | Non-nullable (`NonNullable<T>`) | `id:: ID!` |
@@ -172,20 +172,20 @@ const doubled = __computed<number>(() => count * 2); // ~= emits const
172
172
 
173
173
  ---
174
174
 
175
- ## Type Aliases (`::=`)
175
+ ## Type Aliases (`type`)
176
176
 
177
- The `::=` operator declares a named type, mapping directly to TypeScript's
177
+ The `type` keyword declares a named type, mapping directly to TypeScript's
178
178
  `type X = ...`.
179
179
 
180
180
  ```coffee
181
181
  # Simple aliases
182
- ID ::= number
183
- Name ::= string
182
+ type ID = number
183
+ type Name = string
184
184
 
185
185
  # Complex types
186
- UserID ::= number | string
187
- Callback ::= (error:: Error?, data:: any) => void
188
- Handler ::= (req:: Request, res:: Response) => Promise<void>
186
+ type UserID = number | string
187
+ type Callback = (error:: Error?, data:: any) => void
188
+ type Handler = (req:: Request, res:: Response) => Promise<void>
189
189
  ```
190
190
 
191
191
  **Emits:**
@@ -203,16 +203,16 @@ type Handler = (req: Request, res: Response) => Promise<void>;
203
203
 
204
204
  ## Structural Types
205
205
 
206
- Define object shapes using the `type` keyword followed by a block:
206
+ Define object shapes using the `type` keyword with an indented block:
207
207
 
208
208
  ```coffee
209
- User ::= type
209
+ type User =
210
210
  id: number
211
211
  name: string
212
212
  email?: string
213
213
  createdAt: Date
214
214
 
215
- Config ::= type
215
+ type Config =
216
216
  host: string
217
217
  port: number
218
218
  ssl?: boolean
@@ -240,7 +240,7 @@ type Config = {
240
240
  ### Nesting, Readonly, and Index Signatures
241
241
 
242
242
  ```coffee
243
- Response ::= type
243
+ type Response =
244
244
  data: type
245
245
  users: User[]
246
246
  total: number
@@ -248,11 +248,11 @@ Response ::= type
248
248
  page: number
249
249
  limit: number
250
250
 
251
- ImmutableConfig ::= type
251
+ type ImmutableConfig =
252
252
  readonly host: string
253
253
  readonly port: number
254
254
 
255
- Dictionary ::= type
255
+ type Dictionary =
256
256
  [key: string]: any
257
257
  ```
258
258
 
@@ -361,7 +361,7 @@ In structural types, `?` after the property name makes it optional (the
361
361
  property itself may be absent), distinct from value optionality:
362
362
 
363
363
  ```coffee
364
- User ::= type
364
+ type User =
365
365
  id: number
366
366
  name: string
367
367
  email?: string # Optional property — may be absent
@@ -392,8 +392,8 @@ type User = {
392
392
  ### Inline
393
393
 
394
394
  ```coffee
395
- Status ::= "pending" | "active" | "done"
396
- Result ::= Success | Error
395
+ type Status = "pending" | "active" | "done"
396
+ type Result = Success | Error
397
397
  ```
398
398
 
399
399
  ### Block Form (Preferred)
@@ -401,14 +401,14 @@ Result ::= Success | Error
401
401
  Vertical form is diff-friendly and encourages domain-first modeling:
402
402
 
403
403
  ```coffee
404
- HttpMethod ::=
404
+ type HttpMethod =
405
405
  | "GET"
406
406
  | "POST"
407
407
  | "PUT"
408
408
  | "PATCH"
409
409
  | "DELETE"
410
410
 
411
- Result ::=
411
+ type Result =
412
412
  | { success: true, data: Data }
413
413
  | { success: false, error: Error }
414
414
  ```
@@ -437,8 +437,8 @@ numeric values.
437
437
 
438
438
  ```coffee
439
439
  # Type aliases for function signatures
440
- Comparator ::= (a:: any, b:: any) => number
441
- AsyncFetcher ::= (url:: string) => Promise<Response>
440
+ type Comparator = (a:: any, b:: any) => number
441
+ type AsyncFetcher = (url:: string) => Promise<Response>
442
442
 
443
443
  # Overloads
444
444
  def toHtml(content:: string):: string
@@ -481,16 +481,16 @@ class UserService {
481
481
 
482
482
  ```coffee
483
483
  # Simple generic
484
- Container<T> ::= type
484
+ type Container<T> =
485
485
  value: T
486
486
 
487
487
  # Multiple parameters
488
- Pair<K, V> ::= type
488
+ type Pair<K, V> =
489
489
  key: K
490
490
  value: V
491
491
 
492
492
  # With constraints
493
- Comparable<T extends Ordered> ::= type
493
+ type Comparable<T extends Ordered> =
494
494
  value: T
495
495
  compareTo: (other:: T) => number
496
496
 
@@ -555,7 +555,7 @@ interface Dog extends Animal {
555
555
  }
556
556
  ```
557
557
 
558
- Use `::= type` by default. Use `interface` when you need declaration merging.
558
+ Use `type Name =` by default. Use `interface` when you need declaration merging.
559
559
 
560
560
  ---
561
561
 
@@ -564,7 +564,7 @@ Use `::= type` by default. Use `interface` when you need declaration merging.
564
564
  ### Zero-Runtime (Preferred)
565
565
 
566
566
  ```coffee
567
- Size ::=
567
+ type Size =
568
568
  | "xs"
569
569
  | "sm"
570
570
  | "md"
@@ -687,12 +687,12 @@ Override per-file with a directive:
687
687
  | `file.rip` | `file.d.ts` | Type declarations (when `emit` or `check`) |
688
688
 
689
689
  Type aliases and annotations are stripped from `.js` output and preserved
690
- in `.d.ts` output. Type-only declarations (`::=` aliases, unions) appear
690
+ in `.d.ts` output. Type-only declarations (`type` aliases, unions) appear
691
691
  only in `.d.ts`.
692
692
 
693
693
  ```coffee
694
694
  # user.rip
695
- export User ::= type
695
+ export type User =
696
696
  id: number
697
697
  name: string
698
698
 
@@ -732,7 +732,7 @@ UserSchema = z.object
732
732
  email: z.string().email()
733
733
 
734
734
  # Derive type from schema
735
- User ::= z.infer<typeof UserSchema>
735
+ type User = z.infer<typeof UserSchema>
736
736
 
737
737
  # Validate at API boundary
738
738
  def createUser(req:: Request):: User
@@ -819,7 +819,7 @@ Components added `src/components.js` alongside the compiler — types add
819
819
 
820
820
  | File | Role | Scope |
821
821
  |------|------|-------|
822
- | `src/lexer.js` | Detect `::` and `::=` tokens, import `installTypeSupport` from `types.js` | Small inline changes |
822
+ | `src/lexer.js` | Detect `::` and `type` keyword, import `installTypeSupport` from `types.js` | Small inline changes |
823
823
  | `src/types.js` | Lexer sidecar: `installTypeSupport(Lexer)`, `emitTypes(tokens)`, `generateEnum()` | New file, bulk of logic |
824
824
  | `src/compiler.js` | Call `emitTypes()` before parsing, wire `generateEnum()` | ~8 lines |
825
825
  | `src/grammar/grammar.rip` | Add `Enum` rule to `Expression` | 1 rule + 1 export |
@@ -878,31 +878,21 @@ unchanged — types are invisible to everything except `rewriteTypes()` and
878
878
 
879
879
  #### 1.1 Lexer: Token Detection
880
880
 
881
- **Add `::=` and `::` to `OPERATOR_RE`** (in `src/lexer.js`, near line 215).
882
-
883
- The current regex:
884
-
885
- ```js
886
- let OPERATOR_RE = /^(?:<=>|[-=]>|~>|~=|:=|=!|===|!==|...)/;
887
- ```
881
+ **Add `::` to `OPERATOR_RE`** (in `src/lexer.js`, near line 215).
888
882
 
889
- Add `::=` and `::` with longest-match-first ordering (`::=` before `::`).
890
- Also note that `IDENTIFIER_RE` already avoids matching `:` when followed by
891
- `=` or `:` (the `(?![=:])` lookahead), so `::` after an identifier will fall
892
- through to `literalToken()` where `OPERATOR_RE` picks it up.
883
+ The `type` keyword is contextual it is not in `RIP_KEYWORDS` and
884
+ remains a plain `IDENTIFIER`. The `rewriteTypes()` pass in `types.js`
885
+ detects `IDENTIFIER("type")` at statement position followed by another
886
+ `IDENTIFIER` and `=`, and knows a type alias follows.
887
+ The `::` operator is added to the operator regex for type annotations.
893
888
 
894
- **Tag the operators** (in the operator tagging section of `literalToken()`,
895
- near lines 1095-1100, alongside the reactive operators):
889
+ **Tag the annotation operator** (in the operator tagging section of
890
+ `literalToken()`, near lines 1095-1100, alongside the reactive operators):
896
891
 
897
892
  ```js
898
- else if (val === '::=') tag = 'TYPE_ALIAS';
899
893
  else if (val === '::') tag = 'TYPE_ANNOTATION';
900
894
  ```
901
895
 
902
- These must be checked **before** the `([-+:])\1` pattern in the regex, which
903
- currently matches `::` as a repeated `:`. The `::=` three-character match must
904
- come first.
905
-
906
896
  #### 1.2 Rewriter: `rewriteTypes()`
907
897
 
908
898
  **Add the pass to the rewrite pipeline** (in the `rewrite()` method, after
@@ -1052,7 +1042,7 @@ rewriteTypes() {
1052
1042
  return 0; // Re-examine current position
1053
1043
  }
1054
1044
 
1055
- // --- Handle ::= (type aliases) ---
1045
+ // --- Handle type keyword (type aliases) ---
1056
1046
  // Described in Phase 2 below
1057
1047
 
1058
1048
  return 1;
@@ -1388,9 +1378,9 @@ No changes to `classifyKeyword()` are needed — the existing fallback
1388
1378
  `if (RIP_KEYWORDS.has(id)) return upper` (line 618) automatically tags
1389
1379
  `enum` as `ENUM` and `interface` as `INTERFACE`.
1390
1380
 
1391
- #### 2.2 Type Aliases (`::=`) — Unified typeText
1381
+ #### 2.2 Type Aliases (`type` keyword) — Unified typeText
1392
1382
 
1393
- The `::=` operator declares a named type. The `rewriteTypes()` pass handles
1383
+ The `type` keyword declares a named type. The `rewriteTypes()` pass handles
1394
1384
  it by collecting the right-hand side, converting it to a TypeScript-compatible
1395
1385
  type string, and packaging it into a single `TYPE_DECL` marker token. All
1396
1386
  three forms (simple alias, structural type, block union) produce the same
@@ -1400,35 +1390,27 @@ emits `type ${name} = ${typeText};` for all of them.
1400
1390
  **Simple alias:**
1401
1391
 
1402
1392
  ```coffee
1403
- ID ::= number
1404
- UserID ::= number | string
1393
+ type ID = number
1394
+ type UserID = number | string
1405
1395
  ```
1406
1396
 
1407
- When `rewriteTypes()` encounters `TYPE_ALIAS` (`::=`):
1397
+ When `rewriteTypes()` encounters `IDENTIFIER("type") IDENTIFIER(name) =`:
1408
1398
 
1409
- 1. Record the preceding `IDENTIFIER` token as the type name
1399
+ 1. Record the name `IDENTIFIER` token as the type name
1410
1400
  2. Collect all following tokens as the type body (same boundary rules as `::`)
1411
- 3. Replace the entire sequence (`IDENTIFIER`, `TYPE_ALIAS`, type tokens) with
1401
+ 3. Replace the entire sequence (`type`, name, `=`, type tokens) with
1412
1402
  a single `TYPE_DECL` marker token
1413
1403
 
1414
1404
  ```js
1415
- // Inside rewriteTypes(), handling TYPE_ALIAS:
1416
- if (tag === 'TYPE_ALIAS') {
1417
- let nameToken = tokens[i - 1];
1405
+ // Inside rewriteTypes(), handling contextual type keyword:
1406
+ if (tag === 'IDENTIFIER' && token[1] === 'type') {
1407
+ // Verify statement position and name follows
1408
+ let nameToken = tokens[i + 1];
1409
+ if (!nameToken || nameToken[0] !== 'IDENTIFIER') return 1;
1418
1410
  let name = nameToken[1];
1419
1411
 
1420
- // Collect type body tokens (same boundary logic as ::)
1421
- let typeTokens = [];
1422
- let j = i + 1;
1423
- let depth = 0;
1424
- // ... same collection loop as for TYPE_ANNOTATION ...
1425
-
1426
- let typeStr = /* join collected tokens */;
1427
-
1428
- // Replace name + ::= + type tokens with TYPE_DECL marker
1429
- let declToken = gen('TYPE_DECL', name, nameToken);
1430
- declToken.data = { name, typeText: typeStr };
1431
- tokens.splice(i - 1, 2 + typeTokens.length, declToken);
1412
+ // Must have = after name (handles generics too)
1413
+ // ... collect type body, create TYPE_DECL marker ...
1432
1414
  return 0;
1433
1415
  }
1434
1416
  ```
@@ -1443,15 +1425,14 @@ the token stream** before parsing. No grammar rule is needed.
1443
1425
  **Structural type:**
1444
1426
 
1445
1427
  ```coffee
1446
- User ::= type
1428
+ type User =
1447
1429
  id: number
1448
1430
  name: string
1449
1431
  email?: string
1450
1432
  ```
1451
1433
 
1452
- When `rewriteTypes()` sees `TYPE_ALIAS` followed by `IDENTIFIER("type")` and
1453
- then `INDENT`, it collects the block body and converts it to a TypeScript
1454
- object type string:
1434
+ When `rewriteTypes()` sees `type Name =` followed by `INDENT`, it
1435
+ collects the block body and converts it to a TypeScript object type string:
1455
1436
 
1456
1437
  1. Consume the `INDENT`
1457
1438
  2. Collect property declarations line by line until `OUTDENT`
@@ -1481,15 +1462,15 @@ type User = {
1481
1462
  **Block union:**
1482
1463
 
1483
1464
  ```coffee
1484
- HttpMethod ::=
1465
+ type HttpMethod =
1485
1466
  | "GET"
1486
1467
  | "POST"
1487
1468
  | "PUT"
1488
1469
  | "DELETE"
1489
1470
  ```
1490
1471
 
1491
- When `rewriteTypes()` sees `TYPE_ALIAS` followed by `TERMINATOR` or `INDENT`
1492
- with leading `|` tokens, it collects union members and joins them:
1472
+ When `rewriteTypes()` sees `type Name =` followed by `TERMINATOR` or
1473
+ `INDENT` with leading `|` tokens, it collects union members and joins them:
1493
1474
 
1494
1475
  ```js
1495
1476
  declToken.data = {
@@ -1672,12 +1653,12 @@ if (tag === 'IDENTIFIER' && i >= 1 && tokens[i - 1]?.[0] === 'DEF') {
1672
1653
  Generic parameters on type aliases work the same way:
1673
1654
 
1674
1655
  ```coffee
1675
- Container<T> ::= type
1656
+ type Container<T> =
1676
1657
  value: T
1677
1658
  ```
1678
1659
 
1679
- The `rewriteTypes()` pass detects `IDENTIFIER` + unspaced `<...>` +
1680
- `TYPE_ALIAS` and collects the generic params before processing the `::=`.
1660
+ The `rewriteTypes()` pass detects `type` + `IDENTIFIER` + unspaced `<...>` +
1661
+ `=` and collects the generic params before processing the type body.
1681
1662
 
1682
1663
  .d.ts:
1683
1664
  ```ts
@@ -1823,7 +1804,7 @@ directive before tokenizing.
1823
1804
  #### Export of Type-Only Declarations
1824
1805
 
1825
1806
  ```coffee
1826
- export User ::= type
1807
+ export type User =
1827
1808
  id: number
1828
1809
  name: string
1829
1810
 
@@ -1831,7 +1812,7 @@ export def getUser(id:: number):: User?
1831
1812
  db.find(id)
1832
1813
  ```
1833
1814
 
1834
- The rewriter detects `EXPORT` before `::=` sequences and marks the
1815
+ The rewriter detects `EXPORT` before `type` sequences and marks the
1835
1816
  `TYPE_DECL` marker accordingly. The `emitTypes()` function prepends
1836
1817
  `export` to the declaration. No grammar rule is involved for type-only
1837
1818
  exports — the `TYPE_DECL` marker is removed before parsing.
@@ -1864,16 +1845,16 @@ Each row is a test case. Verify both .js and .d.ts output.
1864
1845
  | 4 | `doubled:: number ~= x * 2` | `const doubled = __computed(...)` | `declare const doubled: Computed<number>;` |
1865
1846
  | 5 | `def f(a:: number):: string` | `function f(a) { ... }` | `declare function f(a: number): string;` |
1866
1847
  | 6 | `(x:: number):: number -> x + 1` | `(x) => x + 1` | `(x: number) => number` |
1867
- | 7 | `ID ::= number` | *(empty)* | `type ID = number;` |
1868
- | 8 | `User ::= type` (+ block) | *(empty)* | `type User = { id: number; ... };` |
1869
- | 9 | `Status ::= \| "a" \| "b"` | *(empty)* | `type Status = "a" \| "b";` |
1848
+ | 7 | `type ID = number` | *(empty)* | `type ID = number;` |
1849
+ | 8 | `type User =` (+ block) | *(empty)* | `type User = { id: number; ... };` |
1850
+ | 9 | `type Status = \| "a" \| "b"` | *(empty)* | `type Status = "a" \| "b";` |
1870
1851
  | 10 | `interface Foo` (+ block) | *(empty)* | `interface Foo { ... }` |
1871
1852
  | 11 | `enum Code` (+ block) | `const Code = { ... }` | `enum Code { ... }` |
1872
1853
  | 12 | `items:: Map<string, number> = x` | `items = x` | `let items: Map<string, number>;` |
1873
1854
  | 13 | `email:: string?` | — | `let email: string \| undefined;` |
1874
1855
  | 14 | `id:: ID!` | — | `let id: NonNullable<ID>;` |
1875
1856
  | 15 | `def identity<T>(v:: T):: T` | `function identity(v) { ... }` | `declare function identity<T>(v: T): T;` |
1876
- | 16 | `export User ::= type` (+ block) | *(empty)* | `export type User = { ... };` |
1857
+ | 16 | `export type User =` (+ block) | *(empty)* | `export type User = { ... };` |
1877
1858
  | 17 | `export def f(x:: number):: number` | `export function f(x) { ... }` | `export function f(x: number): number;` |
1878
1859
 
1879
1860
  ---
@@ -1926,9 +1907,9 @@ The type system uses a two-phase approach:
1926
1907
 
1927
1908
  | Rip Input | .d.ts Output |
1928
1909
  |-----------|-------------|
1929
- | `Name ::= type { id: number }` | `type Name = { id: number; };` |
1930
- | `Name ::= number` | `type Name = number;` |
1931
- | Block union `::= \| "a" \| "b"` | `type Name = "a" \| "b";` |
1910
+ | `type Name =` (+ block `id: number`) | `type Name = { id: number; };` |
1911
+ | `type Name = number` | `type Name = number;` |
1912
+ | Block union `type Name = \| "a" \| "b"` | `type Name = "a" \| "b";` |
1932
1913
  | `interface Name { ... }` | `interface Name { ... }` |
1933
1914
  | `interface X extends Y` | `interface X extends Y { ... }` |
1934
1915
  | Function types `read: => string` | `read: () => string` |
package/docs/charts.html CHANGED
@@ -869,21 +869,21 @@ export Dashboard = component
869
869
 
870
870
  p class: 'section', "Core Charts"
871
871
  .grid
872
- ChartCard title: 'Monthly Revenue', subtitle: 'Total recurring revenue by month', chartId: 'line'
873
- ChartCard title: 'Revenue by Product', subtitle: 'Stacked area breakdown across product lines', chartId: 'area'
874
- ChartCard title: 'Quarterly Revenue', subtitle: 'Quarter-over-quarter comparison', chartId: 'bar'
875
- ChartCard title: 'Revenue by Product × Quarter', subtitle: 'Stacked bar with product breakdown', chartId: 'stackedBar'
876
- ChartCard title: 'Revenue & Margin', subtitle: 'Revenue bars with gross margin % line overlay', chartId: 'combo'
872
+ ChartCard title: 'Monthly Revenue', subtitle: 'Total recurring revenue by month', chartId: 'line'
873
+ ChartCard title: 'Revenue by Product', subtitle: 'Stacked area breakdown across product lines', chartId: 'area'
874
+ ChartCard title: 'Quarterly Revenue', subtitle: 'Quarter-over-quarter comparison', chartId: 'bar'
875
+ ChartCard title: 'Revenue by Product × Quarter', subtitle: 'Stacked bar with product breakdown', chartId: 'stackedBar'
876
+ ChartCard title: 'Revenue & Margin', subtitle: 'Revenue bars with gross margin % line overlay', chartId: 'combo'
877
877
  ChartCard title: 'Revenue & Growth Rate', subtitle: 'Dual-axis: revenue (left) and YoY growth (right)', chartId: 'multiAxis'
878
- ChartCard title: 'Customers by Segment', subtitle: 'Distribution across customer tiers', chartId: 'pie'
879
- ChartCard title: 'Deal Size vs. Close Rate', subtitle: 'Each bubble represents a sales rep', chartId: 'scatter'
880
- ChartCard title: 'Feature Usage Heatmap', subtitle: 'Active sessions by day of week and hour', chartId: 'heatmap'
881
- ChartCard title: 'Sales Pipeline', subtitle: 'Conversion through funnel stages', chartId: 'funnel'
882
- ChartCard title: 'Customer Acquisition Flow', subtitle: 'Channel attribution from source to conversion', chartId: 'sankey', wide: true
878
+ ChartCard title: 'Customers by Segment', subtitle: 'Distribution across customer tiers', chartId: 'pie'
879
+ ChartCard title: 'Deal Size vs. Close Rate', subtitle: 'Each bubble represents a sales rep', chartId: 'scatter'
880
+ ChartCard title: 'Feature Usage Heatmap', subtitle: 'Active sessions by day of week and hour', chartId: 'heatmap'
881
+ ChartCard title: 'Sales Pipeline', subtitle: 'Conversion through funnel stages', chartId: 'funnel'
882
+ ChartCard title: 'Customer Acquisition Flow', subtitle: 'Channel attribution from source to conversion', chartId: 'sankey', wide: true
883
883
 
884
884
  p class: 'section', "Geographic"
885
885
  .grid
886
- ChartCard title: 'Revenue by State', subtitle: 'Annual revenue across US states', chartId: 'choropleth', tall: true
886
+ ChartCard title: 'Revenue by State', subtitle: 'Annual revenue across US states', chartId: 'choropleth', tall: true
887
887
  ChartCard title: 'Customer Locations', subtitle: 'Purchase origins clustered by region (k-means)', chartId: 'scatterMap', tall: true
888
888
 
889
889
  p class: 'section', "KPI Gauges"
@@ -904,10 +904,10 @@ export Dashboard = component
904
904
  p class: 'section', "Analytical"
905
905
  .grid
906
906
  ChartCard title: 'Product Comparison', subtitle: 'Multi-metric radar across product lines', chartId: 'radar'
907
- ChartCard title: 'Revenue Bridge', subtitle: 'Waterfall from Q1 baseline through Q4', chartId: 'waterfall'
908
- ChartCard title: 'Deal Size Distribution', subtitle: 'Boxplot of closed deal values by quarter ($k)', chartId: 'boxplot'
909
- ChartCard title: 'Product Metrics', subtitle: 'Parallel coordinates across key dimensions', chartId: 'parallel'
910
- ChartCard title: 'Daily Platform Activity', subtitle: 'Login volume over the past year', chartId: 'calendar', wide: true
907
+ ChartCard title: 'Revenue Bridge', subtitle: 'Waterfall from Q1 baseline through Q4', chartId: 'waterfall'
908
+ ChartCard title: 'Deal Size Distribution', subtitle: 'Boxplot of closed deal values by quarter ($k)', chartId: 'boxplot'
909
+ ChartCard title: 'Product Metrics', subtitle: 'Parallel coordinates across key dimensions', chartId: 'parallel'
910
+ ChartCard title: 'Daily Platform Activity', subtitle: 'Login volume over the past year', chartId: 'calendar', wide: true
911
911
 
912
912
  p class: 'section', "Additional Chart Types"
913
913
  .grid