markdown2typst 0.1.4 → 0.1.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/README.md +1 -1
- package/dist/markdown2typst.browser.js +20450 -0
- package/dist/markdown2typst.browser.js.map +7 -0
- package/dist/markdown2typst.browser.min.js +106 -0
- package/dist/markdown2typst.js +12936 -12977
- package/dist/markdown2typst.js.map +4 -4
- package/dist/markdown2typst.min.js +63 -62
- package/package.json +1 -1
- package/src/block-renderer.ts +15 -1
- package/src/external-modules.d.ts +36 -0
- package/src/inline-renderer.ts +4 -5
- package/src/markdown2typst.ts +101 -99
- package/src/types.ts +11 -0
- package/src/utils.ts +161 -137
package/package.json
CHANGED
package/src/block-renderer.ts
CHANGED
|
@@ -97,8 +97,22 @@ export function renderBlock(
|
|
|
97
97
|
* @returns Rendered Typst math block
|
|
98
98
|
*/
|
|
99
99
|
function renderMathBlock(node: MathNode, indentLevel: number, context: RenderContext): string {
|
|
100
|
+
// Reconstruct the full LaTeX string.
|
|
101
|
+
// If a LaTeX environment is adjacent to $$, remark-math treats the adjacent text as `meta`,
|
|
102
|
+
// and may absorb the trailing $$ into `value` if it's on the same line as the environment closure.
|
|
103
|
+
let rawLatex = node.value || '';
|
|
104
|
+
const meta = (node as any).meta;
|
|
105
|
+
if (meta) {
|
|
106
|
+
rawLatex = meta + (rawLatex ? '\n' + rawLatex : '');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Check if the closing $$ was absorbed into the value
|
|
110
|
+
if (rawLatex.endsWith('$$')) {
|
|
111
|
+
rawLatex = rawLatex.slice(0, -2);
|
|
112
|
+
}
|
|
113
|
+
|
|
100
114
|
// Convert LaTeX to Typst math syntax
|
|
101
|
-
const value =
|
|
115
|
+
const value = rawLatex.trim();
|
|
102
116
|
try {
|
|
103
117
|
const typstMath = tex2typst(value);
|
|
104
118
|
return indentLines(`$ ${typstMath} $`, indentLevel);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Ambient declarations for external modules that are provided as runtime dependencies
|
|
2
|
+
// These are intentionally minimal so consumers don't need the dev-only @types packages.
|
|
3
|
+
|
|
4
|
+
declare module 'country-list' {
|
|
5
|
+
export function getCode(name: string): string | undefined;
|
|
6
|
+
export function getCodes(): string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
declare module 'langs' {
|
|
10
|
+
export interface Lang {
|
|
11
|
+
name?: string;
|
|
12
|
+
local?: string;
|
|
13
|
+
'1'?: string;
|
|
14
|
+
'2'?: string;
|
|
15
|
+
'2B'?: string;
|
|
16
|
+
'3'?: string;
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function codes(type: string): string[];
|
|
21
|
+
export function all(): Lang[];
|
|
22
|
+
export function where(codeType: string, value: string): Lang | undefined;
|
|
23
|
+
const langs: {
|
|
24
|
+
codes: typeof codes;
|
|
25
|
+
all: typeof all;
|
|
26
|
+
where: typeof where;
|
|
27
|
+
};
|
|
28
|
+
export default langs;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
declare module 'js-yaml' {
|
|
32
|
+
export function load(s: string): any;
|
|
33
|
+
export function dump(o: any): string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {};
|
package/src/inline-renderer.ts
CHANGED
|
@@ -83,12 +83,11 @@ function renderInline(
|
|
|
83
83
|
}
|
|
84
84
|
// Render footnote content inline
|
|
85
85
|
try {
|
|
86
|
+
if (!context.renderBlock) {
|
|
87
|
+
throw new Error('renderBlock not available in context');
|
|
88
|
+
}
|
|
86
89
|
const content = def.children
|
|
87
|
-
.map((child) =>
|
|
88
|
-
// Import renderBlock only when needed to avoid circular dependencies
|
|
89
|
-
const { renderBlock } = require('./block-renderer.js');
|
|
90
|
-
return renderBlock(child, 0, context);
|
|
91
|
-
})
|
|
90
|
+
.map((child) => context.renderBlock!(child, 0, context))
|
|
92
91
|
.filter(isNonEmpty)
|
|
93
92
|
.join(' '); // Join blocks with space for inline footnote
|
|
94
93
|
return `#footnote[${content.trim()}]`;
|
package/src/markdown2typst.ts
CHANGED
|
@@ -1,99 +1,101 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* markdown2typst - Convert Markdown to Typst
|
|
3
|
-
*
|
|
4
|
-
* A comprehensive library for converting Markdown documents to Typst markup language.
|
|
5
|
-
* Supports GitHub Flavored Markdown, math equations, tables, footnotes, and more
|
|
6
|
-
*
|
|
7
|
-
* This code is inspired by the original work of zhaoyiqun (Creator of MDXport; 'cosformula' on GitHub).
|
|
8
|
-
* Refactored, documented, modified and extended by Mapaor.
|
|
9
|
-
*
|
|
10
|
-
* @module markdown2typst
|
|
11
|
-
* @license MIT
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { ErrorSeverity, type Markdown2TypstOptions } from './types.js';
|
|
15
|
-
import { parseMarkdown } from './parser.js';
|
|
16
|
-
import { collectDefinitions, collectFootnotes, findLeadingH1 } from './collectors.js';
|
|
17
|
-
import { parseFrontmatter, mergeMetadata } from './frontmatter.js';
|
|
18
|
-
import { buildOutput } from './output-builder.js';
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
export
|
|
22
|
-
export {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* @param
|
|
39
|
-
* @
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
1
|
+
/**
|
|
2
|
+
* markdown2typst - Convert Markdown to Typst
|
|
3
|
+
*
|
|
4
|
+
* A comprehensive library for converting Markdown documents to Typst markup language.
|
|
5
|
+
* Supports GitHub Flavored Markdown, math equations, tables, footnotes, and more
|
|
6
|
+
*
|
|
7
|
+
* This code is inspired by the original work of zhaoyiqun (Creator of MDXport; 'cosformula' on GitHub).
|
|
8
|
+
* Refactored, documented, modified and extended by Mapaor.
|
|
9
|
+
*
|
|
10
|
+
* @module markdown2typst
|
|
11
|
+
* @license MIT
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { ErrorSeverity, type Markdown2TypstOptions } from './types.js';
|
|
15
|
+
import { parseMarkdown } from './parser.js';
|
|
16
|
+
import { collectDefinitions, collectFootnotes, findLeadingH1 } from './collectors.js';
|
|
17
|
+
import { parseFrontmatter, mergeMetadata } from './frontmatter.js';
|
|
18
|
+
import { buildOutput } from './output-builder.js';
|
|
19
|
+
import { renderBlock } from './block-renderer.js';
|
|
20
|
+
|
|
21
|
+
// Re-export types for public API
|
|
22
|
+
export type { Markdown2TypstOptions, ConversionError, ErrorCallback } from './types.js';
|
|
23
|
+
export { ErrorSeverity } from './types.js';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Convert Markdown text to Typst markup.
|
|
27
|
+
*
|
|
28
|
+
* This is the main entry point for the library. It parses the Markdown using remark,
|
|
29
|
+
* processes frontmatter and metadata, and converts the AST to Typst syntax.
|
|
30
|
+
*
|
|
31
|
+
* The conversion pipeline consists of several stages:
|
|
32
|
+
* 1. Parse Markdown into an AST (Abstract Syntax Tree)
|
|
33
|
+
* 2. Collect link/image definitions and footnotes
|
|
34
|
+
* 3. Parse YAML frontmatter and merge with options
|
|
35
|
+
* 4. Render AST nodes to Typst markup
|
|
36
|
+
* 5. Build final output with metadata and body
|
|
37
|
+
*
|
|
38
|
+
* @param markdown - The Markdown text to convert
|
|
39
|
+
* @param options - Optional configuration for the conversion
|
|
40
|
+
* @returns The converted Typst markup as a string
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const typst = markdown2typst('# Hello\n\nThis is **bold**.');
|
|
45
|
+
* console.log(typst);
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const typst = markdown2typst(markdown, {
|
|
51
|
+
* title: 'My Document',
|
|
52
|
+
* authors: ['John Doe'],
|
|
53
|
+
* lang: 'en'
|
|
54
|
+
* });
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function markdown2typst(markdown: string, options: Markdown2TypstOptions = {}): string {
|
|
58
|
+
try {
|
|
59
|
+
// Stage 1: Parse Markdown into AST
|
|
60
|
+
const tree = parseMarkdown(markdown, options.onError);
|
|
61
|
+
|
|
62
|
+
// Stage 2: Collect definitions and footnotes from the AST
|
|
63
|
+
const definitions = collectDefinitions(tree, options.onError);
|
|
64
|
+
const footnoteDefinitions = collectFootnotes(tree, options.onError);
|
|
65
|
+
|
|
66
|
+
// Stage 3: Parse frontmatter and extract leading title (if enabled)
|
|
67
|
+
const frontmatter = parseFrontmatter(tree, options.onError);
|
|
68
|
+
const leadingH1 = options.useH1AsTitle
|
|
69
|
+
? findLeadingH1(tree, definitions, options.onError)
|
|
70
|
+
: null;
|
|
71
|
+
|
|
72
|
+
// Stage 4: Merge metadata from options, frontmatter, and leading H1
|
|
73
|
+
const metadata = mergeMetadata(options, frontmatter, leadingH1?.title ?? null);
|
|
74
|
+
|
|
75
|
+
// Stage 5: Build final Typst output
|
|
76
|
+
const context = {
|
|
77
|
+
definitions,
|
|
78
|
+
footnoteDefinitions,
|
|
79
|
+
onError: options.onError,
|
|
80
|
+
warnings: { externalImages: false },
|
|
81
|
+
renderBlock
|
|
82
|
+
};
|
|
83
|
+
return buildOutput(tree, metadata, leadingH1?.index ?? null, context);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
// Handle unexpected fatal errors
|
|
86
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
87
|
+
if (options.onError) {
|
|
88
|
+
options.onError({
|
|
89
|
+
severity: ErrorSeverity.ERROR,
|
|
90
|
+
message: `Fatal error during conversion: ${errorMessage}`,
|
|
91
|
+
context: 'markdown2typst',
|
|
92
|
+
originalError: error
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// Rethrow fatal errors after logging
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Export as default for convenience (allows: import markdown2typst from 'markdown2typst')
|
|
101
|
+
export default markdown2typst;
|
package/src/types.ts
CHANGED
|
@@ -144,6 +144,15 @@ export type ConversionWarnings = {
|
|
|
144
144
|
externalImages: boolean;
|
|
145
145
|
};
|
|
146
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Block renderer function type for dependency injection
|
|
149
|
+
*/
|
|
150
|
+
export type BlockRenderer = (
|
|
151
|
+
node: import('mdast').Content,
|
|
152
|
+
indentLevel: number,
|
|
153
|
+
context: RenderContext
|
|
154
|
+
) => string | null;
|
|
155
|
+
|
|
147
156
|
/**
|
|
148
157
|
* Context for rendering nodes
|
|
149
158
|
*/
|
|
@@ -153,4 +162,6 @@ export type RenderContext = {
|
|
|
153
162
|
onError?: ErrorCallback;
|
|
154
163
|
/** Track conversion warnings for generating helper functions */
|
|
155
164
|
warnings: ConversionWarnings;
|
|
165
|
+
/** Block renderer function (injected to avoid circular imports) */
|
|
166
|
+
renderBlock?: BlockRenderer;
|
|
156
167
|
};
|