@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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
23
23
  .replace(/"/g, '&quot;').replace(/'/g, '&#39;')
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
- url && `> 原文链接: ${safe(url)}`].filter(Boolean);
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.13",
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.0",
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.0');
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.2');
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);