metascraper-defuddle 5.50.7 → 5.51.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,6 +14,25 @@
14
14
  $ npm install metascraper-defuddle --save
15
15
  ```
16
16
 
17
+ ## Usage
18
+
19
+ ```js
20
+ const metascraper = require('metascraper')([require('metascraper-defuddle')()])
21
+ ```
22
+
23
+ It runs a single [Defuddle](https://github.com/kepano/defuddle) `parseInternal` pass — not the high-level `Defuddle()`, whose `parse()` re-runs on low `wordCount` to recover _content_. This connector extracts metadata, which is read from meta tags/schema regardless of content removals, so those retries add nothing here.
24
+
25
+ The Defuddle result is memoized by HTML, so the same page is defuddled once even when several rules (or another consumer, such as a markdown renderer) request it; the same URL re-fetched with different HTML still re-extracts.
26
+
27
+ ### Options
28
+
29
+ ```js
30
+ require('metascraper-defuddle')({ preprocess, defuddleOpts })
31
+ ```
32
+
33
+ - **preprocess** `(document, html) => void` — mutate the parsed DOM before extraction (e.g. strip noise, normalize flattened shadow-DOM content).
34
+ - **defuddleOpts** `object` — options forwarded to Defuddle's `parseInternal` (e.g. `{ removeLowScoring: false }` to keep link-heavy blocks).
35
+
17
36
  ## License
18
37
 
19
38
  **metascraper-defuddle** © [Microlink](https://microlink.io), released under the [MIT](https://github.com/microlinkhq/metascraper/blob/master/LICENSE.md) License.<br>
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "metascraper-defuddle",
3
3
  "description": "A Defuddle connector for metascraper",
4
4
  "homepage": "https://github.com/microlinkhq/metascraper/packages/metascraper-defuddle",
5
- "version": "5.50.7",
5
+ "version": "5.51.1",
6
6
  "types": "src/index.d.ts",
7
7
  "main": "src/index.js",
8
8
  "author": {
@@ -23,14 +23,14 @@
23
23
  "metascraper"
24
24
  ],
25
25
  "dependencies": {
26
- "@metascraper/helpers": "5.50.6",
26
+ "@metascraper/helpers": "5.51.1",
27
27
  "async-memoize-one": "~1.2.1",
28
28
  "debug-logfmt": "~1.4.12",
29
- "defuddle": "~0.18.1",
29
+ "defuddle": "~0.19.0",
30
30
  "linkedom": "~0.18.12"
31
31
  },
32
32
  "devDependencies": {
33
- "ava": "5"
33
+ "ava": "8"
34
34
  },
35
35
  "engines": {
36
36
  "node": ">= 22"
@@ -45,5 +45,5 @@
45
45
  "ava": {
46
46
  "timeout": "15s"
47
47
  },
48
- "gitHead": "ff358c29107b437528930e31d76bb9d29fead3e2"
48
+ "gitHead": "6059223e2c30ca9a4d5067dd265609a8ad74f47e"
49
49
  }
package/src/index.d.ts CHANGED
@@ -1,2 +1,7 @@
1
- declare function rules(): import('metascraper').Rules
1
+ type Options = {
2
+ preprocess?: (document: Document, html: string) => void,
3
+ defuddleOpts?: import('defuddle/node').DefuddleOptions
4
+ }
5
+
6
+ declare function rules(options?: Options): import('metascraper').Rules
2
7
  export = rules
package/src/index.js CHANGED
@@ -1,24 +1,46 @@
1
1
  'use strict'
2
2
 
3
- const { memoizeOne, composeRule, getHtml } = require('@metascraper/helpers')
3
+ const { composeRule, getHtml } = require('@metascraper/helpers')
4
+ const debug = require('debug-logfmt')('metascraper-defuddle')
4
5
  const asyncMemoizeOne = require('async-memoize-one')
5
6
  const { parseHTML } = require('linkedom')
6
7
 
7
- const debug = require('debug-logfmt')('metascraper-defuddle')
8
-
9
- const defuddleExtract = asyncMemoizeOne(async (url, html) => {
10
- const { Defuddle } = await import('defuddle/node')
11
- try {
12
- const { document } = parseHTML(html)
13
- return await Defuddle(document, url, { useAsync: false })
14
- } catch (err) {
15
- debug('Defuddle failed, fallback to next rule', { message: err.message })
16
- return undefined
17
- }
18
- }, memoizeOne.EqualityFirstArgument)
19
-
20
- module.exports = () => {
21
- const getDefuddle = composeRule(($, url) => defuddleExtract(url, getHtml($)))
8
+ // Cache key = HTML + url + the identity of `preprocess`/`defuddleOpts`, so a
9
+ // call with the same HTML but a different hook or options (e.g. another
10
+ // metascraper-defuddle() instance or defuddleExtract consumer) re-extracts
11
+ // instead of reusing a result produced with different ones.
12
+ const isSameExtraction = (
13
+ [html, url, opts = {}],
14
+ [oldHtml, oldUrl, oldOpts = {}]
15
+ ) =>
16
+ html === oldHtml &&
17
+ url === oldUrl &&
18
+ opts.preprocess === oldOpts.preprocess &&
19
+ opts.defuddleOpts === oldOpts.defuddleOpts
20
+
21
+ // Single Defuddle `parseInternal` pass, memoized. See README for the
22
+ // `preprocess` / `defuddleOpts` options and the rationale.
23
+ const extractMemo = asyncMemoizeOne(
24
+ async (html, url, { preprocess, defuddleOpts } = {}) => {
25
+ const { DefuddleClass } = await import('defuddle/node')
26
+ try {
27
+ const { document } = parseHTML(html)
28
+ if (preprocess) preprocess(document, html)
29
+ return new DefuddleClass(document, { url }).parseInternal(defuddleOpts)
30
+ } catch (err) {
31
+ debug('Defuddle failed, fallback to next rule', { message: err.message })
32
+ return undefined
33
+ }
34
+ },
35
+ isSameExtraction
36
+ )
37
+
38
+ const defuddleExtract = (url, html, options) => extractMemo(html, url, options)
39
+
40
+ module.exports = ({ preprocess, defuddleOpts } = {}) => {
41
+ const getDefuddle = composeRule(($, url) =>
42
+ defuddleExtract(url, getHtml($), { preprocess, defuddleOpts })
43
+ )
22
44
 
23
45
  const rules = {
24
46
  author: getDefuddle({ from: 'author' }),