atoms-element v5.0.0
git clone https://git.pyrossh.dev/atoms-element
A simple web component library for defining your custom elements. It works on both client and server.
ba74771
— Peter John
2026-08-07T16:03:34+05:30
improve components
- examples/e2e.spec.js +32 -4
- examples/elements/app-counter.js +13 -58
- examples/elements/app-total.js +6 -3
- examples/pages/index.js +2 -2
- examples/server.js +0 -1
- examples/store.js +0 -15
- index.d.ts +13 -0
- index.js +117 -6
- package-lock.json +450 -0
- package.json +1 -0
examples/e2e.spec.js
CHANGED
|
@@ -49,7 +49,18 @@ test('renders each counter exactly once, with no leftover duplicate SSR markup',
|
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
+
test('seeds each counter from its count attribute, and app-total sums them with no manual sync', async () => {
|
|
53
|
+
const first = page.locator('app-counter').nth(0);
|
|
54
|
+
const second = page.locator('app-counter').nth(1);
|
|
55
|
+
assert.strictEqual((await first.locator('h1').textContent()).trim(), '5', 'first app-counter has count="5"');
|
|
56
|
+
assert.strictEqual((await second.locator('h1').textContent()).trim(), '7', 'second app-counter has count="7"');
|
|
57
|
+
// computed server-side by cheerio-parsing the already-rendered preceding
|
|
58
|
+
// markup (both app-counter tags), via useAttr — not a separately-tracked
|
|
59
|
+
// total, and no shared store between the two components.
|
|
60
|
+
assert.strictEqual((await page.locator('app-total h1').textContent()).trim(), 'Total of 2 Counters: 12');
|
|
61
|
+
});
|
|
62
|
+
|
|
52
|
-
test('clicking +/- updates the counter and the
|
|
63
|
+
test('clicking +/- updates the counter and the derived total', async () => {
|
|
53
64
|
const first = page.locator('app-counter').nth(0);
|
|
54
65
|
const second = page.locator('app-counter').nth(1);
|
|
55
66
|
|
|
@@ -59,9 +70,26 @@ test('clicking +/- updates the counter and the shared total reducer', async () =
|
|
|
59
70
|
await second.getByRole('button', { name: '+' }).click();
|
|
60
71
|
await first.getByRole('button', { name: '-' }).click();
|
|
61
72
|
|
|
73
|
+
// first: 5 + 3 - 1 = 7, second: 7 + 1 = 8, total: sum of both, live. Reflection
|
|
74
|
+
// and the MutationObserver it feeds are both async, so wait for the total to
|
|
75
|
+
// actually settle rather than asserting immediately after the last click.
|
|
76
|
+
await page.waitForFunction(() => document.querySelector('app-total h1').textContent.trim() === 'Total of 2 Counters: 15');
|
|
62
|
-
assert.strictEqual((await first.locator('h1').textContent()).trim(), '
|
|
77
|
+
assert.strictEqual((await first.locator('h1').textContent()).trim(), '7');
|
|
63
|
-
assert.strictEqual((await second.locator('h1').textContent()).trim(), '
|
|
78
|
+
assert.strictEqual((await second.locator('h1').textContent()).trim(), '8');
|
|
79
|
+
assert.strictEqual((await page.locator('app-total h1').textContent()).trim(), 'Total of 2 Counters: 15');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('external attribute writes are adopted directly, with no separate internal state to conflict with', async () => {
|
|
83
|
+
// Continuing from the previous test, the first counter currently shows 7.
|
|
84
|
+
// count now lives only in the attribute (via useProp) — there's no reducer
|
|
85
|
+
// value to reconcile it against, so an external write just is the new
|
|
86
|
+
// state, and app-total (via useAttr) picks it up automatically.
|
|
87
|
+
const first = page.locator('app-counter').nth(0);
|
|
88
|
+
await first.evaluate((el) => el.setAttribute('count', '30'));
|
|
89
|
+
await page.waitForFunction(() => document.querySelector('app-counter').querySelector('h1').textContent.trim() === '30');
|
|
90
|
+
assert.strictEqual((await first.locator('h1').textContent()).trim(), '30');
|
|
91
|
+
await page.waitForFunction(() => document.querySelector('app-total h1').textContent.trim() === 'Total of 2 Counters: 38');
|
|
64
|
-
assert.strictEqual((await page.locator('app-total h1').textContent()).trim(), 'Total of 2 Counters:
|
|
92
|
+
assert.strictEqual((await page.locator('app-total h1').textContent()).trim(), 'Total of 2 Counters: 38');
|
|
65
93
|
});
|
|
66
94
|
|
|
67
95
|
test('no console/page errors were thrown', () => {
|
examples/elements/app-counter.js
CHANGED
|
@@ -1,68 +1,23 @@
|
|
|
1
|
-
import { useEffect } from '../../index.js';
|
|
2
|
-
import { createElement, css, html,
|
|
1
|
+
import { createElement, css, html, useProp } from '../../index.js';
|
|
3
|
-
import { totalReducer } from '../store.js';
|
|
4
2
|
|
|
3
|
+
// State lives only in the count attribute — useProp reads it (type-coerced to
|
|
4
|
+
// a number, since the default 0 is a number) and writes it straight back via
|
|
5
|
+
// setAttribute, with no separate internal copy to keep in sync. count still
|
|
6
|
+
// has to appear as a destructured param below for it to end up in
|
|
7
|
+
// observedAttributes; useProp doesn't add it there itself.
|
|
5
|
-
const Counter = ({ name,
|
|
8
|
+
const Counter = ({ name, count }) => {
|
|
6
|
-
const { count, actions, effects } = useReducer({
|
|
7
|
-
initial: {
|
|
8
|
-
count: 0,
|
|
9
|
-
data: undefined,
|
|
10
|
-
err: null,
|
|
11
|
-
},
|
|
12
|
-
reducer: {
|
|
13
|
-
increment: (state) => {
|
|
14
|
-
state.count += 1;
|
|
15
|
-
},
|
|
16
|
-
decrement: (state) => {
|
|
17
|
-
state.count -= 1;
|
|
18
|
-
},
|
|
19
|
-
setLoading: (state, v) => {
|
|
20
|
-
state.loading = v;
|
|
21
|
-
},
|
|
22
|
-
setData: (state, data) => {
|
|
23
|
-
state.data = data;
|
|
24
|
-
},
|
|
25
|
-
setErr: (state, err) => {
|
|
26
|
-
state.err = err;
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
effects: {
|
|
30
|
-
loadData: async (actions, id) => {
|
|
31
|
-
try {
|
|
32
|
-
actions.setLoading(true);
|
|
33
|
-
|
|
9
|
+
const [currentCount, setCount] = useProp('count', 0);
|
|
34
|
-
actions.setData(await res.json());
|
|
35
|
-
} catch (err) {
|
|
36
|
-
actions.setErr(err);
|
|
37
|
-
} finally {
|
|
38
|
-
actions.setLoading(false);
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
effects.loadData(name);
|
|
45
|
-
}, []);
|
|
46
|
-
const increment = () =>
|
|
10
|
+
const increment = () => setCount((c) => c + 1);
|
|
47
|
-
actions.increment();
|
|
48
|
-
totalReducer.actions.increment(count + 1);
|
|
49
|
-
};
|
|
50
|
-
const decrement = () =>
|
|
11
|
+
const decrement = () => setCount((c) => c - 1);
|
|
51
|
-
actions.decrement();
|
|
52
|
-
totalReducer.actions.decrement(count - 1);
|
|
53
|
-
};
|
|
54
|
-
const warningClass =
|
|
12
|
+
const warningClass = currentCount > 10 ? 'warning' : '';
|
|
55
13
|
|
|
56
14
|
return html`
|
|
57
15
|
<div class="heading">
|
|
58
|
-
<div class="label">
|
|
16
|
+
<div class="label">Counter: ${name}</div>
|
|
59
|
-
Counter: ${name}
|
|
60
|
-
<span>starts at ${meta?.start}</span>
|
|
61
|
-
</div>
|
|
62
17
|
<div class="controls">
|
|
63
18
|
<button @click=${decrement}>-</button>
|
|
64
19
|
<div class="count">
|
|
65
|
-
<h1 class="${warningClass}">${
|
|
20
|
+
<h1 class="${warningClass}">${currentCount}</h1>
|
|
66
21
|
</div>
|
|
67
22
|
<button @click=${increment}>+</button>
|
|
68
23
|
</div>
|
examples/elements/app-total.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { createElement, css, html,
|
|
1
|
+
import { createElement, css, html, useAttr } from '../../index.js';
|
|
2
|
-
import { totalReducer } from '../store.js';
|
|
3
2
|
|
|
4
3
|
const Total = () => {
|
|
4
|
+
// No shared store: reads the count attribute directly off every app-counter
|
|
5
|
+
// on the page. Server-side this parses the already-rendered preceding
|
|
6
|
+
// markup; client-side it's backed by a MutationObserver, set up once.
|
|
7
|
+
const counts = useAttr('app-counter', 'count');
|
|
5
|
-
const
|
|
8
|
+
const total = counts.reduce((sum, v) => sum + (Number(v) || 0), 0);
|
|
6
9
|
return html`
|
|
7
10
|
<div>
|
|
8
11
|
<h1>Total of 2 Counters: ${total}</h1>
|
examples/pages/index.js
CHANGED
|
@@ -21,8 +21,8 @@ const head = ({ config }) => {
|
|
|
21
21
|
const body = () => {
|
|
22
22
|
return staticHtml`
|
|
23
23
|
<div class="page">
|
|
24
|
-
<app-counter name="1"
|
|
24
|
+
<app-counter name="1" count="5"></app-counter>
|
|
25
|
-
<app-counter name="2"
|
|
25
|
+
<app-counter name="2" count="7"></app-counter>
|
|
26
26
|
<app-total></app-total>
|
|
27
27
|
</div>
|
|
28
28
|
`;
|
examples/server.js
CHANGED
|
@@ -12,7 +12,6 @@ const port = process.argv[2] || 3000;
|
|
|
12
12
|
const elements = ['app-counter.js', 'app-total.js'];
|
|
13
13
|
const srcMap = {
|
|
14
14
|
'/index.js': `${rootDir}/index.js`,
|
|
15
|
-
'/store.js': `${__dirname}/store.js`,
|
|
16
15
|
};
|
|
17
16
|
elements.forEach((el) => {
|
|
18
17
|
srcMap['/elements/' + el] = `${__dirname}/elements/${el}`;
|
examples/store.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { createReducer } from '../index.js';
|
|
2
|
-
|
|
3
|
-
export const totalReducer = createReducer({
|
|
4
|
-
initial: {
|
|
5
|
-
total: 0,
|
|
6
|
-
},
|
|
7
|
-
reducer: {
|
|
8
|
-
increment: (state) => {
|
|
9
|
-
state.total += 1;
|
|
10
|
-
},
|
|
11
|
-
decrement: (state) => {
|
|
12
|
-
state.total -= 1;
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
});
|
index.d.ts
CHANGED
|
@@ -69,3 +69,16 @@ export function staticHtml(strings: TemplateStringsArray, ...values: any[]): any
|
|
|
69
69
|
// (e.g. meta=${jsonAttr(data)}) so it round-trips through this library's
|
|
70
70
|
// attribute-parsing convention instead of being stringified as [object Object].
|
|
71
71
|
export function jsonAttr(value: any): unknown;
|
|
72
|
+
// Reads `attribute` off every element matching `selector` — server-side via
|
|
73
|
+
// cheerio over the already-rendered preceding markup, client-side via a
|
|
74
|
+
// MutationObserver. Returns the raw attribute strings; parse them yourself.
|
|
75
|
+
export function useAttr(selector: string, attribute: string): string[];
|
|
76
|
+
// The element instance itself (e.g. to call host.setAttribute(...)). Only
|
|
77
|
+
// call this during render — capture the result via closure for later use.
|
|
78
|
+
export function useHost(): any;
|
|
79
|
+
// State lives only in the named attribute — no separate internal copy. `name`
|
|
80
|
+
// must also appear as a destructured render-function parameter for it to end
|
|
81
|
+
// up in observedAttributes. defaultValue's type controls how the attribute
|
|
82
|
+
// string is parsed (number/boolean/string); the setter accepts a value or an
|
|
83
|
+
// updater function, always resolved against the live attribute at call time.
|
|
84
|
+
export function useProp<T>(name: string, defaultValue: T): [T, (next: T | ((prev: T) => T)) => void];
|
index.js
CHANGED
|
@@ -13,11 +13,20 @@ import { create } from 'mutative';
|
|
|
13
13
|
const isBrowser = typeof window !== 'undefined';
|
|
14
14
|
export { html, isBrowser, unsafeHTML, staticHtml };
|
|
15
15
|
|
|
16
|
-
// @lit-labs/ssr
|
|
16
|
+
// @lit-labs/ssr and cheerio both pull in Node-only dependencies (module
|
|
17
|
-
// polyfills), so
|
|
17
|
+
// resolution, fetch polyfills), so they can only ever be imported on the
|
|
18
|
-
// index.js is loaded directly in the browser too (no
|
|
18
|
+
// server. This project's index.js is loaded directly in the browser too (no
|
|
19
|
-
//
|
|
19
|
+
// bundler), so these imports are conditional and dynamic — in the browser
|
|
20
|
+
// these lines never execute.
|
|
20
21
|
const ssr = isBrowser ? null : await import('@lit-labs/ssr');
|
|
22
|
+
const cheerio = isBrowser ? null : await import('cheerio');
|
|
23
|
+
|
|
24
|
+
// Set by expandCustomElements right before rendering each matched component,
|
|
25
|
+
// to whatever HTML has already been generated before it in the current page
|
|
26
|
+
// (i.e. its preceding siblings, already expanded) — this is what lets useAttr
|
|
27
|
+
// answer "what does this other, already-rendered element's attribute say"
|
|
28
|
+
// during SSR, where there's no live DOM to query.
|
|
29
|
+
const ssrContext = { precedingHtml: '' };
|
|
21
30
|
|
|
22
31
|
const attrRE = /\s([^'"/\s><]+?)[\s/>]|([^\s=]+)=\s?(".*?"|'.*?')/g;
|
|
23
32
|
const voidElements = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
|
|
@@ -88,6 +97,28 @@ const parseTag = (tag) => {
|
|
|
88
97
|
};
|
|
89
98
|
const parseAttrValue = (value) => (value && value.startsWith('{') ? JSON.parse(value.replace(/'/g, '"')) : value);
|
|
90
99
|
|
|
100
|
+
// Type is inferred from defaultValue, the way useProp's own default argument
|
|
101
|
+
// works: a number default means parse as a number, a boolean default means
|
|
102
|
+
// parse as a boolean, otherwise pass the string through as-is. Anything
|
|
103
|
+
// already parsed upstream (an object/array, via parseAttrValue) is returned
|
|
104
|
+
// unchanged.
|
|
105
|
+
const coerceAttr = (raw, defaultValue) => {
|
|
106
|
+
if (raw === undefined || raw === null) {
|
|
107
|
+
return defaultValue;
|
|
108
|
+
}
|
|
109
|
+
if (typeof raw !== 'string') {
|
|
110
|
+
return raw;
|
|
111
|
+
}
|
|
112
|
+
if (typeof defaultValue === 'number') {
|
|
113
|
+
return Number(raw);
|
|
114
|
+
}
|
|
115
|
+
if (typeof defaultValue === 'boolean') {
|
|
116
|
+
return raw !== 'false' && raw !== '0';
|
|
117
|
+
}
|
|
118
|
+
return raw;
|
|
119
|
+
};
|
|
120
|
+
const serializeAttr = (value) => (typeof value === 'object' && value !== null ? JSON.stringify(value).replace(/"/g, `'`) : String(value));
|
|
121
|
+
|
|
91
122
|
class JsonAttrDirective extends Directive {
|
|
92
123
|
render(value) {
|
|
93
124
|
return JSON.stringify(value).replace(/"/g, `'`);
|
|
@@ -122,7 +153,8 @@ const expandCustomElements = (htmlString) => {
|
|
|
122
153
|
return htmlString;
|
|
123
154
|
}
|
|
124
155
|
const re = new RegExp(`<(${tagNames.join('|')})(?=[\\s>])([^>]*)>\\s*</\\1>`, 'g');
|
|
125
|
-
return htmlString.replace(re, (match, tagName, attrsPortion) => {
|
|
156
|
+
return htmlString.replace(re, (match, tagName, attrsPortion, offset) => {
|
|
157
|
+
ssrContext.precedingHtml = htmlString.slice(0, offset);
|
|
126
158
|
const { attrs } = parseTag(`<${tagName}${attrsPortion}>`);
|
|
127
159
|
Object.keys(attrs).forEach((key) => {
|
|
128
160
|
attrs[key] = parseAttrValue(attrs[key]);
|
|
@@ -290,6 +322,7 @@ const task = (flush) => {
|
|
|
290
322
|
}
|
|
291
323
|
};
|
|
292
324
|
const depsChanged = (prev, next) => prev == null || next.some((f, i) => !Object.is(f, prev[i]));
|
|
325
|
+
const shallowArrayEqual = (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
|
|
293
326
|
|
|
294
327
|
export const createAttrs = (attrs) => attrs;
|
|
295
328
|
|
|
@@ -354,6 +387,12 @@ export const useReducer = (reducer, selector = identity) => {
|
|
|
354
387
|
const state = comp.hooks.data[index].getValue();
|
|
355
388
|
return { ...state, actions: comp.hooks.data[index].actions, effects: comp.hooks.data[index].effects };
|
|
356
389
|
};
|
|
390
|
+
// The element instance itself, e.g. to reflect state onto its own attributes
|
|
391
|
+
// (host.setAttribute(...)) so other components can read it via useAttr. Safe to
|
|
392
|
+
// call only during render — capture the return value via closure for later use
|
|
393
|
+
// in effects/handlers, don't call this hook itself from inside one.
|
|
394
|
+
export const useHost = () => currentComponent.get();
|
|
395
|
+
|
|
357
396
|
export const useEffect = (fn, deps) => {
|
|
358
397
|
const comp = currentComponent.get();
|
|
359
398
|
const index = comp.hooks.index++;
|
|
@@ -363,6 +402,64 @@ export const useEffect = (fn, deps) => {
|
|
|
363
402
|
}
|
|
364
403
|
};
|
|
365
404
|
|
|
405
|
+
// Reads `attribute` off every element matching `selector`, without either side
|
|
406
|
+
// needing a shared store: on the server there's no live DOM to query, so it
|
|
407
|
+
// reads from ssrContext.precedingHtml (everything already rendered before this
|
|
408
|
+
// component in the current page) via cheerio; in the browser it sets up a
|
|
409
|
+
// MutationObserver once and re-renders this component whenever a match changes.
|
|
410
|
+
export const useAttr = (selector, attribute) => {
|
|
411
|
+
const comp = currentComponent.get();
|
|
412
|
+
const index = comp.hooks.index++;
|
|
413
|
+
if (!isBrowser) {
|
|
414
|
+
const $ = cheerio.load(ssrContext.precedingHtml);
|
|
415
|
+
return $(selector)
|
|
416
|
+
.map((i, el) => $(el).attr(attribute))
|
|
417
|
+
.get();
|
|
418
|
+
}
|
|
419
|
+
if (!comp.hooks.data[index]) {
|
|
420
|
+
const read = () => Array.from(document.querySelectorAll(selector)).map((el) => el.getAttribute(attribute));
|
|
421
|
+
comp.hooks.data[index] = read();
|
|
422
|
+
const observer = new window.MutationObserver(() => {
|
|
423
|
+
const next = read();
|
|
424
|
+
if (!shallowArrayEqual(next, comp.hooks.data[index])) {
|
|
425
|
+
comp.hooks.data[index] = next;
|
|
426
|
+
comp.update();
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
observer.observe(document.body, { attributes: true, attributeFilter: [attribute], subtree: true });
|
|
430
|
+
comp.hooks.cleanups[index] = () => observer.disconnect();
|
|
431
|
+
}
|
|
432
|
+
return comp.hooks.data[index];
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
// The attribute is the only copy of this state — there's no separate internal
|
|
436
|
+
// value to keep in sync with it (that bidirectional sync, tried in an earlier
|
|
437
|
+
// version of this, was a genuine, unresolvable race: whichever side changed
|
|
438
|
+
// last could always be undone by a stale update from the other side still in
|
|
439
|
+
// flight). Reading here is just "what does the attribute say right now";
|
|
440
|
+
// writing is just "set the attribute" (which synchronously updates comp.attrs
|
|
441
|
+
// via attributeChangedCallback and schedules a re-render if connected).
|
|
442
|
+
//
|
|
443
|
+
// The setter accepts a plain value or an updater function (setCount(c => c+1))
|
|
444
|
+
// — always resolved against the live attribute value at call time, not a
|
|
445
|
+
// value captured in a render closure, so rapid successive calls (e.g. quick
|
|
446
|
+
// clicks, each queued before a re-render lands) don't read stale state and
|
|
447
|
+
// silently lose updates.
|
|
448
|
+
//
|
|
449
|
+
// name must still appear as a destructured render-function parameter (even if
|
|
450
|
+
// unused otherwise) for it to end up in observedAttributes — that list is read
|
|
451
|
+
// by the browser once, synchronously, when the class is defined, so it can't
|
|
452
|
+
// depend on anything this hook (called later, during render) discovers.
|
|
453
|
+
export const useProp = (name, defaultValue) => {
|
|
454
|
+
const comp = currentComponent.get();
|
|
455
|
+
const value = coerceAttr(comp.attrs[name], defaultValue);
|
|
456
|
+
const setValue = (next) => {
|
|
457
|
+
const resolved = typeof next === 'function' ? next(coerceAttr(comp.attrs[name], defaultValue)) : next;
|
|
458
|
+
comp.setAttribute(name, serializeAttr(resolved));
|
|
459
|
+
};
|
|
460
|
+
return [value, setValue];
|
|
461
|
+
};
|
|
462
|
+
|
|
366
463
|
const registry = {};
|
|
367
464
|
const injectedStyleTags = new Set();
|
|
368
465
|
export const getElement = (name) => registry[name];
|
|
@@ -381,6 +478,7 @@ export const createElement = (meta, renderFn) => {
|
|
|
381
478
|
constructor(ssrAttrs) {
|
|
382
479
|
super();
|
|
383
480
|
this._dirty = false;
|
|
481
|
+
this._effectsPending = false;
|
|
384
482
|
this._connected = false;
|
|
385
483
|
this._hydrated = false;
|
|
386
484
|
this.attrs = ssrAttrs || {};
|
|
@@ -465,7 +563,20 @@ export const createElement = (meta, renderFn) => {
|
|
|
465
563
|
}
|
|
466
564
|
|
|
467
565
|
enqueueEffects() {
|
|
566
|
+
// Without this guard, several render cycles completing in quick succession
|
|
567
|
+
// (e.g. rapid clicks) each schedule their own separate effects-flush task;
|
|
568
|
+
// those can interleave with later renders' own effect scheduling in ways
|
|
569
|
+
// that break invariants effects rely on (observed this firsthand: a
|
|
570
|
+
// still-pending flush from an earlier render raced a newer one and
|
|
571
|
+
// clobbered state that had already moved on).
|
|
572
|
+
if (this._effectsPending) {
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
this._effectsPending = true;
|
|
468
|
-
this.batch(task, filo, () =>
|
|
576
|
+
this.batch(task, filo, () => {
|
|
577
|
+
this._effectsPending = false;
|
|
578
|
+
this._flushEffects();
|
|
579
|
+
});
|
|
469
580
|
}
|
|
470
581
|
|
|
471
582
|
render() {
|
package-lock.json
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@lit-labs/ssr": "^4.1.0",
|
|
13
13
|
"@lit-labs/ssr-client": "^1.1.8",
|
|
14
|
+
"cheerio": "^1.2.0",
|
|
14
15
|
"lit-html": "^3.3.3",
|
|
15
16
|
"mutative": "^1.3.0"
|
|
16
17
|
},
|
|
@@ -91,6 +92,82 @@
|
|
|
91
92
|
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
|
92
93
|
"license": "MIT"
|
|
93
94
|
},
|
|
95
|
+
"node_modules/boolbase": {
|
|
96
|
+
"version": "1.0.0",
|
|
97
|
+
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
|
98
|
+
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
|
|
99
|
+
"license": "ISC"
|
|
100
|
+
},
|
|
101
|
+
"node_modules/cheerio": {
|
|
102
|
+
"version": "1.2.0",
|
|
103
|
+
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz",
|
|
104
|
+
"integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==",
|
|
105
|
+
"license": "MIT",
|
|
106
|
+
"dependencies": {
|
|
107
|
+
"cheerio-select": "^2.1.0",
|
|
108
|
+
"dom-serializer": "^2.0.0",
|
|
109
|
+
"domhandler": "^5.0.3",
|
|
110
|
+
"domutils": "^3.2.2",
|
|
111
|
+
"encoding-sniffer": "^0.2.1",
|
|
112
|
+
"htmlparser2": "^10.1.0",
|
|
113
|
+
"parse5": "^7.3.0",
|
|
114
|
+
"parse5-htmlparser2-tree-adapter": "^7.1.0",
|
|
115
|
+
"parse5-parser-stream": "^7.1.2",
|
|
116
|
+
"undici": "^7.19.0",
|
|
117
|
+
"whatwg-mimetype": "^4.0.0"
|
|
118
|
+
},
|
|
119
|
+
"engines": {
|
|
120
|
+
"node": ">=20.18.1"
|
|
121
|
+
},
|
|
122
|
+
"funding": {
|
|
123
|
+
"url": "https://github.com/cheeriojs/cheerio?sponsor=1"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"node_modules/cheerio-select": {
|
|
127
|
+
"version": "2.1.0",
|
|
128
|
+
"resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
|
|
129
|
+
"integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
|
|
130
|
+
"license": "BSD-2-Clause",
|
|
131
|
+
"dependencies": {
|
|
132
|
+
"boolbase": "^1.0.0",
|
|
133
|
+
"css-select": "^5.1.0",
|
|
134
|
+
"css-what": "^6.1.0",
|
|
135
|
+
"domelementtype": "^2.3.0",
|
|
136
|
+
"domhandler": "^5.0.3",
|
|
137
|
+
"domutils": "^3.0.1"
|
|
138
|
+
},
|
|
139
|
+
"funding": {
|
|
140
|
+
"url": "https://github.com/sponsors/fb55"
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"node_modules/css-select": {
|
|
144
|
+
"version": "5.2.2",
|
|
145
|
+
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
|
|
146
|
+
"integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
|
|
147
|
+
"license": "BSD-2-Clause",
|
|
148
|
+
"dependencies": {
|
|
149
|
+
"boolbase": "^1.0.0",
|
|
150
|
+
"css-what": "^6.1.0",
|
|
151
|
+
"domhandler": "^5.0.2",
|
|
152
|
+
"domutils": "^3.0.1",
|
|
153
|
+
"nth-check": "^2.0.1"
|
|
154
|
+
},
|
|
155
|
+
"funding": {
|
|
156
|
+
"url": "https://github.com/sponsors/fb55"
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"node_modules/css-what": {
|
|
160
|
+
"version": "6.2.2",
|
|
161
|
+
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
|
|
162
|
+
"integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
|
|
163
|
+
"license": "BSD-2-Clause",
|
|
164
|
+
"engines": {
|
|
165
|
+
"node": ">= 6"
|
|
166
|
+
},
|
|
167
|
+
"funding": {
|
|
168
|
+
"url": "https://github.com/sponsors/fb55"
|
|
169
|
+
}
|
|
170
|
+
},
|
|
94
171
|
"node_modules/data-uri-to-buffer": {
|
|
95
172
|
"version": "4.0.1",
|
|
96
173
|
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
|
@@ -100,6 +177,86 @@
|
|
|
100
177
|
"node": ">= 12"
|
|
101
178
|
}
|
|
102
179
|
},
|
|
180
|
+
"node_modules/dom-serializer": {
|
|
181
|
+
"version": "2.0.0",
|
|
182
|
+
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
|
183
|
+
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
|
184
|
+
"license": "MIT",
|
|
185
|
+
"dependencies": {
|
|
186
|
+
"domelementtype": "^2.3.0",
|
|
187
|
+
"domhandler": "^5.0.2",
|
|
188
|
+
"entities": "^4.2.0"
|
|
189
|
+
},
|
|
190
|
+
"funding": {
|
|
191
|
+
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
"node_modules/dom-serializer/node_modules/entities": {
|
|
195
|
+
"version": "4.5.0",
|
|
196
|
+
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
|
197
|
+
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
|
198
|
+
"license": "BSD-2-Clause",
|
|
199
|
+
"engines": {
|
|
200
|
+
"node": ">=0.12"
|
|
201
|
+
},
|
|
202
|
+
"funding": {
|
|
203
|
+
"url": "https://github.com/fb55/entities?sponsor=1"
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"node_modules/domelementtype": {
|
|
207
|
+
"version": "2.3.0",
|
|
208
|
+
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
|
209
|
+
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
|
210
|
+
"funding": [
|
|
211
|
+
{
|
|
212
|
+
"type": "github",
|
|
213
|
+
"url": "https://github.com/sponsors/fb55"
|
|
214
|
+
}
|
|
215
|
+
],
|
|
216
|
+
"license": "BSD-2-Clause"
|
|
217
|
+
},
|
|
218
|
+
"node_modules/domhandler": {
|
|
219
|
+
"version": "5.0.3",
|
|
220
|
+
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
|
221
|
+
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
|
222
|
+
"license": "BSD-2-Clause",
|
|
223
|
+
"dependencies": {
|
|
224
|
+
"domelementtype": "^2.3.0"
|
|
225
|
+
},
|
|
226
|
+
"engines": {
|
|
227
|
+
"node": ">= 4"
|
|
228
|
+
},
|
|
229
|
+
"funding": {
|
|
230
|
+
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
"node_modules/domutils": {
|
|
234
|
+
"version": "3.2.2",
|
|
235
|
+
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
|
236
|
+
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
|
|
237
|
+
"license": "BSD-2-Clause",
|
|
238
|
+
"dependencies": {
|
|
239
|
+
"dom-serializer": "^2.0.0",
|
|
240
|
+
"domelementtype": "^2.3.0",
|
|
241
|
+
"domhandler": "^5.0.3"
|
|
242
|
+
},
|
|
243
|
+
"funding": {
|
|
244
|
+
"url": "https://github.com/fb55/domutils?sponsor=1"
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
"node_modules/encoding-sniffer": {
|
|
248
|
+
"version": "0.2.1",
|
|
249
|
+
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz",
|
|
250
|
+
"integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==",
|
|
251
|
+
"license": "MIT",
|
|
252
|
+
"dependencies": {
|
|
253
|
+
"iconv-lite": "^0.6.3",
|
|
254
|
+
"whatwg-encoding": "^3.1.1"
|
|
255
|
+
},
|
|
256
|
+
"funding": {
|
|
257
|
+
"url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
|
|
258
|
+
}
|
|
259
|
+
},
|
|
103
260
|
"node_modules/enhanced-resolve": {
|
|
104
261
|
"version": "5.24.5",
|
|
105
262
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz",
|
|
@@ -166,6 +323,49 @@
|
|
|
166
323
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
|
167
324
|
"license": "ISC"
|
|
168
325
|
},
|
|
326
|
+
"node_modules/htmlparser2": {
|
|
327
|
+
"version": "10.1.0",
|
|
328
|
+
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz",
|
|
329
|
+
"integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==",
|
|
330
|
+
"funding": [
|
|
331
|
+
"https://github.com/fb55/htmlparser2?sponsor=1",
|
|
332
|
+
{
|
|
333
|
+
"type": "github",
|
|
334
|
+
"url": "https://github.com/sponsors/fb55"
|
|
335
|
+
}
|
|
336
|
+
],
|
|
337
|
+
"license": "MIT",
|
|
338
|
+
"dependencies": {
|
|
339
|
+
"domelementtype": "^2.3.0",
|
|
340
|
+
"domhandler": "^5.0.3",
|
|
341
|
+
"domutils": "^3.2.2",
|
|
342
|
+
"entities": "^7.0.1"
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
"node_modules/htmlparser2/node_modules/entities": {
|
|
346
|
+
"version": "7.0.1",
|
|
347
|
+
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
|
|
348
|
+
"integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
|
|
349
|
+
"license": "BSD-2-Clause",
|
|
350
|
+
"engines": {
|
|
351
|
+
"node": ">=0.12"
|
|
352
|
+
},
|
|
353
|
+
"funding": {
|
|
354
|
+
"url": "https://github.com/fb55/entities?sponsor=1"
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
"node_modules/iconv-lite": {
|
|
358
|
+
"version": "0.6.3",
|
|
359
|
+
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
|
360
|
+
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
|
361
|
+
"license": "MIT",
|
|
362
|
+
"dependencies": {
|
|
363
|
+
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
|
364
|
+
},
|
|
365
|
+
"engines": {
|
|
366
|
+
"node": ">=0.10.0"
|
|
367
|
+
}
|
|
368
|
+
},
|
|
169
369
|
"node_modules/lit": {
|
|
170
370
|
"version": "3.3.3",
|
|
171
371
|
"resolved": "https://registry.npmjs.org/lit/-/lit-3.3.3.tgz",
|
|
@@ -244,6 +444,18 @@
|
|
|
244
444
|
"url": "https://opencollective.com/node-fetch"
|
|
245
445
|
}
|
|
246
446
|
},
|
|
447
|
+
"node_modules/nth-check": {
|
|
448
|
+
"version": "2.1.1",
|
|
449
|
+
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
|
450
|
+
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
|
|
451
|
+
"license": "BSD-2-Clause",
|
|
452
|
+
"dependencies": {
|
|
453
|
+
"boolbase": "^1.0.0"
|
|
454
|
+
},
|
|
455
|
+
"funding": {
|
|
456
|
+
"url": "https://github.com/fb55/nth-check?sponsor=1"
|
|
457
|
+
}
|
|
458
|
+
},
|
|
247
459
|
"node_modules/parse5": {
|
|
248
460
|
"version": "7.3.0",
|
|
249
461
|
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
|
|
@@ -256,6 +468,31 @@
|
|
|
256
468
|
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
|
257
469
|
}
|
|
258
470
|
},
|
|
471
|
+
"node_modules/parse5-htmlparser2-tree-adapter": {
|
|
472
|
+
"version": "7.1.0",
|
|
473
|
+
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
|
|
474
|
+
"integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
|
|
475
|
+
"license": "MIT",
|
|
476
|
+
"dependencies": {
|
|
477
|
+
"domhandler": "^5.0.3",
|
|
478
|
+
"parse5": "^7.0.0"
|
|
479
|
+
},
|
|
480
|
+
"funding": {
|
|
481
|
+
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
"node_modules/parse5-parser-stream": {
|
|
485
|
+
"version": "7.1.2",
|
|
486
|
+
"resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
|
|
487
|
+
"integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
|
|
488
|
+
"license": "MIT",
|
|
489
|
+
"dependencies": {
|
|
490
|
+
"parse5": "^7.0.0"
|
|
491
|
+
},
|
|
492
|
+
"funding": {
|
|
493
|
+
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
|
494
|
+
}
|
|
495
|
+
},
|
|
259
496
|
"node_modules/playwright": {
|
|
260
497
|
"version": "1.62.1",
|
|
261
498
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz",
|
|
@@ -303,6 +540,12 @@
|
|
|
303
540
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
|
304
541
|
}
|
|
305
542
|
},
|
|
543
|
+
"node_modules/safer-buffer": {
|
|
544
|
+
"version": "2.1.2",
|
|
545
|
+
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
|
546
|
+
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
|
547
|
+
"license": "MIT"
|
|
548
|
+
},
|
|
306
549
|
"node_modules/tapable": {
|
|
307
550
|
"version": "2.3.3",
|
|
308
551
|
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
|
|
@@ -316,6 +559,15 @@
|
|
|
316
559
|
"url": "https://opencollective.com/webpack"
|
|
317
560
|
}
|
|
318
561
|
},
|
|
562
|
+
"node_modules/undici": {
|
|
563
|
+
"version": "7.29.0",
|
|
564
|
+
"resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz",
|
|
565
|
+
"integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==",
|
|
566
|
+
"license": "MIT",
|
|
567
|
+
"engines": {
|
|
568
|
+
"node": ">=20.18.1"
|
|
569
|
+
}
|
|
570
|
+
},
|
|
319
571
|
"node_modules/web-streams-polyfill": {
|
|
320
572
|
"version": "3.3.3",
|
|
321
573
|
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
|
@@ -324,6 +576,28 @@
|
|
|
324
576
|
"engines": {
|
|
325
577
|
"node": ">= 8"
|
|
326
578
|
}
|
|
579
|
+
},
|
|
580
|
+
"node_modules/whatwg-encoding": {
|
|
581
|
+
"version": "3.1.1",
|
|
582
|
+
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
|
|
583
|
+
"integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
|
|
584
|
+
"deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation",
|
|
585
|
+
"license": "MIT",
|
|
586
|
+
"dependencies": {
|
|
587
|
+
"iconv-lite": "0.6.3"
|
|
588
|
+
},
|
|
589
|
+
"engines": {
|
|
590
|
+
"node": ">=18"
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
"node_modules/whatwg-mimetype": {
|
|
594
|
+
"version": "4.0.0",
|
|
595
|
+
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
|
|
596
|
+
"integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
|
|
597
|
+
"license": "MIT",
|
|
598
|
+
"engines": {
|
|
599
|
+
"node": ">=18"
|
|
600
|
+
}
|
|
327
601
|
}
|
|
328
602
|
},
|
|
329
603
|
"dependencies": {
|
|
@@ -380,11 +654,113 @@
|
|
|
380
654
|
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
|
381
655
|
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="
|
|
382
656
|
},
|
|
657
|
+
"boolbase": {
|
|
658
|
+
"version": "1.0.0",
|
|
659
|
+
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
|
660
|
+
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
|
|
661
|
+
},
|
|
662
|
+
"cheerio": {
|
|
663
|
+
"version": "1.2.0",
|
|
664
|
+
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz",
|
|
665
|
+
"integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==",
|
|
666
|
+
"requires": {
|
|
667
|
+
"cheerio-select": "^2.1.0",
|
|
668
|
+
"dom-serializer": "^2.0.0",
|
|
669
|
+
"domhandler": "^5.0.3",
|
|
670
|
+
"domutils": "^3.2.2",
|
|
671
|
+
"encoding-sniffer": "^0.2.1",
|
|
672
|
+
"htmlparser2": "^10.1.0",
|
|
673
|
+
"parse5": "^7.3.0",
|
|
674
|
+
"parse5-htmlparser2-tree-adapter": "^7.1.0",
|
|
675
|
+
"parse5-parser-stream": "^7.1.2",
|
|
676
|
+
"undici": "^7.19.0",
|
|
677
|
+
"whatwg-mimetype": "^4.0.0"
|
|
678
|
+
}
|
|
679
|
+
},
|
|
680
|
+
"cheerio-select": {
|
|
681
|
+
"version": "2.1.0",
|
|
682
|
+
"resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
|
|
683
|
+
"integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
|
|
684
|
+
"requires": {
|
|
685
|
+
"boolbase": "^1.0.0",
|
|
686
|
+
"css-select": "^5.1.0",
|
|
687
|
+
"css-what": "^6.1.0",
|
|
688
|
+
"domelementtype": "^2.3.0",
|
|
689
|
+
"domhandler": "^5.0.3",
|
|
690
|
+
"domutils": "^3.0.1"
|
|
691
|
+
}
|
|
692
|
+
},
|
|
693
|
+
"css-select": {
|
|
694
|
+
"version": "5.2.2",
|
|
695
|
+
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
|
|
696
|
+
"integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
|
|
697
|
+
"requires": {
|
|
698
|
+
"boolbase": "^1.0.0",
|
|
699
|
+
"css-what": "^6.1.0",
|
|
700
|
+
"domhandler": "^5.0.2",
|
|
701
|
+
"domutils": "^3.0.1",
|
|
702
|
+
"nth-check": "^2.0.1"
|
|
703
|
+
}
|
|
704
|
+
},
|
|
705
|
+
"css-what": {
|
|
706
|
+
"version": "6.2.2",
|
|
707
|
+
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
|
|
708
|
+
"integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="
|
|
709
|
+
},
|
|
383
710
|
"data-uri-to-buffer": {
|
|
384
711
|
"version": "4.0.1",
|
|
385
712
|
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
|
386
713
|
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="
|
|
387
714
|
},
|
|
715
|
+
"dom-serializer": {
|
|
716
|
+
"version": "2.0.0",
|
|
717
|
+
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
|
718
|
+
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
|
719
|
+
"requires": {
|
|
720
|
+
"domelementtype": "^2.3.0",
|
|
721
|
+
"domhandler": "^5.0.2",
|
|
722
|
+
"entities": "^4.2.0"
|
|
723
|
+
},
|
|
724
|
+
"dependencies": {
|
|
725
|
+
"entities": {
|
|
726
|
+
"version": "4.5.0",
|
|
727
|
+
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
|
728
|
+
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
},
|
|
732
|
+
"domelementtype": {
|
|
733
|
+
"version": "2.3.0",
|
|
734
|
+
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
|
735
|
+
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
|
|
736
|
+
},
|
|
737
|
+
"domhandler": {
|
|
738
|
+
"version": "5.0.3",
|
|
739
|
+
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
|
740
|
+
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
|
741
|
+
"requires": {
|
|
742
|
+
"domelementtype": "^2.3.0"
|
|
743
|
+
}
|
|
744
|
+
},
|
|
745
|
+
"domutils": {
|
|
746
|
+
"version": "3.2.2",
|
|
747
|
+
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
|
748
|
+
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
|
|
749
|
+
"requires": {
|
|
750
|
+
"dom-serializer": "^2.0.0",
|
|
751
|
+
"domelementtype": "^2.3.0",
|
|
752
|
+
"domhandler": "^5.0.3"
|
|
753
|
+
}
|
|
754
|
+
},
|
|
755
|
+
"encoding-sniffer": {
|
|
756
|
+
"version": "0.2.1",
|
|
757
|
+
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz",
|
|
758
|
+
"integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==",
|
|
759
|
+
"requires": {
|
|
760
|
+
"iconv-lite": "^0.6.3",
|
|
761
|
+
"whatwg-encoding": "^3.1.1"
|
|
762
|
+
}
|
|
763
|
+
},
|
|
388
764
|
"enhanced-resolve": {
|
|
389
765
|
"version": "5.24.5",
|
|
390
766
|
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz",
|
|
@@ -421,6 +797,32 @@
|
|
|
421
797
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
|
422
798
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
|
423
799
|
},
|
|
800
|
+
"htmlparser2": {
|
|
801
|
+
"version": "10.1.0",
|
|
802
|
+
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz",
|
|
803
|
+
"integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==",
|
|
804
|
+
"requires": {
|
|
805
|
+
"domelementtype": "^2.3.0",
|
|
806
|
+
"domhandler": "^5.0.3",
|
|
807
|
+
"domutils": "^3.2.2",
|
|
808
|
+
"entities": "^7.0.1"
|
|
809
|
+
},
|
|
810
|
+
"dependencies": {
|
|
811
|
+
"entities": {
|
|
812
|
+
"version": "7.0.1",
|
|
813
|
+
"resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
|
|
814
|
+
"integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
},
|
|
818
|
+
"iconv-lite": {
|
|
819
|
+
"version": "0.6.3",
|
|
820
|
+
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
|
821
|
+
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
|
822
|
+
"requires": {
|
|
823
|
+
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
|
824
|
+
}
|
|
825
|
+
},
|
|
424
826
|
"lit": {
|
|
425
827
|
"version": "3.3.3",
|
|
426
828
|
"resolved": "https://registry.npmjs.org/lit/-/lit-3.3.3.tgz",
|
|
@@ -469,6 +871,14 @@
|
|
|
469
871
|
"formdata-polyfill": "^4.0.10"
|
|
470
872
|
}
|
|
471
873
|
},
|
|
874
|
+
"nth-check": {
|
|
875
|
+
"version": "2.1.1",
|
|
876
|
+
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
|
|
877
|
+
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
|
|
878
|
+
"requires": {
|
|
879
|
+
"boolbase": "^1.0.0"
|
|
880
|
+
}
|
|
881
|
+
},
|
|
472
882
|
"parse5": {
|
|
473
883
|
"version": "7.3.0",
|
|
474
884
|
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
|
|
@@ -477,6 +887,23 @@
|
|
|
477
887
|
"entities": "^6.0.0"
|
|
478
888
|
}
|
|
479
889
|
},
|
|
890
|
+
"parse5-htmlparser2-tree-adapter": {
|
|
891
|
+
"version": "7.1.0",
|
|
892
|
+
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
|
|
893
|
+
"integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
|
|
894
|
+
"requires": {
|
|
895
|
+
"domhandler": "^5.0.3",
|
|
896
|
+
"parse5": "^7.0.0"
|
|
897
|
+
}
|
|
898
|
+
},
|
|
899
|
+
"parse5-parser-stream": {
|
|
900
|
+
"version": "7.1.2",
|
|
901
|
+
"resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
|
|
902
|
+
"integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
|
|
903
|
+
"requires": {
|
|
904
|
+
"parse5": "^7.0.0"
|
|
905
|
+
}
|
|
906
|
+
},
|
|
480
907
|
"playwright": {
|
|
481
908
|
"version": "1.62.1",
|
|
482
909
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz",
|
|
@@ -502,15 +929,38 @@
|
|
|
502
929
|
"integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==",
|
|
503
930
|
"dev": true
|
|
504
931
|
},
|
|
932
|
+
"safer-buffer": {
|
|
933
|
+
"version": "2.1.2",
|
|
934
|
+
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
|
935
|
+
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
|
936
|
+
},
|
|
505
937
|
"tapable": {
|
|
506
938
|
"version": "2.3.3",
|
|
507
939
|
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
|
|
508
940
|
"integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="
|
|
509
941
|
},
|
|
942
|
+
"undici": {
|
|
943
|
+
"version": "7.29.0",
|
|
944
|
+
"resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz",
|
|
945
|
+
"integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw=="
|
|
946
|
+
},
|
|
510
947
|
"web-streams-polyfill": {
|
|
511
948
|
"version": "3.3.3",
|
|
512
949
|
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
|
513
950
|
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="
|
|
951
|
+
},
|
|
952
|
+
"whatwg-encoding": {
|
|
953
|
+
"version": "3.1.1",
|
|
954
|
+
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
|
|
955
|
+
"integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
|
|
956
|
+
"requires": {
|
|
957
|
+
"iconv-lite": "0.6.3"
|
|
958
|
+
}
|
|
959
|
+
},
|
|
960
|
+
"whatwg-mimetype": {
|
|
961
|
+
"version": "4.0.0",
|
|
962
|
+
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
|
|
963
|
+
"integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="
|
|
514
964
|
}
|
|
515
965
|
}
|
|
516
966
|
}
|
package.json
CHANGED
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@lit-labs/ssr": "^4.1.0",
|
|
43
43
|
"@lit-labs/ssr-client": "^1.1.8",
|
|
44
|
+
"cheerio": "^1.2.0",
|
|
44
45
|
"lit-html": "^3.3.3",
|
|
45
46
|
"mutative": "^1.3.0"
|
|
46
47
|
}
|