@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
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The optional `table.rowGroups` partition of PART 12 §15.
|
|
3
|
+
*
|
|
4
|
+
* The object holds COUNTS, never rows, so a grouping cannot contradict the
|
|
5
|
+
* table's flat `rows` - it partitions them, head first, then each body group
|
|
6
|
+
* (its own intermediate header rows, then its body rows), then the foot.
|
|
7
|
+
*
|
|
8
|
+
* §15 states as a MUST that those counts account for every row exactly once.
|
|
9
|
+
* JSON Schema cannot express a cross-field sum, so `resources/ast-schema.json`
|
|
10
|
+
* deliberately does not check it and an upstream test pins that a non-summing
|
|
11
|
+
* partition still validates. A document that validates is therefore not a
|
|
12
|
+
* document whose partition is coherent, and this bridge has to decide for
|
|
13
|
+
* itself: a partition that does not add up is refused here rather than turned
|
|
14
|
+
* into a table whose sections silently disagree with its rows.
|
|
15
|
+
*/
|
|
16
|
+
/** A body group: its intermediate header rows, its body rows, and its extras. */
|
|
17
|
+
export interface RowGroupBody {
|
|
18
|
+
headRows: number;
|
|
19
|
+
bodyRows: number;
|
|
20
|
+
rowHeadColumns?: number;
|
|
21
|
+
attrs?: unknown;
|
|
22
|
+
}
|
|
23
|
+
/** The whole partition: leading head rows, the body groups, trailing foot rows. */
|
|
24
|
+
export interface RowGroups {
|
|
25
|
+
headRows: number;
|
|
26
|
+
bodies: RowGroupBody[];
|
|
27
|
+
footRows: number;
|
|
28
|
+
}
|
|
29
|
+
/** The outcome of reading the field: at most one of `groups` and `error` is set. */
|
|
30
|
+
export interface RowGroupsRead {
|
|
31
|
+
groups: RowGroups | null;
|
|
32
|
+
error: string | null;
|
|
33
|
+
}
|
|
34
|
+
/** The number of rows a partition consumes. */
|
|
35
|
+
export declare function rowGroupsTotal(groups: RowGroups): number;
|
|
36
|
+
/**
|
|
37
|
+
* Read `table.rowGroups` for a table of `rowCount` rows.
|
|
38
|
+
*
|
|
39
|
+
* Absent is not an error: it means the implicit structure every renderer
|
|
40
|
+
* already derives. Present but unusable IS one, and it is reported rather
|
|
41
|
+
* than repaired, because guessing which of the counts was meant would produce
|
|
42
|
+
* a table nobody wrote.
|
|
43
|
+
*/
|
|
44
|
+
export declare function readRowGroups(value: unknown, rowCount: number): RowGroupsRead;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The optional `table.rowGroups` partition of PART 12 §15.
|
|
3
|
+
*
|
|
4
|
+
* The object holds COUNTS, never rows, so a grouping cannot contradict the
|
|
5
|
+
* table's flat `rows` - it partitions them, head first, then each body group
|
|
6
|
+
* (its own intermediate header rows, then its body rows), then the foot.
|
|
7
|
+
*
|
|
8
|
+
* §15 states as a MUST that those counts account for every row exactly once.
|
|
9
|
+
* JSON Schema cannot express a cross-field sum, so `resources/ast-schema.json`
|
|
10
|
+
* deliberately does not check it and an upstream test pins that a non-summing
|
|
11
|
+
* partition still validates. A document that validates is therefore not a
|
|
12
|
+
* document whose partition is coherent, and this bridge has to decide for
|
|
13
|
+
* itself: a partition that does not add up is refused here rather than turned
|
|
14
|
+
* into a table whose sections silently disagree with its rows.
|
|
15
|
+
*/
|
|
16
|
+
function isObject(value) {
|
|
17
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
18
|
+
}
|
|
19
|
+
/** A required count: a non-negative integer, nothing else. */
|
|
20
|
+
function count(value) {
|
|
21
|
+
return typeof value === 'number' && Number.isInteger(value) && value >= 0 ? value : null;
|
|
22
|
+
}
|
|
23
|
+
/** The number of rows a partition consumes. */
|
|
24
|
+
export function rowGroupsTotal(groups) {
|
|
25
|
+
return (groups.headRows +
|
|
26
|
+
groups.bodies.reduce((sum, b) => sum + b.headRows + b.bodyRows, 0) +
|
|
27
|
+
groups.footRows);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Read `table.rowGroups` for a table of `rowCount` rows.
|
|
31
|
+
*
|
|
32
|
+
* Absent is not an error: it means the implicit structure every renderer
|
|
33
|
+
* already derives. Present but unusable IS one, and it is reported rather
|
|
34
|
+
* than repaired, because guessing which of the counts was meant would produce
|
|
35
|
+
* a table nobody wrote.
|
|
36
|
+
*/
|
|
37
|
+
export function readRowGroups(value, rowCount) {
|
|
38
|
+
if (value === undefined || value === null)
|
|
39
|
+
return { groups: null, error: null };
|
|
40
|
+
if (!isObject(value))
|
|
41
|
+
return { groups: null, error: 'rowGroups is not an object' };
|
|
42
|
+
const headRows = count(value['headRows']);
|
|
43
|
+
const footRows = count(value['footRows']);
|
|
44
|
+
if (headRows === null || footRows === null) {
|
|
45
|
+
return { groups: null, error: 'rowGroups needs integer headRows and footRows of at least 0' };
|
|
46
|
+
}
|
|
47
|
+
if (!Array.isArray(value['bodies'])) {
|
|
48
|
+
return { groups: null, error: 'rowGroups needs a bodies array (an empty one is a head-only table)' };
|
|
49
|
+
}
|
|
50
|
+
const bodies = [];
|
|
51
|
+
for (const [i, raw] of value['bodies'].entries()) {
|
|
52
|
+
if (!isObject(raw))
|
|
53
|
+
return { groups: null, error: `rowGroups body ${i + 1} is not an object` };
|
|
54
|
+
const bodyHead = count(raw['headRows']);
|
|
55
|
+
const bodyRows = count(raw['bodyRows']);
|
|
56
|
+
if (bodyHead === null || bodyRows === null) {
|
|
57
|
+
return {
|
|
58
|
+
groups: null,
|
|
59
|
+
error: `rowGroups body ${i + 1} needs integer headRows and bodyRows of at least 0`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const body = { headRows: bodyHead, bodyRows };
|
|
63
|
+
if (raw['rowHeadColumns'] !== undefined) {
|
|
64
|
+
const rowHead = count(raw['rowHeadColumns']);
|
|
65
|
+
if (rowHead === null) {
|
|
66
|
+
return { groups: null, error: `rowGroups body ${i + 1} has a rowHeadColumns that is not a count` };
|
|
67
|
+
}
|
|
68
|
+
if (rowHead > 0)
|
|
69
|
+
body.rowHeadColumns = rowHead;
|
|
70
|
+
}
|
|
71
|
+
if (raw['attrs'] !== undefined)
|
|
72
|
+
body.attrs = raw['attrs'];
|
|
73
|
+
bodies.push(body);
|
|
74
|
+
}
|
|
75
|
+
const groups = { headRows, bodies, footRows };
|
|
76
|
+
const total = rowGroupsTotal(groups);
|
|
77
|
+
if (total !== rowCount) {
|
|
78
|
+
return {
|
|
79
|
+
groups: null,
|
|
80
|
+
error: `rowGroups partitions ${total} row(s) but the table has ${rowCount} ` +
|
|
81
|
+
`(head ${headRows}, ${bodies.map((b) => `body ${b.headRows}+${b.bodyRows}`).join(', ') || 'no bodies'}, foot ${footRows}). ` +
|
|
82
|
+
'PART 12 §15 requires the counts to account for every row exactly once, and no schema can check that',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return { groups, error: null };
|
|
86
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@markup-carve/pandoc-carve",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Carve to Pandoc bridge: convert Carve markup to Pandoc's JSON AST and reach every pandoc output format (LaTeX, Typst, DOCX, PDF, ...)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"carve",
|
|
7
|
+
"pandoc",
|
|
8
|
+
"markup",
|
|
9
|
+
"converter",
|
|
10
|
+
"latex",
|
|
11
|
+
"typst",
|
|
12
|
+
"ast"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "Mark Scherer",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"bin": {
|
|
26
|
+
"pandoc-carve": "./dist/cli.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist"
|
|
30
|
+
],
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc",
|
|
39
|
+
"examples:build": "npm run build && node scripts/build-examples.mjs",
|
|
40
|
+
"test": "npm run build && node --test test/*.test.mjs",
|
|
41
|
+
"prepublishOnly": "npm run build"
|
|
42
|
+
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/markup-carve/pandoc-carve.git"
|
|
46
|
+
},
|
|
47
|
+
"support": {
|
|
48
|
+
"issues": "https://github.com/markup-carve/pandoc-carve/issues",
|
|
49
|
+
"source": "https://github.com/markup-carve/pandoc-carve"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@markup-carve/carve": "git+https://github.com/markup-carve/carve-js.git#db224f30d10a3c2d7a192b0e60de66563404b7e5"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/node": "^24.0.0",
|
|
56
|
+
"ajv": "^8.20.0",
|
|
57
|
+
"typescript": "^5.8.0"
|
|
58
|
+
}
|
|
59
|
+
}
|