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.
- package/CHANGELOG.md +2 -2
- package/README.md +3 -3
- package/bin/rip +11 -1
- package/docs/AGENTS.md +43 -0
- package/docs/RIP-LANG.md +3 -3
- package/docs/RIP-TYPES.md +72 -91
- package/docs/charts.html +15 -15
- package/docs/dist/rip.js +142 -38
- package/docs/dist/rip.min.js +174 -174
- package/docs/dist/rip.min.js.br +0 -0
- package/docs/index.html +2 -2
- package/package.json +1 -1
- package/src/AGENTS.md +456 -0
- package/src/lexer.js +1 -2
- package/src/typecheck.js +188 -6
- package/src/types.js +63 -38
- package/src/ui.rip +65 -0
- package/docs/ui/accordion.rip +0 -113
- package/docs/ui/alert-dialog.rip +0 -96
- package/docs/ui/autocomplete.rip +0 -141
- package/docs/ui/avatar.rip +0 -37
- package/docs/ui/badge.rip +0 -15
- package/docs/ui/breadcrumb.rip +0 -46
- package/docs/ui/button-group.rip +0 -26
- package/docs/ui/button.rip +0 -23
- package/docs/ui/card.rip +0 -25
- package/docs/ui/carousel.rip +0 -110
- package/docs/ui/checkbox-group.rip +0 -65
- package/docs/ui/checkbox.rip +0 -33
- package/docs/ui/collapsible.rip +0 -50
- package/docs/ui/combobox.rip +0 -155
- package/docs/ui/context-menu.rip +0 -105
- package/docs/ui/date-picker.rip +0 -214
- package/docs/ui/dialog.rip +0 -107
- package/docs/ui/drawer.rip +0 -79
- package/docs/ui/editable-value.rip +0 -80
- package/docs/ui/field.rip +0 -53
- package/docs/ui/fieldset.rip +0 -22
- package/docs/ui/form.rip +0 -39
- package/docs/ui/grid.rip +0 -901
- package/docs/ui/hljs-rip.js +0 -209
- package/docs/ui/index.css +0 -1772
- package/docs/ui/index.html +0 -2433
- package/docs/ui/input-group.rip +0 -28
- package/docs/ui/input.rip +0 -36
- package/docs/ui/label.rip +0 -16
- package/docs/ui/menu.rip +0 -162
- package/docs/ui/menubar.rip +0 -155
- package/docs/ui/meter.rip +0 -36
- package/docs/ui/multi-select.rip +0 -158
- package/docs/ui/native-select.rip +0 -32
- package/docs/ui/nav-menu.rip +0 -129
- package/docs/ui/number-field.rip +0 -162
- package/docs/ui/otp-field.rip +0 -89
- package/docs/ui/pagination.rip +0 -123
- package/docs/ui/popover.rip +0 -143
- package/docs/ui/preview-card.rip +0 -73
- package/docs/ui/progress.rip +0 -25
- package/docs/ui/radio-group.rip +0 -67
- package/docs/ui/resizable.rip +0 -123
- package/docs/ui/scroll-area.rip +0 -145
- package/docs/ui/select.rip +0 -184
- package/docs/ui/separator.rip +0 -17
- package/docs/ui/skeleton.rip +0 -22
- package/docs/ui/slider.rip +0 -165
- package/docs/ui/spinner.rip +0 -17
- package/docs/ui/table.rip +0 -27
- package/docs/ui/tabs.rip +0 -124
- package/docs/ui/textarea.rip +0 -48
- package/docs/ui/toast.rip +0 -87
- package/docs/ui/toggle-group.rip +0 -78
- package/docs/ui/toggle.rip +0 -24
- package/docs/ui/toolbar.rip +0 -46
- 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** (
|
|
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
|
|
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.
|
|
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,
|
|
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
|
|
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
|
|
1818
|
-
User
|
|
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 (
|
|
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
|
-
|
|
|
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
|
|
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
|
|
183
|
-
Name
|
|
182
|
+
type ID = number
|
|
183
|
+
type Name = string
|
|
184
184
|
|
|
185
185
|
# Complex types
|
|
186
|
-
UserID
|
|
187
|
-
Callback
|
|
188
|
-
Handler
|
|
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
|
|
206
|
+
Define object shapes using the `type` keyword with an indented block:
|
|
207
207
|
|
|
208
208
|
```coffee
|
|
209
|
-
User
|
|
209
|
+
type User =
|
|
210
210
|
id: number
|
|
211
211
|
name: string
|
|
212
212
|
email?: string
|
|
213
213
|
createdAt: Date
|
|
214
214
|
|
|
215
|
-
Config
|
|
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
|
|
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
|
|
251
|
+
type ImmutableConfig =
|
|
252
252
|
readonly host: string
|
|
253
253
|
readonly port: number
|
|
254
254
|
|
|
255
|
-
Dictionary
|
|
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
|
|
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
|
|
396
|
-
Result
|
|
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
|
|
441
|
-
AsyncFetcher
|
|
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>
|
|
484
|
+
type Container<T> =
|
|
485
485
|
value: T
|
|
486
486
|
|
|
487
487
|
# Multiple parameters
|
|
488
|
-
Pair<K, V>
|
|
488
|
+
type Pair<K, V> =
|
|
489
489
|
key: K
|
|
490
490
|
value: V
|
|
491
491
|
|
|
492
492
|
# With constraints
|
|
493
|
-
Comparable<T extends Ordered>
|
|
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
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
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
|
|
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
|
|
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 (
|
|
1381
|
+
#### 2.2 Type Aliases (`type` keyword) — Unified typeText
|
|
1392
1382
|
|
|
1393
|
-
The
|
|
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
|
|
1404
|
-
UserID
|
|
1393
|
+
type ID = number
|
|
1394
|
+
type UserID = number | string
|
|
1405
1395
|
```
|
|
1406
1396
|
|
|
1407
|
-
When `rewriteTypes()` encounters `
|
|
1397
|
+
When `rewriteTypes()` encounters `IDENTIFIER("type") IDENTIFIER(name) =`:
|
|
1408
1398
|
|
|
1409
|
-
1. Record the
|
|
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 (`
|
|
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
|
|
1416
|
-
if (tag === '
|
|
1417
|
-
|
|
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
|
-
//
|
|
1421
|
-
|
|
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
|
|
1428
|
+
type User =
|
|
1447
1429
|
id: number
|
|
1448
1430
|
name: string
|
|
1449
1431
|
email?: string
|
|
1450
1432
|
```
|
|
1451
1433
|
|
|
1452
|
-
When `rewriteTypes()` sees `
|
|
1453
|
-
|
|
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 `
|
|
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>
|
|
1656
|
+
type Container<T> =
|
|
1676
1657
|
value: T
|
|
1677
1658
|
```
|
|
1678
1659
|
|
|
1679
|
-
The `rewriteTypes()` pass detects `IDENTIFIER` + unspaced `<...>` +
|
|
1680
|
-
|
|
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
|
|
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
|
|
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
|
|
1868
|
-
| 8 | `User
|
|
1869
|
-
| 9 | `Status
|
|
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
|
|
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
|
|
1930
|
-
| `Name
|
|
1931
|
-
| Block union
|
|
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',
|
|
873
|
-
ChartCard title: 'Revenue by Product', subtitle: 'Stacked area breakdown across product lines',
|
|
874
|
-
ChartCard title: 'Quarterly Revenue', subtitle: 'Quarter-over-quarter comparison',
|
|
875
|
-
ChartCard title: 'Revenue by Product × Quarter',
|
|
876
|
-
ChartCard title: 'Revenue & Margin', subtitle: 'Revenue bars with gross margin % line overlay',
|
|
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',
|
|
879
|
-
ChartCard title: 'Deal Size vs. Close Rate', subtitle: 'Each bubble represents a sales rep',
|
|
880
|
-
ChartCard title: 'Feature Usage Heatmap', subtitle: 'Active sessions by day of week and hour',
|
|
881
|
-
ChartCard title: 'Sales Pipeline', subtitle: 'Conversion through funnel stages',
|
|
882
|
-
ChartCard title: 'Customer Acquisition Flow', subtitle: 'Channel attribution from source to conversion',
|
|
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',
|
|
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',
|
|
908
|
-
ChartCard title: 'Deal Size Distribution', subtitle: 'Boxplot of closed deal values by quarter ($k)',
|
|
909
|
-
ChartCard title: 'Product Metrics', subtitle: 'Parallel coordinates across key dimensions',
|
|
910
|
-
ChartCard title: 'Daily Platform Activity', subtitle: 'Login volume over the past year',
|
|
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
|