@markup-carve/pandoc-carve 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.
@@ -0,0 +1,55 @@
1
+ import { type CarveAstDocument } from './ast-json.js';
2
+ import { type ConvertOptions, type ConvertResult } from './convert.js';
3
+ import { type ParseOptions } from './parse-options.js';
4
+ import type { PandocDoc } from './pandoc.js';
5
+ export { PANDOC_API_VERSION, type PandocDoc } from './pandoc.js';
6
+ export type { ConvertOptions, ConvertResult } from './convert.js';
7
+ export type { ParseOptions } from './parse-options.js';
8
+ export type { ReverseResult } from './reverse.js';
9
+ export type { CarveAstDocument, CarveAstNode } from './ast-json.js';
10
+ /**
11
+ * Parse Carve source to the serialized AST of PART 12 - the shape
12
+ * `resources/ast-schema.json` pins, and the shape every engine's `--to-json`
13
+ * writes.
14
+ */
15
+ export declare function carveToCarveAst(source: string, options?: ParseOptions): CarveAstDocument;
16
+ /**
17
+ * Convert Carve source to a Pandoc document (api-version 1.23.1).
18
+ *
19
+ * Returns the document plus a list of degradation warnings for constructs
20
+ * that have no faithful Pandoc equivalent.
21
+ */
22
+ export declare function carveToPandoc(source: string, options?: ConvertOptions & ParseOptions): ConvertResult;
23
+ /**
24
+ * Convert an already-serialized Carve AST - PART 12, from ANY engine, however
25
+ * it arrived: a `carve --to-json` file, a pipe, an editor's own tree.
26
+ *
27
+ * Takes the document as an object or as JSON text. It runs the same conversion
28
+ * {@link carveToPandoc} does, because the exchange format is what the converter
29
+ * reads in both cases - no implementation's internals are involved.
30
+ */
31
+ export declare function carveAstToPandoc(ast: CarveAstDocument | string, options?: ConvertOptions & ParseOptions): ConvertResult;
32
+ /**
33
+ * Convert Carve source to Pandoc JSON, ready for `pandoc -f json -t <target>`.
34
+ * Degradation warnings are discarded; use {@link carveToPandoc} to inspect them.
35
+ */
36
+ export declare function carveToPandocJson(source: string, options?: ConvertOptions & ParseOptions): string;
37
+ /**
38
+ * The reverse direction: convert a Pandoc document (as emitted by
39
+ * `pandoc -t json`) to Carve source. Serialization is delegated to
40
+ * `renderCarve` (the `carve fmt` serializer), so the output carries fmt's
41
+ * guarantees. Returns the Carve source plus degradation warnings.
42
+ */
43
+ export declare function pandocToCarve(doc: PandocDoc | string): {
44
+ carve: string;
45
+ warnings: string[];
46
+ };
47
+ /**
48
+ * Convert Pandoc to the canonical Carve exchange AST without forcing it through
49
+ * Carve 0.1 source. This preserves structural fields, notably Pandoc's optional
50
+ * short caption, for which the source language intentionally has no spelling.
51
+ */
52
+ export declare function pandocToCarveAst(doc: PandocDoc | string): {
53
+ ast: CarveAstDocument;
54
+ warnings: string[];
55
+ };
package/dist/index.js ADDED
@@ -0,0 +1,93 @@
1
+ import * as carve from '@markup-carve/carve';
2
+ import { normalizeCarveAst, parseCarveAst, toCarveAst } from './ast-json.js';
3
+ import { convert } from './convert.js';
4
+ import { parseExtensions } from './parse-options.js';
5
+ import { pandocToCarve as reverse } from './reverse.js';
6
+ export { PANDOC_API_VERSION } from './pandoc.js';
7
+ /**
8
+ * The engine's own serializer, when the installed engine has one.
9
+ *
10
+ * PART 12 section 1: an implementation whose internals differ maps on the way
11
+ * out. Where the engine does that itself its mapping is authoritative and is
12
+ * used; the current git pin exports `toAstJson`, while any published release
13
+ * up to `0.1.3` does not, and there `toCarveAst` applies the section 7
14
+ * mapping instead. Feature-detected through
15
+ * a NAMESPACE import on purpose - a named import of an export the installed
16
+ * version does not have fails at link time, before any check could run.
17
+ */
18
+ const engineSerializer = carve.toAstJson;
19
+ /**
20
+ * Parse Carve source to the serialized AST of PART 12 - the shape
21
+ * `resources/ast-schema.json` pins, and the shape every engine's `--to-json`
22
+ * writes.
23
+ */
24
+ export function carveToCarveAst(source, options) {
25
+ return toCarveAst(carve.parse(source, { extensions: parseExtensions(options) }), engineSerializer);
26
+ }
27
+ /**
28
+ * Convert Carve source to a Pandoc document (api-version 1.23.1).
29
+ *
30
+ * Returns the document plus a list of degradation warnings for constructs
31
+ * that have no faithful Pandoc equivalent.
32
+ */
33
+ export function carveToPandoc(source, options) {
34
+ return convert(carveToCarveAst(source, options), withParser(options));
35
+ }
36
+ /**
37
+ * The convert options with this module's parser lent to them.
38
+ *
39
+ * `convert` reads a serialized AST from any engine and holds no engine of its
40
+ * own, but metadata block content (`abstract: |`) is Carve SOURCE inside a
41
+ * YAML string and has to be parsed. This is the only place that owns both, so
42
+ * it is the place that hands the parser over. An explicit `parseBlocks` wins,
43
+ * so a caller can supply another engine's.
44
+ */
45
+ function withParser(options) {
46
+ return {
47
+ ...options,
48
+ parseBlocks: options?.parseBlocks
49
+ ?? ((source) => carveToCarveAst(source, options).children ?? []),
50
+ };
51
+ }
52
+ /**
53
+ * Convert an already-serialized Carve AST - PART 12, from ANY engine, however
54
+ * it arrived: a `carve --to-json` file, a pipe, an editor's own tree.
55
+ *
56
+ * Takes the document as an object or as JSON text. It runs the same conversion
57
+ * {@link carveToPandoc} does, because the exchange format is what the converter
58
+ * reads in both cases - no implementation's internals are involved.
59
+ */
60
+ export function carveAstToPandoc(ast, options) {
61
+ return convert(normalizeCarveAst(parseCarveAst(ast)), withParser(options));
62
+ }
63
+ /**
64
+ * Convert Carve source to Pandoc JSON, ready for `pandoc -f json -t <target>`.
65
+ * Degradation warnings are discarded; use {@link carveToPandoc} to inspect them.
66
+ */
67
+ export function carveToPandocJson(source, options) {
68
+ return JSON.stringify(carveToPandoc(source, options).doc);
69
+ }
70
+ /**
71
+ * The reverse direction: convert a Pandoc document (as emitted by
72
+ * `pandoc -t json`) to Carve source. Serialization is delegated to
73
+ * `renderCarve` (the `carve fmt` serializer), so the output carries fmt's
74
+ * guarantees. Returns the Carve source plus degradation warnings.
75
+ */
76
+ export function pandocToCarve(doc) {
77
+ const parsed = typeof doc === 'string' ? JSON.parse(doc) : doc;
78
+ const { ast, warnings } = reverse(parsed);
79
+ return {
80
+ carve: carve.renderCarve(ast),
81
+ warnings,
82
+ };
83
+ }
84
+ /**
85
+ * Convert Pandoc to the canonical Carve exchange AST without forcing it through
86
+ * Carve 0.1 source. This preserves structural fields, notably Pandoc's optional
87
+ * short caption, for which the source language intentionally has no spelling.
88
+ */
89
+ export function pandocToCarveAst(doc) {
90
+ const parsed = typeof doc === 'string' ? JSON.parse(doc) : doc;
91
+ const { ast, warnings } = reverse(parsed, 'ast');
92
+ return { ast: toCarveAst(ast, engineSerializer), warnings };
93
+ }
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Minimal Pandoc JSON AST types and constructors.
3
+ *
4
+ * Shapes follow pandoc-types 1.23 (pandoc 3.x): every node is `{t, c?}`,
5
+ * verified against `pandoc -t json` output of pandoc 3.5.
6
+ */
7
+ export declare const PANDOC_API_VERSION: readonly [1, 23, 1];
8
+ export type Attr = [string, string[], [string, string][]];
9
+ export interface PandocNode {
10
+ t: string;
11
+ c?: unknown;
12
+ }
13
+ export type Inline = PandocNode;
14
+ export type Block = PandocNode;
15
+ export type MetaValue = PandocNode;
16
+ export interface PandocDoc {
17
+ 'pandoc-api-version': number[];
18
+ meta: Record<string, MetaValue>;
19
+ blocks: Block[];
20
+ }
21
+ export declare const emptyAttr: Attr;
22
+ export declare function attr(id?: string, classes?: string[], kvs?: [string, string][]): Attr;
23
+ export declare const Str: (s: string) => Inline;
24
+ export declare const Space: Inline;
25
+ export declare const SoftBreak: Inline;
26
+ export declare const LineBreak: Inline;
27
+ export declare const Emph: (xs: Inline[]) => Inline;
28
+ export declare const Strong: (xs: Inline[]) => Inline;
29
+ export declare const Underline: (xs: Inline[]) => Inline;
30
+ export declare const Strikeout: (xs: Inline[]) => Inline;
31
+ export declare const Superscript: (xs: Inline[]) => Inline;
32
+ export declare const Subscript: (xs: Inline[]) => Inline;
33
+ export declare const SmallCaps: (xs: Inline[]) => Inline;
34
+ export declare const Code: (a: Attr, s: string) => Inline;
35
+ export declare const Link: (a: Attr, xs: Inline[], target: [string, string]) => Inline;
36
+ export declare const Image: (a: Attr, alt: Inline[], target: [string, string]) => Inline;
37
+ export declare const Span: (a: Attr, xs: Inline[]) => Inline;
38
+ export declare const RawInline: (format: string, s: string) => Inline;
39
+ export declare const Note: (blocks: Block[]) => Inline;
40
+ export type QuoteType = 'DoubleQuote' | 'SingleQuote';
41
+ /**
42
+ * A quotation as pandoc models it: the quote WRAPS its content, and the marks
43
+ * themselves are not in the tree. That is the shape difference the bridge has
44
+ * to bridge - Carve's parser resolves each mark to its own
45
+ * `smart_punctuation` node, so the pair has to be found before it can be a
46
+ * `Quoted`, and taken apart again on the way back.
47
+ */
48
+ export declare const Quoted: (kind: QuoteType, xs: Inline[]) => Inline;
49
+ /**
50
+ * pandoc-types `CitationMode`. There is no locator field anywhere in
51
+ * `Citation`: citeproc reads the locator out of `citationSuffix`, which is why
52
+ * pandoc's own markdown reader writes `, p. 33` there.
53
+ */
54
+ export type CitationMode = 'AuthorInText' | 'SuppressAuthor' | 'NormalCitation';
55
+ export interface Citation {
56
+ citationId: string;
57
+ citationPrefix: Inline[];
58
+ citationSuffix: Inline[];
59
+ citationMode: {
60
+ t: CitationMode;
61
+ };
62
+ /**
63
+ * The note number in force where the citation stands - reader bookkeeping,
64
+ * which every reader regenerates. It is not zero on the way in: pandoc's
65
+ * markdown reader counts notes closed so far and stamps that plus one, so a
66
+ * citation in running text before any note carries 1, not 0. Callers pass
67
+ * the count; see the `noteCount` field of the converter's context.
68
+ */
69
+ citationNoteNum: number;
70
+ citationHash: number;
71
+ }
72
+ export declare function citation(id: string, mode: CitationMode, prefix?: Inline[], suffix?: Inline[], noteNum?: number): Citation;
73
+ export declare const Cite: (citations: Citation[], xs: Inline[]) => Inline;
74
+ export declare const MathInline: (s: string) => Inline;
75
+ export declare const MathDisplay: (s: string) => Inline;
76
+ export declare const Para: (xs: Inline[]) => Block;
77
+ export declare const Plain: (xs: Inline[]) => Block;
78
+ export declare const Header: (level: number, a: Attr, xs: Inline[]) => Block;
79
+ export declare const BlockQuote: (blocks: Block[]) => Block;
80
+ export declare const CodeBlock: (a: Attr, s: string) => Block;
81
+ export declare const RawBlock: (format: string, s: string) => Block;
82
+ export declare const HorizontalRule: Block;
83
+ export declare const Div: (a: Attr, blocks: Block[]) => Block;
84
+ export declare const LineBlock: (lines: Inline[][]) => Block;
85
+ export declare const BulletList: (items: Block[][]) => Block;
86
+ export type ListNumberStyle = 'DefaultStyle' | 'Decimal' | 'LowerAlpha' | 'UpperAlpha' | 'LowerRoman' | 'UpperRoman';
87
+ export type ListNumberDelim = 'DefaultDelim' | 'Period' | 'OneParen' | 'TwoParens';
88
+ export declare const OrderedList: (start: number, style: ListNumberStyle, items: Block[][], delim?: ListNumberDelim) => Block;
89
+ export declare const DefinitionList: (items: [Inline[], Block[][]][]) => Block;
90
+ export declare const Figure: (a: Attr, caption: Inline[] | null, blocks: Block[], shortCaption?: Inline[] | null) => Block;
91
+ export type Alignment = 'AlignLeft' | 'AlignRight' | 'AlignCenter' | 'AlignDefault';
92
+ export interface PCell {
93
+ attr: Attr;
94
+ align: Alignment;
95
+ rowSpan: number;
96
+ colSpan: number;
97
+ blocks: Block[];
98
+ }
99
+ export declare const cell: (blocks: Block[], align?: Alignment, a?: Attr) => PCell;
100
+ /**
101
+ * One pandoc `Row`: an `Attr` and its cells. Pandoc gives a row its own
102
+ * attribute slot, and Carve's `table_row.attrs` is the same thing, so the row
103
+ * is a record rather than a bare cell list.
104
+ */
105
+ export interface PRow {
106
+ attr?: Attr;
107
+ cells: PCell[];
108
+ }
109
+ export declare const row: (cells: PCell[], a?: Attr) => PRow;
110
+ /**
111
+ * One pandoc `TableBody`: `Attr`, `RowHeadColumns`, its own intermediate
112
+ * header rows, and its body rows.
113
+ *
114
+ * A table has a LIST of these. Collapsing them to one loses where a body
115
+ * begins, which is the only place pandoc records an intermediate header or a
116
+ * row-head column count.
117
+ */
118
+ export interface TableBody {
119
+ attr?: Attr;
120
+ rowHeadColumns?: number;
121
+ headRows?: PRow[];
122
+ bodyRows: PRow[];
123
+ }
124
+ export declare function Table(a: Attr, caption: Inline[] | null, colAligns: Alignment[], headRows: PRow[], bodies: TableBody[], footRows?: PRow[], shortCaption?: Inline[] | null): Block;
125
+ export declare const MetaString: (s: string) => MetaValue;
126
+ export declare const MetaInlines: (xs: Inline[]) => MetaValue;
127
+ export declare const MetaList: (xs: MetaValue[]) => MetaValue;
128
+ export declare const MetaMap: (m: Record<string, MetaValue>) => MetaValue;
129
+ export declare const MetaBool: (b: boolean) => MetaValue;
130
+ /**
131
+ * Block content in metadata - `abstract`, and any other key a template renders
132
+ * as more than a phrase. Pandoc's own markdown reader produces this for a YAML
133
+ * LITERAL BLOCK SCALAR (`abstract: |`) and only for that, whatever the key is
134
+ * called, which is the rule the bridge follows in both directions.
135
+ */
136
+ export declare const MetaBlocks: (blocks: Block[]) => MetaValue;
package/dist/pandoc.js ADDED
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Minimal Pandoc JSON AST types and constructors.
3
+ *
4
+ * Shapes follow pandoc-types 1.23 (pandoc 3.x): every node is `{t, c?}`,
5
+ * verified against `pandoc -t json` output of pandoc 3.5.
6
+ */
7
+ export const PANDOC_API_VERSION = [1, 23, 1];
8
+ export const emptyAttr = ['', [], []];
9
+ export function attr(id, classes, kvs) {
10
+ return [id ?? '', classes ?? [], kvs ?? []];
11
+ }
12
+ function node(t, c) {
13
+ return c === undefined ? { t } : { t, c };
14
+ }
15
+ // --- Inline constructors ---
16
+ export const Str = (s) => node('Str', s);
17
+ export const Space = node('Space');
18
+ export const SoftBreak = node('SoftBreak');
19
+ export const LineBreak = node('LineBreak');
20
+ export const Emph = (xs) => node('Emph', xs);
21
+ export const Strong = (xs) => node('Strong', xs);
22
+ export const Underline = (xs) => node('Underline', xs);
23
+ export const Strikeout = (xs) => node('Strikeout', xs);
24
+ export const Superscript = (xs) => node('Superscript', xs);
25
+ export const Subscript = (xs) => node('Subscript', xs);
26
+ export const SmallCaps = (xs) => node('SmallCaps', xs);
27
+ export const Code = (a, s) => node('Code', [a, s]);
28
+ export const Link = (a, xs, target) => node('Link', [a, xs, target]);
29
+ export const Image = (a, alt, target) => node('Image', [a, alt, target]);
30
+ export const Span = (a, xs) => node('Span', [a, xs]);
31
+ export const RawInline = (format, s) => node('RawInline', [format, s]);
32
+ export const Note = (blocks) => node('Note', blocks);
33
+ /**
34
+ * A quotation as pandoc models it: the quote WRAPS its content, and the marks
35
+ * themselves are not in the tree. That is the shape difference the bridge has
36
+ * to bridge - Carve's parser resolves each mark to its own
37
+ * `smart_punctuation` node, so the pair has to be found before it can be a
38
+ * `Quoted`, and taken apart again on the way back.
39
+ */
40
+ export const Quoted = (kind, xs) => node('Quoted', [node(kind), xs]);
41
+ export function citation(id, mode, prefix = [], suffix = [], noteNum = 1) {
42
+ return {
43
+ citationId: id,
44
+ citationPrefix: prefix,
45
+ citationSuffix: suffix,
46
+ citationMode: node(mode),
47
+ citationNoteNum: noteNum,
48
+ citationHash: 0,
49
+ };
50
+ }
51
+ export const Cite = (citations, xs) => node('Cite', [citations, xs]);
52
+ export const MathInline = (s) => node('Math', [node('InlineMath'), s]);
53
+ export const MathDisplay = (s) => node('Math', [node('DisplayMath'), s]);
54
+ // --- Block constructors ---
55
+ export const Para = (xs) => node('Para', xs);
56
+ export const Plain = (xs) => node('Plain', xs);
57
+ export const Header = (level, a, xs) => node('Header', [level, a, xs]);
58
+ export const BlockQuote = (blocks) => node('BlockQuote', blocks);
59
+ export const CodeBlock = (a, s) => node('CodeBlock', [a, s]);
60
+ export const RawBlock = (format, s) => node('RawBlock', [format, s]);
61
+ export const HorizontalRule = node('HorizontalRule');
62
+ export const Div = (a, blocks) => node('Div', [a, blocks]);
63
+ export const LineBlock = (lines) => node('LineBlock', lines);
64
+ export const BulletList = (items) => node('BulletList', items);
65
+ export const OrderedList = (start, style, items, delim = 'DefaultDelim') => node('OrderedList', [[start, node(style), node(delim)], items]);
66
+ export const DefinitionList = (items) => node('DefinitionList', items);
67
+ export const Figure = (a, caption, blocks, shortCaption = null) => node('Figure', [a, [shortCaption, caption ? [Plain(caption)] : []], blocks]);
68
+ export const cell = (blocks, align = 'AlignDefault', a = emptyAttr) => ({
69
+ attr: a,
70
+ align,
71
+ rowSpan: 1,
72
+ colSpan: 1,
73
+ blocks,
74
+ });
75
+ export const row = (cells, a) => (a ? { attr: a, cells } : { cells });
76
+ function renderCell(c) {
77
+ return [c.attr, node(c.align), c.rowSpan, c.colSpan, c.blocks];
78
+ }
79
+ function renderRow(r) {
80
+ return [r.attr ?? emptyAttr, r.cells.map(renderCell)];
81
+ }
82
+ function renderBody(b) {
83
+ return [
84
+ b.attr ?? emptyAttr,
85
+ b.rowHeadColumns ?? 0,
86
+ (b.headRows ?? []).map(renderRow),
87
+ b.bodyRows.map(renderRow),
88
+ ];
89
+ }
90
+ export function Table(a, caption, colAligns, headRows, bodies, footRows = [], shortCaption = null) {
91
+ // The export side of the same ColWidth policy `reverse.ts`'s `table()`
92
+ // states: alignment is carried, width is always `ColWidthDefault`. Carve
93
+ // has no width to carry, and pandoc's writers size a default-width column
94
+ // themselves, so this is the honest value rather than a placeholder.
95
+ const colspecs = colAligns.map((al) => [node(al), node('ColWidthDefault')]);
96
+ return node('Table', [
97
+ a,
98
+ [shortCaption, caption ? [Plain(caption)] : []],
99
+ colspecs,
100
+ [emptyAttr, headRows.map(renderRow)],
101
+ bodies.map(renderBody),
102
+ [emptyAttr, footRows.map(renderRow)],
103
+ ]);
104
+ }
105
+ // --- Meta constructors ---
106
+ export const MetaString = (s) => node('MetaString', s);
107
+ export const MetaInlines = (xs) => node('MetaInlines', xs);
108
+ export const MetaList = (xs) => node('MetaList', xs);
109
+ export const MetaMap = (m) => node('MetaMap', m);
110
+ export const MetaBool = (b) => node('MetaBool', b);
111
+ /**
112
+ * Block content in metadata - `abstract`, and any other key a template renders
113
+ * as more than a phrase. Pandoc's own markdown reader produces this for a YAML
114
+ * LITERAL BLOCK SCALAR (`abstract: |`) and only for that, whatever the key is
115
+ * called, which is the rule the bridge follows in both directions.
116
+ */
117
+ export const MetaBlocks = (blocks) => node('MetaBlocks', blocks);
@@ -0,0 +1,35 @@
1
+ import { type CarveExtension } from '@markup-carve/carve';
2
+ /**
3
+ * What to enable while READING Carve source.
4
+ *
5
+ * Only the source entry points take these: once a document is a serialized
6
+ * Carve AST, every parse-stage decision has already been made and recorded in
7
+ * the tree, so `carveAstToPandoc` has nothing to apply them to.
8
+ *
9
+ * THE CONTRACT THESE DEFAULTS SERVE: anything `pandocToCarve` can WRITE,
10
+ * `carveToPandoc` must be able to READ. A construct the bridge chooses on the
11
+ * way out and cannot recognize on the way back is round-trip loss the bridge
12
+ * inflicted on itself, and it is invisible - the source looks right, and only
13
+ * the returned AST is poorer.
14
+ */
15
+ export interface ParseOptions {
16
+ /**
17
+ * Parse `[@key]` as a citation group rather than as an `@mention`.
18
+ *
19
+ * ON by default. Citations are a Tier-2 extension, so with them off the
20
+ * parser reaches the `@` first and `[@doe1990]` becomes
21
+ * `[`, a `.mention` span, `]` - which is what an imported bibliography
22
+ * silently turned into, every key of it. The reverse direction writes
23
+ * `[@key]` for every pandoc `Cite`, so reading it back as a citation is
24
+ * what closes the loop.
25
+ */
26
+ citations?: boolean;
27
+ /**
28
+ * Extra Carve extensions to enable while parsing, appended to whatever the
29
+ * flags above already turned on. For extensions with only render hooks this
30
+ * is unnecessary - nothing downstream of the parse renders.
31
+ */
32
+ extensions?: CarveExtension[];
33
+ }
34
+ /** The extension list a set of {@link ParseOptions} asks for. */
35
+ export declare function parseExtensions(options?: ParseOptions): CarveExtension[];
@@ -0,0 +1,10 @@
1
+ import { citations } from '@markup-carve/carve';
2
+ /** The extension list a set of {@link ParseOptions} asks for. */
3
+ export function parseExtensions(options = {}) {
4
+ const list = [];
5
+ if (options.citations !== false)
6
+ list.push(citations());
7
+ if (options.extensions?.length)
8
+ list.push(...options.extensions);
9
+ return list;
10
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Pandoc JSON AST -> Carve AST.
3
+ *
4
+ * The inverse of convert.ts: walks a Pandoc document (api 1.23) and builds
5
+ * the AST shape `@markup-carve/carve`'s `parse()` produces, so `renderCarve()`
6
+ * (the `carve fmt` serializer) can turn it into Carve source. Spans that
7
+ * convert.ts emits as classed degradations (mention, tag, symbol, ext-*, ...)
8
+ * are recognized and restored to their native Carve nodes, which makes
9
+ * carve -> pandoc -> carve round-trips clean.
10
+ */
11
+ import type { PandocDoc } from './pandoc.js';
12
+ interface CNode {
13
+ type: string;
14
+ [key: string]: unknown;
15
+ }
16
+ export interface ReverseResult {
17
+ ast: CNode;
18
+ warnings: string[];
19
+ }
20
+ export declare function pandocToCarve(doc: PandocDoc, target?: 'source' | 'ast'): ReverseResult;
21
+ export {};