@json-to-office/core-pptx 4.4.1 → 5.4.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.js CHANGED
@@ -3937,6 +3937,12 @@ import {
3937
3937
  REMOTE_EXPORT_WARNING,
3938
3938
  chartFamilyResolver,
3939
3939
  chartPointsPerPixel,
3940
+ chartRequestKey,
3941
+ dedupeChartRequest,
3942
+ limitChartRequest,
3943
+ postJsonToService,
3944
+ recordChartRetry,
3945
+ resolveServiceUrl,
3940
3946
  withChartFontFaceCss,
3941
3947
  withChartTypography
3942
3948
  } from "@json-to-office/shared";
@@ -3956,7 +3962,10 @@ async function expandHighchartsComponents(presentation, services, warnings, char
3956
3962
  slideWidth: presentation.slideWidth,
3957
3963
  services,
3958
3964
  warnings,
3959
- chartFonts
3965
+ chartFonts,
3966
+ // Per deck: a chart repeated on an agenda slide and again in its section
3967
+ // is one render.
3968
+ chartCache: /* @__PURE__ */ new Map()
3960
3969
  };
3961
3970
  const slides = await Promise.all(
3962
3971
  presentation.slides.map(async (slide, index) => ({
@@ -3992,19 +4001,24 @@ async function expandList(components, path4, scope) {
3992
4001
  }
3993
4002
  async function expandOne(component, path4, scope) {
3994
4003
  const props = component.props;
3995
- const chart = await renderChart(
3996
- withChartFontFaces(
3997
- withThemeTypography(
3998
- withThemeColors(props, scope.theme, scope.warnings),
4004
+ const chart = await limitChartRequest(
4005
+ exportServerUrl(props.serverUrl, scope.services?.serverUrl),
4006
+ scope.services?.concurrency,
4007
+ () => renderChart(
4008
+ withChartFontFaces(
4009
+ withThemeTypography(
4010
+ withThemeColors(props, scope.theme, scope.warnings),
4011
+ scope.theme,
4012
+ scope.slideWidth,
4013
+ scope.warnings
4014
+ ),
3999
4015
  scope.theme,
4000
- scope.slideWidth,
4001
- scope.warnings
4016
+ scope.chartFonts
4002
4017
  ),
4003
- scope.theme,
4004
- scope.chartFonts
4005
- ),
4006
- scope.services,
4007
- scope.warnings
4018
+ scope.services,
4019
+ scope.warnings,
4020
+ scope.chartCache
4021
+ )
4008
4022
  );
4009
4023
  void path4;
4010
4024
  return {
@@ -4021,14 +4035,18 @@ async function expandOne(component, path4, scope) {
4021
4035
  }
4022
4036
  function assertExportServerAllowed(serverUrl, services, warnings) {
4023
4037
  const notice = remoteExportNotice(serverUrl, services?.allowRemote);
4024
- if (notice)
4025
- warnings.push({
4026
- code: REMOTE_EXPORT_WARNING,
4027
- component: "highcharts",
4028
- message: notice
4029
- });
4038
+ if (!notice) return;
4039
+ const alreadySaid = warnings.some(
4040
+ (warning) => warning.code === REMOTE_EXPORT_WARNING && warning.message === notice
4041
+ );
4042
+ if (alreadySaid) return;
4043
+ warnings.push({
4044
+ code: REMOTE_EXPORT_WARNING,
4045
+ component: "highcharts",
4046
+ message: notice
4047
+ });
4030
4048
  }
4031
- async function renderChart(config, services, warnings) {
4049
+ async function renderChart(config, services, warnings, cache) {
4032
4050
  if (!isNodeEnvironment()) {
4033
4051
  throw new Error(
4034
4052
  "Highcharts export server requires a Node.js environment. Chart generation is not available in browser environments."
@@ -4045,25 +4063,27 @@ async function renderChart(config, services, warnings) {
4045
4063
  // for callers that omit it.
4046
4064
  ...config.resources ? { resources: config.resources } : {}
4047
4065
  };
4048
- const resolvedHeaders = typeof services?.headers === "function" ? await services.headers(requestBody) : services?.headers;
4049
- const response = await fetch(`${serverUrl}/export`, {
4050
- method: "POST",
4051
- headers: { "Content-Type": "application/json", ...resolvedHeaders },
4052
- body: JSON.stringify(requestBody)
4053
- }).catch((error) => {
4054
- throw Object.assign(
4055
- new Error(
4056
- `Highcharts Export Server is not running at ${serverUrl}. Start it with: npx highcharts-export-server --enableServer true
4057
- Cause: ${error instanceof Error ? error.message : String(error)}`
4058
- ),
4059
- { code: "SERVICE_UNAVAILABLE" }
4060
- );
4066
+ return dedupeChartRequest(
4067
+ cache,
4068
+ chartRequestKey(serverUrl, requestBody),
4069
+ () => postChart(serverUrl, requestBody, config, services)
4070
+ );
4071
+ }
4072
+ async function postChart(serverUrl, requestBody, config, services) {
4073
+ const response = await postJsonToService({
4074
+ url: serverUrl,
4075
+ path: "/export",
4076
+ body: requestBody,
4077
+ headers: services?.headers,
4078
+ timeoutMs: services?.timeoutMs,
4079
+ retries: services?.retries,
4080
+ onRetry: recordChartRetry,
4081
+ serviceLabel: "Highcharts export server",
4082
+ // The code lets a server route report a missing export server as a
4083
+ // dependency outage with this message, not as an internal error.
4084
+ onUnreachable: (url, cause) => `Highcharts Export Server is not running at ${url}. Start it with: npx highcharts-export-server --enableServer true
4085
+ Cause: ${cause}`
4061
4086
  });
4062
- if (!response.ok) {
4063
- throw new Error(
4064
- `Highcharts export server returned ${response.status}: ${response.statusText}`
4065
- );
4066
- }
4067
4087
  return {
4068
4088
  dataUri: `data:image/png;base64,${await response.text()}`,
4069
4089
  widthPx: config.options.chart?.width ?? DEFAULT_CHART_WIDTH_PX,
@@ -4071,8 +4091,7 @@ Cause: ${error instanceof Error ? error.message : String(error)}`
4071
4091
  };
4072
4092
  }
4073
4093
  function exportServerUrl(propsUrl, servicesUrl) {
4074
- const raw = propsUrl || servicesUrl || DEFAULT_EXPORT_SERVER_URL;
4075
- return raw.startsWith("http") ? raw : `http://${raw}`;
4094
+ return resolveServiceUrl(propsUrl, servicesUrl, DEFAULT_EXPORT_SERVER_URL);
4076
4095
  }
4077
4096
  function withThemeColors(props, theme, warnings) {
4078
4097
  if (!props.options || props.options.colors || !theme?.colors) return props;
@@ -4264,100 +4283,637 @@ function isPrivateUrl(urlString) {
4264
4283
  const second = Number.parseInt(hostname.split(".")[1], 10);
4265
4284
  if (second >= 16 && second <= 31) return true;
4266
4285
  }
4267
- return false;
4268
- } catch {
4269
- return true;
4270
- }
4271
- }
4272
- async function probeIntrinsicSize(source, warnings) {
4273
- try {
4274
- if (/^data:image\//.test(source)) {
4275
- const base64Data = source.split(",")[1];
4276
- if (!base64Data) return void 0;
4277
- const result2 = probe.sync(Buffer.from(base64Data, "base64"));
4278
- return result2 ? { width: result2.width, height: result2.height } : void 0;
4286
+ return false;
4287
+ } catch {
4288
+ return true;
4289
+ }
4290
+ }
4291
+ async function probeIntrinsicSize(source, warnings) {
4292
+ try {
4293
+ if (/^data:image\//.test(source)) {
4294
+ const base64Data = source.split(",")[1];
4295
+ if (!base64Data) return void 0;
4296
+ const result2 = probe.sync(Buffer.from(base64Data, "base64"));
4297
+ return result2 ? { width: result2.width, height: result2.height } : void 0;
4298
+ }
4299
+ if (/^https?:\/\//.test(source)) {
4300
+ if (isPrivateUrl(source)) return void 0;
4301
+ const result2 = await probe(source, { timeout: 5e3 });
4302
+ return { width: result2.width, height: result2.height };
4303
+ }
4304
+ const resolved = path3.resolve(resolveFromBaseDir(source));
4305
+ if (!isAllowedLocalPath(resolved)) return void 0;
4306
+ const { createReadStream } = await import("fs");
4307
+ const result = await probe(createReadStream(resolved));
4308
+ return result ? { width: result.width, height: result.height } : void 0;
4309
+ } catch (error) {
4310
+ warn(
4311
+ warnings,
4312
+ W.IMAGE_PROBE_FAILED,
4313
+ `Image probe failed: ${error instanceof Error ? error.message : String(error)}`,
4314
+ { component: "image" }
4315
+ );
4316
+ return void 0;
4317
+ }
4318
+ }
4319
+
4320
+ // src/quality/facts.ts
4321
+ import {
4322
+ chartEncodingFor,
4323
+ collectColorLiterals,
4324
+ collectFontFamilies,
4325
+ collectPlaceholders,
4326
+ hasUnitMarker,
4327
+ normalizeHex,
4328
+ normalizeHighchartsChart,
4329
+ parseNumericCell
4330
+ } from "@json-to-office/quality";
4331
+ import {
4332
+ DEFAULT_PPTX_RENDERER_ID as DEFAULT_PPTX_RENDERER_ID2,
4333
+ SEMANTIC_COLOR_NAMES as SEMANTIC_COLOR_NAMES2
4334
+ } from "@json-to-office/shared-pptx";
4335
+ import { designColors as designColors2 } from "@json-to-office/shared";
4336
+
4337
+ // src/core/generationContext.ts
4338
+ import { applyExportMode } from "@json-to-office/shared";
4339
+
4340
+ // src/themes/consulting.pptx.theme.json
4341
+ var consulting_pptx_theme_default = {
4342
+ name: "consulting",
4343
+ displayName: "Consulting House",
4344
+ description: "The house style for decision decks \u2014 near-black ink, three greys and one deep-blue accent, Calibri body under Arial headings, hairline rules, no fills behind text, safe fonts only",
4345
+ whenToUse: "Decision decks and client readouts: one message per slide, a chart that carries it, a source under it; the twin of the DOCX house theme, so a deck and its report match.",
4346
+ version: "1.0.0",
4347
+ colors: {
4348
+ primary: "#1A1F26",
4349
+ secondary: "#4B5563",
4350
+ accent: "#1B4F8A",
4351
+ background: "#FFFFFF",
4352
+ text: "#1A1F26",
4353
+ text2: "#4B5563",
4354
+ background2: "#F2F4F7",
4355
+ accent4: "#5B8DC9",
4356
+ accent5: "#A9C4E4",
4357
+ accent6: "#7B8794"
4358
+ },
4359
+ palette: {
4360
+ rule: "#C9CED6",
4361
+ textMuted: "#7B8794",
4362
+ onPrimary: "#FFFFFF",
4363
+ surfaceInverse: "#1A1F26",
4364
+ positive: "#1E7F4F",
4365
+ negative: "#B42318",
4366
+ chart: ["accent", "secondary", "accent4", "textMuted", "accent5", "rule"]
4367
+ },
4368
+ fonts: {
4369
+ heading: "Arial",
4370
+ body: "Calibri",
4371
+ mono: "Consolas"
4372
+ },
4373
+ defaults: {
4374
+ fontSize: 14,
4375
+ fontColor: "#1A1F26"
4376
+ },
4377
+ styles: {
4378
+ title: {
4379
+ fontSize: 32,
4380
+ bold: true,
4381
+ fontColor: "text",
4382
+ align: "left"
4383
+ },
4384
+ subtitle: {
4385
+ fontSize: 16,
4386
+ fontColor: "text2",
4387
+ align: "left"
4388
+ },
4389
+ heading1: {
4390
+ fontSize: 24,
4391
+ bold: true,
4392
+ fontColor: "text"
4393
+ },
4394
+ heading2: {
4395
+ fontSize: 18,
4396
+ bold: true,
4397
+ fontColor: "text"
4398
+ },
4399
+ heading3: {
4400
+ fontSize: 14,
4401
+ bold: true,
4402
+ fontColor: "text2"
4403
+ },
4404
+ body: {
4405
+ fontSize: 14,
4406
+ fontColor: "text"
4407
+ },
4408
+ caption: {
4409
+ fontSize: 10,
4410
+ fontColor: "text2"
4411
+ }
4412
+ },
4413
+ typography: {
4414
+ roles: {
4415
+ eyebrow: {
4416
+ face: "heading",
4417
+ size: 10,
4418
+ weight: 700,
4419
+ case: "upper",
4420
+ tracking: 8,
4421
+ color: "accent"
4422
+ },
4423
+ display: {
4424
+ face: "heading",
4425
+ size: 28,
4426
+ weight: 700,
4427
+ color: "primary",
4428
+ lineHeight: 1.1
4429
+ },
4430
+ stat: {
4431
+ face: "heading",
4432
+ size: 40,
4433
+ weight: 700,
4434
+ color: "accent",
4435
+ lineHeight: 1
4436
+ },
4437
+ quote: {
4438
+ face: "body",
4439
+ size: 18,
4440
+ color: "text2",
4441
+ lineHeight: 1.3
4442
+ },
4443
+ label: {
4444
+ face: "body",
4445
+ size: 12,
4446
+ weight: 700,
4447
+ color: "text2"
4448
+ },
4449
+ footer: {
4450
+ face: "body",
4451
+ size: 9,
4452
+ color: "text2"
4453
+ },
4454
+ tableHeader: {
4455
+ face: "body",
4456
+ size: 12,
4457
+ weight: 700,
4458
+ color: "primary"
4459
+ },
4460
+ tableCell: {
4461
+ face: "body",
4462
+ size: 12,
4463
+ color: "text"
4464
+ },
4465
+ chartLabel: {
4466
+ face: "body",
4467
+ size: 11,
4468
+ weight: 400,
4469
+ color: "text2"
4470
+ },
4471
+ tracker: {
4472
+ face: "body",
4473
+ size: 10,
4474
+ case: "upper",
4475
+ tracking: 6,
4476
+ color: "text2"
4477
+ },
4478
+ source: {
4479
+ face: "body",
4480
+ size: 9,
4481
+ color: "text2"
4482
+ }
4483
+ },
4484
+ scale: {
4485
+ wide169: {
4486
+ base: 14,
4487
+ ratio: 1.2,
4488
+ baselinePt: 2
4489
+ },
4490
+ standard43: {
4491
+ base: 14,
4492
+ ratio: 1.2,
4493
+ baselinePt: 2
4494
+ }
4495
+ }
4496
+ },
4497
+ spacing: {
4498
+ basePt: 8,
4499
+ blockGap: {
4500
+ tight: 4,
4501
+ normal: 8,
4502
+ loose: 16
4503
+ },
4504
+ canvas: {
4505
+ wide169: {
4506
+ safeAreaIn: 0.5,
4507
+ gutterIn: 0.2,
4508
+ columns: 12,
4509
+ rows: 8
4510
+ },
4511
+ standard43: {
4512
+ safeAreaIn: 0.5,
4513
+ gutterIn: 0.2,
4514
+ columns: 12,
4515
+ rows: 8
4516
+ }
4517
+ }
4518
+ },
4519
+ chrome: {
4520
+ runningHead: {
4521
+ type: "tracker",
4522
+ color: "text2",
4523
+ rule: {
4524
+ weightPt: 0.5,
4525
+ color: "rule"
4526
+ },
4527
+ alignment: "right"
4528
+ },
4529
+ tracker: {
4530
+ type: "tracker",
4531
+ color: "text2",
4532
+ alignment: "right"
4533
+ },
4534
+ actionTitle: {
4535
+ type: "display",
4536
+ color: "primary"
4537
+ },
4538
+ keyTakeaways: {
4539
+ type: "label",
4540
+ color: "primary",
4541
+ rule: {
4542
+ weightPt: 2,
4543
+ color: "accent"
4544
+ },
4545
+ padPt: 8
4546
+ },
4547
+ sourceLine: {
4548
+ type: "source",
4549
+ color: "text2"
4550
+ },
4551
+ confidentialFooter: {
4552
+ type: "footer",
4553
+ color: "text2",
4554
+ rule: {
4555
+ weightPt: 0.5,
4556
+ color: "rule"
4557
+ },
4558
+ alignment: "left"
4559
+ },
4560
+ logoSlot: {
4561
+ alignment: "right"
4562
+ },
4563
+ cover: {
4564
+ type: "display",
4565
+ color: "primary",
4566
+ rule: {
4567
+ weightPt: 3,
4568
+ color: "accent"
4569
+ }
4570
+ }
4571
+ },
4572
+ motif: {
4573
+ kind: "rule",
4574
+ color: "accent",
4575
+ weightPt: 3,
4576
+ placement: "top"
4577
+ },
4578
+ componentDefaults: {
4579
+ table: {
4580
+ border: {
4581
+ type: "solid",
4582
+ pt: 0.5,
4583
+ color: "#C9CED6"
4584
+ },
4585
+ headerRow: true,
4586
+ fontSize: 12
4587
+ },
4588
+ chart: {
4589
+ showLegend: true,
4590
+ legendPos: "b",
4591
+ legendFontSize: 11,
4592
+ catAxisLabelFontSize: 11,
4593
+ valAxisLabelFontSize: 11,
4594
+ catGridLine: {
4595
+ style: "none"
4596
+ },
4597
+ valGridLine: {
4598
+ style: "solid",
4599
+ size: 0.5,
4600
+ color: "#E4E7EB"
4601
+ },
4602
+ valAxisLineShow: false
4603
+ }
4604
+ }
4605
+ };
4606
+
4607
+ // src/themes/consulting.ts
4608
+ var CONSULTING_PPTX_THEME = consulting_pptx_theme_default;
4609
+
4610
+ // src/themes/vermilion.pptx.theme.json
4611
+ var vermilion_pptx_theme_default = {
4612
+ name: "vermilion",
4613
+ displayName: "Vermilion Editorial",
4614
+ description: "Poster-red editorial deck \u2014 vermilion display titles, ink text, warm creams and hairline rules; the twin of the DOCX vermilion theme",
4615
+ whenToUse: "Talks and readouts that want a strong red display voice beside a vermilion report: a few large titles, one figure per slide. Not for a dense data deck.",
4616
+ version: "1.0.0",
4617
+ colors: {
4618
+ primary: "#282829",
4619
+ secondary: "#58595B",
4620
+ accent: "#EF4130",
4621
+ background: "#FFFFFF",
4622
+ text: "#282829",
4623
+ text2: "#58595B",
4624
+ background2: "#FAF7F5",
4625
+ accent4: "#F4857A",
4626
+ accent5: "#F9C4BE",
4627
+ accent6: "#939598"
4628
+ },
4629
+ palette: {
4630
+ rule: "#C7C8CA",
4631
+ textMuted: "#939598",
4632
+ onPrimary: "#FFFFFF",
4633
+ surfaceInverse: "#282829",
4634
+ positive: "#2E7D4F",
4635
+ negative: "#B42318",
4636
+ chart: ["accent", "primary", "textMuted", "accent4", "rule", "accent5"]
4637
+ },
4638
+ fonts: {
4639
+ heading: "Arial",
4640
+ body: "Calibri",
4641
+ mono: "Courier New"
4642
+ },
4643
+ defaults: {
4644
+ fontSize: 14,
4645
+ fontColor: "#282829"
4646
+ },
4647
+ styles: {
4648
+ title: {
4649
+ fontSize: 32,
4650
+ bold: true,
4651
+ fontColor: "accent",
4652
+ align: "left"
4653
+ },
4654
+ subtitle: {
4655
+ fontSize: 16,
4656
+ fontColor: "text2",
4657
+ align: "left"
4658
+ },
4659
+ heading1: {
4660
+ fontSize: 24,
4661
+ bold: true,
4662
+ fontColor: "accent"
4663
+ },
4664
+ heading2: {
4665
+ fontSize: 18,
4666
+ bold: true,
4667
+ fontColor: "text"
4668
+ },
4669
+ heading3: {
4670
+ fontSize: 14,
4671
+ bold: true,
4672
+ fontColor: "text2"
4673
+ },
4674
+ body: {
4675
+ fontSize: 14,
4676
+ fontColor: "text"
4677
+ },
4678
+ caption: {
4679
+ fontSize: 10,
4680
+ fontColor: "text2"
4681
+ }
4682
+ },
4683
+ typography: {
4684
+ roles: {
4685
+ eyebrow: {
4686
+ face: "heading",
4687
+ size: 10,
4688
+ weight: 700,
4689
+ case: "upper",
4690
+ tracking: 8,
4691
+ color: "accent"
4692
+ },
4693
+ display: {
4694
+ face: "heading",
4695
+ size: 28,
4696
+ weight: 700,
4697
+ color: "accent",
4698
+ lineHeight: 1.1
4699
+ },
4700
+ stat: {
4701
+ face: "heading",
4702
+ size: 40,
4703
+ weight: 700,
4704
+ color: "accent",
4705
+ lineHeight: 1
4706
+ },
4707
+ quote: {
4708
+ face: "body",
4709
+ size: 18,
4710
+ color: "text2",
4711
+ lineHeight: 1.3
4712
+ },
4713
+ label: {
4714
+ face: "body",
4715
+ size: 12,
4716
+ weight: 700,
4717
+ color: "text2"
4718
+ },
4719
+ footer: {
4720
+ face: "body",
4721
+ size: 9,
4722
+ color: "text2"
4723
+ },
4724
+ tableHeader: {
4725
+ face: "body",
4726
+ size: 12,
4727
+ weight: 700,
4728
+ color: "accent"
4729
+ },
4730
+ tableCell: {
4731
+ face: "body",
4732
+ size: 12,
4733
+ color: "text"
4734
+ },
4735
+ chartLabel: {
4736
+ face: "body",
4737
+ size: 11,
4738
+ weight: 400,
4739
+ color: "text2"
4740
+ },
4741
+ tracker: {
4742
+ face: "body",
4743
+ size: 10,
4744
+ case: "upper",
4745
+ tracking: 6,
4746
+ color: "text2"
4747
+ },
4748
+ source: {
4749
+ face: "body",
4750
+ size: 9,
4751
+ color: "text2"
4752
+ }
4753
+ },
4754
+ scale: {
4755
+ wide169: {
4756
+ base: 14,
4757
+ ratio: 1.2,
4758
+ baselinePt: 2
4759
+ },
4760
+ standard43: {
4761
+ base: 14,
4762
+ ratio: 1.2,
4763
+ baselinePt: 2
4764
+ }
4765
+ }
4766
+ },
4767
+ spacing: {
4768
+ basePt: 8,
4769
+ blockGap: {
4770
+ tight: 4,
4771
+ normal: 8,
4772
+ loose: 16
4773
+ },
4774
+ canvas: {
4775
+ wide169: {
4776
+ safeAreaIn: 0.5,
4777
+ gutterIn: 0.2,
4778
+ columns: 12,
4779
+ rows: 8
4780
+ },
4781
+ standard43: {
4782
+ safeAreaIn: 0.5,
4783
+ gutterIn: 0.2,
4784
+ columns: 12,
4785
+ rows: 8
4786
+ }
4787
+ }
4788
+ },
4789
+ chrome: {
4790
+ runningHead: {
4791
+ type: "tracker",
4792
+ color: "text2",
4793
+ rule: {
4794
+ weightPt: 0.5,
4795
+ color: "rule"
4796
+ },
4797
+ alignment: "right"
4798
+ },
4799
+ tracker: {
4800
+ type: "tracker",
4801
+ color: "text2",
4802
+ alignment: "right"
4803
+ },
4804
+ actionTitle: {
4805
+ type: "display",
4806
+ color: "primary"
4807
+ },
4808
+ keyTakeaways: {
4809
+ type: "label",
4810
+ color: "primary",
4811
+ rule: {
4812
+ weightPt: 1.5,
4813
+ color: "accent"
4814
+ },
4815
+ padPt: 8
4816
+ },
4817
+ sourceLine: {
4818
+ type: "source",
4819
+ color: "text2"
4820
+ },
4821
+ confidentialFooter: {
4822
+ type: "footer",
4823
+ color: "text2",
4824
+ rule: {
4825
+ weightPt: 0.5,
4826
+ color: "rule"
4827
+ },
4828
+ alignment: "left"
4829
+ },
4830
+ logoSlot: {
4831
+ alignment: "right"
4832
+ },
4833
+ cover: {
4834
+ type: "display",
4835
+ color: "primary",
4836
+ rule: {
4837
+ weightPt: 4,
4838
+ color: "accent"
4839
+ }
4279
4840
  }
4280
- if (/^https?:\/\//.test(source)) {
4281
- if (isPrivateUrl(source)) return void 0;
4282
- const result2 = await probe(source, { timeout: 5e3 });
4283
- return { width: result2.width, height: result2.height };
4841
+ },
4842
+ motif: {
4843
+ kind: "rule",
4844
+ color: "accent",
4845
+ weightPt: 4,
4846
+ placement: "top"
4847
+ },
4848
+ componentDefaults: {
4849
+ table: {
4850
+ border: {
4851
+ type: "solid",
4852
+ pt: 0.5,
4853
+ color: "#C7C8CA"
4854
+ },
4855
+ headerRow: true,
4856
+ fontSize: 12
4857
+ },
4858
+ chart: {
4859
+ showLegend: true,
4860
+ legendPos: "b",
4861
+ legendFontSize: 11,
4862
+ catAxisLabelFontSize: 11,
4863
+ valAxisLabelFontSize: 11,
4864
+ catGridLine: {
4865
+ style: "none"
4866
+ },
4867
+ valGridLine: {
4868
+ style: "solid",
4869
+ size: 0.5,
4870
+ color: "#EFEAE4"
4871
+ },
4872
+ valAxisLineShow: false
4284
4873
  }
4285
- const resolved = path3.resolve(resolveFromBaseDir(source));
4286
- if (!isAllowedLocalPath(resolved)) return void 0;
4287
- const { createReadStream } = await import("fs");
4288
- const result = await probe(createReadStream(resolved));
4289
- return result ? { width: result.width, height: result.height } : void 0;
4290
- } catch (error) {
4291
- warn(
4292
- warnings,
4293
- W.IMAGE_PROBE_FAILED,
4294
- `Image probe failed: ${error instanceof Error ? error.message : String(error)}`,
4295
- { component: "image" }
4296
- );
4297
- return void 0;
4298
4874
  }
4299
- }
4300
-
4301
- // src/quality/facts.ts
4302
- import {
4303
- chartEncodingFor,
4304
- collectColorLiterals,
4305
- collectFontFamilies,
4306
- collectPlaceholders,
4307
- hasUnitMarker,
4308
- normalizeHex,
4309
- normalizeHighchartsChart,
4310
- parseNumericCell
4311
- } from "@json-to-office/quality";
4312
- import {
4313
- DEFAULT_PPTX_RENDERER_ID as DEFAULT_PPTX_RENDERER_ID2,
4314
- SEMANTIC_COLOR_NAMES as SEMANTIC_COLOR_NAMES2
4315
- } from "@json-to-office/shared-pptx";
4316
- import { designColors as designColors2 } from "@json-to-office/shared";
4317
-
4318
- // src/core/generationContext.ts
4319
- import { applyExportMode } from "@json-to-office/shared";
4875
+ };
4320
4876
 
4321
- // src/themes/consulting.pptx.theme.json
4322
- var consulting_pptx_theme_default = {
4323
- name: "consulting",
4324
- displayName: "Consulting House",
4325
- description: "The house style for decision decks \u2014 near-black ink, three greys and one deep-blue accent, Calibri body under Arial headings, hairline rules, no fills behind text, safe fonts only",
4326
- whenToUse: "Decision decks and client readouts: one message per slide, a chart that carries it, a source under it; the twin of the DOCX house theme, so a deck and its report match.",
4877
+ // src/themes/devportal.pptx.theme.json
4878
+ var devportal_pptx_theme_default = {
4879
+ name: "devportal",
4880
+ displayName: "Field Editorial",
4881
+ description: "Compact editorial deck \u2014 Helvetica in near-black ink with a burnt-orange accent, tight titles, letterspaced labels, warm tinted fills and hairline rules; the twin of the DOCX devportal theme",
4882
+ whenToUse: "Product and engineering readouts, API and platform reviews: dense text, code and tables beside a devportal report. Not for a client's decision deck.",
4327
4883
  version: "1.0.0",
4328
4884
  colors: {
4329
- primary: "#1A1F26",
4330
- secondary: "#4B5563",
4331
- accent: "#1B4F8A",
4885
+ primary: "#12191F",
4886
+ secondary: "#172028",
4887
+ accent: "#E35B3F",
4332
4888
  background: "#FFFFFF",
4333
- text: "#1A1F26",
4334
- text2: "#4B5563",
4335
- background2: "#F2F4F7",
4336
- accent4: "#5B8DC9",
4337
- accent5: "#A9C4E4",
4338
- accent6: "#7B8794"
4889
+ text: "#232323",
4890
+ text2: "#46494C",
4891
+ background2: "#F7ECE7",
4892
+ accent4: "#46494C",
4893
+ accent5: "#8A9299",
4894
+ accent6: "#E8A18D"
4339
4895
  },
4340
4896
  palette: {
4341
- rule: "#C9CED6",
4342
- textMuted: "#7B8794",
4897
+ rule: "#D8D5D1",
4898
+ textMuted: "#737373",
4343
4899
  onPrimary: "#FFFFFF",
4344
- surfaceInverse: "#1A1F26",
4345
- positive: "#1E7F4F",
4900
+ surfaceInverse: "#12191F",
4901
+ positive: "#2E7D4F",
4346
4902
  negative: "#B42318",
4347
- chart: ["accent", "secondary", "accent4", "textMuted", "accent5", "rule"]
4903
+ chart: ["accent", "primary", "accent4", "accent5", "accent6", "rule"]
4348
4904
  },
4349
4905
  fonts: {
4350
- heading: "Arial",
4351
- body: "Calibri",
4352
- mono: "Consolas"
4906
+ heading: "Helvetica",
4907
+ body: "Helvetica",
4908
+ mono: "Courier New"
4353
4909
  },
4354
4910
  defaults: {
4355
4911
  fontSize: 14,
4356
- fontColor: "#1A1F26"
4912
+ fontColor: "#232323"
4357
4913
  },
4358
4914
  styles: {
4359
4915
  title: {
4360
- fontSize: 32,
4916
+ fontSize: 30,
4361
4917
  bold: true,
4362
4918
  fontColor: "text",
4363
4919
  align: "left"
@@ -4370,12 +4926,12 @@ var consulting_pptx_theme_default = {
4370
4926
  heading1: {
4371
4927
  fontSize: 24,
4372
4928
  bold: true,
4373
- fontColor: "text"
4929
+ fontColor: "primary"
4374
4930
  },
4375
4931
  heading2: {
4376
4932
  fontSize: 18,
4377
4933
  bold: true,
4378
- fontColor: "text"
4934
+ fontColor: "secondary"
4379
4935
  },
4380
4936
  heading3: {
4381
4937
  fontSize: 14,
@@ -4398,7 +4954,7 @@ var consulting_pptx_theme_default = {
4398
4954
  size: 10,
4399
4955
  weight: 700,
4400
4956
  case: "upper",
4401
- tracking: 8,
4957
+ tracking: 10,
4402
4958
  color: "accent"
4403
4959
  },
4404
4960
  display: {
@@ -4406,7 +4962,8 @@ var consulting_pptx_theme_default = {
4406
4962
  size: 28,
4407
4963
  weight: 700,
4408
4964
  color: "primary",
4409
- lineHeight: 1.1
4965
+ lineHeight: 1.1,
4966
+ tracking: -2
4410
4967
  },
4411
4968
  stat: {
4412
4969
  face: "heading",
@@ -4425,7 +4982,9 @@ var consulting_pptx_theme_default = {
4425
4982
  face: "body",
4426
4983
  size: 12,
4427
4984
  weight: 700,
4428
- color: "text2"
4985
+ color: "text2",
4986
+ case: "upper",
4987
+ tracking: 6
4429
4988
  },
4430
4989
  footer: {
4431
4990
  face: "body",
@@ -4436,7 +4995,7 @@ var consulting_pptx_theme_default = {
4436
4995
  face: "body",
4437
4996
  size: 12,
4438
4997
  weight: 700,
4439
- color: "primary"
4998
+ color: "secondary"
4440
4999
  },
4441
5000
  tableCell: {
4442
5001
  face: "body",
@@ -4520,7 +5079,7 @@ var consulting_pptx_theme_default = {
4520
5079
  type: "label",
4521
5080
  color: "primary",
4522
5081
  rule: {
4523
- weightPt: 2,
5082
+ weightPt: 1,
4524
5083
  color: "accent"
4525
5084
  },
4526
5085
  padPt: 8
@@ -4553,7 +5112,7 @@ var consulting_pptx_theme_default = {
4553
5112
  motif: {
4554
5113
  kind: "rule",
4555
5114
  color: "accent",
4556
- weightPt: 3,
5115
+ weightPt: 2,
4557
5116
  placement: "top"
4558
5117
  },
4559
5118
  componentDefaults: {
@@ -4561,7 +5120,7 @@ var consulting_pptx_theme_default = {
4561
5120
  border: {
4562
5121
  type: "solid",
4563
5122
  pt: 0.5,
4564
- color: "#C9CED6"
5123
+ color: "#D8D5D1"
4565
5124
  },
4566
5125
  headerRow: true,
4567
5126
  fontSize: 12
@@ -4578,15 +5137,16 @@ var consulting_pptx_theme_default = {
4578
5137
  valGridLine: {
4579
5138
  style: "solid",
4580
5139
  size: 0.5,
4581
- color: "#E4E7EB"
5140
+ color: "#F2F3F3"
4582
5141
  },
4583
5142
  valAxisLineShow: false
4584
5143
  }
4585
5144
  }
4586
5145
  };
4587
5146
 
4588
- // src/themes/consulting.ts
4589
- var CONSULTING_PPTX_THEME = consulting_pptx_theme_default;
5147
+ // src/themes/alternates.ts
5148
+ var VERMILION_PPTX_THEME = vermilion_pptx_theme_default;
5149
+ var DEVPORTAL_PPTX_THEME = devportal_pptx_theme_default;
4590
5150
 
4591
5151
  // src/themes/defaults.ts
4592
5152
  var DEFAULT_TABLE = {
@@ -4633,6 +5193,8 @@ var DEFAULT_PPTX_THEME = {
4633
5193
  var PPTX_THEMES = {
4634
5194
  default: DEFAULT_PPTX_THEME,
4635
5195
  consulting: CONSULTING_PPTX_THEME,
5196
+ vermilion: VERMILION_PPTX_THEME,
5197
+ devportal: DEVPORTAL_PPTX_THEME,
4636
5198
  dark: {
4637
5199
  name: "dark",
4638
5200
  displayName: "Dark",
@@ -6258,8 +6820,8 @@ async function generateAndSaveFromJson(jsonConfig, outputPath, options) {
6258
6820
  writeFileSync(outputPath, buffer);
6259
6821
  }
6260
6822
  async function generateFromFile(filePath, outputPath, options) {
6261
- const { readFileSync } = await import("fs");
6262
- const json = readFileSync(filePath, "utf-8");
6823
+ const { readFileSync: readFileSync2 } = await import("fs");
6824
+ const json = readFileSync2(filePath, "utf-8");
6263
6825
  await generateAndSaveFromJson(json, outputPath, options);
6264
6826
  }
6265
6827
  var PresentationGenerator = {
@@ -6273,6 +6835,620 @@ var PresentationGenerator = {
6273
6835
  // src/index.ts
6274
6836
  init_finalizePackage();
6275
6837
  init_warn();
6838
+ import {
6839
+ getChartRequestStats,
6840
+ resetChartRequestStats
6841
+ } from "@json-to-office/shared";
6842
+
6843
+ // src/blueprints/index.ts
6844
+ import { existsSync, readdirSync, readFileSync } from "fs";
6845
+ import { fileURLToPath } from "url";
6846
+ import { dirname, join } from "path";
6847
+ import {
6848
+ instantiateBlueprint,
6849
+ registerBlueprints
6850
+ } from "@json-to-office/shared";
6851
+ import { collectPlaceholders as collectPlaceholders2 } from "@json-to-office/quality";
6852
+
6853
+ // src/templates/blueprints/consulting-deck.pptx.blueprint.json
6854
+ var consulting_deck_pptx_blueprint_default = {
6855
+ id: "consulting-deck",
6856
+ format: "pptx",
6857
+ title: "Consulting deck",
6858
+ description: "A decision deck for a client readout: a cover, the quarter in numbers, one action-chart per finding with its takeaway and source, a two-column slide for the evidence that is a table or a list, a closing statement; every slide invokes one of the five consulting blocks on the house theme.",
6859
+ whenToUse: "A client readout, a board update or a steering-committee deck: one message per slide, a chart or table that carries it, a source under it. Not for a talk track or a training deck.",
6860
+ theme: "consulting",
6861
+ profile: "consulting-deck",
6862
+ definitions: "consulting-deck-blocks.pptx.json",
6863
+ numbering: "none",
6864
+ toc: false,
6865
+ variants: {
6866
+ "data-heavy": {
6867
+ description: "Evidence-led: cover, a KPI row, three action-charts, a two-column table slide, a closing statement.",
6868
+ whenToUse: "The brief comes with numbers the audience will check: performance, finance, operations.",
6869
+ pages: {
6870
+ min: 6,
6871
+ max: 9
6872
+ },
6873
+ metadata: {
6874
+ title: "{{Title: as on the cover}}",
6875
+ author: "{{Author or team}}",
6876
+ company: "{{Client name}}"
6877
+ },
6878
+ children: [
6879
+ {
6880
+ name: "slide",
6881
+ children: [
6882
+ {
6883
+ name: "block",
6884
+ props: {
6885
+ ref: "cover",
6886
+ slots: {
6887
+ title: "{{Title: the deck's conclusion in one sentence}}",
6888
+ subtitle: "{{Subtitle: what the deck answers, for whom}}",
6889
+ client: "{{Client name}}",
6890
+ date: "{{Month YYYY}}",
6891
+ confidentiality: "{{Confidentiality: Confidential, or For internal use}}"
6892
+ }
6893
+ }
6894
+ }
6895
+ ]
6896
+ },
6897
+ {
6898
+ name: "slide",
6899
+ children: [
6900
+ {
6901
+ name: "block",
6902
+ props: {
6903
+ ref: "kpi-row",
6904
+ slots: {
6905
+ title: "{{Action title: the claim this slide proves, with its number, two lines at most}}",
6906
+ tracker: "{{Tracker: the section, one or two words}}",
6907
+ items: [
6908
+ {
6909
+ value: "{{0.0}}",
6910
+ unit: "{{unit}}",
6911
+ label: "{{What it measures}}",
6912
+ delta: "{{+0.0}}"
6913
+ },
6914
+ {
6915
+ value: "{{0.0}}",
6916
+ unit: "{{unit}}",
6917
+ label: "{{What it measures}}",
6918
+ delta: "{{+0.0}}"
6919
+ },
6920
+ {
6921
+ value: "{{0.0}}",
6922
+ unit: "{{unit}}",
6923
+ label: "{{What it measures}}",
6924
+ delta: "{{+0.0}}"
6925
+ }
6926
+ ],
6927
+ source: "{{Source: system or document, date}}"
6928
+ }
6929
+ }
6930
+ }
6931
+ ]
6932
+ },
6933
+ {
6934
+ name: "slide",
6935
+ children: [
6936
+ {
6937
+ name: "block",
6938
+ props: {
6939
+ ref: "action-chart",
6940
+ slots: {
6941
+ title: "{{Action title: the claim this slide proves, with its number, two lines at most}}",
6942
+ tracker: "{{Tracker: the section, one or two words}}",
6943
+ chart: {
6944
+ name: "chart",
6945
+ props: {
6946
+ type: "bar",
6947
+ valAxisTitle: "{{Measure (unit)}}",
6948
+ data: [
6949
+ {
6950
+ name: "{{Series name}}",
6951
+ labels: [
6952
+ "{{Period 1}}",
6953
+ "{{Period 2}}",
6954
+ "{{Period 3}}"
6955
+ ],
6956
+ values: [0, 0, 0]
6957
+ }
6958
+ ],
6959
+ chartColors: [
6960
+ "accent",
6961
+ "secondary",
6962
+ "accent4",
6963
+ "accent6",
6964
+ "accent5"
6965
+ ]
6966
+ }
6967
+ },
6968
+ takeaway: "{{Takeaway: what the reader should conclude, one or two sentences}}",
6969
+ source: "{{Source: system or document, date}}"
6970
+ }
6971
+ }
6972
+ }
6973
+ ]
6974
+ },
6975
+ {
6976
+ name: "slide",
6977
+ children: [
6978
+ {
6979
+ name: "block",
6980
+ props: {
6981
+ ref: "action-chart",
6982
+ slots: {
6983
+ title: "{{Action title: the claim this slide proves, with its number, two lines at most}}",
6984
+ tracker: "{{Tracker: the section, one or two words}}",
6985
+ chart: {
6986
+ name: "chart",
6987
+ props: {
6988
+ type: "bar",
6989
+ valAxisTitle: "{{Measure (unit)}}",
6990
+ data: [
6991
+ {
6992
+ name: "{{Series name}}",
6993
+ labels: [
6994
+ "{{Period 1}}",
6995
+ "{{Period 2}}",
6996
+ "{{Period 3}}"
6997
+ ],
6998
+ values: [0, 0, 0]
6999
+ }
7000
+ ],
7001
+ chartColors: [
7002
+ "accent",
7003
+ "secondary",
7004
+ "accent4",
7005
+ "accent6",
7006
+ "accent5"
7007
+ ]
7008
+ }
7009
+ },
7010
+ takeaway: "{{Takeaway: what the reader should conclude, one or two sentences}}",
7011
+ source: "{{Source: system or document, date}}"
7012
+ }
7013
+ }
7014
+ }
7015
+ ]
7016
+ },
7017
+ {
7018
+ name: "slide",
7019
+ children: [
7020
+ {
7021
+ name: "block",
7022
+ props: {
7023
+ ref: "action-chart",
7024
+ slots: {
7025
+ title: "{{Action title: the claim this slide proves, with its number, two lines at most}}",
7026
+ tracker: "{{Tracker: the section, one or two words}}",
7027
+ chart: {
7028
+ name: "chart",
7029
+ props: {
7030
+ type: "bar",
7031
+ valAxisTitle: "{{Measure (unit)}}",
7032
+ data: [
7033
+ {
7034
+ name: "{{Series name}}",
7035
+ labels: [
7036
+ "{{Period 1}}",
7037
+ "{{Period 2}}",
7038
+ "{{Period 3}}"
7039
+ ],
7040
+ values: [0, 0, 0]
7041
+ }
7042
+ ],
7043
+ chartColors: [
7044
+ "accent",
7045
+ "secondary",
7046
+ "accent4",
7047
+ "accent6",
7048
+ "accent5"
7049
+ ]
7050
+ }
7051
+ },
7052
+ takeaway: "{{Takeaway: what the reader should conclude, one or two sentences}}",
7053
+ source: "{{Source: system or document, date}}"
7054
+ }
7055
+ }
7056
+ }
7057
+ ]
7058
+ },
7059
+ {
7060
+ name: "slide",
7061
+ children: [
7062
+ {
7063
+ name: "block",
7064
+ props: {
7065
+ ref: "two-column",
7066
+ slots: {
7067
+ title: "{{Action title: the claim this slide proves, with its number, two lines at most}}",
7068
+ tracker: "{{Tracker: the section, one or two words}}",
7069
+ bullets: [
7070
+ "{{Bullet 1: one claim, ten words}}",
7071
+ "{{Bullet 2: one claim, ten words}}",
7072
+ "{{Bullet 3: one claim, ten words}}"
7073
+ ],
7074
+ content: {
7075
+ name: "table",
7076
+ props: {
7077
+ rows: [
7078
+ [
7079
+ "{{Row label}}",
7080
+ {
7081
+ text: "{{Column (unit)}}",
7082
+ align: "right"
7083
+ },
7084
+ {
7085
+ text: "{{Column (unit)}}",
7086
+ align: "right"
7087
+ }
7088
+ ],
7089
+ [
7090
+ "{{Row 1}}",
7091
+ {
7092
+ text: "{{0.0}}",
7093
+ align: "right"
7094
+ },
7095
+ {
7096
+ text: "{{0.0}}",
7097
+ align: "right"
7098
+ }
7099
+ ],
7100
+ [
7101
+ "{{Row 2}}",
7102
+ {
7103
+ text: "{{0.0}}",
7104
+ align: "right"
7105
+ },
7106
+ {
7107
+ text: "{{0.0}}",
7108
+ align: "right"
7109
+ }
7110
+ ],
7111
+ [
7112
+ "{{Row 3}}",
7113
+ {
7114
+ text: "{{0.0}}",
7115
+ align: "right"
7116
+ },
7117
+ {
7118
+ text: "{{0.0}}",
7119
+ align: "right"
7120
+ }
7121
+ ]
7122
+ ]
7123
+ }
7124
+ },
7125
+ source: "{{Source: system or document, date}}"
7126
+ }
7127
+ }
7128
+ }
7129
+ ]
7130
+ },
7131
+ {
7132
+ name: "slide",
7133
+ children: [
7134
+ {
7135
+ name: "block",
7136
+ props: {
7137
+ ref: "statement",
7138
+ slots: {
7139
+ tracker: "{{Tracker: the section, one or two words}}",
7140
+ assertion: "{{Assertion: what to do next, in one sentence}}",
7141
+ support: "{{Support: what backs the assertion, under thirty words}}"
7142
+ }
7143
+ }
7144
+ }
7145
+ ]
7146
+ }
7147
+ ]
7148
+ },
7149
+ narrative: {
7150
+ description: "Argument-led: cover, the position as a statement, two two-column slides that argue it beside a chart, one action-chart, a two-column table, a closing statement.",
7151
+ whenToUse: "The brief is a position or a recommendation with few numbers; the audience follows an argument.",
7152
+ pages: {
7153
+ min: 6,
7154
+ max: 8
7155
+ },
7156
+ metadata: {
7157
+ title: "{{Title: as on the cover}}",
7158
+ author: "{{Author or team}}",
7159
+ company: "{{Client name}}"
7160
+ },
7161
+ children: [
7162
+ {
7163
+ name: "slide",
7164
+ children: [
7165
+ {
7166
+ name: "block",
7167
+ props: {
7168
+ ref: "cover",
7169
+ slots: {
7170
+ title: "{{Title: the deck's conclusion in one sentence}}",
7171
+ subtitle: "{{Subtitle: what the deck answers, for whom}}",
7172
+ client: "{{Client name}}",
7173
+ date: "{{Month YYYY}}",
7174
+ confidentiality: "{{Confidentiality: Confidential, or For internal use}}"
7175
+ }
7176
+ }
7177
+ }
7178
+ ]
7179
+ },
7180
+ {
7181
+ name: "slide",
7182
+ children: [
7183
+ {
7184
+ name: "block",
7185
+ props: {
7186
+ ref: "statement",
7187
+ slots: {
7188
+ tracker: "{{Tracker: the section, one or two words}}",
7189
+ assertion: "{{Assertion: the position, in one sentence}}",
7190
+ support: "{{Support: what backs the assertion, under thirty words}}"
7191
+ }
7192
+ }
7193
+ }
7194
+ ]
7195
+ },
7196
+ {
7197
+ name: "slide",
7198
+ children: [
7199
+ {
7200
+ name: "block",
7201
+ props: {
7202
+ ref: "two-column",
7203
+ slots: {
7204
+ title: "{{Action title: the claim this slide proves, with its number, two lines at most}}",
7205
+ tracker: "{{Tracker: the section, one or two words}}",
7206
+ text: "{{Body: the argument this slide makes, under fifty words}}",
7207
+ content: {
7208
+ name: "chart",
7209
+ props: {
7210
+ type: "bar",
7211
+ valAxisTitle: "{{Measure (unit)}}",
7212
+ data: [
7213
+ {
7214
+ name: "{{Series name}}",
7215
+ labels: [
7216
+ "{{Period 1}}",
7217
+ "{{Period 2}}",
7218
+ "{{Period 3}}"
7219
+ ],
7220
+ values: [0, 0, 0]
7221
+ }
7222
+ ],
7223
+ chartColors: [
7224
+ "accent",
7225
+ "secondary",
7226
+ "accent4",
7227
+ "accent6",
7228
+ "accent5"
7229
+ ]
7230
+ }
7231
+ },
7232
+ source: "{{Source: system or document, date}}"
7233
+ }
7234
+ }
7235
+ }
7236
+ ]
7237
+ },
7238
+ {
7239
+ name: "slide",
7240
+ children: [
7241
+ {
7242
+ name: "block",
7243
+ props: {
7244
+ ref: "two-column",
7245
+ slots: {
7246
+ title: "{{Action title: the claim this slide proves, with its number, two lines at most}}",
7247
+ tracker: "{{Tracker: the section, one or two words}}",
7248
+ text: "{{Body: the argument this slide makes, under fifty words}}",
7249
+ content: {
7250
+ name: "chart",
7251
+ props: {
7252
+ type: "bar",
7253
+ valAxisTitle: "{{Measure (unit)}}",
7254
+ data: [
7255
+ {
7256
+ name: "{{Series name}}",
7257
+ labels: [
7258
+ "{{Period 1}}",
7259
+ "{{Period 2}}",
7260
+ "{{Period 3}}"
7261
+ ],
7262
+ values: [0, 0, 0]
7263
+ }
7264
+ ],
7265
+ chartColors: [
7266
+ "accent",
7267
+ "secondary",
7268
+ "accent4",
7269
+ "accent6",
7270
+ "accent5"
7271
+ ]
7272
+ }
7273
+ },
7274
+ source: "{{Source: system or document, date}}"
7275
+ }
7276
+ }
7277
+ }
7278
+ ]
7279
+ },
7280
+ {
7281
+ name: "slide",
7282
+ children: [
7283
+ {
7284
+ name: "block",
7285
+ props: {
7286
+ ref: "action-chart",
7287
+ slots: {
7288
+ title: "{{Action title: the claim this slide proves, with its number, two lines at most}}",
7289
+ tracker: "{{Tracker: the section, one or two words}}",
7290
+ chart: {
7291
+ name: "chart",
7292
+ props: {
7293
+ type: "bar",
7294
+ valAxisTitle: "{{Measure (unit)}}",
7295
+ data: [
7296
+ {
7297
+ name: "{{Series name}}",
7298
+ labels: [
7299
+ "{{Period 1}}",
7300
+ "{{Period 2}}",
7301
+ "{{Period 3}}"
7302
+ ],
7303
+ values: [0, 0, 0]
7304
+ }
7305
+ ],
7306
+ chartColors: [
7307
+ "accent",
7308
+ "secondary",
7309
+ "accent4",
7310
+ "accent6",
7311
+ "accent5"
7312
+ ]
7313
+ }
7314
+ },
7315
+ takeaway: "{{Takeaway: what the reader should conclude, one or two sentences}}",
7316
+ source: "{{Source: system or document, date}}"
7317
+ }
7318
+ }
7319
+ }
7320
+ ]
7321
+ },
7322
+ {
7323
+ name: "slide",
7324
+ children: [
7325
+ {
7326
+ name: "block",
7327
+ props: {
7328
+ ref: "two-column",
7329
+ slots: {
7330
+ title: "{{Action title: the claim this slide proves, with its number, two lines at most}}",
7331
+ tracker: "{{Tracker: the section, one or two words}}",
7332
+ bullets: [
7333
+ "{{Bullet 1: one claim, ten words}}",
7334
+ "{{Bullet 2: one claim, ten words}}",
7335
+ "{{Bullet 3: one claim, ten words}}"
7336
+ ],
7337
+ content: {
7338
+ name: "table",
7339
+ props: {
7340
+ rows: [
7341
+ [
7342
+ "{{Row label}}",
7343
+ {
7344
+ text: "{{Column (unit)}}",
7345
+ align: "right"
7346
+ },
7347
+ {
7348
+ text: "{{Column (unit)}}",
7349
+ align: "right"
7350
+ }
7351
+ ],
7352
+ [
7353
+ "{{Row 1}}",
7354
+ {
7355
+ text: "{{0.0}}",
7356
+ align: "right"
7357
+ },
7358
+ {
7359
+ text: "{{0.0}}",
7360
+ align: "right"
7361
+ }
7362
+ ],
7363
+ [
7364
+ "{{Row 2}}",
7365
+ {
7366
+ text: "{{0.0}}",
7367
+ align: "right"
7368
+ },
7369
+ {
7370
+ text: "{{0.0}}",
7371
+ align: "right"
7372
+ }
7373
+ ],
7374
+ [
7375
+ "{{Row 3}}",
7376
+ {
7377
+ text: "{{0.0}}",
7378
+ align: "right"
7379
+ },
7380
+ {
7381
+ text: "{{0.0}}",
7382
+ align: "right"
7383
+ }
7384
+ ]
7385
+ ]
7386
+ }
7387
+ },
7388
+ source: "{{Source: system or document, date}}"
7389
+ }
7390
+ }
7391
+ }
7392
+ ]
7393
+ },
7394
+ {
7395
+ name: "slide",
7396
+ children: [
7397
+ {
7398
+ name: "block",
7399
+ props: {
7400
+ ref: "statement",
7401
+ slots: {
7402
+ tracker: "{{Tracker: the section, one or two words}}",
7403
+ assertion: "{{Assertion: what to do next, in one sentence}}",
7404
+ support: "{{Support: what backs the assertion, under thirty words}}"
7405
+ }
7406
+ }
7407
+ }
7408
+ ]
7409
+ }
7410
+ ]
7411
+ }
7412
+ }
7413
+ };
7414
+
7415
+ // src/blueprints/index.ts
7416
+ function scanned(known) {
7417
+ let here;
7418
+ try {
7419
+ here = dirname(fileURLToPath(import.meta.url));
7420
+ } catch {
7421
+ return [];
7422
+ }
7423
+ const directory = [
7424
+ join(here, "../templates/blueprints"),
7425
+ join(here, "templates/blueprints")
7426
+ ].find((path4) => existsSync(path4));
7427
+ if (!directory) return [];
7428
+ return readdirSync(directory).filter((file) => file.endsWith(".pptx.blueprint.json")).map((file) => JSON.parse(readFileSync(join(directory, file), "utf8"))).filter((candidate) => {
7429
+ const id = candidate?.id;
7430
+ return !(typeof id === "string" && id in known);
7431
+ });
7432
+ }
7433
+ var bundled = registerBlueprints("pptx", [consulting_deck_pptx_blueprint_default]);
7434
+ var PPTX_BLUEPRINTS = {
7435
+ ...bundled,
7436
+ ...registerBlueprints("pptx", scanned(bundled))
7437
+ };
7438
+ function pptxBlueprint(id) {
7439
+ return PPTX_BLUEPRINTS[id];
7440
+ }
7441
+ var CANVAS = { slideWidth: 13.333, slideHeight: 7.5 };
7442
+ function instantiatePptxBlueprint(blueprint, options) {
7443
+ return instantiateBlueprint(blueprint, options, {
7444
+ format: "pptx",
7445
+ props: CANVAS,
7446
+ metadataPointer: "/props",
7447
+ markers: (document) => collectPlaceholders2(document).filter(
7448
+ (occurrence) => occurrence.match.kind === "scaffold-marker"
7449
+ )
7450
+ });
7451
+ }
6276
7452
 
6277
7453
  // src/quality/preflight.ts
6278
7454
  import {
@@ -7613,13 +8789,16 @@ export {
7613
8789
  DEFAULT_GENERATED_AT,
7614
8790
  DEFAULT_PPTX_RENDERER_ID,
7615
8791
  DEFAULT_PPTX_THEME,
8792
+ DEVPORTAL_PPTX_THEME,
7616
8793
  DuplicateComponentError,
8794
+ PPTX_BLUEPRINTS,
7617
8795
  PPTX_DEFAULT_QUALITY_PROFILE,
7618
8796
  PPTX_QUALITY_PROFILES,
7619
8797
  PPTX_QUALITY_RULES,
7620
8798
  PresentationGenerator,
7621
8799
  PresentationValidationError,
7622
8800
  UncompiledComponentError,
8801
+ VERMILION_PPTX_THEME,
7623
8802
  W as WarningCodes,
7624
8803
  analyzePptxQuality,
7625
8804
  blockSlotBudgets,
@@ -7636,18 +8815,22 @@ export {
7636
8815
  generateBufferWithWarnings,
7637
8816
  generateFromFile,
7638
8817
  generatePluginPresentationSchema,
8818
+ getChartRequestStats,
7639
8819
  getPptxCoreVersion,
7640
8820
  getPptxTheme,
7641
8821
  hasPptxTheme,
8822
+ instantiatePptxBlueprint,
7642
8823
  isPptxRendererId,
7643
8824
  isPresentationComponent,
7644
8825
  isPresentationComponentDefinition,
7645
8826
  isSlideComponent,
8827
+ pptxBlueprint,
7646
8828
  pptxQualityEngine,
7647
8829
  pptxRendererIds,
7648
8830
  pptxRendererStatuses,
7649
8831
  pptxThemes,
7650
8832
  preparePptxQualityDocument,
8833
+ resetChartRequestStats,
7651
8834
  resolveComponentVersion3 as resolveComponentVersion,
7652
8835
  resolvePptxQualityProfile,
7653
8836
  toAuthoredPointer,