@wenyan-md/core 2.0.1 → 2.0.2
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/publish.js +1 -52
- package/dist/runtimeEnv-pU2mTDLR.js +56 -0
- package/dist/types/node/configStore.d.ts +27 -0
- package/dist/types/node/wrapper.d.ts +2 -0
- package/dist/wrapper.js +92 -0
- package/package.json +4 -5
package/dist/publish.js
CHANGED
|
@@ -2,61 +2,10 @@ import { JSDOM } from "jsdom";
|
|
|
2
2
|
import { fileFromPath } from "formdata-node/file-from-path";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { stat } from "node:fs/promises";
|
|
5
|
+
import { R as RuntimeEnv } from "./runtimeEnv-pU2mTDLR.js";
|
|
5
6
|
import { FormDataEncoder } from "form-data-encoder";
|
|
6
7
|
import { FormData } from "formdata-node";
|
|
7
8
|
import { Readable } from "node:stream";
|
|
8
|
-
function normalizePath(p) {
|
|
9
|
-
return p.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
10
|
-
}
|
|
11
|
-
function isAbsolutePath(path2) {
|
|
12
|
-
if (!path2) return false;
|
|
13
|
-
const winAbsPattern = /^[a-zA-Z]:\//;
|
|
14
|
-
const linuxAbsPattern = /^\//;
|
|
15
|
-
return winAbsPattern.test(path2) || linuxAbsPattern.test(path2);
|
|
16
|
-
}
|
|
17
|
-
const RuntimeEnv = {
|
|
18
|
-
isContainer: !!process.env.CONTAINERIZED,
|
|
19
|
-
hostFilePath: normalizePath(process.env.HOST_FILE_PATH || ""),
|
|
20
|
-
containerFilePath: normalizePath(process.env.CONTAINER_FILE_PATH || "/mnt/host-downloads"),
|
|
21
|
-
resolveLocalPath(inputPath, relativeBase) {
|
|
22
|
-
if (!this.isContainer) {
|
|
23
|
-
if (relativeBase) {
|
|
24
|
-
return path.resolve(relativeBase, inputPath);
|
|
25
|
-
} else {
|
|
26
|
-
if (!path.isAbsolute(inputPath)) {
|
|
27
|
-
throw new Error(
|
|
28
|
-
`Invalid input: '${inputPath}'. When relativeBase is not provided, inputPath must be an absolute path.`
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
return path.normalize(inputPath);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
let normalizedInput = normalizePath(inputPath);
|
|
35
|
-
relativeBase = normalizePath(relativeBase || "");
|
|
36
|
-
if (relativeBase) {
|
|
37
|
-
if (!isAbsolutePath(normalizedInput)) {
|
|
38
|
-
normalizedInput = relativeBase + (normalizedInput.startsWith("/") ? "" : "/") + normalizedInput;
|
|
39
|
-
}
|
|
40
|
-
} else {
|
|
41
|
-
if (!isAbsolutePath(normalizedInput)) {
|
|
42
|
-
throw new Error(
|
|
43
|
-
`Invalid input: '${inputPath}'. When relativeBase is not provided, inputPath must be an absolute path.`
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (normalizedInput.startsWith(this.hostFilePath)) {
|
|
48
|
-
let relativePart = normalizedInput.slice(this.hostFilePath.length);
|
|
49
|
-
if (relativePart && !relativePart.startsWith("/")) {
|
|
50
|
-
return normalizedInput;
|
|
51
|
-
}
|
|
52
|
-
if (!relativePart.startsWith("/")) {
|
|
53
|
-
relativePart = "/" + relativePart;
|
|
54
|
-
}
|
|
55
|
-
return this.containerFilePath + relativePart;
|
|
56
|
-
}
|
|
57
|
-
return normalizedInput;
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
9
|
const tokenUrl = "https://api.weixin.qq.com/cgi-bin/token";
|
|
61
10
|
const publishUrl = "https://api.weixin.qq.com/cgi-bin/draft/add";
|
|
62
11
|
const uploadUrl = "https://api.weixin.qq.com/cgi-bin/material/add_material";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
function normalizePath(p) {
|
|
3
|
+
return p.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
4
|
+
}
|
|
5
|
+
function isAbsolutePath(path2) {
|
|
6
|
+
if (!path2) return false;
|
|
7
|
+
const winAbsPattern = /^[a-zA-Z]:\//;
|
|
8
|
+
const linuxAbsPattern = /^\//;
|
|
9
|
+
return winAbsPattern.test(path2) || linuxAbsPattern.test(path2);
|
|
10
|
+
}
|
|
11
|
+
const RuntimeEnv = {
|
|
12
|
+
isContainer: !!process.env.CONTAINERIZED,
|
|
13
|
+
hostFilePath: normalizePath(process.env.HOST_FILE_PATH || ""),
|
|
14
|
+
containerFilePath: normalizePath(process.env.CONTAINER_FILE_PATH || "/mnt/host-downloads"),
|
|
15
|
+
resolveLocalPath(inputPath, relativeBase) {
|
|
16
|
+
if (!this.isContainer) {
|
|
17
|
+
if (relativeBase) {
|
|
18
|
+
return path.resolve(relativeBase, inputPath);
|
|
19
|
+
} else {
|
|
20
|
+
if (!path.isAbsolute(inputPath)) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`Invalid input: '${inputPath}'. When relativeBase is not provided, inputPath must be an absolute path.`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
return path.normalize(inputPath);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
let normalizedInput = normalizePath(inputPath);
|
|
29
|
+
relativeBase = normalizePath(relativeBase || "");
|
|
30
|
+
if (relativeBase) {
|
|
31
|
+
if (!isAbsolutePath(normalizedInput)) {
|
|
32
|
+
normalizedInput = relativeBase + (normalizedInput.startsWith("/") ? "" : "/") + normalizedInput;
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
if (!isAbsolutePath(normalizedInput)) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Invalid input: '${inputPath}'. When relativeBase is not provided, inputPath must be an absolute path.`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (normalizedInput.startsWith(this.hostFilePath)) {
|
|
42
|
+
let relativePart = normalizedInput.slice(this.hostFilePath.length);
|
|
43
|
+
if (relativePart && !relativePart.startsWith("/")) {
|
|
44
|
+
return normalizedInput;
|
|
45
|
+
}
|
|
46
|
+
if (!relativePart.startsWith("/")) {
|
|
47
|
+
relativePart = "/" + relativePart;
|
|
48
|
+
}
|
|
49
|
+
return this.containerFilePath + relativePart;
|
|
50
|
+
}
|
|
51
|
+
return normalizedInput;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
export {
|
|
55
|
+
RuntimeEnv as R
|
|
56
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface WenyanConfig {
|
|
2
|
+
themes?: Record<string, ThemeConfigOptions>;
|
|
3
|
+
}
|
|
4
|
+
export interface ThemeConfigOptions {
|
|
5
|
+
id: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
path: string;
|
|
9
|
+
}
|
|
10
|
+
export declare const configDir: string;
|
|
11
|
+
export declare const configPath: string;
|
|
12
|
+
declare class ConfigStore {
|
|
13
|
+
private config;
|
|
14
|
+
constructor();
|
|
15
|
+
private load;
|
|
16
|
+
private save;
|
|
17
|
+
private mkdirIfNotExists;
|
|
18
|
+
getConfig(): WenyanConfig;
|
|
19
|
+
addThemeToConfig(name: string, content: string): void;
|
|
20
|
+
getThemes(): ThemeConfigOptions[];
|
|
21
|
+
getThemeById(themeId: string): string | undefined;
|
|
22
|
+
addThemeFile(themeId: string, themeContent: string): string;
|
|
23
|
+
deleteThemeFromConfig(themeId: string): void;
|
|
24
|
+
deleteThemeFile(filePath: string): void;
|
|
25
|
+
}
|
|
26
|
+
export declare const configStore: ConfigStore;
|
|
27
|
+
export {};
|
|
@@ -7,3 +7,5 @@ export interface StyledContent {
|
|
|
7
7
|
}
|
|
8
8
|
export declare function renderStyledContent(content: string, options?: ApplyStylesOptions): Promise<StyledContent>;
|
|
9
9
|
export declare function getGzhContent(content: string, themeId: string, hlThemeId: string, isMacStyle?: boolean, isAddFootnote?: boolean): Promise<StyledContent>;
|
|
10
|
+
export * from "./configStore.js";
|
|
11
|
+
export * from "./runtimeEnv.js";
|
package/dist/wrapper.js
CHANGED
|
@@ -1,5 +1,93 @@
|
|
|
1
1
|
import { JSDOM } from "jsdom";
|
|
2
2
|
import { createWenyanCore } from "./core.js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import { R } from "./runtimeEnv-pU2mTDLR.js";
|
|
7
|
+
const defaultConfig = {};
|
|
8
|
+
const configDir = process.env.APPDATA ? path.join(process.env.APPDATA, "wenyan-md") : path.join(os.homedir(), ".config", "wenyan-md");
|
|
9
|
+
const configPath = path.join(configDir, "config.json");
|
|
10
|
+
class ConfigStore {
|
|
11
|
+
config = { ...defaultConfig };
|
|
12
|
+
constructor() {
|
|
13
|
+
this.load();
|
|
14
|
+
}
|
|
15
|
+
load() {
|
|
16
|
+
if (fs.existsSync(configPath)) {
|
|
17
|
+
try {
|
|
18
|
+
const fileContent = fs.readFileSync(configPath, "utf-8");
|
|
19
|
+
this.config = { ...defaultConfig, ...JSON.parse(fileContent) };
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.warn("⚠️ 配置文件解析失败,将使用默认配置");
|
|
22
|
+
this.config = { ...defaultConfig };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
save() {
|
|
27
|
+
this.mkdirIfNotExists();
|
|
28
|
+
try {
|
|
29
|
+
fs.writeFileSync(configPath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error("❌ 无法保存配置文件:", error);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
mkdirIfNotExists(dir = configDir) {
|
|
35
|
+
try {
|
|
36
|
+
if (!fs.existsSync(dir)) {
|
|
37
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error("❌ 无法创建配置目录:", error);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
getConfig() {
|
|
44
|
+
return this.config;
|
|
45
|
+
}
|
|
46
|
+
addThemeToConfig(name, content) {
|
|
47
|
+
const savedPath = this.addThemeFile(name, content);
|
|
48
|
+
this.config.themes = this.config.themes || {};
|
|
49
|
+
this.config.themes[name] = {
|
|
50
|
+
id: name,
|
|
51
|
+
name,
|
|
52
|
+
path: savedPath
|
|
53
|
+
};
|
|
54
|
+
this.save();
|
|
55
|
+
}
|
|
56
|
+
getThemes() {
|
|
57
|
+
return this.config.themes ? Object.values(this.config.themes) : [];
|
|
58
|
+
}
|
|
59
|
+
getThemeById(themeId) {
|
|
60
|
+
const themeOption = this.config.themes ? this.config.themes[themeId] : void 0;
|
|
61
|
+
if (themeOption) {
|
|
62
|
+
const absoluteFilePath = path.join(configDir, themeOption.path);
|
|
63
|
+
if (fs.existsSync(absoluteFilePath)) {
|
|
64
|
+
return fs.readFileSync(absoluteFilePath, "utf-8");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return void 0;
|
|
68
|
+
}
|
|
69
|
+
addThemeFile(themeId, themeContent) {
|
|
70
|
+
const filePath = `themes/${themeId}.css`;
|
|
71
|
+
const absoluteFilePath = path.join(configDir, filePath);
|
|
72
|
+
this.mkdirIfNotExists(path.dirname(absoluteFilePath));
|
|
73
|
+
fs.writeFileSync(absoluteFilePath, themeContent, "utf-8");
|
|
74
|
+
return filePath;
|
|
75
|
+
}
|
|
76
|
+
deleteThemeFromConfig(themeId) {
|
|
77
|
+
if (this.config.themes && this.config.themes[themeId]) {
|
|
78
|
+
this.deleteThemeFile(this.config.themes[themeId].path);
|
|
79
|
+
delete this.config.themes[themeId];
|
|
80
|
+
this.save();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
deleteThemeFile(filePath) {
|
|
84
|
+
const absoluteFilePath = path.join(configDir, filePath);
|
|
85
|
+
if (fs.existsSync(absoluteFilePath)) {
|
|
86
|
+
fs.unlinkSync(absoluteFilePath);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const configStore = new ConfigStore();
|
|
3
91
|
const wenyanCoreInstance = await createWenyanCore();
|
|
4
92
|
async function renderStyledContent(content, options = {}) {
|
|
5
93
|
const preHandlerContent = await wenyanCoreInstance.handleFrontMatter(content);
|
|
@@ -24,6 +112,10 @@ async function getGzhContent(content, themeId, hlThemeId, isMacStyle = true, isA
|
|
|
24
112
|
});
|
|
25
113
|
}
|
|
26
114
|
export {
|
|
115
|
+
R as RuntimeEnv,
|
|
116
|
+
configDir,
|
|
117
|
+
configPath,
|
|
118
|
+
configStore,
|
|
27
119
|
getGzhContent,
|
|
28
120
|
renderStyledContent
|
|
29
121
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wenyan-md/core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Core library for Wenyan markdown rendering & publishing",
|
|
5
5
|
"author": "Lei <caol64@gmail.com> (https://github.com/caol64)",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -44,7 +44,6 @@
|
|
|
44
44
|
"@types/css-tree": "^2.3.11",
|
|
45
45
|
"@types/jsdom": "^27.0.0",
|
|
46
46
|
"@types/node": "^24.3.0",
|
|
47
|
-
"ts-lib": "^0.0.5",
|
|
48
47
|
"typescript": "^5.9.2",
|
|
49
48
|
"vite": "^7.1.4",
|
|
50
49
|
"vitest": "^3.2.4"
|
|
@@ -58,9 +57,9 @@
|
|
|
58
57
|
"mathjax-full": "3.2.2"
|
|
59
58
|
},
|
|
60
59
|
"peerDependencies": {
|
|
61
|
-
"jsdom": "^27.4.0",
|
|
62
60
|
"form-data-encoder": "^4.1.0",
|
|
63
|
-
"formdata-node": "^6.0.3"
|
|
61
|
+
"formdata-node": "^6.0.3",
|
|
62
|
+
"jsdom": "^27.4.0"
|
|
64
63
|
},
|
|
65
64
|
"peerDependenciesMeta": {
|
|
66
65
|
"jsdom": {
|
|
@@ -76,7 +75,7 @@
|
|
|
76
75
|
"scripts": {
|
|
77
76
|
"dev": "vite build --watch",
|
|
78
77
|
"check": "tsc --noEmit",
|
|
79
|
-
"build": "
|
|
78
|
+
"build": "vite build && tsc",
|
|
80
79
|
"build:browser": "vite build --config vite.config.browser.ts",
|
|
81
80
|
"build:styles": "vite build --config vite.config.styles.ts",
|
|
82
81
|
"build:math": "vite build --config vite.config.math.ts",
|