@openpresentation/cli 0.2.0 → 0.3.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 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`. This checkout prepares CLI 0.2.0 with bundled OPF 0.5.0; that version supports rich table cells and headers during validation and pagination. Until 0.2.0 is published, the registry's latest release has the previous schema.
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,7 +8163,7 @@ 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-WG5A4KZG.js
8166
+ // ../javascript/dist/chunk-C7GKRLI6.js
8167
8167
  var MAX_COMPOSITION_DEPTH = 32;
8168
8168
  function resolveFontFamilies(input) {
8169
8169
  const scheme = record(input);
@@ -8325,6 +8325,16 @@ function richTextLayouter(input, box, requestedSize, options) {
8325
8325
  y += height;
8326
8326
  return line;
8327
8327
  });
8328
+ if (options.uniformLineHeight) {
8329
+ const height = Math.max(...richLines.map((line) => line.height));
8330
+ y = 0;
8331
+ for (const line of richLines) {
8332
+ line.baseline += y - line.y;
8333
+ line.y = y;
8334
+ line.height = height;
8335
+ y += height;
8336
+ }
8337
+ }
8328
8338
  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
8339
  };
8330
8340
  return layout2;
@@ -8399,17 +8409,48 @@ ${flatten(entry.description)}` : ""}`;
8399
8409
  if (field === "quote") return flatten(record(value).text ?? value);
8400
8410
  return void 0;
8401
8411
  }
8402
- function tableOverflows(value, box, scale, settings, options) {
8403
- const table = record(value), rows2 = Array.isArray(table.rows) ? table.rows : [];
8404
- const allRows = Array.isArray(table.columns) && table.columns.length ? [table.columns, ...rows2] : rows2;
8405
- const columns2 = Math.max(1, ...allRows.map((row) => row.length));
8406
- const width = box.width / columns2 - 20 * scale;
8407
- const height = Math.min(54 * scale, box.height / Math.max(1, allRows.length)) - 12 * scale;
8408
- return width <= 0 || height <= 0 || allRows.some((row, index2) => row.some((value2) => {
8409
- const style = { fontFamily: options.fonts?.body ?? "sans-serif", fontWeight: index2 === 0 && table.columns?.length ? 700 : 400 };
8410
- const cell2 = { width, height }, minimum = (settings.minFontSize ?? 16) * scale;
8411
- return (Array.isArray(value2) ? fitRichText(value2, cell2, 15 * scale, minimum, { style, textMeasurement: options.textMeasurement }) : fitText(flatten(value2), cell2, 15 * scale, minimum, textWidthMeasurer(resolveTextStyle(style, options.textMeasurement), options.textMeasurement))).overflow;
8412
- }));
8412
+ function layoutTable(value, box, options = {}) {
8413
+ const scale = options.scale ?? 1, requested = 15 * scale, minimum = (options.minFontSize ?? 16) * scale;
8414
+ 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.");
8415
+ const table = record(value), headers = Array.isArray(table.columns) && table.columns.length > 0;
8416
+ const values = [...headers ? [table.columns] : [], ...Array.isArray(table.rows) ? table.rows : []];
8417
+ const columnCount = Math.max(1, ...values.map((row) => row.length)), cellWidth = box.width / columnCount;
8418
+ const width = Math.max(scale, cellWidth - 20 * scale), padding = 12 * scale;
8419
+ const fitCell = (cell2, height, min) => {
8420
+ const textBox = { width, height: Math.max(scale, height) };
8421
+ return Array.isArray(cell2.value) ? fitRichText(cell2.value, textBox, requested, min, { style: cell2.style, textMeasurement: options.textMeasurement, uniformLineHeight: true }) : fitText(flatten(cell2.value), textBox, requested, min, textWidthMeasurer(resolveTextStyle(cell2.style, options.textMeasurement), options.textMeasurement));
8422
+ };
8423
+ const textHeight = (fit) => "height" in fit ? fit.height : fit.lines.length * fit.lineHeight;
8424
+ const measured = values.map((row, index2) => {
8425
+ const header = headers && index2 === 0;
8426
+ const cells = Array.from({ length: columnCount }, (_, column) => {
8427
+ const path2 = `${options.path ?? "table"}.${header ? "columns" : `rows.${index2 - Number(headers)}`}.${column}`;
8428
+ return { value: row[column], path: path2, header, style: { fontFamily: options.fontFamily ?? "sans-serif", fontWeight: header ? 700 : 400, italic: false, path: path2 } };
8429
+ });
8430
+ const natural2 = Math.max(...cells.map((cell2) => textHeight(fitCell(cell2, scale, requested)) + padding));
8431
+ const preferred2 = Math.max(54 * scale, natural2);
8432
+ const needed2 = Math.min(preferred2, Math.max(...cells.map((cell2) => textHeight(fitCell(cell2, scale, minimum)) + padding)));
8433
+ return { cells, preferred: preferred2, natural: natural2, needed: needed2 };
8434
+ });
8435
+ const preferred = measured.reduce((sum, row) => sum + row.preferred, 0), natural = measured.reduce((sum, row) => sum + row.natural, 0), needed = measured.reduce((sum, row) => sum + row.needed, 0);
8436
+ let y = box.y, overflow = cellWidth <= 20 * scale;
8437
+ const rows2 = measured.map((row) => {
8438
+ const height = preferred <= box.height ? row.preferred : natural <= box.height ? row.natural + (row.preferred - row.natural) * (box.height - natural) / Math.max(Number.EPSILON, preferred - natural) : needed <= box.height ? row.needed + (row.natural - row.needed) * (box.height - needed) / Math.max(Number.EPSILON, natural - needed) : row.needed * box.height / needed;
8439
+ const rowBox = { x: box.x, y, width: box.width, height };
8440
+ const cells = row.cells.map((cell2, column) => {
8441
+ const cellBox = { x: box.x + column * cellWidth, y, width: cellWidth, height };
8442
+ const textBox = { x: cellBox.x + 10 * scale, y: y + 8 * scale, width, height: Math.max(scale, height - padding) };
8443
+ const fit = fitCell(cell2, textBox.height, minimum);
8444
+ overflow ||= height <= padding || fit.overflow;
8445
+ return { value: cell2.value, path: cell2.path, header: cell2.header, rich: Array.isArray(cell2.value), box: cellBox, textBox, textStyle: resolveTextStyle(cell2.style, options.textMeasurement), fit };
8446
+ });
8447
+ y += height;
8448
+ return { box: rowBox, cells };
8449
+ });
8450
+ return { rows: rows2, columnCount, height: y - box.y, overflow };
8451
+ }
8452
+ function tableOverflows(value, box, scale, settings, options, path2) {
8453
+ 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
8454
  }
8414
8455
  function flatten(value) {
8415
8456
  if (value == null) return "";
@@ -8538,7 +8579,7 @@ function composeSlide(input, options = {}) {
8538
8579
  const fit = fitContent(node.field, node.value, text, box, 25 * scale, (settings.minFontSize ?? 16) * scale, node.path);
8539
8580
  score += (25 * scale - fit.fontSize) / scale + (fit.overflow ? 1e3 : 0);
8540
8581
  }
8541
- if (node.field === "table" && tableOverflows(node.value, box, scale, settings, options)) score += 1e3;
8582
+ if (node.field === "table" && tableOverflows(node.value, box, scale, settings, options, node.path)) score += 1e3;
8542
8583
  if (box.width < 100 * scale || box.height < 60 * scale) score += 100;
8543
8584
  return score;
8544
8585
  };
@@ -8593,7 +8634,7 @@ function composeSlide(input, options = {}) {
8593
8634
  arrange(pending, contentBox, rootSettings, composition.mode ? 0 : placeholders.length);
8594
8635
  for (const item of items) {
8595
8636
  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." });
8637
+ 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
8638
  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
8639
  }
8599
8640
  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]);
@@ -33698,7 +33739,7 @@ var catalogEntries = [
33698
33739
  ], records: fontSchemes, index: catalogIndexes.fontSchemes }
33699
33740
  ];
33700
33741
 
33701
- // ../javascript/dist/chunk-PFJE2IW4.js
33742
+ // ../javascript/dist/chunk-23MXJL2K.js
33702
33743
  var import__ = __toESM(require__(), 1);
33703
33744
  var import_ajv_formats = __toESM(require_dist(), 1);
33704
33745
  var catalogIds = {
@@ -34692,7 +34733,7 @@ function assertValidPresentation(value) {
34692
34733
  assertValid(value, "presentation");
34693
34734
  }
34694
34735
 
34695
- // ../javascript/dist/chunk-YLORKB63.js
34736
+ // ../javascript/dist/chunk-C6U7LLBT.js
34696
34737
  var OPFPaginationError = class extends Error {
34697
34738
  constructor(message, diagnostics = []) {
34698
34739
  super(message);
@@ -35132,7 +35173,7 @@ async function main(argv) {
35132
35173
  return;
35133
35174
  }
35134
35175
  if (argv.length === 1 && argv[0] === "--version") {
35135
- print({ cli: "0.2.0", opf: "0.5.0" });
35176
+ print({ cli: "0.3.0", opf: "0.6.0" });
35136
35177
  return;
35137
35178
  }
35138
35179
  const [command, ...args] = argv;