rip-lang 3.13.25 → 3.13.27
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 +15 -15
- package/docs/RIP-INTERNALS.md +1 -1
- package/docs/RIP-LANG.md +2 -2
- package/package.json +1 -1
- package/src/compiler.js +2 -2
- package/src/components.js +91 -13
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.27-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%2C300%2F1%2C300-brightgreen.svg" alt="Tests"></a>
|
|
15
15
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
|
|
@@ -354,7 +354,7 @@ The UI framework is built into rip-lang: file-based router, reactive stash, comp
|
|
|
354
354
|
| **Self-hosting** | No | Yes |
|
|
355
355
|
| **Lexer** | 3,558 LOC | 2,024 LOC |
|
|
356
356
|
| **Compiler** | 10,346 LOC | 3,293 LOC |
|
|
357
|
-
| **Total** | 17,760 LOC | ~11,
|
|
357
|
+
| **Total** | 17,760 LOC | ~11,890 LOC |
|
|
358
358
|
|
|
359
359
|
Smaller codebase, modern output, built-in reactivity.
|
|
360
360
|
|
|
@@ -389,25 +389,25 @@ await rip("res = fetch! 'https://api.example.com/todos/1'; res.json!") // → {
|
|
|
389
389
|
|
|
390
390
|
```
|
|
391
391
|
Source -> Lexer -> emitTypes -> Parser -> S-Expressions -> Codegen -> JavaScript
|
|
392
|
-
(1,
|
|
392
|
+
(1,778) (types.js) (359) ["=", "x", 42] (3,334) + source map
|
|
393
393
|
```
|
|
394
394
|
|
|
395
395
|
Simple arrays (with `.loc`) instead of AST node classes. The compiler is self-hosting — `bun run parser` rebuilds from source.
|
|
396
396
|
|
|
397
397
|
| Component | File | Lines |
|
|
398
398
|
|-----------|------|-------|
|
|
399
|
-
| Lexer + Rewriter | `src/lexer.js` | 1,
|
|
400
|
-
| Compiler + Codegen | `src/compiler.js` | 3,
|
|
401
|
-
| Type System | `src/types.js` | 1,
|
|
402
|
-
| Component System | `src/components.js` |
|
|
399
|
+
| Lexer + Rewriter | `src/lexer.js` | 1,778 |
|
|
400
|
+
| Compiler + Codegen | `src/compiler.js` | 3,334 |
|
|
401
|
+
| Type System | `src/types.js` | 1,091 |
|
|
402
|
+
| Component System | `src/components.js` | 2,026 |
|
|
403
403
|
| Source Maps | `src/sourcemaps.js` | 189 |
|
|
404
|
-
|
|
|
405
|
-
|
|
|
404
|
+
| Type Checking | `src/typecheck.js` | 442 |
|
|
405
|
+
| Parser (generated) | `src/parser.js` | 359 |
|
|
406
|
+
| Grammar | `src/grammar/grammar.rip` | 948 |
|
|
406
407
|
| Parser Generator | `src/grammar/solar.rip` | 929 |
|
|
407
|
-
| REPL | `src/repl.js` |
|
|
408
|
-
| Browser Entry | `src/browser.js` |
|
|
409
|
-
|
|
|
410
|
-
| **Total** | | **~11,289** |
|
|
408
|
+
| REPL | `src/repl.js` | 600 |
|
|
409
|
+
| Browser Entry | `src/browser.js` | 194 |
|
|
410
|
+
| **Total** | | **~11,890** |
|
|
411
411
|
|
|
412
412
|
---
|
|
413
413
|
|
|
@@ -417,7 +417,7 @@ 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.13.
|
|
420
|
+
| [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.13.26 | Core language compiler |
|
|
421
421
|
| [@rip-lang/server](packages/server/) | 1.2.11 | Multi-worker app server (web framework, hot reload, HTTPS, mDNS) |
|
|
422
422
|
| [@rip-lang/db](packages/db/) | 1.3.13 | DuckDB server with official UI + ActiveRecord-style client |
|
|
423
423
|
| [@rip-lang/grid](packages/grid/) | 0.2.8 | Reactive data grid |
|
|
@@ -462,7 +462,7 @@ rip file.rip # Run
|
|
|
462
462
|
rip -c file.rip # Compile
|
|
463
463
|
rip -t file.rip # Tokens
|
|
464
464
|
rip -s file.rip # S-expressions
|
|
465
|
-
bun run test #
|
|
465
|
+
bun run test # 1369 tests
|
|
466
466
|
bun run parser # Rebuild parser
|
|
467
467
|
bun run build # Build browser bundle
|
|
468
468
|
```
|
package/docs/RIP-INTERNALS.md
CHANGED
package/docs/RIP-LANG.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Rip Language Reference
|
|
4
4
|
|
|
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, ~
|
|
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, ~11,890 LOC.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -1829,4 +1829,4 @@ Each would need design discussion before building.
|
|
|
1829
1829
|
|
|
1830
1830
|
---
|
|
1831
1831
|
|
|
1832
|
-
*Rip 3.13 — 1,
|
|
1832
|
+
*Rip 3.13 — 1,369 tests — Zero dependencies — Self-hosting — ~11,890 LOC*
|
package/package.json
CHANGED
package/src/compiler.js
CHANGED
|
@@ -688,9 +688,9 @@ export class CodeGenerator {
|
|
|
688
688
|
|
|
689
689
|
if (this.usesTemplates && !skip) {
|
|
690
690
|
if (skipRT) {
|
|
691
|
-
code += 'var { __pushComponent, __popComponent, setContext, getContext, hasContext, __clsx, __lis, __reconcile, __Component } = globalThis.__ripComponent;\n';
|
|
691
|
+
code += 'var { __pushComponent, __popComponent, setContext, getContext, hasContext, __clsx, __lis, __reconcile, __transition, __handleComponentError, __Component } = globalThis.__ripComponent;\n';
|
|
692
692
|
} else if (typeof globalThis !== 'undefined' && globalThis.__ripComponent) {
|
|
693
|
-
code += 'const { __pushComponent, __popComponent, setContext, getContext, hasContext, __clsx, __lis, __reconcile, __Component } = globalThis.__ripComponent;\n';
|
|
693
|
+
code += 'const { __pushComponent, __popComponent, setContext, getContext, hasContext, __clsx, __lis, __reconcile, __transition, __handleComponentError, __Component } = globalThis.__ripComponent;\n';
|
|
694
694
|
} else {
|
|
695
695
|
code += this.getComponentRuntime();
|
|
696
696
|
}
|
package/src/components.js
CHANGED
|
@@ -55,7 +55,7 @@ const TEMPLATE_TAGS = new Set([...HTML_TAGS, ...SVG_TAGS]);
|
|
|
55
55
|
const BIND_PREFIX = '__bind_';
|
|
56
56
|
const BIND_SUFFIX = '__';
|
|
57
57
|
|
|
58
|
-
const LIFECYCLE_HOOKS = new Set(['beforeMount', 'mounted', 'updated', 'beforeUnmount', 'unmounted']);
|
|
58
|
+
const LIFECYCLE_HOOKS = new Set(['beforeMount', 'mounted', 'updated', 'beforeUnmount', 'unmounted', 'onError']);
|
|
59
59
|
const BOOLEAN_ATTRS = new Set([
|
|
60
60
|
'disabled', 'hidden', 'readonly', 'required', 'checked', 'selected',
|
|
61
61
|
'autofocus', 'autoplay', 'controls', 'loop', 'muted', 'multiple',
|
|
@@ -240,6 +240,19 @@ export function installComponentSupport(CodeGenerator, Lexer) {
|
|
|
240
240
|
// Only process if we're inside a render block
|
|
241
241
|
if (!inRender) return 1;
|
|
242
242
|
|
|
243
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
244
|
+
// Transition modifier
|
|
245
|
+
// div ~fade → div __transition__: "fade"
|
|
246
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
247
|
+
if (tag === 'UNARY_MATH' && token[1] === '~' && nextToken && nextToken[0] === 'IDENTIFIER') {
|
|
248
|
+
token[0] = 'PROPERTY';
|
|
249
|
+
token[1] = '__transition__';
|
|
250
|
+
let colonToken = gen(':', ':', token);
|
|
251
|
+
let valueToken = gen('STRING', `"${nextToken[1]}"`, nextToken);
|
|
252
|
+
tokens.splice(i + 1, 1, colonToken, valueToken);
|
|
253
|
+
return 1;
|
|
254
|
+
}
|
|
255
|
+
|
|
243
256
|
// ─────────────────────────────────────────────────────────────────────
|
|
244
257
|
// Hyphenated attributes
|
|
245
258
|
// data-lucide: "search" → "data-lucide": "search"
|
|
@@ -719,11 +732,12 @@ export function installComponentSupport(CodeGenerator, Lexer) {
|
|
|
719
732
|
// --- Lifecycle hooks ---
|
|
720
733
|
for (const { name, value } of lifecycleHooks) {
|
|
721
734
|
if (Array.isArray(value) && (value[0] === '->' || value[0] === '=>')) {
|
|
722
|
-
const [, , hookBody] = value;
|
|
735
|
+
const [, params, hookBody] = value;
|
|
736
|
+
const paramStr = Array.isArray(params) ? params.map(p => this.formatParam(p)).join(', ') : '';
|
|
723
737
|
const transformed = this.reactiveMembers ? this.transformComponentMembers(hookBody) : hookBody;
|
|
724
738
|
const isAsync = this.containsAwait(hookBody);
|
|
725
|
-
const bodyCode = this.generateFunctionBody(transformed, []);
|
|
726
|
-
lines.push(` ${isAsync ? 'async ' : ''}${name}() ${bodyCode}`);
|
|
739
|
+
const bodyCode = this.generateFunctionBody(transformed, params || []);
|
|
740
|
+
lines.push(` ${isAsync ? 'async ' : ''}${name}(${paramStr}) ${bodyCode}`);
|
|
727
741
|
}
|
|
728
742
|
}
|
|
729
743
|
|
|
@@ -1188,6 +1202,13 @@ export function installComponentSupport(CodeGenerator, Lexer) {
|
|
|
1188
1202
|
continue;
|
|
1189
1203
|
}
|
|
1190
1204
|
|
|
1205
|
+
// Transition: __transition__: "fade" → this._t = "fade" (on block, not DOM)
|
|
1206
|
+
if (key === '__transition__') {
|
|
1207
|
+
const transName = String(value).replace(/^["']|["']$/g, '');
|
|
1208
|
+
this._createLines.push(`this._t = "${transName}";`);
|
|
1209
|
+
continue;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1191
1212
|
// Element ref: ref: "name" → this.name = element
|
|
1192
1213
|
if (key === 'ref') {
|
|
1193
1214
|
const refName = String(value).replace(/^["']|["']$/g, '');
|
|
@@ -1330,7 +1351,9 @@ export function installComponentSupport(CodeGenerator, Lexer) {
|
|
|
1330
1351
|
setupLines.push(` if (want === showing) return;`);
|
|
1331
1352
|
setupLines.push(``);
|
|
1332
1353
|
setupLines.push(` if (currentBlock) {`);
|
|
1333
|
-
setupLines.push(` currentBlock
|
|
1354
|
+
setupLines.push(` const leaving = currentBlock;`);
|
|
1355
|
+
setupLines.push(` if (leaving._t) { __transition(leaving._first, leaving._t, 'leave', () => leaving.d(true)); }`);
|
|
1356
|
+
setupLines.push(` else { leaving.d(true); }`);
|
|
1334
1357
|
setupLines.push(` currentBlock = null;`);
|
|
1335
1358
|
setupLines.push(` }`);
|
|
1336
1359
|
setupLines.push(` showing = want;`);
|
|
@@ -1340,6 +1363,7 @@ export function installComponentSupport(CodeGenerator, Lexer) {
|
|
|
1340
1363
|
setupLines.push(` currentBlock.c();`);
|
|
1341
1364
|
setupLines.push(` if (anchor.parentNode) currentBlock.m(anchor.parentNode, anchor.nextSibling);`);
|
|
1342
1365
|
setupLines.push(` currentBlock.p(${this._self}${outerExtra});`);
|
|
1366
|
+
setupLines.push(` if (currentBlock._t) __transition(currentBlock._first, currentBlock._t, 'enter');`);
|
|
1343
1367
|
setupLines.push(` }`);
|
|
1344
1368
|
if (elseBlock) {
|
|
1345
1369
|
setupLines.push(` if (want === 'else') {`);
|
|
@@ -1347,6 +1371,7 @@ export function installComponentSupport(CodeGenerator, Lexer) {
|
|
|
1347
1371
|
setupLines.push(` currentBlock.c();`);
|
|
1348
1372
|
setupLines.push(` if (anchor.parentNode) currentBlock.m(anchor.parentNode, anchor.nextSibling);`);
|
|
1349
1373
|
setupLines.push(` currentBlock.p(${this._self}${outerExtra});`);
|
|
1374
|
+
setupLines.push(` if (currentBlock._t) __transition(currentBlock._first, currentBlock._t, 'enter');`);
|
|
1350
1375
|
setupLines.push(` }`);
|
|
1351
1376
|
}
|
|
1352
1377
|
setupLines.push(` ${effClose}`);
|
|
@@ -1553,8 +1578,7 @@ export function installComponentSupport(CodeGenerator, Lexer) {
|
|
|
1553
1578
|
this._createLines.push(`${elVar} = ${instVar}._create();`);
|
|
1554
1579
|
this._createLines.push(`(${s}._children || (${s}._children = [])).push(${instVar});`);
|
|
1555
1580
|
|
|
1556
|
-
this._setupLines.push(`if (${instVar}._setup) ${instVar}._setup()
|
|
1557
|
-
this._setupLines.push(`if (${instVar}.mounted) ${instVar}.mounted();`);
|
|
1581
|
+
this._setupLines.push(`try { if (${instVar}._setup) ${instVar}._setup(); if (${instVar}.mounted) ${instVar}.mounted(); } catch (__e) { __handleComponentError(__e, ${instVar}); }`);
|
|
1558
1582
|
|
|
1559
1583
|
for (const { key, valueCode } of reactiveProps) {
|
|
1560
1584
|
this._pushEffect(`if (${instVar}.${key}) ${instVar}.${key}.value = ${valueCode};`);
|
|
@@ -1904,21 +1928,75 @@ function __reconcile(anchor, state, items, ctx, factory, keyFn, ...outer) {
|
|
|
1904
1928
|
state.blocks = newBlocks;
|
|
1905
1929
|
}
|
|
1906
1930
|
|
|
1931
|
+
let __cssInjected = false;
|
|
1932
|
+
function __transitionCSS() {
|
|
1933
|
+
if (__cssInjected) return;
|
|
1934
|
+
__cssInjected = true;
|
|
1935
|
+
const s = document.createElement('style');
|
|
1936
|
+
s.textContent = [
|
|
1937
|
+
'.fade-enter-active,.fade-leave-active{transition:opacity .2s ease}',
|
|
1938
|
+
'.fade-enter-from,.fade-leave-to{opacity:0}',
|
|
1939
|
+
'.slide-enter-active,.slide-leave-active{transition:opacity .2s ease,transform .2s ease}',
|
|
1940
|
+
'.slide-enter-from{opacity:0;transform:translateY(-8px)}',
|
|
1941
|
+
'.slide-leave-to{opacity:0;transform:translateY(8px)}',
|
|
1942
|
+
'.scale-enter-active,.scale-leave-active{transition:opacity .2s ease,transform .2s ease}',
|
|
1943
|
+
'.scale-enter-from,.scale-leave-to{opacity:0;transform:scale(.95)}',
|
|
1944
|
+
'.blur-enter-active,.blur-leave-active{transition:opacity .2s ease,filter .2s ease}',
|
|
1945
|
+
'.blur-enter-from,.blur-leave-to{opacity:0;filter:blur(4px)}',
|
|
1946
|
+
'.fly-enter-active,.fly-leave-active{transition:opacity .2s ease,transform .2s ease}',
|
|
1947
|
+
'.fly-enter-from{opacity:0;transform:translateY(-20px)}',
|
|
1948
|
+
'.fly-leave-to{opacity:0;transform:translateY(20px)}',
|
|
1949
|
+
].join('');
|
|
1950
|
+
document.head.appendChild(s);
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
function __transition(el, name, dir, done) {
|
|
1954
|
+
__transitionCSS();
|
|
1955
|
+
const cl = el.classList;
|
|
1956
|
+
const from = name + '-' + dir + '-from';
|
|
1957
|
+
const active = name + '-' + dir + '-active';
|
|
1958
|
+
const to = name + '-' + dir + '-to';
|
|
1959
|
+
cl.add(from, active);
|
|
1960
|
+
requestAnimationFrame(() => {
|
|
1961
|
+
requestAnimationFrame(() => {
|
|
1962
|
+
cl.remove(from);
|
|
1963
|
+
cl.add(to);
|
|
1964
|
+
const end = () => { cl.remove(active, to); if (done) done(); };
|
|
1965
|
+
el.addEventListener('transitionend', end, { once: true });
|
|
1966
|
+
});
|
|
1967
|
+
});
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
function __handleComponentError(error, component) {
|
|
1971
|
+
let current = component;
|
|
1972
|
+
while (current) {
|
|
1973
|
+
if (current.onError) {
|
|
1974
|
+
try { current.onError(error, component); return; } catch (_) {}
|
|
1975
|
+
}
|
|
1976
|
+
current = current._parent;
|
|
1977
|
+
}
|
|
1978
|
+
throw error;
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1907
1981
|
class __Component {
|
|
1908
1982
|
constructor(props = {}) {
|
|
1909
1983
|
Object.assign(this, props);
|
|
1910
1984
|
const prev = __pushComponent(this);
|
|
1911
|
-
this._init(props);
|
|
1985
|
+
try { this._init(props); } catch (e) { __popComponent(prev); __handleComponentError(e, this); return; }
|
|
1912
1986
|
__popComponent(prev);
|
|
1913
1987
|
}
|
|
1914
1988
|
_init() {}
|
|
1915
1989
|
mount(target) {
|
|
1916
1990
|
if (typeof target === "string") target = document.querySelector(target);
|
|
1917
1991
|
this._target = target;
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1992
|
+
try {
|
|
1993
|
+
this._root = this._create();
|
|
1994
|
+
target.appendChild(this._root);
|
|
1995
|
+
if (this._setup) this._setup();
|
|
1996
|
+
if (this.mounted) this.mounted();
|
|
1997
|
+
} catch (error) {
|
|
1998
|
+
__handleComponentError(error, this);
|
|
1999
|
+
}
|
|
1922
2000
|
return this;
|
|
1923
2001
|
}
|
|
1924
2002
|
unmount() {
|
|
@@ -1939,7 +2017,7 @@ class __Component {
|
|
|
1939
2017
|
|
|
1940
2018
|
// Register on globalThis for runtime deduplication
|
|
1941
2019
|
if (typeof globalThis !== 'undefined') {
|
|
1942
|
-
globalThis.__ripComponent = { __pushComponent, __popComponent, setContext, getContext, hasContext, __clsx, __lis, __reconcile, __Component };
|
|
2020
|
+
globalThis.__ripComponent = { __pushComponent, __popComponent, setContext, getContext, hasContext, __clsx, __lis, __reconcile, __transition, __handleComponentError, __Component };
|
|
1943
2021
|
}
|
|
1944
2022
|
|
|
1945
2023
|
`;
|