@lyhue1991/wxgzh 0.1.0

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.
Files changed (50) hide show
  1. package/README.md +432 -0
  2. package/assets/backgrounds//345/217/214/347/214/253.jpg +0 -0
  3. package/assets/backgrounds//345/217/244/351/243/216.jpg +0 -0
  4. package/assets/backgrounds//345/217/244/351/243/2162.jpg +0 -0
  5. package/assets/backgrounds//345/260/221/345/245/263/346/230/237/347/251/272.jpg +0 -0
  6. package/assets/backgrounds//345/277/203/345/277/203/347/233/270/345/215/260.jpg +0 -0
  7. package/assets/backgrounds//346/230/237/347/251/272.jpg +0 -0
  8. package/assets/backgrounds//346/240/221/346/234/250.jpg +0 -0
  9. package/assets/backgrounds//346/260/264/345/275/251.jpg +0 -0
  10. package/assets/backgrounds//346/260/264/346/274/253.jpg +0 -0
  11. package/assets/backgrounds//346/265/267/346/230/237.jpg +0 -0
  12. package/assets/backgrounds//346/265/267/346/273/251.jpg +0 -0
  13. package/assets/backgrounds//346/265/267/350/261/232.jpg +0 -0
  14. package/assets/backgrounds//346/270/205/346/231/250.jpg +0 -0
  15. package/assets/backgrounds//347/203/255/346/260/224/347/220/203.jpg +0 -0
  16. package/assets/backgrounds//347/214/253/345/222/252/345/245/263/345/255/251.jpg +0 -0
  17. package/assets/backgrounds//347/223/246/345/212/233.jpg +0 -0
  18. package/assets/backgrounds//347/272/242/345/217/266/351/243/230/351/243/230.jpg +0 -0
  19. package/assets/backgrounds//350/212/261/346/234/265.jpg +0 -0
  20. package/assets/backgrounds//351/243/216/350/275/246.jpg +0 -0
  21. package/assets/backgrounds//351/273/204/346/230/217.jpg +0 -0
  22. package/bin/wxgzh.js +3 -0
  23. package/dist/cli/config.js +62 -0
  24. package/dist/cli/cover.js +39 -0
  25. package/dist/cli/fix.js +38 -0
  26. package/dist/cli/index.js +161 -0
  27. package/dist/cli/md2html.js +49 -0
  28. package/dist/cli/publish.js +56 -0
  29. package/dist/core/converter.js +656 -0
  30. package/dist/core/cover.js +164 -0
  31. package/dist/core/fixer.js +97 -0
  32. package/dist/core/parser.js +105 -0
  33. package/dist/core/themes.js +59 -0
  34. package/dist/core/wechat.js +162 -0
  35. package/dist/types.js +2 -0
  36. package/dist/utils/config.js +89 -0
  37. package/dist/utils/fs.js +20 -0
  38. package/dist/utils/logger.js +18 -0
  39. package/dist/utils/tls.js +46 -0
  40. package/package.json +47 -0
  41. package/spec.md +490 -0
  42. package/styles/black.css +600 -0
  43. package/styles/blue.css +616 -0
  44. package/styles/brown.css +620 -0
  45. package/styles/custom.css +8 -0
  46. package/styles/default.css +227 -0
  47. package/styles/green.css +617 -0
  48. package/styles/orange.css +617 -0
  49. package/styles/red.css +617 -0
  50. package/styles/yellow.css +202 -0
