rip-lang 3.13.62 → 3.13.64

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 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.62-blue.svg" alt="Version"></a>
12
+ <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/version-3.13.64-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%2C300%2F1%2C300-brightgreen.svg" alt="Tests"></a>
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>
16
16
  </p>
17
17
 
@@ -213,6 +213,7 @@ All use `globalThis` with `??=` — override any by redeclaring locally.
213
213
  | `?.` `?.[]` `?.()` | `a?.b` `a?.[0]` `a?.()` | Optional chaining (ES6) |
214
214
  | `?[]` `?()` | `a?[0]` `a?(x)` | Optional chaining shorthand |
215
215
  | `?.` `=` | `el?.scrollTop = 0` | Optional chain assignment — guarded write |
216
+ | `=` (render) | `= item.textContent` | Expression output as text node in render blocks |
216
217
  | `??` | `a ?? b` | Nullish coalescing |
217
218
  | `...` (spread) | `[...items, last]` | Prefix spread (ES6) |
218
219
  | `//` | `7 // 2` | Floor division |
@@ -420,7 +421,7 @@ Rip includes optional packages for full-stack development:
420
421
 
421
422
  | Package | Version | Purpose |
422
423
  |---------|---------|---------|
423
- | [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.13.27 | Core language compiler |
424
+ | [rip-lang](https://www.npmjs.com/package/rip-lang) | 3.13.62 | Core language compiler |
424
425
  | [@rip-lang/server](packages/server/) | 1.3.12 | Multi-worker app server (web framework, hot reload, HTTPS, mDNS) |
425
426
  | [@rip-lang/db](packages/db/) | 1.3.15 | DuckDB server with official UI + ActiveRecord-style client |
426
427
  | [ui](packages/ui/) | — | Rip UI — 38 headless components (Grid, Select, Dialog, Tabs, etc.) |
@@ -465,7 +466,7 @@ rip file.rip # Run
465
466
  rip -c file.rip # Compile
466
467
  rip -t file.rip # Tokens
467
468
  rip -s file.rip # S-expressions
468
- bun run test # 1369 tests
469
+ bun run test # 1436 tests
469
470
  bun run parser # Rebuild parser
470
471
  bun run build # Build browser bundle
471
472
  ```
package/docs/RIP-LANG.md CHANGED
@@ -388,6 +388,25 @@ JavaScript does not allow optional chaining on the left side of assignments
388
388
  automatically. This is particularly useful for DOM element references that
389
389
  may not exist yet (before mount, inside conditionals, etc.).
390
390
 
391
+ ### Render Expression Output (`= prefix`)
392
+
393
+ In component render blocks, `x.y` on its own line is parsed as a tag
394
+ with a CSS class (`<x class="y">`), not a property access. The `=`
395
+ prefix forces the line to be an expression, outputting it as a text node:
396
+
397
+ ```coffee
398
+ # In a render block:
399
+ render
400
+ div
401
+ = item.textContent # text node — not a tag
402
+ = nav.dataset.trigger # works even when 'nav' is an HTML tag
403
+ = link.href # works even when 'link' is an HTML tag
404
+ div.card # tag — <div class="card"> (no = prefix)
405
+ ```
406
+
407
+ The `=` removes itself and stamps the expression so the codegen skips
408
+ tag detection. Output is clean: `createTextNode(String(expr))`.
409
+
391
410
  ## Ternary Operator
392
411
 
393
412
  ```coffee
@@ -2131,4 +2150,4 @@ Each would need design discussion before building.
2131
2150
 
2132
2151
  ---
2133
2152
 
2134
- *Rip 3.13 — 1,369 tests — Zero dependencies — Self-hosting — ~11,890 LOC*
2153
+ *Rip 3.13 — 1,436 tests — Zero dependencies — Self-hosting — ~11,890 LOC*
package/docs/dist/rip.js CHANGED
@@ -3511,6 +3511,7 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
3511
3511
  return Array.isArray(target) && target[0] === "." && target[1] === "this";
3512
3512
  }
3513
3513
  function installComponentSupport(CodeGenerator, Lexer2) {
3514
+ let meta = (node, key) => node instanceof String ? node[key] : undefined;
3514
3515
  const origClassify = Lexer2.prototype.classifyKeyword;
3515
3516
  Lexer2.prototype.classifyKeyword = function(id, fallback, data) {
3516
3517
  if (id === "offer" || id === "accept") {
@@ -3630,6 +3631,21 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
3630
3631
  }
3631
3632
  if (!inRender)
3632
3633
  return 1;
3634
+ if (tag === "=" && i > 0) {
3635
+ let prev = tokens[i - 1][0];
3636
+ if (prev === "TERMINATOR" || prev === "INDENT" || prev === "RENDER") {
3637
+ tokens.splice(i, 1);
3638
+ if (tokens[i] && tokens[i][0] === "IDENTIFIER") {
3639
+ let val = tokens[i][1];
3640
+ if (typeof val === "string") {
3641
+ val = new String(val);
3642
+ tokens[i][1] = val;
3643
+ }
3644
+ val.text = true;
3645
+ }
3646
+ return 0;
3647
+ }
3648
+ }
3633
3649
  if (tag === "UNARY_MATH" && token[1] === "~" && nextToken && nextToken[0] === "IDENTIFIER") {
3634
3650
  token[0] = "PROPERTY";
3635
3651
  token[1] = "__transition__";
@@ -3834,11 +3850,11 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
3834
3850
  }
3835
3851
  let raw = typeof current === "string" ? current : current instanceof String ? current.valueOf() : null;
3836
3852
  if (raw === null)
3837
- return { tag: null, classes, id: undefined };
3853
+ return { tag: null, classes, id: undefined, base: current };
3838
3854
  let [tag, id] = raw.split("#");
3839
3855
  if (!tag)
3840
3856
  tag = "div";
3841
- return { tag, classes, id };
3857
+ return { tag, classes, id, base: current };
3842
3858
  };
3843
3859
  const _str = (s) => typeof s === "string" ? s : s instanceof String ? s.valueOf() : null;
3844
3860
  const _transferMeta = (from, to) => {
@@ -4229,7 +4245,7 @@ ${blockFactoriesCode}return ${lines.join(`
4229
4245
  this._createLines.push(`${slotVar} = ${s}.children instanceof Node ? ${s}.children : (${s}.children != null ? document.createTextNode(String(${s}.children)) : document.createComment(''));`);
4230
4246
  return slotVar;
4231
4247
  }
4232
- if (headStr && this.isHtmlTag(headStr)) {
4248
+ if (headStr && this.isHtmlTag(headStr) && !meta(head, "text")) {
4233
4249
  let [tagName, id] = headStr.split("#");
4234
4250
  return this.generateTag(tagName || "div", [], rest, id);
4235
4251
  }
@@ -4247,8 +4263,8 @@ ${blockFactoriesCode}return ${lines.join(`
4247
4263
  this._createLines.push(`${slotVar} = ${s}.${prop} instanceof Node ? ${s}.${prop} : (${s}.${prop} != null ? document.createTextNode(String(${s}.${prop})) : document.createComment(''));`);
4248
4264
  return slotVar;
4249
4265
  }
4250
- const { tag, classes, id } = this.collectTemplateClasses(sexpr);
4251
- if (tag && this.isHtmlTag(tag)) {
4266
+ const { tag, classes, id, base } = this.collectTemplateClasses(sexpr);
4267
+ if (!meta(base, "text") && tag && this.isHtmlTag(tag)) {
4252
4268
  return this.generateTag(tag, classes, [], id);
4253
4269
  }
4254
4270
  const textVar2 = this.newTextVar();
@@ -8703,8 +8719,8 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
8703
8719
  return new CodeGenerator({}).getComponentRuntime();
8704
8720
  }
8705
8721
  // src/browser.js
8706
- var VERSION = "3.13.56";
8707
- var BUILD_DATE = "2026-03-01@02:18:54GMT";
8722
+ var VERSION = "3.13.63";
8723
+ var BUILD_DATE = "2026-03-01@06:49:01GMT";
8708
8724
  if (typeof globalThis !== "undefined") {
8709
8725
  if (!globalThis.__rip)
8710
8726
  new Function(getReactiveRuntime())();