rip-lang 3.7.0 → 3.7.4
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 +25 -0
- package/README.md +5 -5
- package/docs/RIP-LANG.md +8 -1
- package/docs/dist/rip.browser.js +126 -74
- package/docs/dist/rip.browser.min.js +147 -125
- package/docs/dist/rip.browser.min.js.br +0 -0
- package/docs/index.html +1 -1
- package/package.json +1 -1
- package/src/browser.js +19 -13
- package/src/compiler.js +19 -7
- package/src/components.js +55 -47
- package/src/lexer.js +56 -19
- package/src/types.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,31 @@ 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.7.4] - 2026-02-11
|
|
11
|
+
|
|
12
|
+
### Compiler — Nested Function Scope Chain
|
|
13
|
+
|
|
14
|
+
- **Scope stack for variable hoisting** — Nested functions no longer re-declare variables from enclosing function scopes. Previously, the compiler only checked program-level variables; now it tracks a full scope chain. Fixes incorrect `let` shadowing in deeply nested function patterns (e.g., `mountRoute` inside `createRenderer` in `ui.rip`).
|
|
15
|
+
|
|
16
|
+
### Rip UI — Demo App Working
|
|
17
|
+
|
|
18
|
+
- **Router `navigating` getter/setter** — The `_navigating` signal is now accessible through `router.navigating` (read/write), fixing a cross-scope reference where `createRenderer` accessed a variable local to `createRouter`.
|
|
19
|
+
- **Component props passthrough** — `__Component` base class now assigns all props to `this` via `Object.assign(this, props)` before `_init`, so components can access `@router`, `@app`, `@params` etc.
|
|
20
|
+
|
|
21
|
+
### Language — `*@` Merge-This
|
|
22
|
+
|
|
23
|
+
- **`*@ = props`** — New merge-assign variant for `this`. Compiles to `Object.assign(this, props)`. Natural extension of `*obj = expr` — no `??=` guard needed since `this` is never null.
|
|
24
|
+
|
|
25
|
+
## [3.7.3] - 2026-02-11
|
|
26
|
+
|
|
27
|
+
### Fixes & Polish
|
|
28
|
+
|
|
29
|
+
- **Interface `::` fix** — `::` type annotations in interface bodies no longer produce double colons in `.d.ts` output.
|
|
30
|
+
- **`.=` dot chain support** — `obj.name .= toUpperCase()` now works (walks back full property chain).
|
|
31
|
+
- **`*` merge auto-init** — `*foo = {...}` auto-creates `foo` if undefined via `??= {}`.
|
|
32
|
+
- **`loop n` uses `it`** — Loop counter is accessible as `it` inside the body.
|
|
33
|
+
- **Syntax highlighting** — `|>` pipe operator added to VS Code, Vim, Playground, and rip-print.
|
|
34
|
+
|
|
10
35
|
## [3.7.0] - 2026-02-11
|
|
11
36
|
|
|
12
37
|
### Pipe Operator (`|>`)
|
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.7.
|
|
12
|
+
<a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.7.4-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-
|
|
14
|
+
<a href="#"><img src="https://img.shields.io/badge/tests-1225%2F1225-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
|
|
|
@@ -267,7 +267,7 @@ Counter = component
|
|
|
267
267
|
|
|
268
268
|
Two keywords — `component` and `render` — are all the language adds. Everything else (`:=` state, `~=` computed, methods, lifecycle) is standard Rip.
|
|
269
269
|
|
|
270
|
-
See [@rip-lang/ui](packages/ui/) for the full framework: file-based router, reactive stash,
|
|
270
|
+
See [@rip-lang/ui](packages/ui/) for the full framework: file-based router, reactive stash, component store, and renderer.
|
|
271
271
|
|
|
272
272
|
---
|
|
273
273
|
|
|
@@ -344,7 +344,7 @@ Rip includes optional packages for full-stack development:
|
|
|
344
344
|
|
|
345
345
|
| Package | Version | Purpose |
|
|
346
346
|
|---------|---------|---------|
|
|
347
|
-
| [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.7.
|
|
347
|
+
| [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.7.4 | Core language compiler |
|
|
348
348
|
| [@rip-lang/api](packages/api/) | 1.1.4 | HTTP framework (Sinatra-style routing, 37 validators) |
|
|
349
349
|
| [@rip-lang/server](packages/server/) | 1.1.3 | Multi-worker app server (hot reload, HTTPS, mDNS) |
|
|
350
350
|
| [@rip-lang/db](packages/db/) | 1.1.2 | DuckDB server with official UI (pure Bun FFI) |
|
|
@@ -390,7 +390,7 @@ rip file.rip # Run
|
|
|
390
390
|
rip -c file.rip # Compile
|
|
391
391
|
rip -t file.rip # Tokens
|
|
392
392
|
rip -s file.rip # S-expressions
|
|
393
|
-
bun run test #
|
|
393
|
+
bun run test # 1225 tests
|
|
394
394
|
bun run parser # Rebuild parser
|
|
395
395
|
bun run browser # Build browser bundle
|
|
396
396
|
```
|
package/docs/RIP-LANG.md
CHANGED
|
@@ -412,7 +412,14 @@ users .= map -> it.name
|
|
|
412
412
|
users .= sort()
|
|
413
413
|
```
|
|
414
414
|
|
|
415
|
-
Works with any method — built-in or custom, with or without arguments.
|
|
415
|
+
Works with any method — built-in or custom, with or without arguments. Spacing
|
|
416
|
+
is flexible — all of these are equivalent:
|
|
417
|
+
|
|
418
|
+
```coffee
|
|
419
|
+
str .= trim() # canonical (spaced)
|
|
420
|
+
str.=trim() # compact (no spaces)
|
|
421
|
+
str .=trim() # mixed
|
|
422
|
+
```
|
|
416
423
|
|
|
417
424
|
## Merge Assignment (`*`)
|
|
418
425
|
|
package/docs/dist/rip.browser.js
CHANGED
|
@@ -439,7 +439,7 @@ function collectStructuralType(tokens, indentIdx) {
|
|
|
439
439
|
optional = true;
|
|
440
440
|
j++;
|
|
441
441
|
}
|
|
442
|
-
if (tokens[j]?.[1] === ":")
|
|
442
|
+
if (tokens[j]?.[1] === ":" || tokens[j]?.[0] === "TYPE_ANNOTATION")
|
|
443
443
|
j++;
|
|
444
444
|
let propTypeTokens = [];
|
|
445
445
|
let typeDepth = 0;
|
|
@@ -1993,13 +1993,18 @@ class Lexer {
|
|
|
1993
1993
|
if (CODE_RE.test(val))
|
|
1994
1994
|
this.tagParameters();
|
|
1995
1995
|
if (val === "=" && prev && prev[1] === "." && !prev.spaced) {
|
|
1996
|
-
let
|
|
1997
|
-
|
|
1996
|
+
let tokens = this.tokens;
|
|
1997
|
+
let j = tokens.length - 2;
|
|
1998
|
+
while (j >= 1 && tokens[j][0] === "PROPERTY" && tokens[j - 1]?.[1] === ".")
|
|
1999
|
+
j -= 2;
|
|
2000
|
+
if (j >= 0 && (tokens[j][0] === "IDENTIFIER" || tokens[j][0] === ")" || tokens[j][0] === "]")) {
|
|
2001
|
+
let chainTokens = tokens.slice(j, tokens.length - 1);
|
|
1998
2002
|
prev[0] = "=";
|
|
1999
2003
|
prev[1] = "=";
|
|
2000
|
-
let
|
|
2001
|
-
|
|
2002
|
-
|
|
2004
|
+
for (let t of chainTokens) {
|
|
2005
|
+
this.tokens.push(tok(t[0], t[1], { pre: 0, row: t[2], col: t[3], len: t[4] }));
|
|
2006
|
+
}
|
|
2007
|
+
this.tokens.push(tok(".", ".", { pre: 0, row: this.row, col: this.col, len: 1 }));
|
|
2003
2008
|
return val.length;
|
|
2004
2009
|
}
|
|
2005
2010
|
}
|
|
@@ -2044,21 +2049,40 @@ class Lexer {
|
|
|
2044
2049
|
tag = "REACT_ASSIGN";
|
|
2045
2050
|
else if (val === "=!")
|
|
2046
2051
|
tag = "READONLY_ASSIGN";
|
|
2047
|
-
else if (val === "*" && (!prev || prev[0] === "TERMINATOR" || prev[0] === "INDENT" || prev[0] === "OUTDENT") && /^[a-zA-Z_$]/.test(this.chunk[1] || "")) {
|
|
2052
|
+
else if (val === "*" && (!prev || prev[0] === "TERMINATOR" || prev[0] === "INDENT" || prev[0] === "OUTDENT") && (/^[a-zA-Z_$]/.test(this.chunk[1] || "") || this.chunk[1] === "@")) {
|
|
2048
2053
|
let rest = this.chunk.slice(1);
|
|
2054
|
+
let mAt = /^@(\s*)=(?!=)/.exec(rest);
|
|
2055
|
+
if (mAt) {
|
|
2056
|
+
let space = mAt[1];
|
|
2057
|
+
this.emit("IDENTIFIER", "Object");
|
|
2058
|
+
this.emit(".", ".");
|
|
2059
|
+
let t = this.emit("PROPERTY", "assign");
|
|
2060
|
+
t.spaced = true;
|
|
2061
|
+
this.emit("@", "@");
|
|
2062
|
+
this.emit(",", ",");
|
|
2063
|
+
return 1 + 1 + space.length + 1;
|
|
2064
|
+
}
|
|
2049
2065
|
let m = /^((?:(?!\s)[$\w\x7f-\uffff])+(?:\.[a-zA-Z_$][\w]*)*)(\s*)=(?!=)/.exec(rest);
|
|
2050
2066
|
if (m) {
|
|
2051
2067
|
let target = m[1], space = m[2];
|
|
2068
|
+
let parts = target.split(".");
|
|
2069
|
+
let emitTarget = () => {
|
|
2070
|
+
this.emit("IDENTIFIER", parts[0]);
|
|
2071
|
+
for (let i = 1;i < parts.length; i++) {
|
|
2072
|
+
this.emit(".", ".");
|
|
2073
|
+
this.emit("PROPERTY", parts[i]);
|
|
2074
|
+
}
|
|
2075
|
+
};
|
|
2076
|
+
emitTarget();
|
|
2077
|
+
this.emit("=", "=");
|
|
2052
2078
|
this.emit("IDENTIFIER", "Object");
|
|
2053
2079
|
this.emit(".", ".");
|
|
2054
2080
|
this.emit("PROPERTY", "assign");
|
|
2055
2081
|
this.emit("CALL_START", "(");
|
|
2056
|
-
|
|
2057
|
-
this.emit("
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
this.emit("PROPERTY", parts[i]);
|
|
2061
|
-
}
|
|
2082
|
+
emitTarget();
|
|
2083
|
+
this.emit("COMPOUND_ASSIGN", "??=");
|
|
2084
|
+
this.emit("{", "{");
|
|
2085
|
+
this.emit("}", "}");
|
|
2062
2086
|
this.emit(",", ",");
|
|
2063
2087
|
let comma = this.prev();
|
|
2064
2088
|
comma.mergeClose = true;
|
|
@@ -2353,7 +2377,7 @@ class Lexer {
|
|
|
2353
2377
|
let prevToken = i > 0 ? tokens[i - 1] : null;
|
|
2354
2378
|
let prevTag = prevToken ? prevToken[0] : null;
|
|
2355
2379
|
let atLineStart = prevTag === "INDENT" || prevTag === "TERMINATOR";
|
|
2356
|
-
let cxToken = gen("PROPERTY", "
|
|
2380
|
+
let cxToken = gen("PROPERTY", "__clsx", token);
|
|
2357
2381
|
nextToken[0] = "CALL_START";
|
|
2358
2382
|
let depth = 1;
|
|
2359
2383
|
for (let j = i + 2;j < tokens.length && depth > 0; j++) {
|
|
@@ -2403,6 +2427,10 @@ class Lexer {
|
|
|
2403
2427
|
return 3;
|
|
2404
2428
|
}
|
|
2405
2429
|
}
|
|
2430
|
+
if (tag === "IDENTIFIER" && isComponent(token[1]) && nextToken && (nextToken[0] === "OUTDENT" || nextToken[0] === "TERMINATOR")) {
|
|
2431
|
+
tokens.splice(i + 1, 0, gen("CALL_START", "(", token), gen("CALL_END", ")", token));
|
|
2432
|
+
return 3;
|
|
2433
|
+
}
|
|
2406
2434
|
return 1;
|
|
2407
2435
|
});
|
|
2408
2436
|
}
|
|
@@ -3566,6 +3594,9 @@ function installComponentSupport(CodeGenerator) {
|
|
|
3566
3594
|
if (typeof sexpr === "string" && this.reactiveMembers && this.reactiveMembers.has(sexpr)) {
|
|
3567
3595
|
return [".", [".", "this", sexpr], "value"];
|
|
3568
3596
|
}
|
|
3597
|
+
if (typeof sexpr === "string" && this.componentMembers && this.componentMembers.has(sexpr)) {
|
|
3598
|
+
return [".", "this", sexpr];
|
|
3599
|
+
}
|
|
3569
3600
|
return sexpr;
|
|
3570
3601
|
}
|
|
3571
3602
|
if (sexpr[0] === "." && sexpr[1] === "this" && typeof sexpr[2] === "string") {
|
|
@@ -3660,17 +3691,15 @@ function installComponentSupport(CodeGenerator) {
|
|
|
3660
3691
|
this.reactiveMembers = reactiveMembers;
|
|
3661
3692
|
const lines = [];
|
|
3662
3693
|
let blockFactoriesCode = "";
|
|
3663
|
-
lines.push("class {");
|
|
3664
|
-
lines.push("
|
|
3665
|
-
lines.push(" const __prevComponent = __pushComponent(this);");
|
|
3666
|
-
lines.push("");
|
|
3694
|
+
lines.push("class extends __Component {");
|
|
3695
|
+
lines.push(" _init(props) {");
|
|
3667
3696
|
for (const { name, value } of readonlyVars) {
|
|
3668
3697
|
const val = this.generateInComponent(value, "value");
|
|
3669
3698
|
lines.push(` this.${name} = props.${name} ?? ${val};`);
|
|
3670
3699
|
}
|
|
3671
3700
|
for (const { name, value } of stateVars) {
|
|
3672
3701
|
const val = this.generateInComponent(value, "value");
|
|
3673
|
-
lines.push(` this.${name} =
|
|
3702
|
+
lines.push(` this.${name} = __state(props.${name} ?? ${val});`);
|
|
3674
3703
|
}
|
|
3675
3704
|
for (const { name, expr } of derivedVars) {
|
|
3676
3705
|
const val = this.generateInComponent(expr, "value");
|
|
@@ -3681,8 +3710,6 @@ function installComponentSupport(CodeGenerator) {
|
|
|
3681
3710
|
const effectCode = this.generateInComponent(effectBody, "value");
|
|
3682
3711
|
lines.push(` __effect(${effectCode});`);
|
|
3683
3712
|
}
|
|
3684
|
-
lines.push("");
|
|
3685
|
-
lines.push(" __popComponent(__prevComponent);");
|
|
3686
3713
|
lines.push(" }");
|
|
3687
3714
|
for (const { name, func } of methods) {
|
|
3688
3715
|
if (Array.isArray(func) && (func[0] === "->" || func[0] === "=>")) {
|
|
@@ -3723,21 +3750,6 @@ function installComponentSupport(CodeGenerator) {
|
|
|
3723
3750
|
lines.push(" }");
|
|
3724
3751
|
}
|
|
3725
3752
|
}
|
|
3726
|
-
lines.push(" mount(target) {");
|
|
3727
|
-
lines.push(' if (typeof target === "string") target = document.querySelector(target);');
|
|
3728
|
-
lines.push(" this._target = target;");
|
|
3729
|
-
lines.push(" this._root = this._create();");
|
|
3730
|
-
lines.push(" target.appendChild(this._root);");
|
|
3731
|
-
lines.push(" if (this._setup) this._setup();");
|
|
3732
|
-
lines.push(" if (this.mounted) this.mounted();");
|
|
3733
|
-
lines.push(" return this;");
|
|
3734
|
-
lines.push(" }");
|
|
3735
|
-
lines.push(" unmount() {");
|
|
3736
|
-
lines.push(" if (this.unmounted) this.unmounted();");
|
|
3737
|
-
lines.push(" if (this._root && this._root.parentNode) {");
|
|
3738
|
-
lines.push(" this._root.parentNode.removeChild(this._root);");
|
|
3739
|
-
lines.push(" }");
|
|
3740
|
-
lines.push(" }");
|
|
3741
3753
|
lines.push("}");
|
|
3742
3754
|
this.componentMembers = prevComponentMembers;
|
|
3743
3755
|
this.reactiveMembers = prevReactiveMembers;
|
|
@@ -3754,6 +3766,9 @@ ${blockFactoriesCode}return ${lines.join(`
|
|
|
3754
3766
|
if (typeof sexpr === "string" && this.reactiveMembers && this.reactiveMembers.has(sexpr)) {
|
|
3755
3767
|
return `this.${sexpr}.value`;
|
|
3756
3768
|
}
|
|
3769
|
+
if (typeof sexpr === "string" && this.componentMembers && this.componentMembers.has(sexpr)) {
|
|
3770
|
+
return `this.${sexpr}`;
|
|
3771
|
+
}
|
|
3757
3772
|
if (Array.isArray(sexpr) && this.reactiveMembers) {
|
|
3758
3773
|
const transformed = this.transformComponentMembers(sexpr);
|
|
3759
3774
|
return this.generate(transformed, context);
|
|
@@ -3840,11 +3855,9 @@ ${blockFactoriesCode}return ${lines.join(`
|
|
|
3840
3855
|
this._setupLines.push(`__effect(() => { ${textVar3}.data = this.${prop}.value; });`);
|
|
3841
3856
|
return textVar3;
|
|
3842
3857
|
}
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
return slotVar;
|
|
3847
|
-
}
|
|
3858
|
+
const slotVar = this.newElementVar("slot");
|
|
3859
|
+
this._createLines.push(`${slotVar} = this.${prop} instanceof Node ? this.${prop} : (this.${prop} != null ? document.createTextNode(String(this.${prop})) : document.createComment(''));`);
|
|
3860
|
+
return slotVar;
|
|
3848
3861
|
}
|
|
3849
3862
|
const { tag, classes } = this.collectTemplateClasses(sexpr);
|
|
3850
3863
|
if (tag && this.isHtmlTag(tag)) {
|
|
@@ -3856,14 +3869,14 @@ ${blockFactoriesCode}return ${lines.join(`
|
|
|
3856
3869
|
return textVar2;
|
|
3857
3870
|
}
|
|
3858
3871
|
if (Array.isArray(head)) {
|
|
3859
|
-
if (Array.isArray(head[0]) && head[0][0] === "." && (head[0][2] === "
|
|
3872
|
+
if (Array.isArray(head[0]) && head[0][0] === "." && (head[0][2] === "__clsx" || head[0][2] instanceof String && head[0][2].valueOf() === "__clsx")) {
|
|
3860
3873
|
const tag2 = typeof head[0][1] === "string" ? head[0][1] : head[0][1].valueOf();
|
|
3861
3874
|
const classExprs = head.slice(1);
|
|
3862
3875
|
return this.generateDynamicTag(tag2, classExprs, rest);
|
|
3863
3876
|
}
|
|
3864
3877
|
const { tag, classes } = this.collectTemplateClasses(head);
|
|
3865
3878
|
if (tag && this.isHtmlTag(tag)) {
|
|
3866
|
-
if (classes.length === 1 && classes[0] === "
|
|
3879
|
+
if (classes.length === 1 && classes[0] === "__clsx") {
|
|
3867
3880
|
return this.generateDynamicTag(tag, rest, []);
|
|
3868
3881
|
}
|
|
3869
3882
|
return this.generateTag(tag, classes, rest);
|
|
@@ -3947,9 +3960,9 @@ ${blockFactoriesCode}return ${lines.join(`
|
|
|
3947
3960
|
const classArgs = classExprs.map((e) => this.generateInComponent(e, "value")).join(", ");
|
|
3948
3961
|
const hasReactive = classExprs.some((e) => this.hasReactiveDeps(e));
|
|
3949
3962
|
if (hasReactive) {
|
|
3950
|
-
this._setupLines.push(`__effect(() => { ${elVar}.className =
|
|
3963
|
+
this._setupLines.push(`__effect(() => { ${elVar}.className = __clsx(${classArgs}); });`);
|
|
3951
3964
|
} else {
|
|
3952
|
-
this._createLines.push(`${elVar}.className =
|
|
3965
|
+
this._createLines.push(`${elVar}.className = __clsx(${classArgs});`);
|
|
3953
3966
|
}
|
|
3954
3967
|
}
|
|
3955
3968
|
for (const arg of children) {
|
|
@@ -3993,8 +4006,12 @@ ${blockFactoriesCode}return ${lines.join(`
|
|
|
3993
4006
|
let [key, value] = objExpr[i];
|
|
3994
4007
|
if (this.is(key, ".") && key[1] === "this") {
|
|
3995
4008
|
const eventName = key[2];
|
|
3996
|
-
|
|
3997
|
-
|
|
4009
|
+
if (typeof value === "string" && this.componentMembers?.has(value)) {
|
|
4010
|
+
this._createLines.push(`${elVar}.addEventListener('${eventName}', (e) => this.${value}(e));`);
|
|
4011
|
+
} else {
|
|
4012
|
+
const handlerCode = this.generateInComponent(value, "value");
|
|
4013
|
+
this._createLines.push(`${elVar}.addEventListener('${eventName}', (e) => (${handlerCode})(e));`);
|
|
4014
|
+
}
|
|
3998
4015
|
continue;
|
|
3999
4016
|
}
|
|
4000
4017
|
if (typeof key === "string") {
|
|
@@ -4350,10 +4367,6 @@ ${blockFactoriesCode}return ${lines.join(`
|
|
|
4350
4367
|
// Rip Component Runtime
|
|
4351
4368
|
// ============================================================================
|
|
4352
4369
|
|
|
4353
|
-
function isSignal(v) {
|
|
4354
|
-
return v != null && typeof v === 'object' && typeof v.read === 'function';
|
|
4355
|
-
}
|
|
4356
|
-
|
|
4357
4370
|
let __currentComponent = null;
|
|
4358
4371
|
|
|
4359
4372
|
function __pushComponent(component) {
|
|
@@ -4391,13 +4404,38 @@ function hasContext(key) {
|
|
|
4391
4404
|
return false;
|
|
4392
4405
|
}
|
|
4393
4406
|
|
|
4394
|
-
function
|
|
4407
|
+
function __clsx(...args) {
|
|
4395
4408
|
return args.filter(Boolean).join(' ');
|
|
4396
4409
|
}
|
|
4397
4410
|
|
|
4411
|
+
class __Component {
|
|
4412
|
+
constructor(props = {}) {
|
|
4413
|
+
Object.assign(this, props);
|
|
4414
|
+
const prev = __pushComponent(this);
|
|
4415
|
+
this._init(props);
|
|
4416
|
+
__popComponent(prev);
|
|
4417
|
+
}
|
|
4418
|
+
_init() {}
|
|
4419
|
+
mount(target) {
|
|
4420
|
+
if (typeof target === "string") target = document.querySelector(target);
|
|
4421
|
+
this._target = target;
|
|
4422
|
+
this._root = this._create();
|
|
4423
|
+
target.appendChild(this._root);
|
|
4424
|
+
if (this._setup) this._setup();
|
|
4425
|
+
if (this.mounted) this.mounted();
|
|
4426
|
+
return this;
|
|
4427
|
+
}
|
|
4428
|
+
unmount() {
|
|
4429
|
+
if (this.unmounted) this.unmounted();
|
|
4430
|
+
if (this._root && this._root.parentNode) {
|
|
4431
|
+
this._root.parentNode.removeChild(this._root);
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
}
|
|
4435
|
+
|
|
4398
4436
|
// Register on globalThis for runtime deduplication
|
|
4399
4437
|
if (typeof globalThis !== 'undefined') {
|
|
4400
|
-
globalThis.__ripComponent = {
|
|
4438
|
+
globalThis.__ripComponent = { __pushComponent, __popComponent, setContext, getContext, hasContext, __clsx, __Component };
|
|
4401
4439
|
}
|
|
4402
4440
|
|
|
4403
4441
|
`;
|
|
@@ -4784,6 +4822,7 @@ class CodeGenerator {
|
|
|
4784
4822
|
this.programVars = new Set;
|
|
4785
4823
|
this.functionVars = new Map;
|
|
4786
4824
|
this.helpers = new Set;
|
|
4825
|
+
this.scopeStack = [];
|
|
4787
4826
|
this.collectProgramVariables(sexpr);
|
|
4788
4827
|
let code = this.generate(sexpr);
|
|
4789
4828
|
if (this.sourceMap)
|
|
@@ -5213,7 +5252,7 @@ class CodeGenerator {
|
|
|
5213
5252
|
}
|
|
5214
5253
|
if (this.usesTemplates && !skip) {
|
|
5215
5254
|
if (typeof globalThis !== "undefined" && globalThis.__ripComponent) {
|
|
5216
|
-
code += `const {
|
|
5255
|
+
code += `const { __pushComponent, __popComponent, setContext, getContext, hasContext, __clsx, __Component } = globalThis.__ripComponent;
|
|
5217
5256
|
`;
|
|
5218
5257
|
} else {
|
|
5219
5258
|
code += this.getComponentRuntime();
|
|
@@ -5638,7 +5677,7 @@ ${this.indent()}}`;
|
|
|
5638
5677
|
generateLoopN(head, rest) {
|
|
5639
5678
|
let [count, body] = rest;
|
|
5640
5679
|
let n = this.generate(count, "value");
|
|
5641
|
-
return `for (let
|
|
5680
|
+
return `for (let it = 0; it < ${n}; it++) ${this.generateLoopBody(body)}`;
|
|
5642
5681
|
}
|
|
5643
5682
|
generateAwait(head, rest) {
|
|
5644
5683
|
return `await ${this.generate(rest[0], "value")}`;
|
|
@@ -6686,9 +6725,10 @@ export default ${expr[1]}`;
|
|
|
6686
6725
|
if (Array.isArray(params))
|
|
6687
6726
|
params.forEach(extractPN);
|
|
6688
6727
|
let bodyVars = this.collectFunctionVariables(body);
|
|
6689
|
-
let newVars = new Set([...bodyVars].filter((v) => !this.programVars.has(v) && !this.reactiveVars?.has(v) && !paramNames.has(v)));
|
|
6728
|
+
let newVars = new Set([...bodyVars].filter((v) => !this.programVars.has(v) && !this.reactiveVars?.has(v) && !paramNames.has(v) && !this.scopeStack.some((s) => s.has(v))));
|
|
6690
6729
|
let noRetStmts = ["return", "throw", "break", "continue"];
|
|
6691
6730
|
let loopStmts = ["for-in", "for-of", "for-as", "while", "until", "loop"];
|
|
6731
|
+
this.scopeStack.push(new Set([...newVars, ...paramNames]));
|
|
6692
6732
|
if (this.is(body, "block")) {
|
|
6693
6733
|
let statements = this.unwrapBlock(body);
|
|
6694
6734
|
if (hasExpansionParams && this.expansionAfterParams?.length > 0) {
|
|
@@ -6788,17 +6828,22 @@ export default ${expr[1]}`;
|
|
|
6788
6828
|
}
|
|
6789
6829
|
this.indentLevel--;
|
|
6790
6830
|
code += this.indent() + "}";
|
|
6831
|
+
this.scopeStack.pop();
|
|
6791
6832
|
this.sideEffectOnly = prevSEO;
|
|
6792
6833
|
return code;
|
|
6793
6834
|
}
|
|
6794
6835
|
this.sideEffectOnly = prevSEO;
|
|
6836
|
+
let result;
|
|
6795
6837
|
if (isConstructor || this.hasExplicitControlFlow(body))
|
|
6796
|
-
|
|
6797
|
-
if (Array.isArray(body) && (noRetStmts.includes(body[0]) || loopStmts.includes(body[0])))
|
|
6798
|
-
|
|
6799
|
-
if (sideEffectOnly)
|
|
6800
|
-
|
|
6801
|
-
|
|
6838
|
+
result = `{ ${this.generate(body, "statement")}; }`;
|
|
6839
|
+
else if (Array.isArray(body) && (noRetStmts.includes(body[0]) || loopStmts.includes(body[0])))
|
|
6840
|
+
result = `{ ${this.generate(body, "statement")}; }`;
|
|
6841
|
+
else if (sideEffectOnly)
|
|
6842
|
+
result = `{ ${this.generate(body, "statement")}; return; }`;
|
|
6843
|
+
else
|
|
6844
|
+
result = `{ return ${this.generate(body, "value")}; }`;
|
|
6845
|
+
this.scopeStack.pop();
|
|
6846
|
+
return result;
|
|
6802
6847
|
}
|
|
6803
6848
|
generateFunctionBody(body, params = [], sideEffectOnly = false) {
|
|
6804
6849
|
return this.generateBodyWithReturns(body, params, { sideEffectOnly, hasExpansionParams: this.expansionAfterParams?.length > 0 });
|
|
@@ -7734,6 +7779,7 @@ const __primitiveCoercion = {
|
|
|
7734
7779
|
};
|
|
7735
7780
|
|
|
7736
7781
|
function __state(initialValue) {
|
|
7782
|
+
if (initialValue != null && typeof initialValue === 'object' && typeof initialValue.read === 'function') return initialValue;
|
|
7737
7783
|
let value = initialValue;
|
|
7738
7784
|
const subscribers = new Set();
|
|
7739
7785
|
let notifying = false;
|
|
@@ -8028,8 +8074,8 @@ function getComponentRuntime() {
|
|
|
8028
8074
|
return new CodeGenerator({}).getComponentRuntime();
|
|
8029
8075
|
}
|
|
8030
8076
|
// src/browser.js
|
|
8031
|
-
var VERSION = "3.7.
|
|
8032
|
-
var BUILD_DATE = "2026-02-11@
|
|
8077
|
+
var VERSION = "3.7.4";
|
|
8078
|
+
var BUILD_DATE = "2026-02-11@13:07:41GMT";
|
|
8033
8079
|
if (typeof globalThis !== "undefined" && !globalThis.__rip) {
|
|
8034
8080
|
new Function(getReactiveRuntime())();
|
|
8035
8081
|
}
|
|
@@ -8045,24 +8091,23 @@ async function processRipScripts() {
|
|
|
8045
8091
|
continue;
|
|
8046
8092
|
try {
|
|
8047
8093
|
const ripCode = dedent(script.textContent);
|
|
8048
|
-
|
|
8094
|
+
let jsCode;
|
|
8095
|
+
try {
|
|
8096
|
+
jsCode = compileToJS(ripCode);
|
|
8097
|
+
} catch (compileError) {
|
|
8098
|
+
console.error("Rip compile error:", compileError.message);
|
|
8099
|
+
console.error("Source:", ripCode);
|
|
8100
|
+
continue;
|
|
8101
|
+
}
|
|
8049
8102
|
await (0, eval)(`(async()=>{
|
|
8050
8103
|
${jsCode}
|
|
8051
8104
|
})()`);
|
|
8052
8105
|
script.setAttribute("data-rip-processed", "true");
|
|
8053
8106
|
} catch (error) {
|
|
8054
|
-
console.error("
|
|
8055
|
-
console.error("Script content:", script.textContent);
|
|
8107
|
+
console.error("Rip runtime error:", error);
|
|
8056
8108
|
}
|
|
8057
8109
|
}
|
|
8058
8110
|
}
|
|
8059
|
-
if (typeof document !== "undefined") {
|
|
8060
|
-
if (document.readyState === "loading") {
|
|
8061
|
-
document.addEventListener("DOMContentLoaded", processRipScripts);
|
|
8062
|
-
} else {
|
|
8063
|
-
processRipScripts();
|
|
8064
|
-
}
|
|
8065
|
-
}
|
|
8066
8111
|
async function importRip(url) {
|
|
8067
8112
|
const source = await fetch(url).then((r) => {
|
|
8068
8113
|
if (!r.ok)
|
|
@@ -8106,6 +8151,13 @@ if (typeof globalThis !== "undefined") {
|
|
|
8106
8151
|
globalThis.importRip = importRip;
|
|
8107
8152
|
globalThis.compileToJS = compileToJS;
|
|
8108
8153
|
}
|
|
8154
|
+
if (typeof document !== "undefined") {
|
|
8155
|
+
if (document.readyState === "loading") {
|
|
8156
|
+
document.addEventListener("DOMContentLoaded", processRipScripts);
|
|
8157
|
+
} else {
|
|
8158
|
+
processRipScripts();
|
|
8159
|
+
}
|
|
8160
|
+
}
|
|
8109
8161
|
export {
|
|
8110
8162
|
rip,
|
|
8111
8163
|
processRipScripts,
|