rip-lang 3.16.0 → 3.16.1

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/docs/dist/rip.js CHANGED
@@ -2284,7 +2284,7 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
2284
2284
  if (dname === "belongs_to" || dname === "has_many" || dname === "has_one" || dname === "one" || dname === "many" || dname === "mixin") {
2285
2285
  let t0 = argTokens[0];
2286
2286
  if (t0 && (t0[0] === "IDENTIFIER" || t0[0] === "PROPERTY")) {
2287
- let optional = t0.data?.predicate === true;
2287
+ let optional = t0.data?.optional === true;
2288
2288
  if (!optional && argTokens[1]?.[0] === "?")
2289
2289
  optional = true;
2290
2290
  args = [{ target: t0[1], optional }];
@@ -2961,7 +2961,7 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
2961
2961
  throw schemaError(t0 || tokens[tokens.length - 1], `@${name} requires a target name.`);
2962
2962
  }
2963
2963
  let target = t0[1];
2964
- let optional = t0.data?.predicate === true;
2964
+ let optional = t0.data?.optional === true;
2965
2965
  let pos = 1;
2966
2966
  if (!optional && tokens[pos]?.[0] === "?") {
2967
2967
  optional = true;
@@ -3147,9 +3147,9 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
3147
3147
  function collectModifiers(identToken) {
3148
3148
  let mods = [];
3149
3149
  let d = identToken.data;
3150
- if (d?.await === true)
3150
+ if (d?.bang === true)
3151
3151
  mods.push("!");
3152
- if (d?.predicate === true)
3152
+ if (d?.optional === true)
3153
3153
  mods.push("?");
3154
3154
  return mods;
3155
3155
  }
@@ -3501,6 +3501,7 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
3501
3501
  function collectTypeExpression(tokens, j) {
3502
3502
  let typeTokens = [];
3503
3503
  let depth = 0;
3504
+ let bracketStack = [];
3504
3505
  let startJ = j;
3505
3506
  while (j < tokens.length) {
3506
3507
  let t = tokens[j];
@@ -3509,12 +3510,18 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
3509
3510
  let isClose = tTag === ")" || tTag === "]" || tTag === "}" || tTag === "CALL_END" || tTag === "PARAM_END" || tTag === "INDEX_END" || tTag === "COMPARE" && t[1] === ">";
3510
3511
  if (tTag === "SHIFT" && t[1] === ">>" && depth >= 2) {
3511
3512
  depth -= 2;
3513
+ if (bracketStack[bracketStack.length - 1] === "<")
3514
+ bracketStack.pop();
3515
+ if (bracketStack[bracketStack.length - 1] === "<")
3516
+ bracketStack.pop();
3512
3517
  typeTokens.push(t);
3513
3518
  j++;
3514
3519
  continue;
3515
3520
  }
3516
3521
  if (isOpen) {
3517
3522
  depth++;
3523
+ let kind = tTag === "{" ? "{" : tTag === "[" || tTag === "INDEX_START" ? "[" : tTag === "COMPARE" && t[1] === "<" ? "<" : "(";
3524
+ bracketStack.push(kind);
3518
3525
  typeTokens.push(t);
3519
3526
  j++;
3520
3527
  continue;
@@ -3522,6 +3529,7 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
3522
3529
  if (isClose) {
3523
3530
  if (depth > 0) {
3524
3531
  depth--;
3532
+ bracketStack.pop();
3525
3533
  typeTokens.push(t);
3526
3534
  j++;
3527
3535
  continue;
@@ -3550,6 +3558,23 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
3550
3558
  break;
3551
3559
  }
3552
3560
  }
3561
+ if (depth > 0 && (tTag === "INDENT" || tTag === "OUTDENT")) {
3562
+ j++;
3563
+ continue;
3564
+ }
3565
+ if (depth > 0 && tTag === "TERMINATOR") {
3566
+ typeTokens.push(["", ";"]);
3567
+ j++;
3568
+ continue;
3569
+ }
3570
+ if (tTag === "PROPERTY" && bracketStack[bracketStack.length - 1] === "{") {
3571
+ let prev = typeTokens[typeTokens.length - 1];
3572
+ let prevTag = prev?.[0];
3573
+ let prevVal = prev?.[1];
3574
+ let needsSep = prev && prevTag !== "{" && prevTag !== "," && !(prevTag === "" && prevVal === ";");
3575
+ if (needsSep)
3576
+ typeTokens.push(["", ";"]);
3577
+ }
3553
3578
  typeTokens.push(t);
3554
3579
  j++;
3555
3580
  }
@@ -3561,7 +3586,31 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
3561
3586
  return "";
3562
3587
  if (typeTokens[0]?.[0] === "=>")
3563
3588
  typeTokens.unshift(["", "()"]);
3564
- let typeStr = typeTokens.map((t) => t[1]).join(" ").replace(/\s+/g, " ").trim();
3589
+ {
3590
+ let curlyDepth = 0;
3591
+ for (let t of typeTokens) {
3592
+ let tag = t[0];
3593
+ if (tag === "{")
3594
+ curlyDepth++;
3595
+ else if (tag === "}")
3596
+ curlyDepth--;
3597
+ else if (tag === "TYPE_ANNOTATION" && curlyDepth > 0) {
3598
+ let loc = t.loc;
3599
+ let where = loc ? ` (line ${loc.r}, col ${loc.c})` : "";
3600
+ let err = new Error(`Use \`:\` (not \`::\`) inside a structural type literal${where}. ` + `\`::\` binds a name to a type; inside \`{ ... }\` in type ` + `position, fields use \`:\` (TS-style).`);
3601
+ err.loc = loc;
3602
+ throw err;
3603
+ }
3604
+ }
3605
+ }
3606
+ let parts = typeTokens.map((t, i) => {
3607
+ let next = typeTokens[i + 1];
3608
+ if (t.data?.optional && next && (next[0] === "TYPE_ANNOTATION" || next[0] === ":")) {
3609
+ return `${t[1]}?`;
3610
+ }
3611
+ return t[1];
3612
+ });
3613
+ let typeStr = parts.join(" ").replace(/\s+/g, " ").trim();
3565
3614
  typeStr = typeStr.replace(/\s*<\s*/g, "<").replace(/\s*>\s*/g, ">").replace(/\s*\[\s*/g, "[").replace(/\s*\]\s*/g, "]").replace(/\s*\(\s*/g, "(").replace(/\s*\)\s*/g, ")").replace(/\s*,\s*/g, ", ").replace(/\s*=>\s*/g, " => ").replace(/ :: /g, ": ").replace(/:: /g, ": ").replace(/ : /g, ": ");
3566
3615
  return typeStr;
3567
3616
  }
@@ -3639,11 +3688,11 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
3639
3688
  if (propName === "readonly" && tokens[j] && (tokens[j][0] === "PROPERTY" || tokens[j][0] === "IDENTIFIER" || /^[a-zA-Z_$]/.test(tokens[j][1]) && tokens[j + 1]?.[0] === "TYPE_ANNOTATION")) {
3640
3689
  readonly = true;
3641
3690
  propName = tokens[j][1];
3642
- if (tokens[j].data?.predicate)
3691
+ if (tokens[j].data?.optional)
3643
3692
  optional = true;
3644
3693
  j++;
3645
3694
  }
3646
- if (t.data?.predicate)
3695
+ if (t.data?.optional)
3647
3696
  optional = true;
3648
3697
  if (tokens[j]?.[1] === "?" && !tokens[j]?.spaced) {
3649
3698
  optional = true;
@@ -4384,11 +4433,11 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
4384
4433
  }
4385
4434
  }
4386
4435
  if (id.length > 1 && id.endsWith("!")) {
4387
- data.await = true;
4436
+ data.bang = true;
4388
4437
  id = id.slice(0, -1);
4389
4438
  }
4390
4439
  if (id.length > 1 && id.endsWith("?")) {
4391
- data.predicate = true;
4440
+ data.optional = true;
4392
4441
  id = id.slice(0, -1);
4393
4442
  }
4394
4443
  let t = this.emit(tag, id, { len: idLen, data: Object.keys(data).length ? data : null });
@@ -5108,9 +5157,35 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
5108
5157
  return val.length;
5109
5158
  }
5110
5159
  tagParameters() {
5111
- if (this.prevTag() !== ")")
5112
- return this.tagDoIife();
5113
- let i = this.tokens.length - 1;
5160
+ let closeIdx = this.tokens.length - 1;
5161
+ if (this.tokens[closeIdx]?.[0] !== ")") {
5162
+ let n = this.tokens.length;
5163
+ let depth = 0;
5164
+ let j = n - 1;
5165
+ let found = -1;
5166
+ while (j >= 0) {
5167
+ let tk = this.tokens[j];
5168
+ let tg = tk[0];
5169
+ if (tg === ")" || tg === "]" || tg === "}" || tg === "CALL_END" || tg === "PARAM_END" || tg === "INDEX_END" || tg === "COMPARE" && tk[1] === ">") {
5170
+ depth++;
5171
+ } else if (tg === "(" || tg === "[" || tg === "{" || tg === "CALL_START" || tg === "PARAM_START" || tg === "INDEX_START" || tg === "COMPARE" && tk[1] === "<") {
5172
+ depth--;
5173
+ } else if (depth === 0) {
5174
+ if (tg === "TYPE_ANNOTATION") {
5175
+ if (j > 0 && this.tokens[j - 1][0] === ")")
5176
+ found = j - 1;
5177
+ break;
5178
+ }
5179
+ if (tg === "TERMINATOR" || tg === "INDENT" || tg === "OUTDENT" || tg === "=" || tg === "->" || tg === "=>")
5180
+ break;
5181
+ }
5182
+ j--;
5183
+ }
5184
+ if (found < 0)
5185
+ return this.tagDoIife();
5186
+ closeIdx = found;
5187
+ }
5188
+ let i = closeIdx;
5114
5189
  let stack = [];
5115
5190
  this.tokens[i][0] = "PARAM_END";
5116
5191
  while (i-- > 0) {
@@ -5124,7 +5199,7 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
5124
5199
  tok2[0] = "PARAM_START";
5125
5200
  return this.tagDoIife(i - 1);
5126
5201
  } else {
5127
- this.tokens[this.tokens.length - 1][0] = "CALL_END";
5202
+ this.tokens[closeIdx][0] = "CALL_END";
5128
5203
  return;
5129
5204
  }
5130
5205
  }
@@ -5143,10 +5218,10 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
5143
5218
  this.closeMergeAssignments();
5144
5219
  this.closeOpenCalls();
5145
5220
  this.closeOpenIndexes();
5221
+ this.rewriteTypes();
5146
5222
  this.normalizeLines();
5147
5223
  this.rewriteRender?.();
5148
5224
  this.rewriteSchema?.();
5149
- this.rewriteTypes();
5150
5225
  this.tagPostfixConditionals();
5151
5226
  this.rewriteTaggedTemplates();
5152
5227
  this.addImplicitBracesAndParens();
@@ -6023,7 +6098,7 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6023
6098
  // src/components.js
6024
6099
  var BIND_PREFIX = "__bind_";
6025
6100
  var BIND_SUFFIX = "__";
6026
- var LIFECYCLE_HOOKS = new Set(["beforeMount", "mounted", "updated", "beforeUnmount", "unmounted", "onError"]);
6101
+ var LIFECYCLE_HOOKS = new Set(["beforeMount", "mounted", "beforeUnmount", "unmounted", "onError"]);
6027
6102
  var BOOLEAN_ATTRS = new Set([
6028
6103
  "disabled",
6029
6104
  "hidden",
@@ -6077,6 +6152,13 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6077
6152
  return target[2].type;
6078
6153
  return null;
6079
6154
  }
6155
+ function getMemberOptional(target) {
6156
+ if (target instanceof String && target.optional)
6157
+ return true;
6158
+ if (Array.isArray(target) && target[2] instanceof String && target[2].optional)
6159
+ return true;
6160
+ return false;
6161
+ }
6080
6162
  function installComponentSupport(CodeEmitter, Lexer2) {
6081
6163
  let meta = (node, key) => node instanceof String ? node[key] : undefined;
6082
6164
  const origClassify = Lexer2.prototype.classifyKeyword;
@@ -6435,11 +6517,61 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6435
6517
  if (!(from instanceof String))
6436
6518
  return to;
6437
6519
  const s = new String(to);
6438
- if (from.predicate)
6439
- s.predicate = true;
6440
- if (from.await)
6441
- s.await = true;
6442
- return s.predicate || s.await ? s : to;
6520
+ if (from.optional)
6521
+ s.optional = true;
6522
+ if (from.bang)
6523
+ s.bang = true;
6524
+ return s.optional || s.bang ? s : to;
6525
+ };
6526
+ proto.addBodyRipSrcMarkers = function(bodyCode, bodySexpr) {
6527
+ if (typeof bodyCode !== "string" || !bodyCode)
6528
+ return bodyCode;
6529
+ const stmts = Array.isArray(bodySexpr) && bodySexpr[0] === "block" ? bodySexpr.slice(1) : Array.isArray(bodySexpr) ? [bodySexpr] : [];
6530
+ if (stmts.length === 0)
6531
+ return bodyCode;
6532
+ const getLoc = (s) => {
6533
+ if (s == null)
6534
+ return null;
6535
+ if (!Array.isArray(s))
6536
+ return s?.loc?.r ?? null;
6537
+ if (s.loc?.r)
6538
+ return s.loc.r;
6539
+ if (s[0]?.loc?.r)
6540
+ return s[0].loc.r;
6541
+ for (const child of s) {
6542
+ if (child?.loc?.r)
6543
+ return child.loc.r;
6544
+ if (Array.isArray(child)) {
6545
+ const l = getLoc(child);
6546
+ if (l != null)
6547
+ return l;
6548
+ }
6549
+ }
6550
+ return null;
6551
+ };
6552
+ const srcLines = stmts.map(getLoc);
6553
+ if (srcLines.every((l) => l == null))
6554
+ return bodyCode;
6555
+ const lines = bodyCode.split(`
6556
+ `);
6557
+ let si = 0;
6558
+ for (let i = 0;i < lines.length && si < srcLines.length; i++) {
6559
+ const trimmed = lines[i].trim();
6560
+ if (!trimmed)
6561
+ continue;
6562
+ if (trimmed === "{" || trimmed === "}" || trimmed.startsWith("//"))
6563
+ continue;
6564
+ if (lines[i].includes("@rip-src:")) {
6565
+ si++;
6566
+ continue;
6567
+ }
6568
+ if (srcLines[si] != null) {
6569
+ lines[i] = `${lines[i]} // @rip-src:${srcLines[si]}`;
6570
+ }
6571
+ si++;
6572
+ }
6573
+ return lines.join(`
6574
+ `);
6443
6575
  };
6444
6576
  proto.transformComponentMembers = function(sexpr, localScope = new Set) {
6445
6577
  const self = this._self;
@@ -6548,28 +6680,29 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6548
6680
  } else if (op === "." && stmt[1] === "this" && getMemberName(stmt)) {
6549
6681
  const varName = typeof stmt[2] === "string" || stmt[2] instanceof String ? stmt[2].valueOf() : null;
6550
6682
  if (varName) {
6551
- stateVars.push({ name: varName, value: undefined, isPublic: true, type: stmt[2]?.type || null, required: true });
6683
+ const optional = getMemberOptional(stmt);
6684
+ stateVars.push({ name: varName, value: undefined, isPublic: true, type: stmt[2]?.type || null, required: !optional, optional, srcLine: stmt.loc?.r });
6552
6685
  memberNames.add(varName);
6553
6686
  reactiveMembers.add(varName);
6554
6687
  }
6555
6688
  } else if (op === "state") {
6556
6689
  const varName = getMemberName(stmt[1]);
6557
6690
  if (varName) {
6558
- stateVars.push({ name: varName, value: stmt[2], isPublic: isPublicProp(stmt[1]), type: getMemberType(stmt[1]) });
6691
+ stateVars.push({ name: varName, value: stmt[2], isPublic: isPublicProp(stmt[1]), type: getMemberType(stmt[1]), optional: getMemberOptional(stmt[1]), srcLine: stmt.loc?.r });
6559
6692
  memberNames.add(varName);
6560
6693
  reactiveMembers.add(varName);
6561
6694
  }
6562
6695
  } else if (op === "computed") {
6563
6696
  const varName = getMemberName(stmt[1]);
6564
6697
  if (varName) {
6565
- derivedVars.push({ name: varName, expr: stmt[2], type: getMemberType(stmt[1]) });
6698
+ derivedVars.push({ name: varName, expr: stmt[2], type: getMemberType(stmt[1]), srcLine: stmt.loc?.r });
6566
6699
  memberNames.add(varName);
6567
6700
  reactiveMembers.add(varName);
6568
6701
  }
6569
6702
  } else if (op === "readonly") {
6570
6703
  const varName = getMemberName(stmt[1]);
6571
6704
  if (varName) {
6572
- readonlyVars.push({ name: varName, value: stmt[2], isPublic: isPublicProp(stmt[1]), type: getMemberType(stmt[1]) });
6705
+ readonlyVars.push({ name: varName, value: stmt[2], isPublic: isPublicProp(stmt[1]), type: getMemberType(stmt[1]), optional: getMemberOptional(stmt[1]), srcLine: stmt.loc?.r });
6573
6706
  memberNames.add(varName);
6574
6707
  }
6575
6708
  } else if (op === "=") {
@@ -6583,7 +6716,7 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6583
6716
  methods.push({ name: varName, func: val });
6584
6717
  memberNames.add(varName);
6585
6718
  } else {
6586
- stateVars.push({ name: varName, value: val, isPublic: isPublicProp(stmt[1]) });
6719
+ stateVars.push({ name: varName, value: val, isPublic: isPublicProp(stmt[1]), srcLine: stmt.loc?.r });
6587
6720
  memberNames.add(varName);
6588
6721
  reactiveMembers.add(varName);
6589
6722
  }
@@ -6637,18 +6770,32 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6637
6770
  this._autoEventHandlers = autoEventHandlers.size > 0 ? autoEventHandlers : null;
6638
6771
  this._inheritsTag = inheritsTag || null;
6639
6772
  if (this.options.stubComponents) {
6640
- const expandType = (t) => t ? t.replace(/::/g, ":").replace(/(\w+(?:<[^>]+>)?)\?\?/g, "$1 | null | undefined").replace(/(\w+(?:<[^>]+>)?)\?(?![.:])/g, "$1 | undefined").replace(/(\w+(?:<[^>]+>)?)\!/g, "NonNullable<$1>") : null;
6773
+ const expandType = (t) => t ? t.replace(/::/g, ":") : null;
6641
6774
  const sl = [];
6642
6775
  const componentTypeParams = this._componentTypeParams || "";
6643
6776
  sl.push(`class ${componentTypeParams}{`);
6644
- sl.push(" declare _root: Element | null; declare app: any;");
6777
+ sl.push(" declare _root: Element | null; declare app: any; declare router: any; declare params: Record<string, string>; declare query: URLSearchParams; declare children: any;");
6778
+ const userHookNames = new Set(lifecycleHooks.map((h) => h.name));
6779
+ const hookDecls = [];
6780
+ if (!userHookNames.has("beforeMount"))
6781
+ hookDecls.push("beforeMount?(): void;");
6782
+ if (!userHookNames.has("mounted"))
6783
+ hookDecls.push("mounted?(): void;");
6784
+ if (!userHookNames.has("beforeUnmount"))
6785
+ hookDecls.push("beforeUnmount?(): void;");
6786
+ if (!userHookNames.has("unmounted"))
6787
+ hookDecls.push("unmounted?(): void;");
6788
+ if (!userHookNames.has("onError"))
6789
+ hookDecls.push("onError?(err: { status?: number; message?: string; error?: Error; path?: string }): void;");
6790
+ if (hookDecls.length)
6791
+ sl.push(" " + hookDecls.join(" "));
6645
6792
  sl.push(" emit(_name: string, _detail?: any): void {}");
6646
6793
  const propEntries = [];
6647
- for (const { name, type, isPublic, required } of stateVars) {
6794
+ for (const { name, type, isPublic, required, optional } of stateVars) {
6648
6795
  if (!isPublic)
6649
6796
  continue;
6650
6797
  const ts = expandType(type);
6651
- const opt = required ? "" : "?";
6798
+ const opt = optional ?? !required ? "?" : "";
6652
6799
  propEntries.push(`${name}${opt}: ${ts || "any"}`);
6653
6800
  propEntries.push(`__bind_${name}__?: Signal<${ts || "any"}>`);
6654
6801
  }
@@ -6659,7 +6806,7 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6659
6806
  propEntries.push(`${name}?: ${ts || "any"}`);
6660
6807
  }
6661
6808
  {
6662
- const hasRequired = propEntries.length > 0 && stateVars.some((v) => v.isPublic && v.required);
6809
+ const hasRequired = propEntries.length > 0 && stateVars.some((v) => v.isPublic && v.required && !v.optional);
6663
6810
  const propsOpt = hasRequired ? "" : "?";
6664
6811
  let propsType = propEntries.length > 0 ? `{${propEntries.join("; ")}}` : "{}";
6665
6812
  if (inheritsTag)
@@ -6678,9 +6825,12 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6678
6825
  return "string";
6679
6826
  return null;
6680
6827
  };
6681
- for (const { name, type, value } of stateVars) {
6828
+ for (const { name, type, value, optional, srcLine } of stateVars) {
6682
6829
  const ts = expandType(type) || inferLiteralType(value);
6683
- sl.push(ts ? ` declare ${name}: Signal<${ts}>;` : ` declare ${name}: Signal<any>;`);
6830
+ const optNoDefault = optional && value === undefined;
6831
+ const wrapped = ts ? optNoDefault ? `${ts} | undefined` : ts : null;
6832
+ const marker = srcLine != null ? ` // @rip-src:${srcLine}` : "";
6833
+ sl.push((wrapped ? ` declare ${name}: Signal<${wrapped}>;` : ` declare ${name}: Signal<any>;`) + marker);
6684
6834
  }
6685
6835
  if (inheritsTag) {
6686
6836
  sl.push(` declare rest: Signal<__RipProps<'${inheritsTag}'>>;`);
@@ -6702,19 +6852,21 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6702
6852
  }
6703
6853
  }
6704
6854
  sl.push(" _init(props) {");
6705
- for (const { name, value, isPublic } of readonlyVars) {
6855
+ for (const { name, value, isPublic, srcLine } of readonlyVars) {
6706
6856
  const val = this.emitInComponent(value, "value");
6707
- sl.push(isPublic ? ` this.${name} = props.${name} ?? ${val};` : ` this.${name} = ${val};`);
6857
+ const marker = srcLine != null ? ` // @rip-src:${srcLine}` : "";
6858
+ sl.push((isPublic ? ` this.${name} = props.${name} ?? ${val};` : ` this.${name} = ${val};`) + marker);
6708
6859
  }
6709
- for (const { name, value, isPublic, required, type } of stateVars) {
6710
- if (isPublic && required) {
6711
- sl.push(` this.${name} = __state(props.__bind_${name}__ ?? props.${name});`);
6860
+ for (const { name, value, isPublic, required, type, srcLine } of stateVars) {
6861
+ const marker = srcLine != null ? ` // @rip-src:${srcLine}` : "";
6862
+ if (isPublic && (required || value === undefined)) {
6863
+ sl.push(` this.${name} = __state(props.__bind_${name}__ ?? props.${name});` + marker);
6712
6864
  } else if (isPublic) {
6713
6865
  const val = this.emitInComponent(value, "value");
6714
- sl.push(` this.${name} = __state(props.__bind_${name}__ ?? props.${name} ?? ${val});`);
6866
+ sl.push(` this.${name} = __state(props.__bind_${name}__ ?? props.${name} ?? ${val});` + marker);
6715
6867
  } else {
6716
6868
  const val = this.emitInComponent(value, "value");
6717
- sl.push(` this.${name} = __state(${val});`);
6869
+ sl.push(` this.${name} = __state(${val});` + marker);
6718
6870
  }
6719
6871
  }
6720
6872
  for (const effect of effects) {
@@ -6795,7 +6947,8 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6795
6947
  }
6796
6948
  const transformed = this.reactiveMembers ? this.transformComponentMembers(methodBody) : methodBody;
6797
6949
  const isAsync = this.containsAwait(methodBody);
6798
- const bodyCode = this.emitFunctionBody(transformed, params || []);
6950
+ let bodyCode = this.emitFunctionBody(transformed, params || []);
6951
+ bodyCode = this.addBodyRipSrcMarkers(bodyCode, methodBody);
6799
6952
  sl.push(` ${isAsync ? "async " : ""}${name}(${paramStr}) ${bodyCode}`);
6800
6953
  }
6801
6954
  }
@@ -6805,7 +6958,8 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6805
6958
  const paramStr = Array.isArray(params) ? params.map((p) => this.formatParam(p)).join(", ") : "";
6806
6959
  const transformed = this.reactiveMembers ? this.transformComponentMembers(hookBody) : hookBody;
6807
6960
  const isAsync = this.containsAwait(hookBody);
6808
- const bodyCode = this.emitFunctionBody(transformed, params || []);
6961
+ let bodyCode = this.emitFunctionBody(transformed, params || []);
6962
+ bodyCode = this.addBodyRipSrcMarkers(bodyCode, hookBody);
6809
6963
  sl.push(` ${isAsync ? "async " : ""}${name}(${paramStr}) ${bodyCode}`);
6810
6964
  }
6811
6965
  }
@@ -6863,8 +7017,21 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6863
7017
  props.sideExprs = sideExprs;
6864
7018
  return props;
6865
7019
  };
6866
- const extractIntrinsicProps = (args) => {
7020
+ const extractIntrinsicProps = (args, tagName) => {
6867
7021
  const props = [];
7022
+ const wrapHrefVal = (val) => {
7023
+ if (tagName !== "a")
7024
+ return val;
7025
+ if (typeof val !== "string")
7026
+ return val;
7027
+ if (val.length < 2)
7028
+ return val;
7029
+ if (val[0] !== "`")
7030
+ return val;
7031
+ if (val[1] !== "/")
7032
+ return val;
7033
+ return `__ripRoute(${val})`;
7034
+ };
6868
7035
  for (const arg of args) {
6869
7036
  let obj = null;
6870
7037
  if (this.is(arg, "object")) {
@@ -6904,7 +7071,8 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
6904
7071
  props.push({ code: `${propName}: ${val}`, srcLine });
6905
7072
  } else {
6906
7073
  const val = this.emitInComponent(value, "value");
6907
- props.push({ code: `${key}: ${val}`, srcLine });
7074
+ const finalVal = key === "href" ? wrapHrefVal(val) : val;
7075
+ props.push({ code: `${key}: ${finalVal}`, srcLine });
6908
7076
  }
6909
7077
  }
6910
7078
  }
@@ -7139,7 +7307,7 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
7139
7307
  }
7140
7308
  } else if (typeof head2 === "string" && !CodeEmitter.GENERATORS[head2] && (TEMPLATE_TAGS.has(head2.split(/[.#]/)[0]) || /^[a-z][\w-]*$/.test(head2) && node.length > 1)) {
7141
7309
  const tagName = head2.split(/[.#]/)[0];
7142
- const iProps = extractIntrinsicProps(node.slice(1));
7310
+ const iProps = extractIntrinsicProps(node.slice(1), tagName);
7143
7311
  const tagLine = node.loc?.r;
7144
7312
  const srcMarker = tagLine != null ? ` // @rip-src:${tagLine}` : "";
7145
7313
  if (iProps.length === 0) {
@@ -7194,7 +7362,7 @@ Expecting ${expected.join(", ")}, got '${this.tokenNames[symbol] || symbol}'`;
7194
7362
  lines.push(` this.${name} = getContext('${name}');`);
7195
7363
  }
7196
7364
  for (const { name, value, isPublic, required } of stateVars) {
7197
- if (isPublic && required) {
7365
+ if (isPublic && (required || value === undefined)) {
7198
7366
  lines.push(` this.${name} = __state(props.__bind_${name}__ ?? props.${name});`);
7199
7367
  } else if (isPublic) {
7200
7368
  const val = this.emitInComponent(value, "value");
@@ -8179,7 +8347,8 @@ ${blockFactoriesCode}return ${lines.join(`
8179
8347
  this._renderLocalScope = new Set;
8180
8348
  const outerParams = this._loopVarStack.map((v) => `${v.itemVar}, ${v.indexVar}`).join(", ");
8181
8349
  const outerExtra = outerParams ? `, ${outerParams}` : "";
8182
- this._loopVarStack.push({ itemVar, indexVar });
8350
+ const reactiveSource = this.hasReactiveDeps(collection);
8351
+ this._loopVarStack.push({ itemVar, indexVar, reactiveSource });
8183
8352
  const itemNode = this.emitTemplateBlock(body);
8184
8353
  this._loopVarStack.pop();
8185
8354
  const itemCreateLines = this._createLines;
@@ -8355,6 +8524,9 @@ ${blockFactoriesCode}return ${lines.join(`
8355
8524
  if (sexpr[0] === "." && this._rootsAtThis(sexpr[1])) {
8356
8525
  return true;
8357
8526
  }
8527
+ if ((sexpr[0] === "." || sexpr[0] === "[]") && this._rootsAtReactiveLoopVar(sexpr)) {
8528
+ return true;
8529
+ }
8358
8530
  if (Array.isArray(sexpr[0]) && sexpr[0][0] === "." && sexpr[0][1] === "this") {
8359
8531
  const name = _str(sexpr[0][2]);
8360
8532
  if (name && this.componentMembers?.has(name))
@@ -8414,6 +8586,23 @@ ${blockFactoriesCode}return ${lines.join(`
8414
8586
  return false;
8415
8587
  return this._rootsAtThis(sexpr[1]);
8416
8588
  };
8589
+ proto._rootsAtReactiveLoopVar = function(sexpr) {
8590
+ if (typeof sexpr === "string") {
8591
+ if (!this._loopVarStack || this._loopVarStack.length === 0)
8592
+ return false;
8593
+ for (let i = this._loopVarStack.length - 1;i >= 0; i--) {
8594
+ const v = this._loopVarStack[i];
8595
+ if (v.itemVar === sexpr)
8596
+ return !!v.reactiveSource;
8597
+ }
8598
+ return false;
8599
+ }
8600
+ if (!Array.isArray(sexpr))
8601
+ return false;
8602
+ if (sexpr[0] === "." || sexpr[0] === "[]")
8603
+ return this._rootsAtReactiveLoopVar(sexpr[1]);
8604
+ return false;
8605
+ };
8417
8606
  proto.getComponentRuntime = function() {
8418
8607
  return `
8419
8608
  // ============================================================================
@@ -9690,6 +9879,19 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
9690
9879
  return code;
9691
9880
  }
9692
9881
  buildMappings() {
9882
+ if (this._importEntries) {
9883
+ let importLineOffset = 0;
9884
+ for (let entry of this._importEntries) {
9885
+ if (entry.loc) {
9886
+ this.sourceMap.addMapping(importLineOffset, 0, entry.loc.r, entry.loc.c);
9887
+ }
9888
+ if (entry.sexpr && entry.loc) {
9889
+ this.recordSubMappings(entry.code, entry.sexpr, importLineOffset);
9890
+ }
9891
+ importLineOffset += entry.code.split(`
9892
+ `).length;
9893
+ }
9894
+ }
9693
9895
  if (!this._stmtEntries)
9694
9896
  return;
9695
9897
  let lineOffset = this._preambleLines;
@@ -9775,6 +9977,45 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
9775
9977
  ripSrcCache.set(genLineInStmt, v);
9776
9978
  return v;
9777
9979
  };
9980
+ const inlineTypeRangesCache = new Map;
9981
+ const getInlineTypeRanges = (genLineInStmt) => {
9982
+ if (inlineTypeRangesCache.has(genLineInStmt))
9983
+ return inlineTypeRangesCache.get(genLineInStmt);
9984
+ const lt = codeLines[genLineInStmt];
9985
+ const ranges = [];
9986
+ if (lt && /\)\s*(\{|=>)\s*$/.test(lt)) {
9987
+ const annotRe = /\b[a-zA-Z_$][\w$]*\??\s*:\s*\{/g;
9988
+ let am;
9989
+ while ((am = annotRe.exec(lt)) !== null) {
9990
+ const braceStart = am.index + am[0].length - 1;
9991
+ if (CodeEmitter._isColInsideString(lt, braceStart))
9992
+ continue;
9993
+ let depth = 1, j = braceStart + 1, inStr = false, quote = "";
9994
+ while (j < lt.length && depth > 0) {
9995
+ const ch = lt[j];
9996
+ if (inStr) {
9997
+ if (ch === "\\") {
9998
+ j += 2;
9999
+ continue;
10000
+ }
10001
+ if (ch === quote)
10002
+ inStr = false;
10003
+ } else if (ch === '"' || ch === "'" || ch === "`") {
10004
+ inStr = true;
10005
+ quote = ch;
10006
+ } else if (ch === "{")
10007
+ depth++;
10008
+ else if (ch === "}")
10009
+ depth--;
10010
+ j++;
10011
+ }
10012
+ ranges.push([braceStart, j]);
10013
+ annotRe.lastIndex = j;
10014
+ }
10015
+ }
10016
+ inlineTypeRangesCache.set(genLineInStmt, ranges);
10017
+ return ranges;
10018
+ };
9778
10019
  for (let { name, origLine, origCol } of subs) {
9779
10020
  let escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9780
10021
  let re = new RegExp("\\b" + escaped + "\\b", "g");
@@ -9790,6 +10031,9 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
9790
10031
  const annotMatches = annotSrc != null && annotSrc === origLine;
9791
10032
  if (lineText && CodeEmitter._isColInsideString(lineText, genCol) && !annotMatches)
9792
10033
  continue;
10034
+ const itRanges = getInlineTypeRanges(genLineInStmt);
10035
+ if (itRanges.length && itRanges.some(([s, e]) => genCol >= s && genCol < e))
10036
+ continue;
9793
10037
  let genLine = lineOffset + genLineInStmt;
9794
10038
  let dist = annotMatches ? Math.abs(genCol - origCol) : Math.abs(genLineInStmt - origLineInStmt) * 1e4 + Math.abs(genCol - origCol);
9795
10039
  if (dist < bestDist) {
@@ -9835,14 +10079,29 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
9835
10079
  identCol = node.loc.c + node[1].length + 1;
9836
10080
  }
9837
10081
  }
9838
- } else if (typeof head === "string" && /^[=+\-*/%<>!&|?~^]|^\.\.?$|^def$|^class$|^state$|^computed$|^readonly$|^for-/.test(head)) {
9839
- if (typeof node[1] === "string" && /^[a-zA-Z_$]/.test(node[1]))
10082
+ } else if (typeof head === "string" && /^[=+\-*/%<>!&|?~^]|^\.{1,3}$|^def$|^class$|^state$|^computed$|^readonly$|^for-/.test(head)) {
10083
+ if (typeof node[1] === "string" && /^[a-zA-Z_$]/.test(node[1])) {
9840
10084
  ident = node[1];
10085
+ if (head === "...")
10086
+ identCol = node.loc.c + 3;
10087
+ }
9841
10088
  } else if (typeof head === "string" && /^[a-zA-Z_$]/.test(head)) {
9842
10089
  ident = head;
9843
10090
  }
9844
10091
  if (ident)
9845
10092
  result.push({ name: ident, origLine: node.loc.r, origCol: identCol });
10093
+ if ((head === "->" || head === "=>") && Array.isArray(node[2]) && str(node[2][0]) === "block") {
10094
+ const body = node[2];
10095
+ for (let i = 1;i < body.length; i++) {
10096
+ const leaf = body[i];
10097
+ const leafStr = typeof leaf === "string" || leaf instanceof String ? str(leaf) : null;
10098
+ if (leafStr && /^[a-zA-Z_$][\w$]*$/.test(leafStr) && !leaf.loc) {
10099
+ const anchor = this._scanForIdentAfter(leafStr, node.loc);
10100
+ if (anchor)
10101
+ result.push(anchor);
10102
+ }
10103
+ }
10104
+ }
9846
10105
  }
9847
10106
  if (Array.isArray(node._anchors)) {
9848
10107
  for (const a of node._anchors)
@@ -9854,6 +10113,29 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
9854
10113
  this.collectSubExprs(node[i], result);
9855
10114
  }
9856
10115
  }
10116
+ _scanForIdentAfter(ident, startLoc) {
10117
+ const source = this.options && this.options.source;
10118
+ if (!source || !startLoc)
10119
+ return null;
10120
+ const lines = this._sourceLinesCache || (this._sourceLinesCache = source.split(`
10121
+ `));
10122
+ const re = new RegExp("\\b" + ident.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "\\b", "g");
10123
+ const startRow = startLoc.r;
10124
+ const startCol = startLoc.c;
10125
+ for (let r = startRow;r < Math.min(lines.length, startRow + 20); r++) {
10126
+ const line = lines[r];
10127
+ if (!line)
10128
+ continue;
10129
+ re.lastIndex = r === startRow ? startCol : 0;
10130
+ let m;
10131
+ while ((m = re.exec(line)) !== null) {
10132
+ if (CodeEmitter._isColInsideString(line, m.index))
10133
+ continue;
10134
+ return { name: ident, origLine: r, origCol: m.index };
10135
+ }
10136
+ }
10137
+ return null;
10138
+ }
9857
10139
  collectProgramVariables(sexpr) {
9858
10140
  if (!Array.isArray(sexpr))
9859
10141
  return;
@@ -9900,7 +10182,6 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
9900
10182
  return;
9901
10183
  }
9902
10184
  if (head === "for-in" || head === "for-of" || head === "for-as") {
9903
- this.collectVarsFromLoopHead(rest[0], this.programVars);
9904
10185
  rest.slice(1).forEach((item) => this.collectProgramVariables(item));
9905
10186
  return;
9906
10187
  }
@@ -9964,7 +10245,6 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
9964
10245
  return;
9965
10246
  }
9966
10247
  if (head === "for-in" || head === "for-of" || head === "for-as") {
9967
- this.collectVarsFromLoopHead(rest[0], vars);
9968
10248
  rest.slice(1).forEach(collect);
9969
10249
  return;
9970
10250
  }
@@ -9998,12 +10278,38 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
9998
10278
  collect(body);
9999
10279
  return vars;
10000
10280
  }
