@reportforge/playwright-pdf 0.5.1 → 0.6.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/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
+ ## [0.6.0] — 2026-06-22
7
+
8
+ ### Added
9
+
10
+ - **Configurable report sections** — a new `sections` option adds or removes any section in any built-in template (`minimal` / `detailed` / `executive`) straight from `playwright.config`. Flat keys set a baseline for every chosen template; per-template keys override per template. Covers every block (cover page, charts, trend, requirements traceability, CI/environment, suite breakdown, failures, failure analysis, slow tests, defect log, release gate) plus display modifiers (pass-rate, full environment table, retries, failure and stack-trace depth). Unknown keys are rejected with a clear configuration error. Reports render identically to before when the option is omitted.
11
+
12
+ ### Changed
13
+
14
+ - Shared section styles (cover page, charts, defect log, coverage bars, environment table, failure analysis, suite breakdown) moved to the base stylesheet, so a section toggled into a template that didn't ship it before now renders fully styled.
15
+
16
+ ---
17
+
6
18
  ## [0.5.1] — 2026-06-19
7
19
 
8
20
  ### Security
package/README.md CHANGED
@@ -58,6 +58,7 @@ Three templates, one reporter. Every PDF is fully offline — fonts, charts, and
58
58
  - **Flakiness trend** — top-N flakiest tests table with per-test dot sparkline across stored history runs in the `detailed` template; `flakinessTopN` option (default 5, `0` disables)
