rip-lang 3.4.5 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +6 -6
- package/docs/RIP-GUIDE.md +16 -5
- package/docs/RIP-LANG.md +1 -1
- package/docs/dist/rip.browser.js +51 -4
- package/docs/dist/rip.browser.min.js +93 -91
- package/docs/dist/rip.browser.min.js.br +0 -0
- package/docs/index.html +9 -9
- package/package.json +3 -3
- package/scripts/serve.js +1 -2
- package/src/browser.js +33 -4
- package/src/lexer.js +21 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,15 @@ All notable changes to Rip will be documented in this file.
|
|
|
7
7
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
8
8
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
9
9
|
|
|
10
|
+
## [3.5.0] - 2026-02-10
|
|
11
|
+
|
|
12
|
+
### Browser Runtime Enhancements
|
|
13
|
+
|
|
14
|
+
- **`importRip(url)`** — New function to fetch, compile, and import `.rip` files as ES modules via blob URL. Registered on `globalThis` for use in `<script type="text/rip">` blocks.
|
|
15
|
+
- **Async `<script type="text/rip">`** — `processRipScripts` now wraps compiled code in an async IIFE, enabling `await` (Rip's `!` operator) in inline scripts.
|
|
16
|
+
- **Eager reactive runtime** — `globalThis.__rip` is registered when `rip.browser.js` loads, making reactive primitives available to framework code without the compiler needing to detect reactive operators.
|
|
17
|
+
- **`compileToJS` on globalThis** — The compiler function is now globally accessible, enabling auto-detection by framework code like `launch()`.
|
|
18
|
+
|
|
10
19
|
## [3.4.3] - 2026-02-09
|
|
11
20
|
|
|
12
21
|
### Source Maps & IDE Intelligence
|
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.
|
|
12
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.5.0-blue.svg" alt="Version"></a>
|
|
13
13
|
<a href="#zero-dependencies"><img src="https://img.shields.io/badge/dependencies-ZERO-brightgreen.svg" alt="Dependencies"></a>
|
|
14
14
|
<a href="#"><img src="https://img.shields.io/badge/tests-1140%2F1140-brightgreen.svg" alt="Tests"></a>
|
|
15
15
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
|
|
@@ -242,7 +242,7 @@ Counter = component
|
|
|
242
242
|
|
|
243
243
|
Two keywords — `component` and `render` — are all the language adds. Everything else (`:=` state, `~=` computed, methods, lifecycle) is standard Rip.
|
|
244
244
|
|
|
245
|
-
See [@rip-lang/ui](packages/ui/) for the full framework:
|
|
245
|
+
See [@rip-lang/ui](packages/ui/) for the full framework: file-based router, reactive stash, parts system, and component renderer.
|
|
246
246
|
|
|
247
247
|
---
|
|
248
248
|
|
|
@@ -299,9 +299,9 @@ Simple arrays (with `.loc`) instead of AST node classes. The compiler is self-ho
|
|
|
299
299
|
| Grammar | `src/grammar/grammar.rip` | 935 |
|
|
300
300
|
| Parser Generator | `src/grammar/solar.rip` | 916 |
|
|
301
301
|
| REPL | `src/repl.js` | 707 |
|
|
302
|
-
| Browser Entry | `src/browser.js` |
|
|
302
|
+
| Browser Entry | `src/browser.js` | 107 |
|
|
303
303
|
| Tags | `src/tags.js` | 63 |
|
|
304
|
-
| **Total** | |
|
|
304
|
+
| **Total** | | **~10,325** |
|
|
305
305
|
|
|
306
306
|
---
|
|
307
307
|
|
|
@@ -311,11 +311,11 @@ Rip includes optional packages for full-stack development:
|
|
|
311
311
|
|
|
312
312
|
| Package | Version | Purpose |
|
|
313
313
|
|---------|---------|---------|
|
|
314
|
-
| [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.
|
|
314
|
+
| [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.5.0 | Core language compiler |
|
|
315
315
|
| [@rip-lang/api](packages/api/) | 1.1.4 | HTTP framework (Sinatra-style routing, 37 validators) |
|
|
316
316
|
| [@rip-lang/server](packages/server/) | 1.1.3 | Multi-worker app server (hot reload, HTTPS, mDNS) |
|
|
317
317
|
| [@rip-lang/db](packages/db/) | 1.1.2 | DuckDB server with official UI (pure Bun FFI) |
|
|
318
|
-
| [@rip-lang/ui](packages/ui/) | 0.
|
|
318
|
+
| [@rip-lang/ui](packages/ui/) | 0.2.0 | Zero-build reactive web framework (stash, router, components) |
|
|
319
319
|
| [@rip-lang/swarm](packages/swarm/) | 1.1.1 | Parallel job runner with worker pool |
|
|
320
320
|
| [@rip-lang/csv](packages/csv/) | 1.1.1 | CSV parser + writer |
|
|
321
321
|
| [@rip-lang/schema](packages/schema/) | 0.1.0 | ORM + validation |
|
package/docs/RIP-GUIDE.md
CHANGED
|
@@ -448,22 +448,33 @@ start port: 3000
|
|
|
448
448
|
|
|
449
449
|
### @rip-lang/ui — Reactive Web Framework
|
|
450
450
|
|
|
451
|
-
Zero-build framework.
|
|
451
|
+
Zero-build framework. The browser loads the Rip compiler, compiles the UI
|
|
452
|
+
framework, fetches an app bundle, and renders. No build step, no bundler.
|
|
452
453
|
|
|
453
454
|
```coffee
|
|
454
|
-
# Server
|
|
455
|
+
# Server (index.rip)
|
|
455
456
|
import { get, use, start, notFound } from '@rip-lang/api'
|
|
456
457
|
import { ripUI } from '@rip-lang/ui/serve'
|
|
457
458
|
|
|
458
459
|
dir = import.meta.dir
|
|
459
|
-
use ripUI
|
|
460
|
+
use ripUI dir: dir, watch: true, title: 'My App'
|
|
461
|
+
get '/css/*', -> @send "#{dir}/css/#{@req.path.slice(5)}"
|
|
460
462
|
notFound -> @send "#{dir}/index.html", 'text/html; charset=UTF-8'
|
|
461
463
|
start port: 3000
|
|
462
464
|
```
|
|
463
465
|
|
|
466
|
+
```html
|
|
467
|
+
<!-- index.html -->
|
|
468
|
+
<script type="module" src="/rip/browser.js"></script>
|
|
469
|
+
<script type="text/rip">
|
|
470
|
+
{ launch } = importRip! '/rip/ui.rip'
|
|
471
|
+
launch()
|
|
472
|
+
</script>
|
|
473
|
+
```
|
|
474
|
+
|
|
464
475
|
```coffee
|
|
465
|
-
# Component (
|
|
466
|
-
Counter = component
|
|
476
|
+
# Component (parts/counter.rip)
|
|
477
|
+
export Counter = component
|
|
467
478
|
@count := 0
|
|
468
479
|
doubled ~= @count * 2
|
|
469
480
|
|
package/docs/RIP-LANG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<img src="https://raw.githubusercontent.com/shreeve/rip-lang/main/docs/rip.png" style="width:50px" /> <br>
|
|
2
2
|
|
|
3
|
-
# Rip
|
|
3
|
+
# Rip Language Reference
|
|
4
4
|
|
|
5
5
|
Rip is a modern reactive language that compiles to ES2022 JavaScript. It combines CoffeeScript's elegant syntax with built-in reactivity primitives. Zero dependencies, self-hosting, ~10,300 LOC.
|
|
6
6
|
|
package/docs/dist/rip.browser.js
CHANGED
|
@@ -1810,7 +1810,7 @@ class Lexer {
|
|
|
1810
1810
|
let indent = null;
|
|
1811
1811
|
let outdent = null;
|
|
1812
1812
|
let condition = (token, i) => {
|
|
1813
|
-
return token[1] !== ";" && SINGLE_CLOSERS.has(token[0]) && !(token[0] === "TERMINATOR" && EXPRESSION_CLOSE.has(this.tokens[i + 1]?.[0])) && !(token[0] === "ELSE" && starter !== "THEN") || token[0] === "INDENT" && !token.generated && (starter === "->" || starter === "=>") || token[0] === "," && (starter === "->" || starter === "=>") && !this.commaInImplicitCall(i) || CALL_CLOSERS.has(token[0]) && (this.tokens[i - 1]?.newLine || this.tokens[i - 1]?.[0] === "OUTDENT");
|
|
1813
|
+
return token[1] !== ";" && SINGLE_CLOSERS.has(token[0]) && !(token[0] === "TERMINATOR" && EXPRESSION_CLOSE.has(this.tokens[i + 1]?.[0])) && !(token[0] === "ELSE" && starter !== "THEN") || token[0] === "INDENT" && !token.generated && (starter === "->" || starter === "=>") || token[0] === "," && (starter === "->" || starter === "=>") && !this.commaInImplicitCall(i) && !this.commaInImplicitObject(i) || CALL_CLOSERS.has(token[0]) && (this.tokens[i - 1]?.newLine || this.tokens[i - 1]?.[0] === "OUTDENT");
|
|
1814
1814
|
};
|
|
1815
1815
|
let action = (token, i) => {
|
|
1816
1816
|
let idx = this.tokens[i - 1]?.[0] === "," ? i - 1 : i;
|
|
@@ -2275,6 +2275,30 @@ class Lexer {
|
|
|
2275
2275
|
}
|
|
2276
2276
|
return false;
|
|
2277
2277
|
}
|
|
2278
|
+
commaInImplicitObject(i) {
|
|
2279
|
+
let levels = 0;
|
|
2280
|
+
for (let j = i - 1;j >= 0; j--) {
|
|
2281
|
+
let tag = this.tokens[j][0];
|
|
2282
|
+
if (EXPRESSION_END.has(tag)) {
|
|
2283
|
+
levels++;
|
|
2284
|
+
continue;
|
|
2285
|
+
}
|
|
2286
|
+
if (EXPRESSION_START.has(tag)) {
|
|
2287
|
+
levels--;
|
|
2288
|
+
if (levels < 0)
|
|
2289
|
+
return false;
|
|
2290
|
+
continue;
|
|
2291
|
+
}
|
|
2292
|
+
if (levels > 0)
|
|
2293
|
+
continue;
|
|
2294
|
+
if (tag === ":" && j > 0 && this.tokens[j - 1][0] === "PROPERTY") {
|
|
2295
|
+
return this.looksObjectish(i + 1);
|
|
2296
|
+
}
|
|
2297
|
+
if (LINE_BREAK.has(tag))
|
|
2298
|
+
return false;
|
|
2299
|
+
}
|
|
2300
|
+
return false;
|
|
2301
|
+
}
|
|
2278
2302
|
looksObjectish(j) {
|
|
2279
2303
|
if (!this.tokens[j])
|
|
2280
2304
|
return false;
|
|
@@ -7536,8 +7560,11 @@ function getComponentRuntime() {
|
|
|
7536
7560
|
return new CodeGenerator({}).getComponentRuntime();
|
|
7537
7561
|
}
|
|
7538
7562
|
// src/browser.js
|
|
7539
|
-
var VERSION = "3.
|
|
7540
|
-
var BUILD_DATE = "2026-02-
|
|
7563
|
+
var VERSION = "3.5.0";
|
|
7564
|
+
var BUILD_DATE = "2026-02-10@20:22:29GMT";
|
|
7565
|
+
if (typeof globalThis !== "undefined" && !globalThis.__rip) {
|
|
7566
|
+
new Function(getReactiveRuntime())();
|
|
7567
|
+
}
|
|
7541
7568
|
var dedent = (s) => {
|
|
7542
7569
|
const m = s.match(/^[ \t]*(?=\S)/gm);
|
|
7543
7570
|
const i = Math.min(...(m || []).map((x) => x.length));
|
|
@@ -7551,7 +7578,9 @@ async function processRipScripts() {
|
|
|
7551
7578
|
try {
|
|
7552
7579
|
const ripCode = dedent(script.textContent);
|
|
7553
7580
|
const jsCode = compileToJS(ripCode);
|
|
7554
|
-
(0, eval)(
|
|
7581
|
+
await (0, eval)(`(async()=>{
|
|
7582
|
+
${jsCode}
|
|
7583
|
+
})()`);
|
|
7555
7584
|
script.setAttribute("data-rip-processed", "true");
|
|
7556
7585
|
} catch (error) {
|
|
7557
7586
|
console.error("Error compiling Rip script:", error);
|
|
@@ -7566,6 +7595,21 @@ if (typeof document !== "undefined") {
|
|
|
7566
7595
|
processRipScripts();
|
|
7567
7596
|
}
|
|
7568
7597
|
}
|
|
7598
|
+
async function importRip(url) {
|
|
7599
|
+
const source = await fetch(url).then((r) => {
|
|
7600
|
+
if (!r.ok)
|
|
7601
|
+
throw new Error(`importRip: ${url} (${r.status})`);
|
|
7602
|
+
return r.text();
|
|
7603
|
+
});
|
|
7604
|
+
const js = compileToJS(source);
|
|
7605
|
+
const blob = new Blob([js], { type: "application/javascript" });
|
|
7606
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
7607
|
+
try {
|
|
7608
|
+
return await import(blobUrl);
|
|
7609
|
+
} finally {
|
|
7610
|
+
URL.revokeObjectURL(blobUrl);
|
|
7611
|
+
}
|
|
7612
|
+
}
|
|
7569
7613
|
function rip(code) {
|
|
7570
7614
|
try {
|
|
7571
7615
|
const js = compileToJS(code);
|
|
@@ -7582,11 +7626,14 @@ function rip(code) {
|
|
|
7582
7626
|
}
|
|
7583
7627
|
if (typeof globalThis !== "undefined") {
|
|
7584
7628
|
globalThis.rip = rip;
|
|
7629
|
+
globalThis.importRip = importRip;
|
|
7630
|
+
globalThis.compileToJS = compileToJS;
|
|
7585
7631
|
}
|
|
7586
7632
|
export {
|
|
7587
7633
|
rip,
|
|
7588
7634
|
processRipScripts,
|
|
7589
7635
|
parser,
|
|
7636
|
+
importRip,
|
|
7590
7637
|
getReactiveRuntime,
|
|
7591
7638
|
getComponentRuntime,
|
|
7592
7639
|
formatSExpr,
|