@openpresentation/cli 0.2.0 → 0.4.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/README.md +1 -1
- package/dist/index.js +288 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ npm install -g @openpresentation/cli
|
|
|
13
13
|
opf --version
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
Or install it as a development dependency and use `npx --no-install opf`.
|
|
16
|
+
Or install it as a development dependency and use `npx --no-install opf`. CLI 0.2.0 bundles OPF 0.5.0 and supports rich table cells and headers during validation and pagination.
|
|
17
17
|
|
|
18
18
|
To verify the standalone package from source, run `pnpm install` and `pnpm test:cli:packed`. This creates `artifacts/cli/openpresentation-cli-0.2.0.tgz`, which can be installed using its absolute path. For source development, run `pnpm --filter @openpresentation/cli build` and `node packages/cli/dist/index.js --help`.
|
|
19
19
|
|
package/dist/index.js
CHANGED
|
@@ -8163,11 +8163,46 @@ function createDataContent(input, options) {
|
|
|
8163
8163
|
return { chart: { type: options.chartType ?? "column", data: { columns: names, rows: rows2 } } };
|
|
8164
8164
|
}
|
|
8165
8165
|
|
|
8166
|
-
// ../javascript/dist/chunk-
|
|
8166
|
+
// ../javascript/dist/chunk-OVPWNQIJ.js
|
|
8167
|
+
var record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
8168
|
+
function tableGrid(value, path2 = "table") {
|
|
8169
|
+
const table = record(value), hasHeaders = Array.isArray(table.columns) && table.columns.length > 0;
|
|
8170
|
+
const values = [...hasHeaders ? [table.columns] : [], ...Array.isArray(table.rows) ? table.rows : []];
|
|
8171
|
+
const columnCount = values.reduce((count, row) => Math.max(count, Array.isArray(row) ? row.length : 0), 1), rowCount = values.length;
|
|
8172
|
+
const owners = Array.from({ length: rowCount }, () => Array(columnCount));
|
|
8173
|
+
const rows2 = Array.from({ length: rowCount }, () => []), issues = [];
|
|
8174
|
+
const location = (r, c) => `${path2}.${hasHeaders && r === 0 ? "columns" : `rows.${r - Number(hasHeaders)}`}.${c}`;
|
|
8175
|
+
for (let r = 0; r < rowCount; r++) for (let c = 0; c < columnCount; c++) {
|
|
8176
|
+
const input = values[r]?.[c], cellPath = location(r, c), existing = owners[r][c];
|
|
8177
|
+
if (existing) {
|
|
8178
|
+
if (input !== null) issues.push({ path: cellPath, message: "A position covered by a spanning cell must explicitly contain null; content cannot be hidden." });
|
|
8179
|
+
continue;
|
|
8180
|
+
}
|
|
8181
|
+
const object = record(input), styled = Object.hasOwn(object, "value");
|
|
8182
|
+
const rowSpan = styled ? object.rowSpan ?? 1 : 1, colSpan = styled ? object.colSpan ?? 1 : 1;
|
|
8183
|
+
if (!Number.isSafeInteger(rowSpan) || !Number.isSafeInteger(colSpan) || rowSpan < 1 || colSpan < 1 || r + rowSpan > rowCount || c + colSpan > columnCount || hasHeaders && r === 0 && rowSpan > 1) {
|
|
8184
|
+
issues.push({ path: cellPath, message: "Cell spans must be positive integers within the table grid and cannot cross from headers into body rows." });
|
|
8185
|
+
continue;
|
|
8186
|
+
}
|
|
8187
|
+
const cell2 = { input, value: styled ? object.value : input, style: styled ? record(object.style) : {}, row: r, column: c, rowSpan, colSpan, header: hasHeaders && r === 0, path: cellPath, valuePath: styled ? cellPath + ".value" : cellPath };
|
|
8188
|
+
rows2[r].push(cell2);
|
|
8189
|
+
for (let y = r; y < r + rowSpan; y++) for (let x = c; x < c + colSpan; x++) {
|
|
8190
|
+
if (owners[y][x]) issues.push({ path: cellPath, message: "Cell spans cannot overlap another spanning cell." });
|
|
8191
|
+
else owners[y][x] = cell2;
|
|
8192
|
+
}
|
|
8193
|
+
}
|
|
8194
|
+
return { rows: rows2, columnCount, rowCount, hasHeaders, owners, issues };
|
|
8195
|
+
}
|
|
8196
|
+
function tableRowBoundaries(value) {
|
|
8197
|
+
const grid = tableGrid(value), offset = Number(grid.hasHeaders), count = grid.rowCount - offset;
|
|
8198
|
+
const allowed = new Set(Array.from({ length: count + 1 }, (_, i) => i));
|
|
8199
|
+
for (const row of grid.rows) for (const cell2 of row) if (!cell2.header) for (let r = 1; r < cell2.rowSpan; r++) allowed.delete(cell2.row - offset + r);
|
|
8200
|
+
return [...allowed];
|
|
8201
|
+
}
|
|
8167
8202
|
var MAX_COMPOSITION_DEPTH = 32;
|
|
8168
8203
|
function resolveFontFamilies(input) {
|
|
8169
|
-
const scheme =
|
|
8170
|
-
const family = (value) => typeof value === "string" ? value :
|
|
8204
|
+
const scheme = record2(input);
|
|
8205
|
+
const family = (value) => typeof value === "string" ? value : record2(value).family;
|
|
8171
8206
|
return {
|
|
8172
8207
|
heading: family(scheme.heading) ?? scheme.major ?? scheme.minor ?? "Roboto",
|
|
8173
8208
|
body: family(scheme.body) ?? scheme.minor ?? scheme.major ?? "Roboto",
|
|
@@ -8198,7 +8233,7 @@ var fields = ["text", "items", "bullets", "image", "video", "chart", "table", "c
|
|
|
8198
8233
|
var headings = /* @__PURE__ */ new Set(["title", "subtitle", "tag"]);
|
|
8199
8234
|
var rows = ["top", "middle", "bottom"];
|
|
8200
8235
|
var columns = ["left", "center", "right"];
|
|
8201
|
-
var
|
|
8236
|
+
var record2 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
8202
8237
|
var kind = (field) => field === "items" || field === "bullets" ? "list" : field;
|
|
8203
8238
|
var round = (value) => Math.round(value * 1e6) / 1e6 || value;
|
|
8204
8239
|
var textSegments = new Intl.Segmenter("und", { granularity: "grapheme" });
|
|
@@ -8325,6 +8360,16 @@ function richTextLayouter(input, box, requestedSize, options) {
|
|
|
8325
8360
|
y += height;
|
|
8326
8361
|
return line;
|
|
8327
8362
|
});
|
|
8363
|
+
if (options.uniformLineHeight) {
|
|
8364
|
+
const height = Math.max(...richLines.map((line) => line.height));
|
|
8365
|
+
y = 0;
|
|
8366
|
+
for (const line of richLines) {
|
|
8367
|
+
line.baseline += y - line.y;
|
|
8368
|
+
line.y = y;
|
|
8369
|
+
line.height = height;
|
|
8370
|
+
y += height;
|
|
8371
|
+
}
|
|
8372
|
+
}
|
|
8328
8373
|
return { lines: ranges.map((range) => whole.slice(range.start, range.end)), fontSize, lineHeight: Math.max(fontSize * 1.22, ...richLines.map((line) => line.height)), richLines, height: y, overflow: y > box.height + 0.01 || richLines.some((line) => line.width > box.width + 0.01) };
|
|
8329
8374
|
};
|
|
8330
8375
|
return layout2;
|
|
@@ -8391,31 +8436,70 @@ function fitList(input, box, requestedSize = 25, minFontSize = 16, options = { s
|
|
|
8391
8436
|
function contentText(field, value) {
|
|
8392
8437
|
if (field === "text" || headings.has(field)) return flatten(value);
|
|
8393
8438
|
if (field === "items" || field === "bullets") return (Array.isArray(value) ? value : [value]).map((item) => {
|
|
8394
|
-
const entry =
|
|
8439
|
+
const entry = record2(item);
|
|
8395
8440
|
return `\u2022 ${flatten(item)}${entry.description ? `
|
|
8396
8441
|
${flatten(entry.description)}` : ""}`;
|
|
8397
8442
|
}).join("\n");
|
|
8398
|
-
if (field === "code") return flatten(
|
|
8399
|
-
if (field === "quote") return flatten(
|
|
8443
|
+
if (field === "code") return flatten(record2(value).source ?? value);
|
|
8444
|
+
if (field === "quote") return flatten(record2(value).text ?? value);
|
|
8400
8445
|
return void 0;
|
|
8401
8446
|
}
|
|
8402
|
-
function
|
|
8403
|
-
const
|
|
8404
|
-
|
|
8405
|
-
const
|
|
8406
|
-
|
|
8407
|
-
const
|
|
8408
|
-
|
|
8409
|
-
const
|
|
8410
|
-
const
|
|
8411
|
-
|
|
8412
|
-
|
|
8447
|
+
function layoutTable(value, box, options = {}) {
|
|
8448
|
+
const scale = options.scale ?? 1, requested = 15 * scale, minimum = (options.minFontSize ?? 16) * scale;
|
|
8449
|
+
if (![box.x, box.y, box.width, box.height, scale, minimum].every(Number.isFinite) || box.width <= 0 || box.height <= 0 || scale <= 0 || minimum <= 0) throw new RangeError("Table dimensions, scale and font sizes must be finite and positive.");
|
|
8450
|
+
const grid = tableGrid(value, options.path ?? "table");
|
|
8451
|
+
if (grid.issues.length) throw new RangeError(`${grid.issues[0].path}: ${grid.issues[0].message}`);
|
|
8452
|
+
const columnCount = grid.columnCount, cellWidth = box.width / columnCount;
|
|
8453
|
+
const cells = grid.rows.flat().map((cell2) => {
|
|
8454
|
+
const padding = { top: 8, right: 10, bottom: 4, left: 10, ...cell2.style.padding };
|
|
8455
|
+
const width = cellWidth * cell2.colSpan - (padding.left + padding.right) * scale;
|
|
8456
|
+
const style = { fontFamily: options.fontFamily ?? "sans-serif", fontWeight: cell2.header ? 700 : 400, italic: false, path: cell2.valuePath };
|
|
8457
|
+
return { ...cell2, padding, width, textStyle: style };
|
|
8458
|
+
});
|
|
8459
|
+
const fitCell = (cell2, height, min) => {
|
|
8460
|
+
const textBox = { width: Math.max(scale, cell2.width), height: Math.max(scale, height) };
|
|
8461
|
+
return Array.isArray(cell2.value) ? fitRichText(cell2.value, textBox, requested, min, { style: cell2.textStyle, textMeasurement: options.textMeasurement, uniformLineHeight: true }) : fitText(flatten(cell2.value), textBox, requested, min, textWidthMeasurer(resolveTextStyle(cell2.textStyle, options.textMeasurement), options.textMeasurement));
|
|
8462
|
+
};
|
|
8463
|
+
const textHeight = (fit) => "height" in fit ? fit.height : fit.lines.length * fit.lineHeight;
|
|
8464
|
+
const required = (cell2, size) => textHeight(fitCell(cell2, scale, size)) + (cell2.padding.top + cell2.padding.bottom) * scale;
|
|
8465
|
+
const natural = Array(grid.rowCount).fill(0), needed = Array(grid.rowCount).fill(0);
|
|
8466
|
+
for (const cell2 of cells) if (cell2.rowSpan === 1) {
|
|
8467
|
+
natural[cell2.row] = Math.max(natural[cell2.row], required(cell2, requested));
|
|
8468
|
+
needed[cell2.row] = Math.max(needed[cell2.row], required(cell2, minimum));
|
|
8469
|
+
}
|
|
8470
|
+
for (const cell2 of cells) if (cell2.rowSpan > 1) for (const [heights2, size] of [[natural, requested], [needed, minimum]]) {
|
|
8471
|
+
const current = heights2.slice(cell2.row, cell2.row + cell2.rowSpan).reduce((a, b) => a + b, 0);
|
|
8472
|
+
const extra = Math.max(0, required(cell2, size) - current) / cell2.rowSpan;
|
|
8473
|
+
for (let r = cell2.row; r < cell2.row + cell2.rowSpan; r++) heights2[r] += extra;
|
|
8474
|
+
}
|
|
8475
|
+
const preferred = natural.map((height) => Math.max(54 * scale, height));
|
|
8476
|
+
for (let r = 0; r < needed.length; r++) needed[r] = Math.min(preferred[r], needed[r]);
|
|
8477
|
+
const sum = (values) => values.reduce((a, b) => a + b, 0);
|
|
8478
|
+
const preferredTotal = sum(preferred), naturalTotal = sum(natural), neededTotal = sum(needed);
|
|
8479
|
+
const heights = preferred.map((height, r) => preferredTotal <= box.height ? height : naturalTotal <= box.height ? natural[r] + (height - natural[r]) * (box.height - naturalTotal) / Math.max(Number.EPSILON, preferredTotal - naturalTotal) : neededTotal <= box.height ? needed[r] + (natural[r] - needed[r]) * (box.height - neededTotal) / Math.max(Number.EPSILON, naturalTotal - neededTotal) : needed[r] * box.height / neededTotal);
|
|
8480
|
+
const ys = [box.y];
|
|
8481
|
+
for (const height of heights) ys.push(ys.at(-1) + height);
|
|
8482
|
+
let overflow = false;
|
|
8483
|
+
const rows2 = heights.map((height, r) => ({ box: { x: box.x, y: ys[r], width: box.width, height }, cells: [] }));
|
|
8484
|
+
for (const cell2 of cells) {
|
|
8485
|
+
const cellBox = { x: box.x + cell2.column * cellWidth, y: ys[cell2.row], width: cell2.colSpan * cellWidth, height: ys[cell2.row + cell2.rowSpan] - ys[cell2.row] };
|
|
8486
|
+
const available = cellBox.height - (cell2.padding.top + cell2.padding.bottom) * scale;
|
|
8487
|
+
const fit = fitCell(cell2, available, minimum), height = textHeight(fit);
|
|
8488
|
+
const offset = cell2.style.verticalAlign === "bottom" ? Math.max(0, available - height) : cell2.style.verticalAlign === "middle" ? Math.max(0, (available - height) / 2) : 0;
|
|
8489
|
+
const textBox = { x: cellBox.x + cell2.padding.left * scale, y: cellBox.y + cell2.padding.top * scale + offset, width: Math.max(scale, cell2.width), height: Math.max(scale, available - offset) };
|
|
8490
|
+
overflow ||= cell2.width <= 0 || available <= 0 || fit.overflow;
|
|
8491
|
+
rows2[cell2.row].cells.push({ value: cell2.value, input: cell2.input, path: cell2.valuePath, sourcePath: cell2.path, style: cell2.style, row: cell2.row, column: cell2.column, rowSpan: cell2.rowSpan, colSpan: cell2.colSpan, header: cell2.header, rich: Array.isArray(cell2.value), box: cellBox, textBox, textStyle: resolveTextStyle(cell2.textStyle, options.textMeasurement), fit });
|
|
8492
|
+
}
|
|
8493
|
+
return { rows: rows2, columnCount, height: sum(heights), overflow };
|
|
8494
|
+
}
|
|
8495
|
+
function tableOverflows(value, box, scale, settings, options, path2) {
|
|
8496
|
+
return box.width <= 0 || box.height <= 0 || layoutTable(value, box, { scale, minFontSize: settings.minFontSize, fontFamily: options.fonts?.body, textMeasurement: options.textMeasurement, path: path2 }).overflow;
|
|
8413
8497
|
}
|
|
8414
8498
|
function flatten(value) {
|
|
8415
8499
|
if (value == null) return "";
|
|
8416
8500
|
if (typeof value !== "object") return String(value);
|
|
8417
8501
|
if (Array.isArray(value)) return value.map(flatten).join("");
|
|
8418
|
-
const item =
|
|
8502
|
+
const item = record2(value);
|
|
8419
8503
|
return flatten(item.text ?? item.value ?? item.source ?? JSON.stringify(value));
|
|
8420
8504
|
}
|
|
8421
8505
|
function regionParts(key) {
|
|
@@ -8471,11 +8555,11 @@ function assertComposition(value) {
|
|
|
8471
8555
|
if (value.overflow !== void 0 && !["warn", "error"].includes(value.overflow)) throw new RangeError("Invalid composition.overflow.");
|
|
8472
8556
|
}
|
|
8473
8557
|
function composeSlide(input, options = {}) {
|
|
8474
|
-
const slide =
|
|
8558
|
+
const slide = record2(input), layout2 = record2(options.layout);
|
|
8475
8559
|
const width = options.width ?? 1280, height = options.height ?? 720;
|
|
8476
8560
|
if (![width, height].every((value) => Number.isFinite(value) && value > 0)) throw new RangeError("Canvas dimensions must be finite and positive.");
|
|
8477
8561
|
const scale = Math.min(width, height) / 720;
|
|
8478
|
-
const composition = { ...
|
|
8562
|
+
const composition = { ...record2(layout2.composition), ...record2(slide.composition) };
|
|
8479
8563
|
assertComposition(composition);
|
|
8480
8564
|
const padding = (composition.padding ?? 0.08) * Math.min(width, height);
|
|
8481
8565
|
const gap = (composition.gap ?? 1 / 30) * Math.min(width, height);
|
|
@@ -8505,7 +8589,7 @@ function composeSlide(input, options = {}) {
|
|
|
8505
8589
|
const collect = (host, basePath, depth = 0, ancestors = []) => {
|
|
8506
8590
|
if (Array.isArray(host.blocks)) {
|
|
8507
8591
|
if (depth >= MAX_COMPOSITION_DEPTH || ancestors.includes(host)) throw new RangeError(`Content groups must be acyclic and nest at most ${MAX_COMPOSITION_DEPTH} levels.`);
|
|
8508
|
-
const settings =
|
|
8592
|
+
const settings = record2(host.composition);
|
|
8509
8593
|
assertComposition(settings);
|
|
8510
8594
|
return [{
|
|
8511
8595
|
field: "blocks",
|
|
@@ -8514,13 +8598,13 @@ function composeSlide(input, options = {}) {
|
|
|
8514
8598
|
path: basePath,
|
|
8515
8599
|
payload: host,
|
|
8516
8600
|
composition: settings,
|
|
8517
|
-
children: host.blocks.flatMap((block, index2) => collect(
|
|
8601
|
+
children: host.blocks.flatMap((block, index2) => collect(record2(block), `${basePath}.blocks.${index2}`, depth + 1, [...ancestors, host]))
|
|
8518
8602
|
}];
|
|
8519
8603
|
}
|
|
8520
8604
|
return fields.filter((field) => host[field] !== void 0).map((field) => ({ field, type: host.type ?? kind(field), value: host[field], path: `${basePath}.${field}`, payload: { type: host.type ?? kind(field), [field]: host[field] } }));
|
|
8521
8605
|
};
|
|
8522
8606
|
const regions = Object.keys(slide).filter((key) => regionParts(key)).sort();
|
|
8523
|
-
const pending = regions.length ? regions.flatMap((key) => collect(
|
|
8607
|
+
const pending = regions.length ? regions.flatMap((key) => collect(record2(slide[key]), `${path2}.${key}`).map((item) => ({ ...item, region: regionParts(key) }))) : Array.isArray(slide.blocks) ? slide.blocks.flatMap((block, index2) => collect(record2(block), `${path2}.blocks.${index2}`)) : collect(slide, path2);
|
|
8524
8608
|
const groups = [], flows = [];
|
|
8525
8609
|
const inheritedSettings = (parent, own3 = {}) => ({
|
|
8526
8610
|
minFontSize: parent.minFontSize,
|
|
@@ -8538,7 +8622,7 @@ function composeSlide(input, options = {}) {
|
|
|
8538
8622
|
const fit = fitContent(node.field, node.value, text, box, 25 * scale, (settings.minFontSize ?? 16) * scale, node.path);
|
|
8539
8623
|
score += (25 * scale - fit.fontSize) / scale + (fit.overflow ? 1e3 : 0);
|
|
8540
8624
|
}
|
|
8541
|
-
if (node.field === "table" && tableOverflows(node.value, box, scale, settings, options)) score += 1e3;
|
|
8625
|
+
if (node.field === "table" && tableOverflows(node.value, box, scale, settings, options, node.path)) score += 1e3;
|
|
8542
8626
|
if (box.width < 100 * scale || box.height < 60 * scale) score += 100;
|
|
8543
8627
|
return score;
|
|
8544
8628
|
};
|
|
@@ -8593,7 +8677,7 @@ function composeSlide(input, options = {}) {
|
|
|
8593
8677
|
arrange(pending, contentBox, rootSettings, composition.mode ? 0 : placeholders.length);
|
|
8594
8678
|
for (const item of items) {
|
|
8595
8679
|
for (const key of ["x", "y", "width", "height"]) item.box[key] = round(item.box[key]);
|
|
8596
|
-
if (item.field === "table" && tableOverflows(item.value, item.box, scale, item.composition, options)) diagnostics.push({ code: "text-overflow", path: item.path, message: "Table cells do not fit; use fewer rows, fewer columns, or split the table across slides." });
|
|
8680
|
+
if (item.field === "table" && tableOverflows(item.value, item.box, scale, item.composition, options, item.path)) diagnostics.push({ code: "text-overflow", path: item.path, message: "Table cells do not fit; use fewer rows, fewer columns, or split the table across slides." });
|
|
8597
8681
|
if (item.text?.overflow) diagnostics.push({ code: "text-overflow", path: item.path, message: "Text exceeds its cell at the minimum font size; shorten it, increase its space, or split the slide." });
|
|
8598
8682
|
}
|
|
8599
8683
|
for (const group of groups) for (const box of [group.box, group.contentBox]) for (const key of ["x", "y", "width", "height"]) box[key] = round(box[key]);
|
|
@@ -8612,7 +8696,7 @@ function resolveCanvasDimensions(input) {
|
|
|
8612
8696
|
letter: [11, 8.5],
|
|
8613
8697
|
a4: [11.69, 8.27]
|
|
8614
8698
|
};
|
|
8615
|
-
const value =
|
|
8699
|
+
const value = record2(input);
|
|
8616
8700
|
const preset = presets[typeof input === "string" ? input : value.preset] ?? presets.widescreen;
|
|
8617
8701
|
const width = (value.widthInches ?? preset[0]) * 96;
|
|
8618
8702
|
const height = (value.heightInches ?? preset[1]) * 96;
|
|
@@ -8620,7 +8704,7 @@ function resolveCanvasDimensions(input) {
|
|
|
8620
8704
|
return { width, height };
|
|
8621
8705
|
}
|
|
8622
8706
|
|
|
8623
|
-
// ../javascript/dist/chunk-
|
|
8707
|
+
// ../javascript/dist/chunk-GQSK3T7X.js
|
|
8624
8708
|
var presentation = {
|
|
8625
8709
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
8626
8710
|
"$id": "https://openpresentation.org/schema/opf/v1",
|
|
@@ -12310,10 +12394,16 @@ Resolution order: inline catalogs.fontSchemes.records[] -> catalogs.fontSchemes.
|
|
|
12310
12394
|
"items": {
|
|
12311
12395
|
"$ref": "#/$defs/TextRun"
|
|
12312
12396
|
}
|
|
12397
|
+
},
|
|
12398
|
+
{
|
|
12399
|
+
"$ref": "#/$defs/StyledTableCell"
|
|
12400
|
+
},
|
|
12401
|
+
{
|
|
12402
|
+
"type": "null"
|
|
12313
12403
|
}
|
|
12314
12404
|
]
|
|
12315
12405
|
},
|
|
12316
|
-
"description": "Optional column labels
|
|
12406
|
+
"description": "Optional column labels. Labels may be strings, rich runs or styled cell objects. Null is an empty label or a placeholder covered by a preceding column span.",
|
|
12317
12407
|
"examples": [
|
|
12318
12408
|
[
|
|
12319
12409
|
"Region",
|
|
@@ -12484,6 +12574,17 @@ Resolution order: inline catalogs.fontSchemes.records[] -> catalogs.fontSchemes.
|
|
|
12484
12574
|
"description": "A cell in inline chart data."
|
|
12485
12575
|
},
|
|
12486
12576
|
"TableCell": {
|
|
12577
|
+
"oneOf": [
|
|
12578
|
+
{
|
|
12579
|
+
"$ref": "#/$defs/TableCellValue"
|
|
12580
|
+
},
|
|
12581
|
+
{
|
|
12582
|
+
"$ref": "#/$defs/StyledTableCell"
|
|
12583
|
+
}
|
|
12584
|
+
],
|
|
12585
|
+
"description": "A scalar, rich-run array, or styled/spanning cell object. Existing scalar and rich forms remain valid."
|
|
12586
|
+
},
|
|
12587
|
+
"TableCellValue": {
|
|
12487
12588
|
"oneOf": [
|
|
12488
12589
|
{
|
|
12489
12590
|
"type": "string"
|
|
@@ -12504,7 +12605,149 @@ Resolution order: inline catalogs.fontSchemes.records[] -> catalogs.fontSchemes.
|
|
|
12504
12605
|
}
|
|
12505
12606
|
}
|
|
12506
12607
|
],
|
|
12507
|
-
"description": "A
|
|
12608
|
+
"description": "A scalar table value or canonical rich text runs, without cell decoration or geometry."
|
|
12609
|
+
},
|
|
12610
|
+
"StyledTableCell": {
|
|
12611
|
+
"type": "object",
|
|
12612
|
+
"additionalProperties": false,
|
|
12613
|
+
"required": [
|
|
12614
|
+
"value"
|
|
12615
|
+
],
|
|
12616
|
+
"properties": {
|
|
12617
|
+
"value": {
|
|
12618
|
+
"$ref": "#/$defs/TableCellValue",
|
|
12619
|
+
"description": "Editable cell content; styling and spans do not change its scalar type or rich runs."
|
|
12620
|
+
},
|
|
12621
|
+
"style": {
|
|
12622
|
+
"$ref": "#/$defs/TableCellStyle"
|
|
12623
|
+
},
|
|
12624
|
+
"colSpan": {
|
|
12625
|
+
"type": "integer",
|
|
12626
|
+
"minimum": 1,
|
|
12627
|
+
"description": "Number of grid columns covered, starting at this cell. Covered positions must contain null. Default 1."
|
|
12628
|
+
},
|
|
12629
|
+
"rowSpan": {
|
|
12630
|
+
"type": "integer",
|
|
12631
|
+
"minimum": 1,
|
|
12632
|
+
"description": "Number of grid rows covered, starting at this cell. Covered positions must contain null. Header cells cannot span into body rows. Default 1."
|
|
12633
|
+
}
|
|
12634
|
+
},
|
|
12635
|
+
"description": "A cell with explicit visual style or merged geometry. Its position remains its array column index; use null placeholders for every covered grid position."
|
|
12636
|
+
},
|
|
12637
|
+
"TableCellStyle": {
|
|
12638
|
+
"type": "object",
|
|
12639
|
+
"additionalProperties": false,
|
|
12640
|
+
"properties": {
|
|
12641
|
+
"fill": {
|
|
12642
|
+
"type": "string",
|
|
12643
|
+
"pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$",
|
|
12644
|
+
"description": "Explicit RGB or RGBA color. Eight-digit colors include alpha; #00000000 is transparent."
|
|
12645
|
+
},
|
|
12646
|
+
"color": {
|
|
12647
|
+
"type": "string",
|
|
12648
|
+
"pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$",
|
|
12649
|
+
"description": "Default text color, overridden by individual rich run colors."
|
|
12650
|
+
},
|
|
12651
|
+
"align": {
|
|
12652
|
+
"type": "string",
|
|
12653
|
+
"enum": [
|
|
12654
|
+
"left",
|
|
12655
|
+
"center",
|
|
12656
|
+
"right"
|
|
12657
|
+
],
|
|
12658
|
+
"description": "Horizontal text alignment inside the cell."
|
|
12659
|
+
},
|
|
12660
|
+
"verticalAlign": {
|
|
12661
|
+
"type": "string",
|
|
12662
|
+
"enum": [
|
|
12663
|
+
"top",
|
|
12664
|
+
"middle",
|
|
12665
|
+
"bottom"
|
|
12666
|
+
],
|
|
12667
|
+
"description": "Vertical alignment inside the padded cell box."
|
|
12668
|
+
},
|
|
12669
|
+
"padding": {
|
|
12670
|
+
"$ref": "#/$defs/TableCellPadding"
|
|
12671
|
+
},
|
|
12672
|
+
"borders": {
|
|
12673
|
+
"type": "object",
|
|
12674
|
+
"additionalProperties": false,
|
|
12675
|
+
"properties": {
|
|
12676
|
+
"top": {
|
|
12677
|
+
"$ref": "#/$defs/TableCellBorder"
|
|
12678
|
+
},
|
|
12679
|
+
"right": {
|
|
12680
|
+
"$ref": "#/$defs/TableCellBorder"
|
|
12681
|
+
},
|
|
12682
|
+
"bottom": {
|
|
12683
|
+
"$ref": "#/$defs/TableCellBorder"
|
|
12684
|
+
},
|
|
12685
|
+
"left": {
|
|
12686
|
+
"$ref": "#/$defs/TableCellBorder"
|
|
12687
|
+
}
|
|
12688
|
+
},
|
|
12689
|
+
"description": "Independent cell edges. Omitted edges retain the table theme border; width 0 removes an edge."
|
|
12690
|
+
}
|
|
12691
|
+
},
|
|
12692
|
+
"description": "Cell appearance. Sizes use reference pixels at a 720-pixel canvas short edge and scale with the slide."
|
|
12693
|
+
},
|
|
12694
|
+
"TableCellPadding": {
|
|
12695
|
+
"type": "object",
|
|
12696
|
+
"additionalProperties": false,
|
|
12697
|
+
"properties": {
|
|
12698
|
+
"top": {
|
|
12699
|
+
"type": "number",
|
|
12700
|
+
"minimum": 0,
|
|
12701
|
+
"maximum": 200
|
|
12702
|
+
},
|
|
12703
|
+
"right": {
|
|
12704
|
+
"type": "number",
|
|
12705
|
+
"minimum": 0,
|
|
12706
|
+
"maximum": 200
|
|
12707
|
+
},
|
|
12708
|
+
"bottom": {
|
|
12709
|
+
"type": "number",
|
|
12710
|
+
"minimum": 0,
|
|
12711
|
+
"maximum": 200
|
|
12712
|
+
},
|
|
12713
|
+
"left": {
|
|
12714
|
+
"type": "number",
|
|
12715
|
+
"minimum": 0,
|
|
12716
|
+
"maximum": 200
|
|
12717
|
+
}
|
|
12718
|
+
},
|
|
12719
|
+
"description": "Text insets in reference pixels. Defaults: top 8, right 10, bottom 4, left 10."
|
|
12720
|
+
},
|
|
12721
|
+
"TableCellBorder": {
|
|
12722
|
+
"type": "object",
|
|
12723
|
+
"additionalProperties": false,
|
|
12724
|
+
"required": [
|
|
12725
|
+
"color",
|
|
12726
|
+
"width"
|
|
12727
|
+
],
|
|
12728
|
+
"properties": {
|
|
12729
|
+
"color": {
|
|
12730
|
+
"type": "string",
|
|
12731
|
+
"pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$",
|
|
12732
|
+
"description": "Explicit RGB or RGBA color. Eight-digit colors include alpha; #00000000 is transparent."
|
|
12733
|
+
},
|
|
12734
|
+
"width": {
|
|
12735
|
+
"type": "number",
|
|
12736
|
+
"minimum": 0,
|
|
12737
|
+
"maximum": 32,
|
|
12738
|
+
"description": "Border width in reference pixels; 0 removes this edge."
|
|
12739
|
+
},
|
|
12740
|
+
"dash": {
|
|
12741
|
+
"type": "string",
|
|
12742
|
+
"enum": [
|
|
12743
|
+
"solid",
|
|
12744
|
+
"dash",
|
|
12745
|
+
"dot"
|
|
12746
|
+
],
|
|
12747
|
+
"description": "Default solid."
|
|
12748
|
+
}
|
|
12749
|
+
},
|
|
12750
|
+
"description": "One explicit cell border."
|
|
12508
12751
|
},
|
|
12509
12752
|
"Catalogs": {
|
|
12510
12753
|
"type": "object",
|
|
@@ -33698,7 +33941,7 @@ var catalogEntries = [
|
|
|
33698
33941
|
], records: fontSchemes, index: catalogIndexes.fontSchemes }
|
|
33699
33942
|
];
|
|
33700
33943
|
|
|
33701
|
-
// ../javascript/dist/chunk-
|
|
33944
|
+
// ../javascript/dist/chunk-H7UXKXEJ.js
|
|
33702
33945
|
var import__ = __toESM(require__(), 1);
|
|
33703
33946
|
var import_ajv_formats = __toESM(require_dist(), 1);
|
|
33704
33947
|
var catalogIds = {
|
|
@@ -34496,6 +34739,14 @@ function validatePresentationSemantics(value) {
|
|
|
34496
34739
|
slideIds.add(slide.id);
|
|
34497
34740
|
}
|
|
34498
34741
|
issues.push(...validateSlideRegions(slide, `/slides/${index2}`));
|
|
34742
|
+
const visitTables = (node, path2) => {
|
|
34743
|
+
if (isRecord(node.table)) for (const issue of tableGrid(node.table).issues) issues.push(semanticIssue(pathFor(path2, "table") + issue.path.slice(5).replaceAll(".", "/"), issue.message));
|
|
34744
|
+
if (Array.isArray(node.blocks)) node.blocks.forEach((block, i) => {
|
|
34745
|
+
if (isRecord(block)) visitTables(block, `${path2}/blocks/${i}`);
|
|
34746
|
+
});
|
|
34747
|
+
for (const key of promotedRegionKeys) if (isRecord(node[key])) visitTables(node[key], pathFor(path2, key));
|
|
34748
|
+
};
|
|
34749
|
+
visitTables(slide, `/slides/${index2}`);
|
|
34499
34750
|
}
|
|
34500
34751
|
});
|
|
34501
34752
|
return issues;
|
|
@@ -34516,7 +34767,7 @@ function unknownIdWarning(kind2, value, path2, context) {
|
|
|
34516
34767
|
if (context) {
|
|
34517
34768
|
const entry = inlineCatalogEntry(context, kind2);
|
|
34518
34769
|
if (entry) {
|
|
34519
|
-
if (Array.isArray(entry.records) && entry.records.some((
|
|
34770
|
+
if (Array.isArray(entry.records) && entry.records.some((record3) => isRecord(record3) && record3.id === value)) {
|
|
34520
34771
|
return void 0;
|
|
34521
34772
|
}
|
|
34522
34773
|
if (typeof entry.source === "string") {
|
|
@@ -34692,7 +34943,7 @@ function assertValidPresentation(value) {
|
|
|
34692
34943
|
assertValid(value, "presentation");
|
|
34693
34944
|
}
|
|
34694
34945
|
|
|
34695
|
-
// ../javascript/dist/chunk-
|
|
34946
|
+
// ../javascript/dist/chunk-IQ727X3E.js
|
|
34696
34947
|
var OPFPaginationError = class extends Error {
|
|
34697
34948
|
constructor(message, diagnostics = []) {
|
|
34698
34949
|
super(message);
|
|
@@ -34742,7 +34993,7 @@ function leafFor(path2, field, value) {
|
|
|
34742
34993
|
const values = Array.isArray(value) ? value : value[key];
|
|
34743
34994
|
if (Array.isArray(values)) {
|
|
34744
34995
|
leaf.unit = "items";
|
|
34745
|
-
leaf.boundaries = Array.from({ length: values.length + 1 }, (_, i) => i);
|
|
34996
|
+
leaf.boundaries = field === "table" ? tableRowBoundaries(value) : Array.from({ length: values.length + 1 }, (_, i) => i);
|
|
34746
34997
|
leaf.slice = (a, b) => Array.isArray(value) ? value.slice(a, b) : { ...value, [key]: values.slice(a, b) };
|
|
34747
34998
|
}
|
|
34748
34999
|
}
|
|
@@ -34890,7 +35141,7 @@ function paginatePresentation(input, options = {}) {
|
|
|
34890
35141
|
if (!Number.isInteger(maxSlides) || maxSlides < 1 || maxSlides > 1e4) throw new RangeError("maxSlides must be an integer between 1 and 10000.");
|
|
34891
35142
|
const output = [], pages = [];
|
|
34892
35143
|
const reservedIds = presentation2.slides.map((slide) => slide.id).filter(Boolean);
|
|
34893
|
-
const resolve = (kind2, id) => presentation2.catalogs?.[kind2]?.records?.find((
|
|
35144
|
+
const resolve = (kind2, id) => presentation2.catalogs?.[kind2]?.records?.find((record3) => record3.id === id) ?? catalogs[kind2].find((record3) => record3.id === id);
|
|
34894
35145
|
presentation2.slides.forEach((slide, index2) => {
|
|
34895
35146
|
const overrides = options.slideOptions?.(slide, index2) ?? {};
|
|
34896
35147
|
const layout2 = overrides.layout ?? (slide.layout ? resolve("layouts", slide.layout) : void 0);
|
|
@@ -35132,7 +35383,7 @@ async function main(argv) {
|
|
|
35132
35383
|
return;
|
|
35133
35384
|
}
|
|
35134
35385
|
if (argv.length === 1 && argv[0] === "--version") {
|
|
35135
|
-
print({ cli: "0.
|
|
35386
|
+
print({ cli: "0.4.0", opf: "0.7.0" });
|
|
35136
35387
|
return;
|
|
35137
35388
|
}
|
|
35138
35389
|
const [command, ...args] = argv;
|
|
@@ -35244,7 +35495,7 @@ async function main(argv) {
|
|
|
35244
35495
|
arity(args, 1, 2);
|
|
35245
35496
|
const entry = catalogEntries.find((entry2) => entry2.kind === args[0]);
|
|
35246
35497
|
if (!entry) throw new CliError("Unknown catalog. Run opf catalogs.");
|
|
35247
|
-
const result = args[1] === void 0 ? entry.records : entry.records.find((
|
|
35498
|
+
const result = args[1] === void 0 ? entry.records : entry.records.find((record3) => record3.id === args[1]);
|
|
35248
35499
|
if (!result) throw new CliError(`Unknown ${args[0]} id: ${args[1]}`);
|
|
35249
35500
|
print(result);
|
|
35250
35501
|
return;
|