@json-to-office/jto-ops 6.0.0 → 6.2.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/dist/index.d.ts CHANGED
@@ -469,7 +469,7 @@ declare function extractPdfFonts(pdfPath: string, options?: {
469
469
  * pass over it, memoised per fact, so eight rules cost one search.
470
470
  */
471
471
 
472
- type RenderedRuleId = 'rendered/clip' | 'rendered/spill' | 'rendered/overlap' | 'rendered/text-missing' | 'rendered/font-substituted' | 'rendered/empty-page' | 'rendered/heading-stranded' | 'rendered/paragraph-split' | 'rendered/page-underfilled';
472
+ type RenderedRuleId = 'rendered/clip' | 'rendered/spill' | 'rendered/overlap' | 'rendered/text-missing' | 'rendered/font-substituted' | 'rendered/empty-page' | 'rendered/heading-stranded' | 'rendered/paragraph-split' | 'rendered/table-split' | 'rendered/page-underfilled';
473
473
  declare const RENDERED_QUALITY_RULES: QualityRulePack;
474
474
 
475
475
  /**
package/dist/index.js CHANGED
@@ -2149,6 +2149,14 @@ var RENDERED_QUALITY_RULES = {
2149
2149
  defaultSeverity: "warning",
2150
2150
  formats: ["docx"]
2151
2151
  }),
2152
+ renderedRule({
2153
+ id: "rendered/table-split",
2154
+ code: QUALITY_CODES.RENDERED_TABLE_SPLIT,
2155
+ description: "A table broken across a page badly: its header left alone at the foot of a page (`kind: header-alone`), or one row alone on either side of the break (`kind: orphan-row` or `widow-row`).",
2156
+ category: "composition",
2157
+ defaultSeverity: "info",
2158
+ formats: ["docx"]
2159
+ }),
2152
2160
  renderedRule({
2153
2161
  id: "rendered/paragraph-split",
2154
2162
  code: QUALITY_CODES.RENDERED_PARAGRAPH_SPLIT,
@@ -2975,6 +2983,79 @@ function draftRenderedFindings(input) {
2975
2983
  })
2976
2984
  );
2977
2985
  }
2986
+ const TABLE_CELL = /^(.*)\/props\/(?:slots\/)?columns\/(\d+)\/(?:header|cells\/(\d+))(?:\/.*)?$/;
2987
+ const tables = /* @__PURE__ */ new Map();
2988
+ for (const match of matches) {
2989
+ if (match.entry.role !== "table-header" && match.entry.role !== "table-cell" || match.status !== "mapped")
2990
+ continue;
2991
+ const parsed = TABLE_CELL.exec(match.entry.path);
2992
+ if (!parsed) continue;
2993
+ const [, table, column, row] = parsed;
2994
+ const rowIndex = row === void 0 ? -1 : Number(row);
2995
+ const entry = tables.get(table) ?? {
2996
+ pages: /* @__PURE__ */ new Map(),
2997
+ paths: /* @__PURE__ */ new Map()
2998
+ };
2999
+ for (const occurrence2 of match.occurrences)
3000
+ for (const part of occurrence2.parts) {
3001
+ const rows = entry.pages.get(part.pageIndex) ?? /* @__PURE__ */ new Set();
3002
+ rows.add(rowIndex);
3003
+ entry.pages.set(part.pageIndex, rows);
3004
+ }
3005
+ const held = entry.paths.get(rowIndex);
3006
+ if (!held || Number(column) < held.column)
3007
+ entry.paths.set(rowIndex, {
3008
+ column: Number(column),
3009
+ path: match.entry.path
3010
+ });
3011
+ tables.set(table, entry);
3012
+ }
3013
+ for (const [table, { pages: onPage, paths }] of tables) {
3014
+ const ordered = [...onPage.keys()].sort((a, b) => a - b);
3015
+ if (ordered.length < 2) continue;
3016
+ const bodyRows = (page) => [...onPage.get(page) ?? []].filter((row) => row >= 0);
3017
+ const report = (kind, page, path9, message, suggestion) => findings.push(
3018
+ finding({
3019
+ ruleId: "rendered/table-split",
3020
+ mapping: "mapped",
3021
+ page: page + 1,
3022
+ path: path9,
3023
+ message,
3024
+ suggestion,
3025
+ context: { kind, table }
3026
+ })
3027
+ );
3028
+ const firstPage = ordered[0];
3029
+ const lastPage = ordered[ordered.length - 1];
3030
+ if (onPage.get(firstPage).has(-1) && bodyRows(firstPage).length === 0) {
3031
+ report(
3032
+ "header-alone",
3033
+ firstPage,
3034
+ paths.get(-1).path,
3035
+ `The table's header is the only part of it on page ${firstPage + 1}; its rows start on the next page.`,
3036
+ "Keep the header with its first rows, or move the table so it starts on the next page."
3037
+ );
3038
+ continue;
3039
+ }
3040
+ const opening = bodyRows(firstPage);
3041
+ const closing = bodyRows(lastPage);
3042
+ if (opening.length === 1)
3043
+ report(
3044
+ "orphan-row",
3045
+ firstPage,
3046
+ paths.get(opening[0]).path,
3047
+ `The table leaves one row alone at the foot of page ${firstPage + 1}.`,
3048
+ "Keep the table together on one page, or edit the rows above it so the break falls elsewhere."
3049
+ );
3050
+ else if (closing.length === 1)
3051
+ report(
3052
+ "widow-row",
3053
+ lastPage,
3054
+ paths.get(closing[0]).path,
3055
+ `The table leaves one row alone at the top of page ${lastPage + 1}.`,
3056
+ "Keep the table together on one page, or edit the rows above it so the break falls elsewhere."
3057
+ );
3058
+ }
2978
3059
  }
2979
3060
  const inventory = {
2980
3061
  mapped: 0,