10281
+ collectTypedLocals(body) {
10282
+ let typed = new Map;
10283
+ let walk = (sexpr) => {
10284
+ if (!Array.isArray(sexpr))
10285
+ return;
10286
+ let [head, ...rest] = sexpr;
10287
+ head = str(head);
10288
+ if (Array.isArray(head)) {
10289
+ sexpr.forEach(walk);
10290
+ return;
10291
+ }
10292
+ if (CodeEmitter.ASSIGNMENT_OPS.has(head)) {
10293
+ let [target, value] = rest;
10294
+ if (target instanceof String && target.type && !typed.has(str(target))) {
10295
+ typed.set(str(target), target.type);
10296
+ }
10297
+ walk(value);
10298
+ return;
10299
+ }
10300
+ if (head === "def" || head === "->" || head === "=>" || head === "effect")
10301
+ return;
10302
+ rest.forEach(walk);
10303
+ };
10304
+ walk(body);
10305
+ return typed;
10306
+ }
10001
10307
  emit(sexpr, context = "statement") {
10002
10308
  if (sexpr instanceof String) {
10003
- if (meta(sexpr, "await") === true) {
10309
+ if (meta(sexpr, "bang") === true) {
10004
10310
  return `await ${str(sexpr)}()`;
10005
10311
  }
10006
- if (meta(sexpr, "predicate")) {
10312
+ if (meta(sexpr, "optional")) {
10007
10313
  return `(${str(sexpr)} != null)`;
10008
10314
  }
10009
10315
  if (meta(sexpr, "delimiter") === "///" && meta(sexpr, "heregex")) {
@@ -10055,7 +10361,7 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
10055
10361
  if (!Array.isArray(sexpr))
10056
10362
  this.error(`Invalid s-expression: ${JSON.stringify(sexpr)}`, sexpr);
10057
10363
  let [head, ...rest] = sexpr;
10058
- let headAwaitMeta = meta(head, "await");
10364
+ let headBangMeta = meta(head, "bang");
10059
10365
  head = str(head);
10060
10366
  let method = CodeEmitter.GENERATORS[head];
10061
10367
  if (method)
@@ -10069,7 +10375,7 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
10069
10375
  let postfix = this._tryPostfixCall(head, rest, context);
10070
10376
  if (postfix)
10071
10377
  return postfix;
10072
- let needsAwait = headAwaitMeta === true;
10378
+ let needsAwait = headBangMeta === true;
10073
10379
  let callStr = `${this.emit(head, "value")}(${this._emitArgs(rest)})`;
10074
10380
  return needsAwait ? `await ${callStr}` : callStr;
10075
10381
  }
@@ -10091,11 +10397,11 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
10091
10397
  return postfix;
10092
10398
  let needsAwait = false;
10093
10399
  let calleeCode;
10094
- if (head[0] === "." && meta(head[2], "await") === true) {
10400
+ if (head[0] === "." && meta(head[2], "bang") === true) {
10095
10401
  needsAwait = true;
10096
10402
  let [obj, prop] = head.slice(1);
10097
10403
  let objCode = this.emit(obj, "value");
10098
- let needsParens = CodeEmitter.NUMBER_LITERAL_RE.test(objCode) || (this.is(obj, "object") || this.is(obj, "await") || this.is(obj, "yield"));
10404
+ let needsParens = CodeEmitter.NUMBER_LITERAL_RE.test(objCode) || (this.is(obj, "object") || this.is(obj, "await") || this.is(obj, "yield")) || /^(await|yield)\s/.test(objCode);
10099
10405
  let base = needsParens ? `(${objCode})` : objCode;
10100
10406
  calleeCode = `${base}.${str(prop)}`;
10101
10407
  } else {
@@ -10149,7 +10455,12 @@ globalThis.zip ??= (...a) => a[0].map((_, i) => a.map(b => b[i]));
10149
10455
  `);
10150
10456
  let needsBlank = false;
10151
10457
  if (imports.length > 0) {
10152
- code += imports.map((s) => this.addSemicolon(s, this.emit(s, "statement"))).join(`
10458
+ let importEntries = imports.map((s) => {
10459
+ let generated = this.addSemicolon(s, this.emit(s, "statement"));
10460
+ return { code: generated, loc: Array.isArray(s) ? s.loc : null, sexpr: Array.isArray(s) ? s : null };
10461
+ });
10462
+ this._importEntries = importEntries;
10463
+ code += importEntries.map((e) => e.code).join(`
10153
10464
  `);
10154
10465
  needsBlank = true;
10155
10466
  }
@@ -10349,14 +10660,7 @@ function _setDataSection() {
10349
10660
  }
10350
10661
  return `if (${guardCode} != null) ${targetCode2} ${op} ${valueCode2}`;
10351
10662
  }
10352
- let isFnValue = this.is(value, "->") || this.is(value, "=>") || this.is(value, "def");
10353
- if (target instanceof String && meta(target, "await") !== undefined && !isFnValue) {
10354
- let sigil = meta(target, "await") === true ? "!" : "&";
10355
- this.error(`Cannot use ${sigil} sigil in variable declaration '${str(target)}'`, sexpr);
10356
- }
10357
- if (target instanceof String && meta(target, "await") === true && isFnValue) {
10358
- this.nextFunctionIsVoid = true;
10359
- }
10663
+ this.applyVoidMarker(target, value, sexpr);
10360
10664
  let isEmptyArr = this.is(target, "array", 0);
10361
10665
  let isEmptyObj = this.is(target, "object", 0);
10362
10666
  if (isEmptyArr || isEmptyObj) {
@@ -10438,7 +10742,7 @@ function _setDataSection() {
10438
10742
  }
10439
10743
  }
10440
10744
  let targetCode;
10441
- if (target instanceof String && meta(target, "await") !== undefined) {
10745
+ if (target instanceof String && meta(target, "bang") !== undefined) {
10442
10746
  targetCode = str(target);
10443
10747
  } else if (typeof target === "string" && this.reactiveVars?.has(target)) {
10444
10748
  targetCode = `${target}.value`;
@@ -10478,9 +10782,9 @@ function _setDataSection() {
10478
10782
  let objCode = this.emit(obj, "value");
10479
10783
  let needsParens = CodeEmitter.NUMBER_LITERAL_RE.test(objCode) || objCode.startsWith("await ") || (this.is(obj, "object") || this.is(obj, "yield"));
10480
10784
  let base = needsParens ? `(${objCode})` : objCode;
10481
- if (meta(prop, "await") === true)
10785
+ if (meta(prop, "bang") === true)
10482
10786
  return `await ${base}.${str(prop)}()`;
10483
- if (meta(prop, "predicate"))
10787
+ if (meta(prop, "optional"))
10484
10788
  return `(${base}.${str(prop)} != null)`;
10485
10789
  return `${base}.${str(prop)}`;
10486
10790
  }
@@ -10603,7 +10907,7 @@ function _setDataSection() {
10603
10907
  }
10604
10908
  emitDef(head, rest, context, sexpr) {
10605
10909
  let [name, params, body] = rest;
10606
- let sideEffectOnly = meta(name, "await") === true;
10910
+ let sideEffectOnly = meta(name, "bang") === true;
10607
10911
  let cleanName = str(name);
10608
10912
  let paramList = this.emitParamList(params);
10609
10913
  let bodyCode = this.emitFunctionBody(body, params, sideEffectOnly);
@@ -10615,8 +10919,7 @@ function _setDataSection() {
10615
10919
  let [params, body] = rest;
10616
10920
  if ((!params || Array.isArray(params) && params.length === 0) && this.containsIt(body))
10617
10921
  params = ["it"];
10618
- let sideEffectOnly = this.nextFunctionIsVoid || false;
10619
- this.nextFunctionIsVoid = false;
10922
+ let sideEffectOnly = sexpr.isVoid || false;
10620
10923
  let paramList = this.emitParamList(params);
10621
10924
  let bodyCode = this.emitFunctionBody(body, params, sideEffectOnly);
10622
10925
  let isAsync = this.containsAwait(body);
@@ -10628,8 +10931,7 @@ function _setDataSection() {
10628
10931
  let [params, body] = rest;
10629
10932
  if ((!params || Array.isArray(params) && params.length === 0) && this.containsIt(body))
10630
10933
  params = ["it"];
10631
- let sideEffectOnly = this.nextFunctionIsVoid || false;
10632
- this.nextFunctionIsVoid = false;
10934
+ let sideEffectOnly = sexpr.isVoid || false;
10633
10935
  let paramList = this.emitParamList(params);
10634
10936
  let isSingle = params.length === 1 && typeof params[0] === "string" && !paramList.includes("=") && !paramList.includes("...") && !paramList.includes("[") && !paramList.includes("{");
10635
10937
  let paramSyntax = isSingle ? paramList : `(${paramList})`;
@@ -11100,7 +11402,14 @@ ${this.indent()}}`;
11100
11402
  return this.emit(ops[0], "value");
11101
11403
  return `(${ops.map((o) => this.emit(o, "value")).join(" || ")})`;
11102
11404
  }
11103
- emitSymbol(head, rest) {
11405
+ emitSymbol(head, rest, context, sexpr) {
11406
+ if (sexpr && sexpr.loc && typeof rest[0] === "string") {
11407
+ sexpr._anchors = (sexpr._anchors || []).concat([{
11408
+ name: "Symbol",
11409
+ origLine: sexpr.loc.r,
11410
+ origCol: sexpr.loc.c + 1
11411
+ }]);
11412
+ }
11104
11413
  return `Symbol.for(${JSON.stringify(rest[0])})`;
11105
11414
  }
11106
11415
  emitArray(head, elements) {
@@ -11182,8 +11491,7 @@ ${this.indent()}}`;
11182
11491
  let [, mParams, mBody] = value;
11183
11492
  if ((!mParams || Array.isArray(mParams) && mParams.length === 0) && this.containsIt(mBody))
11184
11493
  mParams = ["it"];
11185
- let mSideEffect = this.nextFunctionIsVoid || false;
11186
- this.nextFunctionIsVoid = false;
11494
+ let mSideEffect = value.isVoid || false;
11187
11495
  let mParamList = this.emitParamList(mParams);
11188
11496
  let mBodyCode = this.emitFunctionBody(mBody, mParams, mSideEffect);
11189
11497
  let mIsAsync = this.containsAwait(mBody);
@@ -11753,7 +12061,7 @@ ${this.indent()}}`;
11753
12061
  emitImport(head, rest, context, sexpr) {
11754
12062
  if (rest.length === 1) {
11755
12063
  let importExpr = `import(${this.emit(rest[0], "value")})`;
11756
- if (meta(sexpr[0], "await") === true)
12064
+ if (meta(sexpr[0], "bang") === true)
11757
12065
  return `(await ${importExpr})`;
11758
12066
  return importExpr;
11759
12067
  }
@@ -11765,6 +12073,7 @@ ${this.indent()}}`;
11765
12073
  if (named[0] === "*" && named.length === 2)
11766
12074
  return `import ${def}, * as ${named[1]} from ${fixedSource2}`;
11767
12075
  let names = named.map((i) => Array.isArray(i) && i.length === 2 ? `${i[0]} as ${i[1]}` : i).join(", ");
12076
+ this._attachImportSpecifierAnchors(sexpr, [def, ...named.flatMap((i) => Array.isArray(i) ? i : [i])]);
11768
12077
  return `import ${def}, { ${names} } from ${fixedSource2}`;
11769
12078
  }
11770
12079
  let [specifier, source] = rest;
@@ -11775,10 +12084,59 @@ ${this.indent()}}`;
11775
12084
  if (specifier[0] === "*" && specifier.length === 2)
11776
12085
  return `import * as ${specifier[1]} from ${fixedSource}`;
11777
12086
  let names = specifier.map((i) => Array.isArray(i) && i.length === 2 ? `${i[0]} as ${i[1]}` : i).join(", ");
12087
+ this._attachImportSpecifierAnchors(sexpr, specifier.flatMap((i) => Array.isArray(i) ? i : [i]));
11778
12088
  return `import { ${names} } from ${fixedSource}`;
11779
12089
  }
11780
12090
  return `import ${this.emit(specifier, "value")} from ${fixedSource}`;
11781
12091
  }
12092
+ _attachImportSpecifierAnchors(sexpr, names) {
12093
+ if (!sexpr || !sexpr.loc)
12094
+ return;
12095
+ const source = this.options && this.options.source;
12096
+ if (!source || !names || !names.length)
12097
+ return;
12098
+ const lines = this._sourceLinesCache || (this._sourceLinesCache = source.split(`
12099
+ `));
12100
+ let row = sexpr.loc.r;
12101
+ let col = sexpr.loc.c;
12102
+ const anchors = [];
12103
+ for (const name of names) {
12104
+ if (typeof name !== "string" || !/^[A-Za-z_$][\w$]*$/.test(name))
12105
+ continue;
12106
+ const re = new RegExp("\\b" + name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "\\b");
12107
+ let found = false;
12108
+ while (row < lines.length) {
12109
+ const line = lines[row] || "";
12110
+ const codePart = line.replace(/#.*$/, "");
12111
+ re.lastIndex = 0;
12112
+ const slice = codePart.slice(col);
12113
+ const m = re.exec(slice);
12114
+ if (m) {
12115
+ const c = col + m.index;
12116
+ anchors.push({ name, origLine: row, origCol: c });
12117
+ col = c + name.length;
12118
+ found = true;
12119
+ break;
12120
+ }
12121
+ row++;
12122
+ col = 0;
12123
+ }
12124
+ if (!found)
12125
+ break;
12126
+ }
12127
+ if (anchors.length)
12128
+ sexpr._anchors = (sexpr._anchors || []).concat(anchors);
12129
+ }
12130
+ applyVoidMarker(target, value, sexpr) {
12131
+ let isFnValue = this.is(value, "->") || this.is(value, "=>") || this.is(value, "def");
12132
+ if (target instanceof String && meta(target, "bang") !== undefined && !isFnValue) {
12133
+ let sigil = meta(target, "bang") === true ? "!" : "&";
12134
+ this.error(`Cannot use ${sigil} sigil in variable declaration '${str(target)}'`, sexpr);
12135
+ }
12136
+ if (target instanceof String && meta(target, "bang") === true && isFnValue) {
12137
+ value.isVoid = true;
12138
+ }
12139
+ }
11782
12140
  emitExport(head, rest) {
11783
12141
  let [decl] = rest;
11784
12142
  if (this.options.skipExports) {
@@ -11792,6 +12150,7 @@ ${this.indent()}}`;
11792
12150
  }
11793
12151
  if (this.is(decl[2], "schema"))
11794
12152
  this._schemaName = str(decl[1]);
12153
+ this.applyVoidMarker(decl[1], decl[2], decl);
11795
12154
  const result = `const ${decl[1]} = ${this.emit(decl[2], "value")}`;
11796
12155
  this._componentName = prev;
11797
12156
  this._componentTypeParams = prevTP;
@@ -11812,6 +12171,7 @@ ${this.indent()}}`;
11812
12171
  }
11813
12172
  if (this.is(decl[2], "schema"))
11814
12173
  this._schemaName = str(decl[1]);
12174
+ this.applyVoidMarker(decl[1], decl[2], decl);
11815
12175
  const result = `export const ${decl[1]} = ${this.emit(decl[2], "value")}`;
11816
12176
  this._componentName = prev;
11817
12177
  this._componentTypeParams = prevTP;
@@ -11825,11 +12185,14 @@ ${this.indent()}}`;
11825
12185
  emitExportDefault(head, rest) {
11826
12186
  let [expr] = rest;
11827
12187
  if (this.options.skipExports) {
11828
- if (this.is(expr, "="))
12188
+ if (this.is(expr, "=")) {
12189
+ this.applyVoidMarker(expr[1], expr[2], expr);
11829
12190
  return `const ${expr[1]} = ${this.emit(expr[2], "value")}`;
12191
+ }
11830
12192
  return this.emit(expr, "statement");
11831
12193
  }
11832
12194
  if (this.is(expr, "=")) {
12195
+ this.applyVoidMarker(expr[1], expr[2], expr);
11833
12196
  return `const ${expr[1]} = ${this.emit(expr[2], "value")};
11834
12197
  export default ${expr[1]}`;
11835
12198
  }
@@ -11957,10 +12320,19 @@ export default ${expr[1]}`;
11957
12320
  formatParam(param) {
11958
12321
  if (typeof param === "string")
11959
12322
  return param;
11960
- if (param instanceof String)
12323
+ if (param instanceof String) {
12324
+ if (this.options.inlineTypes && param.type) {
12325
+ return `${param.valueOf()}: ${param.type.replace(/::/g, ":")}`;
12326
+ }
11961
12327
  return param.valueOf();
11962
- if (this.is(param, "rest"))
11963
- return `...${param[1]}`;
12328
+ }
12329
+ if (this.is(param, "rest")) {
12330
+ let restName = param[1];
12331
+ if (this.options.inlineTypes && restName instanceof String && restName.type) {
12332
+ return `...${restName.valueOf()}: ${restName.type.replace(/::/g, ":")}`;
12333
+ }
12334
+ return `...${restName}`;
12335
+ }
11964
12336
  if (this.is(param, "default")) {
11965
12337
  return `${this.formatParam(param[1])} = ${this.emit(param[2], "value")}`;
11966
12338
  }
@@ -12005,15 +12377,15 @@ export default ${expr[1]}`;
12005
12377
  this.sideEffectOnly = sideEffectOnly;
12006
12378
  let paramNames = new Set;
12007
12379
  let extractPN = (p) => {
12008
- if (typeof p === "string")
12009
- paramNames.add(p);
12380
+ if (typeof p === "string" || p instanceof String)
12381
+ paramNames.add(str(p));
12010
12382
  else if (Array.isArray(p)) {
12011
12383
  if (p[0] === "rest" || p[0] === "...") {
12012
- if (typeof p[1] === "string")
12013
- paramNames.add(p[1]);
12384
+ if (typeof p[1] === "string" || p[1] instanceof String)
12385
+ paramNames.add(str(p[1]));
12014
12386
  } else if (p[0] === "default") {
12015
- if (typeof p[1] === "string")
12016
- paramNames.add(p[1]);
12387
+ if (typeof p[1] === "string" || p[1] instanceof String)
12388
+ paramNames.add(str(p[1]));
12017
12389
  } else if (p[0] === "array" || p[0] === "object")
12018
12390
  this.collectVarsFromArray(p, paramNames);
12019
12391
  }
@@ -12051,9 +12423,15 @@ export default ${expr[1]}`;
12051
12423
  this.indentLevel++;
12052
12424
  let code = `{
12053
12425
  `;
12054
- if (newVars.size > 0)
12055
- code += this.indent() + `let ${Array.from(newVars).sort().join(", ")};
12426
+ if (newVars.size > 0) {
12427
+ let typedLocals = this.options.inlineTypes ? this.collectTypedLocals(body) : null;
12428
+ let names = Array.from(newVars).sort().map((n) => {
12429
+ let t = typedLocals?.get(n);
12430
+ return t ? `${n}: ${t}` : n;
12431
+ });
12432
+ code += this.indent() + `let ${names.join(", ")};
12056
12433
  `;
12434
+ }
12057
12435
  let firstIsSuper = autoAssignments.length > 0 && statements.length > 0 && Array.isArray(statements[0]) && statements[0][0] === "super";
12058
12436
  let genStatements = (stmts) => {
12059
12437
  stmts.forEach((stmt, index) => {
@@ -12998,7 +13376,7 @@ ${this.indent()}}`;
12998
13376
  containsAwait(sexpr) {
12999
13377
  if (!sexpr)
13000
13378
  return false;
13001
- if (sexpr instanceof String && meta(sexpr, "await") === true)
13379
+ if (sexpr instanceof String && meta(sexpr, "bang") === true)
13002
13380
  return true;
13003
13381
  if (typeof sexpr !== "object")
13004
13382
  return false;
@@ -13438,7 +13816,7 @@ if (typeof globalThis !== 'undefined') {
13438
13816
  typeTokens = [...tokens];
13439
13817
  }
13440
13818
  tokens = tokens.filter((t) => t[0] !== "TYPE_DECL");
13441
- if (lexer.typeRefNames?.size > 0) {
13819
+ if (lexer.typeRefNames?.size > 0 && !this.options.inlineTypes) {
13442
13820
  let usedNames = new Set;
13443
13821
  let inImport = false;
13444
13822
  for (let t of tokens) {
@@ -13665,6 +14043,7 @@ if (typeof globalThis !== 'undefined') {
13665
14043
  skipDataPart: this.options.skipDataPart,
13666
14044
  stubComponents: this.options.stubComponents,
13667
14045
  reactiveVars: this.options.reactiveVars,
14046
+ inlineTypes: this.options.inlineTypes,
13668
14047
  schemaMode: this.options.schemaMode,
13669
14048
  sourceMap
13670
14049
  });
@@ -13737,8 +14116,8 @@ if (typeof globalThis !== 'undefined') {
13737
14116
  return new CodeEmitter({}).getComponentRuntime();
13738
14117
  }
13739
14118
  // src/browser.js
13740
- var VERSION = "3.16.0";
13741
- var BUILD_DATE = "2026-05-22@08:07:44GMT";
14119
+ var VERSION = "3.16.1";
14120
+ var BUILD_DATE = "2026-06-05@18:16:05GMT";
13742
14121
  if (typeof globalThis !== "undefined") {
13743
14122
  if (!globalThis.__rip)
13744
14123
  new Function(getReactiveRuntime())();
@@ -13751,6 +14130,36 @@ if (typeof globalThis !== 'undefined') {
13751
14130
  return s.replace(RegExp(`^[ ]{${i}}`, "gm"), "").trim();
13752
14131
  };
13753
14132
  var sanitizeSourceURL = (url) => String(url).replace(/[\r\n]/g, "").replace(/\s+$/g, "");
14133
+ function rewriteRipPkgImports(js) {
14134
+ const re = /^(\s*)import\s+([^'"]+?)\s+from\s+['"](@rip-lang\/[^'"]+)['"];?\s*$/gm;
14135
+ return js.replace(re, (full, indent, clause, spec) => {
14136
+ const trimmed = clause.trim();
14137
+ if (trimmed.startsWith("type "))
14138
+ return `${indent}// type-only import erased: ${spec}`;
14139
+ const open = trimmed.indexOf("{");
14140
+ const close = trimmed.lastIndexOf("}");
14141
+ if (open < 0 || close <= open) {
14142
+ console.warn(`[Rip] Skipping non-named import from ${spec}; only \`import { … } from '@rip-lang/*'\` is supported in browser bundles.`);
14143
+ return full;
14144
+ }
14145
+ const inside = trimmed.slice(open + 1, close);
14146
+ const parts = [];
14147
+ for (let raw of inside.split(",")) {
14148
+ let name = raw.trim().replace(/^type\s+/, "");
14149
+ if (!name)
14150
+ continue;
14151
+ if (/\s+as\s+/.test(name)) {
14152
+ const [orig, alias] = name.split(/\s+as\s+/).map((s) => s.trim());
14153
+ parts.push(`${orig}: ${alias}`);
14154
+ } else {
14155
+ parts.push(name);
14156
+ }
14157
+ }
14158
+ if (parts.length === 0)
14159
+ return `${indent}// import erased: ${spec}`;
14160
+ return `${indent}const { ${parts.join(", ")} } = globalThis;`;
14161
+ });
14162
+ }
13754
14163
  function addSourceURL(js, generatedName) {
13755
14164
  const safe = sanitizeSourceURL(generatedName);
13756
14165
  const pragma = `//# sourceURL=${safe}`;
@@ -13816,8 +14225,8 @@ ${tagged}
13816
14225
  if (url)
13817
14226
  sources.push({ url });
13818
14227
  }
13819
- } else if (runtimeTag) {
13820
- sources.push({ url: "/app" });
14228
+ } else if (runtimeTag && /^https?:$/.test(location.protocol)) {
14229
+ sources.push({ url: "/app", optional: true });
13821
14230
  }
13822
14231
  for (const script of document.querySelectorAll('script[type="text/rip"]')) {
13823
14232
  if (script.src) {
@@ -13842,9 +14251,11 @@ ${tagged}
13842
14251
  s.bundle = bundle;
13843
14252
  }
13844
14253
  }));
13845
- for (const r of results) {
13846
- if (r.status === "rejected")
14254
+ for (let i = 0;i < results.length; i++) {
14255
+ const r = results[i];
14256
+ if (r.status === "rejected" && !sources[i].optional) {
13847
14257
  console.warn("Rip: fetch failed:", r.reason.message);
14258
+ }
13848
14259
  }
13849
14260
  const bundles = [];
13850
14261
  const individual = [];
@@ -13875,7 +14286,7 @@ ${tagged}
13875
14286
  const opts = debug ? { ...baseOpts, sourceMap: "inline", filename: ripName } : baseOpts;
13876
14287
  let js;
13877
14288
  try {
13878
- js = compileToJS(s.code, opts);
14289
+ js = rewriteRipPkgImports(compileToJS(s.code, opts));
13879
14290
  } catch (e) {
13880
14291
  console.error(formatError(e, { source: s.code, file: ripName, color: false }));
13881
14292
  continue;
@@ -13899,7 +14310,8 @@ ${js}
13899
14310
  } else {
13900
14311
  const expanded = [];
13901
14312
  for (const b of bundles) {
13902
- for (const [name, code] of Object.entries(b.components || {})) {
14313
+ const mods = b.modules || b.components || {};
14314
+ for (const [name, code] of Object.entries(mods)) {
13903
14315
  expanded.push({ code, url: name });
13904
14316
  }
13905
14317
  if (b.data) {
@@ -13918,8 +14330,9 @@ ${js}
13918
14330
  if (bundles.length > 0 && typeof globalThis.createComponents === "function") {
13919
14331
  const sourceStore = globalThis.createComponents();
13920
14332
  for (const b of bundles) {
13921
- if (b.components)
13922
- sourceStore.load(b.components);
14333
+ const mods = b.modules || b.components;
14334
+ if (mods)
14335
+ sourceStore.load(mods);
13923
14336
  }
13924
14337
  if (typeof window !== "undefined") {
13925
14338
  if (!window.__RIP__)
@@ -13939,14 +14352,14 @@ ${js}
13939
14352
  const ripName = s.url || `inline-${++inlineCounter}.rip`;
13940
14353
  const opts = debug ? { ...baseOpts, sourceMap: "inline", filename: ripName } : baseOpts;
13941
14354
  try {
13942
- const js = compileToJS(s.code, opts);
14355
+ const js = rewriteRipPkgImports(compileToJS(s.code, opts));
13943
14356
  compiled.push({ js, url: ripName });
13944
14357
  } catch (e) {
13945
14358
  console.error(formatError(e, { source: s.code, file: ripName, color: false }));
13946
14359
  }
13947
14360
  }
13948
14361
  if (!globalThis.__ripApp && runtimeTag) {
13949
- const stashFn = globalThis.stash;
14362
+ const stashFn = globalThis.createStash;
13950
14363
  if (stashFn) {
13951
14364
  let initial = {};
13952
14365
  const stateAttr = runtimeTag.getAttribute("data-state");
@@ -14043,7 +14456,7 @@ ${wrapped}
14043
14456
  throw new Error(`importRip: ${url} (${r.status})`);
14044
14457
  return r.text();
14045
14458
  });
14046
- const js = compileToJS(source);
14459
+ const js = rewriteRipPkgImports(compileToJS(source));
14047
14460
  const header = `// ${url}
14048
14461
  `;
14049
14462
  const blob = new Blob([header + js], { type: "application/javascript" });
@@ -14093,18 +14506,17 @@ ${indented}`);
14093
14506
  // docs/dist/_app.js
14094
14507
  var exports__app = {};
14095
14508
  __export(exports__app, {
14509
+ unwrapStash: () => unwrapStash,
14096
14510
  throttle: () => throttle,
14097
- stash: () => stash,
14098
14511
  setContext: () => setContext,
14099
- raw: () => raw,
14100
14512
  persistStash: () => persistStash,
14101
14513
  launch: () => launch,
14102
- isStash: () => isStash,
14103
14514
  hold: () => hold,
14104
14515
  hasContext: () => hasContext,
14105
14516
  getContext: () => getContext,
14106
14517
  delay: () => delay,
14107
14518
  debounce: () => debounce,
14519
+ createStash: () => createStash,
14108
14520
  createRouter: () => createRouter,
14109
14521
  createResource: () => createResource,
14110
14522
  createRenderer: () => createRenderer,
@@ -14118,6 +14530,7 @@ ${indented}`);
14118
14530
  var __batch;
14119
14531
  var __computed;
14120
14532
  var __effect;
14533
+ var __ripCtx;
14121
14534
  var __state;
14122
14535
  var _ariaAnchorChecked;
14123
14536
  var _ariaAnchorSupported;
@@ -14155,10 +14568,8 @@ ${indented}`);
14155
14568
  var fileToPattern;
14156
14569
  var findAllComponents;
14157
14570
  var findComponent;
14158
- var getContext;
14159
14571
  var getLayoutChain;
14160
14572
  var getSignal;
14161
- var hasContext;
14162
14573
  var isNum;
14163
14574
  var isPathKey;
14164
14575
  var keysSignal;
@@ -14167,7 +14578,6 @@ ${indented}`);
14167
14578
  var patternToRegex;
14168
14579
  var resolveIndex;
14169
14580
  var resolveStorePath;
14170
- var setContext;
14171
14581
  var stashGet;
14172
14582
  var stashMethodFn;
14173
14583
  var stashSet;
@@ -14260,7 +14670,16 @@ ${indented}`);
14260
14670
  globalThis.warn ??= console.warn;
14261
14671
  globalThis.zip ??= (...a) => a[0].map((_, i) => a.map((b) => b[i]));
14262
14672
  ({ __state, __computed, __effect, __batch } = globalThis.__rip);
14263
- ({ setContext, getContext, hasContext } = globalThis.__ripComponent || {});
14673
+ __ripCtx = globalThis.__ripComponent || {};
14674
+ var setContext = function(key, value) {
14675
+ return __ripCtx.setContext(key, value);
14676
+ };
14677
+ var getContext = function(key) {
14678
+ return __ripCtx.getContext(key);
14679
+ };
14680
+ var hasContext = function(key) {
14681
+ return __ripCtx.hasContext(key);
14682
+ };
14264
14683
  assertBrowser = function(where) {
14265
14684
  if (typeof window === "undefined" || typeof document === "undefined") {
14266
14685
  throw new Error(`Rip App: '${where}' requires a browser environment`);
@@ -14334,7 +14753,7 @@ ${indented}`);
14334
14753
  return val;
14335
14754
  },
14336
14755
  set(target2, prop, value) {
14337
- let i, newLen, old, oldLen, r, sig;
14756
+ let newLen, old, oldLen, r, sig;
14338
14757
  if (!_depth && isPathKey(prop)) {
14339
14758
  stashSet(proxy, prop, value);
14340
14759
  return true;
@@ -14345,10 +14764,10 @@ ${indented}`);
14345
14764
  target2.length = newLen;
14346
14765
  if (newLen !== oldLen) {
14347
14766
  if (target2[Symbol.for("signals")]) {
14348
- for (let i2 of ((s, e) => Array.from({ length: Math.max(0, Math.abs(e - s)) }, (_, i3) => s + i3 * (s <= e ? 1 : -1)))(Math.min(oldLen, newLen), Math.max(oldLen, newLen))) {
14349
- sig = target2[Symbol.for("signals")].get(String(i2));
14767
+ for (let i of ((s, e) => Array.from({ length: Math.max(0, Math.abs(e - s)) }, (_, i2) => s + i2 * (s <= e ? 1 : -1)))(Math.min(oldLen, newLen), Math.max(oldLen, newLen))) {
14768
+ sig = target2[Symbol.for("signals")].get(String(i));
14350
14769
  if (sig != null)
14351
- sig.value = target2[i2];
14770
+ sig.value = target2[i];
14352
14771
  }
14353
14772
  }
14354
14773
  keysSignal(target2).value = ++_keysVersion;
@@ -14415,23 +14834,23 @@ ${indented}`);
14415
14834
  resolveIndex = function(seg, obj) {
14416
14835
  let t;
14417
14836
  if (typeof seg === "number" && seg < 0) {
14418
- t = raw(obj);
14837
+ t = unwrapStash(obj);
14419
14838
  if (Array.isArray(t))
14420
14839
  return t.length + seg;
14421
14840
  }
14422
14841
  return seg;
14423
14842
  };
14424
14843
  stashGet = function(proxy, path) {
14425
- let obj, seg, segs;
14844
+ let obj, segs;
14426
14845
  segs = walk(path);
14427
14846
  obj = proxy;
14428
14847
  _depth++;
14429
14848
  return (() => {
14430
14849
  try {
14431
- for (let seg2 of segs) {
14850
+ for (let seg of segs) {
14432
14851
  if (!(obj != null))
14433
14852
  return;
14434
- obj = obj[resolveIndex(seg2, obj)];
14853
+ obj = obj[resolveIndex(seg, obj)];
14435
14854
  }
14436
14855
  return obj;
14437
14856
  } finally {
@@ -14440,20 +14859,20 @@ ${indented}`);
14440
14859
  })();
14441
14860
  };
14442
14861
  stashSet = function(proxy, path, value) {
14443
- let i, key, nextSeg, obj, seg, segs;
14862
+ let key, nextSeg, obj, segs;
14444
14863
  segs = walk(path);
14445
14864
  obj = proxy;
14446
14865
  _depth++;
14447
14866
  return (() => {
14448
14867
  try {
14449
- for (let i2 = 0;i2 < segs.length; i2++) {
14450
- let seg2 = segs[i2];
14451
- key = resolveIndex(seg2, obj);
14452
- if (i2 === segs.length - 1) {
14868
+ for (let i = 0;i < segs.length; i++) {
14869
+ let seg = segs[i];
14870
+ key = resolveIndex(seg, obj);
14871
+ if (i === segs.length - 1) {
14453
14872
  obj[key] = value;
14454
14873
  } else {
14455
14874
  if (!(obj[key] != null)) {
14456
- nextSeg = segs[i2 + 1];
14875
+ nextSeg = segs[i + 1];
14457
14876
  obj[key] = typeof nextSeg === "number" || isNum(nextSeg) ? [] : {};
14458
14877
  }
14459
14878
  obj = obj[key];
@@ -14500,7 +14919,7 @@ ${indented}`);
14500
14919
  case "join":
14501
14920
  return function(path, obj) {
14502
14921
  return __batch(function() {
14503
- let k, target, v;
14922
+ let target;
14504
14923
  target = stashGet(proxy, path);
14505
14924
  if (!(target != null && typeof target === "object")) {
14506
14925
  stashSet(proxy, path, {});
@@ -14511,9 +14930,9 @@ ${indented}`);
14511
14930
  try {
14512
14931
  return (() => {
14513
14932
  const result = [];
14514
- for (let k2 in obj) {
14515
- let v2 = obj[k2];
14516
- result.push(target[k2] = v2);
14933
+ for (let k in obj) {
14934
+ let v = obj[k];
14935
+ result.push(target[k] = v);
14517
14936
  }
14518
14937
  return result;
14519
14938
  })();
@@ -14525,20 +14944,20 @@ ${indented}`);
14525
14944
  };
14526
14945
  case "keys":
14527
14946
  return function(path) {
14528
- let obj, seg, segs, t;
14947
+ let obj, segs, t;
14529
14948
  _depth++;
14530
14949
  return (() => {
14531
14950
  try {
14532
14951
  segs = walk(path);
14533
14952
  obj = proxy;
14534
- for (let seg2 of segs) {
14953
+ for (let seg of segs) {
14535
14954
  if (!(obj != null))
14536
14955
  return [];
14537
- obj = obj[resolveIndex(seg2, obj)];
14956
+ obj = obj[resolveIndex(seg, obj)];
14538
14957
  }
14539
14958
  if (!(obj != null && typeof obj === "object"))
14540
14959
  return [];
14541
- t = raw(obj);
14960
+ t = unwrapStash(obj);
14542
14961
  keysSignal(t).value;
14543
14962
  return Object.keys(t);
14544
14963
  } finally {
@@ -14548,7 +14967,7 @@ ${indented}`);
14548
14967
  };
14549
14968
  case "has":
14550
14969
  return function(path) {
14551
- let i, key, obj, seg, segs, t;
14970
+ let key, obj, segs, t;
14552
14971
  _depth++;
14553
14972
  return (() => {
14554
14973
  try {
@@ -14556,11 +14975,11 @@ ${indented}`);
14556
14975
  if (!(segs.length > 0))
14557
14976
  return false;
14558
14977
  obj = proxy;
14559
- for (let i2 = 0;i2 < segs.length; i2++) {
14560
- let seg2 = segs[i2];
14561
- key = resolveIndex(seg2, obj);
14562
- if (i2 === segs.length - 1) {
14563
- t = raw(obj);
14978
+ for (let i = 0;i < segs.length; i++) {
14979
+ let seg = segs[i];
14980
+ key = resolveIndex(seg, obj);
14981
+ if (i === segs.length - 1) {
14982
+ t = unwrapStash(obj);
14564
14983
  keysSignal(t).value;
14565
14984
  return Object.prototype.hasOwnProperty.call(t, key);
14566
14985
  }
@@ -14576,7 +14995,7 @@ ${indented}`);
14576
14995
  };
14577
14996
  case "del":
14578
14997
  return function(path) {
14579
- let i, key, obj, seg, segs;
14998
+ let key, obj, segs;
14580
14999
  _depth++;
14581
15000
  return (() => {
14582
15001
  try {
@@ -14586,10 +15005,10 @@ ${indented}`);
14586
15005
  obj = proxy;
14587
15006
  return (() => {
14588
15007
  const result = [];
14589
- for (let i2 = 0;i2 < segs.length; i2++) {
14590
- let seg2 = segs[i2];
14591
- key = resolveIndex(seg2, obj);
14592
- if (i2 === segs.length - 1) {
15008
+ for (let i = 0;i < segs.length; i++) {
15009
+ let seg = segs[i];
15010
+ key = resolveIndex(seg, obj);
15011
+ if (i === segs.length - 1) {
14593
15012
  delete obj[key];
14594
15013
  return;
14595
15014
  }
@@ -14609,19 +15028,16 @@ ${indented}`);
14609
15028
  cache[prop] = fn;
14610
15029
  return fn;
14611
15030
  };
14612
- var stash = function(data = {}) {
15031
+ function createStash(data = {}) {
14613
15032
  return makeProxy(data);
14614
- };
14615
- var raw = function(proxy) {
15033
+ }
15034
+ function unwrapStash(proxy) {
14616
15035
  return proxy?.[Symbol.for("raw")] ? proxy[Symbol.for("raw")] : proxy;
14617
- };
14618
- var isStash = function(obj) {
14619
- return obj?.[Symbol.for("stash")] === true;
14620
- };
14621
- var persistStash = function(app, opts = {}) {
14622
- let _save, disposed, effectDisposer, k, saved, savedData, storage, storageKey, target, v;
15036
+ }
15037
+ function persistStash(app, opts = {}) {
15038
+ let _save, disposed, effectDisposer, saved, savedData, storage, storageKey, target;
14623
15039
  assertBrowser("persistStash");
14624
- target = raw(app) || app;
15040
+ target = unwrapStash(app) || app;
14625
15041
  return function() {
14626
15042
  return target[Symbol.for("persisted")] ? null : undefined;
14627
15043
  };
@@ -14632,16 +15048,16 @@ ${indented}`);
14632
15048
  saved = storage.getItem(storageKey);
14633
15049
  if (saved) {
14634
15050
  savedData = JSON.parse(saved);
14635
- for (let k2 in savedData) {
14636
- let v2 = savedData[k2];
14637
- app.data[k2] = v2;
15051
+ for (let k in savedData) {
15052
+ let v = savedData[k];
15053
+ app.data[k] = v;
14638
15054
  }
14639
15055
  }
14640
15056
  } catch {}
14641
15057
  _save = function() {
14642
15058
  return (() => {
14643
15059
  try {
14644
- return storage.setItem(storageKey, JSON.stringify(raw(app.data)));
15060
+ return storage.setItem(storageKey, JSON.stringify(unwrapStash(app.data)));
14645
15061
  } catch {
14646
15062
  return null;
14647
15063
  }
@@ -14666,8 +15082,8 @@ ${indented}`);
14666
15082
  _save();
14667
15083
  return target[Symbol.for("persisted")] = false;
14668
15084
  };
14669
- };
14670
- var createResource = function(fn, opts = {}) {
15085
+ }
15086
+ function createResource(fn, opts = {}) {
14671
15087
  let _data, _error, _loading, controller, dispose, generation, load, resource;
14672
15088
  _data = __state(opts.initial ?? null);
14673
15089
  _loading = __state(false);
@@ -14723,7 +15139,7 @@ ${indented}`);
14723
15139
  return null;
14724
15140
  });
14725
15141
  return resource;
14726
- };
15142
+ }
14727
15143
  _toFn = function(source) {
14728
15144
  return typeof source === "function" ? source : function() {
14729
15145
  return source.value;
@@ -14833,18 +15249,17 @@ ${indented}`);
14833
15249
  });
14834
15250
  return typeof source !== "function" ? _proxy(out, source, eff) : _attachDispose(out, eff);
14835
15251
  };
14836
- var createComponents = function() {
15252
+ function createComponents() {
14837
15253
  let compiled, files, notify, watchers;
14838
15254
  files = new Map;
14839
15255
  watchers = new Set;
14840
15256
  compiled = new Map;
14841
15257
  notify = function(event, path) {
14842
- let watcher;
14843
15258
  const _result = [];
14844
- for (let watcher2 of Array.from(watchers)) {
15259
+ for (let watcher of Array.from(watchers)) {
14845
15260
  _result.push((() => {
14846
15261
  try {
14847
- return watcher2(event, path);
15262
+ return watcher(event, path);
14848
15263
  } catch (e) {
14849
15264
  return console.error("[Rip] watcher error:", e);
14850
15265
  }
@@ -14875,36 +15290,35 @@ ${indented}`);
14875
15290
  return files.size;
14876
15291
  },
14877
15292
  list(dir = "") {
14878
- let path, prefix, rest, result;
15293
+ let prefix, rest, result;
14879
15294
  result = [];
14880
15295
  prefix = dir ? dir + "/" : "";
14881
- for (let [path2] of files) {
14882
- if (path2.startsWith(prefix)) {
14883
- rest = path2.slice(prefix.length);
15296
+ for (let [path] of files) {
15297
+ if (path.startsWith(prefix)) {
15298
+ rest = path.slice(prefix.length);
14884
15299
  if (rest.includes("/"))
14885
15300
  continue;
14886
- result.push(path2);
15301
+ result.push(path);
14887
15302
  }
14888
15303
  }
14889
15304
  return result;
14890
15305
  },
14891
15306
  listAll(dir = "") {
14892
- let path, prefix, result;
15307
+ let prefix, result;
14893
15308
  result = [];
14894
15309
  prefix = dir ? dir + "/" : "";
14895
- for (let [path2] of files) {
14896
- if (path2.startsWith(prefix))
14897
- result.push(path2);
15310
+ for (let [path] of files) {
15311
+ if (path.startsWith(prefix))
15312
+ result.push(path);
14898
15313
  }
14899
15314
  return result;
14900
15315
  },
14901
15316
  load(obj) {
14902
- let content, key;
14903
15317
  const _result = [];
14904
- for (let key2 in obj) {
14905
- let content2 = obj[key2];
14906
- files.set(key2, content2);
14907
- _result.push(compiled.delete(key2));
15318
+ for (let key in obj) {
15319
+ let content = obj[key];
15320
+ files.set(key, content);
15321
+ _result.push(compiled.delete(key));
14908
15322
  }
14909
15323
  return _result;
14910
15324
  },
@@ -14926,7 +15340,7 @@ ${indented}`);
14926
15340
  return compiled.set(path, result);
14927
15341
  }
14928
15342
  };
14929
- };
15343
+ }
14930
15344
  fileToPattern = function(rel) {
14931
15345
  let pattern;
14932
15346
  pattern = rel.replace(/\.rip$/, "");
@@ -14951,33 +15365,33 @@ ${indented}`);
14951
15365
  return { regex: new RegExp("^" + str2 + "$"), names };
14952
15366
  };
14953
15367
  matchRoute = function(path, routes) {
14954
- let i, match, name, params, route;
14955
- for (let route2 of routes) {
14956
- match = path.match(route2.regex.regex);
15368
+ let match, params;
15369
+ for (let route of routes) {
15370
+ match = path.match(route.regex.regex);
14957
15371
  if (match) {
14958
15372
  params = {};
14959
- for (let i2 = 0;i2 < route2.regex.names.length; i2++) {
14960
- let name2 = route2.regex.names[i2];
14961
- params[name2] = decodeURIComponent(match[i2 + 1]);
15373
+ for (let i = 0;i < route.regex.names.length; i++) {
15374
+ let name = route.regex.names[i];
15375
+ params[name] = decodeURIComponent(match[i + 1]);
14962
15376
  }
14963
- return { route: route2, params };
15377
+ return { route, params };
14964
15378
  }
14965
15379
  }
14966
15380
  return null;
14967
15381
  };
14968
- buildRoutes = function(components, root = "components") {
14969
- let allFiles, dir, filePath, layouts, name, regex, rel, routes, segs, urlPattern;
15382
+ buildRoutes = function(components, root = "_route") {
15383
+ let allFiles, dir, layouts, name, regex, rel, routes, segs, urlPattern;
14970
15384
  routes = [];
14971
15385
  layouts = new Map;
14972
15386
  allFiles = components.listAll(root);
14973
- for (let filePath2 of allFiles) {
14974
- rel = filePath2.slice(root.length + 1);
15387
+ for (let filePath of allFiles) {
15388
+ rel = filePath.slice(root.length + 1);
14975
15389
  if (!rel.endsWith(".rip"))
14976
15390
  continue;
14977
15391
  name = rel.split("/").pop();
14978
15392
  if (name === "_layout.rip") {
14979
15393
  dir = rel === "_layout.rip" ? "" : rel.slice(0, -"/_layout.rip".length);
14980
- layouts.set(dir, filePath2);
15394
+ layouts.set(dir, filePath);
14981
15395
  continue;
14982
15396
  }
14983
15397
  if (name.startsWith("_"))
@@ -14989,7 +15403,7 @@ ${indented}`);
14989
15403
  continue;
14990
15404
  urlPattern = fileToPattern(rel);
14991
15405
  regex = patternToRegex(urlPattern);
14992
- routes.push({ pattern: urlPattern, regex, file: filePath2, rel });
15406
+ routes.push({ pattern: urlPattern, regex, file: filePath, rel });
14993
15407
  }
14994
15408
  routes.sort(function(a, b) {
14995
15409
  let aCatch, aDyn, bCatch, bDyn;
@@ -15006,27 +15420,27 @@ ${indented}`);
15006
15420
  return { routes, layouts };
15007
15421
  };
15008
15422
  getLayoutChain = function(routeFile, root, layouts) {
15009
- let chain, dir, i, rel, seg, segments;
15423
+ let chain, dir, rel, segments;
15010
15424
  chain = [];
15011
15425
  rel = routeFile.slice(root.length + 1);
15012
15426
  segments = rel.split("/");
15013
15427
  dir = "";
15014
15428
  if (layouts.has(""))
15015
15429
  chain.push(layouts.get(""));
15016
- for (let i2 = 0;i2 < segments.length; i2++) {
15017
- let seg2 = segments[i2];
15018
- if (i2 === segments.length - 1)
15430
+ for (let i = 0;i < segments.length; i++) {
15431
+ let seg = segments[i];
15432
+ if (i === segments.length - 1)
15019
15433
  break;
15020
- dir = dir ? dir + "/" + seg2 : seg2;
15434
+ dir = dir ? dir + "/" + seg : seg;
15021
15435
  if (layouts.has(dir))
15022
15436
  chain.push(layouts.get(dir));
15023
15437
  }
15024
15438
  return chain;
15025
15439
  };
15026
- var createRouter = function(components, opts = {}) {
15027
- let _current, _hash, _layouts, _navigating, _normalizedUrl, _params, _path, _query, _route, addBase, base, hashMode, navCallbacks, onClick, onError, onPopState, readUrl, resolve, root, router, stripBase, tree, unwatchComponents, writeUrl;
15440
+ function createRouter(components, opts = {}) {
15441
+ let _current, _hash, _layouts, _navigating, _normalizedUrl, _params, _path, _query, _route, addBase, applyAria, applyScroll, ariaEffect, ariaObserver, ariaScheduled, base, currentNorm, hashMode, navCallbacks, normalizeHref, onClick, onError, onPopState, onScroll, ownedAnchors, prevScrollRestoration, raf, readUrl, resolve, root, router, scheduleAria, scrollSaveTimer, shouldIgnoreAnchor, stripBase, tree, unwatchComponents, writeUrl;
15028
15442
  assertBrowser("createRouter");
15029
- root = opts.root || "components";
15443
+ root = opts.root || "_route";
15030
15444
  base = opts.base || "";
15031
15445
  hashMode = opts.hash || false;
15032
15446
  onError = opts.onError || null;
@@ -15072,7 +15486,7 @@ ${indented}`);
15072
15486
  return tree = buildRoutes(components, root);
15073
15487
  });
15074
15488
  resolve = function(url) {
15075
- let cb, full, hash, path, queryStr, rawPath, result, snapshot;
15489
+ let full, hash, path, queryStr, rawPath, result, snapshot;
15076
15490
  rawPath = url.split("?")[0].split("#")[0];
15077
15491
  path = stripBase(rawPath);
15078
15492
  path = path[0] === "/" ? path : "/" + path;
@@ -15095,9 +15509,9 @@ ${indented}`);
15095
15509
  return _normalizedUrl.value = full;
15096
15510
  });
15097
15511
  snapshot = Array.from(navCallbacks);
15098
- for (let cb2 of snapshot) {
15512
+ for (let cb of snapshot) {
15099
15513
  try {
15100
- cb2(router.current);
15514
+ cb(router.current);
15101
15515
  } catch (err) {
15102
15516
  console.error("[Rip] router onNavigate callback error:", err);
15103
15517
  }
@@ -15108,13 +15522,80 @@ ${indented}`);
15108
15522
  onError({ status: 404, path });
15109
15523
  return false;
15110
15524
  };
15111
- onPopState = function() {
15112
- return resolve(readUrl());
15525
+ prevScrollRestoration = null;
15526
+ if (typeof history !== "undefined" && "scrollRestoration" in history) {
15527
+ prevScrollRestoration = history.scrollRestoration;
15528
+ history.scrollRestoration = "manual";
15529
+ }
15530
+ raf = function(cb) {
15531
+ return typeof window !== "undefined" && window.requestAnimationFrame ? window.requestAnimationFrame(cb) : setTimeout(cb, 16);
15532
+ };
15533
+ applyScroll = function(y) {
15534
+ let attempts, step;
15535
+ if (typeof window === "undefined")
15536
+ return;
15537
+ attempts = 0;
15538
+ step = function() {
15539
+ let maxY;
15540
+ maxY = Math.max(0, (document?.documentElement?.scrollHeight || 0) - window.innerHeight);
15541
+ window.scrollTo(0, Math.min(y, maxY));
15542
+ attempts += 1;
15543
+ return y > maxY && attempts < 20 ? raf(step) : undefined;
15544
+ };
15545
+ return raf(step);
15546
+ };
15547
+ scrollSaveTimer = null;
15548
+ onScroll = function() {
15549
+ if (scrollSaveTimer || typeof window === "undefined")
15550
+ return;
15551
+ return scrollSaveTimer = setTimeout(function() {
15552
+ scrollSaveTimer = null;
15553
+ return (() => {
15554
+ try {
15555
+ return history.replaceState({ ...history.state || {}, _ripScroll: window.scrollY }, "", location.href);
15556
+ } catch {}
15557
+ })();
15558
+ }, 100);
15559
+ };
15560
+ if (typeof window !== "undefined")
15561
+ window.addEventListener("scroll", onScroll, { passive: true });
15562
+ onPopState = function(e) {
15563
+ let saved;
15564
+ saved = e?.state?._ripScroll;
15565
+ resolve(readUrl());
15566
+ return typeof saved === "number" ? applyScroll(saved) : undefined;
15113
15567
  };
15114
15568
  if (typeof window !== "undefined")
15115
15569
  window.addEventListener("popstate", onPopState);
15570
+ shouldIgnoreAnchor = function(target) {
15571
+ let url;
15572
+ if (!target?.href)
15573
+ return true;
15574
+ url = (() => {
15575
+ try {
15576
+ return new URL(target.href, location.origin);
15577
+ } catch {
15578
+ return null;
15579
+ }
15580
+ })();
15581
+ if (!url)
15582
+ return true;
15583
+ if (url.origin !== location.origin)
15584
+ return true;
15585
+ if (target.target === "_blank")
15586
+ return true;
15587
+ if (target.hasAttribute("download"))
15588
+ return true;
15589
+ if (target.hasAttribute("data-router-ignore"))
15590
+ return true;
15591
+ if (base && !hashMode) {
15592
+ if (!(url.pathname === base || url.pathname.startsWith(base + "/")))
15593
+ return true;
15594
+ }
15595
+ return false;
15596
+ };
15116
15597
  onClick = function(e) {
15117
- let dest, target, url;
15598
+ let dest, noScroll, target, url;
15118
15599
  if (e.defaultPrevented)
15119
15600
  return;
15120
15601
  if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)
@@ -15123,33 +15604,122 @@ ${indented}`);
15123
15604
  while (target && target.tagName !== "A") {
15124
15605
  target = target.parentElement;
15125
15606
  }
15126
- if (!target?.href)
15607
+ if (!target)
15127
15608
  return;
15128
- url = new URL(target.href, location.origin);
15129
- if (url.origin !== location.origin)
15130
- return;
15131
- if (target.target === "_blank" || target.hasAttribute("data-external"))
15132
- return;
15133
- if (target.hasAttribute("download"))
15609
+ if (shouldIgnoreAnchor(target))
15134
15610
  return;
15135
- if (target.hasAttribute("data-router-ignore"))
15136
- return;
15137
- if (base && !hashMode) {
15138
- if (!(url.pathname === base || url.pathname.startsWith(base + "/")))
15139
- return;
15140
- }
15611
+ url = new URL(target.href, location.origin);
15141
15612
  e.preventDefault();
15142
15613
  dest = hashMode && url.hash ? url.hash.slice(1) || "/" : url.pathname + url.search + url.hash;
15143
- return router.push(dest);
15614
+ noScroll = target.hasAttribute("data-router-noscroll");
15615
+ return router.push(dest, { noScroll });
15144
15616
  };
15145
15617
  if (typeof document !== "undefined")
15146
15618
  document.addEventListener("click", onClick);
15619
+ ownedAnchors = new WeakSet;
15620
+ normalizeHref = function(rawPath) {
15621
+ let p;
15622
+ p = rawPath.split("?")[0].split("#")[0];
15623
+ p = decodeURIComponent(p);
15624
+ p = stripBase(p);
15625
+ if (!(p[0] === "/"))
15626
+ p = "/" + p;
15627
+ if (p.length > 1 && p.endsWith("/"))
15628
+ p = p.slice(0, -1);
15629
+ return p;
15630
+ };
15631
+ currentNorm = function() {
15632
+ let p;
15633
+ p = hashMode ? stripBase(readUrl()).split("?")[0].split("#")[0] : _path.value.split("?")[0].split("#")[0];
15634
+ if (!(p[0] === "/"))
15635
+ p = "/" + p;
15636
+ if (p.length > 1 && p.endsWith("/"))
15637
+ p = p.slice(0, -1);
15638
+ return p;
15639
+ };
15640
+ applyAria = function() {
15641
+ let anchors, cur, desired, existing, linkPath, url;
15642
+ if (typeof document === "undefined")
15643
+ return;
15644
+ cur = currentNorm();
15645
+ anchors = document.querySelectorAll("a[href]");
15646
+ for (let a of anchors) {
15647
+ if (shouldIgnoreAnchor(a))
15648
+ continue;
15649
+ url = (() => {
15650
+ try {
15651
+ return new URL(a.href, location.origin);
15652
+ } catch {
15653
+ return null;
15654
+ }
15655
+ })();
15656
+ if (!url)
15657
+ continue;
15658
+ linkPath = normalizeHref(url.pathname + url.search + url.hash);
15659
+ desired = null;
15660
+ if (linkPath === cur)
15661
+ desired = "page";
15662
+ if (!desired && cur !== "/" && cur.startsWith(linkPath + "/") && linkPath !== "")
15663
+ desired = "true";
15664
+ existing = a.getAttribute("aria-current");
15665
+ if (desired) {
15666
+ if (existing && !ownedAnchors.has(a)) {
15667
+ continue;
15668
+ }
15669
+ a.setAttribute("aria-current", desired);
15670
+ ownedAnchors.add(a);
15671
+ } else if (ownedAnchors.has(a)) {
15672
+ a.removeAttribute("aria-current");
15673
+ ownedAnchors.delete(a);
15674
+ }
15675
+ }
15676
+ return;
15677
+ };
15678
+ ariaObserver = null;
15679
+ ariaScheduled = false;
15680
+ scheduleAria = function() {
15681
+ let cb;
15682
+ if (ariaScheduled)
15683
+ return;
15684
+ ariaScheduled = true;
15685
+ cb = function() {
15686
+ ariaScheduled = false;
15687
+ return applyAria();
15688
+ };
15689
+ return typeof window !== "undefined" && window.requestAnimationFrame ? window.requestAnimationFrame(cb) : setTimeout(cb, 0);
15690
+ };
15691
+ ariaEffect = __effect(function() {
15692
+ let target;
15693
+ if (typeof document === "undefined")
15694
+ return;
15695
+ currentNorm();
15696
+ scheduleAria();
15697
+ if (!ariaObserver) {
15698
+ ariaObserver = new MutationObserver(function() {
15699
+ return scheduleAria();
15700
+ });
15701
+ target = document.body || document.documentElement;
15702
+ ariaObserver.observe(target, { childList: true, subtree: true });
15703
+ }
15704
+ return;
15705
+ });
15147
15706
  router = {
15148
- push(url) {
15149
- return resolve(url) ? history.pushState(null, "", writeUrl(_normalizedUrl.read())) : undefined;
15707
+ push(url, opts2) {
15708
+ let prevY;
15709
+ prevY = typeof window !== "undefined" ? window.scrollY : 0;
15710
+ if (resolve(url)) {
15711
+ try {
15712
+ history.replaceState({ ...history.state || {}, _ripScroll: prevY }, "", location.href);
15713
+ } catch {}
15714
+ history.pushState({ _ripScroll: 0 }, "", writeUrl(_normalizedUrl.read()));
15715
+ return !opts2?.noScroll && typeof window !== "undefined" ? window.scrollTo(0, 0) : undefined;
15716
+ }
15150
15717
  },
15151
- replace(url) {
15152
- return resolve(url) ? history.replaceState(null, "", writeUrl(_normalizedUrl.read())) : undefined;
15718
+ replace(url, opts2) {
15719
+ if (resolve(url)) {
15720
+ history.replaceState({ _ripScroll: 0 }, "", writeUrl(_normalizedUrl.read()));
15721
+ return !opts2?.noScroll && typeof window !== "undefined" ? window.scrollTo(0, 0) : undefined;
15722
+ }
15153
15723
  },
15154
15724
  back() {
15155
15725
  return history.back();
@@ -15182,8 +15752,16 @@ ${indented}`);
15182
15752
  destroy() {
15183
15753
  if (typeof window !== "undefined")
15184
15754
  window.removeEventListener("popstate", onPopState);
15755
+ if (typeof window !== "undefined")
15756
+ window.removeEventListener("scroll", onScroll);
15185
15757
  if (typeof document !== "undefined")
15186
15758
  document.removeEventListener("click", onClick);
15759
+ if (prevScrollRestoration !== null && typeof history !== "undefined") {
15760
+ history.scrollRestoration = prevScrollRestoration;
15761
+ }
15762
+ ariaObserver?.disconnect();
15763
+ ariaObserver = null;
15764
+ ariaEffect?.();
15187
15765
  unwatchComponents?.();
15188
15766
  unwatchComponents = null;
15189
15767
  _navigating?.dispose?.();
@@ -15226,37 +15804,35 @@ ${indented}`);
15226
15804
  return tree.routes;
15227
15805
  } });
15228
15806
  return router;
15229
- };
15807
+ }
15230
15808
  arraysEqual = function(a, b) {
15231
- let i, item;
15232
15809
  if (a.length !== b.length)
15233
15810
  return false;
15234
- for (let i2 = 0;i2 < a.length; i2++) {
15235
- let item2 = a[i2];
15236
- if (item2 !== b[i2])
15811
+ for (let i = 0;i < a.length; i++) {
15812
+ let item = a[i];
15813
+ if (item !== b[i])
15237
15814
  return false;
15238
15815
  }
15239
15816
  return true;
15240
15817
  };
15241
15818
  findComponent = function(mod) {
15242
- let key, val;
15243
15819
  if (typeof mod.default === "function" && (mod.default.prototype?.mount || mod.default.prototype?._create)) {
15244
15820
  return mod.default;
15245
15821
  }
15246
- for (let key2 in mod) {
15247
- let val2 = mod[key2];
15248
- if (typeof val2 === "function" && (val2.prototype?.mount || val2.prototype?._create))
15249
- return val2;
15822
+ for (let key in mod) {
15823
+ let val = mod[key];
15824
+ if (typeof val === "function" && (val.prototype?.mount || val.prototype?._create))
15825
+ return val;
15250
15826
  }
15251
15827
  return typeof mod.default === "function" ? mod.default : undefined;
15252
15828
  };
15253
15829
  findAllComponents = function(mod) {
15254
- let key, result, val;
15830
+ let result;
15255
15831
  result = {};
15256
- for (let key2 in mod) {
15257
- let val2 = mod[key2];
15258
- if (typeof val2 === "function" && (val2.prototype?.mount || val2.prototype?._create)) {
15259
- result[key2] = val2;
15832
+ for (let key in mod) {
15833
+ let val = mod[key];
15834
+ if (typeof val === "function" && (val.prototype?.mount || val.prototype?._create)) {
15835
+ result[key] = val;
15260
15836
  }
15261
15837
  }
15262
15838
  return result;
@@ -15268,35 +15844,42 @@ ${indented}`);
15268
15844
  return ch.toUpperCase();
15269
15845
  });
15270
15846
  };
15271
- buildComponentMap = function(components, root = "components") {
15272
- let fileName, map, name, path;
15847
+ buildComponentMap = function(components, roots = ["_app", "_lib", "_pkg", "_route"]) {
15848
+ let fileName, map, name, paths, rootList;
15273
15849
  map = {};
15274
- for (let path2 of components.listAll(root)) {
15275
- if (!path2.endsWith(".rip"))
15850
+ rootList = Array.isArray(roots) ? roots : [roots];
15851
+ paths = [];
15852
+ for (let r of rootList) {
15853
+ for (let p of components.listAll(r)) {
15854
+ paths.push(p);
15855
+ }
15856
+ }
15857
+ for (let path of paths) {
15858
+ if (!path.endsWith(".rip"))
15276
15859
  continue;
15277
- fileName = path2.split("/").pop();
15860
+ fileName = path.split("/").pop();
15278
15861
  if (fileName.startsWith("_"))
15279
15862
  continue;
15280
- name = fileToComponentName(path2);
15863
+ name = fileToComponentName(path);
15281
15864
  if (map[name]) {
15282
- console.warn(`[Rip] Component name collision: ${name} (${map[name]} vs ${path2})`);
15865
+ console.warn(`[Rip] Component name collision: ${name} (${map[name]} vs ${path})`);
15283
15866
  }
15284
- map[name] = path2;
15867
+ map[name] = path;
15285
15868
  }
15286
15869
  return map;
15287
15870
  };
15288
15871
  resolveStorePath = function(specifier, currentPath, components) {
15289
- let candidate, clean, parts, seg;
15872
+ let candidate, clean, parts, storeKey;
15290
15873
  clean = specifier.replace(/^(\.\.\/|\.\/)+/, "");
15291
15874
  if (currentPath) {
15292
15875
  parts = currentPath.split("/");
15293
15876
  parts.pop();
15294
- for (let seg2 of specifier.split("/")) {
15295
- if (seg2 === "..") {
15877
+ for (let seg of specifier.split("/")) {
15878
+ if (seg === "..") {
15296
15879
  parts.pop();
15297
15880
  } else {
15298
- if (!(seg2 === ".")) {
15299
- parts.push(seg2);
15881
+ if (!(seg === ".")) {
15882
+ parts.push(seg);
15300
15883
  }
15301
15884
  }
15302
15885
  }
@@ -15304,14 +15887,17 @@ ${indented}`);
15304
15887
  if (components.exists(candidate))
15305
15888
  return candidate;
15306
15889
  }
15307
- if (components.exists(`components/_lib/${clean}`))
15308
- return `components/_lib/${clean}`;
15309
- if (components.exists(`components/${clean}`))
15310
- return `components/${clean}`;
15890
+ if (components.exists(clean))
15891
+ return clean;
15892
+ for (let prefix of ["_pkg", "_lib", "_app", "_route"]) {
15893
+ storeKey = `${prefix}/${clean}`;
15894
+ if (components.exists(storeKey))
15895
+ return storeKey;
15896
+ }
15311
15897
  return null;
15312
15898
  };
15313
15899
  extractImportedNames = function(clause) {
15314
- let braceIdx, closing, inside, n, names, p, part, rest, t;
15900
+ let braceIdx, closing, inside, names, p, rest, t;
15315
15901
  if (!clause)
15316
15902
  return [];
15317
15903
  rest = clause.trim();
@@ -15324,16 +15910,16 @@ ${indented}`);
15324
15910
  if (closing < 0)
15325
15911
  return names;
15326
15912
  inside = rest.slice(braceIdx + 1, closing);
15327
- for (let n2 of inside.split(",")) {
15328
- t = n2.trim();
15913
+ for (let n of inside.split(",")) {
15914
+ t = n.trim();
15329
15915
  if (!t)
15330
15916
  continue;
15331
15917
  names.push(t.split(/\s+as\s+/).pop().trim());
15332
15918
  }
15333
15919
  rest = rest.slice(0, braceIdx).replace(/,\s*$/, "").trim();
15334
15920
  }
15335
- for (let part2 of rest.split(",")) {
15336
- p = part2.trim();
15921
+ for (let part of rest.split(",")) {
15922
+ p = part.trim();
15337
15923
  if (!p)
15338
15924
  continue;
15339
15925
  if (/^\*\s+as\s+/.test(p)) {
@@ -15345,7 +15931,7 @@ ${indented}`);
15345
15931
  return names;
15346
15932
  };
15347
15933
  compileAndImport = async function(source, compile2, components = null, path = null, resolver = null) {
15348
- let anyImportRe, bindingClause, blob, blobUrl, cached, committed, debug, depMod, depPath, depSource, finalJs, found, full, header, importedNames, js, k, keyLiteral, m, matches, mod, msg, n, name, names, needed, offset, post, pre, preamble, prefixLines, previousUrl, replacement, ripImportRe, specifier, storePath, url, v;
15934
+ let anyImportRe, bareImportRe, bindingClause, blob, blobUrl, cached, committed, debug, depMod, depSource, finalJs, found, full, header, importedNames, js, keyLiteral, matches, mod, msg, names, needed, offset, pkgMap, post, pre, preamble, prefixLines, previousUrl, replacement, ripImportRe, specifier, storePath, url;
15349
15935
  if (components && path) {
15350
15936
  cached = components.getCompiled(path);
15351
15937
  if (cached)
@@ -15362,12 +15948,24 @@ ${indented}`);
15362
15948
  js = debug ? compile2(source, { sourceMap: "inline", filename: path }) : compile2(source);
15363
15949
  if (resolver) {
15364
15950
  importedNames = new Set;
15951
+ pkgMap = resolver.packages || {};
15952
+ if (Object.keys(pkgMap).length > 0) {
15953
+ bareImportRe = /^(\s*import\s+(?:.*?\s+from\s+)?['"])(@rip-lang\/[^\/'"]+)((?:\/[^'"]*)?)(['"];?\s*)$/gm;
15954
+ js = js.replace(bareImportRe, function(full2, pre2, pkgKey, sub, post2) {
15955
+ let info, target;
15956
+ info = pkgMap[pkgKey];
15957
+ if (!info)
15958
+ return full2;
15959
+ target = !sub ? `_pkg/${info.short}/${info.entry}` : sub.endsWith(".rip") ? `_pkg/${info.short}${sub}` : `_pkg/${info.short}${sub}.rip`;
15960
+ return `${pre2}${target}${post2}`;
15961
+ });
15962
+ }
15365
15963
  if (components) {
15366
15964
  ripImportRe = /^(\s*import\s+(?:(.*?)\s+from\s+)?['"])([^'"]*\.rip)(['"];?\s*)$/gm;
15367
15965
  matches = Array.from(js.matchAll(ripImportRe));
15368
15966
  for (let _i = matches.length - 1;_i >= 0; _i--) {
15369
- let m2 = matches[_i];
15370
- [full, pre, bindingClause, specifier, post] = m2;
15967
+ let m = matches[_i];
15968
+ [full, pre, bindingClause, specifier, post] = m;
15371
15969
  storePath = resolveStorePath(specifier, path, components);
15372
15970
  if (storePath === path)
15373
15971
  continue;
@@ -15389,38 +15987,38 @@ ${indented}`);
15389
15987
  blobUrl = resolver.blobUrls?.[storePath];
15390
15988
  if (blobUrl) {
15391
15989
  replacement = `${pre}${blobUrl}${post}`;
15392
- js = js.slice(0, m2.index) + replacement + js.slice(m2.index + full.length);
15393
- for (let n2 of extractImportedNames(bindingClause)) {
15394
- importedNames.add(n2);
15990
+ js = js.slice(0, m.index) + replacement + js.slice(m.index + full.length);
15991
+ for (let n of extractImportedNames(bindingClause)) {
15992
+ importedNames.add(n);
15395
15993
  }
15396
15994
  }
15397
15995
  }
15398
15996
  }
15399
15997
  anyImportRe = /^\s*import\s+(?:(.*?)\s+from\s+)?['"][^'"]*['"];?\s*$/gm;
15400
- for (let m2 of js.matchAll(anyImportRe)) {
15401
- for (let n2 of extractImportedNames(m2[1])) {
15402
- importedNames.add(n2);
15998
+ for (let m of js.matchAll(anyImportRe)) {
15999
+ for (let n of extractImportedNames(m[1])) {
16000
+ importedNames.add(n);
15403
16001
  }
15404
16002
  }
15405
16003
  needed = {};
15406
- for (let name2 in resolver.map) {
15407
- let depPath2 = resolver.map[name2];
15408
- if (importedNames.has(name2))
16004
+ for (let name in resolver.map) {
16005
+ let depPath = resolver.map[name];
16006
+ if (importedNames.has(name))
15409
16007
  continue;
15410
- if (depPath2 !== path && js.includes(`new ${name2}(`)) {
15411
- if (!resolver.classes[name2]) {
15412
- depSource = components.read(depPath2);
16008
+ if (depPath !== path && js.includes(`new ${name}(`)) {
16009
+ if (!resolver.classes[name]) {
16010
+ depSource = components.read(depPath);
15413
16011
  if (depSource) {
15414
- depMod = await compileAndImport(depSource, compile2, components, depPath2, resolver);
16012
+ depMod = await compileAndImport(depSource, compile2, components, depPath, resolver);
15415
16013
  found = findAllComponents(depMod);
15416
- for (let k2 in found) {
15417
- let v2 = found[k2];
15418
- resolver.classes[k2] = v2;
16014
+ for (let k in found) {
16015
+ let v = found[k];
16016
+ resolver.classes[k] = v;
15419
16017
  }
15420
16018
  }
15421
16019
  }
15422
- if (resolver.classes[name2])
15423
- needed[name2] = true;
16020
+ if (resolver.classes[name])
16021
+ needed[name] = true;
15424
16022
  }
15425
16023
  }
15426
16024
  names = Object.keys(needed);
@@ -15459,9 +16057,9 @@ ${indented}`);
15459
16057
  committed = true;
15460
16058
  if (resolver) {
15461
16059
  found = findAllComponents(mod);
15462
- for (let k2 in found) {
15463
- let v2 = found[k2];
15464
- resolver.classes[k2] = v2;
16060
+ for (let k in found) {
16061
+ let v = found[k];
16062
+ resolver.classes[k] = v;
15465
16063
  }
15466
16064
  }
15467
16065
  if (components && path)
@@ -15483,7 +16081,7 @@ ${indented}`);
15483
16081
  }
15484
16082
  })();
15485
16083
  };
15486
- var createRenderer = function(opts = {}) {
16084
+ function createRenderer(opts) {
15487
16085
  let app, compile2, components, container, currentComponent, currentLayouts, currentParams, currentQuery, currentRoute, disposeEffect, generation, invalidateResolver, layoutInstances, mountPoint, mountRoute, onError, renderer, resolver, router, sameKeys, started, target, unmount, unmountCurrent, unwatchSources;
15488
16086
  assertBrowser("createRenderer");
15489
16087
  ({ router, app, components, resolver, compile: compile2, target, onError } = opts);
@@ -15504,7 +16102,6 @@ ${indented}`);
15504
16102
  disposeEffect = null;
15505
16103
  unwatchSources = null;
15506
16104
  invalidateResolver = function(path) {
15507
- let depPath, name;
15508
16105
  if (!resolver)
15509
16106
  return;
15510
16107
  if (resolver.blobUrls?.[path]) {
@@ -15515,9 +16112,9 @@ ${indented}`);
15515
16112
  }
15516
16113
  return resolver.classes && resolver.map ? (() => {
15517
16114
  const result = [];
15518
- for (let name2 in resolver.map) {
15519
- let depPath2 = resolver.map[name2];
15520
- result.push(depPath2 === path ? delete resolver.classes[name2] : undefined);
16115
+ for (let name in resolver.map) {
16116
+ let depPath = resolver.map[name];
16117
+ result.push(depPath === path ? delete resolver.classes[name] : undefined);
15521
16118
  }
15522
16119
  return result;
15523
16120
  })() : undefined;
@@ -15534,12 +16131,11 @@ ${indented}`);
15534
16131
  }
15535
16132
  };
15536
16133
  unmount = function() {
15537
- let inst;
15538
16134
  unmountCurrent();
15539
16135
  for (let _i = layoutInstances.length - 1;_i >= 0; _i--) {
15540
- let inst2 = layoutInstances[_i];
16136
+ let inst = layoutInstances[_i];
15541
16137
  try {
15542
- inst2.unmount?.({ removeDOM: true });
16138
+ inst.unmount?.({ removeDOM: true });
15543
16139
  } catch (e) {
15544
16140
  console.error("[Rip] layout unmount error:", e);
15545
16141
  }
@@ -15551,20 +16147,19 @@ ${indented}`);
15551
16147
  return currentLayouts = [];
15552
16148
  };
15553
16149
  sameKeys = function(a, b) {
15554
- let k, v;
15555
16150
  if (!(a && b))
15556
16151
  return false;
15557
16152
  if (Object.keys(a).length !== Object.keys(b).length)
15558
16153
  return false;
15559
- for (let k2 in a) {
15560
- let v2 = a[k2];
15561
- if (!(b[k2] === v2))
16154
+ for (let k in a) {
16155
+ let v = a[k];
16156
+ if (!(b[k] === v))
15562
16157
  return false;
15563
16158
  }
15564
16159
  return true;
15565
16160
  };
15566
16161
  mountRoute = async function(info, force = false) {
15567
- let Component, LayoutClass, __innerPrev, __pop, __prev, __push, gen2, handled, inst, instance, layoutFile, layoutFiles, layoutMod, layoutSource, layoutsChanged, mod, mp, oldTarget, outerScope, pageParent, pagePrev, pageWrapper, params, pre, prevScope, query, route, sameRoute, slot, source, wrapper;
16162
+ let Component, LayoutClass, __innerPrev, __pop, __prev, __push, gen2, handled, inst, instance, layoutFiles, layoutMod, layoutSource, layoutsChanged, mod, mp, oldTarget, outerScope, pageParent, pagePrev, pageWrapper, params, pre, prevScope, query, route, sameRoute, slot, source, wrapper;
15568
16163
  ({ route, params, layouts: layoutFiles, query } = info);
15569
16164
  if (!route)
15570
16165
  return;
@@ -15623,11 +16218,11 @@ ${indented}`);
15623
16218
  __push = globalThis.__ripComponent?.__pushComponent;
15624
16219
  __pop = globalThis.__ripComponent?.__popComponent;
15625
16220
  outerScope = null;
15626
- for (let layoutFile2 of layoutFiles) {
15627
- layoutSource = components.read(layoutFile2);
16221
+ for (let layoutFile of layoutFiles) {
16222
+ layoutSource = components.read(layoutFile);
15628
16223
  if (!layoutSource)
15629
16224
  continue;
15630
- layoutMod = await compileAndImport(layoutSource, compile2, components, layoutFile2, resolver);
16225
+ layoutMod = await compileAndImport(layoutSource, compile2, components, layoutFile, resolver);
15631
16226
  if (gen2 !== generation) {
15632
16227
  router.navigating = false;
15633
16228
  return;
@@ -15650,7 +16245,7 @@ ${indented}`);
15650
16245
  }
15651
16246
  }
15652
16247
  wrapper = document.createElement("div");
15653
- wrapper.setAttribute("data-layout", layoutFile2);
16248
+ wrapper.setAttribute("data-layout", layoutFile);
15654
16249
  mp.appendChild(wrapper);
15655
16250
  inst.mount(wrapper);
15656
16251
  layoutInstances.push(inst);
@@ -15741,7 +16336,6 @@ ${indented}`);
15741
16336
  return renderer;
15742
16337
  },
15743
16338
  stop() {
15744
- let _, url;
15745
16339
  if (!started)
15746
16340
  return;
15747
16341
  started = false;
@@ -15753,12 +16347,12 @@ ${indented}`);
15753
16347
  unwatchSources?.();
15754
16348
  unwatchSources = null;
15755
16349
  if (resolver?.blobUrls) {
15756
- for (let _2 in resolver.blobUrls) {
15757
- if (!Object.hasOwn(resolver.blobUrls, _2))
16350
+ for (let _ in resolver.blobUrls) {
16351
+ if (!Object.hasOwn(resolver.blobUrls, _))
15758
16352
  continue;
15759
- let url2 = resolver.blobUrls[_2];
16353
+ let url = resolver.blobUrls[_];
15760
16354
  try {
15761
- URL.revokeObjectURL(url2);
16355
+ URL.revokeObjectURL(url);
15762
16356
  } catch {}
15763
16357
  }
15764
16358
  resolver.blobUrls = {};
@@ -15773,7 +16367,7 @@ ${indented}`);
15773
16367
  }
15774
16368
  };
15775
16369
  return renderer;
15776
- };
16370
+ }
15777
16371
  connectWatch = function(url) {
15778
16372
  let closed, connect, es, maxDelay, retryDelay, retryTimer;
15779
16373
  assertBrowser("connectWatch");
@@ -15795,12 +16389,13 @@ ${indented}`);
15795
16389
  return location.reload();
15796
16390
  });
15797
16391
  es.addEventListener("css", function() {
15798
- let cssUrl, link;
16392
+ let cssUrl, sheets;
16393
+ sheets = document.querySelectorAll('link[rel="stylesheet"]');
15799
16394
  const _result = [];
15800
- for (let link2 of document.querySelectorAll('link[rel="stylesheet"]')) {
15801
- cssUrl = new URL(link2.href);
16395
+ for (let link of sheets) {
16396
+ cssUrl = new URL(link.href);
15802
16397
  cssUrl.searchParams.set("_t", Date.now());
15803
- link2.href = cssUrl.toString();
16398
+ link.href = cssUrl.toString();
15804
16399
  }
15805
16400
  return _result;
15806
16401
  });
@@ -15826,8 +16421,8 @@ ${indented}`);
15826
16421
  return es = null;
15827
16422
  };
15828
16423
  };
15829
- var launch = async function(opts = {}) {
15830
- let app, appBase, appComponents, bundle, cached, classesKey, compile2, destroy, destroyed, el, etag, etagKey, hash, headers, k, persist, persistDisposer, renderer, res, resolver, router, seedData, stashMod, stashPath, stashRaw, stashSource, target, v, watchDisposer;
16424
+ async function launch(opts = {}) {
16425
+ let app, appBase, appComponents, bundle, cached, classesKey, compile2, destroy, destroyed, el, etag, etagKey, hash, headers, persist, persistDisposer, renderer, res, resolver, router, seedData, stashMod, stashPath, stashRaw, stashSource, target, watchDisposer, win;
15831
16426
  assertBrowser("launch");
15832
16427
  appBase = (opts.base || "").replace(/\/+$/, "");
15833
16428
  target = opts.target || "#app";
@@ -15866,16 +16461,16 @@ ${indented}`);
15866
16461
  } else {
15867
16462
  throw new Error("launch: no bundle or bundleUrl provided");
15868
16463
  }
15869
- app = stash({ components: {}, routes: {}, data: {} });
16464
+ app = createStash({ components: {}, routes: {}, data: {} });
15870
16465
  globalThis.__ripApp = app;
15871
16466
  appComponents = createComponents();
15872
- if (bundle.components)
15873
- appComponents.load(bundle.components);
16467
+ if (bundle.modules)
16468
+ appComponents.load(bundle.modules);
15874
16469
  classesKey = `__rip_${appBase.replace(/\//g, "_") || "app"}`;
15875
- resolver = { map: buildComponentMap(appComponents), classes: {}, key: classesKey };
16470
+ resolver = { map: buildComponentMap(appComponents), classes: {}, key: classesKey, packages: bundle.packages || {} };
15876
16471
  globalThis[classesKey] = resolver.classes;
15877
16472
  stashRaw = null;
15878
- stashPath = "components/_lib/stash.rip";
16473
+ stashPath = "_app/stash.rip";
15879
16474
  if (appComponents.exists(stashPath)) {
15880
16475
  stashSource = appComponents.read(stashPath);
15881
16476
  if (stashSource) {
@@ -15889,9 +16484,9 @@ ${indented}`);
15889
16484
  }
15890
16485
  }
15891
16486
  if (stashRaw && bundle.data) {
15892
- for (let k2 in bundle.data) {
15893
- let v2 = bundle.data[k2];
15894
- stashRaw[k2] = v2;
16487
+ for (let k in bundle.data) {
16488
+ let v = bundle.data[k];
16489
+ stashRaw[k] = v;
15895
16490
  }
15896
16491
  }
15897
16492
  seedData = stashRaw ?? bundle.data;
@@ -15907,7 +16502,7 @@ ${indented}`);
15907
16502
  if (app.data.title)
15908
16503
  document.title = app.data.title;
15909
16504
  router = createRouter(appComponents, {
15910
- root: "components",
16505
+ root: "_route",
15911
16506
  base: appBase,
15912
16507
  hash,
15913
16508
  onError(err) {
@@ -15930,6 +16525,7 @@ ${indented}`);
15930
16525
  if (bundle.data?.watch) {
15931
16526
  watchDisposer = connectWatch(`${appBase}/watch`);
15932
16527
  }
16528
+ win = window;
15933
16529
  destroyed = false;
15934
16530
  destroy = function() {
15935
16531
  if (destroyed)
@@ -15942,16 +16538,16 @@ ${indented}`);
15942
16538
  delete globalThis[classesKey];
15943
16539
  delete globalThis.__ripApp;
15944
16540
  delete globalThis.__ripLaunched;
15945
- if (window.app === app) {
15946
- delete window.app;
16541
+ if (win.app === app) {
16542
+ delete win.app;
15947
16543
  }
15948
- return window.__RIP__?.app === app ? delete window.__RIP__ : undefined;
16544
+ return win.__RIP__?.app === app ? delete win.__RIP__ : undefined;
15949
16545
  };
15950
- window.app = app;
15951
- window.__RIP__ = { app, components: appComponents, router, renderer, resolver, destroy, version: "0.3.0" };
16546
+ win.app = app;
16547
+ win.__RIP__ = { app, components: appComponents, router, renderer, resolver, destroy, version: "0.3.0" };
15952
16548
  globalThis.__ripLaunched = true;
15953
16549
  return { app, components: appComponents, router, renderer, destroy };
15954
- };
16550
+ }
15955
16551
  _ariaNAV = function(e, fn) {
15956
16552
  if (!fn)
15957
16553
  return;
@@ -16283,10 +16879,11 @@ ${indented}`);
16283
16879
  _ariaTrapFocus = function(panel) {
16284
16880
  let handler;
16285
16881
  handler = function(e) {
16286
- let first, last, list;
16882
+ let first, last, list, nodes;
16287
16883
  if (!(e.key === "Tab"))
16288
16884
  return;
16289
- list = Array.from(panel.querySelectorAll(_FOCUSABLE)).filter(function(f) {
16885
+ nodes = panel.querySelectorAll(_FOCUSABLE);
16886
+ list = Array.from(nodes).filter(function(f) {
16290
16887
  return f.offsetParent !== null;
16291
16888
  });
16292
16889
  if (!list.length)
@@ -16371,10 +16968,9 @@ ${indented}`);
16371
16968
  };
16372
16969
  _ARIA_POSITION_OWNED = ["position", "inset", "top", "right", "bottom", "left", "margin", "marginTop", "marginRight", "marginBottom", "marginLeft", "transform", "minWidth", "positionAnchor", "positionArea", "positionTry", "positionVisibility"];
16373
16970
  _ariaResetPositionStyles = function(el) {
16374
- let prop;
16375
16971
  const _result = [];
16376
- for (let prop2 of _ARIA_POSITION_OWNED) {
16377
- _result.push(el.style[prop2] = "");
16972
+ for (let prop of _ARIA_POSITION_OWNED) {
16973
+ _result.push(el.style[prop] = "");
16378
16974
  }
16379
16975
  return _result;
16380
16976
  };
@@ -16472,12 +17068,11 @@ ${indented}`);
16472
17068
  };
16473
17069
  _ariaCombine = function(...disposers) {
16474
17070
  return function() {
16475
- let d;
16476
17071
  const _result = [];
16477
- for (let d2 of disposers) {
17072
+ for (let d of disposers) {
16478
17073
  _result.push((() => {
16479
17074
  try {
16480
- return d2?.();
17075
+ return d?.();
16481
17076
  } catch {
16482
17077
  return null;
16483
17078
  }