@reportforge/playwright-pdf 0.5.1 → 0.6.1

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.js CHANGED
@@ -10332,6 +10332,113 @@ var DEFAULT_OPTIONS = {
10332
10332
  flakinessTopN: 5
10333
10333
  };
10334
10334
 
10335
+ // src/templates/sections.ts
10336
+ init_cjs_shims();
10337
+ var SECTION_KEYS = [
10338
+ // block toggles
10339
+ "coverPage",
10340
+ "analysisOneliner",
10341
+ "releaseGate",
10342
+ "summary",
10343
+ "charts",
10344
+ "trend",
10345
+ "requirementsMatrix",
10346
+ "ciEnvironment",
10347
+ "suiteBreakdown",
10348
+ "failureDeepDive",
10349
+ "failureAnalysis",
10350
+ "slowTests",
10351
+ "defectLog",
10352
+ // display modifiers
10353
+ "passRate",
10354
+ "fullEnvironment",
10355
+ "retries",
10356
+ "fullFailures",
10357
+ "stackTraces"
10358
+ ];
10359
+ var SECTION_DEFAULTS = {
10360
+ minimal: {
10361
+ coverPage: false,
10362
+ analysisOneliner: false,
10363
+ releaseGate: true,
10364
+ summary: true,
10365
+ charts: false,
10366
+ trend: false,
10367
+ requirementsMatrix: false,
10368
+ ciEnvironment: true,
10369
+ suiteBreakdown: true,
10370
+ failureDeepDive: true,
10371
+ failureAnalysis: false,
10372
+ slowTests: false,
10373
+ defectLog: false,
10374
+ passRate: true,
10375
+ fullEnvironment: false,
10376
+ retries: true,
10377
+ fullFailures: true,
10378
+ stackTraces: true
10379
+ },
10380
+ detailed: {
10381
+ coverPage: false,
10382
+ analysisOneliner: false,
10383
+ releaseGate: true,
10384
+ summary: true,
10385
+ charts: true,
10386
+ trend: true,
10387
+ requirementsMatrix: true,
10388
+ ciEnvironment: true,
10389
+ suiteBreakdown: true,
10390
+ failureDeepDive: true,
10391
+ failureAnalysis: true,
10392
+ slowTests: true,
10393
+ defectLog: true,
10394
+ passRate: true,
10395
+ fullEnvironment: true,
10396
+ retries: true,
10397
+ fullFailures: true,
10398
+ stackTraces: true
10399
+ },
10400
+ executive: {
10401
+ coverPage: true,
10402
+ analysisOneliner: true,
10403
+ releaseGate: true,
10404
+ summary: true,
10405
+ charts: true,
10406
+ trend: true,
10407
+ requirementsMatrix: false,
10408
+ ciEnvironment: true,
10409
+ suiteBreakdown: false,
10410
+ failureDeepDive: true,
10411
+ failureAnalysis: false,
10412
+ slowTests: true,
10413
+ defectLog: false,
10414
+ passRate: true,
10415
+ fullEnvironment: false,
10416
+ retries: false,
10417
+ fullFailures: false,
10418
+ stackTraces: false
10419
+ }
10420
+ };
10421
+ var SECTION_KEY_SET = new Set(SECTION_KEYS);
10422
+ function resolveSections(template, userSections) {
10423
+ const base = SECTION_DEFAULTS[template];
10424
+ if (!userSections) return { ...base };
10425
+ const flat = {};
10426
+ for (const [k, v] of Object.entries(userSections)) {
10427
+ if (v !== void 0 && SECTION_KEY_SET.has(k)) flat[k] = v;
10428
+ }
10429
+ const perTemplateRaw = userSections[template] ?? {};
10430
+ const perTemplate = {};
10431
+ for (const [k, v] of Object.entries(perTemplateRaw)) {
10432
+ if (v !== void 0) perTemplate[k] = v;
10433
+ }
10434
+ const result = { ...base, ...flat, ...perTemplate };
10435
+ if (!result.charts) result.trend = false;
10436
+ return result;
10437
+ }
10438
+ function allSectionsOn() {
10439
+ return Object.fromEntries(SECTION_KEYS.map((k) => [k, true]));
10440
+ }
10441
+
10335
10442
  // src/config/schema.ts
