njsparser 0.1.0 → 0.2.0

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/README.md CHANGED
@@ -1,75 +1,425 @@
1
- # njsparser (JS)
1
+ # NJSParser (JS)
2
2
 
3
- A powerful parser and explorer for any website built with [NextJS](https://nextjs.org).
4
- Ported from the Python library `njsparser`.
3
+ A 99.9% AI-generated (including unit tests & README) JS port of [`novitae/njsparser`](https://github.com/novitae/njsparser) for extracting and parsing Next.js hydration data from HTML content.
5
4
 
6
- - Parses flight data (from the `self.__next_f.push` scripts).
7
- - Parses next data from `__NEXT_DATA__` script.
8
- - Parses build manifests.
9
- - Searches for build id.
5
+ - Parses flight data (from the **`self.__next_f.push`** scripts)
6
+ - Parses next data from **`__NEXT_DATA__`** script
7
+ - Parses **build manifests**
8
+ - Searches for **build id**
9
+ - Many other things...
10
+
11
+ This is the JavaScript/TypeScript port of the Python [njsparser](https://github.com/novitae/njsparser) library, designed to run on Bun.
10
12
 
11
13
  ## Installation
12
14
 
13
15
  ```bash
14
- bun install njsparser
15
- # or
16
- npm install njsparser
16
+ bun add njsparser
17
+ ```
18
+
19
+ Or install from source:
20
+
21
+ ```bash
22
+ git clone <repository-url>
23
+ cd njsparser/js
24
+ bun install
17
25
  ```
18
26
 
27
+ ## DOMParser dependency
28
+
29
+ This library doesn’t bundle an HTML parser. You must pass a `DOMParser` implementation when creating the parser:
30
+
31
+ - In Bun tests we use `deno-dom`’s WASM build.
32
+ - In a browser you can pass the native `DOMParser`.
33
+
19
34
  ## Usage
20
35
 
36
+ ### Basic Setup (Bun)
37
+
38
+ ```javascript
39
+ import { DOMParser } from 'deno-dom/deno-dom-wasm.ts';
40
+ import { NJSParser } from 'njsparser';
41
+
42
+ const parser = NJSParser({ DOMParser });
43
+ ```
44
+
45
+ ### Basic Setup (Browser)
46
+
47
+ ```javascript
48
+ import { NJSParser } from 'njsparser';
49
+
50
+ const parser = NJSParser({ DOMParser: window.DOMParser });
51
+ ```
52
+
21
53
  ### Parsing Flight Data
22
54
 
55
+ Flight data is contained in `self.__next_f.push()` scripts within NextJS pages.
56
+
23
57
  ```javascript
24
- import { BeautifulFD, get_flight_data } from 'njsparser';
58
+ import { DOMParser } from 'deno-dom/deno-dom-wasm.ts';
59
+ import { NJSParser } from 'njsparser';
25
60
 
26
- const html = `...`; // Fetch your HTML
61
+ const parser = NJSParser({ DOMParser });
27
62
 
28
- // Using BeautifulFD for easy searching
29
- const fd = new BeautifulFD(html);
63
+ const response = await fetch('https://nextjs.org');
64
+ const html = await response.text();
30
65
 
31
- // Find specific data types
32
- import { Data, RSCPayload } from 'njsparser';
66
+ const flightData = parser.parser.getFlightData(html);
33
67
 
34
- const rsc = fd.find({ class_filters: [RSCPayload] });
35
- console.log(rsc.build_id);
68
+ // Use BeautifulFD for easier searching
69
+ const fd = new parser.BeautifulFD(html);
36
70
 
37
- const data = fd.find_all({ class_filters: [Data] });
38
- data.forEach(item => {
39
- console.log(item.content);
40
- });
71
+ // Find specific element types
72
+ for (const data of fd.find_iter([parser.types.Data])) {
73
+ if (data.content && typeof data.content === 'object' && 'user' in data.content) {
74
+ console.log(data.content.user);
75
+ break;
76
+ }
77
+ }
41
78
  ```
42
79
 
43
80
  ### Parsing `__NEXT_DATA__`
44
81
 
45
82
  ```javascript
46
- import { get_next_data } from 'njsparser';
83
+ const parser = NJSParser({ DOMParser });
84
+
85
+ const html = await fetch('https://example.com').then(r => r.text());
86
+ const nextData = parser.parser.getNextData(html);
47
87
 
48
- const data = get_next_data(html);
49
- console.log(data.props.pageProps);
88
+ if (nextData) {
89
+ console.log('Build ID:', nextData.buildId);
90
+ console.log('Page Props:', nextData.props);
91
+ }
50
92
  ```
51
93
 
52
- ### Tools
94
+ ### Finding Build ID
53
95
 
54
96
  ```javascript
55
- import { has_nextjs, find_build_id } from 'njsparser';
97
+ const parser = NJSParser({ DOMParser });
56
98
 
57
- if (has_nextjs(html)) {
58
- console.log("NextJS detected!");
59
- console.log("Build ID:", find_build_id(html));
60
- }
99
+ const html = await fetch('https://example.com').then(r => r.text());
100
+ const buildId = parser.findBuildId(html);
101
+
102
+ console.log('Build ID:', buildId);
103
+ ```
104
+
105
+ ### Parsing Build Manifests
106
+
107
+ ```javascript
108
+ const parser = NJSParser({ DOMParser });
109
+
110
+ const manifestScript = await fetch('https://example.com/_next/static/BUILD_ID/_buildManifest.js')
111
+ .then(r => r.text());
112
+
113
+ const manifest = parser.parser.parseBuildManifest(manifestScript);
114
+ console.log('Manifest:', manifest);
61
115
  ```
62
116
 
63
117
  ## API Reference
64
118
 
65
- Most functions from the Python library are available in JS with similar signatures.
119
+ ### Factory Function
120
+
121
+ #### `NJSParser({ DOMParser })`
122
+
123
+ Creates a new parser instance.
124
+
125
+ **Parameters:**
126
+ - `DOMParser` (required): a DOMParser class/constructor to parse HTML
127
+
128
+ **Returns:** Parser instance with all methods and classes
129
+
130
+ ### Parser Methods
131
+
132
+ #### `parser.hasFlightData(html)`
133
+
134
+ Check if HTML contains flight data.
135
+
136
+ **Parameters:**
137
+ - `html` (string): HTML content
138
+
139
+ **Returns:** `boolean`
140
+
141
+ #### `parser.getFlightData(html)`
142
+
143
+ Extract and parse flight data from HTML.
144
+
145
+ **Parameters:**
146
+ - `html` (string): HTML content
147
+
148
+ **Returns:** `Object | null` - Parsed flight data or null
149
+
150
+ #### `parser.hasNextData(html)`
151
+
152
+ Check if HTML contains `__NEXT_DATA__` script.
153
+
154
+ **Parameters:**
155
+ - `html` (string): HTML content
156
+
157
+ **Returns:** `boolean`
158
+
159
+ #### `parser.getNextData(html)`
160
+
161
+ Extract and parse `__NEXT_DATA__` script.
162
+
163
+ **Parameters:**
164
+ - `html` (string): HTML content
165
+
166
+ **Returns:** `Object | null` - Parsed JSON data or null
167
+
168
+ #### `parser.parseBuildManifest(script)`
169
+
170
+ Parse build manifest script.
171
+
172
+ **Parameters:**
173
+ - `script` (string): Build manifest script content
174
+
175
+ **Returns:** `Object` - Parsed manifest
176
+
177
+ #### `parser.getBuildManifestPath(buildId, basePath)`
178
+
179
+ Generate build manifest path.
180
+
181
+ **Parameters:**
182
+ - `buildId` (string): Build ID
183
+ - `basePath` (string, optional): Base path
184
+
185
+ **Returns:** `string` - Build manifest path
186
+
187
+ #### `parser.getNextStaticUrls(html)`
188
+
189
+ Find all NextJS static URLs in HTML.
190
+
191
+ **Parameters:**
192
+ - `html` (string): HTML content
193
+
194
+ **Returns:** `Array<string> | null` - Array of URLs or null
195
+
196
+ #### `parser.getBasePath(htmlOrUrls, removeDomain)`
197
+
198
+ Extract base path from URLs or HTML.
199
+
200
+ **Parameters:**
201
+ - `htmlOrUrls` (string | Array<string>): HTML content or array of URLs
202
+ - `removeDomain` (boolean, optional): Remove domain from absolute URLs
203
+
204
+ **Returns:** `string | null` - Base path or null
205
+
206
+ ### High-Level Tools
207
+
208
+ #### `hasNextJS(html)`
209
+
210
+ Check if page has any NextJS data.
211
+
212
+ **Parameters:**
213
+ - `html` (string): HTML content
214
+
215
+ **Returns:** `boolean`
216
+
217
+ #### `findBuildId(html)`
218
+
219
+ Find build ID from page (searches static URLs, next data, and flight data).
220
+
221
+ **Parameters:**
222
+ - `html` (string): HTML content
223
+
224
+ **Returns:** `string | null` - Build ID or null
225
+
226
+ #### `findInFlightData(flightData, classFilters, callback, recursive)`
227
+
228
+ Find first matching element in flight data.
229
+
230
+ **Parameters:**
231
+ - `flightData` (Object): Flight data dictionary
232
+ - `classFilters` (Array, optional): Array of Element classes to filter by
233
+ - `callback` (Function, optional): Callback function for filtering
234
+ - `recursive` (boolean, optional): Search recursively (default: true)
235
+
236
+ **Returns:** `Element | null`
237
+
238
+ #### `findallInFlightData(flightData, classFilters, callback, recursive)`
239
+
240
+ Find all matching elements in flight data.
241
+
242
+ **Parameters:**
243
+ - `flightData` (Object): Flight data dictionary
244
+ - `classFilters` (Array, optional): Array of Element classes to filter by
245
+ - `callback` (Function, optional): Callback function for filtering
246
+ - `recursive` (boolean, optional): Search recursively (default: true)
247
+
248
+ **Returns:** `Array<Element>`
249
+
250
+ #### `finditerInFlightData(flightData, classFilters, callback, recursive)`
251
+
252
+ Iterator for finding elements in flight data.
253
+
254
+ **Parameters:**
255
+ - `flightData` (Object): Flight data dictionary
256
+ - `classFilters` (Array, optional): Array of Element classes to filter by
257
+ - `callback` (Function, optional): Callback function for filtering
258
+ - `recursive` (boolean, optional): Search recursively (default: true)
259
+
260
+ **Returns:** `Generator<Element>`
261
+
262
+ ### BeautifulFD Class
263
+
264
+ Simplified interface for working with flight data.
265
+
266
+ #### `new BeautifulFD(htmlOrFlightData)`
267
+
268
+ Create BeautifulFD instance.
269
+
270
+ **Parameters:**
271
+ - `htmlOrFlightData` (string | Object): HTML content or parsed flight data
272
+
273
+
274
+ #### `find(classFilters, callback, recursive)`
275
+
276
+ Find first matching element.
277
+
278
+ **Parameters:**
279
+ - `classFilters` (Array, optional): Array of Element classes
280
+ - `callback` (Function, optional): Callback function for filtering
281
+ - `recursive` (boolean, optional): Search recursively (default: true)
282
+
283
+ **Returns:** `Element | null`
284
+
285
+ #### `find_all(classFilters, callback, recursive)`
286
+
287
+ Find all matching elements.
288
+
289
+ **Parameters:**
290
+ - `classFilters` (Array, optional): Array of Element classes
291
+ - `callback` (Function, optional): Callback function for filtering
292
+ - `recursive` (boolean, optional): Search recursively (default: true)
293
+
294
+ **Returns:** `Array<Element>`
295
+
296
+ #### `find_iter(classFilters, callback, recursive)`
297
+
298
+ Iterator for finding elements.
299
+
300
+ **Parameters:**
301
+ - `classFilters` (Array, optional): Array of Element classes
302
+ - `callback` (Function, optional): Callback function for filtering
303
+ - `recursive` (boolean, optional): Search recursively (default: true)
304
+
305
+ **Returns:** `Generator<Element>`
306
+
307
+ #### `as_list()`
308
+
309
+ Get flight data as array.
310
+
311
+ **Returns:** `Array<Element>`
312
+
313
+ #### `static from_list(list, viaEnumerate)`
314
+
315
+ Create BeautifulFD from array.
316
+
317
+ **Parameters:**
318
+ - `list` (Array): Array of Elements
319
+ - `viaEnumerate` (boolean, optional): Use array indices as element indices
320
+
321
+ **Returns:** `BeautifulFD`
322
+
323
+ ### Element Types
324
+
325
+ All flight data elements extend the base `Element` class:
326
+
327
+ - `Element` - Base class
328
+ - `HintPreload` - Preload hints (class "HL")
329
+ - `Module` - Module imports (class "I")
330
+ - `Text` - Text content (class "T")
331
+ - `Data` - Structured data
332
+ - `EmptyData` - Null/empty data
333
+ - `SpecialData` - Special markers (strings starting with "$")
334
+ - `HTMLElement` - HTML elements
335
+ - `DataContainer` - Container of multiple elements
336
+ - `DataParent` - Parent element with children
337
+ - `URLQuery` - URL query parameters
338
+ - `RSCPayload` - React Server Components payload
339
+ - `Error` - Error elements (class "E")
340
+
341
+ You can access types via `parser.types`:
342
+
343
+ ```javascript
344
+ const parser = NJSParser({ DOMParser });
345
+ const fd = new parser.BeautifulFD(html);
346
+
347
+ const textElements = fd.find_all([parser.types.Text]);
348
+ const modules = fd.find_all([parser.types.Module]);
349
+ ```
350
+
351
+ ### API Utilities
352
+
353
+ #### `api.getApiPath(buildId, basePath, path)`
354
+
355
+ Generate API path for a page.
356
+
357
+ **Parameters:**
358
+ - `buildId` (string): Build ID
359
+ - `basePath` (string, optional): Base path
360
+ - `path` (string, optional): Page path
361
+
362
+ **Returns:** `string | null` - API path or null for excluded paths
363
+
364
+ #### `api.getIndexApiPath(buildId, basePath)`
365
+
366
+ Generate index API path.
367
+
368
+ **Parameters:**
369
+ - `buildId` (string): Build ID
370
+ - `basePath` (string, optional): Base path
371
+
372
+ **Returns:** `string`
373
+
374
+ #### `api.isApiExposedFromResponse(statusCode, contentType, text)`
375
+
376
+ Check if API is exposed from response.
377
+
378
+ **Parameters:**
379
+ - `statusCode` (number): HTTP status code
380
+ - `contentType` (string): Content-Type header
381
+ - `text` (string): Response text
382
+
383
+ **Returns:** `boolean`
384
+
385
+ #### `api.listApiPaths(sortedPages, buildId, basePath, isApiExposed)`
386
+
387
+ List API paths from build manifest.
388
+
389
+ **Parameters:**
390
+ - `sortedPages` (Array<string>): Sorted pages from build manifest
391
+ - `buildId` (string): Build ID
392
+ - `basePath` (string): Base path
393
+ - `isApiExposed` (boolean, optional): Is API exposed
394
+
395
+ **Returns:** `Array<string>`
396
+
397
+ ## Differences from Python Version
398
+
399
+ 1. **DOMParser Parameter**: The JavaScript version requires a DOMParser instance to be provided, making it compatible with different environments (Bun, browser, Node.js with jsdom, etc.)
400
+
401
+ 2. **No CLI**: This port focuses on the library functionality only. No CLI is included.
402
+
403
+ 3. **Factory Pattern**: Uses a factory function to inject dependencies rather than global imports.
404
+
405
+ 4. **Async/Await**: JavaScript version is designed to work with async/await for fetching HTML.
406
+
407
+ 5. **Native JSON**: Uses native `JSON.parse` and `JSON.stringify` instead of orjson.
408
+
409
+ 6. **Native eval**: Uses JavaScript `eval` for build manifest parsing instead of pythonmonkey.
410
+
411
+ ## Testing
412
+
413
+ Run tests with Bun:
414
+
415
+ ```bash
416
+ bun test
417
+ ```
418
+
419
+ ## License
420
+
421
+ MIT
66
422
 
67
- - `BeautifulFD(html)`
68
- - `get_flight_data(html)`
69
- - `get_next_data(html)`
70
- - `find_build_id(html)`
71
- - `has_nextjs(html)`
72
- - `get_next_static_urls(html)`
73
- - `get_base_path(html)`
423
+ ## Credits
74
424
 
75
- See source code for more details.
425
+ This is a JavaScript port of the Python [njsparser](https://github.com/novitae/njsparser) library by novitae.
package/api.js CHANGED
@@ -1,57 +1,83 @@
1
- import { join } from './utils.js';
1
+ /**
2
+ * API path generation utilities
3
+ */
2
4
 
3
- const _index_json = "index.json";
4
- const _excluded_paths = ["/404", "/_app", "/_error", "/sitemap.xml", "/_middleware"];
5
+ import { join } from './utils.js';
5
6
 
6
- export { join }; // Export join to match python API
7
+ const _index_json = 'index.json';
8
+ const _excluded_paths = ['/404', '/_app', '/_error', '/sitemap.xml', '/_middleware'];
7
9
 
8
- export const get_api_path = (build_id, { base_path = "", path = null } = {}) => {
9
- if (path === null) {
10
- path = _index_json;
11
- } else if (_excluded_paths.includes(path)) {
12
- return;
13
- }
14
-
15
- if (!path.endsWith(".json")) {
16
- path += ".json";
17
- }
18
- if (path.endsWith("/.json")) { // Python logic: if path ends with /.json -> index.json
19
- // Wait, Python: `if path.endswith("/.json"): path = _index_json`
20
- // Should it replace the filename or?
21
- // Python `_index_json` is just "index.json".
22
- // It seems it replaces the whole path? No, unlikely.
23
- // If path was "foo/.json", it becomes "index.json"?
24
- // Ah, default args?
25
- // Let's assume it replaces the last part.
26
- path = _index_json;
27
- }
28
-
29
- return join(base_path, "/_next/data/", build_id, path);
30
- };
10
+ /**
11
+ * Get API path for a page
12
+ * @param {string} buildId - Build ID
13
+ * @param {string} basePath - Base path (optional)
14
+ * @param {string} path - Page path (optional)
15
+ * @returns {string|null} API path or null
16
+ */
17
+ export function getApiPath(buildId, basePath = '', path = null) {
18
+ if (path === null) {
19
+ path = _index_json;
20
+ } else if (_excluded_paths.includes(path)) {
21
+ return null;
22
+ }
23
+
24
+ if (!path.endsWith('.json')) {
25
+ path += '.json';
26
+ }
27
+
28
+ if (path.endsWith('/.json')) {
29
+ path = _index_json;
30
+ }
31
+
32
+ return join(basePath, '/_next/data/', buildId, path);
33
+ }
31
34
 
32
- export const get_index_api_path = (build_id, { base_path = "" } = {}) => {
33
- return get_api_path(build_id, { base_path, path: _index_json });
34
- };
35
+ /**
36
+ * Get index API path
37
+ * @param {string} buildId - Build ID
38
+ * @param {string} basePath - Base path (optional)
39
+ * @returns {string} Index API path
40
+ */
41
+ export function getIndexApiPath(buildId, basePath = '') {
42
+ return getApiPath(buildId, basePath, _index_json);
43
+ }
35
44
 
36
- export const is_api_exposed_from_response = (status_code, content_type, text) => {
37
- if (status_code === 200) {
38
- return true;
39
- } else if (content_type && content_type.startsWith("application/json")) {
40
- return true;
41
- } else {
42
- return text === '{"notFound":true}';
43
- }
44
- };
45
+ /**
46
+ * Check if API is exposed from response
47
+ * @param {number} statusCode - HTTP status code
48
+ * @param {string} contentType - Content-Type header
49
+ * @param {string} text - Response text
50
+ * @returns {boolean} True if API is exposed
51
+ */
52
+ export function isApiExposedFromResponse(statusCode, contentType, text) {
53
+ if (statusCode === 200) {
54
+ return true;
55
+ } else if (contentType !== null && contentType.startsWith('application/json')) {
56
+ return true;
57
+ } else {
58
+ return text === '{"notFound":true}';
59
+ }
60
+ }
45
61
 
46
- export const list_api_paths = (sorted_pages, build_id, base_path, is_api_exposed = true) => {
47
- const result = [];
48
- if (is_api_exposed !== false) {
49
- for (const path of sorted_pages) {
50
- const api_path = get_api_path(build_id, { base_path, path });
51
- if (api_path) {
52
- result.push(api_path);
53
- }
54
- }
62
+ /**
63
+ * List API paths from build manifest
64
+ * @param {Array<string>} sortedPages - Sorted pages from build manifest
65
+ * @param {string} buildId - Build ID
66
+ * @param {string} basePath - Base path
67
+ * @param {boolean} isApiExposed - Is API exposed (optional)
68
+ * @returns {Array<string>} Array of API paths
69
+ */
70
+ export function listApiPaths(sortedPages, buildId, basePath, isApiExposed = true) {
71
+ const result = [];
72
+
73
+ if (isApiExposed !== false) {
74
+ for (const path of sortedPages) {
75
+ const apiPath = getApiPath(buildId, basePath, path);
76
+ if (apiPath !== null) {
77
+ result.push(apiPath);
78
+ }
55
79
  }
56
- return result;
57
- };
80
+ }
81
+
82
+ return result;
83
+ }
package/bun.lock CHANGED
@@ -4,65 +4,19 @@
4
4
  "workspaces": {
5
5
  "": {
6
6
  "name": "njsparser",
7
- "dependencies": {
8
- "cheerio": "^1.0.0",
9
- },
10
7
  "devDependencies": {
11
8
  "bun-types": "latest",
9
+ "deno-dom": "git+https://github.com/b-fuze/deno-dom.git",
12
10
  },
13
11
  },
14
12
  },
15
13
  "packages": {
16
14
  "@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="],
17
15
 
18
- "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
19
-
20
16
  "bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
21
17
 
22
- "cheerio": ["cheerio@1.2.0", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "encoding-sniffer": "^0.2.1", "htmlparser2": "^10.1.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", "undici": "^7.19.0", "whatwg-mimetype": "^4.0.0" } }, "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg=="],
23
-
24
- "cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="],
25
-
26
- "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="],
27
-
28
- "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="],
29
-
30
- "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="],
31
-
32
- "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="],
33
-
34
- "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="],
35
-
36
- "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
37
-
38
- "encoding-sniffer": ["encoding-sniffer@0.2.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="],
39
-
40
- "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
41
-
42
- "htmlparser2": ["htmlparser2@10.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="],
43
-
44
- "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
45
-
46
- "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="],
47
-
48
- "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
49
-
50
- "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@7.1.0", "", { "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" } }, "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g=="],
51
-
52
- "parse5-parser-stream": ["parse5-parser-stream@7.1.2", "", { "dependencies": { "parse5": "^7.0.0" } }, "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow=="],
53
-
54
- "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
55
-
56
- "undici": ["undici@7.22.0", "", {}, "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg=="],
18
+ "deno-dom": ["deno-dom@github:b-fuze/deno-dom#92ff960", {}, "b-fuze-deno-dom-92ff960"],
57
19
 
58
20
  "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
59
-
60
- "whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="],
61
-
62
- "whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="],
63
-
64
- "htmlparser2/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
65
-
66
- "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
67
21
  }
68
22
  }