@miaskiewicz/turbo-dom 0.1.24 → 0.1.26

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miaskiewicz/turbo-dom",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "description": "Faster, more spec-correct DOM for test runners — native html5ever (Rust/WASM) parser + lazy copy-on-write DOM. A drop-in-style alternative to jsdom/happy-dom for vitest & jest.",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -22,12 +22,12 @@ import { serializeInner, serializeOuter } from './html-serialize.mjs';
22
22
  function cachedQSA(node, sel) {
23
23
  const doc = node.ownerDocument || node;
24
24
  const v = doc.__version || 0;
25
- let cache = node.__qCache;
26
- if (cache) { const c = cache.get('a:' + sel); if (c !== undefined && c.v === v) return c.r; }
27
- else cache = node.__qCache = new Map();
25
+ let cache = node.__qaCache;
26
+ if (cache) { const c = cache.get(sel); if (c !== undefined && c.v === v) return c.r; }
27
+ else cache = node.__qaCache = new Map();
28
28
  if (cache.size > 512) cache.clear();
29
29
  const r = qselAll(node, sel);
30
- cache.set('a:' + sel, { v, r });
30
+ cache.set(sel, { v, r });
31
31
  return r;
32
32
  }
33
33
  // memoize the className → class-list split (pure; the regex split showed up per
@@ -45,12 +45,12 @@ function splitClasses(cls) {
45
45
  function cachedQS(node, sel) {
46
46
  const doc = node.ownerDocument || node;
47
47
  const v = doc.__version || 0;
48
- let cache = node.__qCache;
49
- if (cache) { const c = cache.get('s:' + sel); if (c !== undefined && c.v === v) return c.r; }
50
- else cache = node.__qCache = new Map();
48
+ let cache = node.__qsCache;
49
+ if (cache) { const c = cache.get(sel); if (c !== undefined && c.v === v) return c.r; }
50
+ else cache = node.__qsCache = new Map();
51
51
  if (cache.size > 512) cache.clear();
52
52
  const r = qsel(node, sel);
53
- cache.set('s:' + sel, { v, r });
53
+ cache.set(sel, { v, r });
54
54
  return r;
55
55
  }
56
56
  import { Buffer } from './buffer.mjs';
@@ -338,7 +338,7 @@ export class Element extends Node {
338
338
  super(ownerDocument);
339
339
  this.localName = localName;
340
340
  this.__ns = namespace; // '', 'svg', 'math'
341
- this.__attrs = []; // [{name, value, prefix}]
341
+ this.__attrs = undefined; // lazily built (buffer or []) on first attr touch
342
342
  this.__attrIdx = -1; // buffer index for lazy attr inflation
343
343
  this.content = null; // <template> content fragment
344
344
  this.shadowRoot = null; // open shadow root, if attached
@@ -1106,7 +1106,7 @@ export class Document extends Node {
1106
1106
  case ELEMENT_NODE: {
1107
1107
  node = new Element(this, buf.tagName(idx), buf.ns(idx));
1108
1108
  node.__idx = idx;
1109
- node.__attrIdx = idx; node.__attrs = undefined; // lazy: build on first attr access
1109
+ node.__attrIdx = idx; // attrs lazy (constructor left __attrs undefined)
1110
1110
  // template content fragment: a child node typed 11 named "content"
1111
1111
  if (buf.tagName(idx) === 'template') {
1112
1112
  for (let c = buf.firstChild(idx); c !== -1; c = buf.nextSib(c)) {
@@ -1284,8 +1284,22 @@ export class Document extends Node {
1284
1284
  (this.__classCache || (this.__classCache = new Map())).set(key, { v, arr });
1285
1285
  return arr;
1286
1286
  }
1287
- getElementsByTagName(tag) { const self = this; const t = tag.toLowerCase(); return liveHTMLCollection(() => self.__byTag(t)); }
1288
- getElementsByClassName(cls) { const self = this; const classes = splitClasses(cls); return liveHTMLCollection(() => self.__byClass(cls, classes)); }
1287
+ // Memoize the live HTMLCollection Proxy per key. Its getArray closure re-reads
1288
+ // the version-cached __byTag/__byClass on every access, so a memoized Proxy still
1289
+ // reflects mutations — only the per-call Proxy allocation is saved.
1290
+ getElementsByTagName(tag) {
1291
+ const t = tag.toLowerCase();
1292
+ const m = this.__tagColl || (this.__tagColl = new Map());
1293
+ let coll = m.get(t);
1294
+ if (!coll) { const self = this; coll = liveHTMLCollection(() => self.__byTag(t)); m.set(t, coll); }
1295
+ return coll;
1296
+ }
1297
+ getElementsByClassName(cls) {
1298
+ const m = this.__classColl || (this.__classColl = new Map());
1299
+ let coll = m.get(cls);
1300
+ if (!coll) { const self = this; const classes = splitClasses(cls); coll = liveHTMLCollection(() => self.__byClass(cls, classes)); m.set(cls, coll); }
1301
+ return coll;
1302
+ }
1289
1303
  contains(node) { return Node.prototype.contains.call(this, node); }
1290
1304
 
1291
1305
  // cookie jar: store name=value, strip attributes (path/Secure/SameSite/…),
@@ -307,7 +307,7 @@ function simpleMatcher(selector) {
307
307
  if (!m) return null;
308
308
  const s = m[1];
309
309
  if (s[0] === '#') { const id = s.slice(1); return (el) => el.getAttribute('id') === id; }
310
- if (s[0] === '.') { const cls = s.slice(1); return (el) => el.classList.contains(cls); }
310
+ if (s[0] === '.') { const cls = s.slice(1); return (el) => { const cn = el.getAttribute('class'); return cn ? hasClass(cn, cls) : false; }; }
311
311
  const tag = s.toLowerCase(); return (el) => el.localName === tag;
312
312
  }
313
313