rip-lang 3.13.13 → 3.13.15
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 +11 -12
- package/bin/rip +76 -139
- package/docs/RIP-INTERNALS.md +2 -2
- package/docs/RIP-LANG.md +18 -21
- package/docs/dist/rip.js +19 -6
- package/docs/dist/rip.min.js +157 -157
- package/docs/dist/rip.min.js.br +0 -0
- package/package.json +1 -1
- package/src/app.rip +15 -3
- package/src/grammar/README.md +1 -1
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.13.
|
|
12
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.13.15-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-1%
|
|
14
|
+
<a href="#"><img src="https://img.shields.io/badge/tests-1%2C255%2F1%2C255-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
|
|
|
@@ -417,18 +417,17 @@ Rip includes optional packages for full-stack development:
|
|
|
417
417
|
|
|
418
418
|
| Package | Version | Purpose |
|
|
419
419
|
|---------|---------|---------|
|
|
420
|
-
| [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.
|
|
421
|
-
| [@rip-lang/
|
|
422
|
-
| [@rip-lang/
|
|
423
|
-
| [@rip-lang/
|
|
424
|
-
| [@rip-lang/
|
|
425
|
-
| [@rip-lang/
|
|
426
|
-
| [@rip-lang/
|
|
427
|
-
| [@rip-lang/schema](packages/schema/) | 0.2.1 | Unified schema → TypeScript types, SQL DDL, validation, ORM |
|
|
420
|
+
| [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.13.13 | Core language compiler |
|
|
421
|
+
| [@rip-lang/server](packages/server/) | 1.2.11 | Multi-worker app server (web framework, hot reload, HTTPS, mDNS) |
|
|
422
|
+
| [@rip-lang/db](packages/db/) | 1.3.13 | DuckDB server with official UI + ActiveRecord-style client |
|
|
423
|
+
| [@rip-lang/grid](packages/grid/) | 0.2.8 | Reactive data grid |
|
|
424
|
+
| [@rip-lang/swarm](packages/swarm/) | 1.2.16 | Parallel job runner with worker pool |
|
|
425
|
+
| [@rip-lang/csv](packages/csv/) | 1.3.4 | CSV parser + writer |
|
|
426
|
+
| [@rip-lang/schema](packages/schema/) | 0.3.6 | Unified schema → TypeScript types, SQL DDL, validation, ORM |
|
|
428
427
|
| [VS Code Extension](packages/vscode/) | 0.5.0 | Syntax highlighting, type intelligence, source maps |
|
|
429
428
|
|
|
430
429
|
```bash
|
|
431
|
-
bun add -g @rip-lang/db # Installs everything (rip-lang +
|
|
430
|
+
bun add -g @rip-lang/db # Installs everything (rip-lang + server + db)
|
|
432
431
|
```
|
|
433
432
|
|
|
434
433
|
---
|
|
@@ -463,7 +462,7 @@ rip file.rip # Run
|
|
|
463
462
|
rip -c file.rip # Compile
|
|
464
463
|
rip -t file.rip # Tokens
|
|
465
464
|
rip -s file.rip # S-expressions
|
|
466
|
-
bun run test #
|
|
465
|
+
bun run test # 1255 tests
|
|
467
466
|
bun run parser # Rebuild parser
|
|
468
467
|
bun run build # Build browser bundle
|
|
469
468
|
```
|
package/bin/rip
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import { readFileSync, writeFileSync, existsSync, statSync, unlinkSync } from 'fs';
|
|
3
|
+
import { readFileSync, readdirSync, writeFileSync, existsSync, statSync, unlinkSync } from 'fs';
|
|
4
4
|
import { execSync, spawnSync, spawn } from 'child_process';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { dirname, basename, join } from 'path';
|
|
7
7
|
import { Compiler } from '../src/compiler.js';
|
|
8
|
-
import { startREPL } from '../src/repl.js';
|
|
9
8
|
import packageJson from '../package.json' with { type: 'json' };
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const __dirname = dirname(__filename);
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const loaderPath = join(__dirname, '../rip-loader.js');
|
|
14
12
|
|
|
15
|
-
//
|
|
16
|
-
const
|
|
17
|
-
if (!process.env.NODE_PATH?.split(':').includes(
|
|
18
|
-
process.env.NODE_PATH = [
|
|
13
|
+
// Ensure spawned processes can resolve @rip-lang/* packages
|
|
14
|
+
const nodeModules = join(__dirname, '..', '..');
|
|
15
|
+
if (!process.env.NODE_PATH?.split(':').includes(nodeModules)) {
|
|
16
|
+
process.env.NODE_PATH = [nodeModules, process.env.NODE_PATH].filter(Boolean).join(':');
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
const VERSION = packageJson.version;
|
|
22
20
|
const SUMMARY = packageJson.description;
|
|
23
21
|
|
|
22
|
+
const isFile = (path) => existsSync(path) && statSync(path).isFile();
|
|
23
|
+
|
|
24
24
|
function printHelp() {
|
|
25
25
|
console.log(`
|
|
26
26
|
Rip ${VERSION} - ${SUMMARY}
|
|
@@ -40,15 +40,25 @@ 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
|
-
-w, --web Launch browser REPL (auto-opens + auto-shutdown)
|
|
44
43
|
|
|
45
44
|
Subcommands:
|
|
45
|
+
rip serve [flags] [app] Start server (watches *.rip, HTTPS, mDNS)
|
|
46
46
|
rip check [dir] Type-check all .rip files in directory
|
|
47
47
|
|
|
48
|
+
Serve flags:
|
|
49
|
+
--watch=<glob> Watch glob pattern (default: *.rip)
|
|
50
|
+
--static Disable hot reload and file watching
|
|
51
|
+
http HTTP-only mode (no HTTPS)
|
|
52
|
+
http:<port> Set HTTP port
|
|
53
|
+
w:<n> Worker count (auto, half, 2x, 3x, or number)
|
|
54
|
+
|
|
48
55
|
Examples:
|
|
49
56
|
rip # Interactive REPL (terminal)
|
|
50
57
|
rip script.rip # Execute script directly
|
|
51
58
|
rip script.rip arg1 arg2 # Execute with arguments
|
|
59
|
+
rip serve # Serve ./index.rip (watches *.rip)
|
|
60
|
+
rip serve http # Serve HTTP-only
|
|
61
|
+
rip serve myapp # Serve with mDNS name
|
|
52
62
|
rip -c example.rip # Compile and show JavaScript
|
|
53
63
|
rip -o output.js example.rip # Compile and save to file
|
|
54
64
|
rip -s example.rip # Show ONLY s-expressions
|
|
@@ -59,7 +69,6 @@ Examples:
|
|
|
59
69
|
rip -m example.rip # Compile with inline source map
|
|
60
70
|
rip -cd example.rip # Show compiled JS and type declarations
|
|
61
71
|
rip -q -c example.rip # Just the JS, no headers (for piping)
|
|
62
|
-
rip -w # Launch browser REPL (auto-opens)
|
|
63
72
|
echo 'x = 1 + 2' | rip -c # Compile from stdin
|
|
64
73
|
|
|
65
74
|
Shebang support:
|
|
@@ -71,22 +80,14 @@ Shebang support:
|
|
|
71
80
|
async function main() {
|
|
72
81
|
const args = process.argv.slice(2);
|
|
73
82
|
|
|
74
|
-
// Find
|
|
75
|
-
// Everything
|
|
83
|
+
// Find script file (first non-option argument)
|
|
84
|
+
// Everything before it is rip options, everything after is script arguments
|
|
76
85
|
let scriptFileIndex = -1;
|
|
77
86
|
for (let i = 0; i < args.length; i++) {
|
|
78
|
-
|
|
79
|
-
if (
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
// First non-option arg is the script file
|
|
83
|
-
if (!args[i].startsWith('-')) {
|
|
84
|
-
scriptFileIndex = i;
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
+
if (i > 0 && (args[i - 1] === '-o' || args[i - 1] === '--output')) continue;
|
|
88
|
+
if (!args[i].startsWith('-')) { scriptFileIndex = i; break; }
|
|
87
89
|
}
|
|
88
90
|
|
|
89
|
-
// Split into rip options and script arguments
|
|
90
91
|
const rawOptions = scriptFileIndex === -1 ? args : args.slice(0, scriptFileIndex);
|
|
91
92
|
const scriptArgs = scriptFileIndex === -1 ? [] : args.slice(scriptFileIndex + 1);
|
|
92
93
|
|
|
@@ -95,7 +96,6 @@ async function main() {
|
|
|
95
96
|
/^-[a-zA-Z]{2,}$/.test(arg) ? [...arg.slice(1)].map(ch => `-${ch}`) : [arg]
|
|
96
97
|
);
|
|
97
98
|
|
|
98
|
-
// Only check ripOptions for rip's flags (not script args!)
|
|
99
99
|
if (ripOptions.includes('-h') || ripOptions.includes('--help')) {
|
|
100
100
|
printHelp();
|
|
101
101
|
process.exit(0);
|
|
@@ -104,13 +104,11 @@ async function main() {
|
|
|
104
104
|
if (ripOptions.includes('-v') || ripOptions.includes('--version')) {
|
|
105
105
|
console.log(`Rip ${VERSION} - ${SUMMARY}`);
|
|
106
106
|
try {
|
|
107
|
-
const { readdirSync } = await import('fs');
|
|
108
107
|
const home = process.env.HOME || process.env.USERPROFILE;
|
|
109
108
|
const scopeDir = join(home, '.bun', 'install', 'global', 'node_modules', '@rip-lang');
|
|
110
109
|
if (existsSync(scopeDir) && statSync(scopeDir).isDirectory()) {
|
|
111
|
-
const pkgs = readdirSync(scopeDir).sort();
|
|
112
110
|
console.log();
|
|
113
|
-
for (const name of
|
|
111
|
+
for (const name of readdirSync(scopeDir).sort()) {
|
|
114
112
|
try {
|
|
115
113
|
const pkg = JSON.parse(readFileSync(join(scopeDir, name, 'package.json'), 'utf-8'));
|
|
116
114
|
console.log(` ${pkg.name.padEnd(24)} ${pkg.version}`);
|
|
@@ -121,58 +119,32 @@ async function main() {
|
|
|
121
119
|
process.exit(0);
|
|
122
120
|
}
|
|
123
121
|
|
|
124
|
-
//
|
|
122
|
+
// --- Subcommands ---
|
|
123
|
+
|
|
125
124
|
if (args[0] === 'check') {
|
|
126
|
-
const targetDir = args[1] || '.';
|
|
127
125
|
const { runCheck } = await import('../src/typecheck.js');
|
|
128
|
-
const exitCode = await runCheck(
|
|
126
|
+
const exitCode = await runCheck(args[1] || '.', { quiet: args.includes('-q') || args.includes('--quiet') });
|
|
129
127
|
process.exit(exitCode);
|
|
130
128
|
}
|
|
131
129
|
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
130
|
+
if (args[0] === 'serve') {
|
|
131
|
+
let serverPath;
|
|
132
|
+
try {
|
|
133
|
+
serverPath = fileURLToPath(import.meta.resolve('@rip-lang/server/server'));
|
|
134
|
+
} catch {
|
|
135
|
+
console.error('Error: @rip-lang/server is not installed.\n\n bun add @rip-lang/server\n');
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
const result = spawnSync('bun', ['--preload', loaderPath, serverPath, ...args.slice(1)], {
|
|
139
|
+
stdio: 'inherit',
|
|
140
140
|
env: process.env
|
|
141
141
|
});
|
|
142
|
-
|
|
143
|
-
let actualPort = null;
|
|
144
|
-
|
|
145
|
-
// Capture server output and extract port
|
|
146
|
-
serverProcess.stdout.on('data', (data) => {
|
|
147
|
-
const output = data.toString();
|
|
148
|
-
process.stdout.write(output);
|
|
149
|
-
|
|
150
|
-
// Parse port from "Server running at http://localhost:PORT"
|
|
151
|
-
if (!actualPort) {
|
|
152
|
-
const match = output.match(/localhost:(\d+)/);
|
|
153
|
-
if (match) {
|
|
154
|
-
actualPort = match[1];
|
|
155
|
-
|
|
156
|
-
// Open browser once we know the port
|
|
157
|
-
setTimeout(() => {
|
|
158
|
-
const openCmd = process.platform === 'darwin' ? 'open' :
|
|
159
|
-
process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
160
|
-
execSync(`${openCmd} http://localhost:${actualPort}/`);
|
|
161
|
-
console.log('\n📱 Press Ctrl+C to stop server\n');
|
|
162
|
-
}, 300);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
// Keep server running (don't exit)
|
|
168
|
-
return;
|
|
142
|
+
process.exit(result.status ?? 1);
|
|
169
143
|
}
|
|
170
144
|
|
|
171
|
-
//
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if ((args.length === 0 && isTTY) || ripOptions.includes('-r') || ripOptions.includes('--repl')) {
|
|
175
|
-
// Spawn REPL with --experimental-vm-modules flag for proper ES module support
|
|
145
|
+
// --- REPL ---
|
|
146
|
+
|
|
147
|
+
if ((args.length === 0 && process.stdin.isTTY) || ripOptions.includes('-r') || ripOptions.includes('--repl')) {
|
|
176
148
|
const replModule = join(__dirname, '../src/repl.js');
|
|
177
149
|
const replProcess = spawn('bun', ['--experimental-vm-modules', '-e', `import('${replModule}').then(m => m.startREPL())`], {
|
|
178
150
|
stdio: 'inherit',
|
|
@@ -182,6 +154,8 @@ async function main() {
|
|
|
182
154
|
return;
|
|
183
155
|
}
|
|
184
156
|
|
|
157
|
+
// --- Execute or compile ---
|
|
158
|
+
|
|
185
159
|
const showTokens = ripOptions.includes('-t') || ripOptions.includes('--tokens');
|
|
186
160
|
const showSExpr = ripOptions.includes('-s') || ripOptions.includes('--sexpr');
|
|
187
161
|
const showCompiled = ripOptions.includes('-c') || ripOptions.includes('--compile');
|
|
@@ -189,133 +163,96 @@ async function main() {
|
|
|
189
163
|
const generateMap = ripOptions.includes('-m') || ripOptions.includes('--map');
|
|
190
164
|
const quiet = ripOptions.includes('-q') || ripOptions.includes('--quiet');
|
|
191
165
|
|
|
192
|
-
const options = {
|
|
193
|
-
showTokens,
|
|
194
|
-
showSExpr,
|
|
195
|
-
quiet,
|
|
196
|
-
types: generateDts ? 'emit' : undefined,
|
|
197
|
-
sourceMap: generateMap ? 'inline' : undefined,
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
// Find input file and output file from ripOptions only
|
|
201
166
|
let inputFile = scriptFileIndex === -1 ? null : args[scriptFileIndex];
|
|
202
167
|
let outputFile = null;
|
|
203
168
|
|
|
204
169
|
for (let i = 0; i < ripOptions.length; i++) {
|
|
205
170
|
if (ripOptions[i] === '-o' || ripOptions[i] === '--output') {
|
|
206
|
-
outputFile = ripOptions[i
|
|
207
|
-
i++;
|
|
171
|
+
outputFile = ripOptions[++i];
|
|
208
172
|
}
|
|
209
173
|
}
|
|
210
174
|
|
|
211
|
-
//
|
|
212
|
-
const isFile = (path) => existsSync(path) && statSync(path).isFile();
|
|
213
|
-
|
|
214
|
-
// If no compile flags and file exists → execute the script instead of compiling it
|
|
175
|
+
// Execute script directly (no compile flags)
|
|
215
176
|
const hasCompileFlag = showCompiled || showTokens || showSExpr || generateDts || generateMap || outputFile;
|
|
216
177
|
if (inputFile && !hasCompileFlag && isFile(inputFile)) {
|
|
217
|
-
const loaderPath = join(__dirname, '../rip-loader.js');
|
|
218
|
-
|
|
219
178
|
if (inputFile.endsWith('.rip')) {
|
|
220
179
|
const result = spawnSync('bun', ['--preload', loaderPath, inputFile, ...scriptArgs], {
|
|
221
180
|
stdio: 'inherit',
|
|
222
181
|
env: process.env
|
|
223
182
|
});
|
|
224
183
|
process.exit(result.status ?? 1);
|
|
225
|
-
} else {
|
|
226
|
-
// Non-.rip files (e.g. shebang scripts): compile, write temp file, execute
|
|
227
|
-
const source = readFileSync(inputFile, 'utf-8');
|
|
228
|
-
const compiler = new Compiler();
|
|
229
|
-
const result = compiler.compile(source);
|
|
230
|
-
const tmp = join(dirname(inputFile), `.${basename(inputFile)}.__rip__.mjs`);
|
|
231
|
-
let exitCode = 0;
|
|
232
|
-
try {
|
|
233
|
-
writeFileSync(tmp, result.code);
|
|
234
|
-
const r = spawnSync('bun', ['--preload', loaderPath, tmp, ...scriptArgs], { stdio: 'inherit', env: process.env });
|
|
235
|
-
exitCode = r.status ?? 1;
|
|
236
|
-
} catch (error) {
|
|
237
|
-
exitCode = error.status || 1;
|
|
238
|
-
}
|
|
239
|
-
try { unlinkSync(tmp); } catch {}
|
|
240
|
-
process.exit(exitCode);
|
|
241
184
|
}
|
|
185
|
+
|
|
186
|
+
// Non-.rip files (e.g. shebang scripts): compile to temp file, execute, clean up
|
|
187
|
+
const source = readFileSync(inputFile, 'utf-8');
|
|
188
|
+
const result = new Compiler().compile(source);
|
|
189
|
+
const tmp = join(dirname(inputFile), `.${basename(inputFile)}.__rip__.mjs`);
|
|
190
|
+
let exitCode = 0;
|
|
191
|
+
try {
|
|
192
|
+
writeFileSync(tmp, result.code);
|
|
193
|
+
const r = spawnSync('bun', ['--preload', loaderPath, tmp, ...scriptArgs], { stdio: 'inherit', env: process.env });
|
|
194
|
+
exitCode = r.status ?? 1;
|
|
195
|
+
} catch (error) {
|
|
196
|
+
exitCode = error.status || 1;
|
|
197
|
+
}
|
|
198
|
+
try { unlinkSync(tmp); } catch {}
|
|
199
|
+
process.exit(exitCode);
|
|
242
200
|
}
|
|
243
201
|
|
|
244
|
-
// Fallback:
|
|
202
|
+
// Fallback: look for bin/{command} in git repo root
|
|
245
203
|
// Allows `rip migrate --status` to find and run {repo}/bin/migrate
|
|
246
|
-
// Also triggers if inputFile is a directory (not a compilable file)
|
|
247
204
|
if (inputFile && !inputFile.startsWith('-') && !isFile(inputFile)) {
|
|
248
205
|
try {
|
|
249
|
-
// Check if we're in a git repo
|
|
250
206
|
const repoRoot = execSync('git rev-parse --show-toplevel', {
|
|
251
207
|
encoding: 'utf-8',
|
|
252
208
|
stdio: ['pipe', 'pipe', 'pipe']
|
|
253
209
|
}).trim();
|
|
254
|
-
|
|
255
|
-
// Look for bin/{command} in repo root
|
|
256
210
|
const binScript = join(repoRoot, 'bin', inputFile);
|
|
257
|
-
|
|
258
211
|
if (existsSync(binScript)) {
|
|
259
212
|
const r = spawnSync(binScript, scriptArgs, { stdio: 'inherit', env: process.env });
|
|
260
213
|
process.exit(r.status ?? 1);
|
|
261
214
|
}
|
|
262
|
-
} catch {
|
|
263
|
-
// Not in a git repo, or git not available - fall through to normal error
|
|
264
|
-
}
|
|
215
|
+
} catch {}
|
|
265
216
|
}
|
|
266
217
|
|
|
218
|
+
// --- Compile ---
|
|
219
|
+
|
|
267
220
|
let source;
|
|
268
221
|
|
|
269
222
|
try {
|
|
270
|
-
if (
|
|
271
|
-
// Read from stdin if no file specified (file descriptor 0)
|
|
272
|
-
source = readFileSync(0, 'utf-8');
|
|
273
|
-
} else {
|
|
274
|
-
// Check if file exists and is a regular file
|
|
223
|
+
if (inputFile) {
|
|
275
224
|
if (!isFile(inputFile)) {
|
|
276
225
|
console.error(`Error: File not found: ${inputFile}`);
|
|
277
226
|
process.exit(1);
|
|
278
227
|
}
|
|
279
|
-
// Read source file
|
|
280
228
|
source = readFileSync(inputFile, 'utf-8');
|
|
229
|
+
} else {
|
|
230
|
+
source = readFileSync(0, 'utf-8');
|
|
281
231
|
}
|
|
282
232
|
|
|
283
|
-
|
|
284
|
-
|
|
233
|
+
const compiler = new Compiler({ showTokens, showSExpr, quiet,
|
|
234
|
+
types: generateDts ? 'emit' : undefined,
|
|
235
|
+
sourceMap: generateMap ? 'inline' : undefined,
|
|
236
|
+
});
|
|
285
237
|
const result = compiler.compile(source);
|
|
286
238
|
|
|
287
|
-
// Determine if we should show compiled output
|
|
288
|
-
// Show compiled JS if: -c flag, OR no debug flags (default mode), OR saving to file
|
|
289
239
|
const shouldShowCompiled = showCompiled || (!showTokens && !showSExpr && !generateDts) || outputFile;
|
|
290
240
|
|
|
291
|
-
// Output
|
|
292
241
|
if (outputFile) {
|
|
293
|
-
// Save to file
|
|
294
242
|
writeFileSync(outputFile, result.code, 'utf-8');
|
|
295
|
-
if (!
|
|
296
|
-
console.log(`Compiled to ${outputFile}`);
|
|
297
|
-
}
|
|
243
|
+
if (!quiet) console.log(`Compiled to ${outputFile}`);
|
|
298
244
|
} else if (shouldShowCompiled) {
|
|
299
|
-
|
|
300
|
-
if (!options.quiet) {
|
|
301
|
-
console.log(`// == JavaScript output by Rip ${VERSION} == //\n`);
|
|
302
|
-
}
|
|
245
|
+
if (!quiet) console.log(`// == JavaScript output by Rip ${VERSION} == //\n`);
|
|
303
246
|
console.log(result.code);
|
|
304
247
|
}
|
|
305
248
|
|
|
306
|
-
// Show .d.ts type declarations to stdout
|
|
307
249
|
if (generateDts && result.dts) {
|
|
308
|
-
if (!
|
|
309
|
-
console.log(`// == Type declarations == //\n`);
|
|
310
|
-
}
|
|
250
|
+
if (!quiet) console.log(`// == Type declarations == //\n`);
|
|
311
251
|
console.log(result.dts);
|
|
312
252
|
}
|
|
313
|
-
|
|
314
253
|
} catch (error) {
|
|
315
254
|
console.error('Compilation Error:', error.message);
|
|
316
|
-
if (error.stack)
|
|
317
|
-
console.error(error.stack);
|
|
318
|
-
}
|
|
255
|
+
if (error.stack) console.error(error.stack);
|
|
319
256
|
process.exit(1);
|
|
320
257
|
}
|
|
321
258
|
}
|
package/docs/RIP-INTERNALS.md
CHANGED
|
@@ -494,7 +494,7 @@ The `Compiler` class's lexer adapter reconstructs `new String()` wrapping from t
|
|
|
494
494
|
|
|
495
495
|
**Solar** is a complete SLR(1) parser generator included with Rip — written in Rip, compiled by Rip, zero external dependencies.
|
|
496
496
|
|
|
497
|
-
**Location:** `src/grammar/solar.rip` (
|
|
497
|
+
**Location:** `src/grammar/solar.rip` (929 lines)
|
|
498
498
|
|
|
499
499
|
## Grammar Syntax
|
|
500
500
|
|
|
@@ -533,7 +533,7 @@ Parenthetical: [
|
|
|
533
533
|
| Parse time | 12,500ms | ~50ms |
|
|
534
534
|
| Dependencies | Many | Zero |
|
|
535
535
|
| Self-hosting | No | Yes |
|
|
536
|
-
| Code size | 2,285 LOC |
|
|
536
|
+
| Code size | 2,285 LOC | 929 LOC |
|
|
537
537
|
|
|
538
538
|
After modifying `src/grammar/grammar.rip`:
|
|
539
539
|
|
package/docs/RIP-LANG.md
CHANGED
|
@@ -1232,8 +1232,7 @@ text =~ /line2/m # Works with /m flag
|
|
|
1232
1232
|
Rip includes optional packages for full-stack development. All are written in Rip, have zero dependencies, and run on Bun.
|
|
1233
1233
|
|
|
1234
1234
|
```bash
|
|
1235
|
-
bun add @rip-lang/
|
|
1236
|
-
bun add @rip-lang/server # Production server
|
|
1235
|
+
bun add @rip-lang/server # Web framework + production server
|
|
1237
1236
|
bun add @rip-lang/grid # Reactive data grid
|
|
1238
1237
|
bun add @rip-lang/db # DuckDB server + client
|
|
1239
1238
|
bun add @rip-lang/schema # ORM + validation
|
|
@@ -1241,12 +1240,12 @@ bun add @rip-lang/swarm # Parallel job runner
|
|
|
1241
1240
|
bun add @rip-lang/csv # CSV parser + writer
|
|
1242
1241
|
```
|
|
1243
1242
|
|
|
1244
|
-
## @rip-lang/
|
|
1243
|
+
## @rip-lang/server — Web Framework & Production Server
|
|
1245
1244
|
|
|
1246
|
-
Sinatra-style routing with `@` context magic and built-in validators.
|
|
1245
|
+
Sinatra-style routing with `@` context magic and built-in validators. Run with `rip serve` for multi-worker production deployment with hot reload, HTTPS, and mDNS.
|
|
1247
1246
|
|
|
1248
1247
|
```coffee
|
|
1249
|
-
import { get, post, use, read, start, notFound } from '@rip-lang/
|
|
1248
|
+
import { get, post, use, read, start, notFound } from '@rip-lang/server'
|
|
1250
1249
|
|
|
1251
1250
|
# Routes — return data directly
|
|
1252
1251
|
get '/' -> { message: 'Hello!' }
|
|
@@ -1264,7 +1263,7 @@ get '/css/*' -> @send "public/#{@req.path.slice(5)}"
|
|
|
1264
1263
|
notFound -> @send 'index.html', 'text/html; charset=UTF-8'
|
|
1265
1264
|
|
|
1266
1265
|
# Middleware
|
|
1267
|
-
import { cors, logger, sessions } from '@rip-lang/
|
|
1266
|
+
import { cors, logger, sessions } from '@rip-lang/server/middleware'
|
|
1268
1267
|
|
|
1269
1268
|
use logger()
|
|
1270
1269
|
use cors origin: '*'
|
|
@@ -1277,6 +1276,15 @@ after -> console.log "#{@req.method} #{@req.path} - #{Date.now() - @start}ms"
|
|
|
1277
1276
|
start port: 3000
|
|
1278
1277
|
```
|
|
1279
1278
|
|
|
1279
|
+
### Serving
|
|
1280
|
+
|
|
1281
|
+
```bash
|
|
1282
|
+
rip serve # Start (uses ./index.rip)
|
|
1283
|
+
rip serve --static # No watching, no hot reload (production)
|
|
1284
|
+
rip serve myapp # Named (accessible at myapp.local)
|
|
1285
|
+
rip serve http:3000 # HTTP on specific port
|
|
1286
|
+
```
|
|
1287
|
+
|
|
1280
1288
|
### read() Validators
|
|
1281
1289
|
|
|
1282
1290
|
```coffee
|
|
@@ -1298,25 +1306,14 @@ ids = read 'ids', 'ids' # "1,2,3" → [1, 2, 3]
|
|
|
1298
1306
|
slug = read 'slug', 'slug' # URL-safe slug
|
|
1299
1307
|
```
|
|
1300
1308
|
|
|
1301
|
-
## @rip-lang/server — Production Server
|
|
1302
|
-
|
|
1303
|
-
Multi-worker process manager with hot reload, automatic HTTPS, and mDNS.
|
|
1304
|
-
|
|
1305
|
-
```bash
|
|
1306
|
-
rip-server # Start (uses ./index.rip)
|
|
1307
|
-
rip-server -w # With file watching + hot-reload
|
|
1308
|
-
rip-server myapp # Named (accessible at myapp.local)
|
|
1309
|
-
rip-server http:3000 # HTTP on specific port
|
|
1310
|
-
```
|
|
1311
|
-
|
|
1312
1309
|
## Rip UI — Reactive Web Framework (built into rip-lang)
|
|
1313
1310
|
|
|
1314
1311
|
Zero-build reactive framework. Ships the compiler to the browser and compiles `.rip` components on demand. File-based routing, unified reactive stash, and SSE hot reload.
|
|
1315
1312
|
|
|
1316
1313
|
```coffee
|
|
1317
1314
|
# Server setup (index.rip)
|
|
1318
|
-
import { get, use, start, notFound } from '@rip-lang/
|
|
1319
|
-
import { serve } from '@rip-lang/
|
|
1315
|
+
import { get, use, start, notFound } from '@rip-lang/server'
|
|
1316
|
+
import { serve } from '@rip-lang/server/middleware'
|
|
1320
1317
|
|
|
1321
1318
|
dir = import.meta.dir
|
|
1322
1319
|
use serve dir: dir, watch: true
|
|
@@ -1412,8 +1409,8 @@ user.save!()
|
|
|
1412
1409
|
A complete API server in Rip:
|
|
1413
1410
|
|
|
1414
1411
|
```coffee
|
|
1415
|
-
import { get, post, use, read, start, notFound } from '@rip-lang/
|
|
1416
|
-
import { cors, logger } from '@rip-lang/
|
|
1412
|
+
import { get, post, use, read, start, notFound } from '@rip-lang/server'
|
|
1413
|
+
import { cors, logger } from '@rip-lang/server/middleware'
|
|
1417
1414
|
|
|
1418
1415
|
use logger()
|
|
1419
1416
|
use cors origin: '*'
|
package/docs/dist/rip.js
CHANGED
|
@@ -8352,8 +8352,8 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
|
|
|
8352
8352
|
return new CodeGenerator({}).getComponentRuntime();
|
|
8353
8353
|
}
|
|
8354
8354
|
// src/browser.js
|
|
8355
|
-
var VERSION = "3.13.
|
|
8356
|
-
var BUILD_DATE = "2026-02-25@
|
|
8355
|
+
var VERSION = "3.13.15";
|
|
8356
|
+
var BUILD_DATE = "2026-02-25@06:33:14GMT";
|
|
8357
8357
|
if (typeof globalThis !== "undefined") {
|
|
8358
8358
|
if (!globalThis.__rip)
|
|
8359
8359
|
new Function(getReactiveRuntime())();
|
|
@@ -9519,7 +9519,7 @@ ${indented}`);
|
|
|
9519
9519
|
return renderer;
|
|
9520
9520
|
};
|
|
9521
9521
|
var launch = async function(appBase = "", opts = {}) {
|
|
9522
|
-
let _save, _storage, _storageKey, app, appComponents, bundle, classesKey, compile2, el, hash, persist, renderer, res, resolver, router, saved, savedData, target;
|
|
9522
|
+
let _save, _storage, _storageKey, app, appComponents, bundle, cached, classesKey, compile2, el, etag, etagKey, hash, headers, persist, renderer, res, resolver, router, saved, savedData, target;
|
|
9523
9523
|
globalThis.__ripLaunched = true;
|
|
9524
9524
|
if (typeof appBase === "object") {
|
|
9525
9525
|
opts = appBase;
|
|
@@ -9541,11 +9541,24 @@ ${indented}`);
|
|
|
9541
9541
|
if (opts.bundle) {
|
|
9542
9542
|
bundle = opts.bundle;
|
|
9543
9543
|
} else if (opts.bundleUrl) {
|
|
9544
|
-
|
|
9545
|
-
|
|
9544
|
+
headers = {};
|
|
9545
|
+
etagKey = `__rip_etag_${opts.bundleUrl}`;
|
|
9546
|
+
cached = sessionStorage.getItem(etagKey);
|
|
9547
|
+
if (cached)
|
|
9548
|
+
headers["If-None-Match"] = cached;
|
|
9549
|
+
res = await fetch(opts.bundleUrl, { headers });
|
|
9550
|
+
if (res.status === 304) {
|
|
9551
|
+
bundle = JSON.parse(sessionStorage.getItem(`${etagKey}_data`));
|
|
9552
|
+
} else if (res.ok) {
|
|
9553
|
+
bundle = await res.json();
|
|
9554
|
+
etag = res.headers.get("etag");
|
|
9555
|
+
if (etag) {
|
|
9556
|
+
sessionStorage.setItem(etagKey, etag);
|
|
9557
|
+
sessionStorage.setItem(`${etagKey}_data`, JSON.stringify(bundle));
|
|
9558
|
+
}
|
|
9559
|
+
} else {
|
|
9546
9560
|
throw new Error(`launch: ${opts.bundleUrl} (${res.status})`);
|
|
9547
9561
|
}
|
|
9548
|
-
bundle = await res.json();
|
|
9549
9562
|
} else {
|
|
9550
9563
|
throw new Error("launch: no bundle or bundleUrl provided");
|
|
9551
9564
|
}
|