@sovovs/bycli 2.1.13 → 2.1.15
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.
|
@@ -22,8 +22,21 @@ export function wechatArticleToMarkdown({ html, title, accountName, author, publ
|
|
|
22
22
|
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
23
23
|
.replace(/"/g, '"').replace(/'/g, ''')
|
|
24
24
|
.replace(/([\\`*_[\]{}()#+.!|>~-])/g, '\\$1');
|
|
25
|
+
// A URL must not go through `safe()`: escaping `. _ - ( ) #` and entity-encoding
|
|
26
|
+
// `&` corrupts the link so it can no longer be copied or followed. Rendered as an
|
|
27
|
+
// autolink it only needs whitespace and control characters dropped, `<`/`>`
|
|
28
|
+
// percent-encoded so the autolink cannot be closed early, and an http(s) scheme
|
|
29
|
+
// allowlist to reject `javascript:` and other hostile schemes.
|
|
30
|
+
const safeUrl = value => {
|
|
31
|
+
const raw = [...String(value || '')]
|
|
32
|
+
.filter(char => char > ' ' && char.codePointAt(0) !== 127)
|
|
33
|
+
.join('');
|
|
34
|
+
if (!/^https?:\/\//i.test(raw)) return '';
|
|
35
|
+
return raw.replace(/</g, '%3C').replace(/>/g, '%3E');
|
|
36
|
+
};
|
|
37
|
+
const articleUrl = safeUrl(url);
|
|
25
38
|
const metadata = [accountName && `> 公众号: ${safe(accountName)}`, author && `> 作者: ${safe(author)}`,
|
|
26
39
|
publishedAt && `> 发布时间: ${safe(publishedAt)}`, digest && `> 摘要: ${safe(digest)}`,
|
|
27
|
-
|
|
40
|
+
articleUrl && `> 原文链接: <${articleUrl}>`].filter(Boolean);
|
|
28
41
|
return [`# ${safe(title || 'Untitled')}`, ...metadata, '', '---', '', markdown, ''].join('\n');
|
|
29
42
|
}
|
|
@@ -212,6 +212,13 @@ function convertToMarkdown(contentHtml, codeBlocks, configure, cleanSelectors, s
|
|
|
212
212
|
md = md.replace(/^[ \t]*[-·][ \t]*$/gm, '');
|
|
213
213
|
md = md.replace(/^[ \t]+$/gm, '');
|
|
214
214
|
md = md.replace(/[ \t]+$/gm, '');
|
|
215
|
+
// Bare-text URLs in adjacent inline nodes (WeChat renders each on its own
|
|
216
|
+
// visual line but emits no separator) fuse into one unusable string like
|
|
217
|
+
// `https://a/Xhttps://b/Y`. Split consecutive bare URLs onto their own lines.
|
|
218
|
+
// A URL whose own query carries another URL (`?next=https://…`, common in
|
|
219
|
+
// redirect wrappers) must stay intact, so skip breaks that follow a query or
|
|
220
|
+
// path delimiter. Markdown destinations are already bounded by `()`/`<>`.
|
|
221
|
+
md = md.replace(/(https?:\/\/[^\s<>()[\]]*?)(?=https?:\/\/)/gi, (match) => (/[=?&/:,;-]$/.test(match) ? match : `${match}\n`));
|
|
215
222
|
md = md.replace(/\n{3,}/g, '\n\n');
|
|
216
223
|
return md;
|
|
217
224
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sovovs/bycli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.15",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"dependencies": {
|
|
91
91
|
"@mozilla/readability": "^0.6.0",
|
|
92
92
|
"@sovovs/bycli-recorder-core": "^0.1.0",
|
|
93
|
-
"@sovovs/wechat-article-crawler": "^1.1.
|
|
93
|
+
"@sovovs/wechat-article-crawler": "^1.1.3",
|
|
94
94
|
"cli-table3": "^0.6.5",
|
|
95
95
|
"commander": "^14.0.3",
|
|
96
96
|
"js-yaml": "^4.1.0",
|
|
@@ -59,14 +59,14 @@ try {
|
|
|
59
59
|
project, 'node_modules/@sovovs/bycli/package.json',
|
|
60
60
|
), 'utf8'));
|
|
61
61
|
assert.equal(mainManifest.dependencies?.['@sovovs/bycli-recorder-core'], '^0.1.0');
|
|
62
|
-
assert.equal(mainManifest.dependencies?.['@sovovs/wechat-article-crawler'], '^1.1.
|
|
62
|
+
assert.equal(mainManifest.dependencies?.['@sovovs/wechat-article-crawler'], '^1.1.3');
|
|
63
63
|
|
|
64
64
|
const coreDirectory = join(project, 'node_modules/@sovovs/bycli-recorder-core');
|
|
65
65
|
const crawlerDirectoryInstalled = join(project, 'node_modules/@sovovs/wechat-article-crawler');
|
|
66
66
|
const crawlerManifest = JSON.parse(readFileSync(
|
|
67
67
|
join(crawlerDirectoryInstalled, 'package.json'), 'utf8',
|
|
68
68
|
));
|
|
69
|
-
assert.equal(crawlerManifest.version, '1.1.
|
|
69
|
+
assert.equal(crawlerManifest.version, '1.1.3');
|
|
70
70
|
const projectRequire = createRequire(join(project, 'package.json'));
|
|
71
71
|
const crawlerEntry = projectRequire.resolve('@sovovs/wechat-article-crawler');
|
|
72
72
|
const crawlerModule = await import(pathToFileURL(crawlerEntry).href);
|