@harbortouch/skytab-analytics-report-utils 0.25.0 → 0.27.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.
@@ -765,10 +765,10 @@ var FIELDS13 = {
765
765
  columnKey: "paymentType",
766
766
  footerCalculation: { type: "label", label: "table.total" }
767
767
  },
768
- paymentsCount: { type: "number", columnKey: "paymentsCount", footerCalculation: { type: "sum" } },
769
- paymentsAmount: { type: "money", columnKey: "paymentsAmount", footerCalculation: { type: "sum" } },
770
- tipsAmount: { type: "money", columnKey: "tips", footerCalculation: { type: "sum" } },
771
- totalSales: { type: "money", columnKey: "paymentsTotal", footerCalculation: { type: "sum" } }
768
+ paymentsCount: { type: "number-empty", columnKey: "paymentsCount", footerCalculation: { type: "sum" } },
769
+ paymentsAmount: { type: "money-empty", columnKey: "paymentsAmount", footerCalculation: { type: "sum" } },
770
+ tipsAmount: { type: "money-empty", columnKey: "tips", footerCalculation: { type: "sum" } },
771
+ totalSales: { type: "money-empty", columnKey: "paymentsTotal", footerCalculation: { type: "sum" } }
772
772
  };
773
773
  var DAILY_SALES_PAYMENTS_AVAILABLE_COLUMNS = [
774
774
  "paymentTypeName",
@@ -3365,6 +3365,8 @@ var formatFieldValue = (value, type, localeOptions, fullRecord, fieldConfig = DE
3365
3365
  return formatString(value, localeOptions);
3366
3366
  case "money":
3367
3367
  return formatMoney(getNumberToFormat(value), { currency, locale });
3368
+ case "money-empty":
3369
+ return value != null ? formatMoney(getNumberToFormat(value), { currency, locale }) : "";
3368
3370
  case "percent":
3369
3371
  return formatPercent(getNumberToFormat(value) * 100);
3370
3372
  case "fixedNumber":
@@ -3377,6 +3379,8 @@ var formatFieldValue = (value, type, localeOptions, fullRecord, fieldConfig = DE
3377
3379
  const d = getDateToFormat(value);
3378
3380
  return d ? formatTime(d, { locale, format: "00:00:00" }) : "";
3379
3381
  }
3382
+ case "number-empty":
3383
+ return value != null ? String(getNumberToFormat(value)) : "";
3380
3384
  case "number":
3381
3385
  default:
3382
3386
  return String(getNumberToFormat(value));
@@ -1614,6 +1614,8 @@ var formatFieldValue = (value, type, localeOptions, fullRecord, fieldConfig = DE
1614
1614
  return formatString(value, localeOptions);
1615
1615
  case "money":
1616
1616
  return formatMoney(getNumberToFormat(value), { currency, locale });
1617
+ case "money-empty":
1618
+ return value != null ? formatMoney(getNumberToFormat(value), { currency, locale }) : "";
1617
1619
  case "percent":
1618
1620
  return formatPercent(getNumberToFormat(value) * 100);
1619
1621
  case "fixedNumber":
@@ -1626,6 +1628,8 @@ var formatFieldValue = (value, type, localeOptions, fullRecord, fieldConfig = DE
1626
1628
  const d = getDateToFormat(value);
1627
1629
  return d ? formatTime(d, { locale, format: "00:00:00" }) : "";
1628
1630
  }
1631
+ case "number-empty":
1632
+ return value != null ? String(getNumberToFormat(value)) : "";
1629
1633
  case "number":
1630
1634
  default:
1631
1635
  return String(getNumberToFormat(value));
@@ -2399,10 +2403,10 @@ var FIELDS13 = {
2399
2403
  columnKey: "paymentType",
2400
2404
  footerCalculation: { type: "label", label: "table.total" }
2401
2405
  },
2402
- paymentsCount: { type: "number", columnKey: "paymentsCount", footerCalculation: { type: "sum" } },
2403
- paymentsAmount: { type: "money", columnKey: "paymentsAmount", footerCalculation: { type: "sum" } },
2404
- tipsAmount: { type: "money", columnKey: "tips", footerCalculation: { type: "sum" } },
2405
- totalSales: { type: "money", columnKey: "paymentsTotal", footerCalculation: { type: "sum" } }
2406
+ paymentsCount: { type: "number-empty", columnKey: "paymentsCount", footerCalculation: { type: "sum" } },
2407
+ paymentsAmount: { type: "money-empty", columnKey: "paymentsAmount", footerCalculation: { type: "sum" } },
2408
+ tipsAmount: { type: "money-empty", columnKey: "tips", footerCalculation: { type: "sum" } },
2409
+ totalSales: { type: "money-empty", columnKey: "paymentsTotal", footerCalculation: { type: "sum" } }
2406
2410
  };
2407
2411
  var DAILY_SALES_PAYMENTS_AVAILABLE_COLUMNS = [
2408
2412
  "paymentTypeName",
@@ -3537,10 +3541,13 @@ var ExportBuilder = class {
3537
3541
  }
3538
3542
  let sections;
3539
3543
  if (Array.isArray(rawConfig)) {
3540
- sections = rawConfig.map((config) => ({
3541
- sheetName: this.getConfigSectionName(config),
3542
- ...this.renderTableContent(config, reportData, parameters)
3543
- }));
3544
+ const sectionParameters = { ...parameters, cols: void 0 };
3545
+ sections = rawConfig.map((config) => {
3546
+ return {
3547
+ sheetName: this.getConfigSectionName(config),
3548
+ ...this.renderTableContent(config, reportData, sectionParameters)
3549
+ };
3550
+ });
3544
3551
  } else {
3545
3552
  const metadata = this.buildMetadata(parameters);
3546
3553
  sections = [
@@ -1,4 +1,4 @@
1
- import { R as ReportType, A as AnalyticsField } from '../report-Bx5XpFQ0.cjs';
1
+ import { R as ReportType, A as AnalyticsField } from '../report-D_tOANVX.cjs';
2
2
  import { E as ExportTable, a as ExportFilter } from '../types-BzLsgnfc.cjs';
3
3
 
4
4
  interface ReportDocumentSection {
@@ -1,4 +1,4 @@
1
- import { R as ReportType, A as AnalyticsField } from '../report-Bx5XpFQ0.js';
1
+ import { R as ReportType, A as AnalyticsField } from '../report-D_tOANVX.js';
2
2
  import { E as ExportTable, a as ExportFilter } from '../types-BzLsgnfc.js';
3
3
 
4
4
  interface ReportDocumentSection {
@@ -6,7 +6,7 @@ import {
6
6
  getReportConfig,
7
7
  getReportFormattingLocaleOptions,
8
8
  resolveTranslate
9
- } from "../chunk-SUWIUPHT.js";
9
+ } from "../chunk-OJQZXKA5.js";
10
10
 
11
11
  // src/exporters/exportBuilder.ts
12
12
  import { format, isValid, parseISO } from "date-fns";
@@ -193,10 +193,13 @@ var ExportBuilder = class {
193
193
  }
194
194
  let sections;
195
195
  if (Array.isArray(rawConfig)) {
196
- sections = rawConfig.map((config) => ({
197
- sheetName: this.getConfigSectionName(config),
198
- ...this.renderTableContent(config, reportData, parameters)
199
- }));
196
+ const sectionParameters = { ...parameters, cols: void 0 };
197
+ sections = rawConfig.map((config) => {
198
+ return {
199
+ sheetName: this.getConfigSectionName(config),
200
+ ...this.renderTableContent(config, reportData, sectionParameters)
201
+ };
202
+ });
200
203
  } else {
201
204
  const metadata = this.buildMetadata(parameters);
202
205
  sections = [
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/exporters/json/index.ts
21
+ var json_exports = {};
22
+ __export(json_exports, {
23
+ JsonRenderer: () => JsonRenderer
24
+ });
25
+ module.exports = __toCommonJS(json_exports);
26
+ var JsonRenderer = class {
27
+ render(doc) {
28
+ const slug = doc.title.trim().replace(/[^\w-]/g, "_") || "report";
29
+ return {
30
+ buffer: Buffer.from(JSON.stringify(doc)),
31
+ contentType: "application/json",
32
+ fileName: `${slug}.json`
33
+ };
34
+ }
35
+ };
36
+ // Annotate the CommonJS export names for ESM import in node:
37
+ 0 && (module.exports = {
38
+ JsonRenderer
39
+ });
@@ -0,0 +1,7 @@
1
+ import { a as ReportDocument, R as RenderedReport } from '../../ir-CUi0Z9hv.cjs';
2
+
3
+ declare class JsonRenderer {
4
+ render(doc: ReportDocument): RenderedReport;
5
+ }
6
+
7
+ export { JsonRenderer };
@@ -0,0 +1,7 @@
1
+ import { a as ReportDocument, R as RenderedReport } from '../../ir-CUi0Z9hv.js';
2
+
3
+ declare class JsonRenderer {
4
+ render(doc: ReportDocument): RenderedReport;
5
+ }
6
+
7
+ export { JsonRenderer };
@@ -0,0 +1,14 @@
1
+ // src/exporters/json/index.ts
2
+ var JsonRenderer = class {
3
+ render(doc) {
4
+ const slug = doc.title.trim().replace(/[^\w-]/g, "_") || "report";
5
+ return {
6
+ buffer: Buffer.from(JSON.stringify(doc)),
7
+ contentType: "application/json",
8
+ fileName: `${slug}.json`
9
+ };
10
+ }
11
+ };
12
+ export {
13
+ JsonRenderer
14
+ };
package/dist/index.cjs CHANGED
@@ -837,10 +837,10 @@ var FIELDS13 = {
837
837
  columnKey: "paymentType",
838
838
  footerCalculation: { type: "label", label: "table.total" }
839
839
  },
840
- paymentsCount: { type: "number", columnKey: "paymentsCount", footerCalculation: { type: "sum" } },
841
- paymentsAmount: { type: "money", columnKey: "paymentsAmount", footerCalculation: { type: "sum" } },
842
- tipsAmount: { type: "money", columnKey: "tips", footerCalculation: { type: "sum" } },
843
- totalSales: { type: "money", columnKey: "paymentsTotal", footerCalculation: { type: "sum" } }
840
+ paymentsCount: { type: "number-empty", columnKey: "paymentsCount", footerCalculation: { type: "sum" } },
841
+ paymentsAmount: { type: "money-empty", columnKey: "paymentsAmount", footerCalculation: { type: "sum" } },
842
+ tipsAmount: { type: "money-empty", columnKey: "tips", footerCalculation: { type: "sum" } },
843
+ totalSales: { type: "money-empty", columnKey: "paymentsTotal", footerCalculation: { type: "sum" } }
844
844
  };
845
845
  var DAILY_SALES_PAYMENTS_AVAILABLE_COLUMNS = [
846
846
  "paymentTypeName",
@@ -1783,7 +1783,7 @@ function getColumnAlignment(type) {
1783
1783
  return "right";
1784
1784
  }
1785
1785
  function isNumericType(type) {
1786
- return type === "money" || type === "number" || type === "percent" || type === "fixedNumber";
1786
+ return type === "money" || type === "money-empty" || type === "number" || type === "number-empty" || type === "percent" || type === "fixedNumber";
1787
1787
  }
1788
1788
 
1789
1789
  // src/totals.ts
@@ -1997,7 +1997,27 @@ var buildDailySalesRevClassFooter = (inputs) => {
1997
1997
  ];
1998
1998
  };
1999
1999
  var buildPaymentsSectionData = (payments) => {
2000
- return payments.filter((payment) => payment.paymentTypeName !== TENDER_TYPE.HOUSE_ACCOUNT);
2000
+ const filtered = payments.filter((payment) => payment.paymentTypeName !== TENDER_TYPE.HOUSE_ACCOUNT);
2001
+ const seenParentCategories = /* @__PURE__ */ new Set();
2002
+ const result = [];
2003
+ for (const payment of filtered) {
2004
+ if (payment.parentCategory !== null && !seenParentCategories.has(payment.parentCategory)) {
2005
+ seenParentCategories.add(payment.parentCategory);
2006
+ const headerRow = {
2007
+ ...payment,
2008
+ paymentTypeName: payment.parentCategory,
2009
+ parentCategory: "",
2010
+ paymentsCount: null,
2011
+ paymentsAmount: null,
2012
+ tipsAmount: null,
2013
+ totalSales: null
2014
+ };
2015
+ result.push(headerRow);
2016
+ }
2017
+ const child = payment.parentCategory !== null ? { ...payment, paymentTypeName: ` ${payment.paymentTypeName}` } : payment;
2018
+ result.push(child);
2019
+ }
2020
+ return result;
2001
2021
  };
2002
2022
 
2003
2023
  // src/translations/crowdin/skytab-analytics-report-utils/en-GB.ts
@@ -3605,6 +3625,8 @@ var formatFieldValue = (value, type, localeOptions, fullRecord, fieldConfig = DE
3605
3625
  return formatString(value, localeOptions);
3606
3626
  case "money":
3607
3627
  return formatMoney(getNumberToFormat(value), { currency, locale });
3628
+ case "money-empty":
3629
+ return value != null ? formatMoney(getNumberToFormat(value), { currency, locale }) : "";
3608
3630
  case "percent":
3609
3631
  return formatPercent(getNumberToFormat(value) * 100);
3610
3632
  case "fixedNumber":
@@ -3617,6 +3639,8 @@ var formatFieldValue = (value, type, localeOptions, fullRecord, fieldConfig = DE
3617
3639
  const d = getDateToFormat(value);
3618
3640
  return d ? formatTime(d, { locale, format: "00:00:00" }) : "";
3619
3641
  }
3642
+ case "number-empty":
3643
+ return value != null ? String(getNumberToFormat(value)) : "";
3620
3644
  case "number":
3621
3645
  default:
3622
3646
  return String(getNumberToFormat(value));
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
- import { M as MessageKey, F as FieldType, C as ColumnAlignment, a as ColumnPresentationConfig, b as ColumnGroupConfig, R as ReportType, c as ReportConfig, d as ReportColumnKey } from './report-Bx5XpFQ0.cjs';
2
- export { e as COLUMN_REGISTRY, f as ColumnMessageKey, g as ColumnMetadata, h as FooterCalculation, i as FooterCalculationType, j as Report, k as getColumnExportHeaderLabel, l as getColumnMetadata, m as getReportConfig, n as getReportExportFileName } from './report-Bx5XpFQ0.cjs';
1
+ import { M as MessageKey, F as FieldType, C as ColumnAlignment, a as ColumnPresentationConfig, b as ColumnGroupConfig, R as ReportType, c as ReportConfig, d as ReportColumnKey } from './report-D_tOANVX.cjs';
2
+ export { e as COLUMN_REGISTRY, f as ColumnMessageKey, g as ColumnMetadata, h as FooterCalculation, i as FooterCalculationType, j as Report, k as getColumnExportHeaderLabel, l as getColumnMetadata, m as getReportConfig, n as getReportExportFileName } from './report-D_tOANVX.cjs';
3
3
  import { LocaleCode } from '@harbortouch/locale-registry';
4
+ export { R as RenderedReport, a as ReportDocument, b as ReportFormat, c as ReportSection, d as ResolvedColumn, S as SummaryRow } from './ir-CUi0Z9hv.cjs';
4
5
 
5
6
  type SupportedLocale = LocaleCode;
6
7
  declare function resolveTranslate(key: MessageKey, locale: string): string;
@@ -142,6 +143,11 @@ declare const buildDailySalesRevClassFooter: (inputs: {
142
143
  })[];
143
144
  declare const buildPaymentsSectionData: <T extends {
144
145
  paymentTypeName: string;
146
+ paymentsCount: number | null;
147
+ paymentsAmount: number | null;
148
+ tipsAmount: number | null;
149
+ totalSales: number | null;
150
+ parentCategory: null | string;
145
151
  }>(payments: T[]) => T[];
146
152
 
147
153
  type DailySalesRefundsVoidsField = 'description' | 'count' | 'amount' | 'pctSales';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { M as MessageKey, F as FieldType, C as ColumnAlignment, a as ColumnPresentationConfig, b as ColumnGroupConfig, R as ReportType, c as ReportConfig, d as ReportColumnKey } from './report-Bx5XpFQ0.js';
2
- export { e as COLUMN_REGISTRY, f as ColumnMessageKey, g as ColumnMetadata, h as FooterCalculation, i as FooterCalculationType, j as Report, k as getColumnExportHeaderLabel, l as getColumnMetadata, m as getReportConfig, n as getReportExportFileName } from './report-Bx5XpFQ0.js';
1
+ import { M as MessageKey, F as FieldType, C as ColumnAlignment, a as ColumnPresentationConfig, b as ColumnGroupConfig, R as ReportType, c as ReportConfig, d as ReportColumnKey } from './report-D_tOANVX.js';
2
+ export { e as COLUMN_REGISTRY, f as ColumnMessageKey, g as ColumnMetadata, h as FooterCalculation, i as FooterCalculationType, j as Report, k as getColumnExportHeaderLabel, l as getColumnMetadata, m as getReportConfig, n as getReportExportFileName } from './report-D_tOANVX.js';
3
3
  import { LocaleCode } from '@harbortouch/locale-registry';
4
+ export { R as RenderedReport, a as ReportDocument, b as ReportFormat, c as ReportSection, d as ResolvedColumn, S as SummaryRow } from './ir-CUi0Z9hv.js';
4
5
 
5
6
  type SupportedLocale = LocaleCode;
6
7
  declare function resolveTranslate(key: MessageKey, locale: string): string;
@@ -142,6 +143,11 @@ declare const buildDailySalesRevClassFooter: (inputs: {
142
143
  })[];
143
144
  declare const buildPaymentsSectionData: <T extends {
144
145
  paymentTypeName: string;
146
+ paymentsCount: number | null;
147
+ paymentsAmount: number | null;
148
+ tipsAmount: number | null;
149
+ totalSales: number | null;
150
+ parentCategory: null | string;
145
151
  }>(payments: T[]) => T[];
146
152
 
147
153
  type DailySalesRefundsVoidsField = 'description' | 'count' | 'amount' | 'pctSales';
package/dist/index.js CHANGED
@@ -37,7 +37,7 @@ import {
37
37
  salesSummaryConfig,
38
38
  ticketLiveConfig,
39
39
  ticketSummaryConfig
40
- } from "./chunk-SUWIUPHT.js";
40
+ } from "./chunk-OJQZXKA5.js";
41
41
 
42
42
  // src/utils/alignment.ts
43
43
  function getColumnAlignment(type) {
@@ -47,7 +47,7 @@ function getColumnAlignment(type) {
47
47
  return "right";
48
48
  }
49
49
  function isNumericType(type) {
50
- return type === "money" || type === "number" || type === "percent" || type === "fixedNumber";
50
+ return type === "money" || type === "money-empty" || type === "number" || type === "number-empty" || type === "percent" || type === "fixedNumber";
51
51
  }
52
52
 
53
53
  // src/reports/reportSection.ts
@@ -204,7 +204,27 @@ var buildDailySalesRevClassFooter = (inputs) => {
204
204
  ];
205
205
  };
206
206
  var buildPaymentsSectionData = (payments) => {
207
- return payments.filter((payment) => payment.paymentTypeName !== TENDER_TYPE.HOUSE_ACCOUNT);
207
+ const filtered = payments.filter((payment) => payment.paymentTypeName !== TENDER_TYPE.HOUSE_ACCOUNT);
208
+ const seenParentCategories = /* @__PURE__ */ new Set();
209
+ const result = [];
210
+ for (const payment of filtered) {
211
+ if (payment.parentCategory !== null && !seenParentCategories.has(payment.parentCategory)) {
212
+ seenParentCategories.add(payment.parentCategory);
213
+ const headerRow = {
214
+ ...payment,
215
+ paymentTypeName: payment.parentCategory,
216
+ parentCategory: "",
217
+ paymentsCount: null,
218
+ paymentsAmount: null,
219
+ tipsAmount: null,
220
+ totalSales: null
221
+ };
222
+ result.push(headerRow);
223
+ }
224
+ const child = payment.parentCategory !== null ? { ...payment, paymentTypeName: ` ${payment.paymentTypeName}` } : payment;
225
+ result.push(child);
226
+ }
227
+ return result;
208
228
  };
209
229
  export {
210
230
  COLUMN_REGISTRY,
@@ -0,0 +1,55 @@
1
+ /** Output format a renderer produces. */
2
+ type ReportFormat = 'csv' | 'xlsx' | 'pdf' | 'html' | 'json';
3
+ /**
4
+ * A fully resolved column — header text already translated, alignment
5
+ * already derived. Renderers consume this directly without touching the
6
+ * column registry or i18n layer.
7
+ */
8
+ interface ResolvedColumn {
9
+ key: string;
10
+ header: string;
11
+ shortHeader: string;
12
+ align: 'left' | 'right' | 'center';
13
+ }
14
+ /**
15
+ * A name + value pair for rows that do not conform to the section's column
16
+ * schema. Used for footer lines such as "Tax Total €7.00" or
17
+ * "Total Accountable €13.09" in the Daily Sales Revenue Class section.
18
+ */
19
+ interface SummaryRow {
20
+ label: string;
21
+ value: string;
22
+ bold?: boolean;
23
+ }
24
+ /**
25
+ * A single section within a report (e.g. "Payments", "Taxes").
26
+ * Each section has its own column schema and optional footer / summary rows.
27
+ */
28
+ interface ReportSection {
29
+ title?: string;
30
+ columns: ResolvedColumn[];
31
+ rows: Record<string, string | null>[];
32
+ footer?: Record<string, string | null>;
33
+ summary?: SummaryRow[];
34
+ }
35
+ /**
36
+ * Format-agnostic intermediate representation of a complete report.
37
+ * Built once by a document builder, then passed to any renderer
38
+ * (CSV, XLSX, PDF, HTML, JSON) without further data access.
39
+ */
40
+ interface ReportDocument {
41
+ title: string;
42
+ locale: string;
43
+ filters: [string, string][];
44
+ sections: ReportSection[];
45
+ }
46
+ /**
47
+ * The output produced by a renderer after consuming a ReportDocument.
48
+ */
49
+ interface RenderedReport {
50
+ buffer: Buffer;
51
+ contentType: string;
52
+ fileName: string;
53
+ }
54
+
55
+ export type { RenderedReport as R, SummaryRow as S, ReportDocument as a, ReportFormat as b, ReportSection as c, ResolvedColumn as d };
@@ -0,0 +1,55 @@
1
+ /** Output format a renderer produces. */
2
+ type ReportFormat = 'csv' | 'xlsx' | 'pdf' | 'html' | 'json';
3
+ /**
4
+ * A fully resolved column — header text already translated, alignment
5
+ * already derived. Renderers consume this directly without touching the
6
+ * column registry or i18n layer.
7
+ */
8
+ interface ResolvedColumn {
9
+ key: string;
10
+ header: string;
11
+ shortHeader: string;
12
+ align: 'left' | 'right' | 'center';
13
+ }
14
+ /**
15
+ * A name + value pair for rows that do not conform to the section's column
16
+ * schema. Used for footer lines such as "Tax Total €7.00" or
17
+ * "Total Accountable €13.09" in the Daily Sales Revenue Class section.
18
+ */
19
+ interface SummaryRow {
20
+ label: string;
21
+ value: string;
22
+ bold?: boolean;
23
+ }
24
+ /**
25
+ * A single section within a report (e.g. "Payments", "Taxes").
26
+ * Each section has its own column schema and optional footer / summary rows.
27
+ */
28
+ interface ReportSection {
29
+ title?: string;
30
+ columns: ResolvedColumn[];
31
+ rows: Record<string, string | null>[];
32
+ footer?: Record<string, string | null>;
33
+ summary?: SummaryRow[];
34
+ }
35
+ /**
36
+ * Format-agnostic intermediate representation of a complete report.
37
+ * Built once by a document builder, then passed to any renderer
38
+ * (CSV, XLSX, PDF, HTML, JSON) without further data access.
39
+ */
40
+ interface ReportDocument {
41
+ title: string;
42
+ locale: string;
43
+ filters: [string, string][];
44
+ sections: ReportSection[];
45
+ }
46
+ /**
47
+ * The output produced by a renderer after consuming a ReportDocument.
48
+ */
49
+ interface RenderedReport {
50
+ buffer: Buffer;
51
+ contentType: string;
52
+ fileName: string;
53
+ }
54
+
55
+ export type { RenderedReport as R, SummaryRow as S, ReportDocument as a, ReportFormat as b, ReportSection as c, ResolvedColumn as d };
@@ -1217,7 +1217,7 @@ declare const enUS: {
1217
1217
  };
1218
1218
  type MessageKey = keyof typeof enUS;
1219
1219
 
1220
- type FieldType = 'string' | 'money' | 'percent' | 'number' | 'fixedNumber' | 'date' | 'time' | 'boolean' | 'conditional';
1220
+ type FieldType = 'string' | 'money' | 'percent' | 'number' | 'fixedNumber' | 'date' | 'time' | 'boolean' | 'number-empty' | 'money-empty' | 'conditional';
1221
1221
  type ColumnAlignment = 'left' | 'right';
1222
1222
  type FooterCalculationType = 'sum' | 'percentChange' | 'variancePercent' | 'average' | 'quotientOfDifferences' | 'count' | 'label' | 'none';
1223
1223
  type FooterCalculation<TField = string> = {
@@ -1217,7 +1217,7 @@ declare const enUS: {
1217
1217
  };
1218
1218
  type MessageKey = keyof typeof enUS;
1219
1219
 
1220
- type FieldType = 'string' | 'money' | 'percent' | 'number' | 'fixedNumber' | 'date' | 'time' | 'boolean' | 'conditional';
1220
+ type FieldType = 'string' | 'money' | 'percent' | 'number' | 'fixedNumber' | 'date' | 'time' | 'boolean' | 'number-empty' | 'money-empty' | 'conditional';
1221
1221
  type ColumnAlignment = 'left' | 'right';
1222
1222
  type FooterCalculationType = 'sum' | 'percentChange' | 'variancePercent' | 'average' | 'quotientOfDifferences' | 'count' | 'label' | 'none';
1223
1223
  type FooterCalculation<TField = string> = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harbortouch/skytab-analytics-report-utils",
3
- "version": "0.25.0",
3
+ "version": "0.27.0",
4
4
  "description": "Centralized report column presentation configuration for SkyTab Analytics",
5
5
  "engines": {
6
6
  "node": ">=22.6.0",
@@ -34,6 +34,11 @@
34
34
  "types": "./dist/exporters/exportBuilder.d.ts",
35
35
  "import": "./dist/exporters/exportBuilder.js",
36
36
  "require": "./dist/exporters/exportBuilder.cjs"
37
+ },
38
+ "./json": {
39
+ "types": "./dist/exporters/json/index.d.ts",
40
+ "import": "./dist/exporters/json/index.js",
41
+ "require": "./dist/exporters/json/index.cjs"
37
42
  }
38
43
  },
39
44
  "files": [