rip-lang 3.7.4 → 3.8.9

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.
@@ -1354,7 +1354,7 @@ var NEWLINE_RE = /^(?:\n[^\n\S]*)+/;
1354
1354
  var COMMENT_RE = /^(\s*)###([^#][\s\S]*?)(?:###([^\n\S]*)|###$)|^((?:\s*#(?!##[^#]).*)+)/;
1355
1355
  var CODE_RE = /^[-=]>/;
1356
1356
  var REACTIVE_RE = /^(?:~[=>]|=!)/;
1357
- var STRING_START_RE = /^(?:'''|"""|'|")/;
1357
+ var STRING_START_RE = /^(?:'''\\|"""\\|'''|"""|'|")/;
1358
1358
  var STRING_SINGLE_RE = /^(?:[^\\']|\\[\s\S])*/;
1359
1359
  var STRING_DOUBLE_RE = /^(?:[^\\"#$]|\\[\s\S]|\#(?!\{)|\$(?!\{))*/;
1360
1360
  var HEREDOC_SINGLE_RE = /^(?:[^\\']|\\[\s\S]|'(?!''))*/;
@@ -1650,6 +1650,20 @@ class Lexer {
1650
1650
  return fallback;
1651
1651
  }
1652
1652
  commentToken() {
1653
+ if (this.inRenderBlock) {
1654
+ if (/^#[a-zA-Z_]/.test(this.chunk)) {
1655
+ let prev = this.prev();
1656
+ if (prev && (prev[0] === "IDENTIFIER" || prev[0] === "PROPERTY"))
1657
+ return 0;
1658
+ let m = /^#([a-zA-Z_][\w-]*)/.exec(this.chunk);
1659
+ if (m) {
1660
+ this.emit("IDENTIFIER", "div#" + m[1]);
1661
+ return m[0].length;
1662
+ }
1663
+ }
1664
+ if (/^\s+#[a-zA-Z_]/.test(this.chunk))
1665
+ return 0;
1666
+ }
1653
1667
  let match = COMMENT_RE.exec(this.chunk);
1654
1668
  if (!match)
1655
1669
  return 0;
@@ -1766,12 +1780,14 @@ class Lexer {
1766
1780
  if (!m)
1767
1781
  return 0;
1768
1782
  let quote = m[0];
1783
+ let raw = quote.length > 1 && quote.endsWith("\\");
1784
+ let baseQuote = raw ? quote.slice(0, -1) : quote;
1769
1785
  let prev = this.prev();
1770
1786
  if (prev && this.prevVal() === "from" && (this.seenImport || this.seenExport)) {
1771
1787
  prev[0] = "FROM";
1772
1788
  }
1773
1789
  let regex;
1774
- switch (quote) {
1790
+ switch (baseQuote) {
1775
1791
  case "'":
1776
1792
  regex = STRING_SINGLE_RE;
1777
1793
  break;
@@ -1785,13 +1801,13 @@ class Lexer {
1785
1801
  regex = HEREDOC_DOUBLE_RE;
1786
1802
  break;
1787
1803
  }
1788
- let { tokens: parts, index: end } = this.matchWithInterpolations(regex, quote);
1789
- let heredoc = quote.length === 3;
1804
+ let { tokens: parts, index: end } = this.matchWithInterpolations(regex, quote, baseQuote);
1805
+ let heredoc = baseQuote.length === 3;
1790
1806
  let indent = null;
1791
1807
  if (heredoc) {
1792
- indent = this.processHeredocIndent(end, quote, parts);
1808
+ indent = this.processHeredocIndent(end, baseQuote, parts);
1793
1809
  }
1794
- this.mergeInterpolationTokens(parts, { quote, indent, endOffset: end });
1810
+ this.mergeInterpolationTokens(parts, { quote: baseQuote, indent, endOffset: end, raw });
1795
1811
  return end;
1796
1812
  }
1797
1813
  processHeredocIndent(end, quote, tokens) {
@@ -1875,7 +1891,7 @@ class Lexer {
1875
1891
  }
1876
1892
  return { tokens, index: offset + closingDelimiter.length };
1877
1893
  }
1878
- mergeInterpolationTokens(tokens, { quote, indent, endOffset }) {
1894
+ mergeInterpolationTokens(tokens, { quote, indent, endOffset, raw }) {
1879
1895
  if (tokens.length > 1) {
1880
1896
  this.emit("STRING_START", "(", { len: quote?.length || 0, data: { quote } });
1881
1897
  }
@@ -1897,6 +1913,9 @@ class Lexer {
1897
1913
  if (i === tokens.length - 1 && quote?.length === 3) {
1898
1914
  processed = processed.replace(/\n[^\S\n]*$/, "");
1899
1915
  }
1916
+ if (raw) {
1917
+ processed = processed.replace(/\\([nrtbfv0\\'"`xu])/g, "\\\\$1");
1918
+ }
1900
1919
  this.emit("STRING", `"${processed}"`, { len: val.length, data: { quote } });
1901
1920
  }
1902
1921
  }
@@ -1936,7 +1955,7 @@ class Lexer {
1936
1955
  let [flags2] = REGEX_FLAGS_RE.exec(this.chunk.slice(index2));
1937
1956
  let end2 = index2 + flags2.length;
1938
1957
  if (parts.length === 1 || !parts.some((p) => p[0] === "TOKENS")) {
1939
- let body2 = parts[0]?.[1] || "";
1958
+ let body2 = (parts[0]?.[1] || "").replace(/(?<!\\)\//g, "\\/");
1940
1959
  this.emit("REGEX", `/${body2}/${flags2}`, { len: end2, data: { delimiter: "///", heregex: { flags: flags2 } } });
1941
1960
  } else {
1942
1961
  this.emit("REGEX_START", "(", { len: 0 });
@@ -2264,7 +2283,7 @@ class Lexer {
2264
2283
  let isTemplateTag = (name) => {
2265
2284
  return isHtmlTag(name) || isComponent(name);
2266
2285
  };
2267
- let startsWithHtmlTag = (tokens, i) => {
2286
+ let startsWithTag = (tokens, i) => {
2268
2287
  let j = i;
2269
2288
  while (j > 0) {
2270
2289
  let pt = tokens[j - 1][0];
@@ -2273,7 +2292,7 @@ class Lexer {
2273
2292
  }
2274
2293
  j--;
2275
2294
  }
2276
- return tokens[j] && tokens[j][0] === "IDENTIFIER" && isHtmlTag(tokens[j][1]);
2295
+ return tokens[j] && tokens[j][0] === "IDENTIFIER" && isTemplateTag(tokens[j][1]);
2277
2296
  };
2278
2297
  this.scanTokens(function(token, i, tokens) {
2279
2298
  let tag = token[0];
@@ -2339,7 +2358,7 @@ class Lexer {
2339
2358
  if (tag === "IDENTIFIER" || tag === "PROPERTY") {
2340
2359
  let next = tokens[i + 1];
2341
2360
  let nextNext = tokens[i + 2];
2342
- if (next && next[0] === "#" && nextNext && nextNext[0] === "PROPERTY") {
2361
+ if (next && next[0] === "#" && nextNext && (nextNext[0] === "PROPERTY" || nextNext[0] === "IDENTIFIER")) {
2343
2362
  token[1] = token[1] + "#" + nextNext[1];
2344
2363
  if (nextNext.spaced)
2345
2364
  token.spaced = true;
@@ -2405,12 +2424,14 @@ class Lexer {
2405
2424
  return 1;
2406
2425
  }
2407
2426
  let isTemplateElement = false;
2408
- if (tag === "IDENTIFIER" && isTemplateTag(token[1])) {
2427
+ let prevTag = i > 0 ? tokens[i - 1][0] : null;
2428
+ let isAfterControlFlow = prevTag === "IF" || prevTag === "UNLESS" || prevTag === "WHILE" || prevTag === "UNTIL" || prevTag === "WHEN";
2429
+ if (tag === "IDENTIFIER" && isTemplateTag(token[1]) && !isAfterControlFlow) {
2409
2430
  isTemplateElement = true;
2410
2431
  } else if (tag === "PROPERTY" || tag === "STRING" || tag === "CALL_END" || tag === ")") {
2411
- isTemplateElement = startsWithHtmlTag(tokens, i);
2432
+ isTemplateElement = startsWithTag(tokens, i);
2412
2433
  } else if (tag === "IDENTIFIER" && i > 1 && tokens[i - 1][0] === "...") {
2413
- if (startsWithHtmlTag(tokens, i)) {
2434
+ if (startsWithTag(tokens, i)) {
2414
2435
  let commaToken = gen(",", ",", token);
2415
2436
  let arrowToken = gen("->", "->", token);
2416
2437
  arrowToken.newLine = true;
@@ -2419,12 +2440,21 @@ class Lexer {
2419
2440
  }
2420
2441
  }
2421
2442
  if (isTemplateElement) {
2422
- let callStartToken = gen("CALL_START", "(", token);
2423
- let arrowToken = gen("->", "->", token);
2424
- arrowToken.newLine = true;
2425
- tokens.splice(i + 1, 0, callStartToken, arrowToken);
2426
- pendingCallEnds.push(currentIndent + 1);
2427
- return 3;
2443
+ let isClassOrIdTail = tag === "PROPERTY" && i > 0 && (tokens[i - 1][0] === "." || tokens[i - 1][0] === "#");
2444
+ if (tag === "IDENTIFIER" && isTemplateTag(token[1]) || isClassOrIdTail) {
2445
+ let callStartToken = gen("CALL_START", "(", token);
2446
+ let arrowToken = gen("->", "->", token);
2447
+ arrowToken.newLine = true;
2448
+ tokens.splice(i + 1, 0, callStartToken, arrowToken);
2449
+ pendingCallEnds.push(currentIndent + 1);
2450
+ return 3;
2451
+ } else {
2452
+ let commaToken = gen(",", ",", token);
2453
+ let arrowToken = gen("->", "->", token);
2454
+ arrowToken.newLine = true;
2455
+ tokens.splice(i + 1, 0, commaToken, arrowToken);
2456
+ return 3;
2457
+ }
2428
2458
  }
2429
2459
  }
2430
2460
  if (tag === "IDENTIFIER" && isComponent(token[1]) && nextToken && (nextToken[0] === "OUTDENT" || nextToken[0] === "TERMINATOR")) {
@@ -3154,7 +3184,7 @@ var parserInstance = {
3154
3184
  case 229:
3155
3185
  return $[$0 - 4].length === 3 ? ["if", $[$0 - 4][1], $[$0 - 4][2], ["if", $[$0 - 1], $[$0]]] : [...$[$0 - 4], ["if", $[$0 - 1], $[$0]]];
3156
3186
  case 230:
3157
- return ["unless", $[$0 - 1], $[$0]];
3187
+ return ["if", ["!", $[$0 - 1]], $[$0]];
3158
3188
  case 231:
3159
3189
  return ["if", ["!", $[$0 - 3]], $[$0 - 2], $[$0]];
3160
3190
  case 233:
@@ -3166,7 +3196,7 @@ var parserInstance = {
3166
3196
  return ["?:", $[$0 - 4], $[$0 - 6], $[$0 - 1]];
3167
3197
  case 238:
3168
3198
  case 239:
3169
- return ["unless", $[$0], [$[$0 - 2]]];
3199
+ return ["if", ["!", $[$0]], [$[$0 - 2]]];
3170
3200
  case 240:
3171
3201
  return ["try", $[$0]];
3172
3202
  case 241:
@@ -3200,9 +3230,9 @@ var parserInstance = {
3200
3230
  case 256:
3201
3231
  return ["while", $[$0 - 2], $[$0]];
3202
3232
  case 257:
3203
- return ["until", $[$0]];
3233
+ return ["while", ["!", $[$0]]];
3204
3234
  case 258:
3205
- return ["until", $[$0 - 2], $[$0]];
3235
+ return ["while", ["!", $[$0 - 2]], $[$0]];
3206
3236
  case 259:
3207
3237
  return $[$0 - 1].length === 2 ? [$[$0 - 1][0], $[$0 - 1][1], $[$0]] : [$[$0 - 1][0], $[$0 - 1][1], $[$0 - 1][2], $[$0]];
3208
3238
  case 260:
@@ -3435,11 +3465,12 @@ var parserInstance = {
3435
3465
  [TERROR, EOF] = [2, 1];
3436
3466
  lexer = Object.create(this.lexer);
3437
3467
  sharedState = { ctx: {} };
3438
- for (const k in this.ctx)
3439
- if (Object.hasOwn(this.ctx, k)) {
3440
- const v = this.ctx[k];
3441
- sharedState.ctx[k] = v;
3442
- }
3468
+ for (const k in this.ctx) {
3469
+ if (!Object.hasOwn(this.ctx, k))
3470
+ continue;
3471
+ const v = this.ctx[k];
3472
+ sharedState.ctx[k] = v;
3473
+ }
3443
3474
  lexer.setInput(input, sharedState.ctx);
3444
3475
  [sharedState.ctx.lexer, sharedState.ctx.parser] = [lexer, this];
3445
3476
  if (lexer.loc == null)
@@ -3586,8 +3617,11 @@ function installComponentSupport(CodeGenerator) {
3586
3617
  }
3587
3618
  current = current[1];
3588
3619
  }
3589
- const tag = typeof current === "string" ? current : current instanceof String ? current.valueOf() : "div";
3590
- return { tag, classes };
3620
+ let raw = typeof current === "string" ? current : current instanceof String ? current.valueOf() : "div";
3621
+ let [tag, id] = raw.split("#");
3622
+ if (!tag)
3623
+ tag = "div";
3624
+ return { tag, classes, id };
3591
3625
  };
3592
3626
  proto.transformComponentMembers = function(sexpr) {
3593
3627
  if (!Array.isArray(sexpr)) {
@@ -3606,6 +3640,9 @@ function installComponentSupport(CodeGenerator) {
3606
3640
  }
3607
3641
  return sexpr;
3608
3642
  }
3643
+ if (sexpr[0] === ".") {
3644
+ return [".", this.transformComponentMembers(sexpr[1]), sexpr[2]];
3645
+ }
3609
3646
  if (sexpr[0] === "->") {
3610
3647
  return ["=>", ...sexpr.slice(1).map((item) => this.transformComponentMembers(item))];
3611
3648
  }
@@ -3706,24 +3743,28 @@ function installComponentSupport(CodeGenerator) {
3706
3743
  lines.push(` this.${name} = __computed(() => ${val});`);
3707
3744
  }
3708
3745
  for (const effect of effects) {
3709
- const effectBody = effect[1];
3746
+ const effectBody = effect[2];
3710
3747
  const effectCode = this.generateInComponent(effectBody, "value");
3711
- lines.push(` __effect(${effectCode});`);
3748
+ lines.push(` __effect(() => { ${effectCode}; });`);
3712
3749
  }
3713
3750
  lines.push(" }");
3714
3751
  for (const { name, func } of methods) {
3715
3752
  if (Array.isArray(func) && (func[0] === "->" || func[0] === "=>")) {
3716
3753
  const [, params, methodBody] = func;
3717
3754
  const paramStr = Array.isArray(params) ? params.map((p) => this.formatParam(p)).join(", ") : "";
3718
- const bodyCode = this.generateInComponent(methodBody, "value");
3719
- lines.push(` ${name}(${paramStr}) { return ${bodyCode}; }`);
3755
+ const transformed = this.reactiveMembers ? this.transformComponentMembers(methodBody) : methodBody;
3756
+ const isAsync = this.containsAwait(methodBody);
3757
+ const bodyCode = this.generateFunctionBody(transformed, params || []);
3758
+ lines.push(` ${isAsync ? "async " : ""}${name}(${paramStr}) ${bodyCode}`);
3720
3759
  }
3721
3760
  }
3722
3761
  for (const { name, value } of lifecycleHooks) {
3723
3762
  if (Array.isArray(value) && (value[0] === "->" || value[0] === "=>")) {
3724
3763
  const [, , hookBody] = value;
3725
- const bodyCode = this.generateInComponent(hookBody, "value");
3726
- lines.push(` ${name}() { return ${bodyCode}; }`);
3764
+ const transformed = this.reactiveMembers ? this.transformComponentMembers(hookBody) : hookBody;
3765
+ const isAsync = this.containsAwait(hookBody);
3766
+ const bodyCode = this.generateFunctionBody(transformed, []);
3767
+ lines.push(` ${isAsync ? "async " : ""}${name}() ${bodyCode}`);
3727
3768
  }
3728
3769
  }
3729
3770
  if (renderBlock) {
@@ -3829,8 +3870,11 @@ ${blockFactoriesCode}return ${lines.join(`
3829
3870
  this._setupLines.push(`__effect(() => { ${textVar2}.data = this.${str}.value; });`);
3830
3871
  return textVar2;
3831
3872
  }
3873
+ const [tagStr, idStr] = str.split("#");
3832
3874
  const elVar = this.newElementVar();
3833
- this._createLines.push(`${elVar} = document.createElement('${str}');`);
3875
+ this._createLines.push(`${elVar} = document.createElement('${tagStr || "div"}');`);
3876
+ if (idStr)
3877
+ this._createLines.push(`${elVar}.id = '${idStr}';`);
3834
3878
  return elVar;
3835
3879
  }
3836
3880
  if (!Array.isArray(sexpr)) {
@@ -3844,7 +3888,8 @@ ${blockFactoriesCode}return ${lines.join(`
3844
3888
  return this.generateChildComponent(headStr, rest);
3845
3889
  }
3846
3890
  if (headStr && this.isHtmlTag(headStr)) {
3847
- return this.generateTag(headStr, [], rest);
3891
+ let [tagName, id] = headStr.split("#");
3892
+ return this.generateTag(tagName || "div", [], rest, id);
3848
3893
  }
3849
3894
  if (headStr === ".") {
3850
3895
  const [, obj, prop] = sexpr;
@@ -3859,9 +3904,9 @@ ${blockFactoriesCode}return ${lines.join(`
3859
3904
  this._createLines.push(`${slotVar} = this.${prop} instanceof Node ? this.${prop} : (this.${prop} != null ? document.createTextNode(String(this.${prop})) : document.createComment(''));`);
3860
3905
  return slotVar;
3861
3906
  }
3862
- const { tag, classes } = this.collectTemplateClasses(sexpr);
3907
+ const { tag, classes, id } = this.collectTemplateClasses(sexpr);
3863
3908
  if (tag && this.isHtmlTag(tag)) {
3864
- return this.generateTag(tag, classes, []);
3909
+ return this.generateTag(tag, classes, [], id);
3865
3910
  }
3866
3911
  const textVar2 = this.newTextVar();
3867
3912
  const exprCode2 = this.generateInComponent(sexpr, "value");
@@ -3874,12 +3919,12 @@ ${blockFactoriesCode}return ${lines.join(`
3874
3919
  const classExprs = head.slice(1);
3875
3920
  return this.generateDynamicTag(tag2, classExprs, rest);
3876
3921
  }
3877
- const { tag, classes } = this.collectTemplateClasses(head);
3922
+ const { tag, classes, id } = this.collectTemplateClasses(head);
3878
3923
  if (tag && this.isHtmlTag(tag)) {
3879
3924
  if (classes.length === 1 && classes[0] === "__clsx") {
3880
3925
  return this.generateDynamicTag(tag, rest, []);
3881
3926
  }
3882
- return this.generateTag(tag, classes, rest);
3927
+ return this.generateTag(tag, classes, rest, id);
3883
3928
  }
3884
3929
  }
3885
3930
  if (headStr === "->" || headStr === "=>") {
@@ -3901,14 +3946,9 @@ ${blockFactoriesCode}return ${lines.join(`
3901
3946
  }
3902
3947
  return textVar;
3903
3948
  };
3904
- proto.generateTag = function(tag, classes, args) {
3905
- const elVar = this.newElementVar();
3906
- this._createLines.push(`${elVar} = document.createElement('${tag}');`);
3907
- if (classes.length > 0) {
3908
- this._createLines.push(`${elVar}.className = '${classes.join(" ")}';`);
3909
- }
3949
+ proto.appendChildren = function(elVar, args) {
3910
3950
  for (const arg of args) {
3911
- if (Array.isArray(arg) && (arg[0] === "->" || arg[0] === "=>")) {
3951
+ if (this.is(arg, "->") || this.is(arg, "=>")) {
3912
3952
  const block = arg[2];
3913
3953
  if (this.is(block, "block")) {
3914
3954
  for (const child of block.slice(1)) {
@@ -3921,29 +3961,18 @@ ${blockFactoriesCode}return ${lines.join(`
3921
3961
  }
3922
3962
  } else if (this.is(arg, "object")) {
3923
3963
  this.generateAttributes(elVar, arg);
3924
- } else if (typeof arg === "string") {
3964
+ } else if (typeof arg === "string" || arg instanceof String) {
3925
3965
  const textVar = this.newTextVar();
3926
- if (arg.startsWith('"') || arg.startsWith("'") || arg.startsWith("`")) {
3927
- this._createLines.push(`${textVar} = document.createTextNode(${arg});`);
3928
- } else if (this.reactiveMembers && this.reactiveMembers.has(arg)) {
3929
- this._createLines.push(`${textVar} = document.createTextNode('');`);
3930
- this._setupLines.push(`__effect(() => { ${textVar}.data = this.${arg}.value; });`);
3931
- } else if (this.componentMembers && this.componentMembers.has(arg)) {
3932
- this._createLines.push(`${textVar} = document.createTextNode(String(this.${arg}));`);
3933
- } else {
3934
- this._createLines.push(`${textVar} = document.createTextNode(String(${arg}));`);
3935
- }
3936
- this._createLines.push(`${elVar}.appendChild(${textVar});`);
3937
- } else if (arg instanceof String) {
3938
3966
  const val = arg.valueOf();
3939
- const textVar = this.newTextVar();
3940
3967
  if (val.startsWith('"') || val.startsWith("'") || val.startsWith("`")) {
3941
3968
  this._createLines.push(`${textVar} = document.createTextNode(${val});`);
3942
3969
  } else if (this.reactiveMembers && this.reactiveMembers.has(val)) {
3943
3970
  this._createLines.push(`${textVar} = document.createTextNode('');`);
3944
3971
  this._setupLines.push(`__effect(() => { ${textVar}.data = this.${val}.value; });`);
3972
+ } else if (this.componentMembers && this.componentMembers.has(val)) {
3973
+ this._createLines.push(`${textVar} = document.createTextNode(String(this.${val}));`);
3945
3974
  } else {
3946
- this._createLines.push(`${textVar} = document.createTextNode(String(${val}));`);
3975
+ this._createLines.push(`${textVar} = document.createTextNode(${this.generateInComponent(arg, "value")});`);
3947
3976
  }
3948
3977
  this._createLines.push(`${elVar}.appendChild(${textVar});`);
3949
3978
  } else if (arg) {
@@ -3951,6 +3980,17 @@ ${blockFactoriesCode}return ${lines.join(`
3951
3980
  this._createLines.push(`${elVar}.appendChild(${childVar});`);
3952
3981
  }
3953
3982
  }
3983
+ };
3984
+ proto.generateTag = function(tag, classes, args, id) {
3985
+ const elVar = this.newElementVar();
3986
+ this._createLines.push(`${elVar} = document.createElement('${tag}');`);
3987
+ if (id) {
3988
+ this._createLines.push(`${elVar}.id = '${id}';`);
3989
+ }
3990
+ if (classes.length > 0) {
3991
+ this._createLines.push(`${elVar}.className = '${classes.join(" ")}';`);
3992
+ }
3993
+ this.appendChildren(elVar, args);
3954
3994
  return elVar;
3955
3995
  };
3956
3996
  proto.generateDynamicTag = function(tag, classExprs, children) {
@@ -3958,46 +3998,9 @@ ${blockFactoriesCode}return ${lines.join(`
3958
3998
  this._createLines.push(`${elVar} = document.createElement('${tag}');`);
3959
3999
  if (classExprs.length > 0) {
3960
4000
  const classArgs = classExprs.map((e) => this.generateInComponent(e, "value")).join(", ");
3961
- const hasReactive = classExprs.some((e) => this.hasReactiveDeps(e));
3962
- if (hasReactive) {
3963
- this._setupLines.push(`__effect(() => { ${elVar}.className = __clsx(${classArgs}); });`);
3964
- } else {
3965
- this._createLines.push(`${elVar}.className = __clsx(${classArgs});`);
3966
- }
3967
- }
3968
- for (const arg of children) {
3969
- const argHead = Array.isArray(arg) ? arg[0] instanceof String ? arg[0].valueOf() : arg[0] : null;
3970
- if (argHead === "->" || argHead === "=>") {
3971
- const block = arg[2];
3972
- const blockHead = Array.isArray(block) ? block[0] instanceof String ? block[0].valueOf() : block[0] : null;
3973
- if (blockHead === "block") {
3974
- for (const child of block.slice(1)) {
3975
- const childVar = this.generateNode(child);
3976
- this._createLines.push(`${elVar}.appendChild(${childVar});`);
3977
- }
3978
- } else if (block) {
3979
- const childVar = this.generateNode(block);
3980
- this._createLines.push(`${elVar}.appendChild(${childVar});`);
3981
- }
3982
- } else if (this.is(arg, "object")) {
3983
- this.generateAttributes(elVar, arg);
3984
- } else if (typeof arg === "string" || arg instanceof String) {
3985
- const textVar = this.newTextVar();
3986
- const argStr = arg.valueOf();
3987
- if (argStr.startsWith('"') || argStr.startsWith("'") || argStr.startsWith("`")) {
3988
- this._createLines.push(`${textVar} = document.createTextNode(${argStr});`);
3989
- } else if (this.reactiveMembers && this.reactiveMembers.has(argStr)) {
3990
- this._createLines.push(`${textVar} = document.createTextNode('');`);
3991
- this._setupLines.push(`__effect(() => { ${textVar}.data = this.${argStr}.value; });`);
3992
- } else {
3993
- this._createLines.push(`${textVar} = document.createTextNode(${this.generateInComponent(arg, "value")});`);
3994
- }
3995
- this._createLines.push(`${elVar}.appendChild(${textVar});`);
3996
- } else {
3997
- const childVar = this.generateNode(arg);
3998
- this._createLines.push(`${elVar}.appendChild(${childVar});`);
3999
- }
4001
+ this._setupLines.push(`__effect(() => { ${elVar}.className = __clsx(${classArgs}); });`);
4000
4002
  }
4003
+ this.appendChildren(elVar, children);
4001
4004
  return elVar;
4002
4005
  };
4003
4006
  proto.generateAttributes = function(elVar, objExpr) {
@@ -4018,6 +4021,11 @@ ${blockFactoriesCode}return ${lines.join(`
4018
4021
  if (key.startsWith('"') && key.endsWith('"')) {
4019
4022
  key = key.slice(1, -1);
4020
4023
  }
4024
+ if (key === "ref") {
4025
+ const refName = String(value).replace(/^["']|["']$/g, "");
4026
+ this._createLines.push(`this.${refName} = ${elVar};`);
4027
+ continue;
4028
+ }
4021
4029
  if (key.startsWith(BIND_PREFIX) && key.endsWith(BIND_SUFFIX)) {
4022
4030
  const prop = key.slice(BIND_PREFIX.length, -BIND_SUFFIX.length);
4023
4031
  const valueCode2 = this.generateInComponent(value, "value");
@@ -4302,6 +4310,7 @@ ${blockFactoriesCode}return ${lines.join(`
4302
4310
  const { propsCode, childrenSetupLines } = this.buildComponentProps(args);
4303
4311
  this._createLines.push(`${instVar} = new ${componentName}(${propsCode});`);
4304
4312
  this._createLines.push(`${elVar} = ${instVar}._create();`);
4313
+ this._createLines.push(`(this._children || (this._children = [])).push(${instVar});`);
4305
4314
  this._setupLines.push(`if (${instVar}._setup) ${instVar}._setup();`);
4306
4315
  for (const line of childrenSetupLines) {
4307
4316
  this._setupLines.push(line);
@@ -4317,7 +4326,10 @@ ${blockFactoriesCode}return ${lines.join(`
4317
4326
  for (let i = 1;i < arg.length; i++) {
4318
4327
  const [key, value] = arg[i];
4319
4328
  if (typeof key === "string") {
4329
+ const prevReactive = this.reactiveMembers;
4330
+ this.reactiveMembers = new Set;
4320
4331
  const valueCode = this.generateInComponent(value, "value");
4332
+ this.reactiveMembers = prevReactive;
4321
4333
  props.push(`${key}: ${valueCode}`);
4322
4334
  }
4323
4335
  }
@@ -4345,15 +4357,16 @@ ${blockFactoriesCode}return ${lines.join(`
4345
4357
  return { propsCode, childrenSetupLines };
4346
4358
  };
4347
4359
  proto.hasReactiveDeps = function(sexpr) {
4348
- if (!this.reactiveMembers || this.reactiveMembers.size === 0)
4349
- return false;
4350
4360
  if (typeof sexpr === "string") {
4351
- return this.reactiveMembers.has(sexpr);
4361
+ return !!(this.reactiveMembers && this.reactiveMembers.has(sexpr));
4352
4362
  }
4353
4363
  if (!Array.isArray(sexpr))
4354
4364
  return false;
4355
4365
  if (sexpr[0] === "." && sexpr[1] === "this" && typeof sexpr[2] === "string") {
4356
- return this.reactiveMembers.has(sexpr[2]);
4366
+ return !!(this.reactiveMembers && this.reactiveMembers.has(sexpr[2]));
4367
+ }
4368
+ if (sexpr[0] === "." && this._rootsAtThis(sexpr[1])) {
4369
+ return true;
4357
4370
  }
4358
4371
  for (const child of sexpr) {
4359
4372
  if (this.hasReactiveDeps(child))
@@ -4361,6 +4374,13 @@ ${blockFactoriesCode}return ${lines.join(`
4361
4374
  }
4362
4375
  return false;
4363
4376
  };
4377
+ proto._rootsAtThis = function(sexpr) {
4378
+ if (typeof sexpr === "string")
4379
+ return sexpr === "this";
4380
+ if (!Array.isArray(sexpr) || sexpr[0] !== ".")
4381
+ return false;
4382
+ return this._rootsAtThis(sexpr[1]);
4383
+ };
4364
4384
  proto.getComponentRuntime = function() {
4365
4385
  return `
4366
4386
  // ============================================================================
@@ -4426,6 +4446,11 @@ class __Component {
4426
4446
  return this;
4427
4447
  }
4428
4448
  unmount() {
4449
+ if (this._children) {
4450
+ for (const child of this._children) {
4451
+ child.unmount();
4452
+ }
4453
+ }
4429
4454
  if (this.unmounted) this.unmounted();
4430
4455
  if (this._root && this._root.parentNode) {
4431
4456
  this._root.parentNode.removeChild(this._root);
@@ -4717,6 +4742,7 @@ class CodeGenerator {
4717
4742
  ">>": "generateBinaryOp",
4718
4743
  ">>>": "generateBinaryOp",
4719
4744
  "%%": "generateModulo",
4745
+ "%%=": "generateModuloAssign",
4720
4746
  "//": "generateFloorDiv",
4721
4747
  "//=": "generateFloorDivAssign",
4722
4748
  "..": "generateRange",
@@ -4767,9 +4793,7 @@ class CodeGenerator {
4767
4793
  readonly: "generateReadonly",
4768
4794
  effect: "generateEffect",
4769
4795
  break: "generateBreak",
4770
- "break-if": "generateBreakIf",
4771
4796
  continue: "generateContinue",
4772
- "continue-if": "generateContinueIf",
4773
4797
  "?": "generateExistential",
4774
4798
  "?:": "generateTernary",
4775
4799
  "|>": "generatePipe",
@@ -4779,12 +4803,10 @@ class CodeGenerator {
4779
4803
  yield: "generateYield",
4780
4804
  "yield-from": "generateYieldFrom",
4781
4805
  if: "generateIf",
4782
- unless: "generateIf",
4783
4806
  "for-in": "generateForIn",
4784
4807
  "for-of": "generateForOf",
4785
4808
  "for-as": "generateForAs",
4786
4809
  while: "generateWhile",
4787
- until: "generateUntil",
4788
4810
  try: "generateTry",
4789
4811
  throw: "generateThrow",
4790
4812
  control: "generateControl",
@@ -4860,7 +4882,7 @@ class CodeGenerator {
4860
4882
  continue;
4861
4883
  if (trimmed.startsWith("let ") || trimmed.startsWith("var "))
4862
4884
  continue;
4863
- if (trimmed.startsWith("const slice") || trimmed.startsWith("const modulo") || trimmed.startsWith("const toSearchable"))
4885
+ if (trimmed.startsWith("const slice") || trimmed.startsWith("const modulo") || trimmed.startsWith("const toMatchable"))
4864
4886
  continue;
4865
4887
  if (trimmed.startsWith("const {") && trimmed.includes("__"))
4866
4888
  continue;
@@ -4896,6 +4918,8 @@ class CodeGenerator {
4896
4918
  }
4897
4919
  if (head === "readonly")
4898
4920
  return;
4921
+ if (head === "component")
4922
+ return;
4899
4923
  if (CodeGenerator.ASSIGNMENT_OPS.has(head)) {
4900
4924
  let [target, value] = rest;
4901
4925
  if (typeof target === "string" || target instanceof String) {
@@ -4920,12 +4944,6 @@ class CodeGenerator {
4920
4944
  this.collectProgramVariables(elseBranch);
4921
4945
  return;
4922
4946
  }
4923
- if (head === "unless") {
4924
- let [condition, body] = rest;
4925
- this.collectProgramVariables(condition);
4926
- this.collectProgramVariables(body);
4927
- return;
4928
- }
4929
4947
  if (head === "try") {
4930
4948
  this.collectProgramVariables(rest[0]);
4931
4949
  if (rest.length >= 2 && Array.isArray(rest[1]) && rest[1].length === 2 && rest[1][0] !== "block") {
@@ -5082,7 +5100,7 @@ class CodeGenerator {
5082
5100
  let condCode = this.generate(cond.condition, "value");
5083
5101
  let valCode = this.generate(argWithout, "value");
5084
5102
  let callStr2 = `${callee}(${valCode})`;
5085
- return cond.type === "unless" ? `if (!${condCode}) ${callStr2}` : `if (${condCode}) ${callStr2}`;
5103
+ return `if (${condCode}) ${callStr2}`;
5086
5104
  }
5087
5105
  }
5088
5106
  let needsAwait = headAwaitMeta === true;
@@ -5092,7 +5110,7 @@ class CodeGenerator {
5092
5110
  return needsAwait ? `await ${callStr}` : callStr;
5093
5111
  }
5094
5112
  if (Array.isArray(head) && typeof head[0] === "string") {
5095
- let stmtOps = ["=", "+=", "-=", "*=", "/=", "%=", "**=", "&&=", "||=", "??=", "if", "unless", "return", "throw"];
5113
+ let stmtOps = ["=", "+=", "-=", "*=", "/=", "%=", "**=", "&&=", "||=", "??=", "if", "return", "throw"];
5096
5114
  if (stmtOps.includes(head[0])) {
5097
5115
  let exprs = sexpr.map((stmt) => this.generate(stmt, "value"));
5098
5116
  return `(${exprs.join(", ")})`;
@@ -5114,7 +5132,7 @@ class CodeGenerator {
5114
5132
  let condCode = this.generate(cond.condition, "value");
5115
5133
  let valCode = this.generate(argWithout, "value");
5116
5134
  let callStr2 = `${calleeCode2}(${valCode})`;
5117
- return cond.type === "unless" ? `if (!${condCode}) ${callStr2}` : `if (${condCode}) ${callStr2}`;
5135
+ return `if (${condCode}) ${callStr2}`;
5118
5136
  }
5119
5137
  }
5120
5138
  let needsAwait = false;
@@ -5151,7 +5169,7 @@ class CodeGenerator {
5151
5169
  else
5152
5170
  other.push(stmt);
5153
5171
  }
5154
- let blockStmts = ["def", "class", "if", "unless", "for-in", "for-of", "for-as", "while", "until", "loop", "switch", "try"];
5172
+ let blockStmts = ["def", "class", "if", "for-in", "for-of", "for-as", "while", "loop", "switch", "try"];
5155
5173
  let statementsCode = other.map((stmt, index) => {
5156
5174
  let isSingle = other.length === 1 && imports.length === 0 && exports.length === 0;
5157
5175
  let isObj = this.is(stmt, "object");
@@ -5203,8 +5221,8 @@ class CodeGenerator {
5203
5221
  `;
5204
5222
  needsBlank = true;
5205
5223
  }
5206
- if (this.helpers.has("toSearchable")) {
5207
- code += `const toSearchable = (v, allowNewlines) => {
5224
+ if (this.helpers.has("toMatchable")) {
5225
+ code += `const toMatchable = (v, allowNewlines) => {
5208
5226
  `;
5209
5227
  code += ` if (typeof v === "string") return !allowNewlines && /[\\n\\r]/.test(v) ? null : v;
5210
5228
  `;
@@ -5315,6 +5333,12 @@ function _setDataSection() {
5315
5333
  this.helpers.add("modulo");
5316
5334
  return `modulo(${this.generate(left, "value")}, ${this.generate(right, "value")})`;
5317
5335
  }
5336
+ generateModuloAssign(head, rest) {
5337
+ let [target, value] = rest;
5338
+ this.helpers.add("modulo");
5339
+ let t = this.generate(target, "value"), v = this.generate(value, "value");
5340
+ return `${t} = modulo(${t}, ${v})`;
5341
+ }
5318
5342
  generateFloorDiv(head, rest) {
5319
5343
  let [left, right] = rest;
5320
5344
  return `Math.floor(${this.generate(left, "value")} / ${this.generate(right, "value")})`;
@@ -5398,27 +5422,22 @@ function _setDataSection() {
5398
5422
  }
5399
5423
  if (context === "statement" && head === "=" && Array.isArray(value) && (value[0] === "||" || value[0] === "&&") && value.length === 3) {
5400
5424
  let [binOp, left, right] = value;
5401
- if ((this.is(right, "unless") || this.is(right, "if")) && right.length === 3) {
5402
- let [condType, condition, wrappedValue] = right;
5425
+ if (this.is(right, "if") && right.length === 3) {
5426
+ let [, condition, wrappedValue] = right;
5403
5427
  let unwrapped = Array.isArray(wrappedValue) && wrappedValue.length === 1 ? wrappedValue[0] : wrappedValue;
5404
5428
  let fullValue = [binOp, left, unwrapped];
5405
5429
  let t = this.generate(target, "value"), c = this.generate(condition, "value"), v = this.generate(fullValue, "value");
5406
- return condType === "unless" ? `if (!${c}) ${t} = ${v}` : `if (${c}) ${t} = ${v}`;
5430
+ return `if (${c}) ${t} = ${v}`;
5407
5431
  }
5408
5432
  }
5409
5433
  if (context === "statement" && head === "=" && Array.isArray(value) && value.length === 3) {
5410
5434
  let [valHead, condition, actualValue] = value;
5411
5435
  let isPostfix = Array.isArray(actualValue) && actualValue.length === 1 && (!Array.isArray(actualValue[0]) || actualValue[0][0] !== "block");
5412
- if ((valHead === "unless" || valHead === "if") && isPostfix) {
5436
+ if (valHead === "if" && isPostfix) {
5413
5437
  let unwrapped = Array.isArray(actualValue) && actualValue.length === 1 ? actualValue[0] : actualValue;
5414
5438
  let t = this.generate(target, "value");
5415
5439
  let condCode = this.unwrapLogical(this.generate(condition, "value"));
5416
5440
  let v = this.generate(unwrapped, "value");
5417
- if (valHead === "unless") {
5418
- if (condCode.includes(" ") || /[<>=&|]/.test(condCode))
5419
- condCode = `(${condCode})`;
5420
- return `if (!${condCode}) ${t} = ${v}`;
5421
- }
5422
5441
  return `if (${condCode}) ${t} = ${v}`;
5423
5442
  }
5424
5443
  }
@@ -5444,10 +5463,15 @@ function _setDataSection() {
5444
5463
  }
5445
5464
  generatePropertyAccess(head, rest, context, sexpr) {
5446
5465
  let [obj, prop] = rest;
5466
+ if (this._atParamMap && obj === "this") {
5467
+ let mapped = this._atParamMap.get(str(prop));
5468
+ if (mapped)
5469
+ return mapped;
5470
+ }
5447
5471
  this.suppressReactiveUnwrap = true;
5448
5472
  let objCode = this.generate(obj, "value");
5449
5473
  this.suppressReactiveUnwrap = false;
5450
- let needsParens = CodeGenerator.NUMBER_LITERAL_RE.test(objCode) || (this.is(obj, "object") || this.is(obj, "await") || this.is(obj, "yield"));
5474
+ let needsParens = CodeGenerator.NUMBER_LITERAL_RE.test(objCode) || objCode.startsWith("await ") || (this.is(obj, "object") || this.is(obj, "yield"));
5451
5475
  let base = needsParens ? `(${objCode})` : objCode;
5452
5476
  if (meta(prop, "await") === true)
5453
5477
  return `await ${base}.${str(prop)}()`;
@@ -5461,12 +5485,12 @@ function _setDataSection() {
5461
5485
  }
5462
5486
  generateRegexIndex(head, rest) {
5463
5487
  let [value, regex, captureIndex] = rest;
5464
- this.helpers.add("toSearchable");
5488
+ this.helpers.add("toMatchable");
5465
5489
  this.programVars.add("_");
5466
5490
  let v = this.generate(value, "value"), r = this.generate(regex, "value");
5467
5491
  let idx = captureIndex !== null ? this.generate(captureIndex, "value") : "0";
5468
5492
  let allowNL = r.includes("/m") ? ", true" : "";
5469
- return `(_ = toSearchable(${v}${allowNL}).match(${r})) && _[${idx}]`;
5493
+ return `(_ = toMatchable(${v}${allowNL}).match(${r})) && _[${idx}]`;
5470
5494
  }
5471
5495
  generateIndexAccess(head, rest) {
5472
5496
  let [arr, index] = rest;
@@ -5566,11 +5590,6 @@ function _setDataSection() {
5566
5590
  let [expr] = rest;
5567
5591
  if (this.sideEffectOnly)
5568
5592
  return "return";
5569
- if (this.is(expr, "unless")) {
5570
- let [, condition, body] = expr;
5571
- let val = Array.isArray(body) && body.length === 1 ? body[0] : body;
5572
- return `if (!${this.generate(condition, "value")}) return ${this.generate(val, "value")}`;
5573
- }
5574
5593
  if (this.is(expr, "if")) {
5575
5594
  let [, condition, body, ...elseParts] = expr;
5576
5595
  if (elseParts.length === 0) {
@@ -5578,11 +5597,10 @@ function _setDataSection() {
5578
5597
  return `if (${this.generate(condition, "value")}) return ${this.generate(val, "value")}`;
5579
5598
  }
5580
5599
  }
5581
- if (this.is(expr, "new") && Array.isArray(expr[1]) && expr[1][0] === "unless") {
5582
- let [, unlessNode] = expr;
5583
- let [, condition, body] = unlessNode;
5600
+ if (this.is(expr, "new") && Array.isArray(expr[1]) && expr[1][0] === "if") {
5601
+ let [, condition, body] = expr[1];
5584
5602
  let val = Array.isArray(body) && body.length === 1 ? body[0] : body;
5585
- return `if (!${this.generate(condition, "value")}) return ${this.generate(["new", val], "value")}`;
5603
+ return `if (${this.generate(condition, "value")}) return ${this.generate(["new", val], "value")}`;
5586
5604
  }
5587
5605
  return `return ${this.generate(expr, "value")}`;
5588
5606
  }
@@ -5634,15 +5652,9 @@ ${this.indent()}}`;
5634
5652
  generateBreak() {
5635
5653
  return "break";
5636
5654
  }
5637
- generateBreakIf(head, rest) {
5638
- return `if (${this.generate(rest[0], "value")}) break`;
5639
- }
5640
5655
  generateContinue() {
5641
5656
  return "continue";
5642
5657
  }
5643
- generateContinueIf(head, rest) {
5644
- return `if (${this.generate(rest[0], "value")}) continue`;
5645
- }
5646
5658
  generateExistential(head, rest) {
5647
5659
  return `(${this.generate(rest[0], "value")} != null)`;
5648
5660
  }
@@ -5689,18 +5701,6 @@ ${this.indent()}}`;
5689
5701
  return `yield* ${this.generate(rest[0], "value")}`;
5690
5702
  }
5691
5703
  generateIf(head, rest, context, sexpr) {
5692
- if (head === "unless") {
5693
- let [condition2, body] = rest;
5694
- if (Array.isArray(body) && body.length === 1 && (!Array.isArray(body[0]) || body[0][0] !== "block"))
5695
- body = body[0];
5696
- if (context === "value") {
5697
- return `(!${this.generate(condition2, "value")} ? ${this.extractExpression(body)} : undefined)`;
5698
- }
5699
- let condCode = this.unwrap(this.generate(condition2, "value"));
5700
- if (/[ <>=&|]/.test(condCode))
5701
- condCode = `(${condCode})`;
5702
- return `if (!${condCode}) ` + this.generate(body, "statement");
5703
- }
5704
5704
  let [condition, thenBranch, ...elseBranches] = rest;
5705
5705
  return context === "value" ? this.generateIfAsExpression(condition, thenBranch, elseBranches) : this.generateIfAsStatement(condition, thenBranch, elseBranches);
5706
5706
  }
@@ -5919,10 +5919,6 @@ ${this.indent()}}`;
5919
5919
  let code = `while (${this.unwrap(this.generate(cond, "value"))}) `;
5920
5920
  return code + (guard ? this.generateLoopBodyWithGuard(body, guard) : this.generateLoopBody(body));
5921
5921
  }
5922
- generateUntil(head, rest) {
5923
- let [cond, body] = rest;
5924
- return `while (!(${this.unwrap(this.generate(cond, "value"))})) ` + this.generateLoopBody(body);
5925
- }
5926
5922
  generateRange(head, rest) {
5927
5923
  if (head === "...") {
5928
5924
  if (rest.length === 1)
@@ -5988,11 +5984,11 @@ ${this.indent()}}`;
5988
5984
  }
5989
5985
  generateRegexMatch(head, rest) {
5990
5986
  let [left, right] = rest;
5991
- this.helpers.add("toSearchable");
5987
+ this.helpers.add("toMatchable");
5992
5988
  this.programVars.add("_");
5993
5989
  let r = this.generate(right, "value");
5994
5990
  let allowNL = r.includes("/m") ? ", true" : "";
5995
- return `(_ = toSearchable(${this.generate(left, "value")}${allowNL}).match(${r}))`;
5991
+ return `(_ = toMatchable(${this.generate(left, "value")}${allowNL}).match(${r}))`;
5996
5992
  }
5997
5993
  generateNew(head, rest) {
5998
5994
  let [call] = rest;
@@ -6053,8 +6049,11 @@ ${this.indent()}}`;
6053
6049
  keyCode = `[${this.generate(key[1], "value")}]`;
6054
6050
  else if (this.is(key, "str"))
6055
6051
  keyCode = `[${this.generate(key, "value")}]`;
6056
- else
6052
+ else {
6053
+ this.suppressReactiveUnwrap = true;
6057
6054
  keyCode = this.generate(key, "value");
6055
+ this.suppressReactiveUnwrap = false;
6056
+ }
6058
6057
  let valCode = this.generate(value, "value");
6059
6058
  if (operator === "=")
6060
6059
  return `${keyCode} = ${valCode}`;
@@ -6120,21 +6119,19 @@ ${this.indent()}}`;
6120
6119
  let [expr] = rest;
6121
6120
  if (Array.isArray(expr)) {
6122
6121
  let checkExpr = expr, wrapperType = null;
6123
- if (expr[0] === "new" && Array.isArray(expr[1]) && (expr[1][0] === "if" || expr[1][0] === "unless")) {
6122
+ if (expr[0] === "new" && Array.isArray(expr[1]) && expr[1][0] === "if") {
6124
6123
  wrapperType = "new";
6125
6124
  checkExpr = expr[1];
6126
- } else if (expr[0] === "if" || expr[0] === "unless") {
6125
+ } else if (expr[0] === "if") {
6127
6126
  checkExpr = expr;
6128
6127
  }
6129
- if (checkExpr[0] === "if" || checkExpr[0] === "unless") {
6130
- let [condType, condition, body] = checkExpr;
6128
+ if (checkExpr[0] === "if") {
6129
+ let [, condition, body] = checkExpr;
6131
6130
  let unwrapped = Array.isArray(body) && body.length === 1 ? body[0] : body;
6132
6131
  expr = wrapperType === "new" ? ["new", unwrapped] : unwrapped;
6133
6132
  let condCode = this.generate(condition, "value");
6134
6133
  let throwCode = `throw ${this.generate(expr, "value")}`;
6135
- return condType === "unless" ? `if (!(${condCode})) {
6136
- ${this.indent()} ${throwCode};
6137
- ${this.indent()}}` : `if (${condCode}) {
6134
+ return `if (${condCode}) {
6138
6135
  ${this.indent()} ${throwCode};
6139
6136
  ${this.indent()}}`;
6140
6137
  }
@@ -6206,6 +6203,52 @@ ${this.indent()}}`;
6206
6203
  generateWhen() {
6207
6204
  throw new Error("when clause should be handled by switch");
6208
6205
  }
6206
+ _forInHeader(vars, iterable, step) {
6207
+ let va = Array.isArray(vars) ? vars : [vars];
6208
+ let noVar = va.length === 0;
6209
+ let [itemVar, indexVar] = noVar ? ["_i", null] : va;
6210
+ let ivp = this.is(itemVar, "array") || this.is(itemVar, "object") ? this.generateDestructuringPattern(itemVar) : itemVar;
6211
+ if (step && step !== null) {
6212
+ let ih = Array.isArray(iterable) && iterable[0];
6213
+ if (ih instanceof String)
6214
+ ih = str(ih);
6215
+ let isRange = ih === ".." || ih === "...";
6216
+ if (isRange) {
6217
+ let isExcl = ih === "...";
6218
+ let [s, e] = iterable.slice(1);
6219
+ let sc = this.generate(s, "value"), ec = this.generate(e, "value"), stc2 = this.generate(step, "value");
6220
+ return { header: `for (let ${ivp} = ${sc}; ${ivp} ${isExcl ? "<" : "<="} ${ec}; ${ivp} += ${stc2})`, setup: null };
6221
+ }
6222
+ let ic = this.generate(iterable, "value"), idxN = indexVar || "_i", stc = this.generate(step, "value");
6223
+ let isNeg = this.is(step, "-", 1);
6224
+ let isMinus1 = isNeg && (step[1] === "1" || step[1] === 1 || str(step[1]) === "1");
6225
+ let isPlus1 = !isNeg && (step === "1" || step === 1 || str(step) === "1");
6226
+ let update = isMinus1 ? `${idxN}--` : isPlus1 ? `${idxN}++` : `${idxN} += ${stc}`;
6227
+ let header = isNeg ? `for (let ${idxN} = ${ic}.length - 1; ${idxN} >= 0; ${update})` : `for (let ${idxN} = 0; ${idxN} < ${ic}.length; ${update})`;
6228
+ return { header, setup: noVar ? null : `const ${ivp} = ${ic}[${idxN}];` };
6229
+ }
6230
+ if (indexVar) {
6231
+ let ic = this.generate(iterable, "value");
6232
+ return {
6233
+ header: `for (let ${indexVar} = 0; ${indexVar} < ${ic}.length; ${indexVar}++)`,
6234
+ setup: `const ${ivp} = ${ic}[${indexVar}];`
6235
+ };
6236
+ }
6237
+ return { header: `for (const ${ivp} of ${this.generate(iterable, "value")})`, setup: null };
6238
+ }
6239
+ _forOfHeader(vars, iterable, own) {
6240
+ let va = Array.isArray(vars) ? vars : [vars];
6241
+ let [kv, vv] = va;
6242
+ let kvp = this.is(kv, "array") || this.is(kv, "object") ? this.generateDestructuringPattern(kv) : kv;
6243
+ let oc = this.generate(iterable, "value");
6244
+ return { header: `for (const ${kvp} in ${oc})`, own, vv, oc, kvp };
6245
+ }
6246
+ _forAsHeader(vars, iterable, isAwait) {
6247
+ let va = Array.isArray(vars) ? vars : [vars];
6248
+ let [fv] = va;
6249
+ let ivp = this.is(fv, "array") || this.is(fv, "object") ? this.generateDestructuringPattern(fv) : fv;
6250
+ return { header: `for ${isAwait ? "await " : ""}(const ${ivp} of ${this.generate(iterable, "value")})` };
6251
+ }
6209
6252
  generateComprehension(head, rest, context) {
6210
6253
  let [expr, iterators, guards] = rest;
6211
6254
  if (context === "statement")
@@ -6222,53 +6265,16 @@ ${this.indent()}}`;
6222
6265
  for (let iter of iterators) {
6223
6266
  let [iterType, vars, iterable, stepOrOwn] = iter;
6224
6267
  if (iterType === "for-in") {
6225
- let step = stepOrOwn;
6226
- let va = Array.isArray(vars) ? vars : [vars];
6227
- let noVar = va.length === 0;
6228
- let [itemVar, indexVar] = noVar ? ["_i", null] : va;
6229
- let ivp = this.is(itemVar, "array") || this.is(itemVar, "object") ? this.generateDestructuringPattern(itemVar) : itemVar;
6230
- if (step && step !== null) {
6231
- let ih = Array.isArray(iterable) && iterable[0];
6232
- if (ih instanceof String)
6233
- ih = str(ih);
6234
- let isRange = ih === ".." || ih === "...";
6235
- if (isRange) {
6236
- let isExcl = ih === "...";
6237
- let [s, e] = iterable.slice(1);
6238
- let sc = this.generate(s, "value"), ec = this.generate(e, "value"), stc = this.generate(step, "value");
6239
- code += this.indent() + `for (let ${ivp} = ${sc}; ${ivp} ${isExcl ? "<" : "<="} ${ec}; ${ivp} += ${stc}) {
6240
- `;
6241
- this.indentLevel++;
6242
- } else {
6243
- let ic = this.generate(iterable, "value"), idxN = indexVar || "_i", stc = this.generate(step, "value");
6244
- let isNeg = this.is(step, "-", 1);
6245
- code += isNeg ? this.indent() + `for (let ${idxN} = ${ic}.length - 1; ${idxN} >= 0; ${idxN} += ${stc}) {
6246
- ` : this.indent() + `for (let ${idxN} = 0; ${idxN} < ${ic}.length; ${idxN} += ${stc}) {
6247
- `;
6248
- this.indentLevel++;
6249
- if (!noVar)
6250
- code += this.indent() + `const ${ivp} = ${ic}[${idxN}];
6251
- `;
6252
- }
6253
- } else if (indexVar) {
6254
- let ic = this.generate(iterable, "value");
6255
- code += this.indent() + `for (let ${indexVar} = 0; ${indexVar} < ${ic}.length; ${indexVar}++) {
6268
+ let { header, setup } = this._forInHeader(vars, iterable, stepOrOwn);
6269
+ code += this.indent() + header + ` {
6256
6270
  `;
6257
- this.indentLevel++;
6258
- code += this.indent() + `const ${ivp} = ${ic}[${indexVar}];
6259
- `;
6260
- } else {
6261
- code += this.indent() + `for (const ${ivp} of ${this.generate(iterable, "value")}) {
6271
+ this.indentLevel++;
6272
+ if (setup)
6273
+ code += this.indent() + setup + `
6262
6274
  `;
6263
- this.indentLevel++;
6264
- }
6265
6275
  } else if (iterType === "for-of") {
6266
- let own = stepOrOwn;
6267
- let va = Array.isArray(vars) ? vars : [vars];
6268
- let [kv, vv] = va;
6269
- let kvp = this.is(kv, "array") || this.is(kv, "object") ? this.generateDestructuringPattern(kv) : kv;
6270
- let oc = this.generate(iterable, "value");
6271
- code += this.indent() + `for (const ${kvp} in ${oc}) {
6276
+ let { header, own, vv, oc, kvp } = this._forOfHeader(vars, iterable, stepOrOwn);
6277
+ code += this.indent() + header + ` {
6272
6278
  `;
6273
6279
  this.indentLevel++;
6274
6280
  if (own)
@@ -6278,11 +6284,8 @@ ${this.indent()}}`;
6278
6284
  code += this.indent() + `const ${vv} = ${oc}[${kvp}];
6279
6285
  `;
6280
6286
  } else if (iterType === "for-as") {
6281
- let isAwait = iter[3];
6282
- let va = Array.isArray(vars) ? vars : [vars];
6283
- let [fv] = va;
6284
- let ivp = this.is(fv, "array") || this.is(fv, "object") ? this.generateDestructuringPattern(fv) : fv;
6285
- code += this.indent() + `for ${isAwait ? "await " : ""}(const ${ivp} of ${this.generate(iterable, "value")}) {
6287
+ let { header } = this._forAsHeader(vars, iterable, iter[3]);
6288
+ code += this.indent() + header + ` {
6286
6289
  `;
6287
6290
  this.indentLevel++;
6288
6291
  }
@@ -6297,13 +6300,13 @@ ${this.indent()}}`;
6297
6300
  return true;
6298
6301
  if (!Array.isArray(node))
6299
6302
  return false;
6300
- if (["break", "continue", "break-if", "continue-if", "return", "throw"].includes(node[0]))
6303
+ if (["break", "continue", "return", "throw"].includes(node[0]))
6301
6304
  return true;
6302
- if (node[0] === "if" || node[0] === "unless")
6305
+ if (node[0] === "if")
6303
6306
  return node.slice(1).some(hasCtrl);
6304
6307
  return node.some(hasCtrl);
6305
6308
  };
6306
- let loopStmts = ["for-in", "for-of", "for-as", "while", "until", "loop"];
6309
+ let loopStmts = ["for-in", "for-of", "for-as", "while", "loop"];
6307
6310
  if (this.is(expr, "block")) {
6308
6311
  for (let i = 0;i < expr.length - 1; i++) {
6309
6312
  let s = expr[i + 1], isLast = i === expr.length - 2;
@@ -6425,15 +6428,31 @@ ${this.indent()}}`;
6425
6428
  let hasAwait = this.containsAwait(body), hasYield = this.containsYield(body);
6426
6429
  let cleanParams = params, autoAssign = [];
6427
6430
  if (mName === "constructor") {
6431
+ let isSubclass = !!parentClass;
6432
+ let atParamMap = isSubclass ? new Map : null;
6428
6433
  cleanParams = params.map((p) => {
6429
6434
  if (this.is(p, ".") && p[1] === "this") {
6430
- autoAssign.push(`this.${p[2]} = ${p[2]}`);
6431
- return p[2];
6435
+ let name = p[2];
6436
+ let param = isSubclass ? `_${name}` : name;
6437
+ autoAssign.push(`this.${name} = ${param}`);
6438
+ if (isSubclass)
6439
+ atParamMap.set(name, param);
6440
+ return param;
6441
+ }
6442
+ if (this.is(p, "default") && this.is(p[1], ".") && p[1][1] === "this") {
6443
+ let name = p[1][2];
6444
+ let param = isSubclass ? `_${name}` : name;
6445
+ autoAssign.push(`this.${name} = ${param}`);
6446
+ if (isSubclass)
6447
+ atParamMap.set(name, param);
6448
+ return ["default", param, p[2]];
6432
6449
  }
6433
6450
  return p;
6434
6451
  });
6435
6452
  for (let bm of boundMethods)
6436
6453
  autoAssign.unshift(`this.${bm} = this.${bm}.bind(this)`);
6454
+ if (atParamMap?.size > 0)
6455
+ this._atParamMap = atParamMap;
6437
6456
  }
6438
6457
  let pList = this.generateParamList(cleanParams);
6439
6458
  let prefix = (isStatic ? "static " : "") + (hasAwait ? "async " : "") + (hasYield ? "*" : "");
@@ -6441,6 +6460,7 @@ ${this.indent()}}`;
6441
6460
  if (!isComputed)
6442
6461
  this.currentMethodName = mName;
6443
6462
  code += this.generateMethodBody(body, autoAssign, mName === "constructor", cleanParams);
6463
+ this._atParamMap = null;
6444
6464
  this.currentMethodName = null;
6445
6465
  code += `
6446
6466
  `;
@@ -6618,7 +6638,7 @@ export default ${expr[1]}`;
6618
6638
  if (!Array.isArray(expr))
6619
6639
  return null;
6620
6640
  let h = expr[0];
6621
- if ((h === "unless" || h === "if") && expr.length === 3)
6641
+ if (h === "if" && expr.length === 3)
6622
6642
  return { type: h, condition: expr[1], value: expr[2] };
6623
6643
  if (h === "+" || h === "-" || h === "*" || h === "/") {
6624
6644
  for (let i = 1;i < expr.length; i++) {
@@ -6727,7 +6747,7 @@ export default ${expr[1]}`;
6727
6747
  let bodyVars = this.collectFunctionVariables(body);
6728
6748
  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))));
6729
6749
  let noRetStmts = ["return", "throw", "break", "continue"];
6730
- let loopStmts = ["for-in", "for-of", "for-as", "while", "until", "loop"];
6750
+ let loopStmts = ["for-in", "for-of", "for-as", "while", "loop"];
6731
6751
  this.scopeStack.push(new Set([...newVars, ...paramNames]));
6732
6752
  if (this.is(body, "block")) {
6733
6753
  let statements = this.unwrapBlock(body);
@@ -6769,7 +6789,7 @@ export default ${expr[1]}`;
6769
6789
  `;
6770
6790
  return;
6771
6791
  }
6772
- if (!isConstructor && !sideEffectOnly && isLast && (h === "if" || h === "unless")) {
6792
+ if (!isConstructor && !sideEffectOnly && isLast && h === "if") {
6773
6793
  let [cond, thenB, ...elseB] = stmt.slice(1);
6774
6794
  let hasMulti = (b) => this.is(b, "block") && b.length > 2;
6775
6795
  if (hasMulti(thenB) || elseB.some(hasMulti)) {
@@ -6834,7 +6854,12 @@ export default ${expr[1]}`;
6834
6854
  }
6835
6855
  this.sideEffectOnly = prevSEO;
6836
6856
  let result;
6837
- if (isConstructor || this.hasExplicitControlFlow(body))
6857
+ if (isConstructor && autoAssignments.length > 0) {
6858
+ let isSuper = Array.isArray(body) && body[0] === "super";
6859
+ let bodyCode = this.generate(body, "statement");
6860
+ let assigns = autoAssignments.map((a) => `${a};`).join(" ");
6861
+ result = isSuper ? `{ ${bodyCode}; ${assigns} }` : `{ ${assigns} ${bodyCode}; }`;
6862
+ } else if (isConstructor || this.hasExplicitControlFlow(body))
6838
6863
  result = `{ ${this.generate(body, "statement")}; }`;
6839
6864
  else if (Array.isArray(body) && (noRetStmts.includes(body[0]) || loopStmts.includes(body[0])))
6840
6865
  result = `{ ${this.generate(body, "statement")}; }`;
@@ -6918,37 +6943,13 @@ ${this.indent()}}`;
6918
6943
  if (iterators.length === 1) {
6919
6944
  let [iterType, vars, iterable, stepOrOwn] = iterators[0];
6920
6945
  if (iterType === "for-in") {
6921
- let step = stepOrOwn;
6922
- let va = Array.isArray(vars) ? vars : [vars];
6923
- let noVar = va.length === 0;
6924
- let [itemVar, indexVar] = noVar ? ["_i", null] : va;
6925
- let ivp = this.is(itemVar, "array") || this.is(itemVar, "object") ? this.generateDestructuringPattern(itemVar) : itemVar;
6926
- if (step && step !== null) {
6927
- let ih = Array.isArray(iterable) && iterable[0];
6928
- if (ih instanceof String)
6929
- ih = str(ih);
6930
- let isRange = ih === ".." || ih === "...";
6931
- if (isRange) {
6932
- let isExcl = ih === "...";
6933
- let [s, e] = iterable.slice(1);
6934
- code += this.indent() + `for (let ${ivp} = ${this.generate(s, "value")}; ${ivp} ${isExcl ? "<" : "<="} ${this.generate(e, "value")}; ${ivp} += ${this.generate(step, "value")}) {
6946
+ let { header, setup } = this._forInHeader(vars, iterable, stepOrOwn);
6947
+ code += this.indent() + header + ` {
6935
6948
  `;
6936
- } else {
6937
- let ic = this.generate(iterable, "value"), idxN = indexVar || "_i", stc = this.generate(step, "value");
6938
- let isNeg = this.is(step, "-", 1);
6939
- code += isNeg ? this.indent() + `for (let ${idxN} = ${ic}.length - 1; ${idxN} >= 0; ${idxN} += ${stc}) {
6940
- ` : this.indent() + `for (let ${idxN} = 0; ${idxN} < ${ic}.length; ${idxN} += ${stc}) {
6941
- `;
6942
- this.indentLevel++;
6943
- if (!noVar)
6944
- code += this.indent() + `const ${ivp} = ${ic}[${idxN}];
6945
- `;
6946
- }
6947
- } else {
6948
- code += this.indent() + `for (const ${ivp} of ${this.generate(iterable, "value")}) {
6949
- `;
6950
- }
6951
6949
  this.indentLevel++;
6950
+ if (setup)
6951
+ code += this.indent() + setup + `
6952
+ `;
6952
6953
  if (guards && guards.length > 0) {
6953
6954
  code += this.indent() + `if (${guards.map((g) => this.generate(g, "value")).join(" && ")}) {
6954
6955
  `;
@@ -6972,229 +6973,59 @@ ${this.indent()}}`;
6972
6973
  }
6973
6974
  generateComprehensionAsLoop(expr, iterators, guards) {
6974
6975
  let code = "";
6975
- if (iterators.length === 1) {
6976
- let [iterType, vars, iterable, stepOrOwn] = iterators[0];
6977
- if (iterType === "for-in") {
6978
- let step = stepOrOwn;
6979
- let va = Array.isArray(vars) ? vars : [vars];
6980
- let noVar = va.length === 0;
6981
- let [itemVar, indexVar] = noVar ? ["_i", null] : va;
6982
- let ivp = this.is(itemVar, "array") || this.is(itemVar, "object") ? this.generateDestructuringPattern(itemVar) : itemVar;
6983
- if (step && step !== null) {
6984
- let ih = Array.isArray(iterable) && iterable[0];
6985
- if (ih instanceof String)
6986
- ih = str(ih);
6987
- let isRange = ih === ".." || ih === "...";
6988
- if (isRange) {
6989
- let isExcl = ih === "...";
6990
- let [s, e] = iterable.slice(1);
6991
- code += `for (let ${ivp} = ${this.generate(s, "value")}; ${ivp} ${isExcl ? "<" : "<="} ${this.generate(e, "value")}; ${ivp} += ${this.generate(step, "value")}) `;
6992
- } else {
6993
- let ic = this.generate(iterable, "value"), idxN = indexVar || "_i", stc = this.generate(step, "value");
6994
- let isNeg = this.is(step, "-", 1);
6995
- let isMinus1 = isNeg && (step[1] === "1" || step[1] === 1 || str(step[1]) === "1");
6996
- let isPlus1 = !isNeg && (step === "1" || step === 1 || str(step) === "1");
6997
- if (isMinus1)
6998
- code += `for (let ${idxN} = ${ic}.length - 1; ${idxN} >= 0; ${idxN}--) `;
6999
- else if (isPlus1)
7000
- code += `for (let ${idxN} = 0; ${idxN} < ${ic}.length; ${idxN}++) `;
7001
- else if (isNeg)
7002
- code += `for (let ${idxN} = ${ic}.length - 1; ${idxN} >= 0; ${idxN} += ${stc}) `;
7003
- else
7004
- code += `for (let ${idxN} = 0; ${idxN} < ${ic}.length; ${idxN} += ${stc}) `;
7005
- code += `{
7006
- `;
7007
- this.indentLevel++;
7008
- if (!noVar)
7009
- code += this.indent() + `const ${ivp} = ${ic}[${idxN}];
7010
- `;
7011
- }
7012
- if (guards?.length) {
7013
- if (!isRange)
7014
- code += this.indent();
7015
- code += `{
7016
- `;
7017
- this.indentLevel++;
7018
- code += this.indent() + `if (${guards.map((g) => this.generate(g, "value")).join(" && ")}) {
7019
- `;
7020
- this.indentLevel++;
7021
- code += this.indent() + this.generate(expr, "statement") + `;
7022
- `;
7023
- this.indentLevel--;
7024
- code += this.indent() + `}
7025
- `;
7026
- this.indentLevel--;
7027
- code += this.indent() + "}";
7028
- } else {
7029
- if (!isRange)
7030
- code += this.indent();
7031
- code += `{
7032
- `;
7033
- this.indentLevel++;
7034
- code += this.indent() + this.generate(expr, "statement") + `;
7035
- `;
7036
- this.indentLevel--;
7037
- code += this.indent() + "}";
7038
- }
7039
- if (!isRange) {
7040
- this.indentLevel--;
7041
- code += `
7042
- ` + this.indent() + "}";
7043
- }
7044
- return code;
7045
- }
7046
- if (indexVar) {
7047
- let ic = this.generate(iterable, "value");
7048
- code += `for (let ${indexVar} = 0; ${indexVar} < ${ic}.length; ${indexVar}++) `;
7049
- code += `{
7050
- `;
7051
- this.indentLevel++;
7052
- code += this.indent() + `const ${ivp} = ${ic}[${indexVar}];
7053
- `;
7054
- } else {
7055
- code += `for (const ${ivp} of ${this.generate(iterable, "value")}) `;
7056
- if (guards?.length) {
7057
- code += `{
7058
- `;
7059
- this.indentLevel++;
7060
- code += this.indent() + `if (${guards.map((g) => this.generate(g, "value")).join(" && ")}) {
6976
+ let guardCond = guards?.length ? guards.map((g) => this.generate(g, "value")).join(" && ") : null;
6977
+ let emitBody = () => {
6978
+ if (guardCond) {
6979
+ code += this.indent() + `if (${guardCond}) {
7061
6980
  `;
7062
- this.indentLevel++;
7063
- code += this.indent() + this.generate(expr, "statement") + `;
7064
- `;
7065
- this.indentLevel--;
7066
- code += this.indent() + `}
7067
- `;
7068
- this.indentLevel--;
7069
- code += this.indent() + "}";
7070
- } else {
7071
- code += `{
7072
- `;
7073
- this.indentLevel++;
7074
- code += this.indent() + this.generate(expr, "statement") + `;
6981
+ this.indentLevel++;
6982
+ code += this.indent() + this.generate(expr, "statement") + `;
7075
6983
  `;
7076
- this.indentLevel--;
7077
- code += this.indent() + "}";
7078
- }
7079
- return code;
7080
- }
7081
- if (guards?.length) {
7082
- code += this.indent() + `if (${guards.map((g) => this.generate(g, "value")).join(" && ")}) {
6984
+ this.indentLevel--;
6985
+ code += this.indent() + `}
7083
6986
  `;
7084
- this.indentLevel++;
7085
- code += this.indent() + this.generate(expr, "statement") + `;
6987
+ } else {
6988
+ code += this.indent() + this.generate(expr, "statement") + `;
7086
6989
  `;
7087
- this.indentLevel--;
7088
- code += this.indent() + `}
6990
+ }
6991
+ };
6992
+ if (iterators.length === 1) {
6993
+ let [iterType, vars, iterable, stepOrOwn] = iterators[0];
6994
+ if (iterType === "for-in") {
6995
+ let { header, setup } = this._forInHeader(vars, iterable, stepOrOwn);
6996
+ code += header + ` {
7089
6997
  `;
7090
- } else {
7091
- code += this.indent() + this.generate(expr, "statement") + `;
6998
+ this.indentLevel++;
6999
+ if (setup)
7000
+ code += this.indent() + setup + `
7092
7001
  `;
7093
- }
7002
+ emitBody();
7094
7003
  this.indentLevel--;
7095
7004
  code += this.indent() + "}";
7096
7005
  return code;
7097
7006
  }
7098
7007
  if (iterType === "for-as") {
7099
- let va = Array.isArray(vars) ? vars : [vars];
7100
- let [fv] = va;
7101
- let ivp = this.is(fv, "array") || this.is(fv, "object") ? this.generateDestructuringPattern(fv) : fv;
7102
- code += `for (const ${ivp} of ${this.generate(iterable, "value")}) `;
7103
- if (guards?.length) {
7104
- code += `{
7008
+ let { header } = this._forAsHeader(vars, iterable, stepOrOwn);
7009
+ code += header + ` {
7105
7010
  `;
7106
- this.indentLevel++;
7107
- code += this.indent() + `if (${guards.map((g) => this.generate(g, "value")).join(" && ")}) {
7108
- `;
7109
- this.indentLevel++;
7110
- code += this.indent() + this.generate(expr, "statement") + `;
7111
- `;
7112
- this.indentLevel--;
7113
- code += this.indent() + `}
7114
- `;
7115
- this.indentLevel--;
7116
- code += this.indent() + "}";
7117
- } else {
7118
- code += `{
7119
- `;
7120
- this.indentLevel++;
7121
- code += this.indent() + this.generate(expr, "statement") + `;
7122
- `;
7123
- this.indentLevel--;
7124
- code += this.indent() + "}";
7125
- }
7011
+ this.indentLevel++;
7012
+ emitBody();
7013
+ this.indentLevel--;
7014
+ code += this.indent() + "}";
7126
7015
  return code;
7127
7016
  }
7128
7017
  if (iterType === "for-of") {
7129
- let va = Array.isArray(vars) ? vars : [vars];
7130
- let [kv, vv] = va;
7131
- let own = stepOrOwn;
7132
- let oc = this.generate(iterable, "value");
7133
- code += `for (const ${kv} in ${oc}) {
7018
+ let { header, own, vv, oc, kvp } = this._forOfHeader(vars, iterable, stepOrOwn);
7019
+ code += header + ` {
7134
7020
  `;
7135
7021
  this.indentLevel++;
7136
- if (own && !vv && !guards?.length) {
7137
- code += this.indent() + `if (!Object.hasOwn(${oc}, ${kv})) continue;
7138
- `;
7139
- code += this.indent() + this.generate(expr, "statement") + `;
7140
- `;
7141
- } else if (own && vv && guards?.length) {
7142
- code += this.indent() + `if (Object.hasOwn(${oc}, ${kv})) {
7143
- `;
7144
- this.indentLevel++;
7145
- code += this.indent() + `const ${vv} = ${oc}[${kv}];
7146
- `;
7147
- code += this.indent() + `if (${guards.map((g) => this.generate(g, "value")).join(" && ")}) {
7148
- `;
7149
- this.indentLevel++;
7150
- code += this.indent() + this.generate(expr, "statement") + `;
7151
- `;
7152
- this.indentLevel--;
7153
- code += this.indent() + `}
7154
- `;
7155
- this.indentLevel--;
7156
- code += this.indent() + `}
7157
- `;
7158
- } else if (own && vv) {
7159
- code += this.indent() + `if (Object.hasOwn(${oc}, ${kv})) {
7160
- `;
7161
- this.indentLevel++;
7162
- code += this.indent() + `const ${vv} = ${oc}[${kv}];
7163
- `;
7164
- code += this.indent() + this.generate(expr, "statement") + `;
7165
- `;
7166
- this.indentLevel--;
7167
- code += this.indent() + `}
7168
- `;
7169
- } else if (vv && guards?.length) {
7170
- code += this.indent() + `const ${vv} = ${oc}[${kv}];
7171
- `;
7172
- code += this.indent() + `if (${guards.map((g) => this.generate(g, "value")).join(" && ")}) {
7173
- `;
7174
- this.indentLevel++;
7175
- code += this.indent() + this.generate(expr, "statement") + `;
7176
- `;
7177
- this.indentLevel--;
7178
- code += this.indent() + `}
7179
- `;
7180
- } else if (vv) {
7181
- code += this.indent() + `const ${vv} = ${oc}[${kv}];
7182
- `;
7183
- code += this.indent() + this.generate(expr, "statement") + `;
7184
- `;
7185
- } else if (guards?.length) {
7186
- code += this.indent() + `if (${guards.map((g) => this.generate(g, "value")).join(" && ")}) {
7187
- `;
7188
- this.indentLevel++;
7189
- code += this.indent() + this.generate(expr, "statement") + `;
7190
- `;
7191
- this.indentLevel--;
7192
- code += this.indent() + `}
7022
+ if (own)
7023
+ code += this.indent() + `if (!Object.hasOwn(${oc}, ${kvp})) continue;
7193
7024
  `;
7194
- } else {
7195
- code += this.indent() + this.generate(expr, "statement") + `;
7025
+ if (vv)
7026
+ code += this.indent() + `const ${vv} = ${oc}[${kvp}];
7196
7027
  `;
7197
- }
7028
+ emitBody();
7198
7029
  this.indentLevel--;
7199
7030
  code += this.indent() + "}";
7200
7031
  return code;
@@ -7205,7 +7036,7 @@ ${this.indent()}}`;
7205
7036
  generateIfElseWithEarlyReturns(ifStmt) {
7206
7037
  let [head, condition, thenBranch, ...elseBranches] = ifStmt;
7207
7038
  let code = "";
7208
- let condCode = head === "unless" ? `!${this.generate(condition, "value")}` : this.generate(condition, "value");
7039
+ let condCode = this.generate(condition, "value");
7209
7040
  code += this.indent() + `if (${condCode}) {
7210
7041
  `;
7211
7042
  code += this.withIndent(() => this.generateBranchWithReturn(thenBranch));
@@ -7385,7 +7216,7 @@ ${this.indent()}}`;
7385
7216
  if (!generated.endsWith("}"))
7386
7217
  return true;
7387
7218
  let h = Array.isArray(stmt) ? stmt[0] : null;
7388
- return !["def", "class", "if", "unless", "for-in", "for-of", "for-as", "while", "until", "loop", "switch", "try"].includes(h);
7219
+ return !["def", "class", "if", "for-in", "for-of", "for-as", "while", "loop", "switch", "try"].includes(h);
7389
7220
  }
7390
7221
  addSemicolon(stmt, generated) {
7391
7222
  return generated + (this.needsSemicolon(stmt, generated) ? ";" : "");
@@ -7415,7 +7246,7 @@ ${this.indent()}}`;
7415
7246
  return stmts.some((s) => Array.isArray(s) && ["return", "throw", "break", "continue"].includes(s[0]));
7416
7247
  });
7417
7248
  }
7418
- if (t === "if" || t === "unless") {
7249
+ if (t === "if") {
7419
7250
  let [, , thenB, elseB] = body;
7420
7251
  return this.branchHasControlFlow(thenB) && elseB && this.branchHasControlFlow(elseB);
7421
7252
  }
@@ -7879,14 +7710,19 @@ function __effect(fn) {
7879
7710
  dependencies: new Set(),
7880
7711
 
7881
7712
  run() {
7713
+ if (effect._cleanup) { effect._cleanup(); effect._cleanup = null; }
7882
7714
  for (const dep of effect.dependencies) dep.delete(effect);
7883
7715
  effect.dependencies.clear();
7884
7716
  const prev = __currentEffect;
7885
7717
  __currentEffect = effect;
7886
- try { fn(); } finally { __currentEffect = prev; }
7718
+ try {
7719
+ const result = fn();
7720
+ if (typeof result === 'function') effect._cleanup = result;
7721
+ } finally { __currentEffect = prev; }
7887
7722
  },
7888
7723
 
7889
7724
  dispose() {
7725
+ if (effect._cleanup) { effect._cleanup(); effect._cleanup = null; }
7890
7726
  for (const dep of effect.dependencies) dep.delete(effect);
7891
7727
  effect.dependencies.clear();
7892
7728
  }
@@ -8074,8 +7910,8 @@ function getComponentRuntime() {
8074
7910
  return new CodeGenerator({}).getComponentRuntime();
8075
7911
  }
8076
7912
  // src/browser.js
8077
- var VERSION = "3.7.4";
8078
- var BUILD_DATE = "2026-02-11@13:07:41GMT";
7913
+ var VERSION = "3.8.9";
7914
+ var BUILD_DATE = "2026-02-16@20:02:36GMT";
8079
7915
  if (typeof globalThis !== "undefined" && !globalThis.__rip) {
8080
7916
  new Function(getReactiveRuntime())();
8081
7917
  }
@@ -8090,7 +7926,17 @@ async function processRipScripts() {
8090
7926
  if (script.hasAttribute("data-rip-processed"))
8091
7927
  continue;
8092
7928
  try {
8093
- const ripCode = dedent(script.textContent);
7929
+ let ripCode;
7930
+ if (script.src) {
7931
+ const response = await fetch(script.src);
7932
+ if (!response.ok) {
7933
+ console.error(`Rip: failed to fetch ${script.src} (${response.status})`);
7934
+ continue;
7935
+ }
7936
+ ripCode = await response.text();
7937
+ } else {
7938
+ ripCode = dedent(script.textContent);
7939
+ }
8094
7940
  let jsCode;
8095
7941
  try {
8096
7942
  jsCode = compileToJS(ripCode);
@@ -8150,12 +7996,15 @@ if (typeof globalThis !== "undefined") {
8150
7996
  globalThis.rip = rip;
8151
7997
  globalThis.importRip = importRip;
8152
7998
  globalThis.compileToJS = compileToJS;
7999
+ globalThis.__ripExports = { compile, compileToJS, formatSExpr, VERSION, BUILD_DATE, getReactiveRuntime, getComponentRuntime };
8153
8000
  }
8154
8001
  if (typeof document !== "undefined") {
8155
8002
  if (document.readyState === "loading") {
8156
- document.addEventListener("DOMContentLoaded", processRipScripts);
8003
+ globalThis.__ripScriptsReady = new Promise((resolve) => {
8004
+ document.addEventListener("DOMContentLoaded", () => processRipScripts().then(resolve));
8005
+ });
8157
8006
  } else {
8158
- processRipScripts();
8007
+ globalThis.__ripScriptsReady = processRipScripts();
8159
8008
  }
8160
8009
  }
8161
8010
  export {