10336
10443
  var hexColor = external_exports.string().regex(
10337
10444
  /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,
@@ -10364,6 +10471,15 @@ var failureAnalysisConfigSchema = external_exports.object({
10364
10471
  collectUnclassified: external_exports.boolean().default(true),
10365
10472
  autoUpdateModel: external_exports.boolean().default(true)
10366
10473
  }).default({});
10474
+ var sectionFlagsShape = Object.fromEntries(
10475
+ SECTION_KEYS.map((k) => [k, external_exports.boolean().optional()])
10476
+ );
10477
+ var sectionFlagsSchema = external_exports.object(sectionFlagsShape).strict();
10478
+ var sectionsSchema = sectionFlagsSchema.extend({
10479
+ minimal: sectionFlagsSchema.optional(),
10480
+ detailed: sectionFlagsSchema.optional(),
10481
+ executive: sectionFlagsSchema.optional()
10482
+ }).strict();
10367
10483
  var ReporterOptionsSchema = external_exports.object({
10368
10484
  outputFile: external_exports.string().optional().default(DEFAULT_OPTIONS.outputFile),
10369
10485
  template: external_exports.union([
@@ -10401,7 +10517,8 @@ var ReporterOptionsSchema = external_exports.object({
10401
10517
  ).min(1, "templatePath array must not be empty")
10402
10518
  ]).optional().transform(
10403
10519
  (v) => v === void 0 ? void 0 : Array.isArray(v) ? v : [v]
10404
- )
10520
+ ),
10521
+ sections: sectionsSchema.optional()
10405
10522
  });
10406
10523
  function parseOptions(raw) {
10407
10524
  const result = ReporterOptionsSchema.safeParse(raw ?? {});
@@ -11913,11 +12030,23 @@ function formatDuration(ms) {
11913
12030
  function jsonForInlineScript(value) {
11914
12031
  return JSON.stringify(value).replace(/<\//g, "<\\/");
11915
12032
  }
12033
+ function deriveOptions(s) {
12034
+ return {
12035
+ showCharts: s.charts,
12036
+ showTrend: s.trend,
12037
+ showStackTraces: s.stackTraces,
12038
+ showFullEnvironment: s.fullEnvironment,
12039
+ showPassRate: s.passRate,
12040
+ showRetries: s.retries,
12041
+ showFullFailures: s.fullFailures
12042
+ };
12043
+ }
11916
12044
  var TemplateEngine = class {
11917
12045
  constructor() {
11918
12046
  this.chartjsInline = "";
11919
12047
  this.fontsBundleCss = "";
11920
12048
  this.customTemplateCache = /* @__PURE__ */ new Map();
12049
+ this.styleCache = /* @__PURE__ */ new Map();
11921
12050
  this.handlebars = import_handlebars.default.create();
11922
12051
  this.templatesDir = import_path3.default.resolve(__dirname, "templates");
11923
12052
  if (!import_fs4.default.existsSync(this.templatesDir)) {
@@ -11937,14 +12066,14 @@ var TemplateEngine = class {
11937
12066
  setChartjsBundle(inline) {
11938
12067
  this.chartjsInline = inline;
11939
12068
  }
11940
- render(data, template) {
12069
+ render(data, template, userSections) {
11941
12070
  const layoutPath = import_path3.default.join(this.templatesDir, "layouts", `${template}.hbs`);
11942
12071
  if (!import_fs4.default.existsSync(layoutPath)) {
11943
12072
  throw new Error(`[reportforge] Template layout not found: ${layoutPath}`);
11944
12073
  }
11945
12074
  const layoutSource = import_fs4.default.readFileSync(layoutPath, "utf8");
11946
12075
  const compiledLayout = this.handlebars.compile(layoutSource);
11947
- const ctx = this.buildContext(data, template);
12076
+ const ctx = this.buildContext(data, template, userSections);
11948
12077
  return compiledLayout(ctx);
11949
12078
  }
11950
12079
  renderFromPath(data, filePath) {
@@ -11959,17 +12088,11 @@ var TemplateEngine = class {
11959
12088
  return compiledFn(this.buildCustomContext(data));
11960
12089
  }
11961
12090
  buildCustomContext(data) {
12091
+ const sections = allSectionsOn();
11962
12092
  return {
11963
12093
  ...data,
11964
- options: {
11965
- showCharts: true,
11966
- showTrend: true,
11967
- showStackTraces: true,
11968
- showFullEnvironment: true,
11969
- showPassRate: true,
11970
- showRetries: true,
11971
- showFullFailures: true
11972
- },
12094
+ options: deriveOptions(sections),
12095
+ sections,
11973
12096
  tagGroups: this.buildTagGroups(data),
11974
12097
  slowTests: this.buildSlowTests(data),
11975
12098
  baseCSS: this.fontsBundleCss + "\n" + this.readStyle("base.css"),
@@ -11977,47 +12100,20 @@ var TemplateEngine = class {
11977
12100
  chartjsScript: this.buildChartjsScript()
11978
12101
  };
11979
12102
  }
11980
- buildContext(data, template) {
12103
+ buildContext(data, template, userSections) {
11981
12104
  const baseCSS = this.fontsBundleCss + "\n" + this.readStyle("base.css");
11982
12105
  const templateCSS = this.readStyle(`${template}.css`);
11983
- const optionsMap = {
11984
- minimal: {
11985
- showCharts: false,
11986
- showTrend: false,
11987
- showStackTraces: true,
11988
- showFullEnvironment: false,
11989
- showPassRate: true,
11990
- showRetries: true,
11991
- showFullFailures: true
11992
- },
11993
- detailed: {
11994
- showCharts: true,
11995
- showTrend: true,
11996
- showStackTraces: true,
11997
- showFullEnvironment: true,
11998
- showPassRate: true,
11999
- showRetries: true,
12000
- showFullFailures: true
12001
- },
12002
- executive: {
12003
- showCharts: true,
12004
- showTrend: true,
12005
- showStackTraces: false,
12006
- showFullEnvironment: false,
12007
- showPassRate: true,
12008
- showRetries: false,
12009
- showFullFailures: false
12010
- }
12011
- };
12012
- const chartjsScript = this.buildChartjsScript();
12106
+ const sections = resolveSections(template, userSections);
12107
+ const options = deriveOptions(sections);
12013
12108
  return {
12014
12109
  ...data,
12015
- options: optionsMap[template],
12110
+ options,
12111
+ sections,
12016
12112
  tagGroups: this.buildTagGroups(data),
12017
12113
  slowTests: this.buildSlowTests(data),
12018
12114
  baseCSS,
12019
12115
  templateCSS,
12020
- chartjsScript
12116
+ chartjsScript: this.buildChartjsScript()
12021
12117
  };
12022
12118
  }
12023
12119
  buildChartjsScript() {
@@ -12065,9 +12161,12 @@ var TemplateEngine = class {
12065
12161
  return tests.sort((a, b) => b.durationMs - a.durationMs).slice(0, 10);
12066
12162
  }
12067
12163
  readStyle(filename) {
12164
+ const cached = this.styleCache.get(filename);
12165
+ if (cached !== void 0) return cached;
12068
12166
  const stylePath = import_path3.default.join(this.templatesDir, "styles", filename);
12069
- if (!import_fs4.default.existsSync(stylePath)) return "";
12070
- return import_fs4.default.readFileSync(stylePath, "utf8");
12167
+ const css = import_fs4.default.existsSync(stylePath) ? import_fs4.default.readFileSync(stylePath, "utf8") : "";
12168
+ this.styleCache.set(filename, css);
12169
+ return css;
12071
12170
  }
12072
12171
  registerPartials() {
12073
12172
  const partialsDir = import_path3.default.join(this.templatesDir, "partials");
@@ -12622,6 +12721,12 @@ var PdfGenerator = class {
12622
12721
  `Compression: level=${compression.effective} jpeg-q=${compression.quality} max-w=${compression.maxWidth}px inline-failures\u2264${compression.maxInlineFailures}`
12623
12722
  );
12624
12723
  const outputPaths = [];
12724
+ if (options.sections !== void 0) {
12725
+ const hasCustom = sources.some((s) => s.kind !== "builtin");
12726
+ if (hasCustom) {
12727
+ logger.warn('[reportforge] "sections" applies to built-in templates only; it is ignored for custom templatePath templates.');
12728
+ }
12729
+ }
12625
12730
  const { page } = await this.browserManager.launch(options.puppeteerExecutablePath);
12626
12731
  try {
12627
12732
  for (const source of sources) {
@@ -12729,13 +12834,13 @@ var PdfGenerator = class {
12729
12834
  }
12730
12835
  const templateLabel = source.kind === "builtin" ? source.id : source.label;
12731
12836
  logger.info(`Rendering template: ${templateLabel}`);
12732
- const html = source.kind === "builtin" ? this.templateEngine.render(renderData, source.id) : this.templateEngine.renderFromPath(renderData, source.absolutePath);
12837
+ const html = source.kind === "builtin" ? this.templateEngine.render(renderData, source.id, options.sections) : this.templateEngine.renderFromPath(renderData, source.absolutePath);
12733
12838
  const tempHtmlPath = await this.htmlWriter.write(html);
12734
12839
  const fileUrl = this.htmlWriter.toFileUrl(tempHtmlPath);
12735
12840
  try {
12736
12841
  logger.info(`Navigating to temp HTML (${Math.round(html.length / 1024)} KB)...`);
12737
12842
  await page.goto(fileUrl, { waitUntil: "domcontentloaded", timeout: 6e4 });
12738
- const showCharts = source.kind === "builtin" ? source.id !== "minimal" : true;
12843
+ const showCharts = source.kind === "builtin" ? resolveSections(source.id, options.sections).charts : true;
12739
12844
  await this.chartRenderer.waitForCharts(page, showCharts);
12740
12845
  logger.info(`Generating PDF \u2192 ${import_path8.default.relative(process.cwd(), outputPath)}`);
12741
12846
  await page.pdf({
@@ -13126,7 +13231,7 @@ var PdfReporter = class {
13126
13231
  this.dataCollector = new DataCollector();
13127
13232
  this.pdfGenerator = new PdfGenerator();
13128
13233
  this.options = parseOptions(rawOptions);
13129
- const version = true ? "0.5.1" : "0.x";
13234
+ const version = true ? "0.6.1" : "0.x";
13130
13235
  logger.info(`@reportforge/playwright-pdf v${version} initialised`);
13131
13236
  this.licenseClient = new LicenseClient({
13132
13237
  licenseKey: this.options.licenseKey,
package/dist/index.mjs CHANGED
@@ -10333,6 +10333,113 @@ var DEFAULT_OPTIONS = {
10333
10333
  flakinessTopN: 5
10334
10334
  };
10335
10335
 
10336
+ // src/templates/sections.ts
10337
+ init_esm_shims();
10338
+ var SECTION_KEYS = [
10339
+ // block toggles
10340
+ "coverPage",
10341
+ "analysisOneliner",
10342
+ "releaseGate",
10343
+ "summary",
10344
+ "charts",
10345
+ "trend",
10346
+ "requirementsMatrix",
10347
+ "ciEnvironment",
10348
+ "suiteBreakdown",
10349
+ "failureDeepDive",
10350
+ "failureAnalysis",
10351
+ "slowTests",
10352
+ "defectLog",
10353
+ // display modifiers
10354
+ "passRate",
10355
+ "fullEnvironment",
10356
+ "retries",
10357
+ "fullFailures",
10358
+ "stackTraces"
10359
+ ];
10360
+ var SECTION_DEFAULTS = {
10361
+ minimal: {
10362
+ coverPage: false,
10363
+ analysisOneliner: false,
10364
+ releaseGate: true,
10365
+ summary: true,
10366
+ charts: false,
10367
+ trend: false,
10368
+ requirementsMatrix: false,
10369
+ ciEnvironment: true,
10370
+ suiteBreakdown: true,
10371
+ failureDeepDive: true,
10372
+ failureAnalysis: false,
10373
+ slowTests: false,
10374
+ defectLog: false,
10375
+ passRate: true,
10376
+ fullEnvironment: false,
10377
+ retries: true,
10378
+ fullFailures: true,
10379
+ stackTraces: true
10380
+ },
10381
+ detailed: {
10382
+ coverPage: false,
10383
+ analysisOneliner: false,
10384
+ releaseGate: true,
10385
+ summary: true,
10386
+ charts: true,
10387
+ trend: true,
10388
+ requirementsMatrix: true,
10389
+ ciEnvironment: true,
10390
+ suiteBreakdown: true,
10391
+ failureDeepDive: true,
10392
+ failureAnalysis: true,
10393
+ slowTests: true,
10394
+ defectLog: true,
10395
+ passRate: true,
10396
+ fullEnvironment: true,
10397
+ retries: true,
10398
+ fullFailures: true,
10399
+ stackTraces: true
10400
+ },
10401
+ executive: {
10402
+ coverPage: true,
10403
+ analysisOneliner: true,
10404
+ releaseGate: true,
10405
+ summary: true,
10406
+ charts: true,
10407
+ trend: true,
10408
+ requirementsMatrix: false,
10409
+ ciEnvironment: true,
10410
+ suiteBreakdown: false,
10411
+ failureDeepDive: true,
10412
+ failureAnalysis: false,
10413
+ slowTests: true,
10414
+ defectLog: false,
10415
+ passRate: true,
10416
+ fullEnvironment: false,
10417
+ retries: false,
10418
+ fullFailures: false,
10419
+ stackTraces: false
10420
+ }
10421
+ };
10422
+ var SECTION_KEY_SET = new Set(SECTION_KEYS);
10423
+ function resolveSections(template, userSections) {
10424
+ const base = SECTION_DEFAULTS[template];
10425
+ if (!userSections) return { ...base };
10426
+ const flat = {};
10427
+ for (const [k, v] of Object.entries(userSections)) {
10428
+ if (v !== void 0 && SECTION_KEY_SET.has(k)) flat[k] = v;
10429
+ }
10430
+ const perTemplateRaw = userSections[template] ?? {};
10431
+ const perTemplate = {};
10432
+ for (const [k, v] of Object.entries(perTemplateRaw)) {
10433
+ if (v !== void 0) perTemplate[k] = v;
10434
+ }
10435
+ const result = { ...base, ...flat, ...perTemplate };
10436
+ if (!result.charts) result.trend = false;
10437
+ return result;
10438
+ }
10439
+ function allSectionsOn() {
10440
+ return Object.fromEntries(SECTION_KEYS.map((k) => [k, true]));
10441
+ }
10442
+
10336
10443
  // src/config/schema.ts
10337
10444
  var hexColor = external_exports.string().regex(
10338
10445
  /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,
@@ -10365,6 +10472,15 @@ var failureAnalysisConfigSchema = external_exports.object({
10365
10472
  collectUnclassified: external_exports.boolean().default(true),
10366
10473
  autoUpdateModel: external_exports.boolean().default(true)
10367
10474
  }).default({});
10475
+ var sectionFlagsShape = Object.fromEntries(
10476
+ SECTION_KEYS.map((k) => [k, external_exports.boolean().optional()])
10477
+ );
10478
+ var sectionFlagsSchema = external_exports.object(sectionFlagsShape).strict();
10479
+ var sectionsSchema = sectionFlagsSchema.extend({
10480
+ minimal: sectionFlagsSchema.optional(),
10481
+ detailed: sectionFlagsSchema.optional(),
10482
+ executive: sectionFlagsSchema.optional()
10483
+ }).strict();
10368
10484
  var ReporterOptionsSchema = external_exports.object({
10369
10485
  outputFile: external_exports.string().optional().default(DEFAULT_OPTIONS.outputFile),
10370
10486
  template: external_exports.union([
@@ -10402,7 +10518,8 @@ var ReporterOptionsSchema = external_exports.object({
10402
10518
  ).min(1, "templatePath array must not be empty")
10403
10519
  ]).optional().transform(
10404
10520
  (v) => v === void 0 ? void 0 : Array.isArray(v) ? v : [v]
10405
- )
10521
+ ),
10522
+ sections: sectionsSchema.optional()
10406
10523
  });
10407
10524
  function parseOptions(raw) {
10408
10525
  const result = ReporterOptionsSchema.safeParse(raw ?? {});
@@ -11914,11 +12031,23 @@ function formatDuration(ms) {
11914
12031
  function jsonForInlineScript(value) {
11915
12032
  return JSON.stringify(value).replace(/<\//g, "<\\/");
11916
12033
  }
12034
+ function deriveOptions(s) {
12035
+ return {
12036
+ showCharts: s.charts,
12037
+ showTrend: s.trend,
12038
+ showStackTraces: s.stackTraces,
12039
+ showFullEnvironment: s.fullEnvironment,
12040
+ showPassRate: s.passRate,
12041
+ showRetries: s.retries,
12042
+ showFullFailures: s.fullFailures
12043
+ };
12044
+ }
11917
12045
  var TemplateEngine = class {
11918
12046
  constructor() {
11919
12047
  this.chartjsInline = "";
11920
12048
  this.fontsBundleCss = "";
11921
12049
  this.customTemplateCache = /* @__PURE__ */ new Map();
12050
+ this.styleCache = /* @__PURE__ */ new Map();
11922
12051
  this.handlebars = import_handlebars.default.create();
11923
12052
  this.templatesDir = path7.resolve(__dirname, "templates");
11924
12053
  if (!fs5.existsSync(this.templatesDir)) {
@@ -11938,14 +12067,14 @@ var TemplateEngine = class {
11938
12067
  setChartjsBundle(inline) {
11939
12068
  this.chartjsInline = inline;
11940
12069
  }
11941
- render(data, template) {
12070
+ render(data, template, userSections) {
11942
12071
  const layoutPath = path7.join(this.templatesDir, "layouts", `${template}.hbs`);
11943
12072
  if (!fs5.existsSync(layoutPath)) {
11944
12073
  throw new Error(`[reportforge] Template layout not found: ${layoutPath}`);
11945
12074
  }
11946
12075
  const layoutSource = fs5.readFileSync(layoutPath, "utf8");
11947
12076
  const compiledLayout = this.handlebars.compile(layoutSource);
11948
- const ctx = this.buildContext(data, template);
12077
+ const ctx = this.buildContext(data, template, userSections);
11949
12078
  return compiledLayout(ctx);
11950
12079
  }
11951
12080
  renderFromPath(data, filePath) {
@@ -11960,17 +12089,11 @@ var TemplateEngine = class {
11960
12089
  return compiledFn(this.buildCustomContext(data));
11961
12090
  }
11962
12091
  buildCustomContext(data) {
12092
+ const sections = allSectionsOn();
11963
12093
  return {
11964
12094
  ...data,
11965
- options: {
11966
- showCharts: true,
11967
- showTrend: true,
11968
- showStackTraces: true,
11969
- showFullEnvironment: true,
11970
- showPassRate: true,
11971
- showRetries: true,
11972
- showFullFailures: true
11973
- },
12095
+ options: deriveOptions(sections),
12096
+ sections,
11974
12097
  tagGroups: this.buildTagGroups(data),
11975
12098
  slowTests: this.buildSlowTests(data),
11976
12099
  baseCSS: this.fontsBundleCss + "\n" + this.readStyle("base.css"),
@@ -11978,47 +12101,20 @@ var TemplateEngine = class {
11978
12101
  chartjsScript: this.buildChartjsScript()
11979
12102
  };
11980
12103
  }
11981
- buildContext(data, template) {
12104
+ buildContext(data, template, userSections) {
11982
12105
  const baseCSS = this.fontsBundleCss + "\n" + this.readStyle("base.css");
11983
12106
  const templateCSS = this.readStyle(`${template}.css`);
11984
- const optionsMap = {
11985
- minimal: {
11986
- showCharts: false,
11987
- showTrend: false,
11988
- showStackTraces: true,
11989
- showFullEnvironment: false,
11990
- showPassRate: true,
11991
- showRetries: true,
11992
- showFullFailures: true
11993
- },
11994
- detailed: {
11995
- showCharts: true,
11996
- showTrend: true,
11997
- showStackTraces: true,
11998
- showFullEnvironment: true,
11999
- showPassRate: true,
12000
- showRetries: true,
12001
- showFullFailures: true
12002
- },
12003
- executive: {
12004
- showCharts: true,
12005
- showTrend: true,
12006
- showStackTraces: false,
12007
- showFullEnvironment: false,
12008
- showPassRate: true,
12009
- showRetries: false,
12010
- showFullFailures: false
12011
- }
12012
- };
12013
- const chartjsScript = this.buildChartjsScript();
12107
+ const sections = resolveSections(template, userSections);
12108
+ const options = deriveOptions(sections);
12014
12109
  return {
12015
12110
  ...data,
12016
- options: optionsMap[template],
12111
+ options,
12112
+ sections,
12017
12113
  tagGroups: this.buildTagGroups(data),
12018
12114
  slowTests: this.buildSlowTests(data),
12019
12115
  baseCSS,
12020
12116
  templateCSS,
12021
- chartjsScript
12117
+ chartjsScript: this.buildChartjsScript()
12022
12118
  };
12023
12119
  }
12024
12120
  buildChartjsScript() {
@@ -12066,9 +12162,12 @@ var TemplateEngine = class {
12066
12162
  return tests.sort((a, b) => b.durationMs - a.durationMs).slice(0, 10);
12067
12163
  }
12068
12164
  readStyle(filename) {
12165
+ const cached = this.styleCache.get(filename);
12166
+ if (cached !== void 0) return cached;
12069
12167
  const stylePath = path7.join(this.templatesDir, "styles", filename);
12070
- if (!fs5.existsSync(stylePath)) return "";
12071
- return fs5.readFileSync(stylePath, "utf8");
12168
+ const css = fs5.existsSync(stylePath) ? fs5.readFileSync(stylePath, "utf8") : "";
12169
+ this.styleCache.set(filename, css);
12170
+ return css;
12072
12171
  }
12073
12172
  registerPartials() {
12074
12173
  const partialsDir = path7.join(this.templatesDir, "partials");
@@ -12623,6 +12722,12 @@ var PdfGenerator = class {
12623
12722
  `Compression: level=${compression.effective} jpeg-q=${compression.quality} max-w=${compression.maxWidth}px inline-failures\u2264${compression.maxInlineFailures}`
12624
12723
  );
12625
12724
  const outputPaths = [];
12725
+ if (options.sections !== void 0) {
12726
+ const hasCustom = sources.some((s) => s.kind !== "builtin");
12727
+ if (hasCustom) {
12728
+ logger.warn('[reportforge] "sections" applies to built-in templates only; it is ignored for custom templatePath templates.');
12729
+ }
12730
+ }
12626
12731
  const { page } = await this.browserManager.launch(options.puppeteerExecutablePath);
12627
12732
  try {
12628
12733
  for (const source of sources) {
@@ -12730,13 +12835,13 @@ var PdfGenerator = class {
12730
12835
  }
12731
12836
  const templateLabel = source.kind === "builtin" ? source.id : source.label;
12732
12837
  logger.info(`Rendering template: ${templateLabel}`);
12733
- const html = source.kind === "builtin" ? this.templateEngine.render(renderData, source.id) : this.templateEngine.renderFromPath(renderData, source.absolutePath);
12838
+ const html = source.kind === "builtin" ? this.templateEngine.render(renderData, source.id, options.sections) : this.templateEngine.renderFromPath(renderData, source.absolutePath);
12734
12839
  const tempHtmlPath = await this.htmlWriter.write(html);
12735
12840
  const fileUrl = this.htmlWriter.toFileUrl(tempHtmlPath);
12736
12841
  try {
12737
12842
  logger.info(`Navigating to temp HTML (${Math.round(html.length / 1024)} KB)...`);
12738
12843
  await page.goto(fileUrl, { waitUntil: "domcontentloaded", timeout: 6e4 });
12739
- const showCharts = source.kind === "builtin" ? source.id !== "minimal" : true;
12844
+ const showCharts = source.kind === "builtin" ? resolveSections(source.id, options.sections).charts : true;
12740
12845
  await this.chartRenderer.waitForCharts(page, showCharts);
12741
12846
  logger.info(`Generating PDF \u2192 ${path12.relative(process.cwd(), outputPath)}`);
12742
12847
  await page.pdf({
@@ -13127,7 +13232,7 @@ var PdfReporter = class {
13127
13232
  this.dataCollector = new DataCollector();
13128
13233
  this.pdfGenerator = new PdfGenerator();
13129
13234
  this.options = parseOptions(rawOptions);
13130
- const version = true ? "0.5.1" : "0.x";
13235
+ const version = true ? "0.6.1" : "0.x";
13131
13236
  logger.info(`@reportforge/playwright-pdf v${version} initialised`);
13132
13237
  this.licenseClient = new LicenseClient({
13133
13238
  licenseKey: this.options.licenseKey,
@@ -2,6 +2,8 @@
2
2
 
3
3
  {{> watermark}}
4
4
 
5
+ {{#if sections.coverPage}}{{> cover-page}}{{/if}}
6
+
5
7
  <div class="report-header">
6
8
  {{#if meta.branding.logoBase64}}
7
9
  <img class="report-header__logo" src="{{meta.branding.logoBase64}}" alt="Logo">
@@ -12,25 +14,27 @@
12
14
  </div>
13
15
  </div>
14
16
 
15
- {{> release-gate}}
17
+ {{#if sections.analysisOneliner}}{{> analysis-oneliner}}{{/if}}
18
+
19
+ {{#if sections.releaseGate}}{{> release-gate}}{{/if}}
16
20
 
17
- {{> executive-summary options=(obj showPassRate=true) }}
21
+ {{#if sections.summary}}{{> executive-summary options=(obj showPassRate=sections.passRate) }}{{/if}}
18
22
 
19
- {{> charts options=(obj showCharts=true showTrend=options.showTrend) }}
23
+ {{#if sections.charts}}{{> charts options=(obj showCharts=true showTrend=sections.trend) }}{{/if}}
20
24
 
21
- {{> requirements-matrix }}
25
+ {{#if sections.requirementsMatrix}}{{> requirements-matrix }}{{/if}}
22
26
 
23
- {{> ci-environment options=(obj showFullEnvironment=true) }}
27
+ {{#if sections.ciEnvironment}}{{> ci-environment options=(obj showFullEnvironment=sections.fullEnvironment) }}{{/if}}
24
28
 
25
- {{> suite-breakdown options=(obj showRetries=true) }}
29
+ {{#if sections.suiteBreakdown}}{{> suite-breakdown options=(obj showRetries=sections.retries) }}{{/if}}
26
30
 
27
- {{> failure-deep-dive options=(obj showFullFailures=true showStackTraces=true) }}
31
+ {{#if sections.failureDeepDive}}{{> failure-deep-dive options=(obj showFullFailures=sections.fullFailures showStackTraces=sections.stackTraces) }}{{/if}}
28
32
 
29
- {{> failure-analysis}}
33
+ {{#if sections.failureAnalysis}}{{> failure-analysis}}{{/if}}
30
34
 
31
- {{> slow-tests limit=10 showProject=true}}
35
+ {{#if sections.slowTests}}{{> slow-tests limit=10 showProject=true}}{{/if}}
32
36
 
33
- {{> defect-log }}
37
+ {{#if sections.defectLog}}{{> defect-log }}{{/if}}
34
38
 
35
39
  <div class="report-footer">
36
40
  <span>Generated by ReportForge</span>