markdown2typst 0.1.3 → 0.1.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdown2typst",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "A comprehensive JavaScript library for converting Markdown to Typst code",
5
5
  "type": "module",
6
6
  "main": "./dist/markdown2typst.js",
@@ -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 = node.value.trim();
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 {};
@@ -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()}]`;
@@ -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
- // Re-export types for public API
21
- export type { Markdown2TypstOptions, ConversionError, ErrorCallback } from './types.js';
22
- export { ErrorSeverity } from './types.js';
23
-
24
- /**
25
- * Convert Markdown text to Typst markup.
26
- *
27
- * This is the main entry point for the library. It parses the Markdown using remark,
28
- * processes frontmatter and metadata, and converts the AST to Typst syntax.
29
- *
30
- * The conversion pipeline consists of several stages:
31
- * 1. Parse Markdown into an AST (Abstract Syntax Tree)
32
- * 2. Collect link/image definitions and footnotes
33
- * 3. Parse YAML frontmatter and merge with options
34
- * 4. Render AST nodes to Typst markup
35
- * 5. Build final output with metadata and body
36
- *
37
- * @param markdown - The Markdown text to convert
38
- * @param options - Optional configuration for the conversion
39
- * @returns The converted Typst markup as a string
40
- *
41
- * @example
42
- * ```typescript
43
- * const typst = markdown2typst('# Hello\n\nThis is **bold**.');
44
- * console.log(typst);
45
- * ```
46
- *
47
- * @example
48
- * ```typescript
49
- * const typst = markdown2typst(markdown, {
50
- * title: 'My Document',
51
- * authors: ['John Doe'],
52
- * lang: 'en'
53
- * });
54
- * ```
55
- */
56
- export function markdown2typst(markdown: string, options: Markdown2TypstOptions = {}): string {
57
- try {
58
- // Stage 1: Parse Markdown into AST
59
- const tree = parseMarkdown(markdown, options.onError);
60
-
61
- // Stage 2: Collect definitions and footnotes from the AST
62
- const definitions = collectDefinitions(tree, options.onError);
63
- const footnoteDefinitions = collectFootnotes(tree, options.onError);
64
-
65
- // Stage 3: Parse frontmatter and extract leading title (if enabled)
66
- const frontmatter = parseFrontmatter(tree, options.onError);
67
- const leadingH1 = options.useH1AsTitle
68
- ? findLeadingH1(tree, definitions, options.onError)
69
- : null;
70
-
71
- // Stage 4: Merge metadata from options, frontmatter, and leading H1
72
- const metadata = mergeMetadata(options, frontmatter, leadingH1?.title ?? null);
73
-
74
- // Stage 5: Build final Typst output
75
- const context = {
76
- definitions,
77
- footnoteDefinitions,
78
- onError: options.onError,
79
- warnings: { externalImages: false }
80
- };
81
- return buildOutput(tree, metadata, leadingH1?.index ?? null, context);
82
- } catch (error) {
83
- // Handle unexpected fatal errors
84
- const errorMessage = error instanceof Error ? error.message : String(error);
85
- if (options.onError) {
86
- options.onError({
87
- severity: ErrorSeverity.ERROR,
88
- message: `Fatal error during conversion: ${errorMessage}`,
89
- context: 'markdown2typst',
90
- originalError: error
91
- });
92
- }
93
- // Rethrow fatal errors after logging
94
- throw error;
95
- }
96
- }
97
-
98
- // Export as default for convenience (allows: import markdown2typst from 'markdown2typst')
99
- export default markdown2typst;
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
  };