rip-lang 3.13.129 → 3.13.131
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/README.md +6 -6
- package/bin/rip +50 -52
- package/bin/rip-server +20 -0
- package/docs/RIP-LANG.md +12 -0
- package/docs/dist/rip.js +469 -364
- package/docs/dist/rip.min.js +151 -149
- package/docs/dist/rip.min.js.br +0 -0
- package/docs/ui/hljs-rip.js +7 -0
- package/package.json +1 -1
- package/src/AGENTS.md +1 -0
- package/src/compiler.js +36 -4
- package/src/components.js +17 -8
- package/src/grammar/grammar.rip +40 -0
- package/src/lexer.js +31 -8
- package/src/parser.js +223 -221
- package/src/sourcemap-utils.js +46 -2
- package/src/typecheck.js +39 -9
- package/src/types.js +5 -5
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.130-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>
|
|
@@ -410,16 +410,16 @@ Simple arrays (with `.loc`) instead of AST node classes. The compiler is self-ho
|
|
|
410
410
|
| Component | File | Lines |
|
|
411
411
|
|-----------|------|-------|
|
|
412
412
|
| Lexer + Rewriter | `src/lexer.js` | 1,778 |
|
|
413
|
+
| Grammar | `src/grammar/grammar.rip` | 948 |
|
|
414
|
+
| Parser Generator | `src/grammar/solar.rip` | 929 |
|
|
415
|
+
| Parser (generated) | `src/parser.js` | 359 |
|
|
413
416
|
| Compiler + Codegen | `src/compiler.js` | 3,334 |
|
|
414
|
-
| Type System | `src/types.js` | 1,091 |
|
|
415
417
|
| Component System | `src/components.js` | 2,026 |
|
|
418
|
+
| Browser Engine | `src/browser.js` | 194 |
|
|
416
419
|
| Source Maps | `src/sourcemaps.js` | 189 |
|
|
420
|
+
| Type System | `src/types.js` | 1,091 |
|
|
417
421
|
| Type Checking | `src/typecheck.js` | 442 |
|
|
418
|
-
| Parser (generated) | `src/parser.js` | 359 |
|
|
419
|
-
| Grammar | `src/grammar/grammar.rip` | 948 |
|
|
420
|
-
| Parser Generator | `src/grammar/solar.rip` | 929 |
|
|
421
422
|
| REPL | `src/repl.js` | 600 |
|
|
422
|
-
| Browser Entry | `src/browser.js` | 194 |
|
|
423
423
|
| **Total** | | **~11,890** |
|
|
424
424
|
|
|
425
425
|
---
|
package/bin/rip
CHANGED
|
@@ -32,14 +32,6 @@ function getRepoRoot() {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
function getWorkspaceServerPath() {
|
|
36
|
-
const repoRoot = getRepoRoot();
|
|
37
|
-
if (!repoRoot) return null;
|
|
38
|
-
|
|
39
|
-
const workspaceServerPath = join(repoRoot, 'packages', 'server', 'server.rip');
|
|
40
|
-
return isFile(workspaceServerPath) ? workspaceServerPath : null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
35
|
function printHelp() {
|
|
44
36
|
console.log(`
|
|
45
37
|
Rip ${VERSION} - ${SUMMARY}
|
|
@@ -62,34 +54,28 @@ Options:
|
|
|
62
54
|
--shadow Show virtual TypeScript content (what rip check sees)
|
|
63
55
|
|
|
64
56
|
Subcommands:
|
|
65
|
-
rip server [flags] [app] Start server (watches *.rip, HTTPS, mDNS)
|
|
66
57
|
rip check [dir] Type-check all .rip files in directory
|
|
58
|
+
rip <name> [args] Run rip-<name> (repo bin/, node_modules, or PATH)
|
|
67
59
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
w:<n> Worker count (auto, half, 2x, 3x, or number)
|
|
60
|
+
Packages:
|
|
61
|
+
rip server [flags] [app] Start server (run 'rip server -h' for details)
|
|
62
|
+
rip db DuckDB server
|
|
63
|
+
rip csv CSV parser
|
|
64
|
+
rip print Syntax-highlighted code printer
|
|
74
65
|
|
|
75
66
|
Examples:
|
|
76
67
|
rip # Interactive REPL (terminal)
|
|
77
68
|
rip script.rip # Execute script directly
|
|
78
69
|
rip script.rip arg1 arg2 # Execute with arguments
|
|
79
|
-
rip server #
|
|
80
|
-
rip server
|
|
81
|
-
rip server
|
|
70
|
+
rip server # Start server (watches *.rip, HTTPS, mDNS)
|
|
71
|
+
rip server -c # Validate server config
|
|
72
|
+
rip server -s # Stop running server
|
|
82
73
|
rip -c example.rip # Compile and show JavaScript
|
|
83
74
|
rip -o output.js example.rip # Compile and save to file
|
|
84
75
|
rip -s example.rip # Show ONLY s-expressions
|
|
85
76
|
rip -t example.rip # Show ONLY tokens
|
|
86
|
-
rip -s -c example.rip # Show s-expressions AND JavaScript
|
|
87
|
-
rip -s -t -c example.rip # Show everything (full debug mode)
|
|
88
77
|
rip -d example.rip # Show type declarations
|
|
89
78
|
rip -m example.rip # Compile with inline source map
|
|
90
|
-
rip -cd example.rip # Show compiled JS and type declarations
|
|
91
|
-
rip --shadow example.rip # Show shadow TypeScript (for type-check debugging)
|
|
92
|
-
rip -q -c example.rip # Just the JS, no headers (for piping)
|
|
93
79
|
echo 'p 1 + 2' | rip # Execute from stdin
|
|
94
80
|
echo 'x = 1 + 2' | rip -c # Compile from stdin
|
|
95
81
|
|
|
@@ -141,7 +127,7 @@ async function main() {
|
|
|
141
127
|
process.exit(0);
|
|
142
128
|
}
|
|
143
129
|
|
|
144
|
-
// ---
|
|
130
|
+
// --- Built-in subcommands ---
|
|
145
131
|
|
|
146
132
|
if (args[0] === 'check') {
|
|
147
133
|
const { runCheck } = await import('../src/typecheck.js');
|
|
@@ -153,22 +139,48 @@ async function main() {
|
|
|
153
139
|
process.exit(exitCode);
|
|
154
140
|
}
|
|
155
141
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
142
|
+
// --- Subcommand dispatch: rip <name> → rip-<name> ---
|
|
143
|
+
|
|
144
|
+
if (scriptFileIndex >= 0) {
|
|
145
|
+
const candidate = args[scriptFileIndex];
|
|
146
|
+
if (!candidate.startsWith('-') && !isFile(candidate)) {
|
|
147
|
+
const name = candidate;
|
|
148
|
+
const subArgs = args.slice(scriptFileIndex + 1);
|
|
149
|
+
|
|
150
|
+
const repoRoot = getRepoRoot();
|
|
151
|
+
if (repoRoot) {
|
|
152
|
+
// 1. Repo package: bin/rip-<name>
|
|
153
|
+
const repoPkg = join(repoRoot, 'bin', `rip-${name}`);
|
|
154
|
+
if (existsSync(repoPkg)) {
|
|
155
|
+
const r = spawnSync(repoPkg, subArgs, { stdio: 'inherit', env: process.env });
|
|
156
|
+
process.exit(r.status ?? 1);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 2. Repo script: bin/<name>
|
|
160
|
+
const repoScript = join(repoRoot, 'bin', name);
|
|
161
|
+
if (existsSync(repoScript)) {
|
|
162
|
+
const r = spawnSync(repoScript, subArgs, { stdio: 'inherit', env: process.env });
|
|
163
|
+
process.exit(r.status ?? 1);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 3. Local node_modules: node_modules/.bin/rip-<name>
|
|
167
|
+
const localBin = join(repoRoot, 'node_modules', '.bin', `rip-${name}`);
|
|
168
|
+
if (existsSync(localBin)) {
|
|
169
|
+
const r = spawnSync(localBin, subArgs, { stdio: 'inherit', env: process.env });
|
|
170
|
+
process.exit(r.status ?? 1);
|
|
171
|
+
}
|
|
165
172
|
}
|
|
173
|
+
|
|
174
|
+
// 4. Global PATH: rip-<name>
|
|
175
|
+
const pathResult = spawnSync(`rip-${name}`, subArgs, { stdio: 'inherit', env: process.env });
|
|
176
|
+
if (pathResult.error?.code !== 'ENOENT') {
|
|
177
|
+
process.exit(pathResult.status ?? 1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 5. Not found
|
|
181
|
+
console.error(`rip: unknown command '${name}'\n\nRun 'rip --help' for usage.`);
|
|
182
|
+
process.exit(1);
|
|
166
183
|
}
|
|
167
|
-
const result = spawnSync('bun', ['--preload', loaderPath, serverPath, ...args.slice(1)], {
|
|
168
|
-
stdio: 'inherit',
|
|
169
|
-
env: process.env
|
|
170
|
-
});
|
|
171
|
-
process.exit(result.status ?? 1);
|
|
172
184
|
}
|
|
173
185
|
|
|
174
186
|
// --- REPL ---
|
|
@@ -256,20 +268,6 @@ async function main() {
|
|
|
256
268
|
process.exit(exitCode);
|
|
257
269
|
}
|
|
258
270
|
|
|
259
|
-
// Fallback: look for bin/{command} in git repo root
|
|
260
|
-
// Allows `rip migrate --status` to find and run {repo}/bin/migrate
|
|
261
|
-
if (inputFile && !inputFile.startsWith('-') && !isFile(inputFile)) {
|
|
262
|
-
try {
|
|
263
|
-
const repoRoot = getRepoRoot();
|
|
264
|
-
if (!repoRoot) throw new Error('No git repo root');
|
|
265
|
-
const binScript = join(repoRoot, 'bin', inputFile);
|
|
266
|
-
if (existsSync(binScript)) {
|
|
267
|
-
const r = spawnSync(binScript, scriptArgs, { stdio: 'inherit', env: process.env });
|
|
268
|
-
process.exit(r.status ?? 1);
|
|
269
|
-
}
|
|
270
|
-
} catch {}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
271
|
// --- Compile (with flags) ---
|
|
274
272
|
|
|
275
273
|
if (source === undefined) {
|
package/bin/rip-server
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from 'child_process';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { dirname, join } from 'path';
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const loaderPath = join(__dirname, '../rip-loader.js');
|
|
9
|
+
const serverPath = join(__dirname, '../packages/server/server.rip');
|
|
10
|
+
|
|
11
|
+
const nodeModules = join(__dirname, '..', '..');
|
|
12
|
+
if (!process.env.NODE_PATH?.split(':').includes(nodeModules)) {
|
|
13
|
+
process.env.NODE_PATH = [nodeModules, process.env.NODE_PATH].filter(Boolean).join(':');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const result = spawnSync('bun', ['--preload', loaderPath, serverPath, ...process.argv.slice(2)], {
|
|
17
|
+
stdio: 'inherit',
|
|
18
|
+
env: process.env
|
|
19
|
+
});
|
|
20
|
+
process.exit(result.status ?? 1);
|
package/docs/RIP-LANG.md
CHANGED
|
@@ -108,6 +108,14 @@ user = {name: "Alice", age: 30}
|
|
|
108
108
|
shorthand = {name, age} # Same as {name: name, age: age}
|
|
109
109
|
config = {api.host: "localhost", api.port: 3000} # Dotted keys → flat string keys
|
|
110
110
|
|
|
111
|
+
# Map literals — real JavaScript Map with any key type
|
|
112
|
+
table = *{
|
|
113
|
+
/^NAME:/: [""]
|
|
114
|
+
"CHOOSE 1": [1]
|
|
115
|
+
true: "yes"
|
|
116
|
+
null: "nothing"
|
|
117
|
+
}
|
|
118
|
+
|
|
111
119
|
# Ranges
|
|
112
120
|
nums = [1..5] # [1, 2, 3, 4, 5]
|
|
113
121
|
exclusive = [1...5] # [1, 2, 3, 4]
|
|
@@ -331,6 +339,7 @@ Multiple lines
|
|
|
331
339
|
| `not in` | Not in | `x not in arr` | Negated membership test |
|
|
332
340
|
| `not of` | Not of | `k not of obj` | Negated key existence |
|
|
333
341
|
| `<=>` | Two-way bind | `value <=> name` | Bidirectional reactive binding (render blocks) |
|
|
342
|
+
| `*{ }` | Map literal | `*{/pat/: val}` | `new Map([[/pat/, val]])` |
|
|
334
343
|
|
|
335
344
|
## Assignment Operators
|
|
336
345
|
|
|
@@ -2075,6 +2084,9 @@ a ?? b # nullish coalescing
|
|
|
2075
2084
|
# Word arrays
|
|
2076
2085
|
%w[foo bar baz] # ["foo", "bar", "baz"] — Ruby-style word literal
|
|
2077
2086
|
|
|
2087
|
+
# Map literals — real Map with any key type
|
|
2088
|
+
*{ /regex/: val, "key": val, 42: val }
|
|
2089
|
+
|
|
2078
2090
|
# Two-way binding (render blocks)
|
|
2079
2091
|
input value <=> @name # bidirectional reactive binding
|
|
2080
2092
|
Dialog open <=> @show # works with components too
|