@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.
- package/LICENSE +21 -0
- package/README.md +324 -0
- package/dist/ast-json.d.ts +77 -0
- package/dist/ast-json.js +255 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +204 -0
- package/dist/convert.d.ts +57 -0
- package/dist/convert.js +1816 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.js +93 -0
- package/dist/pandoc.d.ts +136 -0
- package/dist/pandoc.js +117 -0
- package/dist/parse-options.d.ts +35 -0
- package/dist/parse-options.js +10 -0
- package/dist/reverse.d.ts +21 -0
- package/dist/reverse.js +1457 -0
- package/dist/row-groups.d.ts +44 -0
- package/dist/row-groups.js +86 -0
- package/package.json +59 -0
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|
package/dist/pandoc.d.ts
ADDED
|
@@ -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 {};
|