pptx-viewer-mcp 2.2.0 → 2.3.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 +6 -0
- package/README.md +20 -19
- package/dist/index.d.ts +221 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +286 -10
- package/dist/index.mjs +279 -12
- package/dist/mcp/index.js +758 -44
- package/dist/mcp/index.mjs +759 -45
- package/dist/schemas/index.d.ts +601 -1
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +325 -0
- package/dist/schemas/index.mjs +312 -1
- package/package.json +2 -2
package/dist/mcp/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
3
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import { validatePptx, repairPptx, PptxHandler, hasTextProperties, cloneElement as cloneElement$1, isTemplateElementId, makeStoreAwareId, reassignDescendantIds, groupElements as groupElements$1, ungroupElements as ungroupElements$1, PptxMarkdownConverter, ThemePresets, getThemePreset, setChartType, setChartTitle, setChartGrouping, setChartLegend, setChartDataLabels, setChartAxis, setChartCategories, addChartSeries, removeChartSeries, updateChartSeriesValues, ChartBuilder, listChartUserShapes, addChartUserShape, updateChartUserShape, removeChartUserShape, decomposeSmartArt, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, updateSmartArtNodeText, removeSmartArtNode, addSmartArtNode, findPlaceholders, applyTemplate, getSectionForSlide, moveSlidesToSection, reorderSections, removeSection, addSection, SvgExporter, buildPptxJsonDocument, deserializePptxFromJson, applyImportedPptxData, replaceWithCustomGeometry, replaceShapeGeometry, setElementLocked, findLayoutByName, findLayoutByType } from 'pptx-viewer-core';
|
|
5
|
+
import { validatePptx, repairPptx, PptxHandler, hasTextProperties, resolveThemeColorRef, cloneElement as cloneElement$1, isTemplateElementId, makeStoreAwareId, reassignDescendantIds, groupElements as groupElements$1, ungroupElements as ungroupElements$1, TABLE_STYLE_PART_SEQUENCE, normalizeTableStyleGuid, createTableStyleEntry, addTableStyleToMap, deleteTableStyleFromMap, PptxMarkdownConverter, ThemePresets, getThemePreset, setChartType, setChartTitle, setChartGrouping, setChartLegend, setChartDataLabels, setChartAxis, setChartCategories, addChartSeries, removeChartSeries, updateChartSeriesValues, ChartBuilder, setChartDataPointStyle, setChartDataPointExplosion, setChartDataPointMarker, setChartDataPointLabel, setChartSeriesMarker, setChartSeriesTrendline, setChartSeriesErrorBars, setChartHelperLine, setChartColorMapOverride, listChartUserShapes, addChartUserShape, updateChartUserShape, removeChartUserShape, decomposeSmartArt, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, updateSmartArtNodeText, removeSmartArtNode, addSmartArtNode, findPlaceholders, applyTemplate, getSectionForSlide, moveSlidesToSection, reorderSections, removeSection, addSection, SvgExporter, buildPptxJsonDocument, deserializePptxFromJson, applyImportedPptxData, replaceWithCustomGeometry, replaceShapeGeometry, setElementLocked, findLayoutByName, findLayoutByType } from 'pptx-viewer-core';
|
|
6
6
|
import { writeFile, readFile } from 'fs/promises';
|
|
7
7
|
import { resolve, isAbsolute, sep } from 'path';
|
|
8
8
|
|
|
@@ -66,6 +66,32 @@ var ConvertToMarkdownSchema = z.object({
|
|
|
66
66
|
var AccessibilityCheckSchema = z.object({
|
|
67
67
|
filePath: z.string().describe("Path to the PPTX file")
|
|
68
68
|
});
|
|
69
|
+
var ThemeColorRefSchema = z.object({
|
|
70
|
+
scheme: z.enum([
|
|
71
|
+
"dk1",
|
|
72
|
+
"lt1",
|
|
73
|
+
"dk2",
|
|
74
|
+
"lt2",
|
|
75
|
+
"accent1",
|
|
76
|
+
"accent2",
|
|
77
|
+
"accent3",
|
|
78
|
+
"accent4",
|
|
79
|
+
"accent5",
|
|
80
|
+
"accent6",
|
|
81
|
+
"hlink",
|
|
82
|
+
"folHlink",
|
|
83
|
+
"bg1",
|
|
84
|
+
"tx1",
|
|
85
|
+
"bg2",
|
|
86
|
+
"tx2",
|
|
87
|
+
"phClr"
|
|
88
|
+
]),
|
|
89
|
+
lumMod: z.number().optional().describe("Multiply HSL luminance (0..1)"),
|
|
90
|
+
lumOff: z.number().optional().describe("Add to HSL luminance after lumMod (0..1)"),
|
|
91
|
+
tint: z.number().optional().describe("Blend towards white (0..1)"),
|
|
92
|
+
shade: z.number().optional().describe("Blend towards black (0..1)"),
|
|
93
|
+
alpha: z.number().optional().describe("Opacity fraction, 1 = opaque")
|
|
94
|
+
});
|
|
69
95
|
var AddElementSchema = z.object({
|
|
70
96
|
filePath: z.string().describe("Path to the PPTX file"),
|
|
71
97
|
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
@@ -110,6 +136,12 @@ var UpdateElementSchema = z.object({
|
|
|
110
136
|
fontSize: z.number().optional(),
|
|
111
137
|
fontFamily: z.string().optional(),
|
|
112
138
|
fontColor: z.string().optional(),
|
|
139
|
+
/**
|
|
140
|
+
* A theme colour for the run text. Wins on save; resolves `fontColor`
|
|
141
|
+
* immediately when `fontColor` was not also given. Passing `fontColor`
|
|
142
|
+
* alone clears a previously-set text theme colour.
|
|
143
|
+
*/
|
|
144
|
+
fontThemeColor: ThemeColorRefSchema.optional(),
|
|
113
145
|
bold: z.boolean().optional(),
|
|
114
146
|
italic: z.boolean().optional(),
|
|
115
147
|
underline: z.boolean().optional(),
|
|
@@ -182,6 +214,32 @@ var BatchUpdateElementsSchema = z.object({
|
|
|
182
214
|
opacity: z.number().min(0).max(1).optional(),
|
|
183
215
|
hidden: z.boolean().optional()
|
|
184
216
|
});
|
|
217
|
+
var ThemeColorRefSchema2 = z.object({
|
|
218
|
+
scheme: z.enum([
|
|
219
|
+
"dk1",
|
|
220
|
+
"lt1",
|
|
221
|
+
"dk2",
|
|
222
|
+
"lt2",
|
|
223
|
+
"accent1",
|
|
224
|
+
"accent2",
|
|
225
|
+
"accent3",
|
|
226
|
+
"accent4",
|
|
227
|
+
"accent5",
|
|
228
|
+
"accent6",
|
|
229
|
+
"hlink",
|
|
230
|
+
"folHlink",
|
|
231
|
+
"bg1",
|
|
232
|
+
"tx1",
|
|
233
|
+
"bg2",
|
|
234
|
+
"tx2",
|
|
235
|
+
"phClr"
|
|
236
|
+
]),
|
|
237
|
+
lumMod: z.number().optional().describe("Multiply HSL luminance (0..1)"),
|
|
238
|
+
lumOff: z.number().optional().describe("Add to HSL luminance after lumMod (0..1)"),
|
|
239
|
+
tint: z.number().optional().describe("Blend towards white (0..1)"),
|
|
240
|
+
shade: z.number().optional().describe("Blend towards black (0..1)"),
|
|
241
|
+
alpha: z.number().optional().describe("Opacity fraction, 1 = opaque")
|
|
242
|
+
});
|
|
185
243
|
var UpdateTableCellsSchema = z.object({
|
|
186
244
|
filePath: z.string().describe("Path to the PPTX file"),
|
|
187
245
|
slideIndex: z.number().int().min(0),
|
|
@@ -208,6 +266,14 @@ var UpdateElementStyleSchema = z.object({
|
|
|
208
266
|
slideIndex: z.number().int().min(0),
|
|
209
267
|
elementId: z.string(),
|
|
210
268
|
fillColor: z.string().optional(),
|
|
269
|
+
/**
|
|
270
|
+
* A theme colour for the fill (e.g. `{ scheme: 'accent1', lumMod: 0.8 }`
|
|
271
|
+
* for "Accent 1, Lighter 80%"). When set, the shape saves as
|
|
272
|
+
* `<a:schemeClr>` and keeps following the theme after a later theme
|
|
273
|
+
* change, instead of freezing today's resolved hex. Setting `fillColor`
|
|
274
|
+
* without this clears any previously-set fill theme colour.
|
|
275
|
+
*/
|
|
276
|
+
fillThemeColor: ThemeColorRefSchema2.optional(),
|
|
211
277
|
fillMode: z.string().optional(),
|
|
212
278
|
fillGradientStops: z.array(
|
|
213
279
|
z.object({
|
|
@@ -220,6 +286,8 @@ var UpdateElementStyleSchema = z.object({
|
|
|
220
286
|
fillGradientType: z.string().optional(),
|
|
221
287
|
fillOpacity: z.number().optional(),
|
|
222
288
|
strokeColor: z.string().optional(),
|
|
289
|
+
/** A theme colour for the outline; see `fillThemeColor` above. */
|
|
290
|
+
strokeThemeColor: ThemeColorRefSchema2.optional(),
|
|
223
291
|
strokeWidth: z.number().optional(),
|
|
224
292
|
strokeDash: z.string().optional(),
|
|
225
293
|
strokeOpacity: z.number().optional(),
|
|
@@ -266,6 +334,116 @@ var ManageCommentsSchema = z.object({
|
|
|
266
334
|
resolved: z.boolean().optional(),
|
|
267
335
|
includeResolved: z.boolean().optional()
|
|
268
336
|
});
|
|
337
|
+
var TABLE_STYLE_SECTIONS = [
|
|
338
|
+
"wholeTbl",
|
|
339
|
+
"band1H",
|
|
340
|
+
"band2H",
|
|
341
|
+
"band1V",
|
|
342
|
+
"band2V",
|
|
343
|
+
"lastCol",
|
|
344
|
+
"firstCol",
|
|
345
|
+
"lastRow",
|
|
346
|
+
"seCell",
|
|
347
|
+
"swCell",
|
|
348
|
+
"firstRow",
|
|
349
|
+
"neCell",
|
|
350
|
+
"nwCell"
|
|
351
|
+
];
|
|
352
|
+
var TableStyleSimpleColorSchema = z.object({
|
|
353
|
+
schemeColor: z.string().describe('Theme colour key (e.g. "accent1"), or "" for a non-scheme fill'),
|
|
354
|
+
tint: z.number().optional().describe("0-100000"),
|
|
355
|
+
shade: z.number().optional().describe("0-100000"),
|
|
356
|
+
color: z.string().optional().describe('Explicit hex colour, e.g. "#FF8800"')
|
|
357
|
+
});
|
|
358
|
+
var TableStyleFillSchema = z.object({
|
|
359
|
+
schemeColor: z.string(),
|
|
360
|
+
tint: z.number().optional(),
|
|
361
|
+
shade: z.number().optional(),
|
|
362
|
+
color: z.string().optional(),
|
|
363
|
+
noFill: z.boolean().optional(),
|
|
364
|
+
gradient: z.object({
|
|
365
|
+
type: z.enum(["linear", "radial"]),
|
|
366
|
+
angle: z.number().optional(),
|
|
367
|
+
stops: z.array(z.object({ position: z.number(), fill: TableStyleSimpleColorSchema }))
|
|
368
|
+
}).optional(),
|
|
369
|
+
pattern: z.object({
|
|
370
|
+
preset: z.string(),
|
|
371
|
+
foreground: TableStyleSimpleColorSchema.optional(),
|
|
372
|
+
background: TableStyleSimpleColorSchema.optional()
|
|
373
|
+
}).optional(),
|
|
374
|
+
image: z.object({ path: z.string().optional(), data: z.string().optional() }).optional()
|
|
375
|
+
});
|
|
376
|
+
var TableStyleTextSchema = z.object({
|
|
377
|
+
bold: z.boolean().optional(),
|
|
378
|
+
italic: z.boolean().optional(),
|
|
379
|
+
underline: z.boolean().optional(),
|
|
380
|
+
fontSchemeColor: z.string().optional(),
|
|
381
|
+
fontTint: z.number().optional(),
|
|
382
|
+
fontShade: z.number().optional(),
|
|
383
|
+
fontColor: z.string().optional(),
|
|
384
|
+
fontFace: z.string().optional(),
|
|
385
|
+
fontRefIdx: z.string().optional()
|
|
386
|
+
});
|
|
387
|
+
var TableStyleBorderSideSchema = z.object({
|
|
388
|
+
width: z.number().optional(),
|
|
389
|
+
dash: z.string().optional(),
|
|
390
|
+
fill: TableStyleSimpleColorSchema.optional(),
|
|
391
|
+
color: z.string().optional(),
|
|
392
|
+
noFill: z.boolean().optional()
|
|
393
|
+
});
|
|
394
|
+
var TableStyleBordersSchema = z.object({
|
|
395
|
+
left: TableStyleBorderSideSchema.optional(),
|
|
396
|
+
right: TableStyleBorderSideSchema.optional(),
|
|
397
|
+
top: TableStyleBorderSideSchema.optional(),
|
|
398
|
+
bottom: TableStyleBorderSideSchema.optional(),
|
|
399
|
+
insideH: TableStyleBorderSideSchema.optional(),
|
|
400
|
+
insideV: TableStyleBorderSideSchema.optional(),
|
|
401
|
+
tl2br: TableStyleBorderSideSchema.optional(),
|
|
402
|
+
tr2bl: TableStyleBorderSideSchema.optional()
|
|
403
|
+
});
|
|
404
|
+
var TableStyleCell3DSchema = z.object({
|
|
405
|
+
bevelWidth: z.number().optional(),
|
|
406
|
+
bevelHeight: z.number().optional(),
|
|
407
|
+
bevelPreset: z.string().optional(),
|
|
408
|
+
material: z.string().optional(),
|
|
409
|
+
lightRig: z.string().optional(),
|
|
410
|
+
lightRigDirection: z.string().optional()
|
|
411
|
+
});
|
|
412
|
+
var SetTableStyleSectionSchema = z.object({
|
|
413
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
414
|
+
styleId: z.string().describe('Table style GUID, e.g. "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}"'),
|
|
415
|
+
section: z.enum(TABLE_STYLE_SECTIONS).describe("Which of the 13 CT_TableStyle parts to patch"),
|
|
416
|
+
styleName: z.string().optional().describe("Rename the style"),
|
|
417
|
+
fill: TableStyleFillSchema.optional(),
|
|
418
|
+
text: TableStyleTextSchema.optional(),
|
|
419
|
+
borders: TableStyleBordersSchema.optional(),
|
|
420
|
+
cell3D: TableStyleCell3DSchema.optional()
|
|
421
|
+
});
|
|
422
|
+
var CreateTableStyleSchema = z.object({
|
|
423
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
424
|
+
styleName: z.string().describe("Display name for the new style"),
|
|
425
|
+
basedOnStyleId: z.string().optional().describe("Deep-clone every section from this existing style GUID as the starting point"),
|
|
426
|
+
setAsDefault: z.boolean().optional().describe("Repoint ppt/tableStyles.xml's default style at the new one")
|
|
427
|
+
});
|
|
428
|
+
var DeleteTableStyleSchema = z.object({
|
|
429
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
430
|
+
styleId: z.string().describe("Table style GUID to remove"),
|
|
431
|
+
force: z.boolean().optional().describe("Delete even though a table on this deck still references the style")
|
|
432
|
+
});
|
|
433
|
+
var AssignTableStyleSchema = z.object({
|
|
434
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
435
|
+
slideIndex: z.number().int().min(0),
|
|
436
|
+
elementId: z.string().describe("Table element ID"),
|
|
437
|
+
styleId: z.string().optional().describe(
|
|
438
|
+
"Table style GUID to assign. Defaults to the presentation's current default table style when omitted."
|
|
439
|
+
),
|
|
440
|
+
bandedRows: z.boolean().optional(),
|
|
441
|
+
bandedColumns: z.boolean().optional(),
|
|
442
|
+
firstRowHeader: z.boolean().optional(),
|
|
443
|
+
lastRow: z.boolean().optional(),
|
|
444
|
+
firstCol: z.boolean().optional(),
|
|
445
|
+
lastCol: z.boolean().optional()
|
|
446
|
+
});
|
|
269
447
|
var GetThemeInfoSchema = z.object({
|
|
270
448
|
filePath: z.string().describe("Path to the PPTX file")
|
|
271
449
|
});
|
|
@@ -295,6 +473,139 @@ var UpdateThemeFontsSchema = z.object({
|
|
|
295
473
|
majorFont: z.string().optional().describe("Heading (major) font family"),
|
|
296
474
|
minorFont: z.string().optional().describe("Body (minor) font family")
|
|
297
475
|
});
|
|
476
|
+
var MarkerSymbolSchema = z.enum([
|
|
477
|
+
"circle",
|
|
478
|
+
"dash",
|
|
479
|
+
"diamond",
|
|
480
|
+
"dot",
|
|
481
|
+
"none",
|
|
482
|
+
"picture",
|
|
483
|
+
"plus",
|
|
484
|
+
"square",
|
|
485
|
+
"star",
|
|
486
|
+
"triangle",
|
|
487
|
+
"x",
|
|
488
|
+
"auto"
|
|
489
|
+
]);
|
|
490
|
+
var DataLabelPositionSchema = z.enum([
|
|
491
|
+
"bestFit",
|
|
492
|
+
"b",
|
|
493
|
+
"ctr",
|
|
494
|
+
"inBase",
|
|
495
|
+
"inEnd",
|
|
496
|
+
"l",
|
|
497
|
+
"outEnd",
|
|
498
|
+
"r",
|
|
499
|
+
"t"
|
|
500
|
+
]);
|
|
501
|
+
var FormatChartDataPointSchema = z.object({
|
|
502
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
503
|
+
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
504
|
+
elementId: z.string().describe("Chart element ID"),
|
|
505
|
+
seriesIndex: z.number().int().min(0).describe("Zero-based series index"),
|
|
506
|
+
pointIndex: z.number().int().min(0).describe("Zero-based data point (category) index"),
|
|
507
|
+
fillColor: z.string().optional().describe("Fill colour (hex) for this point only"),
|
|
508
|
+
strokeColor: z.string().optional().describe("Outline colour (hex) for this point only"),
|
|
509
|
+
strokeWidth: z.number().optional().describe("Outline width in points"),
|
|
510
|
+
strokeDashStyle: z.string().optional().describe("Outline dash style, e.g. solid, dash, dashDot, sysDot"),
|
|
511
|
+
clearStyle: z.boolean().optional().describe("Remove all per-point shape formatting"),
|
|
512
|
+
explosion: z.number().nullable().optional().describe("Pie/doughnut slice pull-out distance 0-100; null clears it"),
|
|
513
|
+
marker: z.object({
|
|
514
|
+
symbol: MarkerSymbolSchema.optional(),
|
|
515
|
+
size: z.number().optional(),
|
|
516
|
+
fillColor: z.string().optional()
|
|
517
|
+
}).nullable().optional().describe("Per-point marker override (line/scatter/bubble); null clears it")
|
|
518
|
+
});
|
|
519
|
+
var FormatChartDataLabelSchema = z.object({
|
|
520
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
521
|
+
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
522
|
+
elementId: z.string().describe("Chart element ID"),
|
|
523
|
+
seriesIndex: z.number().int().min(0).describe("Zero-based series index"),
|
|
524
|
+
pointIndex: z.number().int().min(0).describe("Zero-based data point (category) index"),
|
|
525
|
+
remove: z.boolean().optional().describe("Remove the per-point label override entirely"),
|
|
526
|
+
showValue: z.boolean().optional(),
|
|
527
|
+
showCategory: z.boolean().optional(),
|
|
528
|
+
showSeriesName: z.boolean().optional(),
|
|
529
|
+
showPercent: z.boolean().optional(),
|
|
530
|
+
showLegendKey: z.boolean().optional(),
|
|
531
|
+
position: DataLabelPositionSchema.optional(),
|
|
532
|
+
text: z.string().optional().describe("Custom label text override; '' clears it"),
|
|
533
|
+
spPr: z.object({
|
|
534
|
+
fillColor: z.string().optional(),
|
|
535
|
+
strokeColor: z.string().optional(),
|
|
536
|
+
strokeWidth: z.number().optional(),
|
|
537
|
+
strokeDashStyle: z.string().optional()
|
|
538
|
+
}).nullable().optional().describe("This label's own fill/line formatting; null removes it"),
|
|
539
|
+
txPr: z.object({
|
|
540
|
+
fontFamily: z.string().optional(),
|
|
541
|
+
fontSize: z.number().optional(),
|
|
542
|
+
bold: z.boolean().optional(),
|
|
543
|
+
italic: z.boolean().optional(),
|
|
544
|
+
color: z.string().optional()
|
|
545
|
+
}).nullable().optional().describe("This label's own font; null removes it")
|
|
546
|
+
});
|
|
547
|
+
var FormatChartSeriesSchema = z.object({
|
|
548
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
549
|
+
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
550
|
+
elementId: z.string().describe("Chart element ID"),
|
|
551
|
+
seriesIndex: z.number().int().min(0).describe("Zero-based series index"),
|
|
552
|
+
marker: z.object({
|
|
553
|
+
symbol: MarkerSymbolSchema.optional(),
|
|
554
|
+
size: z.number().optional(),
|
|
555
|
+
fillColor: z.string().optional(),
|
|
556
|
+
strokeColor: z.string().optional(),
|
|
557
|
+
strokeWidth: z.number().optional(),
|
|
558
|
+
strokeDashStyle: z.string().optional()
|
|
559
|
+
}).nullable().optional().describe("Series marker (line/scatter/bubble/radar); null removes it"),
|
|
560
|
+
trendline: z.object({
|
|
561
|
+
trendlineType: z.enum([
|
|
562
|
+
"linear",
|
|
563
|
+
"exponential",
|
|
564
|
+
"logarithmic",
|
|
565
|
+
"polynomial",
|
|
566
|
+
"power",
|
|
567
|
+
"movingAvg"
|
|
568
|
+
]),
|
|
569
|
+
color: z.string().optional(),
|
|
570
|
+
lineWidth: z.number().optional().describe("Trendline width in points"),
|
|
571
|
+
lineDashStyle: z.string().optional(),
|
|
572
|
+
order: z.number().optional().describe("Polynomial order, 2-6"),
|
|
573
|
+
period: z.number().optional().describe("Moving-average period"),
|
|
574
|
+
displayEq: z.boolean().optional(),
|
|
575
|
+
displayRSq: z.boolean().optional()
|
|
576
|
+
}).nullable().optional().describe("Series trendline; null removes it"),
|
|
577
|
+
errorBars: z.object({
|
|
578
|
+
direction: z.enum(["x", "y"]),
|
|
579
|
+
barType: z.enum(["both", "minus", "plus"]),
|
|
580
|
+
valType: z.enum(["cust", "fixedVal", "percentage", "stdDev", "stdErr"]),
|
|
581
|
+
val: z.number().optional(),
|
|
582
|
+
customPlus: z.array(z.number()).optional(),
|
|
583
|
+
customMinus: z.array(z.number()).optional(),
|
|
584
|
+
noEndCap: z.boolean().optional(),
|
|
585
|
+
color: z.string().optional(),
|
|
586
|
+
width: z.number().optional().describe("Error-bar line width in points"),
|
|
587
|
+
dashStyle: z.string().optional()
|
|
588
|
+
}).nullable().optional().describe("Series error bars; null removes them")
|
|
589
|
+
});
|
|
590
|
+
var SetChartHelperLineSchema = z.object({
|
|
591
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
592
|
+
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
593
|
+
elementId: z.string().describe("Chart element ID"),
|
|
594
|
+
line: z.enum(["dropLines", "hiLowLines"]).describe("Which helper line to set"),
|
|
595
|
+
style: z.object({
|
|
596
|
+
color: z.string().optional(),
|
|
597
|
+
width: z.number().optional(),
|
|
598
|
+
dashStyle: z.string().optional()
|
|
599
|
+
}).nullable().describe("Line colour/width/dash; {} shows the line with defaults, null removes it")
|
|
600
|
+
});
|
|
601
|
+
var SetChartColorMapOverrideSchema = z.object({
|
|
602
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
603
|
+
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
604
|
+
elementId: z.string().describe("Chart element ID"),
|
|
605
|
+
overrides: z.record(z.string(), z.string()).nullable().describe(
|
|
606
|
+
'Theme colour role remap (bg1/tx1/bg2/tx2/accent1-6/hlink/folHlink -> role), e.g. { "accent1": "accent2" }; null removes the override'
|
|
607
|
+
)
|
|
608
|
+
});
|
|
298
609
|
var UpdateChartSchema = z.object({
|
|
299
610
|
filePath: z.string().describe("Path to the PPTX file"),
|
|
300
611
|
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
@@ -557,39 +868,6 @@ var ApplyLayoutSchema = z.object({
|
|
|
557
868
|
layoutName: z.string().optional().describe("Layout name to apply"),
|
|
558
869
|
layoutType: z.string().optional().describe("Layout type to apply (alternative to name)")
|
|
559
870
|
});
|
|
560
|
-
|
|
561
|
-
// src/tools/chart-pareto.ts
|
|
562
|
-
function cumulativePercent(values) {
|
|
563
|
-
const total = values.reduce((sum, value) => sum + value, 0);
|
|
564
|
-
if (total === 0) {
|
|
565
|
-
return values.map(() => 0);
|
|
566
|
-
}
|
|
567
|
-
let running = 0;
|
|
568
|
-
return values.map((value) => {
|
|
569
|
-
running += value;
|
|
570
|
-
return Math.round(running / total * 1e4) / 100;
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
function applyParetoChartTypeAlias(chart, requestedType) {
|
|
574
|
-
if (requestedType.trim().toLowerCase() !== "pareto" || !chart.chartData) {
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
const data = chart.chartData;
|
|
578
|
-
data.chartType = "histogram";
|
|
579
|
-
const [frequency] = data.series;
|
|
580
|
-
if (!frequency) {
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
frequency.histogramOptions = { ...frequency.histogramOptions, layout: "histogram" };
|
|
584
|
-
const hasParetoLine = data.series.some((s) => s.histogramOptions?.layout === "pareto");
|
|
585
|
-
if (!hasParetoLine) {
|
|
586
|
-
data.series.push({
|
|
587
|
-
name: "Cumulative %",
|
|
588
|
-
values: cumulativePercent(frequency.values),
|
|
589
|
-
histogramOptions: { layout: "pareto" }
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
871
|
function generateElementId() {
|
|
594
872
|
return `el-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
595
873
|
}
|
|
@@ -697,6 +975,133 @@ function validateSlideIndex(slideIndex, slideCount) {
|
|
|
697
975
|
return null;
|
|
698
976
|
}
|
|
699
977
|
|
|
978
|
+
// src/tools/chart-formatting-tools.ts
|
|
979
|
+
function findChartElement(ctx, slideIndex, elementId) {
|
|
980
|
+
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
981
|
+
if (err) {
|
|
982
|
+
throw new Error(err);
|
|
983
|
+
}
|
|
984
|
+
const slide = ctx.pptxData.slides[slideIndex];
|
|
985
|
+
const el = slide.elements.find((e) => e.id === elementId);
|
|
986
|
+
if (!el) {
|
|
987
|
+
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
988
|
+
}
|
|
989
|
+
if (el.type !== "chart") {
|
|
990
|
+
throw new Error(`Element '${elementId}' is not a chart.`);
|
|
991
|
+
}
|
|
992
|
+
return el;
|
|
993
|
+
}
|
|
994
|
+
function formatChartDataPoint(ctx, params) {
|
|
995
|
+
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
996
|
+
if (params.clearStyle) {
|
|
997
|
+
setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, null);
|
|
998
|
+
} else if (params.fillColor !== void 0 || params.strokeColor !== void 0 || params.strokeWidth !== void 0 || params.strokeDashStyle !== void 0) {
|
|
999
|
+
setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, {
|
|
1000
|
+
...params.fillColor !== void 0 ? { fillColor: params.fillColor } : {},
|
|
1001
|
+
...params.strokeColor !== void 0 ? { strokeColor: params.strokeColor } : {},
|
|
1002
|
+
...params.strokeWidth !== void 0 ? { strokeWidth: params.strokeWidth } : {},
|
|
1003
|
+
...params.strokeDashStyle !== void 0 ? { strokeDashStyle: params.strokeDashStyle } : {}
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
if (params.explosion !== void 0) {
|
|
1007
|
+
setChartDataPointExplosion(chart, params.seriesIndex, params.pointIndex, params.explosion);
|
|
1008
|
+
}
|
|
1009
|
+
if (params.marker !== void 0) {
|
|
1010
|
+
setChartDataPointMarker(chart, params.seriesIndex, params.pointIndex, params.marker);
|
|
1011
|
+
}
|
|
1012
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1013
|
+
}
|
|
1014
|
+
function formatChartDataLabel(ctx, params) {
|
|
1015
|
+
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1016
|
+
if (params.remove) {
|
|
1017
|
+
setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, null);
|
|
1018
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1019
|
+
}
|
|
1020
|
+
setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, {
|
|
1021
|
+
...params.showValue !== void 0 ? { showValue: params.showValue } : {},
|
|
1022
|
+
...params.showCategory !== void 0 ? { showCategory: params.showCategory } : {},
|
|
1023
|
+
...params.showSeriesName !== void 0 ? { showSeriesName: params.showSeriesName } : {},
|
|
1024
|
+
...params.showPercent !== void 0 ? { showPercent: params.showPercent } : {},
|
|
1025
|
+
...params.showLegendKey !== void 0 ? { showLegendKey: params.showLegendKey } : {},
|
|
1026
|
+
...params.position !== void 0 ? { position: params.position } : {},
|
|
1027
|
+
...params.text !== void 0 ? { text: params.text } : {},
|
|
1028
|
+
...params.spPr !== void 0 ? { spPr: params.spPr } : {},
|
|
1029
|
+
...params.txPr !== void 0 ? { txPr: params.txPr } : {}
|
|
1030
|
+
});
|
|
1031
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1032
|
+
}
|
|
1033
|
+
function formatChartSeries(ctx, params) {
|
|
1034
|
+
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1035
|
+
if (params.marker !== void 0) {
|
|
1036
|
+
if (params.marker === null) {
|
|
1037
|
+
setChartSeriesMarker(chart, params.seriesIndex, null);
|
|
1038
|
+
} else if (params.marker.strokeColor !== void 0 || params.marker.strokeWidth !== void 0 || params.marker.strokeDashStyle !== void 0) {
|
|
1039
|
+
setChartSeriesMarker(chart, params.seriesIndex, {
|
|
1040
|
+
symbol: params.marker.symbol ?? "circle",
|
|
1041
|
+
...params.marker.size !== void 0 ? { size: params.marker.size } : {},
|
|
1042
|
+
spPr: {
|
|
1043
|
+
...params.marker.fillColor !== void 0 ? { fillColor: params.marker.fillColor } : {},
|
|
1044
|
+
...params.marker.strokeColor !== void 0 ? { strokeColor: params.marker.strokeColor } : {},
|
|
1045
|
+
...params.marker.strokeWidth !== void 0 ? { strokeWidth: params.marker.strokeWidth } : {},
|
|
1046
|
+
...params.marker.strokeDashStyle !== void 0 ? { strokeDashStyle: params.marker.strokeDashStyle } : {}
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
} else {
|
|
1050
|
+
setChartSeriesMarker(chart, params.seriesIndex, params.marker);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
if (params.trendline !== void 0) {
|
|
1054
|
+
setChartSeriesTrendline(chart, params.seriesIndex, params.trendline);
|
|
1055
|
+
}
|
|
1056
|
+
if (params.errorBars !== void 0) {
|
|
1057
|
+
setChartSeriesErrorBars(chart, params.seriesIndex, params.errorBars);
|
|
1058
|
+
}
|
|
1059
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1060
|
+
}
|
|
1061
|
+
function setChartHelperLineT(ctx, params) {
|
|
1062
|
+
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1063
|
+
setChartHelperLine(chart, params.line, params.style);
|
|
1064
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1065
|
+
}
|
|
1066
|
+
function setChartColorMapOverrideT(ctx, params) {
|
|
1067
|
+
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1068
|
+
setChartColorMapOverride(chart, params.overrides);
|
|
1069
|
+
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
// src/tools/chart-pareto.ts
|
|
1073
|
+
function cumulativePercent(values) {
|
|
1074
|
+
const total = values.reduce((sum, value) => sum + value, 0);
|
|
1075
|
+
if (total === 0) {
|
|
1076
|
+
return values.map(() => 0);
|
|
1077
|
+
}
|
|
1078
|
+
let running = 0;
|
|
1079
|
+
return values.map((value) => {
|
|
1080
|
+
running += value;
|
|
1081
|
+
return Math.round(running / total * 1e4) / 100;
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
function applyParetoChartTypeAlias(chart, requestedType) {
|
|
1085
|
+
if (requestedType.trim().toLowerCase() !== "pareto" || !chart.chartData) {
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
const data = chart.chartData;
|
|
1089
|
+
data.chartType = "histogram";
|
|
1090
|
+
const [frequency] = data.series;
|
|
1091
|
+
if (!frequency) {
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
frequency.histogramOptions = { ...frequency.histogramOptions, layout: "histogram" };
|
|
1095
|
+
const hasParetoLine = data.series.some((s) => s.histogramOptions?.layout === "pareto");
|
|
1096
|
+
if (!hasParetoLine) {
|
|
1097
|
+
data.series.push({
|
|
1098
|
+
name: "Cumulative %",
|
|
1099
|
+
values: cumulativePercent(frequency.values),
|
|
1100
|
+
histogramOptions: { layout: "pareto" }
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
700
1105
|
// src/tools/chart-tools.ts
|
|
701
1106
|
function updateChart(ctx, params) {
|
|
702
1107
|
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
@@ -837,7 +1242,7 @@ function createChart(ctx, params) {
|
|
|
837
1242
|
result: { elementId: chart.id, slideIndex: params.slideIndex }
|
|
838
1243
|
};
|
|
839
1244
|
}
|
|
840
|
-
function
|
|
1245
|
+
function findChartElement2(ctx, slideIndex, elementId) {
|
|
841
1246
|
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
842
1247
|
if (err) {
|
|
843
1248
|
throw new Error(err);
|
|
@@ -867,17 +1272,17 @@ function buildShape(input) {
|
|
|
867
1272
|
};
|
|
868
1273
|
}
|
|
869
1274
|
function listChartUserShapesT(ctx, params) {
|
|
870
|
-
const chart =
|
|
1275
|
+
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
871
1276
|
return { pptxData: ctx.pptxData, dirty: false, result: { shapes: listChartUserShapes(chart) } };
|
|
872
1277
|
}
|
|
873
1278
|
function addChartUserShapeT(ctx, params) {
|
|
874
|
-
const chart =
|
|
1279
|
+
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
875
1280
|
addChartUserShape(chart, buildShape(params.shape));
|
|
876
1281
|
const index = (chart.chartData?.userShapes?.length ?? 1) - 1;
|
|
877
1282
|
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId, index } };
|
|
878
1283
|
}
|
|
879
1284
|
function updateChartUserShapeT(ctx, params) {
|
|
880
|
-
const chart =
|
|
1285
|
+
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
881
1286
|
const patch = {
|
|
882
1287
|
...params.patch.kind ? { kind: params.patch.kind } : {},
|
|
883
1288
|
...params.patch.anchor ? { anchor: params.patch.anchor } : {},
|
|
@@ -894,7 +1299,7 @@ function updateChartUserShapeT(ctx, params) {
|
|
|
894
1299
|
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
895
1300
|
}
|
|
896
1301
|
function removeChartUserShapeT(ctx, params) {
|
|
897
|
-
const chart =
|
|
1302
|
+
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
898
1303
|
removeChartUserShape(chart, params.index);
|
|
899
1304
|
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
900
1305
|
}
|
|
@@ -1422,8 +1827,17 @@ function updateElement(ctx, params) {
|
|
|
1422
1827
|
if (params.fontFamily !== void 0) {
|
|
1423
1828
|
textEl.textStyle.fontFamily = params.fontFamily;
|
|
1424
1829
|
}
|
|
1425
|
-
if (params.
|
|
1830
|
+
if (params.fontThemeColor !== void 0) {
|
|
1831
|
+
textEl.textStyle.colorRef = params.fontThemeColor;
|
|
1832
|
+
const resolved = resolveThemeColorRef(params.fontThemeColor, ctx.pptxData.themeColorMap);
|
|
1833
|
+
if (params.fontColor !== void 0) {
|
|
1834
|
+
textEl.textStyle.color = params.fontColor;
|
|
1835
|
+
} else if (resolved) {
|
|
1836
|
+
textEl.textStyle.color = resolved;
|
|
1837
|
+
}
|
|
1838
|
+
} else if (params.fontColor !== void 0) {
|
|
1426
1839
|
textEl.textStyle.color = params.fontColor;
|
|
1840
|
+
textEl.textStyle.colorRef = void 0;
|
|
1427
1841
|
}
|
|
1428
1842
|
if (params.bold !== void 0) {
|
|
1429
1843
|
textEl.textStyle.bold = params.bold;
|
|
@@ -2663,8 +3077,17 @@ function updateElementStyle(ctx, params) {
|
|
|
2663
3077
|
el.shapeStyle = {};
|
|
2664
3078
|
}
|
|
2665
3079
|
const ss = el.shapeStyle;
|
|
2666
|
-
if (params.
|
|
3080
|
+
if (params.fillThemeColor !== void 0) {
|
|
3081
|
+
ss.fillColorRef = params.fillThemeColor;
|
|
3082
|
+
const resolved = resolveThemeColorRef(params.fillThemeColor, ctx.pptxData.themeColorMap);
|
|
3083
|
+
if (params.fillColor !== void 0) {
|
|
3084
|
+
ss.fillColor = params.fillColor;
|
|
3085
|
+
} else if (resolved) {
|
|
3086
|
+
ss.fillColor = resolved;
|
|
3087
|
+
}
|
|
3088
|
+
} else if (params.fillColor !== void 0) {
|
|
2667
3089
|
ss.fillColor = params.fillColor;
|
|
3090
|
+
ss.fillColorRef = void 0;
|
|
2668
3091
|
}
|
|
2669
3092
|
if (params.fillMode !== void 0) {
|
|
2670
3093
|
ss.fillMode = params.fillMode;
|
|
@@ -2681,8 +3104,17 @@ function updateElementStyle(ctx, params) {
|
|
|
2681
3104
|
if (params.fillOpacity !== void 0) {
|
|
2682
3105
|
ss.fillOpacity = params.fillOpacity;
|
|
2683
3106
|
}
|
|
2684
|
-
if (params.
|
|
3107
|
+
if (params.strokeThemeColor !== void 0) {
|
|
3108
|
+
ss.strokeColorRef = params.strokeThemeColor;
|
|
3109
|
+
const resolved = resolveThemeColorRef(params.strokeThemeColor, ctx.pptxData.themeColorMap);
|
|
3110
|
+
if (params.strokeColor !== void 0) {
|
|
3111
|
+
ss.strokeColor = params.strokeColor;
|
|
3112
|
+
} else if (resolved) {
|
|
3113
|
+
ss.strokeColor = resolved;
|
|
3114
|
+
}
|
|
3115
|
+
} else if (params.strokeColor !== void 0) {
|
|
2685
3116
|
ss.strokeColor = params.strokeColor;
|
|
3117
|
+
ss.strokeColorRef = void 0;
|
|
2686
3118
|
}
|
|
2687
3119
|
if (params.strokeWidth !== void 0) {
|
|
2688
3120
|
ss.strokeWidth = params.strokeWidth;
|
|
@@ -2832,6 +3264,142 @@ function runAccessibilityCheck(ctx) {
|
|
|
2832
3264
|
}
|
|
2833
3265
|
};
|
|
2834
3266
|
}
|
|
3267
|
+
function findTableElement(ctx, slideIndex, elementId) {
|
|
3268
|
+
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
3269
|
+
if (err) {
|
|
3270
|
+
throw new Error(err);
|
|
3271
|
+
}
|
|
3272
|
+
const slide = ctx.pptxData.slides[slideIndex];
|
|
3273
|
+
const el = slide.elements.find((e) => e.id === elementId);
|
|
3274
|
+
if (!el) {
|
|
3275
|
+
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
3276
|
+
}
|
|
3277
|
+
if (el.type !== "table") {
|
|
3278
|
+
throw new Error(`Element '${elementId}' is not a table.`);
|
|
3279
|
+
}
|
|
3280
|
+
return el;
|
|
3281
|
+
}
|
|
3282
|
+
function tableStyleIdsInUse(ctx) {
|
|
3283
|
+
const used = /* @__PURE__ */ new Set();
|
|
3284
|
+
for (const slide of ctx.pptxData.slides) {
|
|
3285
|
+
for (const el of slide.elements) {
|
|
3286
|
+
if (el.type === "table" && el.tableData?.tableStyleId) {
|
|
3287
|
+
used.add(normalizeTableStyleGuid(el.tableData.tableStyleId));
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
return used;
|
|
3292
|
+
}
|
|
3293
|
+
function setTableStyleSection(ctx, params) {
|
|
3294
|
+
if (!TABLE_STYLE_PART_SEQUENCE.includes(params.section)) {
|
|
3295
|
+
throw new Error(
|
|
3296
|
+
`Unknown table style section '${params.section}'. Valid sections: ${TABLE_STYLE_PART_SEQUENCE.join(", ")}.`
|
|
3297
|
+
);
|
|
3298
|
+
}
|
|
3299
|
+
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
3300
|
+
ctx.pptxData.tableStyleMap = map;
|
|
3301
|
+
const normalizedId = normalizeTableStyleGuid(params.styleId);
|
|
3302
|
+
const entry = map[normalizedId];
|
|
3303
|
+
if (!entry) {
|
|
3304
|
+
throw new Error(
|
|
3305
|
+
`Table style '${params.styleId}' is not loaded in this presentation. Use create_table_style to add a new one.`
|
|
3306
|
+
);
|
|
3307
|
+
}
|
|
3308
|
+
if (params.styleName !== void 0) {
|
|
3309
|
+
entry.styleName = params.styleName;
|
|
3310
|
+
}
|
|
3311
|
+
const mutableEntry = entry;
|
|
3312
|
+
if (params.fill !== void 0) {
|
|
3313
|
+
mutableEntry[`${params.section}Fill`] = params.fill;
|
|
3314
|
+
}
|
|
3315
|
+
if (params.text !== void 0) {
|
|
3316
|
+
mutableEntry[`${params.section}Text`] = params.text;
|
|
3317
|
+
}
|
|
3318
|
+
if (params.borders !== void 0) {
|
|
3319
|
+
mutableEntry[`${params.section}Borders`] = params.borders;
|
|
3320
|
+
}
|
|
3321
|
+
if (params.cell3D !== void 0) {
|
|
3322
|
+
mutableEntry[`${params.section}Cell3D`] = params.cell3D;
|
|
3323
|
+
}
|
|
3324
|
+
return {
|
|
3325
|
+
pptxData: ctx.pptxData,
|
|
3326
|
+
dirty: true,
|
|
3327
|
+
result: { styleId: normalizedId, section: params.section }
|
|
3328
|
+
};
|
|
3329
|
+
}
|
|
3330
|
+
function createTableStyle(ctx, params) {
|
|
3331
|
+
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
3332
|
+
ctx.pptxData.tableStyleMap = map;
|
|
3333
|
+
const basedOn = params.basedOnStyleId ? map[normalizeTableStyleGuid(params.basedOnStyleId)] : void 0;
|
|
3334
|
+
if (params.basedOnStyleId && !basedOn) {
|
|
3335
|
+
throw new Error(`basedOnStyleId '${params.basedOnStyleId}' is not a loaded table style.`);
|
|
3336
|
+
}
|
|
3337
|
+
const entry = createTableStyleEntry(map, { styleName: params.styleName, basedOn });
|
|
3338
|
+
addTableStyleToMap(map, entry);
|
|
3339
|
+
return {
|
|
3340
|
+
pptxData: ctx.pptxData,
|
|
3341
|
+
dirty: true,
|
|
3342
|
+
result: { styleId: entry.styleId },
|
|
3343
|
+
...params.setAsDefault ? { saveOptions: { tableStylesDefaultId: entry.styleId } } : {}
|
|
3344
|
+
};
|
|
3345
|
+
}
|
|
3346
|
+
function deleteTableStyle(ctx, params) {
|
|
3347
|
+
const normalizedId = normalizeTableStyleGuid(params.styleId);
|
|
3348
|
+
if (!params.force) {
|
|
3349
|
+
const used = tableStyleIdsInUse(ctx);
|
|
3350
|
+
if (used.has(normalizedId)) {
|
|
3351
|
+
throw new Error(
|
|
3352
|
+
`Table style '${params.styleId}' is assigned to at least one table on this deck. Reassign those tables first, or pass force: true.`
|
|
3353
|
+
);
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
3357
|
+
ctx.pptxData.tableStyleMap = map;
|
|
3358
|
+
deleteTableStyleFromMap(map, normalizedId);
|
|
3359
|
+
return {
|
|
3360
|
+
pptxData: ctx.pptxData,
|
|
3361
|
+
dirty: true,
|
|
3362
|
+
result: { deleted: true },
|
|
3363
|
+
saveOptions: { tableStylesToDelete: [normalizedId] }
|
|
3364
|
+
};
|
|
3365
|
+
}
|
|
3366
|
+
function assignTableStyle(ctx, params) {
|
|
3367
|
+
const el = findTableElement(ctx, params.slideIndex, params.elementId);
|
|
3368
|
+
if (!el.tableData) {
|
|
3369
|
+
throw new Error(`Table '${params.elementId}' has no tableData.`);
|
|
3370
|
+
}
|
|
3371
|
+
const styleId = params.styleId ?? ctx.pptxData.tableStylesDefaultId;
|
|
3372
|
+
if (!styleId) {
|
|
3373
|
+
throw new Error(
|
|
3374
|
+
"styleId was not provided and this presentation has no tableStylesDefaultId to fall back to."
|
|
3375
|
+
);
|
|
3376
|
+
}
|
|
3377
|
+
const normalizedId = normalizeTableStyleGuid(styleId);
|
|
3378
|
+
el.tableData.tableStyleId = normalizedId;
|
|
3379
|
+
if (params.bandedRows !== void 0) {
|
|
3380
|
+
el.tableData.bandedRows = params.bandedRows;
|
|
3381
|
+
}
|
|
3382
|
+
if (params.bandedColumns !== void 0) {
|
|
3383
|
+
el.tableData.bandedColumns = params.bandedColumns;
|
|
3384
|
+
}
|
|
3385
|
+
if (params.firstRowHeader !== void 0) {
|
|
3386
|
+
el.tableData.firstRowHeader = params.firstRowHeader;
|
|
3387
|
+
}
|
|
3388
|
+
if (params.lastRow !== void 0) {
|
|
3389
|
+
el.tableData.lastRow = params.lastRow;
|
|
3390
|
+
}
|
|
3391
|
+
if (params.firstCol !== void 0) {
|
|
3392
|
+
el.tableData.firstCol = params.firstCol;
|
|
3393
|
+
}
|
|
3394
|
+
if (params.lastCol !== void 0) {
|
|
3395
|
+
el.tableData.lastCol = params.lastCol;
|
|
3396
|
+
}
|
|
3397
|
+
return {
|
|
3398
|
+
pptxData: ctx.pptxData,
|
|
3399
|
+
dirty: true,
|
|
3400
|
+
result: { elementId: params.elementId, styleId: normalizedId }
|
|
3401
|
+
};
|
|
3402
|
+
}
|
|
2835
3403
|
|
|
2836
3404
|
// src/tools/table-tools.ts
|
|
2837
3405
|
function updateTableCells(ctx, params) {
|
|
@@ -3111,11 +3679,17 @@ async function loadPresentation(filePath, execCtx) {
|
|
|
3111
3679
|
const pptxData = await handler.load(rawBytes.buffer);
|
|
3112
3680
|
return { pptxData, rawBytes };
|
|
3113
3681
|
}
|
|
3114
|
-
async function savePresentation(filePath, pptxData, rawBytes, execCtx) {
|
|
3682
|
+
async function savePresentation(filePath, pptxData, rawBytes, execCtx, tableStyleSaveOptions) {
|
|
3115
3683
|
const handler = new PptxHandler();
|
|
3116
3684
|
await handler.load(rawBytes.buffer);
|
|
3117
3685
|
const outputBytes = await handler.save(pptxData.slides, {
|
|
3118
|
-
headerFooter: pptxData.headerFooter
|
|
3686
|
+
headerFooter: pptxData.headerFooter,
|
|
3687
|
+
// `pptxData.tableStyleMap` carries any in-memory table-style edits a
|
|
3688
|
+
// tool made (e.g. `set_table_style_section`, `create_table_style`);
|
|
3689
|
+
// without forwarding it here those edits were silently dropped on
|
|
3690
|
+
// save even though the core save pipeline already supports them.
|
|
3691
|
+
tableStyles: pptxData.tableStyleMap,
|
|
3692
|
+
...tableStyleSaveOptions
|
|
3119
3693
|
});
|
|
3120
3694
|
if (execCtx.collaboration) {
|
|
3121
3695
|
const room = execCtx.collaboration.getRoom(filePath);
|
|
@@ -3147,7 +3721,13 @@ async function executeToolWithContext(filePath, execCtx, toolFn) {
|
|
|
3147
3721
|
const { pptxData, rawBytes } = await loadPresentation(filePath, execCtx);
|
|
3148
3722
|
const toolResult = await toolFn({ pptxData });
|
|
3149
3723
|
if (toolResult.dirty) {
|
|
3150
|
-
const saveResult = await savePresentation(
|
|
3724
|
+
const saveResult = await savePresentation(
|
|
3725
|
+
filePath,
|
|
3726
|
+
toolResult.pptxData,
|
|
3727
|
+
rawBytes,
|
|
3728
|
+
execCtx,
|
|
3729
|
+
toolResult.saveOptions
|
|
3730
|
+
);
|
|
3151
3731
|
return { ...toolResult.result, ...saveResult };
|
|
3152
3732
|
}
|
|
3153
3733
|
return toolResult.result;
|
|
@@ -3627,6 +4207,70 @@ function createServer() {
|
|
|
3627
4207
|
};
|
|
3628
4208
|
}
|
|
3629
4209
|
);
|
|
4210
|
+
server2.registerTool(
|
|
4211
|
+
"set_table_style_section",
|
|
4212
|
+
{
|
|
4213
|
+
description: "Patch the fill, text, borders, or cell3D of one section (wholeTbl, banding, first/last row/col, or a corner cell) of an existing loaded table style",
|
|
4214
|
+
inputSchema: SetTableStyleSectionSchema.shape
|
|
4215
|
+
},
|
|
4216
|
+
async (params) => {
|
|
4217
|
+
const result = await runMcpTool(
|
|
4218
|
+
params.filePath,
|
|
4219
|
+
(ctx) => setTableStyleSection(ctx, params)
|
|
4220
|
+
);
|
|
4221
|
+
return {
|
|
4222
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
4223
|
+
};
|
|
4224
|
+
}
|
|
4225
|
+
);
|
|
4226
|
+
server2.registerTool(
|
|
4227
|
+
"create_table_style",
|
|
4228
|
+
{
|
|
4229
|
+
description: "Create a new table style (optionally cloned from an existing one) and optionally set it as the default",
|
|
4230
|
+
inputSchema: CreateTableStyleSchema.shape
|
|
4231
|
+
},
|
|
4232
|
+
async (params) => {
|
|
4233
|
+
const result = await runMcpTool(
|
|
4234
|
+
params.filePath,
|
|
4235
|
+
(ctx) => createTableStyle(ctx, params)
|
|
4236
|
+
);
|
|
4237
|
+
return {
|
|
4238
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
4239
|
+
};
|
|
4240
|
+
}
|
|
4241
|
+
);
|
|
4242
|
+
server2.registerTool(
|
|
4243
|
+
"delete_table_style",
|
|
4244
|
+
{
|
|
4245
|
+
description: "Remove a table style from the presentation",
|
|
4246
|
+
inputSchema: DeleteTableStyleSchema.shape
|
|
4247
|
+
},
|
|
4248
|
+
async (params) => {
|
|
4249
|
+
const result = await runMcpTool(
|
|
4250
|
+
params.filePath,
|
|
4251
|
+
(ctx) => deleteTableStyle(ctx, params)
|
|
4252
|
+
);
|
|
4253
|
+
return {
|
|
4254
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
4255
|
+
};
|
|
4256
|
+
}
|
|
4257
|
+
);
|
|
4258
|
+
server2.registerTool(
|
|
4259
|
+
"assign_table_style",
|
|
4260
|
+
{
|
|
4261
|
+
description: "Assign a table style (and row/column emphasis flags) to an existing table",
|
|
4262
|
+
inputSchema: AssignTableStyleSchema.shape
|
|
4263
|
+
},
|
|
4264
|
+
async (params) => {
|
|
4265
|
+
const result = await runMcpTool(
|
|
4266
|
+
params.filePath,
|
|
4267
|
+
(ctx) => assignTableStyle(ctx, params)
|
|
4268
|
+
);
|
|
4269
|
+
return {
|
|
4270
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
4271
|
+
};
|
|
4272
|
+
}
|
|
4273
|
+
);
|
|
3630
4274
|
server2.registerTool(
|
|
3631
4275
|
"update_element_style",
|
|
3632
4276
|
{
|
|
@@ -3873,6 +4517,76 @@ function createServer() {
|
|
|
3873
4517
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3874
4518
|
}
|
|
3875
4519
|
);
|
|
4520
|
+
server2.registerTool(
|
|
4521
|
+
"format_chart_data_point",
|
|
4522
|
+
{
|
|
4523
|
+
description: "Set per-data-point chart formatting: fill/stroke colour, stroke width, dash style (c:dPt/c:spPr), explosion, and marker override",
|
|
4524
|
+
inputSchema: FormatChartDataPointSchema.shape
|
|
4525
|
+
},
|
|
4526
|
+
async (params) => {
|
|
4527
|
+
const result = await runMcpTool(
|
|
4528
|
+
params.filePath,
|
|
4529
|
+
(ctx) => formatChartDataPoint(ctx, params)
|
|
4530
|
+
);
|
|
4531
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4532
|
+
}
|
|
4533
|
+
);
|
|
4534
|
+
server2.registerTool(
|
|
4535
|
+
"format_chart_data_label",
|
|
4536
|
+
{
|
|
4537
|
+
description: "Set a per-data-point data-label override (c:dLbl): show flags, position, custom text, and the label's own fill/line formatting (c:spPr) and font (c:txPr)",
|
|
4538
|
+
inputSchema: FormatChartDataLabelSchema.shape
|
|
4539
|
+
},
|
|
4540
|
+
async (params) => {
|
|
4541
|
+
const result = await runMcpTool(
|
|
4542
|
+
params.filePath,
|
|
4543
|
+
(ctx) => formatChartDataLabel(ctx, params)
|
|
4544
|
+
);
|
|
4545
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4546
|
+
}
|
|
4547
|
+
);
|
|
4548
|
+
server2.registerTool(
|
|
4549
|
+
"format_chart_series",
|
|
4550
|
+
{
|
|
4551
|
+
description: "Set a chart series marker (c:marker), trendline (c:trendline, incl. line width/dash), or error bars (c:errBars, incl. line width/dash)",
|
|
4552
|
+
inputSchema: FormatChartSeriesSchema.shape
|
|
4553
|
+
},
|
|
4554
|
+
async (params) => {
|
|
4555
|
+
const result = await runMcpTool(
|
|
4556
|
+
params.filePath,
|
|
4557
|
+
(ctx) => formatChartSeries(ctx, params)
|
|
4558
|
+
);
|
|
4559
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4560
|
+
}
|
|
4561
|
+
);
|
|
4562
|
+
server2.registerTool(
|
|
4563
|
+
"set_chart_helper_line",
|
|
4564
|
+
{
|
|
4565
|
+
description: "Set or remove a chart-level helper line on a line/stock/combo chart: c:dropLines or c:hiLowLines",
|
|
4566
|
+
inputSchema: SetChartHelperLineSchema.shape
|
|
4567
|
+
},
|
|
4568
|
+
async (params) => {
|
|
4569
|
+
const result = await runMcpTool(
|
|
4570
|
+
params.filePath,
|
|
4571
|
+
(ctx) => setChartHelperLineT(ctx, params)
|
|
4572
|
+
);
|
|
4573
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4574
|
+
}
|
|
4575
|
+
);
|
|
4576
|
+
server2.registerTool(
|
|
4577
|
+
"set_chart_color_map_override",
|
|
4578
|
+
{
|
|
4579
|
+
description: "Set or remove a chart's theme colour-map override (c:clrMapOvr), remapping theme colour roles for this chart only",
|
|
4580
|
+
inputSchema: SetChartColorMapOverrideSchema.shape
|
|
4581
|
+
},
|
|
4582
|
+
async (params) => {
|
|
4583
|
+
const result = await runMcpTool(
|
|
4584
|
+
params.filePath,
|
|
4585
|
+
(ctx) => setChartColorMapOverrideT(ctx, params)
|
|
4586
|
+
);
|
|
4587
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4588
|
+
}
|
|
4589
|
+
);
|
|
3876
4590
|
server2.registerTool(
|
|
3877
4591
|
"chart_user_shape_list",
|
|
3878
4592
|
{
|