webforai 1.5.1 → 1.6.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/dist/bin.js +277 -334
- package/dist/cjs/cli/bin.js +3 -4
- package/dist/cjs/cli/commands/{handlers → webforai}/index.js +33 -31
- package/dist/cjs/cli/commands/webforai/loadHtml.js +93 -0
- package/dist/cjs/cli/utils.js +18 -51
- package/dist/cjs/extract-hast/index.js +4 -3
- package/dist/cjs/extract-hast/readability.js +28 -61
- package/dist/cjs/extract-hast/strongly.js +2 -1
- package/dist/cjs/extract-hast/utils.js +0 -15
- package/dist/cjs/html-to-mdast.js +6 -6
- package/dist/cjs/link-replacer.js +10 -5
- package/dist/cjs/loaders/playwright.js +36 -7
- package/dist/cjs/mdast-handlers/custom-br-handler.js +31 -0
- package/dist/cjs/mdast-to-markdown.js +1 -1
- package/dist/cjs/utils/hast-utils.js +71 -0
- package/dist/cli/bin.js +3 -4
- package/dist/cli/commands/webforai/index.js +53 -0
- package/dist/cli/commands/webforai/loadHtml.js +60 -0
- package/dist/cli/utils.js +18 -51
- package/dist/extract-hast/index.js +4 -3
- package/dist/extract-hast/readability.js +29 -62
- package/dist/extract-hast/strongly.js +2 -1
- package/dist/extract-hast/utils.js +0 -14
- package/dist/html-to-mdast.js +6 -6
- package/dist/link-replacer.js +10 -5
- package/dist/loaders/playwright.js +36 -7
- package/dist/mdast-handlers/custom-br-handler.js +8 -0
- package/dist/mdast-to-markdown.js +1 -1
- package/dist/types/cli/bin.js.map +1 -1
- package/dist/types/cli/commands/webforai/index.d.ts +6 -0
- package/dist/types/cli/commands/webforai/index.js.map +1 -0
- package/dist/types/cli/commands/webforai/loadHtml.d.ts +3 -0
- package/dist/types/cli/commands/webforai/loadHtml.js.map +1 -0
- package/dist/types/cli/utils.d.ts +27 -0
- package/dist/types/cli/utils.js.map +1 -1
- package/dist/types/extract-hast/index.d.ts +9 -4
- package/dist/types/extract-hast/index.js.map +1 -1
- package/dist/types/extract-hast/readability.d.ts +2 -1
- package/dist/types/extract-hast/readability.js.map +1 -1
- package/dist/types/extract-hast/strongly.d.ts +2 -1
- package/dist/types/extract-hast/strongly.js.map +1 -1
- package/dist/types/extract-hast/utils.d.ts +0 -1
- package/dist/types/extract-hast/utils.js.map +1 -1
- package/dist/types/html-to-mdast.d.ts +4 -0
- package/dist/types/html-to-mdast.js.map +1 -1
- package/dist/types/link-replacer.d.ts +1 -1
- package/dist/types/link-replacer.js.map +1 -1
- package/dist/types/loaders/playwright.d.ts +8 -2
- package/dist/types/loaders/playwright.js.map +1 -1
- package/dist/types/mdast-handlers/custom-br-handler.d.ts +2 -0
- package/dist/types/mdast-handlers/custom-br-handler.js.map +1 -0
- package/dist/types/mdast-to-markdown.js.map +1 -1
- package/dist/types/utils/hast-utils.d.ts +4 -0
- package/dist/types/utils/hast-utils.js.map +1 -0
- package/dist/utils/hast-utils.js +46 -0
- package/package.json +21 -10
- package/dist/cjs/cli/commands/handlers/loadHtml.js +0 -127
- package/dist/cjs/html-to-markdown.test.js +0 -118
- package/dist/cjs/link-replacer.test.js +0 -47
- package/dist/cjs/loaders/fetch.test.js +0 -9
- package/dist/cjs/loaders/playwright.test.js +0 -17
- package/dist/cjs/loaders/puppeteer.test.js +0 -17
- package/dist/cli/commands/handlers/index.js +0 -51
- package/dist/cli/commands/handlers/loadHtml.js +0 -94
- package/dist/html-to-markdown.test.js +0 -118
- package/dist/link-replacer.test.js +0 -47
- package/dist/loaders/fetch.test.js +0 -9
- package/dist/loaders/playwright.test.js +0 -17
- package/dist/loaders/puppeteer.test.js +0 -17
- package/dist/types/cli/commands/handlers/index.d.ts +0 -13
- package/dist/types/cli/commands/handlers/index.js.map +0 -1
- package/dist/types/cli/commands/handlers/loadHtml.d.ts +0 -2
- package/dist/types/cli/commands/handlers/loadHtml.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -1,64 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
-
var __esm = (fn, res) => function __init() {
|
|
4
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
-
};
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
// src/loaders/fetch.ts
|
|
12
|
-
var fetch_exports = {};
|
|
13
|
-
__export(fetch_exports, {
|
|
14
|
-
USER_AGENT: () => USER_AGENT,
|
|
15
|
-
loadHtml: () => loadHtml
|
|
16
|
-
});
|
|
17
|
-
var USER_AGENT, loadHtml;
|
|
18
|
-
var init_fetch = __esm({
|
|
19
|
-
"src/loaders/fetch.ts"() {
|
|
20
|
-
"use strict";
|
|
21
|
-
USER_AGENT = "mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/125.0.0.0 safari/537.36";
|
|
22
|
-
loadHtml = async (url, userAgent = USER_AGENT) => {
|
|
23
|
-
const response = await fetch(url, { headers: { "User-Agent": userAgent } });
|
|
24
|
-
return response.text();
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// src/loaders/playwright.ts
|
|
30
|
-
var playwright_exports = {};
|
|
31
|
-
__export(playwright_exports, {
|
|
32
|
-
loadHtml: () => loadHtml2
|
|
33
|
-
});
|
|
34
|
-
import { chromium } from "playwright";
|
|
35
|
-
var loadHtml2;
|
|
36
|
-
var init_playwright = __esm({
|
|
37
|
-
"src/loaders/playwright.ts"() {
|
|
38
|
-
"use strict";
|
|
39
|
-
loadHtml2 = async (url, context) => {
|
|
40
|
-
const _context = context ?? await chromium.launch({ headless: true });
|
|
41
|
-
const page = await _context.newPage();
|
|
42
|
-
await page.goto(url, { waitUntil: "load" });
|
|
43
|
-
const html = await page.content();
|
|
44
|
-
await page.close();
|
|
45
|
-
if (!context) {
|
|
46
|
-
await _context.close();
|
|
47
|
-
}
|
|
48
|
-
return html;
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
52
2
|
|
|
53
3
|
// src/cli/bin.ts
|
|
54
|
-
import { intro } from "@clack/prompts";
|
|
4
|
+
import { intro as intro2 } from "@clack/prompts";
|
|
55
5
|
import { program } from "commander";
|
|
56
|
-
import
|
|
6
|
+
import pc3 from "picocolors";
|
|
57
7
|
|
|
58
8
|
// package.json
|
|
59
9
|
var package_default = {
|
|
60
10
|
name: "webforai",
|
|
61
|
-
version: "1.
|
|
11
|
+
version: "1.6.0",
|
|
62
12
|
description: "A library that provides a web interface for AI",
|
|
63
13
|
author: "inaridiy",
|
|
64
14
|
license: "MIT",
|
|
@@ -146,20 +96,30 @@ var package_default = {
|
|
|
146
96
|
},
|
|
147
97
|
peerDependencies: {
|
|
148
98
|
"@cloudflare/puppeteer": ">=0.0.6",
|
|
149
|
-
playwright: ">=1.4",
|
|
99
|
+
"playwright-core": ">=1.4",
|
|
150
100
|
puppeteer: ">=22"
|
|
151
101
|
},
|
|
102
|
+
peerDependenciesMeta: {
|
|
103
|
+
"@cloudflare/puppeteer": {
|
|
104
|
+
optional: true
|
|
105
|
+
},
|
|
106
|
+
"playwright-core": {
|
|
107
|
+
optional: false
|
|
108
|
+
},
|
|
109
|
+
puppeteer: {
|
|
110
|
+
optional: true
|
|
111
|
+
}
|
|
112
|
+
},
|
|
152
113
|
dependencies: {
|
|
153
114
|
"@clack/prompts": "^0.7.0",
|
|
154
115
|
commander: "^12.1.0",
|
|
155
|
-
"
|
|
156
|
-
"hast-util-
|
|
157
|
-
"hast-util-
|
|
158
|
-
"hast-util-to-html": "^9.0.0",
|
|
116
|
+
"hast-util-from-html": "^2.0.3",
|
|
117
|
+
"hast-util-select": "^6.0.2",
|
|
118
|
+
"hast-util-to-html": "^9.0.3",
|
|
159
119
|
"hast-util-to-mdast": "^10.1.0",
|
|
160
120
|
"hast-util-to-string": "^3.0.0",
|
|
161
121
|
"hast-util-to-text": "^4.0.0",
|
|
162
|
-
"mathml-to-latex": "^1.
|
|
122
|
+
"mathml-to-latex": "^1.4.1",
|
|
163
123
|
"mdast-util-gfm": "^3.0.0",
|
|
164
124
|
"mdast-util-math": "^3.0.0",
|
|
165
125
|
"mdast-util-to-markdown": "^2.1.0",
|
|
@@ -171,26 +131,28 @@ var package_default = {
|
|
|
171
131
|
devDependencies: {
|
|
172
132
|
"@cloudflare/puppeteer": "^0.0.6",
|
|
173
133
|
"@tsconfig/recommended": "^1.0.3",
|
|
134
|
+
"fastest-levenshtein": "^1.0.16",
|
|
174
135
|
"@types/hast": "^3.0.2",
|
|
175
136
|
"@types/mdast": "^4.0.2",
|
|
176
|
-
"@types/node": "^20.
|
|
137
|
+
"@types/node": "^20.14.10",
|
|
177
138
|
arg: "^5.0.2",
|
|
178
139
|
esbuild: "^0.19.11",
|
|
179
140
|
glob: "^10.3.10",
|
|
180
141
|
ncp: "^2.0.0",
|
|
181
142
|
np: "^9.2.0",
|
|
182
|
-
playwright: "^1.40.1",
|
|
143
|
+
"playwright-core": "^1.40.1",
|
|
183
144
|
puppeteer: "^23.2.2",
|
|
184
145
|
rimraf: "^5.0.5",
|
|
185
|
-
tsx: "^4.
|
|
146
|
+
tsx: "^4.19.1",
|
|
186
147
|
typescript: "^5.4.5"
|
|
187
148
|
}
|
|
188
149
|
};
|
|
189
150
|
|
|
190
|
-
// src/cli/commands/
|
|
191
|
-
import fs5 from "node:fs";
|
|
151
|
+
// src/cli/commands/webforai/index.ts
|
|
152
|
+
import fs5 from "node:fs/promises";
|
|
192
153
|
import path2 from "node:path";
|
|
193
|
-
import { outro } from "@clack/prompts";
|
|
154
|
+
import { intro, outro, spinner } from "@clack/prompts";
|
|
155
|
+
import pc2 from "picocolors";
|
|
194
156
|
|
|
195
157
|
// src/html-to-mdast.ts
|
|
196
158
|
import { fromHtml } from "hast-util-from-html";
|
|
@@ -215,19 +177,6 @@ var isStrInclude = (value, match) => {
|
|
|
215
177
|
}
|
|
216
178
|
return false;
|
|
217
179
|
};
|
|
218
|
-
var hasAncestors = (element, tagNames, depth = 3) => {
|
|
219
|
-
let parent = element.parent;
|
|
220
|
-
for (let i = 0; i < depth; i++) {
|
|
221
|
-
if (!parent || parent.type !== "element") {
|
|
222
|
-
return false;
|
|
223
|
-
}
|
|
224
|
-
if (tagNames.includes(parent.tagName)) {
|
|
225
|
-
return true;
|
|
226
|
-
}
|
|
227
|
-
parent = parent.parent;
|
|
228
|
-
}
|
|
229
|
-
return false;
|
|
230
|
-
};
|
|
231
180
|
|
|
232
181
|
// src/extract-hast/readability.ts
|
|
233
182
|
var UNLIKELY_ROLES = ["menu", "menubar", "complementary", "navigation", "alert", "alertdialog", "dialog"];
|
|
@@ -235,35 +184,24 @@ var REGEXPS = {
|
|
|
235
184
|
hidden: /hidden|invisible|fallback-image/i,
|
|
236
185
|
byline: /byline|author|dateline|writtenby|p-author/i,
|
|
237
186
|
specialUnlikelyCandidates: /frb-|uls-menu|language-link/i,
|
|
238
|
-
unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote|speechify-ignore/i,
|
|
187
|
+
unlikelyCandidates: /-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|tooltip|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote|speechify-ignore|avatar/i,
|
|
239
188
|
okMaybeItsaCandidate: /and|article|body|column|content|main|shadow|code/i
|
|
240
189
|
};
|
|
241
|
-
var BODY_SELECTORS = ["article", "#article", ".article_body", ".article-body", "#content", ".entry"
|
|
242
|
-
var PARAGRAPH_TAGS = ["p", "div", "section", "article", "main", "ul", "ol", "li"];
|
|
190
|
+
var BODY_SELECTORS = ["article", "#article", ".article_body", ".article-body", "#content", ".entry"];
|
|
191
|
+
var PARAGRAPH_TAGS = ["a", "p", "div", "section", "article", "main", "ul", "ol", "li"];
|
|
243
192
|
var BASE_MINIMAL_LENGTH = {
|
|
244
193
|
ja: 200,
|
|
245
194
|
en: 500
|
|
246
195
|
};
|
|
247
|
-
var
|
|
248
|
-
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
const element = node;
|
|
252
|
-
if (element.tagName !== "html") {
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
const langAttr = element.properties.lang || element.properties["xml:lang"];
|
|
256
|
-
if (langAttr) {
|
|
257
|
-
return langAttr;
|
|
258
|
-
}
|
|
196
|
+
var metadataFilter = (node) => {
|
|
197
|
+
return !(["comment", "doctype"].includes(node.type) || node.type === "element" && ["script", "style", "link", "meta", "noscript", "svg", "title"].includes(node.tagName));
|
|
259
198
|
};
|
|
260
|
-
var metadataFilter = (node) => !["comment", "doctype"].includes(node.type);
|
|
261
199
|
var universalElementFilter = (node) => {
|
|
262
200
|
if (node.type !== "element") {
|
|
263
201
|
return true;
|
|
264
202
|
}
|
|
265
203
|
const element = node;
|
|
266
|
-
if (["
|
|
204
|
+
if (["aside", "nav"].includes(element.tagName)) {
|
|
267
205
|
return false;
|
|
268
206
|
}
|
|
269
207
|
if (["hidden", "aria-hidden"].some((key) => element.properties[key])) {
|
|
@@ -294,10 +232,7 @@ var unlikelyElementFilter = (node) => {
|
|
|
294
232
|
return true;
|
|
295
233
|
}
|
|
296
234
|
const element = node;
|
|
297
|
-
if (["body", "article", "main", "section", "
|
|
298
|
-
return true;
|
|
299
|
-
}
|
|
300
|
-
if (hasAncestors(element, ["table", "code"], 3)) {
|
|
235
|
+
if (["body", "article", "main", "section", "h1", "h2", "h3", "h4", "h5", "h6", "p"].includes(element.tagName)) {
|
|
301
236
|
return true;
|
|
302
237
|
}
|
|
303
238
|
const match = matchString(element);
|
|
@@ -309,55 +244,36 @@ var unlikelyElementFilter = (node) => {
|
|
|
309
244
|
}
|
|
310
245
|
return true;
|
|
311
246
|
};
|
|
312
|
-
var
|
|
313
|
-
const a = select("a", element);
|
|
314
|
-
const img = select("img", a);
|
|
315
|
-
if (!(a && img)) {
|
|
316
|
-
return false;
|
|
317
|
-
}
|
|
318
|
-
const imgFilename = img.properties.src?.toString().split("/").pop();
|
|
319
|
-
const hrefFilename = a.properties.href?.toString().split("/").pop();
|
|
320
|
-
return imgFilename === hrefFilename && imgFilename;
|
|
321
|
-
};
|
|
322
|
-
var removeEmptyFilter = (node) => {
|
|
247
|
+
var removeEmptyFilter = (node, _lang) => {
|
|
323
248
|
if (node.type !== "element") {
|
|
324
249
|
return true;
|
|
325
250
|
}
|
|
326
251
|
const element = node;
|
|
327
|
-
if (
|
|
252
|
+
if (PARAGRAPH_TAGS.includes(element.tagName)) {
|
|
328
253
|
return true;
|
|
329
254
|
}
|
|
330
|
-
if (
|
|
331
|
-
return true;
|
|
332
|
-
}
|
|
333
|
-
const text3 = hastToString(element);
|
|
334
|
-
if (text3.length < 10) {
|
|
255
|
+
if (element.tagName === "img" && !element.properties.src) {
|
|
335
256
|
return false;
|
|
336
257
|
}
|
|
337
258
|
return true;
|
|
338
259
|
};
|
|
339
|
-
var readabilityExtractHast = (
|
|
340
|
-
const lang =
|
|
260
|
+
var readabilityExtractHast = (params) => {
|
|
261
|
+
const { hast, lang = "en" } = params;
|
|
341
262
|
const body = select("body", hast) ?? hast;
|
|
342
|
-
const
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
return true;
|
|
351
|
-
});
|
|
352
|
-
if (!baseFilterd) {
|
|
353
|
-
return { type: "root", children: [] };
|
|
354
|
-
}
|
|
355
|
-
const baseFilterdText = hastToString(baseFilterd);
|
|
356
|
-
let [baseTree, baseText] = baseFilterdText.length > bodyText.length / 3 || baseFilterdText.length > 5e3 ? [baseFilterd, baseFilterdText] : [body, bodyText];
|
|
263
|
+
const metadataFilteredHast = filter(body, (node) => metadataFilter(node));
|
|
264
|
+
const metadataFilteredHastText = metadataFilteredHast && hastToString(metadataFilteredHast);
|
|
265
|
+
if (!(metadataFilteredHast && metadataFilteredHastText)) {
|
|
266
|
+
return body;
|
|
267
|
+
}
|
|
268
|
+
const baseFilterd = filter(metadataFilteredHast, (node) => universalElementFilter(node));
|
|
269
|
+
const baseFilterdText = baseFilterd ? hastToString(baseFilterd) : "";
|
|
270
|
+
const [baseTree, baseText] = baseFilterdText.length > metadataFilteredHastText.length / 3 || baseFilterdText.length > 5e3 ? [baseFilterd, baseFilterdText] : [metadataFilteredHast, metadataFilteredHastText];
|
|
357
271
|
let minimalLength = lang in BASE_MINIMAL_LENGTH ? BASE_MINIMAL_LENGTH[lang] : 500;
|
|
358
272
|
if (baseText.length < minimalLength) {
|
|
359
273
|
minimalLength = Math.max(0, baseText.length - 200);
|
|
360
274
|
}
|
|
275
|
+
let extractedTree = baseTree;
|
|
276
|
+
let extractedText = baseText;
|
|
361
277
|
for (const selector of BODY_SELECTORS) {
|
|
362
278
|
const content = { type: "root", children: selectAll(selector, baseFilterd) };
|
|
363
279
|
const contentText = hastToString(content);
|
|
@@ -366,18 +282,18 @@ var readabilityExtractHast = (hast) => {
|
|
|
366
282
|
}
|
|
367
283
|
const links = selectAll("a", content);
|
|
368
284
|
const linkText = links.map((link) => hastToString(link)).join("");
|
|
369
|
-
const linkDensity = linkText.length /
|
|
285
|
+
const linkDensity = linkText.length / contentText.length;
|
|
370
286
|
if (linkDensity > 0.4) {
|
|
371
287
|
continue;
|
|
372
288
|
}
|
|
373
289
|
if (contentText.length > minimalLength) {
|
|
374
|
-
|
|
375
|
-
|
|
290
|
+
extractedTree = content;
|
|
291
|
+
extractedText = contentText;
|
|
376
292
|
break;
|
|
377
293
|
}
|
|
378
294
|
}
|
|
379
|
-
const finalFilteredTree = filter(
|
|
380
|
-
if (!removeEmptyFilter(node)) {
|
|
295
|
+
const finalFilteredTree = filter(extractedTree, (node) => {
|
|
296
|
+
if (!removeEmptyFilter(node, lang)) {
|
|
381
297
|
return false;
|
|
382
298
|
}
|
|
383
299
|
if (!unlikelyElementFilter(node)) {
|
|
@@ -385,7 +301,7 @@ var readabilityExtractHast = (hast) => {
|
|
|
385
301
|
}
|
|
386
302
|
return true;
|
|
387
303
|
});
|
|
388
|
-
const finalTree = hastToString(finalFilteredTree).length >
|
|
304
|
+
const finalTree = hastToString(finalFilteredTree).length > extractedText.length / 3 ? finalFilteredTree : extractedTree;
|
|
389
305
|
return finalTree;
|
|
390
306
|
};
|
|
391
307
|
|
|
@@ -393,7 +309,8 @@ var readabilityExtractHast = (hast) => {
|
|
|
393
309
|
import { select as select2 } from "hast-util-select";
|
|
394
310
|
import { filter as filter2 } from "unist-util-filter";
|
|
395
311
|
var REMOVE_REGEX = /fallback|icon|header|nav|speechify-ignore|assist|-ad-|banner|combx|comment|com-|contact|foot|footer|footnote|gdpr|masthead|media|meta|outbrain|promo|related|scroll|share|assist|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i;
|
|
396
|
-
var stronglyExtractHast = (
|
|
312
|
+
var stronglyExtractHast = (params) => {
|
|
313
|
+
const { hast } = params;
|
|
397
314
|
const selectors = ["article", "#article", "#content", "main", "div.container"];
|
|
398
315
|
let selectedElement = hast;
|
|
399
316
|
for (const selector of selectors) {
|
|
@@ -426,17 +343,18 @@ var PRESET_EXTRACT_HAST = {
|
|
|
426
343
|
readability: readabilityExtractHast
|
|
427
344
|
};
|
|
428
345
|
var DEFAULT_EXTRACT_HAST = ["readability"];
|
|
429
|
-
var extractHast = (
|
|
346
|
+
var extractHast = (params, extractors = DEFAULT_EXTRACT_HAST) => {
|
|
347
|
+
const { hast, lang } = params;
|
|
430
348
|
const _extractors = Array.isArray(extractors) ? extractors : [extractors];
|
|
431
349
|
const extracted = _extractors.reduce((acc, extractor) => {
|
|
432
350
|
if (extractor === false) {
|
|
433
351
|
return acc;
|
|
434
352
|
}
|
|
435
353
|
if (typeof extractor === "string" && extractor in PRESET_EXTRACT_HAST) {
|
|
436
|
-
return PRESET_EXTRACT_HAST[extractor](acc);
|
|
354
|
+
return PRESET_EXTRACT_HAST[extractor]({ hast: acc, lang });
|
|
437
355
|
}
|
|
438
356
|
if (typeof extractor === "function") {
|
|
439
|
-
return extractor(acc);
|
|
357
|
+
return extractor({ hast: acc, lang });
|
|
440
358
|
}
|
|
441
359
|
throw new Error(`Invalid extractor: ${extractor}`);
|
|
442
360
|
}, hast) || hast;
|
|
@@ -625,10 +543,6 @@ var customTableHandler = (options) => (state, node) => {
|
|
|
625
543
|
return defaultHandlers4.table(state, node);
|
|
626
544
|
};
|
|
627
545
|
|
|
628
|
-
// src/mdast-handlers/empty-handler.ts
|
|
629
|
-
var emptyHandler = () => {
|
|
630
|
-
};
|
|
631
|
-
|
|
632
546
|
// src/mdast-handlers/math-handler.ts
|
|
633
547
|
import { toHtml } from "hast-util-to-html";
|
|
634
548
|
import { MathMLToLaTeX } from "mathml-to-latex";
|
|
@@ -640,11 +554,54 @@ var mathHandler = (state, node) => {
|
|
|
640
554
|
return result;
|
|
641
555
|
};
|
|
642
556
|
|
|
557
|
+
// src/utils/hast-utils.ts
|
|
558
|
+
import { select as select4, selectAll as selectAll2 } from "hast-util-select";
|
|
559
|
+
var getLangFromHast = (node) => {
|
|
560
|
+
const html = select4("html", node);
|
|
561
|
+
if (html && typeof html.properties.lang === "string") {
|
|
562
|
+
return html.properties.lang;
|
|
563
|
+
}
|
|
564
|
+
if (node.type !== "element") {
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
const element = node;
|
|
568
|
+
if (element.tagName !== "html") {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
const langAttr = element.properties.lang || element.properties["xml:lang"];
|
|
572
|
+
if (langAttr) {
|
|
573
|
+
return langAttr;
|
|
574
|
+
}
|
|
575
|
+
return void 0;
|
|
576
|
+
};
|
|
577
|
+
var getLangFromStr = (str) => {
|
|
578
|
+
const match = str.match(/lang=["']([^"']+)["']/);
|
|
579
|
+
if (match) {
|
|
580
|
+
return match[1];
|
|
581
|
+
}
|
|
582
|
+
return void 0;
|
|
583
|
+
};
|
|
584
|
+
var getUrlFromHast = (node) => {
|
|
585
|
+
if (node.type !== "element") {
|
|
586
|
+
return void 0;
|
|
587
|
+
}
|
|
588
|
+
const metaTagAttributes = ["og:url", "twitter:url"];
|
|
589
|
+
const metaTags = selectAll2("meta", node);
|
|
590
|
+
for (const meta of metaTags) {
|
|
591
|
+
const property = meta.properties.property || meta.properties.name;
|
|
592
|
+
if (typeof property === "string" && metaTagAttributes.includes(property)) {
|
|
593
|
+
return typeof meta.properties.content === "string" ? meta.properties.content : void 0;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return void 0;
|
|
597
|
+
};
|
|
598
|
+
|
|
643
599
|
// src/html-to-mdast.ts
|
|
644
600
|
var htmlToMdast = (htmlOrHast, options) => {
|
|
645
|
-
const { extractors } = options || {};
|
|
646
|
-
const hast = typeof htmlOrHast === "string" ? fromHtml(htmlOrHast, { fragment: true }) : htmlOrHast;
|
|
647
|
-
const
|
|
601
|
+
const { extractors, url: defaultUrl, lang: defaultLang } = options || {};
|
|
602
|
+
const [lang, hast] = typeof htmlOrHast === "string" ? [defaultLang || getLangFromStr(htmlOrHast), fromHtml(htmlOrHast, { fragment: true })] : [defaultLang || getLangFromHast(htmlOrHast), htmlOrHast];
|
|
603
|
+
const url = defaultUrl || getUrlFromHast(hast);
|
|
604
|
+
const extractedHast = extractHast({ hast, lang, url }, extractors);
|
|
648
605
|
const mdast = toMdast(extractedHast, {
|
|
649
606
|
handlers: {
|
|
650
607
|
math: mathHandler,
|
|
@@ -652,8 +609,7 @@ var htmlToMdast = (htmlOrHast, options) => {
|
|
|
652
609
|
pre: customCodeHandler,
|
|
653
610
|
a: customAHandler({ asText: options?.linkAsText }),
|
|
654
611
|
img: customImgHandler({ hideImage: options?.hideImage }),
|
|
655
|
-
table: customTableHandler({ asText: options?.tableAsText })
|
|
656
|
-
br: emptyHandler
|
|
612
|
+
table: customTableHandler({ asText: options?.tableAsText })
|
|
657
613
|
}
|
|
658
614
|
});
|
|
659
615
|
const extractedMdast = extractMdast(mdast);
|
|
@@ -666,13 +622,18 @@ import { mathToMarkdown } from "mdast-util-math";
|
|
|
666
622
|
import { toMarkdown } from "mdast-util-to-markdown";
|
|
667
623
|
|
|
668
624
|
// src/link-replacer.ts
|
|
669
|
-
var linkReplacer = (markdown,
|
|
670
|
-
const regex = /(!?\[.*?\]\()(
|
|
671
|
-
return markdown.replace(regex, (match, pre,
|
|
672
|
-
if (
|
|
625
|
+
var linkReplacer = (markdown, base) => {
|
|
626
|
+
const regex = /(!?\[.*?\]\()([^)\s]+)(\))/g;
|
|
627
|
+
return markdown.replace(regex, (match, pre, url, post) => {
|
|
628
|
+
if (/^(https?:|#)/.test(url)) {
|
|
629
|
+
return match;
|
|
630
|
+
}
|
|
631
|
+
try {
|
|
632
|
+
const absoluteUrl = new URL(url, base).href;
|
|
633
|
+
return `${pre}${absoluteUrl}${post}`;
|
|
634
|
+
} catch {
|
|
673
635
|
return match;
|
|
674
636
|
}
|
|
675
|
-
return `${pre}${new URL(thisUrl, link).href}${post}`;
|
|
676
637
|
});
|
|
677
638
|
};
|
|
678
639
|
|
|
@@ -691,7 +652,7 @@ var DEFAULT_MDAST_TO_MARKDOWN_OPTIONS = {
|
|
|
691
652
|
};
|
|
692
653
|
var mdastToMarkdown = (mdast, options) => {
|
|
693
654
|
const { baseUrl, ...toMarkdownOptions } = { ...DEFAULT_MDAST_TO_MARKDOWN_OPTIONS, ...options };
|
|
694
|
-
let markdown = toMarkdown(warpRoot(mdast), toMarkdownOptions);
|
|
655
|
+
let markdown = toMarkdown(warpRoot(mdast), toMarkdownOptions).replace(/\*\*\*\*/g, "");
|
|
695
656
|
if (baseUrl) {
|
|
696
657
|
markdown = linkReplacer(markdown, baseUrl);
|
|
697
658
|
}
|
|
@@ -722,71 +683,38 @@ var isUrl = (maybeUrl) => {
|
|
|
722
683
|
}
|
|
723
684
|
};
|
|
724
685
|
function changeFileExtension(filePath, newExtension) {
|
|
725
|
-
const
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
if (fileName.startsWith(".")) {
|
|
729
|
-
const parts = fileName.split(".");
|
|
730
|
-
if (parts.length === 2) {
|
|
731
|
-
return parsedPath.slice(0, -1).concat(`${fileName}${formattedNewExtension}`).join("/");
|
|
732
|
-
}
|
|
733
|
-
parts[parts.length - 1] = newExtension.replace(/^\./, "");
|
|
734
|
-
return parsedPath.slice(0, -1).concat(parts.join(".")).join("/");
|
|
735
|
-
}
|
|
736
|
-
const lastDotIndex = fileName.lastIndexOf(".");
|
|
737
|
-
const baseName = lastDotIndex !== -1 ? fileName.slice(0, lastDotIndex) : fileName;
|
|
738
|
-
const newFileName = `${baseName}${formattedNewExtension}`;
|
|
739
|
-
parsedPath[parsedPath.length - 1] = newFileName;
|
|
740
|
-
return parsedPath.join("/");
|
|
686
|
+
const parsed = path.parse(filePath);
|
|
687
|
+
const ext = newExtension.startsWith(".") ? newExtension : `.${newExtension}`;
|
|
688
|
+
return path.format({ ...parsed, ext });
|
|
741
689
|
}
|
|
742
690
|
function urlToFilename(url) {
|
|
743
691
|
try {
|
|
744
692
|
const urlObj = new URL(url);
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
return acc;
|
|
748
|
-
}
|
|
749
|
-
if (acc.length >= 2) {
|
|
750
|
-
return acc;
|
|
751
|
-
}
|
|
752
|
-
if (part === "www") {
|
|
753
|
-
return acc;
|
|
754
|
-
}
|
|
755
|
-
return [part, ...acc];
|
|
756
|
-
}, []);
|
|
757
|
-
const domainString = domainParts.reverse().join("-");
|
|
693
|
+
const hostname = urlObj.hostname.startsWith("www.") ? urlObj.hostname.slice(4) : urlObj.hostname;
|
|
694
|
+
const domainParts = hostname.split(".").slice(-2).join("-");
|
|
758
695
|
const pathParts = urlObj.pathname.split("/").filter(Boolean);
|
|
759
|
-
const relevantPathParts = pathParts.slice(-2);
|
|
760
|
-
|
|
761
|
-
let filename = [domainString, pathString].filter(Boolean).join("-");
|
|
696
|
+
const relevantPathParts = pathParts.slice(-2).map(decodeURIComponent).join("-");
|
|
697
|
+
let filename = [domainParts, relevantPathParts].filter(Boolean).join("-");
|
|
762
698
|
filename = filename.toLowerCase().replace(/[<>:"/\\|?*\x00-\x1F]/g, "").replace(/[\s.]+/g, "-").replace(/^-+|-+$/g, "");
|
|
763
699
|
return filename || "output";
|
|
764
700
|
} catch {
|
|
765
701
|
return "output";
|
|
766
702
|
}
|
|
767
703
|
}
|
|
768
|
-
var sourcePathToOutputPath = (sourcePath) => {
|
|
769
|
-
return isUrl(sourcePath) ? `${urlToFilename(sourcePath)}.md` : changeFileExtension(sourcePath, "md");
|
|
770
|
-
};
|
|
704
|
+
var sourcePathToOutputPath = (sourcePath) => isUrl(sourcePath) ? `${urlToFilename(sourcePath)}.md` : changeFileExtension(sourcePath, "md");
|
|
771
705
|
function getNextAvailableFilePath(filePath) {
|
|
772
|
-
const
|
|
773
|
-
const
|
|
774
|
-
const
|
|
775
|
-
const
|
|
776
|
-
const
|
|
777
|
-
|
|
778
|
-
let
|
|
779
|
-
|
|
780
|
-
while (fs.existsSync(nextFilePath)) {
|
|
781
|
-
const match = firstPart.match(/_(\d+)$/);
|
|
782
|
-
if (match) {
|
|
783
|
-
counter = Number.parseInt(match[1], 10) + 1;
|
|
784
|
-
}
|
|
785
|
-
const newName = `${baseName}_${counter}${restName}`;
|
|
786
|
-
nextFilePath = path.join(directory, newName);
|
|
706
|
+
const parsed = path.parse(filePath);
|
|
707
|
+
const dir = parsed.dir;
|
|
708
|
+
const ext = parsed.ext;
|
|
709
|
+
const baseName = parsed.name.replace(/_\d+$/, "");
|
|
710
|
+
const match = parsed.name.match(/_(\d+)$/);
|
|
711
|
+
let counter = match ? Number(match[1]) + 1 : 1;
|
|
712
|
+
let newPath = path.join(dir, `${baseName}_${counter}${ext}`);
|
|
713
|
+
while (fs.existsSync(newPath)) {
|
|
787
714
|
counter++;
|
|
715
|
+
newPath = path.join(dir, `${baseName}_${counter}${ext}`);
|
|
788
716
|
}
|
|
789
|
-
return
|
|
717
|
+
return newPath;
|
|
790
718
|
}
|
|
791
719
|
|
|
792
720
|
// src/cli/helpers/assertContinue.ts
|
|
@@ -882,9 +810,9 @@ var inputSourcePath = async () => {
|
|
|
882
810
|
};
|
|
883
811
|
|
|
884
812
|
// src/cli/helpers/selectExtractMode.ts
|
|
885
|
-
import { select as
|
|
813
|
+
import { select as select5 } from "@clack/prompts";
|
|
886
814
|
var selectExtractMode = async () => {
|
|
887
|
-
const result = await
|
|
815
|
+
const result = await select5({
|
|
888
816
|
message: "Select processing mode:",
|
|
889
817
|
options: MODES.map((mode) => ({ value: mode, label: mode })),
|
|
890
818
|
initialValue: MODES[0]
|
|
@@ -894,14 +822,14 @@ var selectExtractMode = async () => {
|
|
|
894
822
|
};
|
|
895
823
|
|
|
896
824
|
// src/cli/helpers/selectLoader.ts
|
|
897
|
-
import { select as
|
|
825
|
+
import { select as select6 } from "@clack/prompts";
|
|
898
826
|
var loadersHint = {
|
|
899
827
|
fetch: "Fetch HTML content from the given URL",
|
|
900
828
|
playwright: "Retrieve HTML content after rendering using Playwright; Playwright must be installed in advance.",
|
|
901
829
|
puppeteer: "Retrieve HTML content after rendering using Puppeteer; Puppeteer must be installed in advance."
|
|
902
830
|
};
|
|
903
831
|
var selectLoader = async () => {
|
|
904
|
-
const result = await
|
|
832
|
+
const result = await select6({
|
|
905
833
|
message: "Select loader:",
|
|
906
834
|
initialValue: "fetch",
|
|
907
835
|
options: LOADERS.map((mode) => ({ value: mode, label: mode, hint: loadersHint[mode] || "" }))
|
|
@@ -910,140 +838,155 @@ var selectLoader = async () => {
|
|
|
910
838
|
return result;
|
|
911
839
|
};
|
|
912
840
|
|
|
913
|
-
// src/cli/commands/
|
|
841
|
+
// src/cli/commands/webforai/loadHtml.ts
|
|
914
842
|
import fs4 from "node:fs/promises";
|
|
915
|
-
import { cancel as cancel2, spinner as clackSpinner, confirm as confirm2, spinner } from "@clack/prompts";
|
|
916
843
|
import pc from "picocolors";
|
|
917
|
-
import {
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
switch (loader.loader) {
|
|
926
|
-
case "fetch":
|
|
927
|
-
return await loadFetchHtml(sourcePath, loadSpinner);
|
|
928
|
-
case "playwright":
|
|
929
|
-
return await loadPlaywrightHtml(sourcePath, loadSpinner);
|
|
930
|
-
default:
|
|
931
|
-
throw new Error("Invalid loader");
|
|
932
|
-
}
|
|
933
|
-
default:
|
|
934
|
-
throw new Error("Invalid loader type");
|
|
935
|
-
}
|
|
936
|
-
} catch (error) {
|
|
937
|
-
loadSpinner.stop(pc.red("Content loading failed!"));
|
|
938
|
-
console.error(error);
|
|
939
|
-
process.exit(1);
|
|
940
|
-
}
|
|
941
|
-
};
|
|
942
|
-
var loadLocalHtml = async (sourcePath, loadSpinner) => {
|
|
943
|
-
loadSpinner.start("Retrieving content.");
|
|
944
|
-
try {
|
|
945
|
-
await fs4.access(sourcePath);
|
|
946
|
-
} catch {
|
|
947
|
-
throw new Error("The file does not exist");
|
|
948
|
-
}
|
|
949
|
-
const stats = await fs4.stat(sourcePath);
|
|
950
|
-
if (!stats.isFile()) {
|
|
951
|
-
throw new Error("The source must be a file");
|
|
952
|
-
}
|
|
953
|
-
const content = await fs4.readFile(sourcePath, "utf-8");
|
|
954
|
-
loadSpinner.stop("Content retrieval is complete!");
|
|
955
|
-
return content;
|
|
956
|
-
};
|
|
957
|
-
var loadFetchHtml = async (sourcePath, loadSpinner) => {
|
|
958
|
-
loadSpinner.start("Downloading content.");
|
|
959
|
-
const { loadHtml: loadHtml4 } = await Promise.resolve().then(() => (init_fetch(), fetch_exports));
|
|
960
|
-
const content = await loadHtml4(sourcePath);
|
|
961
|
-
loadSpinner.stop("Content download is complete!");
|
|
962
|
-
return content;
|
|
963
|
-
};
|
|
964
|
-
var loadPlaywrightHtml = async (sourcePath, loadSpinner) => {
|
|
965
|
-
const launchSpinner = clackSpinner();
|
|
966
|
-
launchSpinner.start("Launching playwright.");
|
|
967
|
-
const playwright = await import("playwright");
|
|
968
|
-
let browser;
|
|
969
|
-
try {
|
|
970
|
-
browser = await playwright.chromium.launch();
|
|
971
|
-
launchSpinner.stop("Playwright launched!");
|
|
972
|
-
} catch (error) {
|
|
973
|
-
await handlePlaywrightLaunchError(error);
|
|
974
|
-
browser = await playwright.chromium.launch();
|
|
975
|
-
}
|
|
976
|
-
loadSpinner.start("Loading content.");
|
|
977
|
-
const { loadHtml: loadHtml4 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
978
|
-
const content = await loadHtml4(sourcePath, browser);
|
|
979
|
-
loadSpinner.stop("Content download is complete!");
|
|
980
|
-
await browser.close();
|
|
981
|
-
return content;
|
|
982
|
-
};
|
|
983
|
-
var handlePlaywrightLaunchError = async (error) => {
|
|
984
|
-
if (!error.message.includes("npx playwright install")) {
|
|
985
|
-
throw error;
|
|
986
|
-
}
|
|
987
|
-
const isInstall = await confirm2({
|
|
988
|
-
message: "To continue, you will need to download a browser. Do you wish to continue?"
|
|
989
|
-
});
|
|
990
|
-
if (!isInstall) {
|
|
991
|
-
cancel2("End of process.");
|
|
992
|
-
process.exit(1);
|
|
993
|
-
}
|
|
994
|
-
const installDepsSpinner = spinner();
|
|
995
|
-
installDepsSpinner.start("Installing browser dependencies.");
|
|
996
|
-
try {
|
|
997
|
-
await $`npx playwright install`;
|
|
998
|
-
installDepsSpinner.stop("Browser dependencies installed!");
|
|
999
|
-
} catch (error2) {
|
|
1000
|
-
installDepsSpinner.stop(pc.red("Browser dependencies failed to install!"));
|
|
1001
|
-
throw error2;
|
|
1002
|
-
}
|
|
844
|
+
import { chromium as chromium2 } from "playwright-core";
|
|
845
|
+
import playwrightPackageJson from "playwright-core/package.json";
|
|
846
|
+
|
|
847
|
+
// src/loaders/fetch.ts
|
|
848
|
+
var USER_AGENT = "mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/125.0.0.0 safari/537.36";
|
|
849
|
+
var loadHtml = async (url, userAgent = USER_AGENT) => {
|
|
850
|
+
const response = await fetch(url, { headers: { "User-Agent": userAgent } });
|
|
851
|
+
return response.text();
|
|
1003
852
|
};
|
|
1004
853
|
|
|
1005
|
-
// src/
|
|
854
|
+
// src/loaders/playwright.ts
|
|
855
|
+
import { chromium, devices } from "playwright-core";
|
|
856
|
+
var SUPER_BYPASS_DEVICE = {
|
|
857
|
+
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
|
|
858
|
+
viewport: { width: 1920, height: 1080 },
|
|
859
|
+
deviceScaleFactor: 1,
|
|
860
|
+
hasTouch: false,
|
|
861
|
+
isMobile: false,
|
|
862
|
+
javaScriptEnabled: true,
|
|
863
|
+
locale: "en-US",
|
|
864
|
+
timezoneId: "America/New_York"
|
|
865
|
+
};
|
|
866
|
+
var loadHtml2 = async (url, options) => {
|
|
867
|
+
const { browser, waitUntil, timeout, superBypassMode } = options ?? {};
|
|
868
|
+
const _browser = browser ?? await chromium.launch({ headless: true });
|
|
869
|
+
const context = await _browser.newContext(superBypassMode ? SUPER_BYPASS_DEVICE : devices["Desktop Chrome"]);
|
|
870
|
+
if (superBypassMode) {
|
|
871
|
+
await context.addInitScript(() => {
|
|
872
|
+
Object.defineProperty(navigator, "webdriver", { get: () => void 0 });
|
|
873
|
+
Object.defineProperty(navigator, "languages", { get: () => ["en-US", "en"] });
|
|
874
|
+
Object.defineProperty(navigator, "plugins", { get: () => [1, 2, 3, 4, 5] });
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
const page = await context.newPage();
|
|
878
|
+
if (superBypassMode) {
|
|
879
|
+
await page.route("**/*.js", (route) => {
|
|
880
|
+
if (route.request().url().includes("captcha-delivery")) {
|
|
881
|
+
return route.abort();
|
|
882
|
+
}
|
|
883
|
+
return route.continue();
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
await page.goto(url, { waitUntil: waitUntil ?? "load", timeout });
|
|
887
|
+
const html = await page.content();
|
|
888
|
+
await page.close();
|
|
889
|
+
if (browser) {
|
|
890
|
+
await context.close();
|
|
891
|
+
} else {
|
|
892
|
+
await _browser.close();
|
|
893
|
+
}
|
|
894
|
+
return html;
|
|
895
|
+
};
|
|
896
|
+
|
|
897
|
+
// src/cli/commands/webforai/loadHtml.ts
|
|
898
|
+
var checkPlaywrightAvailable = async () => {
|
|
899
|
+
const path3 = chromium2.executablePath();
|
|
900
|
+
const isAvailable = await fs4.access(path3).catch(() => false);
|
|
901
|
+
return !!isAvailable;
|
|
902
|
+
};
|
|
903
|
+
var loadHtml3 = async (sourcePath, loader, options) => {
|
|
904
|
+
if (loader === "local") {
|
|
905
|
+
options.debug && console.debug(`Loading HTML from local file: ${sourcePath}`);
|
|
906
|
+
const content = await fs4.readFile(sourcePath, "utf-8");
|
|
907
|
+
options.debug && console.debug(`HTML loaded: ${content.slice(0, 100)}`);
|
|
908
|
+
return content;
|
|
909
|
+
}
|
|
910
|
+
if (loader === "fetch") {
|
|
911
|
+
options.debug && console.debug(`Loading HTML from URL: ${sourcePath}`);
|
|
912
|
+
const content = await loadHtml(sourcePath);
|
|
913
|
+
options.debug && console.debug(`HTML loaded: ${content.slice(0, 100)}`);
|
|
914
|
+
return content;
|
|
915
|
+
}
|
|
916
|
+
if (loader === "playwright") {
|
|
917
|
+
options.debug && console.debug(`Loading HTML from playwright: ${sourcePath}`);
|
|
918
|
+
const isPlaywrightAvailable = await checkPlaywrightAvailable();
|
|
919
|
+
options.debug && console.debug(`Playwright available: ${isPlaywrightAvailable}`);
|
|
920
|
+
if (!isPlaywrightAvailable) {
|
|
921
|
+
const message = [
|
|
922
|
+
"To use playwright loader, you need to install playwright.",
|
|
923
|
+
"You can install it by running:",
|
|
924
|
+
"",
|
|
925
|
+
` ${pc.bold(`npx playwright@${playwrightPackageJson.version} install chromium`)} `,
|
|
926
|
+
"",
|
|
927
|
+
"Hint1: If you get warning like this:",
|
|
928
|
+
"WARNING: It looks like you are running 'npx playwright install' without first installing your project's dependencies. ",
|
|
929
|
+
`${pc.bold("Ignore this warning.")}`,
|
|
930
|
+
"",
|
|
931
|
+
"Hint2: If you get message like this:",
|
|
932
|
+
"Host system is missing dependencies to run browsers.",
|
|
933
|
+
"You should install dependencies by running:",
|
|
934
|
+
"",
|
|
935
|
+
` ${pc.bold(`sudo npx playwright@${playwrightPackageJson.version} install-deps`)} `,
|
|
936
|
+
"",
|
|
937
|
+
pc.gray("Note: Good luck with that.")
|
|
938
|
+
];
|
|
939
|
+
console.info(message.join("\n"));
|
|
940
|
+
throw new Error("Playwright is not available");
|
|
941
|
+
}
|
|
942
|
+
const content = await loadHtml2(sourcePath);
|
|
943
|
+
options.debug && console.debug(`HTML loaded: ${content.slice(0, 100)}`);
|
|
944
|
+
return content;
|
|
945
|
+
}
|
|
946
|
+
throw new Error(`Unsupported loader: ${loader}`);
|
|
947
|
+
};
|
|
948
|
+
|
|
949
|
+
// src/cli/commands/webforai/index.ts
|
|
1006
950
|
var aiModeOptions = { linkAsText: true, tableAsText: true, hideImage: true };
|
|
1007
951
|
var readabilityModeOptions = { linkAsText: false, tableAsText: false, hideImage: false };
|
|
1008
|
-
var webforaiCommand = async (initialPath,
|
|
952
|
+
var webforaiCommand = async (initialPath, options) => {
|
|
953
|
+
intro(pc2.bold(pc2.green(`webforai CLI version ${package_default.version}`)));
|
|
1009
954
|
const sourcePath = initialPath ?? await inputSourcePath();
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
}
|
|
1013
|
-
const
|
|
1014
|
-
|
|
1015
|
-
console.debug(`loader: ${loader}`);
|
|
1016
|
-
}
|
|
1017
|
-
const outputPath = initialOutputPath ?? await inputOutputPath(sourcePath);
|
|
1018
|
-
if (options.debug) {
|
|
1019
|
-
console.debug(`outputPath: ${outputPath}`);
|
|
1020
|
-
}
|
|
955
|
+
options.debug && console.debug(`sourcePath: ${sourcePath}`);
|
|
956
|
+
const loader = isUrl(sourcePath) ? options.loader ?? await selectLoader() : "local";
|
|
957
|
+
options.debug && console.debug(`loader: ${loader}`);
|
|
958
|
+
const outputPath = options.output ?? await inputOutputPath(sourcePath);
|
|
959
|
+
options.debug && console.debug(`outputPath: ${outputPath}`);
|
|
1021
960
|
const mode = options.mode ?? await selectExtractMode();
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
961
|
+
options.debug && console.debug(`mode: ${mode}`);
|
|
962
|
+
let html;
|
|
963
|
+
const s = spinner();
|
|
964
|
+
try {
|
|
965
|
+
s.start("Loading content...");
|
|
966
|
+
html = await loadHtml3(sourcePath, loader, { debug: options.debug });
|
|
967
|
+
s.stop(pc2.green("Content loaded!"));
|
|
968
|
+
} catch (error) {
|
|
969
|
+
s.stop(pc2.red("Content loading failed!"));
|
|
970
|
+
console.error(error);
|
|
971
|
+
process.exit(1);
|
|
1028
972
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
973
|
+
options.debug && console.debug(`html: ${html}`);
|
|
974
|
+
const markdown = htmlToMarkdown(html, {
|
|
975
|
+
baseUrl: isUrl(sourcePath) ? sourcePath : void 0,
|
|
1031
976
|
...mode === "ai" ? aiModeOptions : readabilityModeOptions
|
|
1032
977
|
});
|
|
1033
|
-
|
|
1034
|
-
console.debug(`markdown: ${markdown}`);
|
|
1035
|
-
}
|
|
978
|
+
options.debug && console.debug(`markdown: ${markdown}`);
|
|
1036
979
|
const directory = path2.dirname(outputPath);
|
|
1037
|
-
|
|
1038
|
-
|
|
980
|
+
const isDirectoryExists = await fs5.stat(directory).then((stat) => stat.isDirectory());
|
|
981
|
+
if (!isDirectoryExists) {
|
|
982
|
+
await fs5.mkdir(directory, { recursive: true });
|
|
1039
983
|
}
|
|
1040
|
-
fs5.
|
|
1041
|
-
outro("Markdown
|
|
984
|
+
await fs5.writeFile(outputPath, markdown);
|
|
985
|
+
outro(pc2.green(`${pc2.bold("Done!")} Markdown saved to ${outputPath}`));
|
|
1042
986
|
};
|
|
1043
987
|
|
|
1044
988
|
// src/cli/bin.ts
|
|
1045
|
-
program.name("webforai").description("CLI tool for ultra-precise HTML to Markdown conversion").version(package_default.version, "-v, --version", "output the current version")
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
intro(pc2.inverse(`webforai CLI version ${package_default.version}`));
|
|
989
|
+
program.name("webforai").description("CLI tool for ultra-precise HTML to Markdown conversion").version(package_default.version, "-v, --version", "output the current version");
|
|
990
|
+
program.argument("[source]", "URL or path to process").option("-o, --output <output>", "Path to output file or directory").option("-m, --mode <mode>", `Processing mode (${MODES.join(", ")})`).option("-l, --loader <loader>", `Loader to use (${LOADERS.join(", ")})`).option("-d, --debug", "output extra debugging information").action(webforaiCommand);
|
|
991
|
+
intro2(pc3.inverse(`webforai CLI version ${package_default.version}`));
|
|
1049
992
|
program.parse();
|