59
59
  - **Offline failure analysis** — sorts failures into 7 root-cause buckets and clusters them, right inside the `detailed` PDF (one-liner in `executive`). No network, no AI service — a small embedded classifier that updates itself safely over your existing license refresh; pin it any time. Full details at [reportforge.org/docs/advanced/failure-analysis](https://reportforge.org/docs/advanced/failure-analysis).
60
60
  - `reportforge-export-feedback` — exports locally-collected unrecognized failures (tokenized, local-only) for optional manual sharing.
61
+ - **Configurable sections** — add or remove any report section per template via `sections`.
61
62
  - **Hybrid licensing** — one short key unlocks it; reports keep rendering offline via a cached JWT between refreshes
62
63
 
63
64
  ---
@@ -198,6 +199,7 @@ All options are the second element of the reporter tuple.
198
199
  | `showTrend` | `boolean` | `true` | Show the pass-rate sparkline and delta badge in the `detailed` template. Set to `false` to disable history tracking entirely. |
199
200
  | `flakinessTopN` | `number` | `5` | Maximum flaky tests to show in the flakiness table (`detailed` template). Set to `0` to disable the table entirely. |
200
201
  | `templatePath` | `string \| string[]` | — | Path to a custom Handlebars (`.hbs`) template file. Takes precedence over `template`. Pass an array to generate one PDF per custom template. See the Custom Templates docs. |
202
+ | `sections` | `object` | per-template | Override which report sections appear, on top of the chosen template's defaults. Flat keys are the baseline for every chosen template; per-template keys (`minimal`\|`detailed`\|`executive`) override per template. Block toggles: `coverPage`, `analysisOneliner`, `releaseGate`, `summary`, `charts`, `trend`, `requirementsMatrix`, `ciEnvironment`, `suiteBreakdown`, `failureDeepDive`, `failureAnalysis`, `slowTests`, `defectLog`. Display modifiers: `passRate`, `fullEnvironment`, `retries`, `fullFailures`, `stackTraces`. See the Report Sections docs. |
201
203
  <!-- AUTOGEN:options-table END -->
202
204
 
203
205
  Full reference: [reportforge.org/docs#configuration](https://reportforge.org/docs#configuration).
@@ -360,6 +362,38 @@ reporter: [
360
362
 
361
363
  One license check, one data-collection pass — faster than multiple reporter instances. Duplicate entries are silently deduplicated.
362
364
 
365
+ ### Report Sections
366
+
367
+ Each template ships a curated set of sections. Override them per run with the
368
+ `sections` option — add a section a template hides, or remove one it shows.
369
+
370
+ ```ts
371
+ reporter: [['@reportforge/playwright-pdf', {
372
+ template: ['minimal', 'detailed'],
373
+ sections: {
374
+ defectLog: false, // baseline: drop the defect log everywhere
375
+ minimal: { charts: true }, // add charts to the minimal report
376
+ detailed: { ciEnvironment: false },
377
+ },
378
+ }]]
379
+ ```
380
+
381
+ Flat keys form the baseline for every chosen template; per-template keys
382
+ (`minimal` / `detailed` / `executive`) override the baseline for that template.
383
+
384
+ **Block toggles:** `coverPage`, `analysisOneliner`, `releaseGate`, `summary`,
385
+ `charts`, `trend`, `requirementsMatrix`, `ciEnvironment`, `suiteBreakdown`,
386
+ `failureDeepDive`, `failureAnalysis`, `slowTests`, `defectLog`.
387
+
388
+ **Display modifiers:** `passRate` (summary), `fullEnvironment` (full env table vs
389
+ compact), `retries` (suite retries column), `fullFailures` + `stackTraces`
390
+ (failure detail depth).
391
+
392
+ `trend` renders only when `charts` is also on **and** history data exists (`showTrend` enabled). Data-gated sections
393
+ (`failureAnalysis`, `requirementsMatrix`, `slowTests`, `defectLog`) appear only
394
+ when matching data exists — `sections` controls rendering, never data collection.
395
+ An unknown key throws a config error (typo-safe).
396
+
363
397
  ---
364
398
 
365
399
  ## CI/CD Integration
@@ -546,6 +580,7 @@ Full documentation at [reportforge.org/docs](https://reportforge.org/docs):
546
580
  - [Configuration reference](https://reportforge.org/docs#configuration) — all options
547
581
  - [Filename tokens](https://reportforge.org/docs#tokens) — `{date}`, `{branch}`, `{status}`
548
582
  - [Templates](https://reportforge.org/docs#templates) — minimal, detailed, executive
583
+ - [Report Sections](https://reportforge.org/docs#report-sections) — add or remove sections per template
549
584
  - [License & offline behaviour](https://reportforge.org/docs#license) — JWT cache, machine cap, cancellation
550
585
  - [Troubleshooting](https://reportforge.org/docs#troubleshooting) — common issues and debug flags
551
586
  - **Changelog** — [CHANGELOG.md](./CHANGELOG.md)
package/dist/demo/cli.js CHANGED
@@ -6531,15 +6531,134 @@ function dominantCategory(clusters) {
6531
6531
  return clusters[0]?.category ?? "unknown";
6532
6532
  }
6533
6533
 
6534
+ // src/templates/sections.ts
6535
+ init_cjs_shims();
6536
+ var SECTION_KEYS = [
6537
+ // block toggles
6538
+ "coverPage",
6539
+ "analysisOneliner",
6540
+ "releaseGate",
6541
+ "summary",
6542
+ "charts",
6543
+ "trend",
6544
+ "requirementsMatrix",
6545
+ "ciEnvironment",
6546
+ "suiteBreakdown",
6547
+ "failureDeepDive",
6548
+ "failureAnalysis",
6549
+ "slowTests",
6550
+ "defectLog",
6551
+ // display modifiers
6552
+ "passRate",
6553
+ "fullEnvironment",
6554
+ "retries",
6555
+ "fullFailures",
6556
+ "stackTraces"
6557
+ ];
6558
+ var SECTION_DEFAULTS = {
6559
+ minimal: {
6560
+ coverPage: false,
6561
+ analysisOneliner: false,
6562
+ releaseGate: true,
6563
+ summary: true,
6564
+ charts: false,
6565
+ trend: false,
6566
+ requirementsMatrix: false,
6567
+ ciEnvironment: true,
6568
+ suiteBreakdown: true,
6569
+ failureDeepDive: true,
6570
+ failureAnalysis: false,
6571
+ slowTests: false,
6572
+ defectLog: false,
6573
+ passRate: true,
6574
+ fullEnvironment: false,
6575
+ retries: true,
6576
+ fullFailures: true,
6577
+ stackTraces: true
6578
+ },
6579
+ detailed: {
6580
+ coverPage: false,
6581
+ analysisOneliner: false,
6582
+ releaseGate: true,
6583
+ summary: true,
6584
+ charts: true,
6585
+ trend: true,
6586
+ requirementsMatrix: true,
6587
+ ciEnvironment: true,
6588
+ suiteBreakdown: true,
6589
+ failureDeepDive: true,
6590
+ failureAnalysis: true,
6591
+ slowTests: true,
6592
+ defectLog: true,
6593
+ passRate: true,
6594
+ fullEnvironment: true,
6595
+ retries: true,
6596
+ fullFailures: true,
6597
+ stackTraces: true
6598
+ },
6599
+ executive: {
6600
+ coverPage: true,
6601
+ analysisOneliner: true,
6602
+ releaseGate: true,
6603
+ summary: true,
6604
+ charts: true,
6605
+ trend: true,
6606
+ requirementsMatrix: false,
6607
+ ciEnvironment: true,
6608
+ suiteBreakdown: false,
6609
+ failureDeepDive: true,
6610
+ failureAnalysis: false,
6611
+ slowTests: true,
6612
+ defectLog: false,
6613
+ passRate: true,
6614
+ fullEnvironment: false,
6615
+ retries: false,
6616
+ fullFailures: false,
6617
+ stackTraces: false
6618
+ }
6619
+ };
6620
+ var SECTION_KEY_SET = new Set(SECTION_KEYS);
6621
+ function resolveSections(template, userSections) {
6622
+ const base = SECTION_DEFAULTS[template];
6623
+ if (!userSections) return { ...base };
6624
+ const flat = {};
6625
+ for (const [k, v] of Object.entries(userSections)) {
6626
+ if (v !== void 0 && SECTION_KEY_SET.has(k)) flat[k] = v;
6627
+ }
6628
+ const perTemplateRaw = userSections[template] ?? {};
6629
+ const perTemplate = {};
6630
+ for (const [k, v] of Object.entries(perTemplateRaw)) {
6631
+ if (v !== void 0) perTemplate[k] = v;
6632
+ }
6633
+ const result = { ...base, ...flat, ...perTemplate };
6634
+ if (!result.charts) result.trend = false;
6635
+ return result;
6636
+ }
6637
+ function allSectionsOn() {
6638
+ return Object.fromEntries(SECTION_KEYS.map((k) => [k, true]));
6639
+ }
6640
+
6534
6641
  // src/templates/engine.ts
6535
6642
  function jsonForInlineScript(value) {
6536
6643
  return JSON.stringify(value).replace(/<\//g, "<\\/");
6537
6644
  }
6645
+ function deriveOptions(s) {
6646
+ return {
6647
+ showCharts: s.charts,
6648
+ showTrend: s.trend,
6649
+ showStackTraces: s.stackTraces,
6650
+ showFullEnvironment: s.fullEnvironment,
6651
+ showPassRate: s.passRate,
6652
+ showRetries: s.retries,
6653
+ showFullFailures: s.fullFailures
6654
+ };
6655
+ }
6538
6656
  var TemplateEngine = class {
6539
6657
  constructor() {
6540
6658
  this.chartjsInline = "";
6541
6659
  this.fontsBundleCss = "";
6542
6660
  this.customTemplateCache = /* @__PURE__ */ new Map();
6661
+ this.styleCache = /* @__PURE__ */ new Map();
6543
6662
  this.handlebars = import_handlebars.default.create();
6544
6663
  this.templatesDir = import_path.default.resolve(__dirname, "templates");
6545
6664
  if (!import_fs.default.existsSync(this.templatesDir)) {
@@ -6559,14 +6678,14 @@ var TemplateEngine = class {
6559
6678
  setChartjsBundle(inline) {
6560
6679
  this.chartjsInline = inline;
6561
6680
  }
6562
- render(data, template) {
6681
+ render(data, template, userSections) {
6563
6682
  const layoutPath = import_path.default.join(this.templatesDir, "layouts", `${template}.hbs`);
6564
6683
  if (!import_fs.default.existsSync(layoutPath)) {
6565
6684
  throw new Error(`[reportforge] Template layout not found: ${layoutPath}`);
6566
6685
  }
6567
6686
  const layoutSource = import_fs.default.readFileSync(layoutPath, "utf8");
6568
6687
  const compiledLayout = this.handlebars.compile(layoutSource);
6569
- const ctx = this.buildContext(data, template);
6688
+ const ctx = this.buildContext(data, template, userSections);
6570
6689
  return compiledLayout(ctx);
6571
6690
  }
6572
6691
  renderFromPath(data, filePath) {
@@ -6581,17 +6700,11 @@ var TemplateEngine = class {
6581
6700
  return compiledFn(this.buildCustomContext(data));
6582
6701
  }
6583
6702
  buildCustomContext(data) {
6703
+ const sections = allSectionsOn();
6584
6704
  return {
6585
6705
  ...data,
6586
- options: {
6587
- showCharts: true,
6588
- showTrend: true,
6589
- showStackTraces: true,
6590
- showFullEnvironment: true,
6591
- showPassRate: true,
6592
- showRetries: true,
6593
- showFullFailures: true
6594
- },
6706
+ options: deriveOptions(sections),
6707
+ sections,
6595
6708
  tagGroups: this.buildTagGroups(data),
6596
6709
  slowTests: this.buildSlowTests(data),
6597
6710
  baseCSS: this.fontsBundleCss + "\n" + this.readStyle("base.css"),
@@ -6599,47 +6712,20 @@ var TemplateEngine = class {
6599
6712
  chartjsScript: this.buildChartjsScript()
6600
6713
  };
6601
6714
  }
6602
- buildContext(data, template) {
6715
+ buildContext(data, template, userSections) {
6603
6716
  const baseCSS = this.fontsBundleCss + "\n" + this.readStyle("base.css");
6604
6717
  const templateCSS = this.readStyle(`${template}.css`);
6605
- const optionsMap = {
6606
- minimal: {
6607
- showCharts: false,
6608
- showTrend: false,
6609
- showStackTraces: true,
6610
- showFullEnvironment: false,
6611
- showPassRate: true,
6612
- showRetries: true,
6613
- showFullFailures: true
6614
- },
6615
- detailed: {
6616
- showCharts: true,
6617
- showTrend: true,
6618
- showStackTraces: true,
6619
- showFullEnvironment: true,
6620
- showPassRate: true,
6621
- showRetries: true,
6622
- showFullFailures: true
6623
- },
6624
- executive: {
6625
- showCharts: true,
6626
- showTrend: true,
6627
- showStackTraces: false,
6628
- showFullEnvironment: false,
6629
- showPassRate: true,
6630
- showRetries: false,
6631
- showFullFailures: false
6632
- }
6633
- };
6634
- const chartjsScript = this.buildChartjsScript();
6718
+ const sections = resolveSections(template, userSections);
6719
+ const options = deriveOptions(sections);
6635
6720
  return {
6636
6721
  ...data,
6637
- options: optionsMap[template],
6722
+ options,
6723
+ sections,
6638
6724
  tagGroups: this.buildTagGroups(data),
6639
6725
  slowTests: this.buildSlowTests(data),
6640
6726
  baseCSS,
6641
6727
  templateCSS,
6642
- chartjsScript
6728
+ chartjsScript: this.buildChartjsScript()
6643
6729
  };
6644
6730
  }
6645
6731
  buildChartjsScript() {
@@ -6687,9 +6773,12 @@ var TemplateEngine = class {
6687
6773
  return tests.sort((a, b) => b.durationMs - a.durationMs).slice(0, 10);
6688
6774
  }
6689
6775
  readStyle(filename) {
6776
+ const cached = this.styleCache.get(filename);
6777
+ if (cached !== void 0) return cached;
6690
6778
  const stylePath = import_path.default.join(this.templatesDir, "styles", filename);
6691
- if (!import_fs.default.existsSync(stylePath)) return "";
6692
- return import_fs.default.readFileSync(stylePath, "utf8");
6779
+ const css = import_fs.default.existsSync(stylePath) ? import_fs.default.readFileSync(stylePath, "utf8") : "";
6780
+ this.styleCache.set(filename, css);
6781
+ return css;
6693
6782
  }
6694
6783
  registerPartials() {
6695
6784
  const partialsDir = import_path.default.join(this.templatesDir, "partials");
@@ -7274,6 +7363,12 @@ var PdfGenerator = class {
7274
7363
  `Compression: level=${compression.effective} jpeg-q=${compression.quality} max-w=${compression.maxWidth}px inline-failures\u2264${compression.maxInlineFailures}`
7275
7364
  );
7276
7365
  const outputPaths = [];
7366
+ if (options.sections !== void 0) {
7367
+ const hasCustom = sources.some((s) => s.kind !== "builtin");
7368
+ if (hasCustom) {
7369
+ logger.warn('[reportforge] "sections" applies to built-in templates only; it is ignored for custom templatePath templates.');
7370
+ }
7371
+ }
7277
7372
  const { page } = await this.browserManager.launch(options.puppeteerExecutablePath);
7278
7373
  try {
7279
7374
  for (const source of sources) {
@@ -7381,13 +7476,13 @@ var PdfGenerator = class {
7381
7476
  }
7382
7477
  const templateLabel = source.kind === "builtin" ? source.id : source.label;
7383
7478
  logger.info(`Rendering template: ${templateLabel}`);
7384
- const html = source.kind === "builtin" ? this.templateEngine.render(renderData, source.id) : this.templateEngine.renderFromPath(renderData, source.absolutePath);
7479
+ const html = source.kind === "builtin" ? this.templateEngine.render(renderData, source.id, options.sections) : this.templateEngine.renderFromPath(renderData, source.absolutePath);
7385
7480
  const tempHtmlPath = await this.htmlWriter.write(html);
7386
7481
  const fileUrl = this.htmlWriter.toFileUrl(tempHtmlPath);
7387
7482
  try {
7388
7483
  logger.info(`Navigating to temp HTML (${Math.round(html.length / 1024)} KB)...`);
7389
7484
  await page.goto(fileUrl, { waitUntil: "domcontentloaded", timeout: 6e4 });
7390
- const showCharts = source.kind === "builtin" ? source.id !== "minimal" : true;
7485
+ const showCharts = source.kind === "builtin" ? resolveSections(source.id, options.sections).charts : true;
7391
7486
  await this.chartRenderer.waitForCharts(page, showCharts);
7392
7487
  logger.info(`Generating PDF \u2192 ${import_path6.default.relative(process.cwd(), outputPath)}`);
7393
7488
  await page.pdf({
@@ -11516,6 +11611,15 @@ var failureAnalysisConfigSchema = external_exports.object({
11516
11611
  collectUnclassified: external_exports.boolean().default(true),
11517
11612
  autoUpdateModel: external_exports.boolean().default(true)
11518
11613
  }).default({});
11614
+ var sectionFlagsShape = Object.fromEntries(
11615
+ SECTION_KEYS.map((k) => [k, external_exports.boolean().optional()])
11616
+ );
11617
+ var sectionFlagsSchema = external_exports.object(sectionFlagsShape).strict();
11618
+ var sectionsSchema = sectionFlagsSchema.extend({
11619
+ minimal: sectionFlagsSchema.optional(),
11620
+ detailed: sectionFlagsSchema.optional(),
11621
+ executive: sectionFlagsSchema.optional()
11622
+ }).strict();
11519
11623
  var ReporterOptionsSchema = external_exports.object({
11520
11624
  outputFile: external_exports.string().optional().default(DEFAULT_OPTIONS.outputFile),
11521
11625
  template: external_exports.union([
@@ -11553,7 +11657,8 @@ var ReporterOptionsSchema = external_exports.object({
11553
11657
  ).min(1, "templatePath array must not be empty")
11554
11658
  ]).optional().transform(
11555
11659
  (v) => v === void 0 ? void 0 : Array.isArray(v) ? v : [v]
11556
- )
11660
+ ),
11661
+ sections: sectionsSchema.optional()
11557
11662
  });
11558
11663
  function parseOptions(raw) {
11559
11664
  const result = ReporterOptionsSchema.safeParse(raw ?? {});
package/dist/index.d.mts CHANGED
@@ -1,5 +1,21 @@
1
1
  import { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter';
2
2
 
3
+ /**
4
+ * Canonical section catalog. 13 block toggles (section present/absent) followed
5
+ * by 5 display modifiers (tweak a section that is on). Single source of truth —
6
+ * the Zod schema in src/config/schema.ts builds its flag shape from this array.
7
+ */
8
+ declare const SECTION_KEYS: readonly ["coverPage", "analysisOneliner", "releaseGate", "summary", "charts", "trend", "requirementsMatrix", "ciEnvironment", "suiteBreakdown", "failureDeepDive", "failureAnalysis", "slowTests", "defectLog", "passRate", "fullEnvironment", "retries", "fullFailures", "stackTraces"];
9
+ type SectionKey = (typeof SECTION_KEYS)[number];
10
+ /** A partial map of section flags — used both as the flat baseline and per-template. */
11
+ type SectionFlags = Partial<Record<SectionKey, boolean>>;
12
+ /** The public `sections` option shape: flat flags + optional per-template overrides. */
13
+ type SectionsOption = SectionFlags & {
14
+ minimal?: SectionFlags;
15
+ detailed?: SectionFlags;
16
+ executive?: SectionFlags;
17
+ };
18
+
3
19
  declare const TEMPLATE_IDS: readonly ["minimal", "detailed", "executive"];
4
20
  type TemplateId = (typeof TEMPLATE_IDS)[number];
5
21
  /**
@@ -230,6 +246,30 @@ interface ReporterOptions {
230
246
  * templatePath: ['./templates/exec.hbs', './templates/eng.hbs']
231
247
  */
232
248
  templatePath?: string | string[];
249
+ /**
250
+ * Per-section override of which report sections appear, on top of the chosen
251
+ * template's defaults. Both-layered: flat keys are the baseline applied to
252
+ * every chosen template; per-template keys (`minimal` / `detailed` /
253
+ * `executive`) override the baseline for that template only.
254
+ *
255
+ * Block toggles: `coverPage`, `analysisOneliner`, `releaseGate`, `summary`,
256
+ * `charts`, `trend`, `requirementsMatrix`, `ciEnvironment`, `suiteBreakdown`,
257
+ * `failureDeepDive`, `failureAnalysis`, `slowTests`, `defectLog`.
258
+ * Display modifiers: `passRate`, `fullEnvironment`, `retries`, `fullFailures`,
259
+ * `stackTraces`.
260
+ *
261
+ * `trend` renders only when `charts` is also on and history data exists (`showTrend` enabled). Sections gated on data
262
+ * (`failureAnalysis`, `requirementsMatrix`, `slowTests`, `defectLog`) appear
263
+ * only when matching data exists — this option never changes data collection.
264
+ *
265
+ * @example
266
+ * sections: {
267
+ * defectLog: false, // baseline for all chosen templates
268
+ * minimal: { charts: true }, // add charts to the minimal report
269
+ * detailed: { ciEnvironment: false },
270
+ * }
271
+ */
272
+ sections?: SectionsOption;
233
273
  }
234
274
 
235
275
  /**
package/dist/index.d.ts CHANGED
@@ -1,5 +1,21 @@
1
1
  import { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter';
2
2
 
3
+ /**
4
+ * Canonical section catalog. 13 block toggles (section present/absent) followed
5
+ * by 5 display modifiers (tweak a section that is on). Single source of truth —
6
+ * the Zod schema in src/config/schema.ts builds its flag shape from this array.
7
+ */
8
+ declare const SECTION_KEYS: readonly ["coverPage", "analysisOneliner", "releaseGate", "summary", "charts", "trend", "requirementsMatrix", "ciEnvironment", "suiteBreakdown", "failureDeepDive", "failureAnalysis", "slowTests", "defectLog", "passRate", "fullEnvironment", "retries", "fullFailures", "stackTraces"];
9
+ type SectionKey = (typeof SECTION_KEYS)[number];
10
+ /** A partial map of section flags — used both as the flat baseline and per-template. */
11
+ type SectionFlags = Partial<Record<SectionKey, boolean>>;
12
+ /** The public `sections` option shape: flat flags + optional per-template overrides. */
13
+ type SectionsOption = SectionFlags & {
14
+ minimal?: SectionFlags;
15
+ detailed?: SectionFlags;
16
+ executive?: SectionFlags;
17
+ };
18
+
3
19
  declare const TEMPLATE_IDS: readonly ["minimal", "detailed", "executive"];
4
20
  type TemplateId = (typeof TEMPLATE_IDS)[number];
5
21
  /**
@@ -230,6 +246,30 @@ interface ReporterOptions {
230
246
  * templatePath: ['./templates/exec.hbs', './templates/eng.hbs']
231
247
  */
232
248
  templatePath?: string | string[];
249
+ /**
250
+ * Per-section override of which report sections appear, on top of the chosen
251
+ * template's defaults. Both-layered: flat keys are the baseline applied to
252
+ * every chosen template; per-template keys (`minimal` / `detailed` /
253
+ * `executive`) override the baseline for that template only.
254
+ *
255
+ * Block toggles: `coverPage`, `analysisOneliner`, `releaseGate`, `summary`,
256
+ * `charts`, `trend`, `requirementsMatrix`, `ciEnvironment`, `suiteBreakdown`,
257
+ * `failureDeepDive`, `failureAnalysis`, `slowTests`, `defectLog`.
258
+ * Display modifiers: `passRate`, `fullEnvironment`, `retries`, `fullFailures`,
259
+ * `stackTraces`.
260
+ *
261
+ * `trend` renders only when `charts` is also on and history data exists (`showTrend` enabled). Sections gated on data
262
+ * (`failureAnalysis`, `requirementsMatrix`, `slowTests`, `defectLog`) appear
263
+ * only when matching data exists — this option never changes data collection.
264
+ *
265
+ * @example
266
+ * sections: {
267
+ * defectLog: false, // baseline for all chosen templates
268
+ * minimal: { charts: true }, // add charts to the minimal report
269
+ * detailed: { ciEnvironment: false },
270
+ * }
271
+ */
272
+ sections?: SectionsOption;
233
273
  }
234
274
 
235
275
  /**