tutuca 0.9.34 → 0.9.36

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.
@@ -118,16 +118,6 @@ class RenderBatch {
118
118
  }
119
119
  }
120
120
 
121
- class DoctorReport {
122
- constructor({ lint, renders }) {
123
- this.lint = lint;
124
- this.renders = renders;
125
- }
126
- get ok() {
127
- return !this.lint.hasErrors && !this.renders.hasErrors;
128
- }
129
- }
130
-
131
121
  // tools/core/module.js
132
122
  class Example {
133
123
  constructor({ title, description = null, value, view = "main", componentName = null }) {
@@ -456,6 +446,30 @@ function docComponents(normalized, { name = null } = {}) {
456
446
  }
457
447
  var init_docs = () => {};
458
448
 
449
+ // tools/core/list.js
450
+ function summarize(comp) {
451
+ const meta = comp.Class.getMetaClass();
452
+ const fields = [];
453
+ for (const fieldName in meta.fields) {
454
+ const f = meta.fields[fieldName];
455
+ fields.push({ name: fieldName, type: f.type });
456
+ }
457
+ return new ComponentSummary({
458
+ name: comp.name,
459
+ views: Object.keys(comp.views ?? {}),
460
+ fields
461
+ });
462
+ }
463
+ function listComponents(normalized, { name = null } = {}) {
464
+ const comps = normalized.components;
465
+ const picked = name === null ? comps : comps.filter((c) => c.name === name);
466
+ return new ComponentList({ items: picked.map(summarize) });
467
+ }
468
+ function listExamples(normalized) {
469
+ return new ExampleIndex({ sections: normalized.sections });
470
+ }
471
+ var init_list = () => {};
472
+
459
473
  // src/path.js
460
474
  class Step {
461
475
  lookup(_v, dval = null) {
@@ -708,7 +722,7 @@ class ValParser {
708
722
  }
709
723
  allowFieldOnly() {
710
724
  this.okField = true;
711
- this.okBind = this.okComputed = this.okDyn = this.okType = this.okRequest = false;
725
+ this.okBind = this.okDyn = this.okType = this.okRequest = false;
712
726
  this.okName = this.okConst = this.okStrTpl = this.okSeqAccess = false;
713
727
  }
714
728
  _parseSeqAccess(s, px) {
@@ -749,8 +763,6 @@ class ValParser {
749
763
  return this.okDyn ? parseDyn(s.slice(1), px) : null;
750
764
  case 46:
751
765
  return this.okField ? parseField(s.slice(1), px) : null;
752
- case 36:
753
- return this.okComputed ? parseComp(s.slice(1), px) : null;
754
766
  case 33:
755
767
  return this.okRequest ? parseReq(s.slice(1), px) : null;
756
768
  }
@@ -767,17 +779,16 @@ class ValParser {
767
779
  }
768
780
  parseDynamic(s, px) {
769
781
  this.allowFieldOnly();
770
- this.okComputed = true;
771
782
  return this.parse(s, px);
772
783
  }
773
784
  parseEach(s, px) {
774
785
  this.allowFieldOnly();
775
- this.okComputed = this.okDyn = true;
786
+ this.okDyn = true;
776
787
  return this.parse(s, px);
777
788
  }
778
789
  allowHandlerArg() {
779
790
  this.allowFieldOnly();
780
- this.okBind = this.okComputed = this.okDyn = this.okType = this.okRequest = true;
791
+ this.okBind = this.okDyn = this.okType = this.okRequest = true;
781
792
  this.okName = this.okConst = true;
782
793
  }
783
794
  parseHandlerArg(s, px) {
@@ -806,12 +817,12 @@ class ValParser {
806
817
  }
807
818
  parseCondValue(s, px) {
808
819
  this.allowFieldOnly();
809
- this.okBind = this.okComputed = this.okDyn = this.okConst = true;
820
+ this.okBind = this.okDyn = this.okConst = true;
810
821
  return this.parse(s, px);
811
822
  }
812
823
  parseText(s, px) {
813
824
  this.allowFieldOnly();
814
- this.okBind = this.okComputed = this.okDyn = this.okConst = this.okStrTpl = true;
825
+ this.okBind = this.okDyn = this.okConst = this.okStrTpl = true;
815
826
  return this.parse(s, px);
816
827
  }
817
828
  parseRender(s, px) {
@@ -853,10 +864,10 @@ function getValSubType(s) {
853
864
  return open === 1 && close === 1 ? VAL_SUB_TYPE_SEQ_ACCESS : VAL_SUB_TYPE_INVALID;
854
865
  return -1;
855
866
  }
856
- var VALID_VAL_ID_RE, isValidValId = (name) => VALID_VAL_ID_RE.test(name), VALID_FLOAT_RE, STR_TPL_SPLIT_RE, parseStrTemplate = (v, px) => StrTplVal.parse(v, px), parseConst = (v, _) => new ConstVal(v), parseName = (v, _) => isValidValId(v) ? new NameVal(v) : null, parseType = (v, _) => isValidValId(v) ? new TypeVal(v) : null, parseBind = (v, _) => isValidValId(v) ? new BindVal(v) : null, parseDyn = (v, _) => isValidValId(v) ? new DynVal(v) : null, parseField = (v, _) => isValidValId(v) ? new FieldVal(v) : null, parseComp = (v, _) => isValidValId(v) ? new ComputedVal(v) : null, parseReq = (v, _) => isValidValId(v) ? new RequestVal(v) : null, ConstVal, VarVal, StrTplVal, NameVal, InputHandlerNameVal, AlterHandlerNameVal, mk404Handler = (type, name) => function(...args) {
867
+ var VALID_VAL_ID_RE, isValidValId = (name) => VALID_VAL_ID_RE.test(name), VALID_FLOAT_RE, STR_TPL_SPLIT_RE, parseStrTemplate = (v, px) => StrTplVal.parse(v, px), parseConst = (v, _) => new ConstVal(v), parseName = (v, _) => isValidValId(v) ? new NameVal(v) : null, parseType = (v, _) => isValidValId(v) ? new TypeVal(v) : null, parseBind = (v, _) => isValidValId(v) ? new BindVal(v) : null, parseDyn = (v, _) => isValidValId(v) ? new DynVal(v) : null, parseField = (v, _) => isValidValId(v) ? new FieldVal(v) : null, parseReq = (v, _) => isValidValId(v) ? new RequestVal(v) : null, ConstVal, VarVal, StrTplVal, NameVal, InputHandlerNameVal, AlterHandlerNameVal, mk404Handler = (type, name) => function(...args) {
857
868
  console.warn("handler not found", { type, name, args }, this);
858
869
  return this;
859
- }, TypeVal, RequestVal, RawFieldVal, RenderVal, RenderNameVal, BindVal, DynVal, FieldVal, ComputedVal, SeqAccessVal, VAL_SUB_TYPE_STRING_TEMPLATE = 0, VAL_SUB_TYPE_SEQ_ACCESS = 1, VAL_SUB_TYPE_INVALID = 2, VAL_SUB_TYPE_CONST_STRING = 3, vp;
870
+ }, TypeVal, RequestVal, RawFieldVal, RenderVal, RenderNameVal, BindVal, DynVal, FieldVal, SeqAccessVal, VAL_SUB_TYPE_STRING_TEMPLATE = 0, VAL_SUB_TYPE_SEQ_ACCESS = 1, VAL_SUB_TYPE_INVALID = 2, VAL_SUB_TYPE_CONST_STRING = 3, vp;
860
871
  var init_value = __esm(() => {
861
872
  init_path();
862
873
  VALID_VAL_ID_RE = /^[a-zA-Z][a-zA-Z0-9_]*$/;
@@ -995,14 +1006,6 @@ var init_value = __esm(() => {
995
1006
  return `.${this.name}`;
996
1007
  }
997
1008
  };
998
- ComputedVal = class ComputedVal extends RenderNameVal {
999
- eval(stack) {
1000
- return stack.lookupComputed(this.name);
1001
- }
1002
- toString() {
1003
- return `$${this.name}`;
1004
- }
1005
- };
1006
1009
  SeqAccessVal = class SeqAccessVal extends RenderVal {
1007
1010
  constructor(seqVal, keyVal) {
1008
1011
  super();
@@ -1969,111 +1972,11 @@ var init_anode = __esm(() => {
1969
1972
  };
1970
1973
  });
1971
1974
 
1972
- // src/cache.js
1973
- class NullDomCache {
1974
- get(_keys, _cacheKey) {}
1975
- set(_keys, _cacheKey, _v) {}
1976
- evict() {
1977
- return { hit: 0, miss: 0, badKey: 0 };
1978
- }
1979
- }
1980
-
1981
- class WeakMapDomCache {
1982
- constructor() {
1983
- this.hit = this.miss = this.badKey = 0;
1984
- this.keysByLen = new Map;
1985
- }
1986
- _returnValue(r) {
1987
- if (r === undefined)
1988
- this.miss += 1;
1989
- else
1990
- this.hit += 1;
1991
- return r;
1992
- }
1993
- get(keys, cacheKey) {
1994
- const len = keys.length;
1995
- let cur = this.keysByLen.get(len);
1996
- if (!cur)
1997
- return this._returnValue(undefined);
1998
- for (let i = 0;i < len - 1; i++) {
1999
- cur = cur.get(keys[i]);
2000
- if (!cur)
2001
- return this._returnValue(undefined);
2002
- }
2003
- return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
2004
- }
2005
- set(keys, cacheKey, v) {
2006
- const len = keys.length;
2007
- let cur = this.keysByLen.get(len);
2008
- if (!cur) {
2009
- cur = new WeakMap;
2010
- this.keysByLen.set(len, cur);
2011
- }
2012
- for (let i = 0;i < len - 1; i++) {
2013
- const key = keys[i];
2014
- let next = cur.get(key);
2015
- if (!next) {
2016
- if (typeof key !== "object") {
2017
- this.badKey += 1;
2018
- return;
2019
- }
2020
- next = new WeakMap;
2021
- cur.set(key, next);
2022
- }
2023
- cur = next;
2024
- }
2025
- const lastKey = keys[len - 1];
2026
- const leaf = cur.get(lastKey);
2027
- if (leaf)
2028
- leaf[cacheKey] = v;
2029
- else if (typeof lastKey === "object")
2030
- cur.set(lastKey, { [cacheKey]: v });
2031
- else
2032
- this.badKey += 1;
2033
- }
2034
- evict() {
2035
- const { hit, miss, badKey } = this;
2036
- this.hit = this.miss = this.badKey = 0;
2037
- this.keysByLen = new Map;
2038
- return { hit, miss, badKey };
2039
- }
2040
- }
2041
-
2042
- class NullComputedCache {
2043
- getKey(v, _key, fn) {
2044
- return fn.call(v);
2045
- }
2046
- }
2047
-
2048
- class WeakMapComputedCache {
2049
- constructor() {
2050
- this.map = new WeakMap;
2051
- }
2052
- getKey(v, key, fn) {
2053
- const cur = this.map.get(v);
2054
- if (cur) {
2055
- const curValue = cur[key];
2056
- if (curValue !== undefined)
2057
- return curValue;
2058
- const newValue2 = fn.call(v) ?? null;
2059
- cur[key] = newValue2;
2060
- return newValue2;
2061
- }
2062
- const newValue = fn.call(v) ?? null;
2063
- this.map.set(v, { [key]: newValue });
2064
- return newValue;
2065
- }
2066
- }
2067
-
2068
1975
  // src/components.js
2069
1976
  class Components {
2070
1977
  constructor() {
2071
1978
  this.getComponentSymbol = Symbol("getComponent");
2072
1979
  this.byId = new Map;
2073
- this.computedCache = new WeakMapComputedCache;
2074
- }
2075
- setNullComputedCache() {
2076
- this.computedCache = new NullComputedCache;
2077
1980
  }
2078
1981
  registerComponent(comp) {
2079
1982
  comp.Class.prototype[this.getComponentSymbol] = () => comp;
@@ -2096,10 +1999,6 @@ class Components {
2096
1999
  const comp = this.getCompFor(v);
2097
2000
  return comp ? comp.scope.lookupRequest(name) : null;
2098
2001
  }
2099
- lookupComputed(v, name) {
2100
- const fn = this.getHandlerFor(v, name, "computed");
2101
- return fn ? this.computedCache.getKey(v, name, fn) : null;
2102
- }
2103
2002
  compileStyles() {
2104
2003
  const styles = [];
2105
2004
  for (const comp of this.byId.values())
@@ -2172,23 +2071,21 @@ function checkComponent(Comp, lx = new LintContext) {
2172
2071
  return lx.push({ componentName: Comp.name }, () => {
2173
2072
  const referencedAlters = new Set;
2174
2073
  const referencedInputs = new Set;
2175
- const referencedComputed = new Set;
2176
2074
  checkEventHandlersHaveImpls(lx, Comp, referencedInputs);
2177
- checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed);
2075
+ checkConsistentAttrs(lx, Comp, referencedAlters);
2178
2076
  for (const name in Comp.views) {
2179
- lx.push({ viewName: name }, () => checkView(lx, Comp.views[name], Comp, referencedAlters, referencedComputed));
2077
+ lx.push({ viewName: name }, () => checkView(lx, Comp.views[name], Comp, referencedAlters));
2180
2078
  }
2181
2079
  checkUnreferencedAlterHandlers(lx, Comp, referencedAlters);
2182
2080
  checkUnreferencedInputHandlers(lx, Comp, referencedInputs);
2183
- checkUnreferencedComputed(lx, Comp, referencedComputed);
2184
2081
  return lx;
2185
2082
  });
2186
2083
  }
2187
- function checkView(lx, view, Comp, referencedAlters, referencedComputed) {
2084
+ function checkView(lx, view, Comp, referencedAlters) {
2188
2085
  checkParseIssues(lx, view);
2189
2086
  checkRenderItInLoop(lx, view);
2190
2087
  checkEventModifiers(lx, view);
2191
- checkKnownHandlerNames(lx, view, Comp, referencedAlters, referencedComputed);
2088
+ checkKnownHandlerNames(lx, view, Comp, referencedAlters);
2192
2089
  checkMacroCallArgs(lx, view, Comp);
2193
2090
  }
2194
2091
  function checkParseIssues(lx, view) {
@@ -2289,8 +2186,8 @@ function checkEventModifiers(lx, view) {
2289
2186
  function isKnownHandlerName(name) {
2290
2187
  return KNOWN_HANDLER_NAMES.has(name);
2291
2188
  }
2292
- function checkKnownHandlerNames(lx, view, Comp, referencedAlters, referencedComputed) {
2293
- const { computed, scope, alter, Class } = Comp;
2189
+ function checkKnownHandlerNames(lx, view, Comp, referencedAlters) {
2190
+ const { scope, alter, Class } = Comp;
2294
2191
  const { prototype: proto } = Class;
2295
2192
  const { fields } = Class.getMetaClass();
2296
2193
  for (const event of view.ctx.events) {
@@ -2304,7 +2201,10 @@ function checkKnownHandlerNames(lx, view, Comp, referencedAlters, referencedComp
2304
2201
  originAttr: `@on.${eventName}`
2305
2202
  };
2306
2203
  for (let i = 0;i < args.length; i++) {
2307
- checkConsistentAttrVal(lx, args[i], fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { ...errCtx, argIndex: i });
2204
+ checkConsistentAttrVal(lx, args[i], fields, proto, scope, alter, referencedAlters, false, {
2205
+ ...errCtx,
2206
+ argIndex: i
2207
+ });
2308
2208
  }
2309
2209
  }
2310
2210
  }
@@ -2367,22 +2267,16 @@ function checkEventHandlersHaveImpls(lx, Comp, referencedInputs) {
2367
2267
  });
2368
2268
  }
2369
2269
  }
2370
- function checkConsistentAttrVal(lx, val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, skipNameVal = false, errCtx = null) {
2270
+ function checkConsistentAttrVal(lx, val, fields, proto, scope, alter, referencedAlters, skipNameVal = false, errCtx = null) {
2371
2271
  const valName = val?.constructor.name;
2372
2272
  if (valName === "FieldVal" || valName === "RawFieldVal") {
2373
2273
  const { name } = val;
2374
2274
  if (fields[name] === undefined && proto[name] === undefined) {
2375
2275
  lx.error(FIELD_VAL_NOT_DEFINED, { ...errCtx, val, name });
2376
2276
  }
2377
- } else if (valName === "ComputedVal") {
2378
- const { name } = val;
2379
- referencedComputed?.add(name);
2380
- if (computed[name] === undefined) {
2381
- lx.error(COMPUTED_VAL_NOT_DEFINED, { ...errCtx, val, name });
2382
- }
2383
2277
  } else if (valName === "SeqAccessVal") {
2384
- checkConsistentAttrVal(lx, val.seqVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, skipNameVal, errCtx);
2385
- checkConsistentAttrVal(lx, val.keyVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, skipNameVal, errCtx);
2278
+ checkConsistentAttrVal(lx, val.seqVal, fields, proto, scope, alter, referencedAlters, skipNameVal, errCtx);
2279
+ checkConsistentAttrVal(lx, val.keyVal, fields, proto, scope, alter, referencedAlters, skipNameVal, errCtx);
2386
2280
  } else if (valName === "RequestVal") {
2387
2281
  if (scope.lookupRequest(val.name) === null) {
2388
2282
  lx.error(UNKNOWN_REQUEST_NAME, { ...errCtx, name: val.name });
@@ -2397,7 +2291,7 @@ function checkConsistentAttrVal(lx, val, fields, proto, computed, scope, alter,
2397
2291
  }
2398
2292
  } else if (valName === "StrTplVal") {
2399
2293
  for (const subVal of val.vals) {
2400
- checkConsistentAttrVal(lx, subVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, skipNameVal, errCtx);
2294
+ checkConsistentAttrVal(lx, subVal, fields, proto, scope, alter, referencedAlters, skipNameVal, errCtx);
2401
2295
  }
2402
2296
  } else if (valName === "AlterHandlerNameVal") {
2403
2297
  referencedAlters?.add(val.name);
@@ -2429,8 +2323,8 @@ function attrOriginAttr(attr) {
2429
2323
  return "@dangerouslysetinnerhtml";
2430
2324
  return `:${attr.name}`;
2431
2325
  }
2432
- function checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed) {
2433
- const { computed, scope, views, alter, Class } = Comp;
2326
+ function checkConsistentAttrs(lx, Comp, referencedAlters) {
2327
+ const { scope, views, alter, Class } = Comp;
2434
2328
  const { prototype: proto } = Class;
2435
2329
  const { fields } = Class.getMetaClass();
2436
2330
  for (const viewName in views) {
@@ -2460,10 +2354,10 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed) {
2460
2354
  ["@else", attr.elseVal]
2461
2355
  ];
2462
2356
  for (const [branch, subVal] of branches) {
2463
- checkConsistentAttrVal(lx, subVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, isMacroCall, { tag, originAttr: `@if.${attr.name}`, branch });
2357
+ checkConsistentAttrVal(lx, subVal, fields, proto, scope, alter, referencedAlters, isMacroCall, { tag, originAttr: `@if.${attr.name}`, branch });
2464
2358
  }
2465
2359
  } else if (attr?.val !== undefined) {
2466
- checkConsistentAttrVal(lx, attr.val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, isMacroCall, { tag, originAttr: attrOriginAttr(attr) });
2360
+ checkConsistentAttrVal(lx, attr.val, fields, proto, scope, alter, referencedAlters, isMacroCall, { tag, originAttr: attrOriginAttr(attr) });
2467
2361
  }
2468
2362
  }
2469
2363
  for (const [name, sources] of sourcesByName) {
@@ -2476,19 +2370,19 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed) {
2476
2370
  for (const w of wrapperAttrs) {
2477
2371
  if (w.name === "each") {
2478
2372
  if (w.whenVal)
2479
- checkConsistentAttrVal(lx, w.whenVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { tag, originAttr: "@when" });
2373
+ checkConsistentAttrVal(lx, w.whenVal, fields, proto, scope, alter, referencedAlters, false, { tag, originAttr: "@when" });
2480
2374
  if (w.enrichWithVal)
2481
- checkConsistentAttrVal(lx, w.enrichWithVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { tag, originAttr: "@enrich-with" });
2375
+ checkConsistentAttrVal(lx, w.enrichWithVal, fields, proto, scope, alter, referencedAlters, false, { tag, originAttr: "@enrich-with" });
2482
2376
  if (w.loopWithVal)
2483
- checkConsistentAttrVal(lx, w.loopWithVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { tag, originAttr: "@loop-with" });
2377
+ checkConsistentAttrVal(lx, w.loopWithVal, fields, proto, scope, alter, referencedAlters, false, { tag, originAttr: "@loop-with" });
2484
2378
  } else {
2485
2379
  const originAttr = w.name === "scope" ? "@enrich-with" : `@${w.name}`;
2486
- checkConsistentAttrVal(lx, w.val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { tag, originAttr });
2380
+ checkConsistentAttrVal(lx, w.val, fields, proto, scope, alter, referencedAlters, false, { tag, originAttr });
2487
2381
  }
2488
2382
  }
2489
2383
  }
2490
2384
  if (textChild) {
2491
- checkConsistentAttrVal(lx, textChild, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { tag, originAttr: "@text" });
2385
+ checkConsistentAttrVal(lx, textChild, fields, proto, scope, alter, referencedAlters, false, { tag, originAttr: "@text" });
2492
2386
  }
2493
2387
  }
2494
2388
  for (const node of view.ctx.nodes) {
@@ -2497,14 +2391,14 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed) {
2497
2391
  continue;
2498
2392
  const baseCtx = nodeCtxForNode(nodeKind);
2499
2393
  if (node.val) {
2500
- checkConsistentAttrVal(lx, node.val, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, baseCtx);
2394
+ checkConsistentAttrVal(lx, node.val, fields, proto, scope, alter, referencedAlters, false, baseCtx);
2501
2395
  }
2502
2396
  if (nodeKind === "RenderEachNode") {
2503
2397
  const iter = node.iterInfo;
2504
2398
  if (iter.whenVal)
2505
- checkConsistentAttrVal(lx, iter.whenVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { originAttr: "<x render-each when>" });
2399
+ checkConsistentAttrVal(lx, iter.whenVal, fields, proto, scope, alter, referencedAlters, false, { originAttr: "<x render-each when>" });
2506
2400
  if (iter.loopWithVal)
2507
- checkConsistentAttrVal(lx, iter.loopWithVal, fields, proto, computed, scope, alter, referencedAlters, referencedComputed, false, { originAttr: "<x render-each loop-with>" });
2401
+ checkConsistentAttrVal(lx, iter.loopWithVal, fields, proto, scope, alter, referencedAlters, false, { originAttr: "<x render-each loop-with>" });
2508
2402
  }
2509
2403
  }
2510
2404
  });
@@ -2524,13 +2418,6 @@ function checkUnreferencedInputHandlers(lx, Comp, referencedInputs) {
2524
2418
  }
2525
2419
  }
2526
2420
  }
2527
- function checkUnreferencedComputed(lx, Comp, referencedComputed) {
2528
- for (const name in Comp.computed) {
2529
- if (!referencedComputed.has(name)) {
2530
- lx.hint(COMPUTED_NOT_REFERENCED, { name });
2531
- }
2532
- }
2533
- }
2534
2421
 
2535
2422
  class LintContext {
2536
2423
  constructor() {
@@ -2559,7 +2446,7 @@ class LintContext {
2559
2446
  this.reports.push({ id, info, level, context: { ...this.frame } });
2560
2447
  }
2561
2448
  }
2562
- var ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED", ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED", RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP", UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER", UNKNOWN_HANDLER_ARG_NAME = "UNKNOWN_HANDLER_ARG_NAME", INPUT_HANDLER_NOT_IMPLEMENTED = "INPUT_HANDLER_NOT_IMPLEMENTED", INPUT_HANDLER_NOT_REFERENCED = "INPUT_HANDLER_NOT_REFERENCED", INPUT_HANDLER_METHOD_NOT_IMPLEMENTED = "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED", INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD = "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD", INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER = "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER", FIELD_VAL_NOT_DEFINED = "FIELD_VAL_NOT_DEFINED", COMPUTED_VAL_NOT_DEFINED = "COMPUTED_VAL_NOT_DEFINED", COMPUTED_NOT_REFERENCED = "COMPUTED_NOT_REFERENCED", DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION", IF_NO_BRANCH_SET = "IF_NO_BRANCH_SET", UNKNOWN_REQUEST_NAME = "UNKNOWN_REQUEST_NAME", UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME", UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG", UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE", UNKNOWN_X_OP = "UNKNOWN_X_OP", UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR", MAYBE_DROP_AT_PREFIX = "MAYBE_DROP_AT_PREFIX", BAD_VALUE = "BAD_VALUE", PARSE_ISSUE_KIND_TO_LINT_ID, X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, AT_PREFIX_HINT_KNOWN_BY_KIND, LEVEL_WARN = "warn", LEVEL_ERROR = "error", LEVEL_HINT = "hint", NO_WRAPPERS, KNOWN_HANDLER_NAMES, NODE_KIND_TO_CTX, LintParseContext;
2449
+ var ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED", ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED", RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP", UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER", UNKNOWN_HANDLER_ARG_NAME = "UNKNOWN_HANDLER_ARG_NAME", INPUT_HANDLER_NOT_IMPLEMENTED = "INPUT_HANDLER_NOT_IMPLEMENTED", INPUT_HANDLER_NOT_REFERENCED = "INPUT_HANDLER_NOT_REFERENCED", INPUT_HANDLER_METHOD_NOT_IMPLEMENTED = "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED", INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD = "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD", INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER = "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER", FIELD_VAL_NOT_DEFINED = "FIELD_VAL_NOT_DEFINED", DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION", IF_NO_BRANCH_SET = "IF_NO_BRANCH_SET", UNKNOWN_REQUEST_NAME = "UNKNOWN_REQUEST_NAME", UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME", UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG", UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE", UNKNOWN_X_OP = "UNKNOWN_X_OP", UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR", MAYBE_DROP_AT_PREFIX = "MAYBE_DROP_AT_PREFIX", BAD_VALUE = "BAD_VALUE", PARSE_ISSUE_KIND_TO_LINT_ID, X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, AT_PREFIX_HINT_KNOWN_BY_KIND, LEVEL_WARN = "warn", LEVEL_ERROR = "error", LEVEL_HINT = "hint", NO_WRAPPERS, KNOWN_HANDLER_NAMES, NODE_KIND_TO_CTX, LintParseContext;
2563
2450
  var init_lint_check = __esm(() => {
2564
2451
  init_anode();
2565
2452
  PARSE_ISSUE_KIND_TO_LINT_ID = {
@@ -2771,10 +2658,6 @@ class Stack {
2771
2658
  lookupName(name) {
2772
2659
  return this.ctx.lookupName(name);
2773
2660
  }
2774
- lookupComputed(name) {
2775
- const node = this.binds[0].isFrame ? this.binds[0] : this.binds[1][0];
2776
- return this.comps.lookupComputed(node.it, name);
2777
- }
2778
2661
  getHandlerFor(name, key) {
2779
2662
  return this.comps.getHandlerFor(this.it, name, key);
2780
2663
  }
@@ -3127,8 +3010,6 @@ function applyProperties(node, props, previous) {
3127
3010
  node.setAttribute(propName, propValue);
3128
3011
  else if (propName === "dangerouslySetInnerHTML")
3129
3012
  node.innerHTML = propValue.__html ?? "";
3130
- else if (isObject(propValue))
3131
- patchObject(node, previous, propName, propValue);
3132
3013
  else if (propName === "className")
3133
3014
  node.setAttribute("class", propValue);
3134
3015
  else
@@ -3148,18 +3029,6 @@ function removeProperty(node, propName, previous) {
3148
3029
  else
3149
3030
  node[propName] = null;
3150
3031
  }
3151
- function patchObject(node, previous, propName, propValue) {
3152
- const previousValue = previous?.[propName];
3153
- if (isObject(previousValue) && prototypesDiffer(previousValue, propValue)) {
3154
- node[propName] = propValue;
3155
- return;
3156
- }
3157
- if (!isObject(node[propName]))
3158
- node[propName] = {};
3159
- const target = node[propName];
3160
- for (const k in propValue)
3161
- target[k] = propValue[k];
3162
- }
3163
3032
 
3164
3033
  class VBase {
3165
3034
  }
@@ -3197,26 +3066,9 @@ function diffProps(a, b) {
3197
3066
  if (!Object.hasOwn(b, aKey)) {
3198
3067
  diff ??= {};
3199
3068
  diff[aKey] = undefined;
3200
- continue;
3201
- }
3202
- const aValue = a[aKey];
3203
- const bValue = b[aKey];
3204
- if (aValue === bValue)
3205
- continue;
3206
- if (isObject(aValue) && isObject(bValue)) {
3207
- if (prototypesDiffer(bValue, aValue)) {
3208
- diff ??= {};
3209
- diff[aKey] = bValue;
3210
- } else {
3211
- const objectDiff = diffProps(aValue, bValue);
3212
- if (objectDiff) {
3213
- diff ??= {};
3214
- diff[aKey] = objectDiff;
3215
- }
3216
- }
3217
- } else {
3069
+ } else if (a[aKey] !== b[aKey]) {
3218
3070
  diff ??= {};
3219
- diff[aKey] = bValue;
3071
+ diff[aKey] = b[aKey];
3220
3072
  }
3221
3073
  }
3222
3074
  for (const bKey in b) {
@@ -3369,7 +3221,7 @@ function h(tagName, properties, children) {
3369
3221
  addChild(normalizedChildren, children);
3370
3222
  return new VNode(tag, props, normalizedChildren, key, namespace);
3371
3223
  }
3372
- var isHtmlAttribute = (propName) => propName[4] === "-" && (propName[0] === "d" || propName[0] === "a"), isObject = (v) => v !== null && typeof v === "object", prototypesDiffer = (a, b) => Object.getPrototypeOf(a) !== Object.getPrototypeOf(b), getKey = (child) => child instanceof VNode ? child.key : undefined, isIterable = (obj) => obj != null && typeof obj !== "string" && typeof obj[Symbol.iterator] === "function", VText, VComment, VFragment, VNode;
3224
+ var isHtmlAttribute = (propName) => propName[4] === "-" && (propName[0] === "d" || propName[0] === "a"), getKey = (child) => child instanceof VNode ? child.key : undefined, isIterable = (obj) => obj != null && typeof obj !== "string" && typeof obj[Symbol.iterator] === "function", VText, VComment, VFragment, VNode;
3373
3225
  var init_vdom = __esm(() => {
3374
3226
  VText = class VText extends VBase {
3375
3227
  constructor(text) {
@@ -3623,12 +3475,10 @@ class App {
3623
3475
  this.render();
3624
3476
  });
3625
3477
  injectCss("tutuca-app", this.comps.compileStyles(), opts?.head ?? document.head);
3626
- if (opts?.noCache) {
3478
+ if (opts?.noCache)
3627
3479
  this.renderer.setNullCache();
3628
- this.comps.setNullComputedCache();
3629
- } else {
3480
+ else
3630
3481
  this.startCacheEvictionInterval();
3631
- }
3632
3482
  this.render();
3633
3483
  }
3634
3484
  stop() {
@@ -7946,6 +7796,76 @@ var init_immutable = __esm(() => {
7946
7796
  initCollectionConversions();
7947
7797
  });
7948
7798
 
7799
+ // src/cache.js
7800
+ class NullDomCache {
7801
+ get(_keys, _cacheKey) {}
7802
+ set(_keys, _cacheKey, _v) {}
7803
+ evict() {
7804
+ return { hit: 0, miss: 0, badKey: 0 };
7805
+ }
7806
+ }
7807
+
7808
+ class WeakMapDomCache {
7809
+ constructor() {
7810
+ this.hit = this.miss = this.badKey = 0;
7811
+ this.keysByLen = new Map;
7812
+ }
7813
+ _returnValue(r) {
7814
+ if (r === undefined)
7815
+ this.miss += 1;
7816
+ else
7817
+ this.hit += 1;
7818
+ return r;
7819
+ }
7820
+ get(keys, cacheKey) {
7821
+ const len = keys.length;
7822
+ let cur = this.keysByLen.get(len);
7823
+ if (!cur)
7824
+ return this._returnValue(undefined);
7825
+ for (let i = 0;i < len - 1; i++) {
7826
+ cur = cur.get(keys[i]);
7827
+ if (!cur)
7828
+ return this._returnValue(undefined);
7829
+ }
7830
+ return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
7831
+ }
7832
+ set(keys, cacheKey, v) {
7833
+ const len = keys.length;
7834
+ let cur = this.keysByLen.get(len);
7835
+ if (!cur) {
7836
+ cur = new WeakMap;
7837
+ this.keysByLen.set(len, cur);
7838
+ }
7839
+ for (let i = 0;i < len - 1; i++) {
7840
+ const key = keys[i];
7841
+ let next = cur.get(key);
7842
+ if (!next) {
7843
+ if (typeof key !== "object") {
7844
+ this.badKey += 1;
7845
+ return;
7846
+ }
7847
+ next = new WeakMap;
7848
+ cur.set(key, next);
7849
+ }
7850
+ cur = next;
7851
+ }
7852
+ const lastKey = keys[len - 1];
7853
+ const leaf = cur.get(lastKey);
7854
+ if (leaf)
7855
+ leaf[cacheKey] = v;
7856
+ else if (typeof lastKey === "object")
7857
+ cur.set(lastKey, { [cacheKey]: v });
7858
+ else
7859
+ this.badKey += 1;
7860
+ }
7861
+ evict() {
7862
+ const { hit, miss, badKey } = this;
7863
+ this.hit = this.miss = this.badKey = 0;
7864
+ this.keysByLen = new Map;
7865
+ return { hit, miss, badKey };
7866
+ }
7867
+ }
7868
+
7949
7869
  // src/renderer.js
7950
7870
  class Renderer {
7951
7871
  constructor(comps) {
@@ -8150,6 +8070,8 @@ function renderExamples(normalized, env, { name = null, title = null, view = nul
8150
8070
  error
8151
8071
  }));
8152
8072
  }
8073
+ if (items.length === 0)
8074
+ continue;
8153
8075
  sections.push(new RenderedSection({
8154
8076
  title: section.title,
8155
8077
  description: section.description,
@@ -8162,43 +8084,6 @@ var init_render2 = __esm(() => {
8162
8084
  init_render();
8163
8085
  });
8164
8086
 
8165
- // tools/core/doctor.js
8166
- function runDoctor(normalized, env) {
8167
- const lint = lintComponents(normalized, {
8168
- LintParseContextClass: env.LintParseContext
8169
- });
8170
- const renders = renderExamples(normalized, env);
8171
- return new DoctorReport({ lint, renders });
8172
- }
8173
- var init_doctor = __esm(() => {
8174
- init_lint();
8175
- init_render2();
8176
- });
8177
-
8178
- // tools/core/list.js
8179
- function summarize(comp) {
8180
- const meta = comp.Class.getMetaClass();
8181
- const fields = [];
8182
- for (const fieldName in meta.fields) {
8183
- const f = meta.fields[fieldName];
8184
- fields.push({ name: fieldName, type: f.type });
8185
- }
8186
- return new ComponentSummary({
8187
- name: comp.name,
8188
- views: Object.keys(comp.views ?? {}),
8189
- fields
8190
- });
8191
- }
8192
- function listComponents(normalized, { name = null } = {}) {
8193
- const comps = normalized.components;
8194
- const picked = name === null ? comps : comps.filter((c) => c.name === name);
8195
- return new ComponentList({ items: picked.map(summarize) });
8196
- }
8197
- function listExamples(normalized) {
8198
- return new ExampleIndex({ sections: normalized.sections });
8199
- }
8200
- var init_list = () => {};
8201
-
8202
8087
  // tools/cli/commands/_registry.js
8203
8088
  var exports__registry = {};
8204
8089
  __export(exports__registry, {
@@ -8208,7 +8093,6 @@ var COMMANDS;
8208
8093
  var init__registry = __esm(() => {
8209
8094
  init_describe();
8210
8095
  init_docs();
8211
- init_doctor();
8212
8096
  init_list();
8213
8097
  init_lint();
8214
8098
  init_render2();
@@ -8257,19 +8141,6 @@ var init__registry = __esm(() => {
8257
8141
  view: values.view ?? null
8258
8142
  }),
8259
8143
  exitOn: (result) => result.hasErrors ? 3 : 0
8260
- },
8261
- doctor: {
8262
- describe: "Run lint + render as a smoke test over the module.",
8263
- defaultFormat: "cli",
8264
- needsEnv: true,
8265
- run: (normalized, _parsed, env) => runDoctor(normalized, env),
8266
- exitOn: (result) => {
8267
- if (result.lint.hasErrors)
8268
- return 2;
8269
- if (result.renders.hasErrors)
8270
- return 3;
8271
- return 0;
8272
- }
8273
8144
  }
8274
8145
  };
8275
8146
  });
@@ -8396,7 +8267,7 @@ MODULE CONVENTION
8396
8267
  export function getComponents() // required for all module commands
8397
8268
  -> Component[] // results of tutuca's component()
8398
8269
 
8399
- export function getExamples() // required for render/doctor
8270
+ export function getExamples() // required for render
8400
8271
  -> Section | Section[] // single section or an array
8401
8272
  where Section = { title: string, description?: string,
8402
8273
  items: Example[] }
@@ -8441,10 +8312,6 @@ COMMANDS (require <module-path>)
8441
8312
  --view <v> override the example's view name
8442
8313
  Exits 3 if any render crashes.
8443
8314
 
8444
- doctor
8445
- lint + render in one pass, producing a combined report. The smoke
8446
- test invocation for CI. Exits 2 on lint errors, 3 on render crashes.
8447
-
8448
8315
  COMMANDS (no module required)
8449
8316
  help [command]
8450
8317
  Without [command]: prints this full reference.
@@ -8458,8 +8325,8 @@ COMMANDS (no module required)
8458
8325
  GLOBAL FLAGS
8459
8326
  -f, --format <cli|md|json|html>
8460
8327
  Output format. Defaults per command:
8461
- info, list, examples, lint, doctor -> cli
8462
- docs, render -> md
8328
+ info, list, examples, lint -> cli
8329
+ docs, render -> md
8463
8330
  html is only supported by render.
8464
8331
  json is supported by every command and serializes the result
8465
8332
  class directly — useful for piping into other tools or agents.
@@ -8493,8 +8360,9 @@ EXAMPLES
8493
8360
  # Render a single example
8494
8361
  tutuca ./src/components.js render Button --title "Disabled state"
8495
8362
 
8496
- # CI smoke test
8497
- tutuca ./src/components.js doctor
8363
+ # Post-edit verification: lint, then render the example you changed
8364
+ tutuca ./src/components.js lint
8365
+ tutuca ./src/components.js render --title "Disabled state"
8498
8366
  `;
8499
8367
  async function run2(argv) {
8500
8368
  const target = argv?.[0];
@@ -8532,9 +8400,18 @@ import { parseArgs as parseArgs2 } from "node:util";
8532
8400
  // tools/cli/env.js
8533
8401
  init_anode();
8534
8402
  init_lint_check();
8535
- import { JSDOM } from "jsdom";
8403
+ import { JSDOM, VirtualConsole } from "jsdom";
8536
8404
  async function createNodeEnv() {
8537
- const dom = new JSDOM("<!DOCTYPE html><html><head></head><body></body></html>");
8405
+ const virtualConsole = new VirtualConsole;
8406
+ virtualConsole.forwardTo(console, { jsdomErrors: "none" });
8407
+ virtualConsole.on("jsdomError", (err) => {
8408
+ if (err?.message?.includes("Could not parse CSS stylesheet"))
8409
+ return;
8410
+ console.error(err.message);
8411
+ });
8412
+ const dom = new JSDOM("<!DOCTYPE html><html><head></head><body></body></html>", {
8413
+ virtualConsole
8414
+ });
8538
8415
  const { document: document2, Text, Comment } = dom.window;
8539
8416
  globalThis.document = document2;
8540
8417
 
@@ -8664,10 +8541,6 @@ function lintIdToMessage(id, info) {
8664
8541
  return `'${info.name}' exists as method — use with '.' prefix${fmtEventSuffix(info)}`;
8665
8542
  case "FIELD_VAL_NOT_DEFINED":
8666
8543
  return `Field '.${info.name}' is not defined${fmtOriginSuffix(info)}`;
8667
- case "COMPUTED_VAL_NOT_DEFINED":
8668
- return `Computed property '$${info.name}' is not defined${fmtOriginSuffix(info)}`;
8669
- case "COMPUTED_NOT_REFERENCED":
8670
- return `Computed property '$${info.name}' is defined but not referenced`;
8671
8544
  case "DUPLICATE_ATTR_DEFINITION": {
8672
8545
  const sources = info.sources?.length ? ` (${info.sources.join(", ")})` : "";
8673
8546
  const tag = info.tag ? ` on <${String(info.tag).toLowerCase()}>` : "";
@@ -8809,26 +8682,13 @@ function fmtRenderBatch(batch) {
8809
8682
  return lines.join(`
8810
8683
  `);
8811
8684
  }
8812
- function fmtDoctor(rep) {
8813
- const lines = [];
8814
- lines.push("== lint ==");
8815
- lines.push(fmtLintReport(rep.lint));
8816
- lines.push("");
8817
- lines.push("== renders ==");
8818
- lines.push(fmtRenderBatch(rep.renders));
8819
- lines.push("");
8820
- lines.push(`Result: ${rep.ok ? "OK" : "FAIL"}`);
8821
- return lines.join(`
8822
- `);
8823
- }
8824
8685
  var { supports, format } = makeFormatter("cli", {
8825
8686
  ModuleInfo: fmtModuleInfo,
8826
8687
  ComponentList: fmtComponentList,
8827
8688
  ExampleIndex: fmtExampleIndex,
8828
8689
  ComponentDocs: fmtComponentDocs,
8829
8690
  LintReport: fmtLintReport,
8830
- RenderBatch: fmtRenderBatch,
8831
- DoctorReport: fmtDoctor
8691
+ RenderBatch: fmtRenderBatch
8832
8692
  });
8833
8693
 
8834
8694
  // tools/format/md.js
@@ -9004,8 +8864,7 @@ var { supports: supports3, format: format3 } = makeFormatter("json", {
9004
8864
  ExampleIndex: fmtJson,
9005
8865
  ComponentDocs: fmtJson,
9006
8866
  LintReport: fmtJson,
9007
- RenderBatch: fmtJson,
9008
- DoctorReport: fmtJson
8867
+ RenderBatch: fmtJson
9009
8868
  });
9010
8869
 
9011
8870
  // tools/format/html.js