@@ -0,0 +1,656 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.renderMarkdownToHtml = renderMarkdownToHtml;
40
+ exports.extractPublishableContent = extractPublishableContent;
41
+ exports.readHtmlMetadata = readHtmlMetadata;
42
+ const promises_1 = require("node:fs/promises");
43
+ const node_path_1 = __importDefault(require("node:path"));
44
+ const cheerio = __importStar(require("cheerio"));
45
+ const highlight_js_1 = __importDefault(require("highlight.js"));
46
+ const juice_1 = __importDefault(require("juice"));
47
+ const markdown_it_1 = __importDefault(require("markdown-it"));
48
+ const markdown_it_mathjax3_1 = __importDefault(require("markdown-it-mathjax3"));
49
+ const themes_1 = require("./themes");
50
+ const HIGHLIGHT_INLINE_CSS = `
51
+ .hljs-comment,
52
+ .hljs-quote {
53
+ color: #6a9955;
54
+ font-style: italic;
55
+ }
56
+
57
+ .hljs-keyword,
58
+ .hljs-selector-tag,
59
+ .hljs-literal,
60
+ .hljs-section,
61
+ .hljs-link,
62
+ .hljs-meta .hljs-keyword {
63
+ color: #c586c0;
64
+ font-weight: 600;
65
+ }
66
+
67
+ .hljs-string,
68
+ .hljs-regexp,
69
+ .hljs-symbol,
70
+ .hljs-bullet,
71
+ .hljs-addition,
72
+ .hljs-template-tag,
73
+ .hljs-template-variable {
74
+ color: #ce9178;
75
+ }
76
+
77
+ .hljs-number,
78
+ .hljs-literal,
79
+ .hljs-meta,
80
+ .hljs-selector-attr,
81
+ .hljs-selector-pseudo,
82
+ .hljs-attr,
83
+ .hljs-attribute {
84
+ color: #b5cea8;
85
+ }
86
+
87
+ .hljs-built_in,
88
+ .hljs-type,
89
+ .hljs-name,
90
+ .hljs-selector-class,
91
+ .hljs-selector-id {
92
+ color: #4ec9b0;
93
+ }
94
+
95
+ .hljs-title,
96
+ .hljs-title.class_,
97
+ .hljs-title.class_.inherited__,
98
+ .hljs-title.function_,
99
+ .hljs-function .hljs-title,
100
+ .hljs-class .hljs-title {
101
+ color: #dcdcaa;
102
+ }
103
+
104
+ .hljs-variable,
105
+ .hljs-params,
106
+ .hljs-operator,
107
+ .hljs-punctuation,
108
+ .hljs-subst,
109
+ .hljs-deletion,
110
+ .hljs-property {
111
+ color: #d4d4d4;
112
+ }
113
+
114
+ .hljs-emphasis {
115
+ font-style: italic;
116
+ }
117
+
118
+ .hljs-strong {
119
+ font-weight: 700;
120
+ }
121
+ `;
122
+ const WECHAT_BLOCKQUOTE_INLINE_CSS = `
123
+ blockquote,
124
+ q {
125
+ margin: 1.2em 3% !important;
126
+ padding: 0 0 0 1em !important;
127
+ border: 0 !important;
128
+ border-left: 4px solid #d9d9d9 !important;
129
+ border-radius: 0 !important;
130
+ background: transparent !important;
131
+ color: #8c8c8c !important;
132
+ quotes: none;
133
+ }
134
+
135
+ blockquote p,
136
+ blockquote ul,
137
+ blockquote ol,
138
+ blockquote section,
139
+ blockquote pre,
140
+ blockquote table,
141
+ q p,
142
+ q ul,
143
+ q ol,
144
+ q section,
145
+ q pre,
146
+ q table {
147
+ margin: 0.45em 0 !important;
148
+ color: inherit !important;
149
+ }
150
+
151
+ blockquote p:first-child,
152
+ blockquote ul:first-child,
153
+ blockquote ol:first-child,
154
+ blockquote section:first-child,
155
+ blockquote pre:first-child,
156
+ blockquote table:first-child,
157
+ q p:first-child,
158
+ q ul:first-child,
159
+ q ol:first-child,
160
+ q section:first-child,
161
+ q pre:first-child,
162
+ q table:first-child {
163
+ margin-top: 0 !important;
164
+ }
165
+
166
+ blockquote p:last-child,
167
+ blockquote ul:last-child,
168
+ blockquote ol:last-child,
169
+ blockquote section:last-child,
170
+ blockquote pre:last-child,
171
+ blockquote table:last-child,
172
+ q p:last-child,
173
+ q ul:last-child,
174
+ q ol:last-child,
175
+ q section:last-child,
176
+ q pre:last-child,
177
+ q table:last-child {
178
+ margin-bottom: 0 !important;
179
+ }
180
+ `;
181
+ const WECHAT_TABLE_INLINE_CSS = `
182
+ section.tbl-wrapper {
183
+ margin: 1.4em 3% !important;
184
+ padding: 0 0 10px 0 !important;
185
+ overflow-x: auto !important;
186
+ overflow-y: hidden !important;
187
+ -webkit-overflow-scrolling: touch;
188
+ background: transparent !important;
189
+ }
190
+
191
+ section.tbl-wrapper table {
192
+ width: max-content !important;
193
+ min-width: 100% !important;
194
+ margin: 0 !important;
195
+ border-collapse: collapse !important;
196
+ border-spacing: 0 !important;
197
+ table-layout: auto !important;
198
+ background: #ffffff !important;
199
+ font-size: 15px !important;
200
+ line-height: 1.75 !important;
201
+ }
202
+
203
+ section.tbl-wrapper thead,
204
+ section.tbl-wrapper tbody,
205
+ section.tbl-wrapper tr {
206
+ background: #ffffff !important;
207
+ }
208
+
209
+ section.tbl-wrapper th,
210
+ section.tbl-wrapper td {
211
+ min-width: 120px !important;
212
+ padding: 14px 16px !important;
213
+ border: 1px solid #d9d9d9 !important;
214
+ text-align: left !important;
215
+ vertical-align: middle !important;
216
+ white-space: nowrap !important;
217
+ }
218
+
219
+ section.tbl-wrapper th {
220
+ background: #fafafa !important;
221
+ color: #444444 !important;
222
+ font-weight: 700 !important;
223
+ }
224
+
225
+ section.tbl-wrapper td {
226
+ color: #4f638f !important;
227
+ }
228
+
229
+ section.tbl-wrapper a {
230
+ color: #4f638f !important;
231
+ text-decoration: none !important;
232
+ }
233
+ `;
234
+ const WECHAT_MATH_INLINE_CSS = `
235
+ span.math-inline {
236
+ display: inline-block !important;
237
+ max-width: 100% !important;
238
+ margin: 0 0.12em !important;
239
+ vertical-align: middle !important;
240
+ }
241
+
242
+ span.math-inline mjx-container {
243
+ display: inline-block !important;
244
+ max-width: 100% !important;
245
+ color: #111111 !important;
246
+ vertical-align: middle !important;
247
+ }
248
+
249
+ section.math-block {
250
+ margin: 1.4em 3% !important;
251
+ overflow-x: auto !important;
252
+ overflow-y: hidden !important;
253
+ text-align: center !important;
254
+ -webkit-overflow-scrolling: touch;
255
+ }
256
+
257
+ section.math-block mjx-container {
258
+ display: inline-block !important;
259
+ min-width: min-content !important;
260
+ color: #111111 !important;
261
+ }
262
+
263
+ section.math-block mjx-container > svg,
264
+ span.math-inline mjx-container > svg {
265
+ display: block !important;
266
+ }
267
+ `;
268
+ const LANGUAGE_ALIASES = {
269
+ 'c#': 'csharp',
270
+ 'c++': 'cpp',
271
+ bash: 'bash',
272
+ console: 'bash',
273
+ js: 'javascript',
274
+ jsx: 'javascript',
275
+ py: 'python',
276
+ py3: 'python',
277
+ python3: 'python',
278
+ rs: 'rust',
279
+ sh: 'bash',
280
+ shell: 'bash',
281
+ text: null,
282
+ plaintext: null,
283
+ txt: null,
284
+ ts: 'typescript',
285
+ tsx: 'typescript',
286
+ yml: 'yaml',
287
+ zsh: 'bash'
288
+ };
289
+ function resolveHighlightLanguage(language) {
290
+ const raw = language.trim().toLowerCase();
291
+ if (!raw) {
292
+ return '';
293
+ }
294
+ const token = raw
295
+ .replace(/^[{\[]|[}\]]$/g, '')
296
+ .replace(/^language-/, '')
297
+ .replace(/^lang-/, '')
298
+ .split(/[\s,{]/, 1)[0]
299
+ ?.trim();
300
+ if (!token) {
301
+ return '';
302
+ }
303
+ if (Object.prototype.hasOwnProperty.call(LANGUAGE_ALIASES, token)) {
304
+ return LANGUAGE_ALIASES[token];
305
+ }
306
+ return token;
307
+ }
308
+ function renderHighlightedCode(code, language) {
309
+ const normalizedLanguage = resolveHighlightLanguage(language);
310
+ if (normalizedLanguage === null) {
311
+ return escapeHtml(code);
312
+ }
313
+ if (normalizedLanguage && highlight_js_1.default.getLanguage(normalizedLanguage)) {
314
+ return highlight_js_1.default.highlight(code, { language: normalizedLanguage }).value;
315
+ }
316
+ return highlight_js_1.default.highlightAuto(code).value;
317
+ }
318
+ const markdown = new markdown_it_1.default({
319
+ html: true,
320
+ linkify: true,
321
+ breaks: false,
322
+ highlight(code, language) {
323
+ const normalizedLanguage = resolveHighlightLanguage(language);
324
+ const highlighted = renderHighlightedCode(code, language);
325
+ const languageClass = normalizedLanguage ? ` language-${normalizedLanguage}` : '';
326
+ return `<pre><code class="hljs${languageClass}">${highlighted}</code></pre>`;
327
+ }
328
+ });
329
+ markdown.use(markdown_it_mathjax3_1.default);
330
+ const DEFAULT_THEME = (0, themes_1.getDefaultThemeName)();
331
+ const VOID_HTML_TAGS = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
332
+ function escapeHtml(value) {
333
+ return value
334
+ .replace(/&/g, '&amp;')
335
+ .replace(/</g, '&lt;')
336
+ .replace(/>/g, '&gt;')
337
+ .replace(/"/g, '&quot;');
338
+ }
339
+ function escapeHtmlAttribute(value) {
340
+ return escapeHtml(value);
341
+ }
342
+ function isTextNodeEmpty(node) {
343
+ return node.type === 'text' && !node.data.trim();
344
+ }
345
+ function isStandaloneImageParagraph($paragraph) {
346
+ const nodes = $paragraph.contents().toArray().filter((node) => !isTextNodeEmpty(node));
347
+ return nodes.every((node) => node.type === 'tag' && ['img', 'br'].includes(node.tagName.toLowerCase()));
348
+ }
349
+ function getStylesRoot() {
350
+ return node_path_1.default.resolve(__dirname, '../../styles');
351
+ }
352
+ function getThemeCssPath(theme) {
353
+ return node_path_1.default.join(getStylesRoot(), `${theme}.css`);
354
+ }
355
+ async function pathExists(filePath) {
356
+ try {
357
+ await (0, promises_1.access)(filePath);
358
+ return true;
359
+ }
360
+ catch {
361
+ return false;
362
+ }
363
+ }
364
+ function getCustomCssPath() {
365
+ return node_path_1.default.join(getStylesRoot(), 'custom.css');
366
+ }
367
+ async function loadThemeCss(theme) {
368
+ const resolvedTheme = (theme ?? DEFAULT_THEME).trim() || DEFAULT_THEME;
369
+ if (resolvedTheme === DEFAULT_THEME || !(0, themes_1.isValidTheme)(resolvedTheme)) {
370
+ return (0, promises_1.readFile)(getThemeCssPath(DEFAULT_THEME), 'utf8');
371
+ }
372
+ return (0, promises_1.readFile)(getThemeCssPath(resolvedTheme), 'utf8');
373
+ }
374
+ async function loadCustomCss() {
375
+ const customCssPath = getCustomCssPath();
376
+ if (!(await pathExists(customCssPath))) {
377
+ return '';
378
+ }
379
+ return (0, promises_1.readFile)(customCssPath, 'utf8');
380
+ }
381
+ function normalizeListItems($) {
382
+ $('li').each((_, element) => {
383
+ const $item = $(element);
384
+ const childElements = $item
385
+ .contents()
386
+ .toArray()
387
+ .filter((node) => !isTextNodeEmpty(node));
388
+ if (childElements.length === 0) {
389
+ return;
390
+ }
391
+ const hasBlockChild = childElements.some((node) => {
392
+ if (node.type !== 'tag') {
393
+ return false;
394
+ }
395
+ const tagName = node.tagName.toLowerCase();
396
+ return ['p', 'ul', 'ol', 'section', 'blockquote', 'pre', 'table'].includes(tagName);
397
+ });
398
+ const firstChild = childElements[0];
399
+ if (!hasBlockChild && firstChild?.type === 'tag' && firstChild.tagName.toLowerCase() === 'span' && childElements.length === 1) {
400
+ return;
401
+ }
402
+ if (hasBlockChild) {
403
+ return;
404
+ }
405
+ $item.html(`<span>${$item.html() ?? ''}</span>`);
406
+ });
407
+ }
408
+ function normalizeImages($) {
409
+ $('img').each((_, element) => {
410
+ const $image = $(element);
411
+ const parent = $image.parent();
412
+ const parentTag = parent.get(0)?.type === 'tag' ? parent.get(0).tagName.toLowerCase() : undefined;
413
+ if (parentTag === 'section' && parent.attr('data-wxgzh') === 'image') {
414
+ parent.addClass('img-wrapper');
415
+ return;
416
+ }
417
+ if (parentTag === 'p') {
418
+ if (isStandaloneImageParagraph(parent)) {
419
+ parent.replaceWith(`<section class="img-wrapper" data-wxgzh="image">${$.html($image)}</section>`);
420
+ }
421
+ else {
422
+ $image.wrap('<section class="img-wrapper" data-wxgzh="image"></section>');
423
+ }
424
+ return;
425
+ }
426
+ $image.wrap('<section class="img-wrapper" data-wxgzh="image"></section>');
427
+ });
428
+ }
429
+ function normalizeTables($) {
430
+ $('table').each((_, element) => {
431
+ const $table = $(element);
432
+ const parent = $table.parent();
433
+ const parentTag = parent.get(0)?.type === 'tag' ? parent.get(0).tagName.toLowerCase() : undefined;
434
+ if (parentTag === 'section' && parent.attr('data-wxgzh') === 'table') {
435
+ parent.addClass('tbl-wrapper');
436
+ return;
437
+ }
438
+ $table.wrap('<section class="tbl-wrapper" data-wxgzh="table"></section>');
439
+ });
440
+ }
441
+ function renderSoftBreakFriendlyHtml(nodes, preserveSoftBreak = true) {
442
+ return nodes.map((node) => renderSoftBreakFriendlyNode(node, preserveSoftBreak)).join('');
443
+ }
444
+ function renderSoftBreakFriendlyNode(node, preserveSoftBreak) {
445
+ if (node.type === 'text') {
446
+ return renderSoftBreakFriendlyText(node, preserveSoftBreak);
447
+ }
448
+ if (node.type !== 'tag') {
449
+ return '';
450
+ }
451
+ const element = node;
452
+ const tagName = element.tagName.toLowerCase();
453
+ const attributes = Object.entries(element.attribs ?? {})
454
+ .map(([key, value]) => ` ${key}="${escapeHtmlAttribute(String(value))}"`)
455
+ .join('');
456
+ if (VOID_HTML_TAGS.has(tagName)) {
457
+ return `<${tagName}${attributes}>`;
458
+ }
459
+ const nextPreserveSoftBreak = preserveSoftBreak && !['code', 'pre'].includes(tagName);
460
+ const children = renderSoftBreakFriendlyHtml(element.children ?? [], nextPreserveSoftBreak);
461
+ return `<${tagName}${attributes}>${children}</${tagName}>`;
462
+ }
463
+ function renderSoftBreakFriendlyText(node, preserveSoftBreak) {
464
+ const normalized = node.data.replace(/\r\n?/g, '\n');
465
+ if (!preserveSoftBreak || !normalized.includes('\n')) {
466
+ return escapeHtml(normalized);
467
+ }
468
+ return normalized.split('\n').map((segment) => escapeHtml(segment)).join('<br>');
469
+ }
470
+ function normalizeBlockquoteSoftBreaks($) {
471
+ $('blockquote p, q p').each((_, element) => {
472
+ const paragraph = element;
473
+ $(paragraph).html(renderSoftBreakFriendlyHtml(paragraph.children ?? []));
474
+ });
475
+ }
476
+ function normalizeMathFormulas($) {
477
+ $('span[id^="mjx-"]').each((_, element) => {
478
+ const $wrapper = $(element);
479
+ const $container = $wrapper.find('mjx-container').first();
480
+ if ($container.length === 0) {
481
+ return;
482
+ }
483
+ $wrapper.find('style, mjx-assistive-mml').remove();
484
+ const isDisplay = $container.attr('display') === 'true';
485
+ $container.removeAttr('style');
486
+ if (isDisplay) {
487
+ $wrapper.replaceWith(`<section class="math-block" data-wxgzh="math-block">${$.html($container)}</section>`);
488
+ return;
489
+ }
490
+ $wrapper.replaceWith(`<span class="math-inline" data-wxgzh="math-inline">${$.html($container)}</span>`);
491
+ });
492
+ $('section > eqn').each((_, element) => {
493
+ const $eqn = $(element);
494
+ const $container = $eqn.find('mjx-container').first();
495
+ if ($container.length === 0) {
496
+ return;
497
+ }
498
+ $eqn.find('style, mjx-assistive-mml').remove();
499
+ $container.removeAttr('style');
500
+ $eqn.replaceWith(`<section class="math-block" data-wxgzh="math-block">${$.html($container)}</section>`);
501
+ });
502
+ $('eq').each((_, element) => {
503
+ const $eq = $(element);
504
+ const $container = $eq.find('mjx-container').first();
505
+ if ($container.length === 0) {
506
+ return;
507
+ }
508
+ $eq.find('style, mjx-assistive-mml').remove();
509
+ $container.removeAttr('style');
510
+ $eq.replaceWith(`<span class="math-inline" data-wxgzh="math-inline">${$.html($container)}</span>`);
511
+ });
512
+ }
513
+ function createMetadataTags(metadata) {
514
+ const entries = Object.entries(metadata).filter(([, value]) => value !== undefined);
515
+ return entries
516
+ .map(([key, value]) => `<meta name="wxgzh:${key}" content="${escapeHtmlAttribute(String(value))}">`)
517
+ .join('\n');
518
+ }
519
+ function createDocumentHtml(content, metadata) {
520
+ return [
521
+ '<!DOCTYPE html>',
522
+ '<html lang="zh-CN">',
523
+ '<head>',
524
+ ' <meta charset="UTF-8">',
525
+ ` <title>${escapeHtmlAttribute(metadata.title ?? 'wxgzh article')}</title>`,
526
+ ` ${createMetadataTags(metadata)}`,
527
+ '</head>',
528
+ '<body>',
529
+ ` <div id="write" class="wrapper"><article>${content}</article></div>`,
530
+ '</body>',
531
+ '</html>'
532
+ ].join('\n');
533
+ }
534
+ function setInlineStyleProperty(existingStyle, property, value) {
535
+ const entries = new Map();
536
+ if (existingStyle) {
537
+ for (const declaration of existingStyle.split(';')) {
538
+ const trimmed = declaration.trim();
539
+ if (!trimmed) {
540
+ continue;
541
+ }
542
+ const separatorIndex = trimmed.indexOf(':');
543
+ if (separatorIndex === -1) {
544
+ continue;
545
+ }
546
+ const name = trimmed.slice(0, separatorIndex).trim();
547
+ const declarationValue = trimmed.slice(separatorIndex + 1).trim();
548
+ if (!name || !declarationValue) {
549
+ continue;
550
+ }
551
+ entries.set(name, declarationValue);
552
+ }
553
+ }
554
+ entries.set(property, value);
555
+ return Array.from(entries.entries())
556
+ .map(([name, declarationValue]) => `${name}: ${declarationValue}`)
557
+ .join('; ');
558
+ }
559
+ function cleanInlinedHtml(html) {
560
+ const $ = cheerio.load(html);
561
+ $('pre > code').each((_, element) => {
562
+ const $element = $(element);
563
+ $element.html(renderWechatFriendlyCodeHtml($element.contents().toArray()));
564
+ });
565
+ const $article = $('body > #write > article').first();
566
+ const $firstChild = $article.children().first();
567
+ if ($firstChild.length > 0) {
568
+ $firstChild.attr('style', setInlineStyleProperty($firstChild.attr('style'), 'margin-top', '0 !important'));
569
+ }
570
+ $('style').remove();
571
+ return $.html();
572
+ }
573
+ function renderWechatFriendlyCodeHtml(nodes) {
574
+ return nodes.map((node) => renderWechatFriendlyCodeNode(node)).join('');
575
+ }
576
+ function renderWechatFriendlyCodeNode(node) {
577
+ if (node.type === 'text') {
578
+ return renderWechatFriendlyCodeText(node);
579
+ }
580
+ if (node.type !== 'tag') {
581
+ return '';
582
+ }
583
+ const element = node;
584
+ const attributes = Object.entries(element.attribs ?? {})
585
+ .map(([key, value]) => ` ${key}="${escapeHtmlAttribute(String(value))}"`)
586
+ .join('');
587
+ const children = renderWechatFriendlyCodeHtml(element.children ?? []);
588
+ return `<${element.tagName}${attributes}>${children}</${element.tagName}>`;
589
+ }
590
+ function renderWechatFriendlyCodeText(node) {
591
+ const normalized = node.data.replace(/\r\n?/g, '\n').replace(/\t/g, ' ');
592
+ let result = '';
593
+ for (const char of normalized) {
594
+ if (char === '\n') {
595
+ result += '<br>';
596
+ continue;
597
+ }
598
+ if (char === ' ') {
599
+ result += '&nbsp;';
600
+ continue;
601
+ }
602
+ result += escapeHtml(char);
603
+ }
604
+ return result;
605
+ }
606
+ async function renderMarkdownToHtml(body, metadata) {
607
+ const content = markdown.render(body);
608
+ const $ = cheerio.load(`<article>${content}</article>`);
609
+ normalizeListItems($);
610
+ normalizeImages($);
611
+ normalizeTables($);
612
+ normalizeBlockquoteSoftBreaks($);
613
+ normalizeMathFormulas($);
614
+ const themeCss = await loadThemeCss(metadata.theme);
615
+ const customCss = await loadCustomCss();
616
+ const articleHtml = $('article').html() ?? '';
617
+ const baseHtml = createDocumentHtml(articleHtml, metadata);
618
+ const inlinedHtml = juice_1.default.inlineContent(baseHtml, `${themeCss}\n${HIGHLIGHT_INLINE_CSS}\n${WECHAT_BLOCKQUOTE_INLINE_CSS}\n${WECHAT_TABLE_INLINE_CSS}\n${WECHAT_MATH_INLINE_CSS}\n${customCss}`, {
619
+ removeStyleTags: true,
620
+ preserveMediaQueries: true,
621
+ preserveFontFaces: true,
622
+ applyWidthAttributes: false,
623
+ applyHeightAttributes: false,
624
+ applyAttributesTableElements: true
625
+ });
626
+ return cleanInlinedHtml(inlinedHtml);
627
+ }
628
+ function extractPublishableContent(html) {
629
+ const $ = cheerio.load(html);
630
+ const articleHtml = $('body > #write > article').first().html();
631
+ if (typeof articleHtml === 'string' && articleHtml.trim()) {
632
+ return articleHtml.trim();
633
+ }
634
+ const bodyHtml = $('body').html();
635
+ if (typeof bodyHtml === 'string' && bodyHtml.trim()) {
636
+ return bodyHtml.trim();
637
+ }
638
+ return html.trim();
639
+ }
640
+ function readHtmlMetadata(html) {
641
+ const $ = cheerio.load(html);
642
+ const metadata = {};
643
+ $('meta[name^="wxgzh:"]').each((_, element) => {
644
+ const name = $(element).attr('name')?.replace('wxgzh:', '');
645
+ const value = $(element).attr('content');
646
+ if (!name || value === undefined) {
647
+ return;
648
+ }
649
+ if (name === 'enableComment') {
650
+ metadata.enableComment = value === 'true';
651
+ return;
652
+ }
653
+ metadata[name] = value;
654
+ });
655
+ return metadata;
656
+ }