@wenyan-md/core 3.0.5 → 3.0.6
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 +12 -3
- package/dist/types/core/index.d.ts +2 -2
- package/dist/types/core/parser/frontMatterParser.d.ts +5 -2
- package/dist/types/node/clientPublish.d.ts +1 -0
- package/dist/types/node/publish.d.ts +6 -2
- package/dist/types/node/render.d.ts +2 -3
- package/dist/types/node/types.d.ts +4 -1
- package/dist/types/node/wrapper.d.ts +1 -2
- package/dist/types/publish.d.ts +5 -0
- package/dist/types/wechat.d.ts +18 -0
- package/dist/wrapper.js +103 -38
- package/package.json +1 -1
package/dist/core.js
CHANGED
|
@@ -194,9 +194,9 @@ function renderListStyleFootnotes(footnotes) {
|
|
|
194
194
|
}
|
|
195
195
|
async function handleFrontMatter(markdown) {
|
|
196
196
|
const { attributes, body } = fm(markdown);
|
|
197
|
-
const result = {
|
|
197
|
+
const result = { content: body || "" };
|
|
198
198
|
let head = "";
|
|
199
|
-
const { title, description, cover, author, source_url } = attributes;
|
|
199
|
+
const { title, description, cover, author, source_url, need_open_comment, only_fans_can_comment, image_list } = attributes;
|
|
200
200
|
if (title) {
|
|
201
201
|
result.title = title;
|
|
202
202
|
}
|
|
@@ -208,7 +208,7 @@ async function handleFrontMatter(markdown) {
|
|
|
208
208
|
result.cover = cover;
|
|
209
209
|
}
|
|
210
210
|
if (head) {
|
|
211
|
-
result.
|
|
211
|
+
result.content = head + result.content;
|
|
212
212
|
}
|
|
213
213
|
if (author) {
|
|
214
214
|
result.author = author;
|
|
@@ -216,6 +216,15 @@ async function handleFrontMatter(markdown) {
|
|
|
216
216
|
if (source_url) {
|
|
217
217
|
result.source_url = source_url;
|
|
218
218
|
}
|
|
219
|
+
if (need_open_comment !== void 0) {
|
|
220
|
+
result.need_open_comment = need_open_comment;
|
|
221
|
+
}
|
|
222
|
+
if (only_fans_can_comment !== void 0) {
|
|
223
|
+
result.only_fans_can_comment = only_fans_can_comment;
|
|
224
|
+
}
|
|
225
|
+
if (image_list) {
|
|
226
|
+
result.image_list = image_list;
|
|
227
|
+
}
|
|
219
228
|
return result;
|
|
220
229
|
}
|
|
221
230
|
const parseOptions = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StyledContent } from "../node/types.js";
|
|
2
2
|
export interface WenyanOptions {
|
|
3
3
|
isConvertMathJax?: boolean;
|
|
4
4
|
isWechat?: boolean;
|
|
@@ -12,7 +12,7 @@ export interface ApplyStylesOptions {
|
|
|
12
12
|
isAddFootnote?: boolean;
|
|
13
13
|
}
|
|
14
14
|
export declare function createWenyanCore(options?: WenyanOptions): Promise<{
|
|
15
|
-
handleFrontMatter(markdown: string): Promise<
|
|
15
|
+
handleFrontMatter(markdown: string): Promise<StyledContent>;
|
|
16
16
|
renderMarkdown(markdown: string): Promise<string>;
|
|
17
17
|
applyStylesWithTheme(wenyanElement: HTMLElement, options?: ApplyStylesOptions): Promise<string>;
|
|
18
18
|
applyStylesWithResolvedCss(wenyanElement: HTMLElement, options: {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
export interface FrontMatterResult {
|
|
2
|
-
|
|
2
|
+
content: string;
|
|
3
3
|
title?: string;
|
|
4
|
-
cover?: string;
|
|
5
4
|
description?: string;
|
|
5
|
+
cover?: string;
|
|
6
6
|
author?: string;
|
|
7
7
|
source_url?: string;
|
|
8
|
+
need_open_comment?: boolean;
|
|
9
|
+
only_fans_can_comment?: boolean;
|
|
10
|
+
image_list?: string[];
|
|
8
11
|
}
|
|
9
12
|
export declare function handleFrontMatter(markdown: string): Promise<FrontMatterResult>;
|
|
@@ -13,3 +13,4 @@ export declare function uploadStyledContent(gzhContent: StyledContent, serverUrl
|
|
|
13
13
|
export declare function requestServerPublish(mdFileId: string, serverUrl: string, headers: Record<string, string>, options: ClientPublishOptions): Promise<string>;
|
|
14
14
|
export declare function uploadLocalImages(content: string, serverUrl: string, headers: Record<string, string>, relativePath?: string): Promise<string>;
|
|
15
15
|
export declare function uploadCover(serverUrl: string, headers: Record<string, string>, cover?: string, relativePath?: string): Promise<string | undefined>;
|
|
16
|
+
export declare function uploadImageList(serverUrl: string, headers: Record<string, string>, imageList?: string[], relativePath?: string): Promise<string[]>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { WechatPublishResponse } from "../wechat.js";
|
|
2
|
-
import { ArticleOptions, WechatPublisher } from "../publish.js";
|
|
1
|
+
import type { WechatPublishResponse } from "../wechat.js";
|
|
2
|
+
import { ArticleOptions, ImageTextArticleOptions, WechatPublisher } from "../publish.js";
|
|
3
3
|
import { CredentialStore } from "../credentialStore.js";
|
|
4
4
|
export declare const wechatPublisher: WechatPublisher;
|
|
5
5
|
export declare const credentialStore: CredentialStore;
|
|
@@ -9,5 +9,9 @@ interface PublishOptions {
|
|
|
9
9
|
relativePath?: string;
|
|
10
10
|
}
|
|
11
11
|
export declare function publishToWechatDraft(articleOptions: ArticleOptions, publishOptions?: PublishOptions): Promise<WechatPublishResponse>;
|
|
12
|
+
/**
|
|
13
|
+
* @deprecated use publishToWechatDraft instead
|
|
14
|
+
*/
|
|
12
15
|
export declare function publishToDraft(title: string, content: string, cover?: string, options?: PublishOptions): Promise<WechatPublishResponse>;
|
|
16
|
+
export declare function publishImageTextToWechatDraft(articleOptions: ImageTextArticleOptions, publishOptions?: PublishOptions): Promise<WechatPublishResponse>;
|
|
13
17
|
export {};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ApplyStylesOptions } from "../core/index.js";
|
|
2
|
-
import { GetInputContentFn, RenderContext, RenderOptions
|
|
3
|
-
export declare function
|
|
4
|
-
export declare function renderStyledContent(content: string, options?: ApplyStylesOptions): Promise<StyledContent>;
|
|
2
|
+
import { GetInputContentFn, RenderContext, RenderOptions } from "./types.js";
|
|
3
|
+
export declare function renderStyledContent(content: string, options?: ApplyStylesOptions): Promise<string>;
|
|
5
4
|
export declare function prepareRenderContext(inputContent: string | undefined, options: RenderOptions, getInputContent: GetInputContentFn): Promise<RenderContext>;
|
|
@@ -21,10 +21,13 @@ export interface RenderContext {
|
|
|
21
21
|
export interface StyledContent {
|
|
22
22
|
content: string;
|
|
23
23
|
title?: string;
|
|
24
|
-
cover?: string;
|
|
25
24
|
description?: string;
|
|
25
|
+
cover?: string;
|
|
26
26
|
author?: string;
|
|
27
27
|
source_url?: string;
|
|
28
|
+
need_open_comment?: boolean;
|
|
29
|
+
only_fans_can_comment?: boolean;
|
|
30
|
+
image_list?: string[];
|
|
28
31
|
}
|
|
29
32
|
export type GetInputContentFn = (inputContent?: string, filePath?: string) => Promise<{
|
|
30
33
|
content: string;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ClientPublishOptions, GetInputContentFn, PublishOptions
|
|
2
|
-
export declare function getGzhContent(content: string, themeId: string, hlThemeId: string, isMacStyle?: boolean, isAddFootnote?: boolean): Promise<StyledContent>;
|
|
1
|
+
import { ClientPublishOptions, GetInputContentFn, PublishOptions } from "./types.js";
|
|
3
2
|
export declare function renderAndPublish(inputContent: string | undefined, options: PublishOptions, getInputContent: GetInputContentFn): Promise<string>;
|
|
4
3
|
export declare function renderAndPublishToServer(inputContent: string | undefined, options: ClientPublishOptions, getInputContent: GetInputContentFn): Promise<string>;
|
|
5
4
|
export * from "./configStore.js";
|
package/dist/types/publish.d.ts
CHANGED
|
@@ -8,6 +8,11 @@ export interface ArticleOptions {
|
|
|
8
8
|
cover?: string;
|
|
9
9
|
author?: string;
|
|
10
10
|
source_url?: string;
|
|
11
|
+
need_open_comment?: boolean;
|
|
12
|
+
only_fans_can_comment?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface ImageTextArticleOptions extends ArticleOptions {
|
|
15
|
+
images: string[];
|
|
11
16
|
}
|
|
12
17
|
export declare class WechatPublisher {
|
|
13
18
|
private tokenStore;
|
package/dist/types/wechat.d.ts
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import type { HttpAdapter } from "./http.js";
|
|
2
|
+
export interface ImageCropPercent {
|
|
3
|
+
ratio: string;
|
|
4
|
+
x1: number;
|
|
5
|
+
y1: number;
|
|
6
|
+
x2: number;
|
|
7
|
+
y2: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ImageListItem {
|
|
10
|
+
image_media_id: string;
|
|
11
|
+
crop_percent_list?: ImageCropPercent[];
|
|
12
|
+
}
|
|
13
|
+
export interface ImageInfo {
|
|
14
|
+
image_list: ImageListItem[];
|
|
15
|
+
}
|
|
2
16
|
export interface WechatPublishOptions {
|
|
3
17
|
title: string;
|
|
4
18
|
author?: string;
|
|
5
19
|
content: string;
|
|
6
20
|
thumb_media_id: string;
|
|
7
21
|
content_source_url?: string;
|
|
22
|
+
article_type?: "news" | "newspic";
|
|
23
|
+
image_info?: ImageInfo;
|
|
24
|
+
need_open_comment?: 0 | 1;
|
|
25
|
+
only_fans_can_comment?: 0 | 1;
|
|
8
26
|
}
|
|
9
27
|
export interface WechatErrorResponse {
|
|
10
28
|
errcode: number;
|
package/dist/wrapper.js
CHANGED
|
@@ -327,6 +327,19 @@ async function uploadCover(serverUrl, headers, cover, relativePath) {
|
|
|
327
327
|
}
|
|
328
328
|
return cover;
|
|
329
329
|
}
|
|
330
|
+
async function uploadImageList(serverUrl, headers, imageList, relativePath) {
|
|
331
|
+
if (imageList && imageList.length > 0) {
|
|
332
|
+
const uploadPromises = imageList.map(async (image) => {
|
|
333
|
+
if (needUpload(image)) {
|
|
334
|
+
const newImageUrl = await uploadLocalImage(image, serverUrl, headers, relativePath);
|
|
335
|
+
return newImageUrl || image;
|
|
336
|
+
}
|
|
337
|
+
return image;
|
|
338
|
+
});
|
|
339
|
+
return await Promise.all(uploadPromises);
|
|
340
|
+
}
|
|
341
|
+
return imageList || [];
|
|
342
|
+
}
|
|
330
343
|
const nodeHttpAdapter = {
|
|
331
344
|
fetch,
|
|
332
345
|
createMultipart(field, file, filename) {
|
|
@@ -463,7 +476,7 @@ async function uploadImages(content, accessToken, relativePath, appId) {
|
|
|
463
476
|
return { html: updatedHtml, firstImageId };
|
|
464
477
|
}
|
|
465
478
|
async function publishToWechatDraft(articleOptions, publishOptions = {}) {
|
|
466
|
-
const { title, content, cover, author, source_url } = articleOptions;
|
|
479
|
+
const { title, content, cover, author, source_url, need_open_comment, only_fans_can_comment } = articleOptions;
|
|
467
480
|
const { appId, appSecret, relativePath } = publishOptions;
|
|
468
481
|
const { appId: appIdFinal, appSecret: appSecretFinal } = await getAppIdAndSecret(appId, appSecret);
|
|
469
482
|
const accessToken = await wechatPublisher.getAccessTokenWithCache(appIdFinal, appSecretFinal);
|
|
@@ -498,7 +511,9 @@ async function publishToWechatDraft(articleOptions, publishOptions = {}) {
|
|
|
498
511
|
content: html,
|
|
499
512
|
thumb_media_id: thumbMediaId,
|
|
500
513
|
author,
|
|
501
|
-
content_source_url: source_url
|
|
514
|
+
content_source_url: source_url,
|
|
515
|
+
need_open_comment: need_open_comment ? 1 : 0,
|
|
516
|
+
only_fans_can_comment: only_fans_can_comment ? 1 : 0
|
|
502
517
|
});
|
|
503
518
|
if (data.media_id) {
|
|
504
519
|
return data;
|
|
@@ -526,6 +541,52 @@ async function getAppIdAndSecret(appId, appSecret) {
|
|
|
526
541
|
}
|
|
527
542
|
throw new Error(`未能找到 AppID 为 "${appId}" 的公众号凭据,请检查配置文件。`);
|
|
528
543
|
}
|
|
544
|
+
async function publishImageTextToWechatDraft(articleOptions, publishOptions = {}) {
|
|
545
|
+
const { title, content, images, cover, author, need_open_comment, only_fans_can_comment } = articleOptions;
|
|
546
|
+
const { appId, appSecret, relativePath } = publishOptions;
|
|
547
|
+
const { appId: appIdFinal, appSecret: appSecretFinal } = await getAppIdAndSecret(appId, appSecret);
|
|
548
|
+
if (!images || images.length === 0) {
|
|
549
|
+
throw new Error("图片消息至少需要一张图片");
|
|
550
|
+
}
|
|
551
|
+
const accessToken = await wechatPublisher.getAccessTokenWithCache(appIdFinal, appSecretFinal);
|
|
552
|
+
const imageInfoList = [];
|
|
553
|
+
for (const img of images) {
|
|
554
|
+
const resp = await uploadImage(img, accessToken, void 0, relativePath);
|
|
555
|
+
imageInfoList.push({ image_media_id: resp.media_id });
|
|
556
|
+
}
|
|
557
|
+
let thumbMediaId = "";
|
|
558
|
+
if (cover) {
|
|
559
|
+
const cachedThumbMediaId = mediaIdMapping.get(cover);
|
|
560
|
+
if (cachedThumbMediaId) {
|
|
561
|
+
thumbMediaId = cachedThumbMediaId;
|
|
562
|
+
} else {
|
|
563
|
+
const resp = await uploadImage(cover, accessToken, "cover.jpg", relativePath);
|
|
564
|
+
thumbMediaId = resp.media_id;
|
|
565
|
+
}
|
|
566
|
+
} else {
|
|
567
|
+
thumbMediaId = imageInfoList[0].image_media_id;
|
|
568
|
+
}
|
|
569
|
+
if (!thumbMediaId) {
|
|
570
|
+
throw new Error("未能获取封面图的 media_id");
|
|
571
|
+
}
|
|
572
|
+
const data = await wechatPublisher.publishToDraft(
|
|
573
|
+
accessToken,
|
|
574
|
+
{
|
|
575
|
+
title,
|
|
576
|
+
content,
|
|
577
|
+
thumb_media_id: thumbMediaId,
|
|
578
|
+
author,
|
|
579
|
+
article_type: "newspic",
|
|
580
|
+
image_info: { image_list: imageInfoList },
|
|
581
|
+
need_open_comment: need_open_comment ? 1 : 0,
|
|
582
|
+
only_fans_can_comment: only_fans_can_comment ? 1 : 0
|
|
583
|
+
}
|
|
584
|
+
);
|
|
585
|
+
if (data.media_id) {
|
|
586
|
+
return data;
|
|
587
|
+
}
|
|
588
|
+
throw new Error(`上传图片消息到公众号草稿失败: ${JSON.stringify(data)}`);
|
|
589
|
+
}
|
|
529
590
|
const defaultConfig = {};
|
|
530
591
|
const configPath = path.join(configDir, "config.json");
|
|
531
592
|
class ConfigStore {
|
|
@@ -625,25 +686,22 @@ async function renderWithTheme(markdownContent, options) {
|
|
|
625
686
|
return gzhContent;
|
|
626
687
|
}
|
|
627
688
|
async function renderStyledContent(content, options = {}) {
|
|
628
|
-
const
|
|
629
|
-
const html = await wenyanCoreInstance.renderMarkdown(preHandlerContent.body);
|
|
689
|
+
const html = await wenyanCoreInstance.renderMarkdown(content);
|
|
630
690
|
const dom = new JSDOM(`<body><section id="wenyan">${html}</section></body>`);
|
|
631
691
|
const document = dom.window.document;
|
|
632
692
|
const wenyan = document.getElementById("wenyan");
|
|
633
693
|
const result = await wenyanCoreInstance.applyStylesWithTheme(wenyan, options);
|
|
634
|
-
return
|
|
635
|
-
content: result,
|
|
636
|
-
title: preHandlerContent.title,
|
|
637
|
-
cover: preHandlerContent.cover,
|
|
638
|
-
description: preHandlerContent.description,
|
|
639
|
-
author: preHandlerContent.author,
|
|
640
|
-
source_url: preHandlerContent.source_url
|
|
641
|
-
};
|
|
694
|
+
return result;
|
|
642
695
|
}
|
|
643
696
|
async function prepareRenderContext(inputContent, options, getInputContent) {
|
|
644
697
|
const { content, absoluteDirPath } = await getInputContent(inputContent, options.file);
|
|
645
|
-
const
|
|
646
|
-
|
|
698
|
+
const preHandlerContent = await wenyanCoreInstance.handleFrontMatter(content);
|
|
699
|
+
if (preHandlerContent.image_list && preHandlerContent.image_list.length > 0) {
|
|
700
|
+
return { gzhContent: preHandlerContent, absoluteDirPath };
|
|
701
|
+
}
|
|
702
|
+
const styledContent = await renderWithTheme(preHandlerContent.content, options);
|
|
703
|
+
preHandlerContent.content = styledContent;
|
|
704
|
+
return { gzhContent: preHandlerContent, absoluteDirPath };
|
|
647
705
|
}
|
|
648
706
|
async function listThemes() {
|
|
649
707
|
const themes = getAllGzhThemes();
|
|
@@ -705,30 +763,34 @@ async function checkCustomThemeExists(themeId) {
|
|
|
705
763
|
const customThemes = await configStore.getThemes();
|
|
706
764
|
return customThemes.some((theme) => theme.id === themeId);
|
|
707
765
|
}
|
|
708
|
-
async function getGzhContent(content, themeId, hlThemeId, isMacStyle = true, isAddFootnote = true) {
|
|
709
|
-
return await renderStyledContent(content, {
|
|
710
|
-
themeId,
|
|
711
|
-
hlThemeId,
|
|
712
|
-
isMacStyle,
|
|
713
|
-
isAddFootnote
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
766
|
async function renderAndPublish(inputContent, options, getInputContent) {
|
|
717
767
|
const { gzhContent, absoluteDirPath } = await prepareRenderContext(inputContent, options, getInputContent);
|
|
718
768
|
if (!gzhContent.title) throw new Error("未能找到文章标题");
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
769
|
+
let data;
|
|
770
|
+
if (gzhContent.image_list && gzhContent.image_list.length > 0) {
|
|
771
|
+
data = await publishImageTextToWechatDraft(
|
|
772
|
+
{
|
|
773
|
+
...gzhContent,
|
|
774
|
+
title: gzhContent.title,
|
|
775
|
+
images: gzhContent.image_list
|
|
776
|
+
},
|
|
777
|
+
{
|
|
778
|
+
appId: options.appId,
|
|
779
|
+
relativePath: absoluteDirPath
|
|
780
|
+
}
|
|
781
|
+
);
|
|
782
|
+
} else {
|
|
783
|
+
data = await publishToWechatDraft(
|
|
784
|
+
{
|
|
785
|
+
...gzhContent,
|
|
786
|
+
title: gzhContent.title
|
|
787
|
+
},
|
|
788
|
+
{
|
|
789
|
+
appId: options.appId,
|
|
790
|
+
relativePath: absoluteDirPath
|
|
791
|
+
}
|
|
792
|
+
);
|
|
793
|
+
}
|
|
732
794
|
if (data.media_id) {
|
|
733
795
|
return data.media_id;
|
|
734
796
|
} else {
|
|
@@ -743,7 +805,11 @@ async function renderAndPublishToServer(inputContent, options, getInputContent)
|
|
|
743
805
|
await verifyAuth(serverUrl, headers);
|
|
744
806
|
const { gzhContent, absoluteDirPath } = await prepareRenderContext(inputContent, options, getInputContent);
|
|
745
807
|
if (!gzhContent.title) throw new Error("未能找到文章标题");
|
|
746
|
-
gzhContent.
|
|
808
|
+
if (gzhContent.image_list && gzhContent.image_list.length > 0) {
|
|
809
|
+
gzhContent.image_list = await uploadImageList(serverUrl, headers, gzhContent.image_list, absoluteDirPath);
|
|
810
|
+
} else {
|
|
811
|
+
gzhContent.content = await uploadLocalImages(gzhContent.content, serverUrl, headers, absoluteDirPath);
|
|
812
|
+
}
|
|
747
813
|
gzhContent.cover = await uploadCover(serverUrl, headers, gzhContent.cover, absoluteDirPath);
|
|
748
814
|
const mdFileId = await uploadStyledContent(gzhContent, serverUrl, headers);
|
|
749
815
|
return await requestServerPublish(mdFileId, serverUrl, headers, options);
|
|
@@ -755,7 +821,6 @@ export {
|
|
|
755
821
|
configStore,
|
|
756
822
|
credentialStore,
|
|
757
823
|
ensureDir,
|
|
758
|
-
getGzhContent,
|
|
759
824
|
getNormalizeFilePath,
|
|
760
825
|
isAbsolutePath,
|
|
761
826
|
listThemes,
|
|
@@ -763,6 +828,7 @@ export {
|
|
|
763
828
|
md5FromFile,
|
|
764
829
|
normalizePath,
|
|
765
830
|
prepareRenderContext,
|
|
831
|
+
publishImageTextToWechatDraft,
|
|
766
832
|
publishToDraft,
|
|
767
833
|
publishToWechatDraft,
|
|
768
834
|
readBinaryFile,
|
|
@@ -771,7 +837,6 @@ export {
|
|
|
771
837
|
renderAndPublish,
|
|
772
838
|
renderAndPublishToServer,
|
|
773
839
|
renderStyledContent,
|
|
774
|
-
renderWithTheme,
|
|
775
840
|
safeReadJson,
|
|
776
841
|
safeWriteJson,
|
|
777
842
|
wechatPublisher
|
package/package.json
CHANGED