@wenyan-md/core 3.0.10 → 3.0.12
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/core.js +50 -9
- package/dist/publish.js +16 -1
- package/dist/types/core/parser/frontMatterParser.d.ts +3 -0
- package/dist/types/publish.d.ts +10 -1
- package/dist/types/wechat.d.ts +25 -0
- package/dist/wechat.js +37 -1
- package/dist/wrapper.js +51 -4
- package/package.json +1 -1
package/dist/core.js
CHANGED
|
@@ -202,7 +202,20 @@ async function handleFrontMatter(markdown) {
|
|
|
202
202
|
const { attributes, body } = fm(markdown);
|
|
203
203
|
const result = { content: body || "" };
|
|
204
204
|
let head = "";
|
|
205
|
-
const {
|
|
205
|
+
const {
|
|
206
|
+
title,
|
|
207
|
+
description,
|
|
208
|
+
cover,
|
|
209
|
+
author,
|
|
210
|
+
source_url,
|
|
211
|
+
pic_crop_235_1,
|
|
212
|
+
pic_crop_1_1,
|
|
213
|
+
need_open_comment,
|
|
214
|
+
only_fans_can_comment,
|
|
215
|
+
image_list,
|
|
216
|
+
type,
|
|
217
|
+
digest
|
|
218
|
+
} = attributes;
|
|
206
219
|
if (title) {
|
|
207
220
|
result.title = title;
|
|
208
221
|
}
|
|
@@ -219,6 +232,12 @@ async function handleFrontMatter(markdown) {
|
|
|
219
232
|
if (source_url) {
|
|
220
233
|
result.source_url = source_url;
|
|
221
234
|
}
|
|
235
|
+
if (pic_crop_235_1) {
|
|
236
|
+
result.pic_crop_235_1 = String(pic_crop_235_1);
|
|
237
|
+
}
|
|
238
|
+
if (pic_crop_1_1) {
|
|
239
|
+
result.pic_crop_1_1 = String(pic_crop_1_1);
|
|
240
|
+
}
|
|
222
241
|
if (need_open_comment !== void 0) {
|
|
223
242
|
result.need_open_comment = need_open_comment;
|
|
224
243
|
}
|
|
@@ -231,6 +250,9 @@ async function handleFrontMatter(markdown) {
|
|
|
231
250
|
if (type) {
|
|
232
251
|
result.type = type;
|
|
233
252
|
}
|
|
253
|
+
if (digest) {
|
|
254
|
+
result.digest = digest;
|
|
255
|
+
}
|
|
234
256
|
if (head) {
|
|
235
257
|
result.content = head + result.content;
|
|
236
258
|
}
|
|
@@ -996,15 +1018,34 @@ function wechatPostRender(element) {
|
|
|
996
1018
|
}
|
|
997
1019
|
li.appendChild(section);
|
|
998
1020
|
});
|
|
999
|
-
const
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1021
|
+
const flattenNestedLists = () => {
|
|
1022
|
+
let nestedLists = element.querySelectorAll(
|
|
1023
|
+
"li > section > ul, li > section > ol"
|
|
1024
|
+
);
|
|
1025
|
+
while (nestedLists.length > 0) {
|
|
1026
|
+
Array.from(nestedLists).reverse().forEach((nestedList) => {
|
|
1027
|
+
const isOrdered = nestedList.tagName === "OL";
|
|
1028
|
+
const doc = element.ownerDocument;
|
|
1029
|
+
const items = Array.from(nestedList.children).filter(
|
|
1030
|
+
(child) => child.tagName === "LI"
|
|
1031
|
+
);
|
|
1032
|
+
const wrapper = doc.createElement("section");
|
|
1033
|
+
wrapper.style.marginLeft = "1em";
|
|
1034
|
+
items.forEach((item, index) => {
|
|
1035
|
+
const content = item.querySelector("section");
|
|
1036
|
+
const sectionEl = doc.createElement("section");
|
|
1037
|
+
const marker = isOrdered ? `${index + 1}. ` : "• ";
|
|
1038
|
+
sectionEl.innerHTML = marker + (content?.innerHTML ?? item.innerHTML);
|
|
1039
|
+
wrapper.appendChild(sectionEl);
|
|
1040
|
+
});
|
|
1041
|
+
nestedList.replaceWith(wrapper);
|
|
1042
|
+
});
|
|
1043
|
+
nestedLists = element.querySelectorAll(
|
|
1044
|
+
"li > section > ul, li > section > ol"
|
|
1045
|
+
);
|
|
1006
1046
|
}
|
|
1007
|
-
}
|
|
1047
|
+
};
|
|
1048
|
+
flattenNestedLists();
|
|
1008
1049
|
element.style.color = "rgb(0, 0, 0)";
|
|
1009
1050
|
element.style.caretColor = "rgb(0, 0, 0)";
|
|
1010
1051
|
}
|
package/dist/publish.js
CHANGED
|
@@ -196,12 +196,18 @@ class WechatPublisher {
|
|
|
196
196
|
uploadCacheStore;
|
|
197
197
|
uploadMaterial;
|
|
198
198
|
publishArticle;
|
|
199
|
+
_listDraftsFn;
|
|
200
|
+
_getDraftFn;
|
|
201
|
+
_updateDraftFn;
|
|
199
202
|
fetchAccessToken;
|
|
200
203
|
constructor(httpAdapter, tokenStoreAdapter, uploadCacheStoreAdapter) {
|
|
201
|
-
const { uploadMaterial, publishArticle, fetchAccessToken } = createWechatClient(httpAdapter);
|
|
204
|
+
const { uploadMaterial, publishArticle, fetchAccessToken, listDrafts, getDraft, updateDraft } = createWechatClient(httpAdapter);
|
|
202
205
|
this.uploadMaterial = uploadMaterial;
|
|
203
206
|
this.publishArticle = publishArticle;
|
|
204
207
|
this.fetchAccessToken = fetchAccessToken;
|
|
208
|
+
this._listDraftsFn = listDrafts;
|
|
209
|
+
this._getDraftFn = getDraft;
|
|
210
|
+
this._updateDraftFn = updateDraft;
|
|
205
211
|
this.tokenStore = tokenStoreAdapter ? new TokenStore(tokenStoreAdapter) : void 0;
|
|
206
212
|
this.uploadCacheStore = uploadCacheStoreAdapter ? new UploadCacheStore(uploadCacheStoreAdapter) : void 0;
|
|
207
213
|
}
|
|
@@ -242,6 +248,15 @@ class WechatPublisher {
|
|
|
242
248
|
async publishToDraft(accessToken, options) {
|
|
243
249
|
return await this.publishArticle(accessToken, options);
|
|
244
250
|
}
|
|
251
|
+
async listDrafts(accessToken, offset = 0, count = 20, noContent = 0) {
|
|
252
|
+
return await this._listDraftsFn(accessToken, offset, count, noContent);
|
|
253
|
+
}
|
|
254
|
+
async getDraft(accessToken, mediaId) {
|
|
255
|
+
return await this._getDraftFn(accessToken, mediaId);
|
|
256
|
+
}
|
|
257
|
+
async updateDraft(accessToken, mediaId, articleIndex, options) {
|
|
258
|
+
await this._updateDraftFn(accessToken, mediaId, articleIndex, options);
|
|
259
|
+
}
|
|
245
260
|
async clearCache() {
|
|
246
261
|
if (this.tokenStore) {
|
|
247
262
|
await this.tokenStore.clear();
|
|
@@ -5,9 +5,12 @@ export interface FrontMatterResult {
|
|
|
5
5
|
cover?: string;
|
|
6
6
|
author?: string;
|
|
7
7
|
source_url?: string;
|
|
8
|
+
pic_crop_235_1?: string;
|
|
9
|
+
pic_crop_1_1?: string;
|
|
8
10
|
need_open_comment?: boolean;
|
|
9
11
|
only_fans_can_comment?: boolean;
|
|
10
12
|
image_list?: string[];
|
|
11
13
|
type?: string;
|
|
14
|
+
digest?: string;
|
|
12
15
|
}
|
|
13
16
|
export declare function handleFrontMatter(markdown: string): Promise<FrontMatterResult>;
|
package/dist/types/publish.d.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { HttpAdapter } from "./http.js";
|
|
2
2
|
import { TokenStorageAdapter } from "./tokenStore.js";
|
|
3
3
|
import { UploadCacheStorageAdapter } from "./uploadCacheStore.js";
|
|
4
|
-
import { WechatPublishOptions, WechatPublishResponse, WechatUploadResponse } from "./wechat.js";
|
|
4
|
+
import { WechatPublishOptions, WechatPublishResponse, WechatUploadResponse, WechatDraftListResponse, WechatDraftGetResponse } from "./wechat.js";
|
|
5
5
|
export interface ArticleOptions {
|
|
6
6
|
title: string;
|
|
7
7
|
content: string;
|
|
8
8
|
cover?: string;
|
|
9
9
|
author?: string;
|
|
10
10
|
source_url?: string;
|
|
11
|
+
pic_crop_235_1?: string;
|
|
12
|
+
pic_crop_1_1?: string;
|
|
11
13
|
need_open_comment?: boolean;
|
|
12
14
|
only_fans_can_comment?: boolean;
|
|
15
|
+
digest?: string;
|
|
13
16
|
}
|
|
14
17
|
export interface ImageTextArticleOptions extends ArticleOptions {
|
|
15
18
|
images: string[];
|
|
@@ -19,11 +22,17 @@ export declare class WechatPublisher {
|
|
|
19
22
|
private uploadCacheStore;
|
|
20
23
|
private uploadMaterial;
|
|
21
24
|
private publishArticle;
|
|
25
|
+
private _listDraftsFn;
|
|
26
|
+
private _getDraftFn;
|
|
27
|
+
private _updateDraftFn;
|
|
22
28
|
private fetchAccessToken;
|
|
23
29
|
constructor(httpAdapter: HttpAdapter, tokenStoreAdapter?: TokenStorageAdapter, uploadCacheStoreAdapter?: UploadCacheStorageAdapter);
|
|
24
30
|
getAccessTokenWithCache(appId: string, appSecret: string): Promise<string>;
|
|
25
31
|
uploadImage(file: Blob, filename: string, accessToken: string, appId?: string): Promise<WechatUploadResponse>;
|
|
26
32
|
publishToDraft(accessToken: string, options: WechatPublishOptions): Promise<WechatPublishResponse>;
|
|
33
|
+
listDrafts(accessToken: string, offset?: number, count?: number, noContent?: number): Promise<WechatDraftListResponse>;
|
|
34
|
+
getDraft(accessToken: string, mediaId: string): Promise<WechatDraftGetResponse>;
|
|
35
|
+
updateDraft(accessToken: string, mediaId: string, articleIndex: number, options: Partial<WechatPublishOptions>): Promise<void>;
|
|
27
36
|
clearCache(): Promise<void>;
|
|
28
37
|
setExternalToken(appid: string, accessToken: string): Promise<void>;
|
|
29
38
|
}
|
package/dist/types/wechat.d.ts
CHANGED
|
@@ -19,10 +19,13 @@ export interface WechatPublishOptions {
|
|
|
19
19
|
content: string;
|
|
20
20
|
thumb_media_id: string;
|
|
21
21
|
content_source_url?: string;
|
|
22
|
+
pic_crop_235_1?: string;
|
|
23
|
+
pic_crop_1_1?: string;
|
|
22
24
|
article_type?: "news" | "newspic";
|
|
23
25
|
image_info?: ImageInfo;
|
|
24
26
|
need_open_comment?: 0 | 1;
|
|
25
27
|
only_fans_can_comment?: 0 | 1;
|
|
28
|
+
digest?: string;
|
|
26
29
|
}
|
|
27
30
|
export interface WechatErrorResponse {
|
|
28
31
|
errcode: number;
|
|
@@ -39,9 +42,31 @@ export interface WechatTokenResponse {
|
|
|
39
42
|
export interface WechatPublishResponse {
|
|
40
43
|
media_id: string;
|
|
41
44
|
}
|
|
45
|
+
export interface WechatDraftListItem {
|
|
46
|
+
media_id: string;
|
|
47
|
+
content: {
|
|
48
|
+
news_item: WechatPublishOptions[];
|
|
49
|
+
};
|
|
50
|
+
update_time: number;
|
|
51
|
+
}
|
|
52
|
+
export interface WechatDraftListResponse {
|
|
53
|
+
total_count: number;
|
|
54
|
+
item_count: number;
|
|
55
|
+
item: WechatDraftListItem[];
|
|
56
|
+
}
|
|
57
|
+
export interface WechatDraftGetResponse {
|
|
58
|
+
news_item: WechatPublishOptions[];
|
|
59
|
+
}
|
|
60
|
+
export interface WechatDraftUpdateResponse {
|
|
61
|
+
errcode: number;
|
|
62
|
+
errmsg: string;
|
|
63
|
+
}
|
|
42
64
|
export declare function createWechatClient(httpAdapter: HttpAdapter): {
|
|
43
65
|
fetchAccessToken(appId: string, appSecret: string): Promise<WechatTokenResponse>;
|
|
44
66
|
uploadMaterial(type: string, file: Blob, filename: string, accessToken: string): Promise<WechatUploadResponse>;
|
|
45
67
|
publishArticle(accessToken: string, options: WechatPublishOptions): Promise<WechatPublishResponse>;
|
|
68
|
+
listDrafts(accessToken: string, offset?: number, count?: number, noContent?: number): Promise<WechatDraftListResponse>;
|
|
69
|
+
getDraft(accessToken: string, mediaId: string): Promise<WechatDraftGetResponse>;
|
|
70
|
+
updateDraft(accessToken: string, mediaId: string, articleIndex: number, options: Partial<WechatPublishOptions>): Promise<void>;
|
|
46
71
|
};
|
|
47
72
|
export type WechatClient = ReturnType<typeof createWechatClient>;
|
package/dist/wechat.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
const tokenUrl = "https://api.weixin.qq.com/cgi-bin/token";
|
|
2
2
|
const publishUrl = "https://api.weixin.qq.com/cgi-bin/draft/add";
|
|
3
3
|
const uploadUrl = "https://api.weixin.qq.com/cgi-bin/material/add_material";
|
|
4
|
+
const draftListUrl = "https://api.weixin.qq.com/cgi-bin/draft/batchget";
|
|
5
|
+
const draftGetUrl = "https://api.weixin.qq.com/cgi-bin/draft/get";
|
|
6
|
+
const draftUpdateUrl = "https://api.weixin.qq.com/cgi-bin/draft/update";
|
|
4
7
|
function createWechatClient(httpAdapter) {
|
|
5
8
|
return {
|
|
6
9
|
async fetchAccessToken(appId, appSecret) {
|
|
@@ -37,6 +40,39 @@ function createWechatClient(httpAdapter) {
|
|
|
37
40
|
const data = await res.json();
|
|
38
41
|
assertWechatSuccess(data);
|
|
39
42
|
return data;
|
|
43
|
+
},
|
|
44
|
+
async listDrafts(accessToken, offset = 0, count = 20, noContent = 0) {
|
|
45
|
+
const res = await httpAdapter.fetch(`${draftListUrl}?access_token=${accessToken}`, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
body: JSON.stringify({ offset, count, no_content: noContent })
|
|
48
|
+
});
|
|
49
|
+
if (!res.ok) throw new Error(await res.text());
|
|
50
|
+
const data = await res.json();
|
|
51
|
+
assertWechatSuccess(data);
|
|
52
|
+
return data;
|
|
53
|
+
},
|
|
54
|
+
async getDraft(accessToken, mediaId) {
|
|
55
|
+
const res = await httpAdapter.fetch(`${draftGetUrl}?access_token=${accessToken}`, {
|
|
56
|
+
method: "POST",
|
|
57
|
+
body: JSON.stringify({ media_id: mediaId })
|
|
58
|
+
});
|
|
59
|
+
if (!res.ok) throw new Error(await res.text());
|
|
60
|
+
const data = await res.json();
|
|
61
|
+
assertWechatSuccess(data);
|
|
62
|
+
return data;
|
|
63
|
+
},
|
|
64
|
+
async updateDraft(accessToken, mediaId, articleIndex, options) {
|
|
65
|
+
const res = await httpAdapter.fetch(`${draftUpdateUrl}?access_token=${accessToken}`, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
body: JSON.stringify({
|
|
68
|
+
media_id: mediaId,
|
|
69
|
+
index: articleIndex,
|
|
70
|
+
articles: options
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
if (!res.ok) throw new Error(await res.text());
|
|
74
|
+
const data = await res.json();
|
|
75
|
+
assertWechatSuccess(data);
|
|
40
76
|
}
|
|
41
77
|
};
|
|
42
78
|
}
|
|
@@ -44,7 +80,7 @@ const WECHAT_ERROR_HINTS = {
|
|
|
44
80
|
45166: "内容超长。小绿书模式有内容长度限制,请精简正文后重试。"
|
|
45
81
|
};
|
|
46
82
|
function assertWechatSuccess(data) {
|
|
47
|
-
if ("errcode" in data) {
|
|
83
|
+
if ("errcode" in data && data.errcode !== 0) {
|
|
48
84
|
const hint = WECHAT_ERROR_HINTS[data.errcode];
|
|
49
85
|
throw new Error(hint ? `${data.errcode}: ${hint} (${data.errmsg})` : `${data.errcode}: ${data.errmsg}`);
|
|
50
86
|
}
|
package/dist/wrapper.js
CHANGED
|
@@ -478,7 +478,18 @@ async function uploadImages(content, accessToken, relativePath, appId) {
|
|
|
478
478
|
return { html: updatedHtml, firstImageId };
|
|
479
479
|
}
|
|
480
480
|
async function publishToWechatDraft(articleOptions, publishOptions = {}) {
|
|
481
|
-
const {
|
|
481
|
+
const {
|
|
482
|
+
title,
|
|
483
|
+
content,
|
|
484
|
+
cover,
|
|
485
|
+
author,
|
|
486
|
+
source_url,
|
|
487
|
+
pic_crop_235_1,
|
|
488
|
+
pic_crop_1_1,
|
|
489
|
+
need_open_comment,
|
|
490
|
+
only_fans_can_comment,
|
|
491
|
+
digest
|
|
492
|
+
} = articleOptions;
|
|
482
493
|
const { appId, appSecret, relativePath } = publishOptions;
|
|
483
494
|
const { appId: appIdFinal, appSecret: appSecretFinal } = await getAppIdAndSecret(appId, appSecret);
|
|
484
495
|
const accessToken = await wechatPublisher.getAccessTokenWithCache(appIdFinal, appSecretFinal);
|
|
@@ -514,8 +525,11 @@ async function publishToWechatDraft(articleOptions, publishOptions = {}) {
|
|
|
514
525
|
thumb_media_id: thumbMediaId,
|
|
515
526
|
author,
|
|
516
527
|
content_source_url: source_url,
|
|
528
|
+
pic_crop_235_1,
|
|
529
|
+
pic_crop_1_1,
|
|
517
530
|
need_open_comment: need_open_comment ? 1 : 0,
|
|
518
|
-
only_fans_can_comment: only_fans_can_comment ? 1 : 0
|
|
531
|
+
only_fans_can_comment: only_fans_can_comment ? 1 : 0,
|
|
532
|
+
digest
|
|
519
533
|
});
|
|
520
534
|
if (data.media_id) {
|
|
521
535
|
return data;
|
|
@@ -571,11 +585,30 @@ async function publishImageTextToWechatDraft(articleOptions, publishOptions = {}
|
|
|
571
585
|
if (!thumbMediaId) {
|
|
572
586
|
throw new Error("未能获取封面图的 media_id");
|
|
573
587
|
}
|
|
588
|
+
let plainContent = content || "";
|
|
589
|
+
if (plainContent) {
|
|
590
|
+
if (plainContent.includes("<br") || plainContent.includes("<p")) {
|
|
591
|
+
plainContent = plainContent.replace(/<br\s*\/?>\n/g, "\n");
|
|
592
|
+
const dom = new JSDOM(`<body>${plainContent}</body>`);
|
|
593
|
+
const document = dom.window.document;
|
|
594
|
+
const brs = document.querySelectorAll("br");
|
|
595
|
+
for (const br of brs) {
|
|
596
|
+
br.replaceWith(document.createTextNode("\n"));
|
|
597
|
+
}
|
|
598
|
+
const paragraphs = document.querySelectorAll("p");
|
|
599
|
+
for (const p of paragraphs) {
|
|
600
|
+
const text = document.createTextNode("\n" + p.textContent + "\n");
|
|
601
|
+
p.replaceWith(text);
|
|
602
|
+
}
|
|
603
|
+
plainContent = document.body.textContent?.trim() || "";
|
|
604
|
+
}
|
|
605
|
+
plainContent = plainContent.replace(/^#{1,6}\s+/gm, "").replace(/\*\*(.*?)\*\*/g, "$1").replace(/\*(.*?)\*/g, "$1").replace(/__(.*?)__/g, "$1").replace(/_(.*?)_/g, "$1").replace(/`{1,3}[^`]*`{1,3}/g, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/!\[([^\]]*)\]\([^)]+\)/g, "").replace(/^\s*[-*+]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").replace(/^\s*>\s+/gm, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
606
|
+
}
|
|
574
607
|
const data = await wechatPublisher.publishToDraft(
|
|
575
608
|
accessToken,
|
|
576
609
|
{
|
|
577
610
|
title,
|
|
578
|
-
content,
|
|
611
|
+
content: plainContent,
|
|
579
612
|
thumb_media_id: thumbMediaId,
|
|
580
613
|
author,
|
|
581
614
|
article_type: "newspic",
|
|
@@ -864,7 +897,21 @@ async function extractAndCleanImages(body) {
|
|
|
864
897
|
parent.remove();
|
|
865
898
|
}
|
|
866
899
|
}
|
|
867
|
-
|
|
900
|
+
for (const child of Array.from(wenyan.children)) {
|
|
901
|
+
if (!child.textContent?.trim()) {
|
|
902
|
+
child.remove();
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
const paragraphs = Array.from(wenyan.querySelectorAll("p"));
|
|
906
|
+
for (const p of paragraphs) {
|
|
907
|
+
const frag = document.createDocumentFragment();
|
|
908
|
+
while (p.firstChild) {
|
|
909
|
+
frag.appendChild(p.firstChild);
|
|
910
|
+
}
|
|
911
|
+
frag.appendChild(document.createElement("br"));
|
|
912
|
+
p.parentNode?.replaceChild(frag, p);
|
|
913
|
+
}
|
|
914
|
+
return { imagePaths, cleanedHtml: wenyan.innerHTML.trim() };
|
|
868
915
|
}
|
|
869
916
|
const nodeMermaidRenderer = createNodeMermaidRenderer();
|
|
870
917
|
const wenyanCoreInstance = await createWenyanCore({
|
package/package.json
CHANGED