convpdf 0.2.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.
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/dist/bin/convpdf.d.ts +3 -0
- package/dist/bin/convpdf.d.ts.map +1 -0
- package/dist/bin/convpdf.js +297 -0
- package/dist/bin/convpdf.js.map +1 -0
- package/dist/src/html/template.d.ts +10 -0
- package/dist/src/html/template.d.ts.map +1 -0
- package/dist/src/html/template.js +57 -0
- package/dist/src/html/template.js.map +1 -0
- package/dist/src/markdown/frontmatter.d.ts +3 -0
- package/dist/src/markdown/frontmatter.d.ts.map +1 -0
- package/dist/src/markdown/frontmatter.js +48 -0
- package/dist/src/markdown/frontmatter.js.map +1 -0
- package/dist/src/markdown/marked.d.ts +4 -0
- package/dist/src/markdown/marked.d.ts.map +1 -0
- package/dist/src/markdown/marked.js +82 -0
- package/dist/src/markdown/marked.js.map +1 -0
- package/dist/src/markdown/math.d.ts +7 -0
- package/dist/src/markdown/math.d.ts.map +1 -0
- package/dist/src/markdown/math.js +42 -0
- package/dist/src/markdown/math.js.map +1 -0
- package/dist/src/markdown/toc.d.ts +3 -0
- package/dist/src/markdown/toc.d.ts.map +1 -0
- package/dist/src/markdown/toc.js +29 -0
- package/dist/src/markdown/toc.js.map +1 -0
- package/dist/src/renderer.d.ts +17 -0
- package/dist/src/renderer.d.ts.map +1 -0
- package/dist/src/renderer.js +181 -0
- package/dist/src/renderer.js.map +1 -0
- package/dist/src/styles/default.css +147 -0
- package/dist/src/styles/github.css +118 -0
- package/dist/src/types.d.ts +40 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +14 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/html.d.ts +3 -0
- package/dist/src/utils/html.d.ts.map +1 -0
- package/dist/src/utils/html.js +24 -0
- package/dist/src/utils/html.js.map +1 -0
- package/dist/src/utils/validation.d.ts +6 -0
- package/dist/src/utils/validation.d.ts.map +1 -0
- package/dist/src/utils/validation.js +49 -0
- package/dist/src/utils/validation.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Marked } from 'marked';
|
|
2
|
+
import { markedHighlight } from 'marked-highlight';
|
|
3
|
+
import { gfmHeadingId } from 'marked-gfm-heading-id';
|
|
4
|
+
import footnote from 'marked-footnote';
|
|
5
|
+
import hljs from 'highlight.js';
|
|
6
|
+
import { escapeHtml, sanitizeHref } from '../utils/html.js';
|
|
7
|
+
const stripHtml = (value) => value.replace(/<[^>]+>/g, '').trim();
|
|
8
|
+
const stripMarkdownLinks = (value) => value.replace(/\[([^\]]+)\]\([^\)]+\)/g, '$1');
|
|
9
|
+
export const createMarkedInstance = (slugger) => {
|
|
10
|
+
const marked = new Marked()
|
|
11
|
+
.use(markedHighlight({
|
|
12
|
+
langPrefix: 'hljs language-',
|
|
13
|
+
highlight: (code, languageHint) => {
|
|
14
|
+
const language = hljs.getLanguage(languageHint) ? languageHint : 'plaintext';
|
|
15
|
+
return hljs.highlight(code, { language }).value;
|
|
16
|
+
}
|
|
17
|
+
}))
|
|
18
|
+
.use(footnote())
|
|
19
|
+
.use(gfmHeadingId())
|
|
20
|
+
.use({
|
|
21
|
+
walkTokens(token) {
|
|
22
|
+
const current = token;
|
|
23
|
+
if (current.type === 'heading' && !current.id && current.text) {
|
|
24
|
+
current.id = slugger.slug(stripMarkdownLinks(stripHtml(current.text)));
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
extensions: [
|
|
28
|
+
{
|
|
29
|
+
name: 'pageBreak',
|
|
30
|
+
level: 'block',
|
|
31
|
+
start(source) {
|
|
32
|
+
return source.match(/<!--\s*PAGE_BREAK\s*-->/)?.index;
|
|
33
|
+
},
|
|
34
|
+
tokenizer(source) {
|
|
35
|
+
const match = /^<!--\s*PAGE_BREAK\s*-->/.exec(source);
|
|
36
|
+
if (!match)
|
|
37
|
+
return undefined;
|
|
38
|
+
return { type: 'pageBreak', raw: match[0] };
|
|
39
|
+
},
|
|
40
|
+
renderer() {
|
|
41
|
+
return '<div class="page-break"></div>';
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'tocPlaceholder',
|
|
46
|
+
level: 'block',
|
|
47
|
+
start(source) {
|
|
48
|
+
return source.match(/^\[TOC\]/im)?.index;
|
|
49
|
+
},
|
|
50
|
+
tokenizer(source) {
|
|
51
|
+
const match = /^\[TOC\]/i.exec(source);
|
|
52
|
+
if (!match)
|
|
53
|
+
return undefined;
|
|
54
|
+
return { type: 'tocPlaceholder', raw: match[0] };
|
|
55
|
+
},
|
|
56
|
+
renderer() {
|
|
57
|
+
return '[[TOC_PLACEHOLDER]]';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
renderer: {
|
|
62
|
+
link(token) {
|
|
63
|
+
const href = token.href?.trim();
|
|
64
|
+
const title = token.title?.trim();
|
|
65
|
+
const text = token.text ?? '';
|
|
66
|
+
if (!href)
|
|
67
|
+
return text;
|
|
68
|
+
const external = /^(?:[a-z][a-z\d+\-.]*:)?\/\//i.test(href);
|
|
69
|
+
const rewrittenHref = !external && href.toLowerCase().endsWith('.md') ? href.replace(/\.md$/i, '.pdf') : href;
|
|
70
|
+
const safeHref = sanitizeHref(rewrittenHref);
|
|
71
|
+
let output = `<a href="${escapeHtml(safeHref)}"`;
|
|
72
|
+
if (title)
|
|
73
|
+
output += ` title="${escapeHtml(title)}"`;
|
|
74
|
+
output += `>${text}</a>`;
|
|
75
|
+
return output;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
marked.setOptions({ gfm: true, breaks: true });
|
|
80
|
+
return marked;
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=marked.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marked.js","sourceRoot":"","sources":["../../../src/markdown/marked.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface MathProtectionResult {
|
|
2
|
+
text: string;
|
|
3
|
+
restore: (html: string) => string;
|
|
4
|
+
}
|
|
5
|
+
export declare const protectMath: (content: string) => MathProtectionResult;
|
|
6
|
+
export declare const hasMathSyntax: (content: string) => boolean;
|
|
7
|
+
//# sourceMappingURL=math.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../../../src/markdown/math.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACnC;AAcD,eAAO,MAAM,WAAW,GAAI,SAAS,MAAM,KAAG,oBAsD7C,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,KAAG,OAS/C,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { randomBytes } from 'crypto';
|
|
2
|
+
const replaceWithPlaceholders = (input, pattern, keyPrefix, store) => input.replace(pattern, (match) => {
|
|
3
|
+
const id = `${keyPrefix}_${randomBytes(6).toString('hex')}`;
|
|
4
|
+
store.set(id, match);
|
|
5
|
+
return id;
|
|
6
|
+
});
|
|
7
|
+
export const protectMath = (content) => {
|
|
8
|
+
const codeGuards = new Map();
|
|
9
|
+
const mathGuards = new Map();
|
|
10
|
+
// Fence guards first so we never interpret math inside code blocks.
|
|
11
|
+
let text = replaceWithPlaceholders(content, /^( {0,3})(`{3,}|~{3,})[^\n]*\n[\s\S]*?\n\1\2[ \t]*$/gm, 'CODE_FENCE', codeGuards);
|
|
12
|
+
// Inline code spans can still contain things that look like LaTeX.
|
|
13
|
+
text = replaceWithPlaceholders(text, /(`+)([^`\n]|`(?!\1))+?\1/g, 'CODE_SPAN', codeGuards);
|
|
14
|
+
// Display math blocks.
|
|
15
|
+
text = replaceWithPlaceholders(text, /^\$\$[ \t]*\n[\s\S]*?\n\$\$[ \t]*$/gm, 'MATH_BLOCK', mathGuards);
|
|
16
|
+
text = replaceWithPlaceholders(text, /^\\\[[ \t]*\n[\s\S]*?\n\\\][ \t]*$/gm, 'MATH_BLOCK', mathGuards);
|
|
17
|
+
text = replaceWithPlaceholders(text, /\$\$[^\n]+?\$\$/g, 'MATH_INLINE', mathGuards);
|
|
18
|
+
text = replaceWithPlaceholders(text, /\\\[[^\n]*?\\\]/g, 'MATH_INLINE', mathGuards);
|
|
19
|
+
// Inline math.
|
|
20
|
+
text = replaceWithPlaceholders(text, /\\\([^\n]*?\\\)/g, 'MATH_INLINE', mathGuards);
|
|
21
|
+
text = replaceWithPlaceholders(text, /(?<!\\)\$(?!\s)([^\n$]|\\\$)+?(?<!\s)(?<!\\)\$/g, 'MATH_INLINE', mathGuards);
|
|
22
|
+
// Restore code guards before lexing markdown.
|
|
23
|
+
for (const [id, code] of codeGuards) {
|
|
24
|
+
text = text.split(id).join(code);
|
|
25
|
+
}
|
|
26
|
+
const restore = (html) => {
|
|
27
|
+
let output = html;
|
|
28
|
+
for (const [id, original] of mathGuards) {
|
|
29
|
+
output = output.split(id).join(original);
|
|
30
|
+
}
|
|
31
|
+
return output;
|
|
32
|
+
};
|
|
33
|
+
return { text, restore };
|
|
34
|
+
};
|
|
35
|
+
export const hasMathSyntax = (content) => {
|
|
36
|
+
const sanitized = content
|
|
37
|
+
.replace(/^( {0,3})(`{3,}|~{3,})[^\n]*\n[\s\S]*?\n\1\2[ \t]*$/gm, '')
|
|
38
|
+
.replace(/`[^`\n]*`/g, '')
|
|
39
|
+
.replace(/\[([^\]]*)\]\([^\)]+\)/g, '$1');
|
|
40
|
+
return /(?<!\\)\$[^$\n]+\$|(?<!\\)\$\$[\s\S]+?\$\$|\\\([^\n]+?\\\)|\\\[[\s\S]+?\\\]/.test(sanitized);
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=math.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"math.js","sourceRoot":"","sources":["../../../src/markdown/math.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAOrC,MAAM,uBAAuB,GAAG,CAC9B,KAAa,EACb,OAAe,EACf,SAAiB,EACjB,KAA0B,EAClB,EAAE,CACV,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;IAC/B,MAAM,EAAE,GAAG,GAAG,SAAS,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IAC5D,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IACrB,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAe,EAAwB,EAAE;IACnE,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE7C,oEAAoE;IACpE,IAAI,IAAI,GAAG,uBAAuB,CAChC,OAAO,EACP,uDAAuD,EACvD,YAAY,EACZ,UAAU,CACX,CAAC;IAEF,mEAAmE;IACnE,IAAI,GAAG,uBAAuB,CAAC,IAAI,EAAE,2BAA2B,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;IAE3F,uBAAuB;IACvB,IAAI,GAAG,uBAAuB,CAC5B,IAAI,EACJ,sCAAsC,EACtC,YAAY,EACZ,UAAU,CACX,CAAC;IACF,IAAI,GAAG,uBAAuB,CAC5B,IAAI,EACJ,sCAAsC,EACtC,YAAY,EACZ,UAAU,CACX,CAAC;IACF,IAAI,GAAG,uBAAuB,CAAC,IAAI,EAAE,kBAAkB,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC;IACpF,IAAI,GAAG,uBAAuB,CAAC,IAAI,EAAE,kBAAkB,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC;IAEpF,eAAe;IACf,IAAI,GAAG,uBAAuB,CAAC,IAAI,EAAE,kBAAkB,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC;IACpF,IAAI,GAAG,uBAAuB,CAC5B,IAAI,EACJ,iDAAiD,EACjD,aAAa,EACb,UAAU,CACX,CAAC;IAEF,8CAA8C;IAC9C,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,UAAU,EAAE,CAAC;QACpC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,IAAY,EAAU,EAAE;QACvC,IAAI,MAAM,GAAG,IAAI,CAAC;QAClB,KAAK,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,UAAU,EAAE,CAAC;YACxC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IAEF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,OAAe,EAAW,EAAE;IACxD,MAAM,SAAS,GAAG,OAAO;SACtB,OAAO,CAAC,uDAAuD,EAAE,EAAE,CAAC;SACpE,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;SACzB,OAAO,CAAC,yBAAyB,EAAE,IAAI,CAAC,CAAC;IAE5C,OAAO,6EAA6E,CAAC,IAAI,CACvF,SAAS,CACV,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toc.d.ts","sourceRoot":"","sources":["../../../src/markdown/toc.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,aAAa,CAAC;AAM3D,eAAO,MAAM,WAAW,GAAI,QAAQ,WAAW,EAAE,EAAE,aAAa,MAAM,KAAG,MA8BxE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Marked } from 'marked';
|
|
2
|
+
import { normalizeTocDepth } from '../utils/validation.js';
|
|
3
|
+
const stripNestedAnchors = (value) => value.replace(/<a\s+[^>]*>([\s\S]*?)<\/a>/gi, '$1');
|
|
4
|
+
export const generateToc = (tokens, depthInput) => {
|
|
5
|
+
const depth = normalizeTocDepth(depthInput);
|
|
6
|
+
const headings = [];
|
|
7
|
+
const inlineParser = new Marked();
|
|
8
|
+
const walk = (items) => {
|
|
9
|
+
for (const token of items) {
|
|
10
|
+
if (token.type === 'heading' && token.depth !== undefined && token.depth <= depth) {
|
|
11
|
+
headings.push({
|
|
12
|
+
level: token.depth,
|
|
13
|
+
text: inlineParser.parseInline(token.text ?? ''),
|
|
14
|
+
id: token.id ?? ''
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (token.tokens?.length)
|
|
18
|
+
walk(token.tokens);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
walk(tokens);
|
|
22
|
+
if (!headings.length)
|
|
23
|
+
return '';
|
|
24
|
+
const listItems = headings
|
|
25
|
+
.map((heading) => `<li class="toc-level-${heading.level}"><a href="#${heading.id}">${stripNestedAnchors(heading.text)}</a></li>`)
|
|
26
|
+
.join('\n');
|
|
27
|
+
return `<div class="toc"><h2>Table of Contents</h2><ul>${listItems}</ul></div>`;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=toc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toc.js","sourceRoot":"","sources":["../../../src/markdown/toc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,MAAM,kBAAkB,GAAG,CAAC,KAAa,EAAU,EAAE,CACnD,KAAK,CAAC,OAAO,CAAC,8BAA8B,EAAE,IAAI,CAAC,CAAC;AAEtD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAqB,EAAE,UAAmB,EAAU,EAAE;IAChF,MAAM,KAAK,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAiB,EAAE,CAAC;IAClC,MAAM,YAAY,GAAG,IAAI,MAAM,EAAE,CAAC;IAElC,MAAM,IAAI,GAAG,CAAC,KAAoB,EAAQ,EAAE;QAC1C,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,EAAE,CAAC;gBAClF,QAAQ,CAAC,IAAI,CAAC;oBACZ,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,IAAI,EAAE,YAAY,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAW;oBAC1D,EAAE,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE;iBACnB,CAAC,CAAC;YACL,CAAC;YAED,IAAI,KAAK,CAAC,MAAM,EAAE,MAAM;gBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC;IAEF,IAAI,CAAC,MAAM,CAAC,CAAC;IACb,IAAI,CAAC,QAAQ,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAEhC,MAAM,SAAS,GAAG,QAAQ;SACvB,GAAG,CACF,CAAC,OAAO,EAAE,EAAE,CACV,wBAAwB,OAAO,CAAC,KAAK,eAAe,OAAO,CAAC,EAAE,KAAK,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CACjH;SACA,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO,kDAAkD,SAAS,aAAa,CAAC;AAClF,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RendererOptions, Frontmatter, CustomToken } from './types.js';
|
|
2
|
+
export declare class Renderer {
|
|
3
|
+
private options;
|
|
4
|
+
private browser;
|
|
5
|
+
private page;
|
|
6
|
+
constructor(options?: RendererOptions);
|
|
7
|
+
init(): Promise<void>;
|
|
8
|
+
close(): Promise<void>;
|
|
9
|
+
parseFrontmatter(markdown: string): {
|
|
10
|
+
data: Frontmatter;
|
|
11
|
+
content: string;
|
|
12
|
+
};
|
|
13
|
+
generateToc(tokens: CustomToken[], depth?: number): string;
|
|
14
|
+
renderHtml(md: string, overrides?: RendererOptions): Promise<string>;
|
|
15
|
+
generatePdf(md: string, outputPath: string, overrides?: RendererOptions): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/renderer.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAY5E,qBAAa,QAAQ;IACnB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,IAAI,CAAqB;gBAErB,OAAO,GAAE,eAAoB;IAInC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAUrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAQ1E,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,KAAK,SAAI,GAAG,MAAM;IAI/C,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,GAAE,eAAoB,GAAG,OAAO,CAAC,MAAM,CAAC;IAmExE,WAAW,CACf,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,eAAoB,GAC9B,OAAO,CAAC,IAAI,CAAC;CA4FjB"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import puppeteer from 'puppeteer';
|
|
2
|
+
import { readFile, writeFile, unlink, rm, mkdtemp } from 'fs/promises';
|
|
3
|
+
import { join, dirname, resolve } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
6
|
+
import GithubSlugger from 'github-slugger';
|
|
7
|
+
import { parseFrontmatter } from './markdown/frontmatter.js';
|
|
8
|
+
import { protectMath, hasMathSyntax } from './markdown/math.js';
|
|
9
|
+
import { createMarkedInstance } from './markdown/marked.js';
|
|
10
|
+
import { generateToc } from './markdown/toc.js';
|
|
11
|
+
import { renderTemplate } from './html/template.js';
|
|
12
|
+
import { normalizePaperFormat, normalizeTocDepth, parseMargin } from './utils/validation.js';
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const read = (p) => readFile(join(__dirname, p), 'utf-8');
|
|
15
|
+
const stylesPromise = Promise.all([read('styles/default.css'), read('styles/github.css')]);
|
|
16
|
+
export class Renderer {
|
|
17
|
+
options;
|
|
18
|
+
browser = null;
|
|
19
|
+
page = null;
|
|
20
|
+
constructor(options = {}) {
|
|
21
|
+
this.options = { margin: '20mm', format: 'A4', ...options };
|
|
22
|
+
}
|
|
23
|
+
async init() {
|
|
24
|
+
if (!this.browser) {
|
|
25
|
+
this.browser = await puppeteer.launch({
|
|
26
|
+
headless: true,
|
|
27
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox']
|
|
28
|
+
});
|
|
29
|
+
this.page = await this.browser.newPage();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async close() {
|
|
33
|
+
if (this.page)
|
|
34
|
+
await this.page.close();
|
|
35
|
+
if (this.browser)
|
|
36
|
+
await this.browser.close();
|
|
37
|
+
this.page = this.browser = null;
|
|
38
|
+
}
|
|
39
|
+
parseFrontmatter(markdown) {
|
|
40
|
+
const parsed = parseFrontmatter(markdown);
|
|
41
|
+
for (const warning of parsed.warnings) {
|
|
42
|
+
console.warn(warning);
|
|
43
|
+
}
|
|
44
|
+
return { data: parsed.data, content: parsed.content };
|
|
45
|
+
}
|
|
46
|
+
generateToc(tokens, depth = 6) {
|
|
47
|
+
return generateToc(tokens, depth);
|
|
48
|
+
}
|
|
49
|
+
async renderHtml(md, overrides = {}) {
|
|
50
|
+
const opts = { ...this.options, ...overrides };
|
|
51
|
+
const parsedFrontmatter = parseFrontmatter(md);
|
|
52
|
+
const { data, content } = parsedFrontmatter;
|
|
53
|
+
for (const warning of parsedFrontmatter.warnings) {
|
|
54
|
+
console.warn(warning);
|
|
55
|
+
}
|
|
56
|
+
const slugger = new GithubSlugger();
|
|
57
|
+
const marked = createMarkedInstance(slugger);
|
|
58
|
+
// Protect math from Marked's break conversion and entity escaping.
|
|
59
|
+
const { text: safeContent, restore: restoreMath } = protectMath(content);
|
|
60
|
+
const tokens = marked.lexer(safeContent);
|
|
61
|
+
if (marked.defaults.walkTokens) {
|
|
62
|
+
void marked.walkTokens(tokens, marked.defaults.walkTokens);
|
|
63
|
+
}
|
|
64
|
+
const footnoteIndex = tokens.findIndex((t) => t.type === 'footnotes');
|
|
65
|
+
if (footnoteIndex !== -1) {
|
|
66
|
+
const [footnoteToken] = tokens.splice(footnoteIndex, 1);
|
|
67
|
+
if (footnoteToken)
|
|
68
|
+
tokens.push(footnoteToken);
|
|
69
|
+
}
|
|
70
|
+
const tocDepth = normalizeTocDepth(typeof data.tocDepth === 'number' ? data.tocDepth : opts.tocDepth);
|
|
71
|
+
const hasTocPlaceholder = tokens.some((t) => t.type === 'tocPlaceholder');
|
|
72
|
+
const frontmatterToc = typeof data.toc === 'boolean' ? data.toc : undefined;
|
|
73
|
+
const tocEnabled = opts.toc ?? frontmatterToc ?? false;
|
|
74
|
+
const tocHtml = tocEnabled || hasTocPlaceholder ? this.generateToc(tokens, tocDepth) : '';
|
|
75
|
+
let html = restoreMath(marked.parser(tokens));
|
|
76
|
+
if (tocHtml) {
|
|
77
|
+
if (html.includes('[[TOC_PLACEHOLDER]]')) {
|
|
78
|
+
html = html.replace('[[TOC_PLACEHOLDER]]', tocHtml);
|
|
79
|
+
}
|
|
80
|
+
else if (tocEnabled && !hasTocPlaceholder) {
|
|
81
|
+
html = tocHtml + html;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
let customCssContent = '';
|
|
85
|
+
if (opts.customCss) {
|
|
86
|
+
try {
|
|
87
|
+
customCssContent = await readFile(resolve(opts.customCss), 'utf-8');
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
91
|
+
throw new Error(`Failed to read custom CSS at "${opts.customCss}": ${message}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const [defaultCss, highlightCss] = await stylesPromise;
|
|
95
|
+
const css = `${defaultCss}\n${highlightCss}\n${customCssContent}`;
|
|
96
|
+
const title = typeof data.title === 'string' ? data.title : 'Markdown Document';
|
|
97
|
+
return renderTemplate({
|
|
98
|
+
templatePath: opts.template,
|
|
99
|
+
title: overrides.title ?? title,
|
|
100
|
+
css,
|
|
101
|
+
content: html,
|
|
102
|
+
basePath: opts.basePath,
|
|
103
|
+
includeMathJax: opts.math !== false && hasMathSyntax(content)
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async generatePdf(md, outputPath, overrides = {}) {
|
|
107
|
+
const opts = { ...this.options, ...overrides };
|
|
108
|
+
const html = await this.renderHtml(md, opts);
|
|
109
|
+
await this.init();
|
|
110
|
+
if (!this.page)
|
|
111
|
+
throw new Error('Browser page not initialized');
|
|
112
|
+
const tempDir = await mkdtemp(join(tmpdir(), 'convpdf-'));
|
|
113
|
+
const tempHtmlPath = join(tempDir, 'document.html');
|
|
114
|
+
await writeFile(tempHtmlPath, html, 'utf-8');
|
|
115
|
+
try {
|
|
116
|
+
await this.page.emulateMediaType('print');
|
|
117
|
+
await this.page.goto(pathToFileURL(tempHtmlPath).href, {
|
|
118
|
+
waitUntil: 'networkidle0',
|
|
119
|
+
timeout: 60000
|
|
120
|
+
});
|
|
121
|
+
await this.page.evaluate(async () => {
|
|
122
|
+
const images = Array.from(document.querySelectorAll('img'));
|
|
123
|
+
await Promise.all(images.map((img) => {
|
|
124
|
+
if (img.complete)
|
|
125
|
+
return Promise.resolve();
|
|
126
|
+
return new Promise((resolve) => {
|
|
127
|
+
img.addEventListener('load', () => {
|
|
128
|
+
resolve();
|
|
129
|
+
}, { once: true });
|
|
130
|
+
img.addEventListener('error', () => {
|
|
131
|
+
resolve();
|
|
132
|
+
}, { once: true });
|
|
133
|
+
setTimeout(resolve, 5000); // Max 5s per image
|
|
134
|
+
});
|
|
135
|
+
}));
|
|
136
|
+
const win = window;
|
|
137
|
+
if (!document.getElementById('MathJax-script'))
|
|
138
|
+
return;
|
|
139
|
+
await new Promise((resolve, reject) => {
|
|
140
|
+
const startedAt = Date.now();
|
|
141
|
+
const tick = () => {
|
|
142
|
+
if (win.MathJax?.typesetPromise) {
|
|
143
|
+
resolve();
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (Date.now() - startedAt > 10000) {
|
|
147
|
+
reject(new Error('MathJax did not initialize within 10s'));
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
setTimeout(tick, 100);
|
|
151
|
+
};
|
|
152
|
+
tick();
|
|
153
|
+
});
|
|
154
|
+
await win.MathJax?.typesetPromise?.();
|
|
155
|
+
});
|
|
156
|
+
const margin = parseMargin(opts.margin);
|
|
157
|
+
const format = normalizePaperFormat(typeof opts.format === 'string' ? opts.format : undefined);
|
|
158
|
+
await this.page.pdf({
|
|
159
|
+
path: outputPath,
|
|
160
|
+
format,
|
|
161
|
+
printBackground: true,
|
|
162
|
+
margin,
|
|
163
|
+
displayHeaderFooter: !!(opts.headerTemplate || opts.footerTemplate),
|
|
164
|
+
headerTemplate: opts.headerTemplate || '<span></span>',
|
|
165
|
+
footerTemplate: opts.footerTemplate ||
|
|
166
|
+
'<div style="font-size: 10px; width: 100%; text-align: center; color: #666;"><span class="pageNumber"></span> / <span class="totalPages"></span></div>'
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
if (e instanceof Error && e.message.includes('Session closed')) {
|
|
171
|
+
this.page = null;
|
|
172
|
+
}
|
|
173
|
+
throw e;
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
await unlink(tempHtmlPath).catch(() => { });
|
|
177
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => { });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--primary-color: #333;
|
|
3
|
+
--bg-color: #fff;
|
|
4
|
+
--code-bg: #f6f8fa;
|
|
5
|
+
--border-color: #d0d7de;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
body {
|
|
9
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
10
|
+
font-size: 16px;
|
|
11
|
+
line-height: 1.6;
|
|
12
|
+
color: var(--primary-color);
|
|
13
|
+
background-color: var(--bg-color);
|
|
14
|
+
max-width: 800px;
|
|
15
|
+
margin: 0 auto;
|
|
16
|
+
padding: 2rem;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
h1, h2, h3, h4, h5, h6 {
|
|
20
|
+
margin-top: 24px;
|
|
21
|
+
margin-bottom: 16px;
|
|
22
|
+
font-weight: 600;
|
|
23
|
+
line-height: 1.25;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
h1 { font-size: 2em; padding-bottom: 0.3em; border-bottom: 1px solid var(--border-color); }
|
|
27
|
+
h2 { font-size: 1.5em; padding-bottom: 0.3em; border-bottom: 1px solid var(--border-color); }
|
|
28
|
+
|
|
29
|
+
a { color: #0969da; text-decoration: none; }
|
|
30
|
+
a:hover { text-decoration: underline; }
|
|
31
|
+
|
|
32
|
+
p, blockquote, ul, ol, dl, table, pre { margin-top: 0; margin-bottom: 16px; }
|
|
33
|
+
|
|
34
|
+
blockquote {
|
|
35
|
+
padding: 0 1em;
|
|
36
|
+
color: #636c76;
|
|
37
|
+
border-left: 0.25em solid var(--border-color);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
table {
|
|
41
|
+
border-spacing: 0;
|
|
42
|
+
border-collapse: collapse;
|
|
43
|
+
width: 100%;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
table th, table td {
|
|
47
|
+
padding: 6px 13px;
|
|
48
|
+
border: 1px solid var(--border-color);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
table tr:nth-child(2n) { background-color: #f6f8fa; }
|
|
52
|
+
|
|
53
|
+
pre {
|
|
54
|
+
padding: 16px;
|
|
55
|
+
overflow: auto;
|
|
56
|
+
font-size: 85%;
|
|
57
|
+
line-height: 1.45;
|
|
58
|
+
background-color: var(--code-bg);
|
|
59
|
+
border-radius: 6px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
code {
|
|
63
|
+
padding: 0.2em 0.4em;
|
|
64
|
+
margin: 0;
|
|
65
|
+
font-size: 85%;
|
|
66
|
+
background-color: rgba(175, 184, 193, 0.2);
|
|
67
|
+
border-radius: 6px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
pre code {
|
|
71
|
+
padding: 0;
|
|
72
|
+
background-color: transparent;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Footnotes */
|
|
76
|
+
.footnotes {
|
|
77
|
+
font-size: 85%;
|
|
78
|
+
color: #636c76;
|
|
79
|
+
border-top: 1px solid var(--border-color);
|
|
80
|
+
margin-top: 40px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.footnotes-title {
|
|
84
|
+
font-size: 1.2rem;
|
|
85
|
+
margin-bottom: 0.5rem;
|
|
86
|
+
font-weight: bold;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* TOC */
|
|
90
|
+
.toc {
|
|
91
|
+
background-color: #f8f9fa;
|
|
92
|
+
padding: 1rem;
|
|
93
|
+
border-radius: 6px;
|
|
94
|
+
margin-bottom: 2rem;
|
|
95
|
+
border: 1px solid var(--border-color);
|
|
96
|
+
page-break-inside: avoid;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.toc h2 {
|
|
100
|
+
margin-top: 0;
|
|
101
|
+
font-size: 1.2rem;
|
|
102
|
+
border-bottom: none;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.toc ul {
|
|
106
|
+
list-style: none;
|
|
107
|
+
padding-left: 0;
|
|
108
|
+
margin-bottom: 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.toc li { margin-bottom: 0.25rem; }
|
|
112
|
+
.toc-level-1 { font-weight: bold; }
|
|
113
|
+
.toc-level-2 { padding-left: 1rem; }
|
|
114
|
+
.toc-level-3 { padding-left: 2rem; }
|
|
115
|
+
.toc-level-4 { padding-left: 3rem; }
|
|
116
|
+
.toc-level-5 { padding-left: 4rem; }
|
|
117
|
+
.toc-level-6 { padding-left: 5rem; }
|
|
118
|
+
|
|
119
|
+
@media print {
|
|
120
|
+
body {
|
|
121
|
+
padding: 0;
|
|
122
|
+
max-width: none;
|
|
123
|
+
width: 100%;
|
|
124
|
+
font-size: 12pt;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Prevent long content from causing the page to zoom out */
|
|
128
|
+
pre, code, table {
|
|
129
|
+
max-width: 100%;
|
|
130
|
+
overflow-wrap: break-word;
|
|
131
|
+
word-wrap: break-word;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
pre {
|
|
135
|
+
white-space: pre-wrap;
|
|
136
|
+
word-break: break-all;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
img {
|
|
140
|
+
max-width: 100%;
|
|
141
|
+
height: auto;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.page-break { page-break-before: always; }
|
|
145
|
+
h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }
|
|
146
|
+
table, pre, blockquote, .toc { page-break-inside: avoid; }
|
|
147
|
+
}
|