page-markdown 0.2.0 → 0.3.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/ADDITIONAL_TERMS.md +122 -122
- package/CHANGELOG.md +80 -0
- package/LICENSE +694 -694
- package/README.md +55 -10
- package/THIRD_PARTY_NOTICES.md +264 -264
- package/dist/types/concealed.d.ts +59 -0
- package/dist/types/extract.d.ts +1 -0
- package/dist/types/index.d.ts +8 -3
- package/dist/types/sanitize.d.ts +18 -1
- package/dist/types/standardize.d.ts +14 -1
- package/dist/types/types.d.ts +37 -1
- package/package.json +69 -68
- package/robots.txt +79 -79
- package/src/clean.js +1 -1
- package/src/concealed.js +418 -0
- package/src/convert.js +34 -15
- package/src/extract.js +37 -2
- package/src/index.js +23 -4
- package/src/sanitize.js +93 -65
- package/src/standardize.js +62 -5
- package/src/types.js +18 -1
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ import { pageToMarkdown } from "page-markdown";
|
|
|
44
44
|
const result = pageToMarkdown(document);
|
|
45
45
|
result.markdown; // "# Title\n\n…"
|
|
46
46
|
result.metadata; // { url, canonicalUrl, title, author, published, siteName, lang, … }
|
|
47
|
-
result.extraction.method; // "readability" | "full_page"
|
|
47
|
+
result.extraction.method; // "readability" | "main_content" | "full_page" | custom method
|
|
48
48
|
|
|
49
49
|
// In Node, with any DOM implementation (linkedom shown)
|
|
50
50
|
import { parseHTML } from "linkedom";
|
|
@@ -57,11 +57,11 @@ pageToMarkdown(doc, { url: "https://example.com/article" });
|
|
|
57
57
|
| Option | Default | Meaning |
|
|
58
58
|
|---|---|---|
|
|
59
59
|
| `url` | the document's URL | Base for absolute links and images |
|
|
60
|
-
| `extract` | `"readable"` | `"readable"` (Readability
|
|
61
|
-
| `minExtractChars` | `100` | Below this,
|
|
60
|
+
| `extract` | `"readable"` | `"readable"` (Readability with main-content or full-page fallback), `"full"`, or a function `(docCopy) => { html, method }` |
|
|
61
|
+
| `minExtractChars` | `100` | Below this, Readability falls back to a sufficiently long `<main>` or `[role="main"]`, else the full page; custom extractors fall back to the full page |
|
|
62
62
|
| `minExtractShare` | `0.4` | When Readability keeps less than this share of the page's main content (and misses at least 500 characters), the main content is used instead: forum threads and product grids. `0` turns it off |
|
|
63
63
|
| `includeFullPage` | `false` | Also return `fullPageMarkdown` |
|
|
64
|
-
| `includeTitle` | `true` |
|
|
64
|
+
| `includeTitle` | `true` | Add `# <headline>` to Readability or main-content output when no H1 remains; skipped in `text_only` mode |
|
|
65
65
|
| `recoverLead` | `true` | Restore a lead paragraph the extractor dropped, when it matches the meta description |
|
|
66
66
|
| `pageFacts` | `false` | Append `## Page facts`: short label/value pairs outside the article (a sidebar's version or license, spec rows, infobox rows) that the extractor dropped. `extraction.pageFacts` counts them |
|
|
67
67
|
| `removeHiddenText` | `false` | Remove text hidden from people but read by models: runs of tag characters, variation selectors, invisible operators and reserved tag-plane code points, found by [text-sanctifier](https://github.com/iWhatty/text-sanctifier)'s `findHiddenRuns`. Applies to `markdown` (fenced code included), `fullPageMarkdown` and `metadata`. The England, Scotland and Wales flags and a lone emoji or text presentation selector are kept. `omissions` gets one entry per kind (`hidden_tag`, `hidden_variation_selector`, `hidden_invisible_operator`, `hidden_reserved_tag_plane`) with `count` runs and `chars` code points removed from `markdown` |
|
|
@@ -88,17 +88,64 @@ The stages are also exported for advanced use: `sanitizeToInertDocument`,
|
|
|
88
88
|
| `metadata.headline` | `string?` | The heading chosen for the capture |
|
|
89
89
|
| `metadata.extractedTitle`, `byline` | `string?` | What the extractor reported |
|
|
90
90
|
| `extraction.method` | `string` | `"readability"`, `"main_content"`, `"full_page"`, or the name a custom extractor gave |
|
|
91
|
-
| `extraction.fallbackReason` | `string?` | Why extraction fell back: `extracted_small_share_of_page`, `extracted_site_menu` or `extracted_few_sections_of_page`
|
|
91
|
+
| `extraction.fallbackReason` | `string?` | Why extraction fell back: `extracted_small_share_of_page`, `extracted_site_menu` or `extracted_few_sections_of_page` use the main content; `extractor_found_nothing`, `extracted_text_below_minimum` or `extractor_error: ...` use a sufficiently long main-content region for Readability, else the full page. Custom extractors fall back to the full page |
|
|
92
92
|
| `extraction.leadRecovered` | `true?` | A dropped lead paragraph was restored |
|
|
93
93
|
| `extraction.pageFacts` | `number?` | How many facts `pageFacts` appended |
|
|
94
94
|
| `omissions[]` | `{ kind, count, note, chars? }` | What was left out or removed. `kind` is `shadow_content`, `json_line`, `inactive_tabs`, `comments` or a `hidden_*` kind; only `hidden_*` entries have `chars`. All but `hidden_*` also add a closing line to `markdown`, as a fallback does, so a caller that passes on only the Markdown still says so |
|
|
95
95
|
| `warnings[]` | `string` | Read these before trusting a capture: a fallback, or shadow content cut off at the capture limit, in which case the main content may be missing |
|
|
96
96
|
| `stats.mode` | `string` | The output mode used |
|
|
97
97
|
| `stats.extractedHtmlChars`, `convertedChars`, `markdownChars` | `number` | Sizes at each step. `markdownChars` is the returned Markdown's length |
|
|
98
|
-
| `stats.
|
|
98
|
+
| `stats.pageTextChars` | `number` | Whitespace-normalized text length of the standardized page at capture time |
|
|
99
|
+
| `stats.standardization` | `object` | Counts of what standardizing changed: `lazyImagesResolved`, `inlineImagesDropped`, `scriptLinksUnwrapped`, `invalidLinksUnwrapped`, `emptyLinksRemoved`, `preWrapped`, `headingWidgetsRemoved`, `headingsUnwrapped`; `omittedTabs` lists labels of inactive panels left out |
|
|
99
100
|
|
|
100
101
|
A `?` marks a field that is absent, not empty, when it doesn't apply.
|
|
101
102
|
|
|
103
|
+
### Concealed text (opt-in)
|
|
104
|
+
|
|
105
|
+
Detection is off by default. Enable it for a live document:
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
const result = pageToMarkdown(document, {
|
|
109
|
+
detectConcealedText: true,
|
|
110
|
+
includeFullPage: true,
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Supported computed styles separate concealed DOM text from the article and
|
|
115
|
+
return it in `concealedText` as `{ reason, chars, text }` blocks. Text is capped
|
|
116
|
+
at 2,048 UTF-16 units per block, 16,384 total and 100 entries;
|
|
117
|
+
`concealedTextTruncated` reports capping. Omission counts and character totals
|
|
118
|
+
are uncapped. A `Concealed text omitted:` notice appears in both `markdown`
|
|
119
|
+
and `fullPageMarkdown` when text is captured.
|
|
120
|
+
|
|
121
|
+
The seven reasons are `display_none`, `visibility_hidden`, `opacity_zero`,
|
|
122
|
+
`font_size_zero`, `clipped`, `transparent_text` and `same_color`. Supported
|
|
123
|
+
clips are zero-area legacy rectangles on absolute/fixed elements,
|
|
124
|
+
`inset(50%)` and zero-radius circles. Colour checks compare computed sRGB
|
|
125
|
+
rgb()/rgba() values for an element's own text against its own or nearest
|
|
126
|
+
declared opaque background.
|
|
127
|
+
|
|
128
|
+
`concealmentCheck` is `disabled` by default (no computed-style calls),
|
|
129
|
+
`static-only` when enabled without a computed-style API, `computed` after a
|
|
130
|
+
successful check, or `incomplete` if the capability probe or a consulted
|
|
131
|
+
property fails. Detection applies to live documents only; enabled static
|
|
132
|
+
input retains its previous output. A top-level `detectConcealedText` option
|
|
133
|
+
takes precedence over `sanitize.detectConcealedText`, then the default false.
|
|
134
|
+
|
|
135
|
+
Limits include white text with no declared opaque background, non-zero alpha,
|
|
136
|
+
near-colour matches, and unparsed OKLCH and Display P3 colours. Intervening
|
|
137
|
+
images or translucent backgrounds and uncertain text painting effects prevent
|
|
138
|
+
colour equality detection. Existing short inactive tab, collapsed answer and
|
|
139
|
+
code wrapper exceptions remain; independent concealment reasons still apply.
|
|
140
|
+
Off-screen or covered text, attributes, metadata and custom-extractor output
|
|
141
|
+
are outside this check.
|
|
142
|
+
|
|
143
|
+
The scroll-reveal rule is **provisional**: zero-opacity content with an
|
|
144
|
+
opacity-applicable transition or named animation of nonzero duration stays
|
|
145
|
+
in place with a warning. A declaration does not prove it will appear, and a
|
|
146
|
+
page can use one to evade detection. Real-site validation is still required.
|
|
147
|
+
Chrome is the only browser tested; Firefox and Safari are untested.
|
|
148
|
+
|
|
102
149
|
### TypeScript
|
|
103
150
|
|
|
104
151
|
Types ship with the package, generated from the JSDoc in `src`: `pageToMarkdown`,
|
|
@@ -127,7 +174,7 @@ const { markdown: safe, omissions } = pageToMarkdown(document, { removeHiddenTex
|
|
|
127
174
|
## Quality
|
|
128
175
|
|
|
129
176
|
`npm test` runs the contract suite. It covers:
|
|
130
|
-
- golden outputs for
|
|
177
|
+
- golden outputs for 51 fixtures;
|
|
131
178
|
- regressions for known converter bugs, including dropped lead paragraphs,
|
|
132
179
|
raw HTML tables, flattened code in tables, site-suffixed titles and
|
|
133
180
|
unescaped table pipes;
|
|
@@ -179,7 +226,7 @@ its products. What it still fails on these pages:
|
|
|
179
226
|
|
|
180
227
|
- **Promo boxes kept** inside a BBC Arabic article.
|
|
181
228
|
|
|
182
|
-
Browser bundle: about
|
|
229
|
+
Browser bundle: about 86.0 KB minified, 31.2 KB gzip (`npm run size`, ceiling 86 KB
|
|
183
230
|
minified). Readability is most of it.
|
|
184
231
|
|
|
185
232
|
`npm run ci` runs the contract suite, the type check and the size check, and must
|
|
@@ -202,8 +249,6 @@ deliberately has no cloud CI.
|
|
|
202
249
|
kept by the main-content fallback only; Readability removes hidden text.
|
|
203
250
|
- **Bylines and dates can be missing from the Markdown.** Readability often leaves
|
|
204
251
|
them out of the article. Look in `metadata.author` and `metadata.published`.
|
|
205
|
-
- **Note labels can be lost.** On Docker's docs, "Warning", "Note" and "Tip" are
|
|
206
|
-
dropped, though the blockquotes stay.
|
|
207
252
|
- **Some legacy markup loses paragraph breaks.** Readability can drop runs of
|
|
208
253
|
`<br>` between inline elements in old HTML. The text survives; a paragraph
|
|
209
254
|
break may not.
|