rip-lang 3.14.0 → 3.14.2
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 +42 -32
- package/docs/RIP-LANG.md +89 -4
- package/docs/RIP-SCHEMA.md +98 -8
- package/docs/dist/rip.js +724 -455
- package/docs/dist/rip.min.js +232 -177
- package/docs/dist/rip.min.js.br +0 -0
- package/docs/extensions/duckdb/index.html +97 -0
- package/docs/extensions/duckdb/manifest.json +11 -0
- package/docs/extensions/duckdb/v1.5.2/linux_amd64/ripdb.duckdb_extension.gz +0 -0
- package/docs/extensions/duckdb/v1.5.2/osx_arm64/ripdb.duckdb_extension.gz +0 -0
- package/docs/extensions/index.html +82 -0
- package/docs/extensions/vscode/print/index.html +40 -0
- package/docs/extensions/vscode/print/print-1.0.13.vsix +0 -0
- package/docs/extensions/vscode/print/print-latest.vsix +0 -0
- package/docs/extensions/vscode/rip/index.html +40 -0
- package/docs/extensions/vscode/rip/rip-0.5.15.vsix +0 -0
- package/docs/extensions/vscode/rip/rip-latest.vsix +0 -0
- package/package.json +3 -2
- package/src/AGENTS.md +32 -0
- package/src/compiler.js +140 -22
- package/src/grammar/grammar.rip +41 -0
- package/src/lexer.js +146 -17
- package/src/parser.js +213 -205
- package/src/schema.js +104 -13
- package/src/typecheck.js +532 -3
- package/src/sourcemap-utils.js +0 -521
package/docs/dist/rip.min.js.br
CHANGED
|
Binary file
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>ripdb — DuckDB extension repository</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root { --bg: #fff; --text: #1a1d21; --muted: #6b7280; --link: #2563eb; --code-bg: #f4f4f5; --border: #e2e5e9; --pre-bg: #fafafa; }
|
|
9
|
+
@media (prefers-color-scheme: dark) {
|
|
10
|
+
:root { --bg: #0a0a0c; --text: #e4e4e7; --muted: #71717a; --link: #60a5fa; --code-bg: #1e1e22; --border: #2a2a2e; --pre-bg: #161618; }
|
|
11
|
+
}
|
|
12
|
+
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
|
|
13
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Inter', system-ui, sans-serif;
|
|
14
|
+
font-size: 16px; line-height: 1.7; color: var(--text); background: var(--bg);
|
|
15
|
+
max-width: 720px; margin: 0 auto; padding: 3rem 1.5rem; }
|
|
16
|
+
h1 { font-size: 1.75rem; margin-bottom: .25em; letter-spacing: -0.02em; }
|
|
17
|
+
h2 { font-size: 1.25rem; margin: 2em 0 .5em; }
|
|
18
|
+
p, ul, ol, pre { margin: 0 0 1em; }
|
|
19
|
+
p.lead { color: var(--muted); font-size: 1.0625rem; margin-bottom: 2rem; }
|
|
20
|
+
code { font-family: 'SF Mono', 'JetBrains Mono', 'Fira Code', ui-monospace, monospace;
|
|
21
|
+
font-size: .875em; background: var(--code-bg); padding: 2px 5px; border-radius: 4px; }
|
|
22
|
+
pre { background: var(--pre-bg); border: 1px solid var(--border); border-radius: 8px;
|
|
23
|
+
padding: 1rem 1.25rem; overflow-x: auto; }
|
|
24
|
+
pre code { background: none; padding: 0; font-size: .8125rem; line-height: 1.6; }
|
|
25
|
+
a { color: var(--link); text-decoration: none; } a:hover { text-decoration: underline; }
|
|
26
|
+
.platforms { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
|
27
|
+
gap: .5rem; margin: 1em 0; }
|
|
28
|
+
.platforms code { display: block; text-align: center; padding: .5em; }
|
|
29
|
+
footer { margin-top: 4rem; padding-top: 1.5rem; border-top: 1px solid var(--border);
|
|
30
|
+
color: var(--muted); font-size: .875rem; }
|
|
31
|
+
</style>
|
|
32
|
+
</head>
|
|
33
|
+
<body>
|
|
34
|
+
|
|
35
|
+
<h1>ripdb</h1>
|
|
36
|
+
<p class="lead">A custom DuckDB extension repository. Install <code>ripdb</code> directly from this URL.</p>
|
|
37
|
+
|
|
38
|
+
<h2>Install</h2>
|
|
39
|
+
<pre><code>SET allow_unsigned_extensions = true;
|
|
40
|
+
INSTALL ripdb FROM 'PAGE_BASE_URL';
|
|
41
|
+
LOAD ripdb;</code></pre>
|
|
42
|
+
|
|
43
|
+
<p>
|
|
44
|
+
Custom-repository extensions are unsigned, so you need the
|
|
45
|
+
<code>allow_unsigned_extensions</code> setting — pass it on startup
|
|
46
|
+
(<code>duckdb -unsigned</code>) or <code>SET</code> it at the top of your
|
|
47
|
+
session before <code>LOAD</code>.
|
|
48
|
+
</p>
|
|
49
|
+
|
|
50
|
+
<h2>Currently published</h2>
|
|
51
|
+
<div class="platforms">
|
|
52
|
+
<code>osx_arm64</code>
|
|
53
|
+
<code>linux_amd64</code>
|
|
54
|
+
</div>
|
|
55
|
+
<p>
|
|
56
|
+
Additional platforms (<code>osx_amd64</code>, <code>linux_arm64</code>,
|
|
57
|
+
<code>wasm_*</code>, <code>windows_*</code>) are supported by the build
|
|
58
|
+
system but not currently published. They'll reappear here once enabled in
|
|
59
|
+
the <a href="https://github.com/shreeve/rip-lang/blob/main/.github/workflows/ripdb-extension.yml">CI matrix</a>.
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
<h2>URL layout</h2>
|
|
63
|
+
<p>Each build is published under the path DuckDB expects for a custom repository:</p>
|
|
64
|
+
<pre><code><base>/<duckdb_version>/<platform>/ripdb.duckdb_extension.gz</code></pre>
|
|
65
|
+
<p>See <a href="manifest.json"><code>manifest.json</code></a> for the exact set of builds available on this instance.</p>
|
|
66
|
+
|
|
67
|
+
<h2>Verify before installing</h2>
|
|
68
|
+
<p>DuckDB builds the full URL itself from your client's version and platform. You can sanity-check that the right build is published — no DuckDB session needed:</p>
|
|
69
|
+
<pre><code># 1) Your DuckDB version
|
|
70
|
+
duckdb -csv -noheader -c "SELECT library_version FROM pragma_version()"
|
|
71
|
+
# → v1.5.2
|
|
72
|
+
|
|
73
|
+
# 2) Your platform
|
|
74
|
+
duckdb -csv -noheader -c "PRAGMA platform"
|
|
75
|
+
# → osx_arm64
|
|
76
|
+
|
|
77
|
+
# 3) Is a build published for that (version, platform) pair?
|
|
78
|
+
curl -I "PAGE_BASE_URL/v1.5.2/osx_arm64/ripdb.duckdb_extension.gz"
|
|
79
|
+
# → HTTP/2 200 means INSTALL will succeed
|
|
80
|
+
# → HTTP/2 404 means that cell isn't published yet — run the workflow
|
|
81
|
+
# with your DuckDB version as input.</code></pre>
|
|
82
|
+
|
|
83
|
+
<footer>
|
|
84
|
+
Built by the
|
|
85
|
+
<a href="https://github.com/shreeve/rip-lang/actions/workflows/ripdb-extension.yml">ripdb-extension workflow</a>
|
|
86
|
+
in the <a href="https://github.com/shreeve/rip-lang">rip-lang</a> repository.
|
|
87
|
+
</footer>
|
|
88
|
+
|
|
89
|
+
<script>
|
|
90
|
+
// Rewrite PAGE_BASE_URL to the actual origin at load time — works on any fork.
|
|
91
|
+
document.querySelectorAll('pre code').forEach(el => {
|
|
92
|
+
el.textContent = el.textContent.replace(/PAGE_BASE_URL/g, location.origin + location.pathname.replace(/\/$/, ''));
|
|
93
|
+
});
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
</body>
|
|
97
|
+
</html>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>rip-lang extensions</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root { --bg:#fff; --text:#1a1d21; --muted:#6b7280; --link:#2563eb; --code-bg:#f4f4f5; --border:#e2e5e9; --pre-bg:#fafafa; --card:#fff; --card-border:#e2e5e9; }
|
|
9
|
+
@media (prefers-color-scheme:dark) {
|
|
10
|
+
:root { --bg:#0a0a0c; --text:#e4e4e7; --muted:#71717a; --link:#60a5fa; --code-bg:#1e1e22; --border:#2a2a2e; --pre-bg:#161618; --card:#161618; --card-border:#2a2a2e; }
|
|
11
|
+
}
|
|
12
|
+
*, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }
|
|
13
|
+
body { font-family:-apple-system,BlinkMacSystemFont,'Inter','Segoe UI',system-ui,sans-serif;
|
|
14
|
+
font-size:16px; line-height:1.7; color:var(--text); background:var(--bg);
|
|
15
|
+
max-width:760px; margin:0 auto; padding:3rem 1.5rem; }
|
|
16
|
+
h1 { font-size:1.875rem; letter-spacing:-0.02em; }
|
|
17
|
+
h2 { font-size:1.25rem; margin:2em 0 .75em; }
|
|
18
|
+
.lead { color:var(--muted); font-size:1.0625rem; margin:.5em 0 2rem; }
|
|
19
|
+
a { color:var(--link); text-decoration:none; } a:hover { text-decoration:underline; }
|
|
20
|
+
code { font-family:'SF Mono','JetBrains Mono',ui-monospace,monospace;
|
|
21
|
+
font-size:.875em; background:var(--code-bg); padding:2px 5px; border-radius:4px; }
|
|
22
|
+
pre { background:var(--pre-bg); border:1px solid var(--border); border-radius:8px;
|
|
23
|
+
padding:1rem 1.25rem; overflow-x:auto; margin:0 0 1em; }
|
|
24
|
+
pre code { background:none; padding:0; font-size:.8125rem; line-height:1.6; }
|
|
25
|
+
.cards { display:grid; grid-template-columns:1fr; gap:1rem; margin:1em 0; }
|
|
26
|
+
@media (min-width:640px) { .cards { grid-template-columns:1fr 1fr; } }
|
|
27
|
+
.card { border:1px solid var(--card-border); border-radius:12px; padding:1.25rem;
|
|
28
|
+
background:var(--card); transition:transform 120ms ease, box-shadow 120ms ease; }
|
|
29
|
+
.card:hover { transform:translateY(-1px); box-shadow:0 4px 14px rgba(0,0,0,.05); }
|
|
30
|
+
.card h3 { font-size:1.0625rem; margin-bottom:.25em; }
|
|
31
|
+
.card p { color:var(--muted); font-size:.9375rem; margin-bottom:.75em; }
|
|
32
|
+
.card a.more { font-size:.8125rem; font-weight:500; }
|
|
33
|
+
footer { margin-top:4rem; padding-top:1.5rem; border-top:1px solid var(--border);
|
|
34
|
+
color:var(--muted); font-size:.875rem; }
|
|
35
|
+
</style>
|
|
36
|
+
</head>
|
|
37
|
+
<body>
|
|
38
|
+
|
|
39
|
+
<h1>rip-lang extensions</h1>
|
|
40
|
+
<p class="lead">Drop-in extensions for DuckDB, VS Code, and Cursor — built straight from the <a href="https://github.com/shreeve/rip-lang">rip-lang</a> monorepo.</p>
|
|
41
|
+
|
|
42
|
+
<h2>DuckDB</h2>
|
|
43
|
+
<div class="cards">
|
|
44
|
+
<a class="card" href="duckdb/">
|
|
45
|
+
<h3>ripdb</h3>
|
|
46
|
+
<p>Native DuckDB extension that exposes a rip-db server as a first-class attached database.</p>
|
|
47
|
+
<span class="more">Install instructions →</span>
|
|
48
|
+
</a>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<h2>VS Code / Cursor</h2>
|
|
52
|
+
<div class="cards">
|
|
53
|
+
<a class="card" href="vscode/print/">
|
|
54
|
+
<h3>rip-lang.print</h3>
|
|
55
|
+
<p>Syntax-highlighted source printer. Right-click any file or folder, choose <em>Rip Print</em>, and get a clean printable document.</p>
|
|
56
|
+
<span class="more">Download .vsix →</span>
|
|
57
|
+
</a>
|
|
58
|
+
<a class="card" href="vscode/rip/">
|
|
59
|
+
<h3>rip-lang.rip</h3>
|
|
60
|
+
<p>Language support for the Rip programming language — grammars, commands, and editor integration.</p>
|
|
61
|
+
<span class="more">Download .vsix →</span>
|
|
62
|
+
</a>
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<h2>Why custom hosting?</h2>
|
|
66
|
+
<p>
|
|
67
|
+
The <code>ripdb</code> DuckDB extension is unsigned and therefore isn't published on
|
|
68
|
+
the official <code>extensions.duckdb.org</code> community index. The VS Code extensions
|
|
69
|
+
are published separately to the Marketplace, but the <code>.vsix</code> files here
|
|
70
|
+
let you install the exact build that ships with the current source tree (handy for
|
|
71
|
+
Cursor, offline setups, or pre-release testing).
|
|
72
|
+
</p>
|
|
73
|
+
|
|
74
|
+
<footer>
|
|
75
|
+
Updated by the
|
|
76
|
+
<a href="https://github.com/shreeve/rip-lang/actions">rip-lang GitHub Actions</a>
|
|
77
|
+
on every release. The full tree is served by GitHub Pages from
|
|
78
|
+
<a href="https://github.com/shreeve/rip-lang/tree/main/docs/extensions"><code>main/docs/extensions/</code></a>.
|
|
79
|
+
</footer>
|
|
80
|
+
|
|
81
|
+
</body>
|
|
82
|
+
</html>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>rip-lang.print — VS Code / Cursor extension</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root { --bg:#fff; --text:#1a1d21; --muted:#6b7280; --link:#2563eb; --code-bg:#f4f4f5; --border:#e2e5e9; --pre-bg:#fafafa; }
|
|
9
|
+
@media (prefers-color-scheme:dark) { :root { --bg:#0a0a0c; --text:#e4e4e7; --muted:#71717a; --link:#60a5fa; --code-bg:#1e1e22; --border:#2a2a2e; --pre-bg:#161618; } }
|
|
10
|
+
*, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }
|
|
11
|
+
body { font-family:-apple-system,BlinkMacSystemFont,'Inter','Segoe UI',system-ui,sans-serif; font-size:16px; line-height:1.7; color:var(--text); background:var(--bg); max-width:720px; margin:0 auto; padding:3rem 1.5rem; }
|
|
12
|
+
h1 { font-size:1.75rem; letter-spacing:-0.02em; }
|
|
13
|
+
h2 { font-size:1.25rem; margin:2em 0 .5em; }
|
|
14
|
+
p, pre, ul { margin:0 0 1em; } ul { padding-left:1.25rem; }
|
|
15
|
+
code { font-family:'SF Mono',ui-monospace,monospace; font-size:.875em; background:var(--code-bg); padding:2px 5px; border-radius:4px; }
|
|
16
|
+
pre { background:var(--pre-bg); border:1px solid var(--border); border-radius:8px; padding:1rem 1.25rem; overflow-x:auto; }
|
|
17
|
+
pre code { background:none; padding:0; font-size:.8125rem; line-height:1.6; }
|
|
18
|
+
a { color:var(--link); text-decoration:none; } a:hover { text-decoration:underline; }
|
|
19
|
+
footer { margin-top:3rem; padding-top:1.5rem; border-top:1px solid var(--border); color:var(--muted); font-size:.875rem; }
|
|
20
|
+
</style>
|
|
21
|
+
</head>
|
|
22
|
+
<body>
|
|
23
|
+
<h1>rip-lang.print</h1>
|
|
24
|
+
<p>VS Code / Cursor extension, published from the <a href="https://github.com/shreeve/rip-lang">rip-lang</a> monorepo.</p>
|
|
25
|
+
|
|
26
|
+
<h2>Install (latest)</h2>
|
|
27
|
+
<pre><code>curl -LO https://shreeve.github.io/rip-lang/extensions/vscode/print/print-latest.vsix
|
|
28
|
+
cursor --install-extension ./print-latest.vsix
|
|
29
|
+
|
|
30
|
+
# VS Code:
|
|
31
|
+
# code --install-extension ./print-latest.vsix</code></pre>
|
|
32
|
+
|
|
33
|
+
<h2>Versions</h2>
|
|
34
|
+
<ul>
|
|
35
|
+
<li><a href="./print-1.0.13.vsix"><code>print-1.0.13.vsix</code></a></li>
|
|
36
|
+
</ul>
|
|
37
|
+
|
|
38
|
+
<footer>← <a href="../../">all rip-lang extensions</a></footer>
|
|
39
|
+
</body>
|
|
40
|
+
</html>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>rip-lang.rip — VS Code / Cursor extension</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root { --bg:#fff; --text:#1a1d21; --muted:#6b7280; --link:#2563eb; --code-bg:#f4f4f5; --border:#e2e5e9; --pre-bg:#fafafa; }
|
|
9
|
+
@media (prefers-color-scheme:dark) { :root { --bg:#0a0a0c; --text:#e4e4e7; --muted:#71717a; --link:#60a5fa; --code-bg:#1e1e22; --border:#2a2a2e; --pre-bg:#161618; } }
|
|
10
|
+
*, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }
|
|
11
|
+
body { font-family:-apple-system,BlinkMacSystemFont,'Inter','Segoe UI',system-ui,sans-serif; font-size:16px; line-height:1.7; color:var(--text); background:var(--bg); max-width:720px; margin:0 auto; padding:3rem 1.5rem; }
|
|
12
|
+
h1 { font-size:1.75rem; letter-spacing:-0.02em; }
|
|
13
|
+
h2 { font-size:1.25rem; margin:2em 0 .5em; }
|
|
14
|
+
p, pre, ul { margin:0 0 1em; } ul { padding-left:1.25rem; }
|
|
15
|
+
code { font-family:'SF Mono',ui-monospace,monospace; font-size:.875em; background:var(--code-bg); padding:2px 5px; border-radius:4px; }
|
|
16
|
+
pre { background:var(--pre-bg); border:1px solid var(--border); border-radius:8px; padding:1rem 1.25rem; overflow-x:auto; }
|
|
17
|
+
pre code { background:none; padding:0; font-size:.8125rem; line-height:1.6; }
|
|
18
|
+
a { color:var(--link); text-decoration:none; } a:hover { text-decoration:underline; }
|
|
19
|
+
footer { margin-top:3rem; padding-top:1.5rem; border-top:1px solid var(--border); color:var(--muted); font-size:.875rem; }
|
|
20
|
+
</style>
|
|
21
|
+
</head>
|
|
22
|
+
<body>
|
|
23
|
+
<h1>rip-lang.rip</h1>
|
|
24
|
+
<p>VS Code / Cursor extension, published from the <a href="https://github.com/shreeve/rip-lang">rip-lang</a> monorepo.</p>
|
|
25
|
+
|
|
26
|
+
<h2>Install (latest)</h2>
|
|
27
|
+
<pre><code>curl -LO https://shreeve.github.io/rip-lang/extensions/vscode/rip/rip-latest.vsix
|
|
28
|
+
cursor --install-extension ./rip-latest.vsix
|
|
29
|
+
|
|
30
|
+
# VS Code:
|
|
31
|
+
# code --install-extension ./rip-latest.vsix</code></pre>
|
|
32
|
+
|
|
33
|
+
<h2>Versions</h2>
|
|
34
|
+
<ul>
|
|
35
|
+
<li><a href="./rip-0.5.15.vsix"><code>rip-0.5.15.vsix</code></a></li>
|
|
36
|
+
</ul>
|
|
37
|
+
|
|
38
|
+
<footer>← <a href="../../">all rip-lang extensions</a></footer>
|
|
39
|
+
</body>
|
|
40
|
+
</html>
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rip-lang",
|
|
3
|
-
"version": "3.14.
|
|
3
|
+
"version": "3.14.2",
|
|
4
4
|
"description": "A modern language that compiles to JavaScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/compiler.js",
|
|
@@ -42,9 +42,10 @@
|
|
|
42
42
|
"serve": "bun scripts/serve.js",
|
|
43
43
|
"test": "bun test/runner.js",
|
|
44
44
|
"test:types": "bun test/types/runner.js",
|
|
45
|
+
"test:singleton": "bun test/schema-singleton.test.js",
|
|
45
46
|
"test:server": "./bin/rip packages/server/tests/runner.rip",
|
|
46
47
|
"test:time": "bun run --cwd packages/time test",
|
|
47
|
-
"test:all": "bun run test && bun run test:types && bun run test:server && bun run test:time",
|
|
48
|
+
"test:all": "bun run test && bun run test:types && bun run test:singleton && bun run test:server && bun run test:time",
|
|
48
49
|
"test:ui": "bun run --cwd packages/ui test:e2e",
|
|
49
50
|
"test:ui:chromium": "bun run --cwd packages/ui test:e2e:chromium",
|
|
50
51
|
"test:ui:axe": "bun run --cwd packages/ui test:e2e:axe",
|
package/src/AGENTS.md
CHANGED
|
@@ -93,6 +93,13 @@ Complete node reference:
|
|
|
93
93
|
['map-literal', ...pairs] // *{ } → new Map([[key, value], ...])
|
|
94
94
|
['...', expr] // Spread (prefix only)
|
|
95
95
|
|
|
96
|
+
// Pick operator — obj.{ } / obj?.{ }
|
|
97
|
+
// Heads use syntax-shape strings (not `pick`/`optpick`) so they can't
|
|
98
|
+
// collide with a user function of the same name: `pick(false)` as an
|
|
99
|
+
// ordinary call would otherwise be misrouted through the emitter table.
|
|
100
|
+
['.{}', source, ...items] // items: [srcKey, dstKey, defaultExpr|null]
|
|
101
|
+
['?.{}', source, ...items] // optional-chain pick — undefined if source null
|
|
102
|
+
|
|
96
103
|
// Operators
|
|
97
104
|
['+', left, right] ['-', left, right] ['*', left, right]
|
|
98
105
|
['/', left, right] ['%', left, right] ['**', left, right]
|
|
@@ -383,6 +390,31 @@ Compile-time optimizations:
|
|
|
383
390
|
- array-based `state.blocks[]`
|
|
384
391
|
- `state.keys = items.slice()` for default item-as-key behavior
|
|
385
392
|
|
|
393
|
+
### Nested Loop Variable Collision (known gotcha)
|
|
394
|
+
|
|
395
|
+
The emitted patch function for a reactive block is named `p` and takes
|
|
396
|
+
every enclosing loop variable as a positional parameter:
|
|
397
|
+
|
|
398
|
+
```javascript
|
|
399
|
+
// For a render with `for item in items` containing `for v, i in item.enum`
|
|
400
|
+
p(ctx, v, i, item, i) { ... } // duplicate `i` — invalid in strict mode
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
The outer `for item in items` allocates an implicit `i` counter even
|
|
404
|
+
when the user wrote no explicit index. If the inner loop uses `i` as an
|
|
405
|
+
explicit index, both end up in `p`'s signature and V8 throws
|
|
406
|
+
`Duplicate parameter name not allowed in this context` at parse time.
|
|
407
|
+
|
|
408
|
+
Current workaround (author-facing, documented in
|
|
409
|
+
`packages/ui/AGENTS.md`): use a different inner index name (`idx`, `n`,
|
|
410
|
+
`j`).
|
|
411
|
+
|
|
412
|
+
Long-term fix: the emitter should generate unique internal names for
|
|
413
|
+
auto-allocated loop counters (e.g. `__i0`, `__i1`) rather than reusing
|
|
414
|
+
`i`, so no user-chosen name can ever collide. The fix lives in whichever
|
|
415
|
+
`emitFor*` path closes over the block into a patch function — search
|
|
416
|
+
for sites that build the `p(ctx, ...args)` signature in `compiler.js`.
|
|
417
|
+
|
|
386
418
|
### Error Boundaries
|
|
387
419
|
|
|
388
420
|
`onError` walks the `_parent` chain.
|