@markup-carve/pandoc-carve 0.1.7 → 0.1.8
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/dist/convert.js +32 -24
- package/dist/reverse.js +122 -66
- package/package.json +2 -2
package/dist/convert.js
CHANGED
|
@@ -452,8 +452,8 @@ function inLink(ctx, n) {
|
|
|
452
452
|
* The heading a COLLAPSED reference reaches, or null.
|
|
453
453
|
*
|
|
454
454
|
* `[Some Heading][]` with no definition anywhere links to the heading whose
|
|
455
|
-
* RENDERED text matches, case
|
|
456
|
-
* `# Plain One
|
|
455
|
+
* RENDERED text matches exactly, case included - so `[Plain One][]` reaches
|
|
456
|
+
* `# Plain One` and `[plain one][]` does not. The engine resolves this after the parse, which is why the
|
|
457
457
|
* node still carries an empty `href` here.
|
|
458
458
|
*
|
|
459
459
|
* Only the collapsed form. `[text][Some Heading]` does not reach a heading,
|
|
@@ -463,9 +463,13 @@ function inLink(ctx, n) {
|
|
|
463
463
|
function collapsedHeadingRef(ctx, n) {
|
|
464
464
|
if (!String(n.rawRef ?? '').endsWith('][]'))
|
|
465
465
|
return undefined;
|
|
466
|
-
const text = plainText(n.children ?? [])
|
|
466
|
+
const text = headingTextKey(plainText(n.children ?? []));
|
|
467
467
|
return text ? ctx.headingIdByText.get(text) : undefined;
|
|
468
468
|
}
|
|
469
|
+
/** The key a collapsed reference and a heading's text meet on (PART 9R R1). */
|
|
470
|
+
function headingTextKey(text) {
|
|
471
|
+
return text.replace(/[ \t\n\f\r]+/g, ' ').replace(/^ | $/g, '').normalize('NFC');
|
|
472
|
+
}
|
|
469
473
|
function unresolvedReference(ctx, n, kind) {
|
|
470
474
|
if (n.ref === undefined)
|
|
471
475
|
return null;
|
|
@@ -631,20 +635,21 @@ function inline(ctx, n) {
|
|
|
631
635
|
if (ctx.inCrossref)
|
|
632
636
|
return [];
|
|
633
637
|
const target = String(n.target ?? '');
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
638
|
+
// Ids compare exactly (PART 9R R4): the target as written, then
|
|
639
|
+
// its NFC form. No case fold.
|
|
640
|
+
const key = ctx.crossrefTargets.has(target) ? target : target.normalize('NFC');
|
|
641
|
+
const found = ctx.crossrefTargets.get(key);
|
|
637
642
|
if (found) {
|
|
638
643
|
// A caption target cannot come back as a crossref (see
|
|
639
644
|
// `captionTargets`), so it goes out as a plain link.
|
|
640
|
-
const classes = ctx.captionTargets.has(
|
|
645
|
+
const classes = ctx.captionTargets.has(key)
|
|
641
646
|
? []
|
|
642
647
|
: ['crossref'];
|
|
643
648
|
ctx.inCrossref = true;
|
|
644
649
|
try {
|
|
645
650
|
return [
|
|
646
651
|
P.Link(P.attr(undefined, classes), inlines(ctx, found), [
|
|
647
|
-
`#${
|
|
652
|
+
`#${key}`,
|
|
648
653
|
'',
|
|
649
654
|
]),
|
|
650
655
|
];
|
|
@@ -906,14 +911,6 @@ function citationDefinition(ctx, n) {
|
|
|
906
911
|
// pandoc's own readers produce.
|
|
907
912
|
entry.length ? [P.Para(entry)] : []);
|
|
908
913
|
}
|
|
909
|
-
function findCaseInsensitive(map, target) {
|
|
910
|
-
const lower = target.toLowerCase();
|
|
911
|
-
for (const [k, v] of map) {
|
|
912
|
-
if (k.toLowerCase() === lower)
|
|
913
|
-
return v;
|
|
914
|
-
}
|
|
915
|
-
return undefined;
|
|
916
|
-
}
|
|
917
914
|
// --- Blocks ---
|
|
918
915
|
function blocks(ctx, nodes) {
|
|
919
916
|
if (!nodes)
|
|
@@ -1563,11 +1560,22 @@ function table(ctx, n, caption, shortCaption = null) {
|
|
|
1563
1560
|
+ `${lead} unmarked one(s), which its model cannot express`, { construct: 'table', row: r + 1, rowHeadColumns: lead, dropped: strays }, n.pos);
|
|
1564
1561
|
}
|
|
1565
1562
|
return P.Table(
|
|
1566
|
-
// `header-rows` / `footer-rows` are the partition
|
|
1567
|
-
// reached `groups` above - leaving them here would
|
|
1568
|
-
// twice and put a stray attribute on the table in
|
|
1569
|
-
// The list-table reader
|
|
1570
|
-
|
|
1563
|
+
// `header-rows` / `footer-rows` are the partition when a partition was
|
|
1564
|
+
// consumed, and it reached `groups` above - leaving them here would
|
|
1565
|
+
// state the same fact twice and put a stray attribute on the table in
|
|
1566
|
+
// every pandoc writer. The list-table reader filters its own copies too.
|
|
1567
|
+
//
|
|
1568
|
+
// WITHOUT A PARTITION THEY ARE ORDINARY ATTRIBUTES AND HAVE TO SURVIVE.
|
|
1569
|
+
// PART 12 section 15: invalid body metadata synthesizes no partition and
|
|
1570
|
+
// leaves every row-group name, `header-rows` and `footer-rows` included,
|
|
1571
|
+
// an ordinary attribute in HTML. The engine keeps the keys on `attrs`
|
|
1572
|
+
// either way and signals consumption by `rowGroups` alone, so that is
|
|
1573
|
+
// what this reads. Corpus 541: `{header-rows=1 body-rows=x}` renders
|
|
1574
|
+
// `<table header-rows="1" body-rows="x">` and filtering unconditionally
|
|
1575
|
+
// dropped the first of the two.
|
|
1576
|
+
toAttrWithout(ctx, n.attrs, groups
|
|
1577
|
+
? ['aligns', 'valigns', 'widths', 'header-rows', 'footer-rows']
|
|
1578
|
+
: ['aligns', 'valigns', 'widths']), caption, colAligns, toRows(0, headCount), bodies, footRows, shortCaption, Array.from({ length: width }, (_, c) => columns[c]?.width ?? null), toAttr(ctx, groups?.headAttrs), toAttr(ctx, groups?.footAttrs));
|
|
1571
1579
|
}
|
|
1572
1580
|
/**
|
|
1573
1581
|
* The row-head column count a declared body's rows agree on, or 0.
|
|
@@ -2196,7 +2204,7 @@ function collectCrossrefTargets(ctx, nodes, captionCounts, inPanel = false) {
|
|
|
2196
2204
|
const id = a.id ?? slugify(plainText(children));
|
|
2197
2205
|
if (id && !ctx.crossrefTargets.has(id))
|
|
2198
2206
|
ctx.crossrefTargets.set(id, children);
|
|
2199
|
-
const text = plainText(children)
|
|
2207
|
+
const text = headingTextKey(plainText(children));
|
|
2200
2208
|
// First heading wins, the same way the id map resolves a duplicate.
|
|
2201
2209
|
if (id && text && !ctx.headingIdByText.has(text))
|
|
2202
2210
|
ctx.headingIdByText.set(text, id);
|
|
@@ -2214,7 +2222,7 @@ function collectCrossrefTargets(ctx, nodes, captionCounts, inPanel = false) {
|
|
|
2214
2222
|
const a = (n.attrs ?? {});
|
|
2215
2223
|
if (a.id && !ctx.crossrefTargets.has(a.id)) {
|
|
2216
2224
|
ctx.crossrefTargets.set(a.id, [{ type: 'text', value: `${label} ${next}` }]);
|
|
2217
|
-
ctx.captionTargets.add(a.id
|
|
2225
|
+
ctx.captionTargets.add(a.id);
|
|
2218
2226
|
}
|
|
2219
2227
|
}
|
|
2220
2228
|
}
|
|
@@ -2259,7 +2267,7 @@ function figureGroupTargets(ctx, n, captionCounts, inPanel) {
|
|
|
2259
2267
|
const a = (n.attrs ?? {});
|
|
2260
2268
|
if (a.id && !ctx.crossrefTargets.has(a.id)) {
|
|
2261
2269
|
ctx.crossrefTargets.set(a.id, [{ type: 'text', value: resolved }]);
|
|
2262
|
-
ctx.captionTargets.add(a.id
|
|
2270
|
+
ctx.captionTargets.add(a.id);
|
|
2263
2271
|
}
|
|
2264
2272
|
}
|
|
2265
2273
|
let panelIndex = 0;
|
package/dist/reverse.js
CHANGED
|
@@ -1120,7 +1120,77 @@ function table(ctx, c, captionOverride, shortCaptionOverride = null) {
|
|
|
1120
1120
|
// pushed per raw row, so §15's sum holds by construction here. It is
|
|
1121
1121
|
// checked where it can actually fail instead: on a partition that arrived
|
|
1122
1122
|
// from outside (see readRowGroups).
|
|
1123
|
-
|
|
1123
|
+
// PART 12 section 15, carve#2402: A ROW-HEAD COUNT THE CELLS ALREADY STATE
|
|
1124
|
+
// IS NOT A PARTITION. One body's data rows all carry the same leading `|=`
|
|
1125
|
+
// run, so the count is derivable from them and the field would state
|
|
1126
|
+
// nothing the rows do not - section 15 asks a producer to publish no
|
|
1127
|
+
// `rowGroups` for a table whose one departure is that count on its single
|
|
1128
|
+
// body. Measured on engine 0.1.10: keeping it made the writer spell
|
|
1129
|
+
// `{header-rows=1 body-rows=1 body-header-cols=1}` where the bare pipe
|
|
1130
|
+
// table renders byte-identical HTML. A body with no data row to carry the
|
|
1131
|
+
// markers keeps the field, and so does every multi-body partition, where
|
|
1132
|
+
// the counts are per body and the writer states them positionally.
|
|
1133
|
+
//
|
|
1134
|
+
// THE SAME RULE REACHES A SPLIT THAT ONLY ENCODES THOSE RUNS. Pandoc has no
|
|
1135
|
+
// per-row row-head count, so the FORWARD direction splits one Carve body at
|
|
1136
|
+
// every change in the marked run - that is the only way `|= b |` under
|
|
1137
|
+
// `| a |` keeps its scope through pandoc's model. Those bodies are an
|
|
1138
|
+
// encoding of the cells, not a partition the author wrote, and re-stating
|
|
1139
|
+
// them invents a `tbody` boundary the source never had: measured on corpus
|
|
1140
|
+
// 354-2, one `<tbody>` in becomes two out.
|
|
1141
|
+
//
|
|
1142
|
+
// A split that carries anything else - an intermediate header row, body
|
|
1143
|
+
// attributes, a head or a foot - is real and is stated.
|
|
1144
|
+
//
|
|
1145
|
+
// A LEADING RUN THAT COVERS EVERY COLUMN IS NOT DERIVABLE EITHER WAY. A row
|
|
1146
|
+
// whose every cell is marked reads as a HEADER ROW, and a leading run of
|
|
1147
|
+
// them becomes the table head - so leaving the first body's count to the
|
|
1148
|
+
// markers turns row headers into column headers. Measured on one column:
|
|
1149
|
+
// a single body of two rows at `RowHeadColumns = 1` came back as a two-row
|
|
1150
|
+
// `TableHead` over an empty body, and bodies at `[1, 0]` moved row 1 into
|
|
1151
|
+
// the head. Only the FIRST body matters, because only a LEADING run is read
|
|
1152
|
+
// as a head: corpus 354 collapses safely with counts `[0, 1]` over one
|
|
1153
|
+
// column, since nothing marks its first row.
|
|
1154
|
+
const leadingRunFillsTheRow = (groupBodies[0]?.rowHeadColumns ?? 0) >= nCols;
|
|
1155
|
+
//
|
|
1156
|
+
// EVERY ADJACENT PAIR MUST DISAGREE, because the forward direction splits at
|
|
1157
|
+
// every CHANGE in the run - so the bodies it synthesizes never put two equal
|
|
1158
|
+
// counts side by side. Counts of `[1, 1, 0]` hold a boundary no run change
|
|
1159
|
+
// could have produced, and collapsing the lot merged the first two sections.
|
|
1160
|
+
// "Some count somewhere differs" is not evidence about any one boundary.
|
|
1161
|
+
const adjacentRunsDiffer = groupBodies.every((body, i) => i === 0 || (body.rowHeadColumns ?? 0) !== (groupBodies[i - 1].rowHeadColumns ?? 0));
|
|
1162
|
+
//
|
|
1163
|
+
// AND IT IS THE SOURCE WRITER'S NORMALIZATION ONLY. The pipe table cannot
|
|
1164
|
+
// tell a derived split from an authored one, so writing it has to choose;
|
|
1165
|
+
// the exchange AST has no such constraint and `rowGroups` is exact there,
|
|
1166
|
+
// so `pandocToCarveAst` keeps every boundary the pandoc table carried.
|
|
1167
|
+
const onlyRowHeadRuns = ctx.target === 'source'
|
|
1168
|
+
&& groupBodies.length > 1
|
|
1169
|
+
&& groupBodies.every((b) => b.headRows === 0 && b.attrs === undefined)
|
|
1170
|
+
// AN EMPTY BODY IS NEVER A DERIVED ONE. The splitter cuts a run of data
|
|
1171
|
+
// rows, so it cannot produce a body with none, and section 15 asks the
|
|
1172
|
+
// writer to state even a single empty body. Collapsing one dropped the
|
|
1173
|
+
// boundary AND, with the empty body leading, left the count check
|
|
1174
|
+
// looking at a body with no rows to mark: `[0 (empty), 2]` over two
|
|
1175
|
+
// columns emitted one fully marked row, which came back as the head.
|
|
1176
|
+
&& groupBodies.every((b) => b.bodyRows > 0)
|
|
1177
|
+
&& adjacentRunsDiffer
|
|
1178
|
+
&& !leadingRunFillsTheRow
|
|
1179
|
+
&& headRaw.length === 0 && footRaw.length === 0
|
|
1180
|
+
&& !headAttrs && !footAttrs;
|
|
1181
|
+
const collapsed = [{
|
|
1182
|
+
headRows: 0,
|
|
1183
|
+
bodyRows: groupBodies.reduce((sum, b) => sum + b.bodyRows, 0),
|
|
1184
|
+
}];
|
|
1185
|
+
const derivableRowHead = groupBodies.length === 1
|
|
1186
|
+
&& groupBodies[0].bodyRows > 0
|
|
1187
|
+
&& !leadingRunFillsTheRow;
|
|
1188
|
+
const publishedBodies = onlyRowHeadRuns
|
|
1189
|
+
? collapsed
|
|
1190
|
+
: derivableRowHead
|
|
1191
|
+
? groupBodies.map(({ rowHeadColumns: _derivable, ...rest }) => rest)
|
|
1192
|
+
: groupBodies;
|
|
1193
|
+
const groups = { headRows: headRaw.length, bodies: publishedBodies, footRows: footRaw.length };
|
|
1124
1194
|
if (headAttrs)
|
|
1125
1195
|
groups.headAttrs = headAttrs;
|
|
1126
1196
|
if (footAttrs)
|
|
@@ -1130,18 +1200,10 @@ function table(ctx, c, captionOverride, shortCaptionOverride = null) {
|
|
|
1130
1200
|
if (ctx.target === 'source')
|
|
1131
1201
|
reportUnspellableGroups(ctx, groups);
|
|
1132
1202
|
}
|
|
1133
|
-
//
|
|
1134
|
-
//
|
|
1135
|
-
//
|
|
1136
|
-
//
|
|
1137
|
-
// merge has no cost to report.
|
|
1138
|
-
const stated = ctx.target === 'source' && footRaw.length > 0;
|
|
1139
|
-
reportRunsAStatedPartitionMerges(ctx, {
|
|
1140
|
-
leads: allRaw.map((_, r) => (isHeaderRow[r] === true ? nCols : rowHeadCols[r] ?? 0)),
|
|
1141
|
-
from: headRaw.length,
|
|
1142
|
-
to: allRaw.length - footRaw.length,
|
|
1143
|
-
stated,
|
|
1144
|
-
});
|
|
1203
|
+
// STATING THE PARTITION IS THE SOURCE WRITER'S BUSINESS ONLY. On the `ast`
|
|
1204
|
+
// target it stays in `rowGroups`, where it is exact: there is no attribute
|
|
1205
|
+
// line to state it on, so stating it would invent attributes the pandoc
|
|
1206
|
+
// table never carried.
|
|
1145
1207
|
const attrs = ctx.target === 'source' ? statePartition(fromAttr(a), groups) : fromAttr(a);
|
|
1146
1208
|
if (attrs)
|
|
1147
1209
|
node.attrs = attrs;
|
|
@@ -1155,33 +1217,20 @@ function table(ctx, c, captionOverride, shortCaptionOverride = null) {
|
|
|
1155
1217
|
return node;
|
|
1156
1218
|
}
|
|
1157
1219
|
/**
|
|
1158
|
-
*
|
|
1159
|
-
*
|
|
1160
|
-
* The count is not written down anywhere - `RowHeadColumns` has no spelling on
|
|
1161
|
-
* the attribute line - so the reader derives it from the leading `|=` run of the
|
|
1162
|
-
* body rows. It can only take a count every row agrees on: a declared body's
|
|
1163
|
-
* boundaries were stated, so it cannot split at a change the way the derived
|
|
1164
|
-
* bodies do. Rows that disagree therefore come back as data cells.
|
|
1220
|
+
* Whether the table's attributes carry body metadata the engine did not consume.
|
|
1165
1221
|
*
|
|
1166
|
-
*
|
|
1167
|
-
*
|
|
1168
|
-
*
|
|
1169
|
-
*
|
|
1170
|
-
* Reported from the writer because the writer is the only side that knows the
|
|
1171
|
-
* runs it just wrote: by the time the source is read back, the disagreement is
|
|
1172
|
-
* all that is left of them.
|
|
1222
|
+
* The positional keys only reach `keyValues` when the engine read them as
|
|
1223
|
+
* invalid - a consumed partition is spent on the AST's `rowGroups` instead. So
|
|
1224
|
+
* their presence beside a flat partition is the signal, and PART 12 section 15
|
|
1225
|
+
* then makes every row-group name on that block an ordinary attribute.
|
|
1173
1226
|
*/
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
if (!
|
|
1177
|
-
return;
|
|
1178
|
-
const
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
warn(ctx, 'table: the body rows disagree on how many leading cells are row headers '
|
|
1182
|
-
+ `(${[...distinct].sort((x, y) => x - y).join(', ')}), and stating the foot states `
|
|
1183
|
-
+ 'the whole partition as ONE body - the reader takes a count every row agrees on, so '
|
|
1184
|
-
+ 'those cells come back as data cells');
|
|
1227
|
+
const POSITIONAL_BODY_KEYS = ['body-rows', 'body-header-rows', 'body-header-cols'];
|
|
1228
|
+
function carriesInvalidBodyMetadata(keyValues, groups) {
|
|
1229
|
+
if (!POSITIONAL_BODY_KEYS.some((key) => keyValues[key] !== undefined))
|
|
1230
|
+
return false;
|
|
1231
|
+
const flat = groups.headRows === 0 && groups.footRows === 0 && groups.bodies.length === 1
|
|
1232
|
+
&& groups.bodies[0].headRows === 0 && groups.bodies[0].attrs === undefined;
|
|
1233
|
+
return flat;
|
|
1185
1234
|
}
|
|
1186
1235
|
/**
|
|
1187
1236
|
* State the head and foot row counts on the pipe table's attribute line.
|
|
@@ -1217,9 +1266,23 @@ function reportRunsAStatedPartitionMerges(ctx, input) {
|
|
|
1217
1266
|
*/
|
|
1218
1267
|
function statePartition(attrs, groups) {
|
|
1219
1268
|
const keyValues = { ...(attrs?.keyValues ?? {}) };
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1269
|
+
// INVALID BODY METADATA MAKES THE WHOLE VOCABULARY ORDINARY ATTRIBUTES, and
|
|
1270
|
+
// an ordinary attribute is retained, not restated. PART 12 section 15:
|
|
1271
|
+
// "Invalid body metadata synthesizes no partition; all row-group metadata
|
|
1272
|
+
// attributes, including `header-rows` and `footer-rows`, remain ordinary
|
|
1273
|
+
// attributes in HTML." Corpus 541 exists to pin that, and dropping
|
|
1274
|
+
// `header-rows` from `{header-rows=1 body-rows=x}` broke it: the source
|
|
1275
|
+
// renders `<table header-rows="1" body-rows="x">` and the round trip
|
|
1276
|
+
// rendered `<table body-rows="x">`.
|
|
1277
|
+
//
|
|
1278
|
+
// The stale-key guard below still applies whenever no such key is present,
|
|
1279
|
+
// which is every table whose partition the engine actually consumed - a
|
|
1280
|
+
// consumed key never reaches `keyValues` at all.
|
|
1281
|
+
if (!carriesInvalidBodyMetadata(keyValues, groups)) {
|
|
1282
|
+
delete keyValues['header-rows'];
|
|
1283
|
+
delete keyValues['footer-rows'];
|
|
1284
|
+
}
|
|
1285
|
+
if (groups.footRows > 0 && !carriesInvalidBodyMetadata(keyValues, groups)) {
|
|
1223
1286
|
if (groups.headRows > 0)
|
|
1224
1287
|
keyValues['header-rows'] = String(groups.headRows);
|
|
1225
1288
|
keyValues['footer-rows'] = String(groups.footRows);
|
|
@@ -1247,43 +1310,36 @@ function statePartition(attrs, groups) {
|
|
|
1247
1310
|
/**
|
|
1248
1311
|
* What a `rowGroups` partition says that the PIPE form cannot say back.
|
|
1249
1312
|
*
|
|
1250
|
-
*
|
|
1251
|
-
* intact
|
|
1252
|
-
*
|
|
1253
|
-
*
|
|
1254
|
-
*
|
|
1255
|
-
* PART 12 §15 says so in as many words and asks for exactly this - "a canonical
|
|
1256
|
-
* Carve writer loses it ... conversion APIs with diagnostics should report that
|
|
1257
|
-
* loss".
|
|
1313
|
+
* Only a body group's own attributes, now. The partition itself reaches the
|
|
1314
|
+
* exchange AST intact and `pandocToCarveAst` hands it on whole, and the source
|
|
1315
|
+
* writer states the rest of it: `{header-rows=N footer-rows=M}` for the head
|
|
1316
|
+
* and foot, and PART 12 section 15's positional `body-rows`,
|
|
1317
|
+
* `body-header-rows` and `body-header-cols` for the bodies.
|
|
1258
1318
|
*
|
|
1259
|
-
*
|
|
1260
|
-
*
|
|
1261
|
-
*
|
|
1262
|
-
*
|
|
1263
|
-
*
|
|
1264
|
-
*
|
|
1319
|
+
* THREE THINGS CAME OFF THIS LIST, each because the writer started spelling
|
|
1320
|
+
* them. The foot went first. Row-head columns went next, read back off the
|
|
1321
|
+
* `|= North | 11 |` markers the writer puts on the cells. The body groups and
|
|
1322
|
+
* their intermediate header rows went with carve 0.1.10, which writes the
|
|
1323
|
+
* positional keys: measured on a head, two bodies of which the second leads
|
|
1324
|
+
* with a header row, and a foot, the round trip returns the same partition and
|
|
1325
|
+
* the HTML carries one `tbody` per body. Reporting them as lost named a loss
|
|
1326
|
+
* that no longer happens.
|
|
1265
1327
|
*
|
|
1266
|
-
*
|
|
1267
|
-
*
|
|
1268
|
-
* the forward direction reads the count back off exactly that run. Measured in
|
|
1269
|
-
* both shapes, with a foot and without.
|
|
1328
|
+
* Section attributes have no attribute-line spelling at all (section 15 says
|
|
1329
|
+
* so), so they are what is left.
|
|
1270
1330
|
*
|
|
1271
1331
|
* AST output retains these groups. This diagnostic applies only when writing
|
|
1272
|
-
* source
|
|
1332
|
+
* source.
|
|
1273
1333
|
*/
|
|
1274
1334
|
function reportUnspellableGroups(ctx, groups) {
|
|
1275
1335
|
const lost = [];
|
|
1276
|
-
if (groups.bodies.length > 1)
|
|
1277
|
-
lost.push(`${groups.bodies.length} body groups`);
|
|
1278
|
-
if (groups.bodies.some((b) => b.headRows > 0))
|
|
1279
|
-
lost.push("a body's intermediate header rows");
|
|
1280
1336
|
if (groups.bodies.some((b) => b.attrs !== undefined))
|
|
1281
1337
|
lost.push("a body group's attributes");
|
|
1282
1338
|
if (!lost.length)
|
|
1283
1339
|
return;
|
|
1284
1340
|
warn(ctx, `table: ${lost.join(', ')} - preserved in the Carve AST as \`rowGroups\`, `
|
|
1285
|
-
+ 'but
|
|
1286
|
-
+ 'emitted source
|
|
1341
|
+
+ 'but Carve source has no spelling for the attributes of a table section, '
|
|
1342
|
+
+ 'so the emitted source drops them');
|
|
1287
1343
|
}
|
|
1288
1344
|
/**
|
|
1289
1345
|
* Whether a cell's blocks fit Carve's pipe-table cell, which holds INLINES.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markup-carve/pandoc-carve",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
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
5
|
"keywords": [
|
|
6
6
|
"carve",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"source": "https://github.com/markup-carve/pandoc-carve"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@markup-carve/carve": "^0.1.
|
|
58
|
+
"@markup-carve/carve": "^0.1.10"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@types/node": "^24.0.0",
|