pptx-viewer-mcp 2.5.9 → 2.7.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/LICENSE +202 -0
- package/README.md +7 -0
- package/dist/codec/index.d.ts +4 -49
- package/dist/codec/index.d.ts.map +1 -1
- package/dist/codec/index.js +7 -357
- package/dist/codec/index.mjs +7 -357
- package/dist/index.d.ts +192 -1277
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +90 -3204
- package/dist/index.mjs +89 -3204
- package/dist/mcp/cli.d.ts +1 -0
- package/dist/mcp/cli.js +2288 -0
- package/dist/mcp/cli.mjs +2286 -0
- package/dist/mcp/index.d.ts +18 -1
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +240 -3313
- package/dist/mcp/index.mjs +239 -3313
- package/dist/types-BUuwyzY-.d.ts +11 -0
- package/dist/types-BUuwyzY-.d.ts.map +1 -0
- package/package.json +4 -4
package/dist/mcp/index.mjs
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
2
|
import { z } from 'zod';
|
|
5
|
-
import {
|
|
3
|
+
import { apiToolsChartFormattingTools, apiToolsChartTools, apiToolsChartUserShapeTools, apiToolsContentTools, apiToolsConversionTools, apiToolsElementTools, apiToolsExportTools, apiToolsGeometryTools, apiToolsHyperlinkTools, apiToolsJsonTools, apiToolsLayoutTools, apiToolsLockTools, apiToolsMetadataTools, apiToolsOleTools, apiToolsPresentationTools, apiToolsSectionTools, apiToolsSlideTools, apiToolsSmartartTools, apiToolsStyleTools, apiToolsTableStyleTools, apiToolsTableTools, apiToolsTemplateTools, apiToolsThemeTools, apiToolsValidationTools, apiExecution } from 'ooxml-core/pptx/automation';
|
|
6
4
|
import { writeFile, readFile } from 'fs/promises';
|
|
7
5
|
import { resolve, isAbsolute, sep } from 'path';
|
|
8
6
|
|
|
7
|
+
// src/mcp/server.ts
|
|
9
8
|
var GetSlideSchema = z.object({
|
|
10
9
|
filePath: z.string().describe("Path to the PPTX file"),
|
|
11
10
|
slideIndex: z.number().int().min(0).describe("Zero-based slide index")
|
|
@@ -930,3162 +929,86 @@ var SetOleObjectNameSchema = z.object({
|
|
|
930
929
|
elementId: z.string().describe("OLE element ID"),
|
|
931
930
|
name: z.string().describe("New Object Name (p:oleObj/@name); blank/whitespace clears it")
|
|
932
931
|
});
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
}
|
|
1014
|
-
base.hasImageData = Boolean(img.imageData);
|
|
1015
|
-
}
|
|
1016
|
-
if (el.type === "table") {
|
|
1017
|
-
const tbl = el;
|
|
1018
|
-
if (tbl.tableData) {
|
|
1019
|
-
base.rowCount = tbl.tableData.rows.length;
|
|
1020
|
-
base.columnCount = tbl.tableData.columnWidths.length;
|
|
1021
|
-
base.cells = tbl.tableData.rows.map((row) => row.cells.map((cell) => cell.text ?? ""));
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
if (el.type === "chart" && el.chartData) {
|
|
1025
|
-
base.chartType = resolveDisplayedChartTypeName(el.chartData);
|
|
1026
|
-
}
|
|
1027
|
-
if (el.type === "group") {
|
|
1028
|
-
const grp = el;
|
|
1029
|
-
base.childCount = grp.children?.length ?? 0;
|
|
1030
|
-
}
|
|
1031
|
-
return base;
|
|
1032
|
-
}
|
|
1033
|
-
function validateSlideIndex(slideIndex, slideCount) {
|
|
1034
|
-
if (slideIndex < 0 || slideIndex >= slideCount) {
|
|
1035
|
-
return `Slide index ${slideIndex} out of range (0\u2013${slideCount - 1}).`;
|
|
1036
|
-
}
|
|
1037
|
-
return null;
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
// src/tools/chart-formatting-tools.ts
|
|
1041
|
-
function findChartElement(ctx, slideIndex, elementId) {
|
|
1042
|
-
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
1043
|
-
if (err) {
|
|
1044
|
-
throw new Error(err);
|
|
1045
|
-
}
|
|
1046
|
-
const slide = ctx.pptxData.slides[slideIndex];
|
|
1047
|
-
const el = slide.elements.find((e) => e.id === elementId);
|
|
1048
|
-
if (!el) {
|
|
1049
|
-
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
1050
|
-
}
|
|
1051
|
-
if (el.type !== "chart") {
|
|
1052
|
-
throw new Error(`Element '${elementId}' is not a chart.`);
|
|
1053
|
-
}
|
|
1054
|
-
return el;
|
|
1055
|
-
}
|
|
1056
|
-
function formatChartDataPoint(ctx, params) {
|
|
1057
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1058
|
-
if (params.clearStyle) {
|
|
1059
|
-
setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, null);
|
|
1060
|
-
} else if (params.fillColor !== void 0 || params.strokeColor !== void 0 || params.strokeWidth !== void 0 || params.strokeDashStyle !== void 0) {
|
|
1061
|
-
setChartDataPointStyle(chart, params.seriesIndex, params.pointIndex, {
|
|
1062
|
-
...params.fillColor !== void 0 ? { fillColor: params.fillColor } : {},
|
|
1063
|
-
...params.strokeColor !== void 0 ? { strokeColor: params.strokeColor } : {},
|
|
1064
|
-
...params.strokeWidth !== void 0 ? { strokeWidth: params.strokeWidth } : {},
|
|
1065
|
-
...params.strokeDashStyle !== void 0 ? { strokeDashStyle: params.strokeDashStyle } : {}
|
|
1066
|
-
});
|
|
1067
|
-
}
|
|
1068
|
-
if (params.explosion !== void 0) {
|
|
1069
|
-
setChartDataPointExplosion(chart, params.seriesIndex, params.pointIndex, params.explosion);
|
|
1070
|
-
}
|
|
1071
|
-
if (params.marker !== void 0) {
|
|
1072
|
-
setChartDataPointMarker(chart, params.seriesIndex, params.pointIndex, params.marker);
|
|
1073
|
-
}
|
|
1074
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1075
|
-
}
|
|
1076
|
-
function formatChartDataLabel(ctx, params) {
|
|
1077
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1078
|
-
if (params.remove) {
|
|
1079
|
-
setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, null);
|
|
1080
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1081
|
-
}
|
|
1082
|
-
setChartDataPointLabel(chart, params.seriesIndex, params.pointIndex, {
|
|
1083
|
-
...params.showValue !== void 0 ? { showValue: params.showValue } : {},
|
|
1084
|
-
...params.showCategory !== void 0 ? { showCategory: params.showCategory } : {},
|
|
1085
|
-
...params.showSeriesName !== void 0 ? { showSeriesName: params.showSeriesName } : {},
|
|
1086
|
-
...params.showPercent !== void 0 ? { showPercent: params.showPercent } : {},
|
|
1087
|
-
...params.showLegendKey !== void 0 ? { showLegendKey: params.showLegendKey } : {},
|
|
1088
|
-
...params.position !== void 0 ? { position: params.position } : {},
|
|
1089
|
-
...params.text !== void 0 ? { text: params.text } : {},
|
|
1090
|
-
...params.spPr !== void 0 ? { spPr: params.spPr } : {},
|
|
1091
|
-
...params.txPr !== void 0 ? { txPr: params.txPr } : {}
|
|
1092
|
-
});
|
|
1093
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1094
|
-
}
|
|
1095
|
-
function formatChartSeries(ctx, params) {
|
|
1096
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1097
|
-
if (params.marker !== void 0) {
|
|
1098
|
-
if (params.marker === null) {
|
|
1099
|
-
setChartSeriesMarker(chart, params.seriesIndex, null);
|
|
1100
|
-
} else if (params.marker.strokeColor !== void 0 || params.marker.strokeWidth !== void 0 || params.marker.strokeDashStyle !== void 0) {
|
|
1101
|
-
setChartSeriesMarker(chart, params.seriesIndex, {
|
|
1102
|
-
symbol: params.marker.symbol ?? "circle",
|
|
1103
|
-
...params.marker.size !== void 0 ? { size: params.marker.size } : {},
|
|
1104
|
-
spPr: {
|
|
1105
|
-
...params.marker.fillColor !== void 0 ? { fillColor: params.marker.fillColor } : {},
|
|
1106
|
-
...params.marker.strokeColor !== void 0 ? { strokeColor: params.marker.strokeColor } : {},
|
|
1107
|
-
...params.marker.strokeWidth !== void 0 ? { strokeWidth: params.marker.strokeWidth } : {},
|
|
1108
|
-
...params.marker.strokeDashStyle !== void 0 ? { strokeDashStyle: params.marker.strokeDashStyle } : {}
|
|
1109
|
-
}
|
|
1110
|
-
});
|
|
1111
|
-
} else {
|
|
1112
|
-
setChartSeriesMarker(chart, params.seriesIndex, params.marker);
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
if (params.trendline !== void 0) {
|
|
1116
|
-
setChartSeriesTrendline(chart, params.seriesIndex, params.trendline);
|
|
1117
|
-
}
|
|
1118
|
-
if (params.errorBars !== void 0) {
|
|
1119
|
-
setChartSeriesErrorBars(chart, params.seriesIndex, params.errorBars);
|
|
1120
|
-
}
|
|
1121
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1122
|
-
}
|
|
1123
|
-
function setChartHelperLineT(ctx, params) {
|
|
1124
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1125
|
-
setChartHelperLine(chart, params.line, params.style);
|
|
1126
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1127
|
-
}
|
|
1128
|
-
function setChartColorMapOverrideT(ctx, params) {
|
|
1129
|
-
const chart = findChartElement(ctx, params.slideIndex, params.elementId);
|
|
1130
|
-
setChartColorMapOverride(chart, params.overrides);
|
|
1131
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
// src/tools/chart-pareto.ts
|
|
1135
|
-
function cumulativePercent(values) {
|
|
1136
|
-
const total = values.reduce((sum, value) => sum + value, 0);
|
|
1137
|
-
if (total === 0) {
|
|
1138
|
-
return values.map(() => 0);
|
|
1139
|
-
}
|
|
1140
|
-
let running = 0;
|
|
1141
|
-
return values.map((value) => {
|
|
1142
|
-
running += value;
|
|
1143
|
-
return Math.round(running / total * 1e4) / 100;
|
|
1144
|
-
});
|
|
1145
|
-
}
|
|
1146
|
-
function applyParetoChartTypeAlias(chart, requestedType) {
|
|
1147
|
-
if (requestedType.trim().toLowerCase() !== "pareto" || !chart.chartData) {
|
|
1148
|
-
return;
|
|
1149
|
-
}
|
|
1150
|
-
const data = chart.chartData;
|
|
1151
|
-
data.chartType = "histogram";
|
|
1152
|
-
const [frequency] = data.series;
|
|
1153
|
-
if (!frequency) {
|
|
1154
|
-
return;
|
|
1155
|
-
}
|
|
1156
|
-
frequency.histogramOptions = { ...frequency.histogramOptions, layout: "histogram" };
|
|
1157
|
-
const hasParetoLine = data.series.some((s) => s.histogramOptions?.layout === "pareto");
|
|
1158
|
-
if (!hasParetoLine) {
|
|
1159
|
-
data.series.push({
|
|
1160
|
-
name: "Cumulative %",
|
|
1161
|
-
values: cumulativePercent(frequency.values),
|
|
1162
|
-
histogramOptions: { layout: "pareto" }
|
|
1163
|
-
});
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
// src/tools/chart-tools.ts
|
|
1168
|
-
function updateChart(ctx, params) {
|
|
1169
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1170
|
-
if (err) {
|
|
1171
|
-
throw new Error(err);
|
|
1172
|
-
}
|
|
1173
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1174
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1175
|
-
if (!el) {
|
|
1176
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1177
|
-
}
|
|
1178
|
-
if (el.type !== "chart") {
|
|
1179
|
-
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
1180
|
-
}
|
|
1181
|
-
const chart = el;
|
|
1182
|
-
if (params.chartType) {
|
|
1183
|
-
setChartType(chart, params.chartType);
|
|
1184
|
-
applyParetoChartTypeAlias(chart, params.chartType);
|
|
1185
|
-
}
|
|
1186
|
-
if (params.title !== void 0) {
|
|
1187
|
-
setChartTitle(chart, params.title);
|
|
1188
|
-
}
|
|
1189
|
-
if (params.grouping) {
|
|
1190
|
-
setChartGrouping(chart, params.grouping);
|
|
1191
|
-
}
|
|
1192
|
-
if (params.legend) {
|
|
1193
|
-
setChartLegend(chart, {
|
|
1194
|
-
show: params.legend.show,
|
|
1195
|
-
position: params.legend.position
|
|
1196
|
-
});
|
|
1197
|
-
}
|
|
1198
|
-
if (params.dataLabels) {
|
|
1199
|
-
setChartDataLabels(chart, params.dataLabels);
|
|
1200
|
-
}
|
|
1201
|
-
if (params.axis) {
|
|
1202
|
-
setChartAxis(chart, params.axis.type, params.axis.edit);
|
|
1203
|
-
}
|
|
1204
|
-
if (params.categories) {
|
|
1205
|
-
setChartCategories(chart, params.categories);
|
|
1206
|
-
}
|
|
1207
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1208
|
-
}
|
|
1209
|
-
function addChartSeriesT(ctx, params) {
|
|
1210
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1211
|
-
if (err) {
|
|
1212
|
-
throw new Error(err);
|
|
1213
|
-
}
|
|
1214
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1215
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1216
|
-
if (!el) {
|
|
1217
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1218
|
-
}
|
|
1219
|
-
if (el.type !== "chart") {
|
|
1220
|
-
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
1221
|
-
}
|
|
1222
|
-
const chart = el;
|
|
1223
|
-
addChartSeries(chart, { name: params.name, values: params.values, color: params.color });
|
|
1224
|
-
const seriesCount = chart.chartData?.series?.length ?? 0;
|
|
1225
|
-
return {
|
|
1226
|
-
pptxData: ctx.pptxData,
|
|
1227
|
-
dirty: true,
|
|
1228
|
-
result: { elementId: params.elementId, seriesCount }
|
|
1229
|
-
};
|
|
1230
|
-
}
|
|
1231
|
-
function removeChartSeriesT(ctx, params) {
|
|
1232
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1233
|
-
if (err) {
|
|
1234
|
-
throw new Error(err);
|
|
1235
|
-
}
|
|
1236
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1237
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1238
|
-
if (!el) {
|
|
1239
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1240
|
-
}
|
|
1241
|
-
if (el.type !== "chart") {
|
|
1242
|
-
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
1243
|
-
}
|
|
1244
|
-
const chart = el;
|
|
1245
|
-
removeChartSeries(chart, params.seriesIndex);
|
|
1246
|
-
const seriesCount = chart.chartData?.series?.length ?? 0;
|
|
1247
|
-
return {
|
|
1248
|
-
pptxData: ctx.pptxData,
|
|
1249
|
-
dirty: true,
|
|
1250
|
-
result: { elementId: params.elementId, seriesCount }
|
|
1251
|
-
};
|
|
1252
|
-
}
|
|
1253
|
-
function updateChartSeriesData(ctx, params) {
|
|
1254
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1255
|
-
if (err) {
|
|
1256
|
-
throw new Error(err);
|
|
1257
|
-
}
|
|
1258
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1259
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1260
|
-
if (!el) {
|
|
1261
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1262
|
-
}
|
|
1263
|
-
if (el.type !== "chart") {
|
|
1264
|
-
throw new Error(`Element '${params.elementId}' is not a chart.`);
|
|
1265
|
-
}
|
|
1266
|
-
const chart = el;
|
|
1267
|
-
updateChartSeriesValues(chart, params.seriesIndex, params.values);
|
|
1268
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1269
|
-
}
|
|
1270
|
-
function createChart(ctx, params) {
|
|
1271
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1272
|
-
if (err) {
|
|
1273
|
-
throw new Error(err);
|
|
1274
|
-
}
|
|
1275
|
-
const builder = ChartBuilder.create(
|
|
1276
|
-
params.chartType
|
|
1277
|
-
);
|
|
1278
|
-
builder.position(params.x ?? 100, params.y ?? 100);
|
|
1279
|
-
builder.size(params.width ?? 500, params.height ?? 350);
|
|
1280
|
-
if (params.title) {
|
|
1281
|
-
builder.title(params.title);
|
|
1282
|
-
}
|
|
1283
|
-
if (params.categories) {
|
|
1284
|
-
builder.categories(params.categories);
|
|
1285
|
-
}
|
|
1286
|
-
if (params.series) {
|
|
1287
|
-
for (const s of params.series) {
|
|
1288
|
-
builder.addSeries(s.name, s.values, s.color);
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
if (params.legend) {
|
|
1292
|
-
builder.legend(
|
|
1293
|
-
params.legend.show,
|
|
1294
|
-
params.legend.position
|
|
1295
|
-
);
|
|
1296
|
-
}
|
|
1297
|
-
const chart = builder.build();
|
|
1298
|
-
applyParetoChartTypeAlias(chart, params.chartType);
|
|
1299
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1300
|
-
slide.elements.push(chart);
|
|
1301
|
-
return {
|
|
1302
|
-
pptxData: ctx.pptxData,
|
|
1303
|
-
dirty: true,
|
|
1304
|
-
result: { elementId: chart.id, slideIndex: params.slideIndex }
|
|
1305
|
-
};
|
|
1306
|
-
}
|
|
1307
|
-
function findChartElement2(ctx, slideIndex, elementId) {
|
|
1308
|
-
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
1309
|
-
if (err) {
|
|
1310
|
-
throw new Error(err);
|
|
1311
|
-
}
|
|
1312
|
-
const slide = ctx.pptxData.slides[slideIndex];
|
|
1313
|
-
const el = slide.elements.find((e) => e.id === elementId);
|
|
1314
|
-
if (!el) {
|
|
1315
|
-
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
1316
|
-
}
|
|
1317
|
-
if (el.type !== "chart") {
|
|
1318
|
-
throw new Error(`Element '${elementId}' is not a chart.`);
|
|
1319
|
-
}
|
|
1320
|
-
return el;
|
|
1321
|
-
}
|
|
1322
|
-
function buildShape(input) {
|
|
1323
|
-
return {
|
|
1324
|
-
kind: input.kind ?? "sp",
|
|
1325
|
-
anchor: input.anchor ?? "rel",
|
|
1326
|
-
from: input.from,
|
|
1327
|
-
...input.to ? { to: input.to } : {},
|
|
1328
|
-
...input.ext ? { ext: input.ext } : {},
|
|
1329
|
-
...input.prst ? { prst: input.prst } : {},
|
|
1330
|
-
...input.fill ? { fill: input.fill } : {},
|
|
1331
|
-
...input.stroke ? { stroke: input.stroke } : {},
|
|
1332
|
-
...input.strokeWidth !== void 0 ? { strokeWidth: input.strokeWidth } : {},
|
|
1333
|
-
...input.text ? { paragraphs: [{ text: input.text, align: "ctr" }] } : {}
|
|
1334
|
-
};
|
|
1335
|
-
}
|
|
1336
|
-
function listChartUserShapesT(ctx, params) {
|
|
1337
|
-
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
1338
|
-
return { pptxData: ctx.pptxData, dirty: false, result: { shapes: listChartUserShapes(chart) } };
|
|
1339
|
-
}
|
|
1340
|
-
function addChartUserShapeT(ctx, params) {
|
|
1341
|
-
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
1342
|
-
addChartUserShape(chart, buildShape(params.shape));
|
|
1343
|
-
const index = (chart.chartData?.userShapes?.length ?? 1) - 1;
|
|
1344
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId, index } };
|
|
1345
|
-
}
|
|
1346
|
-
function updateChartUserShapeT(ctx, params) {
|
|
1347
|
-
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
1348
|
-
const patch = {
|
|
1349
|
-
...params.patch.kind ? { kind: params.patch.kind } : {},
|
|
1350
|
-
...params.patch.anchor ? { anchor: params.patch.anchor } : {},
|
|
1351
|
-
...params.patch.from ? { from: params.patch.from } : {},
|
|
1352
|
-
...params.patch.to ? { to: params.patch.to } : {},
|
|
1353
|
-
...params.patch.ext ? { ext: params.patch.ext } : {},
|
|
1354
|
-
...params.patch.prst ? { prst: params.patch.prst } : {},
|
|
1355
|
-
...params.patch.fill ? { fill: params.patch.fill } : {},
|
|
1356
|
-
...params.patch.stroke ? { stroke: params.patch.stroke } : {},
|
|
1357
|
-
...params.patch.strokeWidth !== void 0 ? { strokeWidth: params.patch.strokeWidth } : {},
|
|
1358
|
-
...params.patch.text !== void 0 ? { paragraphs: [{ text: params.patch.text, align: "ctr" }] } : {}
|
|
1359
|
-
};
|
|
1360
|
-
updateChartUserShape(chart, params.index, patch);
|
|
1361
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1362
|
-
}
|
|
1363
|
-
function removeChartUserShapeT(ctx, params) {
|
|
1364
|
-
const chart = findChartElement2(ctx, params.slideIndex, params.elementId);
|
|
1365
|
-
removeChartUserShape(chart, params.index);
|
|
1366
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { elementId: params.elementId } };
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
|
-
// src/tools/text-editing.ts
|
|
1370
|
-
function editRange(segments, start, end, replacement) {
|
|
1371
|
-
let offset = 0;
|
|
1372
|
-
let inserted = false;
|
|
1373
|
-
for (const segment of segments) {
|
|
1374
|
-
const text = segment.text;
|
|
1375
|
-
const next = offset + text.length;
|
|
1376
|
-
if (!segment.bulletInfo?.ownedByParagraph && next > start && offset < end) {
|
|
1377
|
-
const from = Math.max(0, start - offset);
|
|
1378
|
-
const to = Math.min(text.length, end - offset);
|
|
1379
|
-
segment.text = text.slice(0, from) + (inserted ? "" : replacement) + text.slice(to);
|
|
1380
|
-
inserted = true;
|
|
1381
|
-
} else if (!inserted && start === end && offset <= start && next >= start && !segment.bulletInfo?.ownedByParagraph) {
|
|
1382
|
-
const at = start - offset;
|
|
1383
|
-
segment.text = text.slice(0, at) + replacement + text.slice(at);
|
|
1384
|
-
inserted = true;
|
|
1385
|
-
}
|
|
1386
|
-
offset = next;
|
|
1387
|
-
}
|
|
1388
|
-
if (!inserted && replacement) {
|
|
1389
|
-
segments.push({ text: replacement, style: {} });
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
function changedRange(before, text) {
|
|
1393
|
-
let start = 0;
|
|
1394
|
-
while (start < before.length && start < text.length && before[start] === text[start]) {
|
|
1395
|
-
start++;
|
|
1396
|
-
}
|
|
1397
|
-
let suffix = 0;
|
|
1398
|
-
while (suffix < before.length - start && suffix < text.length - start && before[before.length - suffix - 1] === text[text.length - suffix - 1]) {
|
|
1399
|
-
suffix++;
|
|
1400
|
-
}
|
|
1401
|
-
return {
|
|
1402
|
-
start,
|
|
1403
|
-
end: before.length - suffix,
|
|
1404
|
-
replacement: text.slice(start, text.length - suffix)
|
|
1405
|
-
};
|
|
1406
|
-
}
|
|
1407
|
-
function setElementText(element, text) {
|
|
1408
|
-
const segments = element.textSegments;
|
|
1409
|
-
if (segments?.length) {
|
|
1410
|
-
const before = segments.map((segment) => segment.text).join("");
|
|
1411
|
-
const oldLines = before.split("\n");
|
|
1412
|
-
const newLines = text.split("\n");
|
|
1413
|
-
if (oldLines.length === newLines.length) {
|
|
1414
|
-
let offset = before.length;
|
|
1415
|
-
for (let index = oldLines.length - 1; index >= 0; index--) {
|
|
1416
|
-
const line = oldLines[index];
|
|
1417
|
-
offset -= line.length;
|
|
1418
|
-
const edit = changedRange(line, newLines[index]);
|
|
1419
|
-
editRange(segments, offset + edit.start, offset + edit.end, edit.replacement);
|
|
1420
|
-
offset--;
|
|
1421
|
-
}
|
|
1422
|
-
} else {
|
|
1423
|
-
const edit = changedRange(before, text);
|
|
1424
|
-
editRange(segments, edit.start, edit.end, edit.replacement);
|
|
1425
|
-
}
|
|
1426
|
-
element.text = segments.map((segment) => segment.text).join("");
|
|
1427
|
-
} else {
|
|
1428
|
-
element.text = text;
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
function replaceElementText(element, regex, replacement) {
|
|
1432
|
-
const before = element.text ?? element.textSegments?.map((segment) => segment.text).join("") ?? "";
|
|
1433
|
-
const matches = Array.from(before.matchAll(regex));
|
|
1434
|
-
if (before.replace(regex, replacement) === before) {
|
|
1435
|
-
return 0;
|
|
1436
|
-
}
|
|
1437
|
-
if (!element.textSegments?.length) {
|
|
1438
|
-
element.text = before.replace(regex, replacement);
|
|
1439
|
-
return matches.length;
|
|
1440
|
-
}
|
|
1441
|
-
for (const match of matches.reverse()) {
|
|
1442
|
-
const start = match.index;
|
|
1443
|
-
const end = start + match[0].length;
|
|
1444
|
-
const single = new RegExp(regex.source, `${regex.flags.replace("g", "")}y`);
|
|
1445
|
-
single.lastIndex = start;
|
|
1446
|
-
const after = before.replace(single, replacement);
|
|
1447
|
-
editRange(
|
|
1448
|
-
element.textSegments,
|
|
1449
|
-
start,
|
|
1450
|
-
end,
|
|
1451
|
-
after.slice(start, after.length - (before.length - end))
|
|
1452
|
-
);
|
|
1453
|
-
}
|
|
1454
|
-
element.text = element.textSegments.map((segment) => segment.text).join("");
|
|
1455
|
-
return matches.length;
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
// src/tools/content-tools.ts
|
|
1459
|
-
var MAX_REGEX_LEN = 200;
|
|
1460
|
-
function hasNestedUnboundedQuantifier(pattern) {
|
|
1461
|
-
return /\([^)]*[+*]\)[+*]/u.test(pattern);
|
|
1462
|
-
}
|
|
1463
|
-
function buildSearchRegex(query, useRegex, caseSensitive) {
|
|
1464
|
-
if (useRegex) {
|
|
1465
|
-
if (query.length > MAX_REGEX_LEN) {
|
|
1466
|
-
return null;
|
|
1467
|
-
}
|
|
1468
|
-
if (hasNestedUnboundedQuantifier(query)) {
|
|
1469
|
-
return null;
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
const pattern = useRegex ? query : query.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
1473
|
-
const flags = caseSensitive ? "g" : "gi";
|
|
1474
|
-
try {
|
|
1475
|
-
return new RegExp(pattern, flags);
|
|
1476
|
-
} catch {
|
|
1477
|
-
return null;
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
function findText(ctx, params) {
|
|
1481
|
-
const regex = buildSearchRegex(
|
|
1482
|
-
params.query,
|
|
1483
|
-
params.useRegex === true,
|
|
1484
|
-
params.caseSensitive === true
|
|
1485
|
-
);
|
|
1486
|
-
if (!regex) {
|
|
1487
|
-
return {
|
|
1488
|
-
pptxData: ctx.pptxData,
|
|
1489
|
-
dirty: false,
|
|
1490
|
-
result: { query: params.query, matchCount: 0, matches: [] }
|
|
1491
|
-
};
|
|
1492
|
-
}
|
|
1493
|
-
const targetIndexes = params.slideIndexes ? params.slideIndexes : ctx.pptxData.slides.map((_, i) => i);
|
|
1494
|
-
const matches = [];
|
|
1495
|
-
for (const si of targetIndexes) {
|
|
1496
|
-
const err = validateSlideIndex(si, ctx.pptxData.slides.length);
|
|
1497
|
-
if (err) {
|
|
1498
|
-
throw new Error(err);
|
|
1499
|
-
}
|
|
1500
|
-
const slide = ctx.pptxData.slides[si];
|
|
1501
|
-
for (const el of slide.elements) {
|
|
1502
|
-
if (hasTextProperties(el)) {
|
|
1503
|
-
const textEl = el;
|
|
1504
|
-
if (textEl.text) {
|
|
1505
|
-
const localMatches = Array.from(textEl.text.matchAll(regex));
|
|
1506
|
-
for (const m of localMatches) {
|
|
1507
|
-
matches.push({
|
|
1508
|
-
slideIndex: si,
|
|
1509
|
-
elementId: el.id,
|
|
1510
|
-
elementType: el.type,
|
|
1511
|
-
matchedText: m[0],
|
|
1512
|
-
context: textEl.text.slice(
|
|
1513
|
-
Math.max(0, (m.index ?? 0) - 20),
|
|
1514
|
-
(m.index ?? 0) + m[0].length + 20
|
|
1515
|
-
)
|
|
1516
|
-
});
|
|
1517
|
-
}
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
if (el.type === "table") {
|
|
1521
|
-
const tbl = el;
|
|
1522
|
-
if (tbl.tableData) {
|
|
1523
|
-
for (const row of tbl.tableData.rows) {
|
|
1524
|
-
for (const cell of row.cells) {
|
|
1525
|
-
if (cell.text) {
|
|
1526
|
-
const localMatches = Array.from(cell.text.matchAll(regex));
|
|
1527
|
-
for (const m of localMatches) {
|
|
1528
|
-
matches.push({
|
|
1529
|
-
slideIndex: si,
|
|
1530
|
-
elementId: el.id,
|
|
1531
|
-
elementType: "table-cell",
|
|
1532
|
-
matchedText: m[0],
|
|
1533
|
-
context: cell.text.slice(
|
|
1534
|
-
Math.max(0, (m.index ?? 0) - 20),
|
|
1535
|
-
(m.index ?? 0) + m[0].length + 20
|
|
1536
|
-
)
|
|
1537
|
-
});
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
if (slide.notes) {
|
|
1546
|
-
const noteMatches = Array.from(slide.notes.matchAll(regex));
|
|
1547
|
-
for (const m of noteMatches) {
|
|
1548
|
-
matches.push({
|
|
1549
|
-
slideIndex: si,
|
|
1550
|
-
elementId: "notes",
|
|
1551
|
-
elementType: "notes",
|
|
1552
|
-
matchedText: m[0],
|
|
1553
|
-
context: slide.notes.slice(
|
|
1554
|
-
Math.max(0, (m.index ?? 0) - 20),
|
|
1555
|
-
(m.index ?? 0) + m[0].length + 20
|
|
1556
|
-
)
|
|
1557
|
-
});
|
|
1558
|
-
}
|
|
1559
|
-
}
|
|
1560
|
-
}
|
|
1561
|
-
return {
|
|
1562
|
-
pptxData: ctx.pptxData,
|
|
1563
|
-
dirty: false,
|
|
1564
|
-
result: {
|
|
1565
|
-
query: params.query,
|
|
1566
|
-
matchCount: matches.length,
|
|
1567
|
-
matches
|
|
1568
|
-
}
|
|
1569
|
-
};
|
|
1570
|
-
}
|
|
1571
|
-
function replaceText(ctx, params) {
|
|
1572
|
-
const regex = buildSearchRegex(
|
|
1573
|
-
params.query,
|
|
1574
|
-
params.useRegex === true,
|
|
1575
|
-
params.caseSensitive === true
|
|
1576
|
-
);
|
|
1577
|
-
if (!regex) {
|
|
1578
|
-
return {
|
|
1579
|
-
pptxData: ctx.pptxData,
|
|
1580
|
-
dirty: false,
|
|
1581
|
-
result: { query: params.query, replacement: params.replacement, replacementCount: 0 }
|
|
1582
|
-
};
|
|
1583
|
-
}
|
|
1584
|
-
const targetIndexes = params.slideIndexes ? params.slideIndexes : ctx.pptxData.slides.map((_, i) => i);
|
|
1585
|
-
let count = 0;
|
|
1586
|
-
for (const si of targetIndexes) {
|
|
1587
|
-
const err = validateSlideIndex(si, ctx.pptxData.slides.length);
|
|
1588
|
-
if (err) {
|
|
1589
|
-
throw new Error(err);
|
|
1590
|
-
}
|
|
1591
|
-
const slide = ctx.pptxData.slides[si];
|
|
1592
|
-
for (const el of slide.elements) {
|
|
1593
|
-
if (hasTextProperties(el)) {
|
|
1594
|
-
const textEl = el;
|
|
1595
|
-
if (textEl.text) {
|
|
1596
|
-
const before = textEl.text;
|
|
1597
|
-
const after = before.replace(regex, params.replacement);
|
|
1598
|
-
if (after !== before) {
|
|
1599
|
-
const matchCount = Array.from(before.matchAll(regex)).length;
|
|
1600
|
-
count += matchCount;
|
|
1601
|
-
replaceElementText(textEl, regex, params.replacement);
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
}
|
|
1605
|
-
if (el.type === "table") {
|
|
1606
|
-
const tbl = el;
|
|
1607
|
-
if (tbl.tableData) {
|
|
1608
|
-
for (const row of tbl.tableData.rows) {
|
|
1609
|
-
for (const cell of row.cells) {
|
|
1610
|
-
if (cell.text) {
|
|
1611
|
-
const before = cell.text;
|
|
1612
|
-
const after = before.replace(regex, params.replacement);
|
|
1613
|
-
if (after !== before) {
|
|
1614
|
-
count += Array.from(before.matchAll(regex)).length;
|
|
1615
|
-
cell.text = after;
|
|
1616
|
-
}
|
|
1617
|
-
}
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
if (slide.notes) {
|
|
1624
|
-
const before = slide.notes;
|
|
1625
|
-
const after = before.replace(regex, params.replacement);
|
|
1626
|
-
if (after !== before) {
|
|
1627
|
-
count += Array.from(before.matchAll(regex)).length;
|
|
1628
|
-
slide.notes = after;
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
return {
|
|
1633
|
-
pptxData: ctx.pptxData,
|
|
1634
|
-
dirty: count > 0,
|
|
1635
|
-
result: {
|
|
1636
|
-
query: params.query,
|
|
1637
|
-
replacement: params.replacement,
|
|
1638
|
-
replacementCount: count
|
|
1639
|
-
}
|
|
1640
|
-
};
|
|
1641
|
-
}
|
|
1642
|
-
function manageComments(ctx, params) {
|
|
1643
|
-
switch (params.action) {
|
|
1644
|
-
case "list": {
|
|
1645
|
-
const all = [];
|
|
1646
|
-
for (let si = 0; si < ctx.pptxData.slides.length; si++) {
|
|
1647
|
-
if (params.slideIndex !== void 0 && si !== params.slideIndex) {
|
|
1648
|
-
continue;
|
|
1649
|
-
}
|
|
1650
|
-
const slide = ctx.pptxData.slides[si];
|
|
1651
|
-
for (const c of slide.comments ?? []) {
|
|
1652
|
-
if (!params.includeResolved && c.resolved) {
|
|
1653
|
-
continue;
|
|
1654
|
-
}
|
|
1655
|
-
all.push({
|
|
1656
|
-
id: c.id,
|
|
1657
|
-
slideIndex: si,
|
|
1658
|
-
text: c.text,
|
|
1659
|
-
author: c.author,
|
|
1660
|
-
createdAt: c.createdAt,
|
|
1661
|
-
resolved: c.resolved
|
|
1662
|
-
});
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
return {
|
|
1666
|
-
pptxData: ctx.pptxData,
|
|
1667
|
-
dirty: false,
|
|
1668
|
-
result: { action: "list", comments: all, count: all.length }
|
|
1669
|
-
};
|
|
1670
|
-
}
|
|
1671
|
-
case "add": {
|
|
1672
|
-
if (params.slideIndex === void 0) {
|
|
1673
|
-
throw new Error("slideIndex is required for add action.");
|
|
1674
|
-
}
|
|
1675
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1676
|
-
if (err) {
|
|
1677
|
-
throw new Error(err);
|
|
1678
|
-
}
|
|
1679
|
-
if (!params.text) {
|
|
1680
|
-
throw new Error("text is required for add action.");
|
|
1681
|
-
}
|
|
1682
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1683
|
-
if (!slide.comments) {
|
|
1684
|
-
slide.comments = [];
|
|
1685
|
-
}
|
|
1686
|
-
const newId = `comment-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1687
|
-
slide.comments.push({
|
|
1688
|
-
id: newId,
|
|
1689
|
-
text: params.text,
|
|
1690
|
-
author: params.author,
|
|
1691
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1692
|
-
resolved: false
|
|
1693
|
-
});
|
|
1694
|
-
return {
|
|
1695
|
-
pptxData: ctx.pptxData,
|
|
1696
|
-
dirty: true,
|
|
1697
|
-
result: { action: "add", commentId: newId }
|
|
1698
|
-
};
|
|
1699
|
-
}
|
|
1700
|
-
case "delete": {
|
|
1701
|
-
if (!params.commentId) {
|
|
1702
|
-
throw new Error("commentId is required for delete action.");
|
|
1703
|
-
}
|
|
1704
|
-
let deleted = false;
|
|
1705
|
-
for (const slide of ctx.pptxData.slides) {
|
|
1706
|
-
if (!slide.comments) {
|
|
1707
|
-
continue;
|
|
1708
|
-
}
|
|
1709
|
-
const before = slide.comments.length;
|
|
1710
|
-
slide.comments = slide.comments.filter((c) => c.id !== params.commentId);
|
|
1711
|
-
if (slide.comments.length < before) {
|
|
1712
|
-
deleted = true;
|
|
1713
|
-
break;
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
if (!deleted) {
|
|
1717
|
-
throw new Error(`Comment '${params.commentId}' not found.`);
|
|
1718
|
-
}
|
|
1719
|
-
return {
|
|
1720
|
-
pptxData: ctx.pptxData,
|
|
1721
|
-
dirty: true,
|
|
1722
|
-
result: { action: "delete", commentId: params.commentId }
|
|
1723
|
-
};
|
|
1724
|
-
}
|
|
1725
|
-
case "resolve": {
|
|
1726
|
-
if (!params.commentId) {
|
|
1727
|
-
throw new Error("commentId is required for resolve action.");
|
|
1728
|
-
}
|
|
1729
|
-
let found = false;
|
|
1730
|
-
for (const slide of ctx.pptxData.slides) {
|
|
1731
|
-
const comment = slide.comments?.find((c) => c.id === params.commentId);
|
|
1732
|
-
if (comment) {
|
|
1733
|
-
comment.resolved = params.resolved !== false;
|
|
1734
|
-
found = true;
|
|
1735
|
-
break;
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
if (!found) {
|
|
1739
|
-
throw new Error(`Comment '${params.commentId}' not found.`);
|
|
1740
|
-
}
|
|
1741
|
-
return {
|
|
1742
|
-
pptxData: ctx.pptxData,
|
|
1743
|
-
dirty: true,
|
|
1744
|
-
result: { action: "resolve", commentId: params.commentId }
|
|
1745
|
-
};
|
|
1746
|
-
}
|
|
1747
|
-
default: {
|
|
1748
|
-
throw new Error(`Unknown action: ${String(params.action)}`);
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
async function convertToMarkdown(ctx, params) {
|
|
1753
|
-
const options = {
|
|
1754
|
-
mediaFolderName: params.mediaFolderName ?? "media",
|
|
1755
|
-
includeMetadata: params.includeMetadata !== false,
|
|
1756
|
-
slideRange: params.slideRange,
|
|
1757
|
-
includeSpeakerNotes: params.includeSpeakerNotes !== false,
|
|
1758
|
-
semanticMode: params.semanticMode === true,
|
|
1759
|
-
sourceName: params.sourceName ?? "unknown"
|
|
1760
|
-
};
|
|
1761
|
-
const outputDir = params.outputDir ?? ".";
|
|
1762
|
-
const safeOutputDir = params.scopeOutputDir ? params.scopeOutputDir(outputDir, params.rootDir) : outputDir;
|
|
1763
|
-
const converter = new PptxMarkdownConverter(safeOutputDir, options);
|
|
1764
|
-
const markdown = await converter.convert(ctx.pptxData);
|
|
1765
|
-
return {
|
|
1766
|
-
pptxData: ctx.pptxData,
|
|
1767
|
-
dirty: false,
|
|
1768
|
-
result: {
|
|
1769
|
-
markdown,
|
|
1770
|
-
slidesConverted: converter.slidesConverted,
|
|
1771
|
-
totalSlides: converter.presentationSlides,
|
|
1772
|
-
imagesExtracted: converter.imagesExtracted
|
|
1773
|
-
}
|
|
1774
|
-
};
|
|
1775
|
-
}
|
|
1776
|
-
var ALT_TEXT_ELEMENT_TYPES = /* @__PURE__ */ new Set(["image", "picture", "table", "chart", "smartArt", "ole", "media", "text", "shape", "connector"]);
|
|
1777
|
-
var TITLE_ELEMENT_TYPES = /* @__PURE__ */ new Set([
|
|
1778
|
-
"table",
|
|
1779
|
-
"chart",
|
|
1780
|
-
"smartArt",
|
|
1781
|
-
"ole",
|
|
1782
|
-
"media",
|
|
1783
|
-
"text",
|
|
1784
|
-
"shape",
|
|
1785
|
-
"connector"
|
|
1786
|
-
]);
|
|
1787
|
-
function applyElementAltText(el, altText) {
|
|
1788
|
-
if (!ALT_TEXT_ELEMENT_TYPES.has(el.type)) {
|
|
1789
|
-
throw new Error(
|
|
1790
|
-
`Element '${el.id}' (${el.type}) does not support altText; only ${[...ALT_TEXT_ELEMENT_TYPES].join(", ")} elements do.`
|
|
1791
|
-
);
|
|
1792
|
-
}
|
|
1793
|
-
el.altText = altText;
|
|
1794
|
-
}
|
|
1795
|
-
function applyElementTitle(el, title) {
|
|
1796
|
-
if (!TITLE_ELEMENT_TYPES.has(el.type)) {
|
|
1797
|
-
throw new Error(
|
|
1798
|
-
`Element '${el.id}' (${el.type}) does not support title; only ${[...TITLE_ELEMENT_TYPES].join(", ")} elements do.`
|
|
1799
|
-
);
|
|
1800
|
-
}
|
|
1801
|
-
el.title = title;
|
|
1802
|
-
}
|
|
1803
|
-
function updateElementStyle(ctx, params) {
|
|
1804
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
1805
|
-
if (err) {
|
|
1806
|
-
throw new Error(err);
|
|
1807
|
-
}
|
|
1808
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
1809
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
1810
|
-
if (!el) {
|
|
1811
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
1812
|
-
}
|
|
1813
|
-
if ("shapeStyle" in el) {
|
|
1814
|
-
if (!el.shapeStyle) {
|
|
1815
|
-
el.shapeStyle = {};
|
|
1816
|
-
}
|
|
1817
|
-
const ss = el.shapeStyle;
|
|
1818
|
-
if (params.fillThemeColor !== void 0) {
|
|
1819
|
-
ss.fillColorRef = params.fillThemeColor;
|
|
1820
|
-
const resolved = resolveThemeColorRef(params.fillThemeColor, ctx.pptxData.themeColorMap);
|
|
1821
|
-
if (params.fillColor !== void 0) {
|
|
1822
|
-
ss.fillColor = params.fillColor;
|
|
1823
|
-
} else if (resolved) {
|
|
1824
|
-
ss.fillColor = resolved;
|
|
1825
|
-
}
|
|
1826
|
-
} else if (params.fillColor !== void 0) {
|
|
1827
|
-
ss.fillColor = params.fillColor;
|
|
1828
|
-
ss.fillColorRef = void 0;
|
|
1829
|
-
}
|
|
1830
|
-
if (params.fillMode !== void 0) {
|
|
1831
|
-
ss.fillMode = params.fillMode;
|
|
1832
|
-
}
|
|
1833
|
-
if (params.fillGradientStops !== void 0) {
|
|
1834
|
-
ss.fillGradientStops = params.fillGradientStops;
|
|
1835
|
-
}
|
|
1836
|
-
if (params.fillGradientAngle !== void 0) {
|
|
1837
|
-
ss.fillGradientAngle = params.fillGradientAngle;
|
|
1838
|
-
}
|
|
1839
|
-
if (params.fillGradientType !== void 0) {
|
|
1840
|
-
ss.fillGradientType = params.fillGradientType;
|
|
1841
|
-
}
|
|
1842
|
-
if (params.fillOpacity !== void 0) {
|
|
1843
|
-
ss.fillOpacity = params.fillOpacity;
|
|
1844
|
-
}
|
|
1845
|
-
if (params.strokeThemeColor !== void 0) {
|
|
1846
|
-
ss.strokeColorRef = params.strokeThemeColor;
|
|
1847
|
-
const resolved = resolveThemeColorRef(params.strokeThemeColor, ctx.pptxData.themeColorMap);
|
|
1848
|
-
if (params.strokeColor !== void 0) {
|
|
1849
|
-
ss.strokeColor = params.strokeColor;
|
|
1850
|
-
} else if (resolved) {
|
|
1851
|
-
ss.strokeColor = resolved;
|
|
1852
|
-
}
|
|
1853
|
-
} else if (params.strokeColor !== void 0) {
|
|
1854
|
-
ss.strokeColor = params.strokeColor;
|
|
1855
|
-
ss.strokeColorRef = void 0;
|
|
1856
|
-
}
|
|
1857
|
-
if (params.strokeWidth !== void 0) {
|
|
1858
|
-
ss.strokeWidth = params.strokeWidth;
|
|
1859
|
-
}
|
|
1860
|
-
if (params.strokeDash !== void 0) {
|
|
1861
|
-
ss.strokeDash = params.strokeDash;
|
|
1862
|
-
}
|
|
1863
|
-
if (params.strokeOpacity !== void 0) {
|
|
1864
|
-
ss.strokeOpacity = params.strokeOpacity;
|
|
1865
|
-
}
|
|
1866
|
-
if (params.shadowColor !== void 0) {
|
|
1867
|
-
ss.shadowColor = params.shadowColor;
|
|
1868
|
-
}
|
|
1869
|
-
if (params.shadowBlur !== void 0) {
|
|
1870
|
-
ss.shadowBlur = params.shadowBlur;
|
|
1871
|
-
}
|
|
1872
|
-
if (params.shadowOffsetX !== void 0) {
|
|
1873
|
-
ss.shadowOffsetX = params.shadowOffsetX;
|
|
1874
|
-
}
|
|
1875
|
-
if (params.shadowOffsetY !== void 0) {
|
|
1876
|
-
ss.shadowOffsetY = params.shadowOffsetY;
|
|
1877
|
-
}
|
|
1878
|
-
if (params.shadowOpacity !== void 0) {
|
|
1879
|
-
ss.shadowOpacity = params.shadowOpacity;
|
|
1880
|
-
}
|
|
1881
|
-
if (params.glowColor !== void 0) {
|
|
1882
|
-
ss.glowColor = params.glowColor;
|
|
1883
|
-
}
|
|
1884
|
-
if (params.glowRadius !== void 0) {
|
|
1885
|
-
ss.glowRadius = params.glowRadius;
|
|
1886
|
-
}
|
|
1887
|
-
if (params.glowOpacity !== void 0) {
|
|
1888
|
-
ss.glowOpacity = params.glowOpacity;
|
|
1889
|
-
}
|
|
1890
|
-
if (params.softEdgeRadius !== void 0) {
|
|
1891
|
-
ss.softEdgeRadius = params.softEdgeRadius;
|
|
1892
|
-
}
|
|
1893
|
-
}
|
|
1894
|
-
if (params.altText !== void 0) {
|
|
1895
|
-
applyElementAltText(el, params.altText);
|
|
1896
|
-
}
|
|
1897
|
-
if (params.title !== void 0) {
|
|
1898
|
-
applyElementTitle(el, params.title);
|
|
1899
|
-
}
|
|
1900
|
-
if (el.type === "image" || el.type === "picture") {
|
|
1901
|
-
const img = el;
|
|
1902
|
-
if (params.cropLeft !== void 0) {
|
|
1903
|
-
img.cropLeft = params.cropLeft;
|
|
1904
|
-
}
|
|
1905
|
-
if (params.cropTop !== void 0) {
|
|
1906
|
-
img.cropTop = params.cropTop;
|
|
1907
|
-
}
|
|
1908
|
-
if (params.cropRight !== void 0) {
|
|
1909
|
-
img.cropRight = params.cropRight;
|
|
1910
|
-
}
|
|
1911
|
-
if (params.cropBottom !== void 0) {
|
|
1912
|
-
img.cropBottom = params.cropBottom;
|
|
1913
|
-
}
|
|
1914
|
-
if (params.brightness !== void 0 || params.contrast !== void 0 || params.grayscale !== void 0) {
|
|
1915
|
-
if (!img.imageEffects) {
|
|
1916
|
-
img.imageEffects = {};
|
|
1917
|
-
}
|
|
1918
|
-
if (params.brightness !== void 0) {
|
|
1919
|
-
img.imageEffects.brightness = params.brightness;
|
|
1920
|
-
}
|
|
1921
|
-
if (params.contrast !== void 0) {
|
|
1922
|
-
img.imageEffects.contrast = params.contrast;
|
|
1923
|
-
}
|
|
1924
|
-
if (params.grayscale !== void 0) {
|
|
1925
|
-
img.imageEffects.grayscale = params.grayscale;
|
|
1926
|
-
}
|
|
1927
|
-
}
|
|
1928
|
-
}
|
|
1929
|
-
return {
|
|
1930
|
-
pptxData: ctx.pptxData,
|
|
1931
|
-
dirty: true,
|
|
1932
|
-
result: { elementId: params.elementId }
|
|
1933
|
-
};
|
|
1934
|
-
}
|
|
1935
|
-
function runAccessibilityCheck(ctx) {
|
|
1936
|
-
const issues = [];
|
|
1937
|
-
for (let si = 0; si < ctx.pptxData.slides.length; si++) {
|
|
1938
|
-
const slide = ctx.pptxData.slides[si];
|
|
1939
|
-
let slideHasText = false;
|
|
1940
|
-
for (const el of slide.elements) {
|
|
1941
|
-
if (el.type === "image" || el.type === "picture") {
|
|
1942
|
-
const img = el;
|
|
1943
|
-
if (!img.altText) {
|
|
1944
|
-
issues.push({
|
|
1945
|
-
slideIndex: si,
|
|
1946
|
-
elementId: el.id,
|
|
1947
|
-
severity: "error",
|
|
1948
|
-
message: `Image element '${el.id}' has no alt text.`
|
|
1949
|
-
});
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
|
-
if (hasTextProperties(el)) {
|
|
1953
|
-
const textEl = el;
|
|
1954
|
-
slideHasText = true;
|
|
1955
|
-
if (!textEl.text || textEl.text.trim() === "") {
|
|
1956
|
-
issues.push({
|
|
1957
|
-
slideIndex: si,
|
|
1958
|
-
elementId: el.id,
|
|
1959
|
-
severity: "info",
|
|
1960
|
-
message: `Text element '${el.id}' is empty.`
|
|
1961
|
-
});
|
|
1962
|
-
}
|
|
1963
|
-
const fs = textEl.textStyle?.fontSize;
|
|
1964
|
-
if (fs !== void 0 && fs < 10) {
|
|
1965
|
-
issues.push({
|
|
1966
|
-
slideIndex: si,
|
|
1967
|
-
elementId: el.id,
|
|
1968
|
-
severity: "warning",
|
|
1969
|
-
message: `Text element '${el.id}' has very small font size (${fs}pt < 10pt).`
|
|
1970
|
-
});
|
|
1971
|
-
}
|
|
1972
|
-
const textColor = textEl.textStyle?.color?.toLowerCase();
|
|
1973
|
-
const bgColor = slide.backgroundColor?.toLowerCase();
|
|
1974
|
-
if (textColor && bgColor && textColor === bgColor) {
|
|
1975
|
-
issues.push({
|
|
1976
|
-
slideIndex: si,
|
|
1977
|
-
elementId: el.id,
|
|
1978
|
-
severity: "error",
|
|
1979
|
-
message: `Text element '${el.id}' has same color as slide background (${textColor}).`
|
|
1980
|
-
});
|
|
1981
|
-
}
|
|
1982
|
-
}
|
|
1983
|
-
}
|
|
1984
|
-
if (!slideHasText) {
|
|
1985
|
-
issues.push({
|
|
1986
|
-
slideIndex: si,
|
|
1987
|
-
severity: "warning",
|
|
1988
|
-
message: `Slide ${si + 1} contains no text elements.`
|
|
1989
|
-
});
|
|
1990
|
-
}
|
|
1991
|
-
}
|
|
1992
|
-
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
1993
|
-
const warningCount = issues.filter((i) => i.severity === "warning").length;
|
|
1994
|
-
const infoCount = issues.filter((i) => i.severity === "info").length;
|
|
1995
|
-
return {
|
|
1996
|
-
pptxData: ctx.pptxData,
|
|
1997
|
-
dirty: false,
|
|
1998
|
-
result: {
|
|
1999
|
-
slideCount: ctx.pptxData.slides.length,
|
|
2000
|
-
totalIssues: issues.length,
|
|
2001
|
-
errorCount,
|
|
2002
|
-
warningCount,
|
|
2003
|
-
infoCount,
|
|
2004
|
-
issues
|
|
2005
|
-
}
|
|
2006
|
-
};
|
|
2007
|
-
}
|
|
2008
|
-
|
|
2009
|
-
// src/tools/element-tools.ts
|
|
2010
|
-
function addElement(ctx, params) {
|
|
2011
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2012
|
-
if (err) {
|
|
2013
|
-
throw new Error(err);
|
|
2014
|
-
}
|
|
2015
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2016
|
-
const id = generateElementId();
|
|
2017
|
-
const x = params.x ?? 100;
|
|
2018
|
-
const y = params.y ?? 100;
|
|
2019
|
-
const width = params.width ?? 300;
|
|
2020
|
-
const height = params.height ?? 60;
|
|
2021
|
-
switch (params.type) {
|
|
2022
|
-
case "text": {
|
|
2023
|
-
const el = {
|
|
2024
|
-
id,
|
|
2025
|
-
type: "text",
|
|
2026
|
-
x,
|
|
2027
|
-
y,
|
|
2028
|
-
width,
|
|
2029
|
-
height,
|
|
2030
|
-
text: params.text ?? "",
|
|
2031
|
-
textStyle: {
|
|
2032
|
-
fontSize: params.fontSize,
|
|
2033
|
-
fontFamily: params.fontFamily,
|
|
2034
|
-
color: params.fontColor,
|
|
2035
|
-
bold: params.bold,
|
|
2036
|
-
italic: params.italic,
|
|
2037
|
-
underline: params.underline,
|
|
2038
|
-
align: params.alignment
|
|
2039
|
-
},
|
|
2040
|
-
textSegments: [
|
|
2041
|
-
{
|
|
2042
|
-
text: params.text ?? "",
|
|
2043
|
-
style: {
|
|
2044
|
-
fontSize: params.fontSize,
|
|
2045
|
-
fontFamily: params.fontFamily,
|
|
2046
|
-
color: params.fontColor,
|
|
2047
|
-
bold: params.bold,
|
|
2048
|
-
italic: params.italic,
|
|
2049
|
-
underline: params.underline
|
|
2050
|
-
}
|
|
2051
|
-
}
|
|
2052
|
-
]
|
|
2053
|
-
};
|
|
2054
|
-
slide.elements.push(el);
|
|
2055
|
-
break;
|
|
2056
|
-
}
|
|
2057
|
-
case "shape": {
|
|
2058
|
-
const el = {
|
|
2059
|
-
id,
|
|
2060
|
-
type: "shape",
|
|
2061
|
-
x,
|
|
2062
|
-
y,
|
|
2063
|
-
width,
|
|
2064
|
-
height,
|
|
2065
|
-
shapeType: params.shapeType ?? "rect",
|
|
2066
|
-
text: params.text,
|
|
2067
|
-
textStyle: params.text ? {
|
|
2068
|
-
fontSize: params.fontSize,
|
|
2069
|
-
fontFamily: params.fontFamily,
|
|
2070
|
-
color: params.fontColor,
|
|
2071
|
-
bold: params.bold,
|
|
2072
|
-
italic: params.italic,
|
|
2073
|
-
align: params.alignment
|
|
2074
|
-
} : void 0,
|
|
2075
|
-
shapeStyle: {
|
|
2076
|
-
fillColor: params.fillColor,
|
|
2077
|
-
strokeColor: params.strokeColor,
|
|
2078
|
-
strokeWidth: params.strokeWidth
|
|
2079
|
-
}
|
|
2080
|
-
};
|
|
2081
|
-
slide.elements.push(el);
|
|
2082
|
-
break;
|
|
2083
|
-
}
|
|
2084
|
-
case "image": {
|
|
2085
|
-
const el = {
|
|
2086
|
-
id,
|
|
2087
|
-
type: "image",
|
|
2088
|
-
x,
|
|
2089
|
-
y,
|
|
2090
|
-
width,
|
|
2091
|
-
height,
|
|
2092
|
-
imageData: params.imageData,
|
|
2093
|
-
altText: params.altText
|
|
2094
|
-
};
|
|
2095
|
-
slide.elements.push(el);
|
|
2096
|
-
break;
|
|
2097
|
-
}
|
|
2098
|
-
case "table": {
|
|
2099
|
-
const rowCount = params.rows ?? 2;
|
|
2100
|
-
const colCount = params.columns ?? 2;
|
|
2101
|
-
const colWidth = 1 / colCount;
|
|
2102
|
-
const tableRows = Array.from({ length: rowCount }, (_, r) => ({
|
|
2103
|
-
height: 40,
|
|
2104
|
-
cells: Array.from({ length: colCount }, (__, c) => ({
|
|
2105
|
-
text: params.cellData?.[r]?.[c] ?? ""
|
|
2106
|
-
}))
|
|
2107
|
-
}));
|
|
2108
|
-
const tableEl = {
|
|
2109
|
-
id,
|
|
2110
|
-
type: "table",
|
|
2111
|
-
x,
|
|
2112
|
-
y,
|
|
2113
|
-
width,
|
|
2114
|
-
height: params.height ?? rowCount * 40,
|
|
2115
|
-
tableData: {
|
|
2116
|
-
rows: tableRows,
|
|
2117
|
-
columnWidths: Array.from({ length: colCount }, () => colWidth),
|
|
2118
|
-
firstRowHeader: params.headerRow ?? false
|
|
2119
|
-
}
|
|
2120
|
-
};
|
|
2121
|
-
slide.elements.push(tableEl);
|
|
2122
|
-
break;
|
|
2123
|
-
}
|
|
2124
|
-
case "connector": {
|
|
2125
|
-
const el = {
|
|
2126
|
-
id,
|
|
2127
|
-
type: "connector",
|
|
2128
|
-
x,
|
|
2129
|
-
y,
|
|
2130
|
-
width,
|
|
2131
|
-
height,
|
|
2132
|
-
shapeStyle: {
|
|
2133
|
-
strokeColor: params.strokeColor ?? "#000000",
|
|
2134
|
-
strokeWidth: params.strokeWidth ?? 1,
|
|
2135
|
-
connectorStartArrow: params.startArrow,
|
|
2136
|
-
connectorEndArrow: params.endArrow
|
|
2137
|
-
}
|
|
2138
|
-
};
|
|
2139
|
-
slide.elements.push(el);
|
|
2140
|
-
break;
|
|
2141
|
-
}
|
|
2142
|
-
default: {
|
|
2143
|
-
throw new Error(`Unknown element type: ${String(params.type)}`);
|
|
2144
|
-
}
|
|
2145
|
-
}
|
|
2146
|
-
return {
|
|
2147
|
-
pptxData: ctx.pptxData,
|
|
2148
|
-
dirty: true,
|
|
2149
|
-
result: { elementId: id, slideIndex: params.slideIndex }
|
|
2150
|
-
};
|
|
2151
|
-
}
|
|
2152
|
-
function updateElement(ctx, params) {
|
|
2153
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2154
|
-
if (err) {
|
|
2155
|
-
throw new Error(err);
|
|
2156
|
-
}
|
|
2157
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2158
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2159
|
-
if (!el) {
|
|
2160
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2161
|
-
}
|
|
2162
|
-
if (params.x !== void 0) {
|
|
2163
|
-
el.x = params.x;
|
|
2164
|
-
}
|
|
2165
|
-
if (params.y !== void 0) {
|
|
2166
|
-
el.y = params.y;
|
|
2167
|
-
}
|
|
2168
|
-
if (params.width !== void 0) {
|
|
2169
|
-
el.width = params.width;
|
|
2170
|
-
}
|
|
2171
|
-
if (params.height !== void 0) {
|
|
2172
|
-
el.height = params.height;
|
|
2173
|
-
}
|
|
2174
|
-
if (params.rotation !== void 0) {
|
|
2175
|
-
el.rotation = params.rotation;
|
|
2176
|
-
}
|
|
2177
|
-
if (params.opacity !== void 0) {
|
|
2178
|
-
el.opacity = params.opacity;
|
|
2179
|
-
}
|
|
2180
|
-
if (params.hidden !== void 0) {
|
|
2181
|
-
el.hidden = params.hidden;
|
|
2182
|
-
}
|
|
2183
|
-
if (params.flipH !== void 0) {
|
|
2184
|
-
el.flipHorizontal = params.flipH;
|
|
2185
|
-
}
|
|
2186
|
-
if (params.flipV !== void 0) {
|
|
2187
|
-
el.flipVertical = params.flipV;
|
|
2188
|
-
}
|
|
2189
|
-
if (params.altText !== void 0) {
|
|
2190
|
-
applyElementAltText(el, params.altText);
|
|
2191
|
-
}
|
|
2192
|
-
if (params.title !== void 0) {
|
|
2193
|
-
applyElementTitle(el, params.title);
|
|
2194
|
-
}
|
|
2195
|
-
if (hasTextProperties(el)) {
|
|
2196
|
-
const textEl = el;
|
|
2197
|
-
if (params.textSegments !== void 0) {
|
|
2198
|
-
textEl.textSegments = structuredClone(params.textSegments);
|
|
2199
|
-
textEl.text = textEl.textSegments.map((segment) => segment.text).join("");
|
|
2200
|
-
} else if (params.text !== void 0) {
|
|
2201
|
-
setElementText(textEl, params.text);
|
|
2202
|
-
}
|
|
2203
|
-
if (!textEl.textStyle) {
|
|
2204
|
-
textEl.textStyle = {};
|
|
2205
|
-
}
|
|
2206
|
-
if (params.fontSize !== void 0) {
|
|
2207
|
-
textEl.textStyle.fontSize = params.fontSize;
|
|
2208
|
-
}
|
|
2209
|
-
if (params.fontFamily !== void 0) {
|
|
2210
|
-
textEl.textStyle.fontFamily = params.fontFamily;
|
|
2211
|
-
}
|
|
2212
|
-
if (params.fontThemeColor !== void 0) {
|
|
2213
|
-
textEl.textStyle.colorRef = params.fontThemeColor;
|
|
2214
|
-
const resolved = resolveThemeColorRef(params.fontThemeColor, ctx.pptxData.themeColorMap);
|
|
2215
|
-
if (params.fontColor !== void 0) {
|
|
2216
|
-
textEl.textStyle.color = params.fontColor;
|
|
2217
|
-
} else if (resolved) {
|
|
2218
|
-
textEl.textStyle.color = resolved;
|
|
2219
|
-
}
|
|
2220
|
-
} else if (params.fontColor !== void 0) {
|
|
2221
|
-
textEl.textStyle.color = params.fontColor;
|
|
2222
|
-
textEl.textStyle.colorRef = void 0;
|
|
2223
|
-
}
|
|
2224
|
-
if (params.bold !== void 0) {
|
|
2225
|
-
textEl.textStyle.bold = params.bold;
|
|
2226
|
-
}
|
|
2227
|
-
if (params.italic !== void 0) {
|
|
2228
|
-
textEl.textStyle.italic = params.italic;
|
|
2229
|
-
}
|
|
2230
|
-
if (params.underline !== void 0) {
|
|
2231
|
-
textEl.textStyle.underline = params.underline;
|
|
2232
|
-
}
|
|
2233
|
-
if (params.alignment !== void 0) {
|
|
2234
|
-
textEl.textStyle.align = params.alignment;
|
|
2235
|
-
}
|
|
2236
|
-
}
|
|
2237
|
-
if ("shapeStyle" in el && el.shapeStyle) {
|
|
2238
|
-
const ss = el.shapeStyle;
|
|
2239
|
-
if (params.fillColor !== void 0) {
|
|
2240
|
-
ss.fillColor = params.fillColor;
|
|
2241
|
-
}
|
|
2242
|
-
if (params.strokeColor !== void 0) {
|
|
2243
|
-
ss.strokeColor = params.strokeColor;
|
|
2244
|
-
}
|
|
2245
|
-
if (params.strokeWidth !== void 0) {
|
|
2246
|
-
ss.strokeWidth = params.strokeWidth;
|
|
2247
|
-
}
|
|
2248
|
-
} else if (params.fillColor !== void 0 || params.strokeColor !== void 0 || params.strokeWidth !== void 0) {
|
|
2249
|
-
if ("shapeStyle" in el) {
|
|
2250
|
-
el.shapeStyle = {
|
|
2251
|
-
fillColor: params.fillColor,
|
|
2252
|
-
strokeColor: params.strokeColor,
|
|
2253
|
-
strokeWidth: params.strokeWidth
|
|
2254
|
-
};
|
|
2255
|
-
}
|
|
2256
|
-
}
|
|
2257
|
-
return {
|
|
2258
|
-
pptxData: ctx.pptxData,
|
|
2259
|
-
dirty: true,
|
|
2260
|
-
result: { elementId: params.elementId }
|
|
2261
|
-
};
|
|
2262
|
-
}
|
|
2263
|
-
function renameElement(ctx, params) {
|
|
2264
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2265
|
-
if (err) {
|
|
2266
|
-
throw new Error(err);
|
|
2267
|
-
}
|
|
2268
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2269
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2270
|
-
if (!el) {
|
|
2271
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2272
|
-
}
|
|
2273
|
-
const name = params.name.trim();
|
|
2274
|
-
if (name.length === 0) {
|
|
2275
|
-
delete el.name;
|
|
2276
|
-
} else {
|
|
2277
|
-
el.name = name;
|
|
2278
|
-
}
|
|
2279
|
-
return {
|
|
2280
|
-
pptxData: ctx.pptxData,
|
|
2281
|
-
dirty: true,
|
|
2282
|
-
result: { elementId: params.elementId, name }
|
|
2283
|
-
};
|
|
2284
|
-
}
|
|
2285
|
-
function deleteElements(ctx, params) {
|
|
2286
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2287
|
-
if (err) {
|
|
2288
|
-
throw new Error(err);
|
|
2289
|
-
}
|
|
2290
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2291
|
-
const idSet = new Set(params.elementIds);
|
|
2292
|
-
const existingIds = new Set(slide.elements.map((element) => element.id));
|
|
2293
|
-
const notFound = params.elementIds.filter((id) => !existingIds.has(id));
|
|
2294
|
-
if (notFound.length > 0) {
|
|
2295
|
-
throw new Error(`Elements not found: ${notFound.join(", ")}`);
|
|
2296
|
-
}
|
|
2297
|
-
const before = slide.elements.length;
|
|
2298
|
-
slide.elements = slide.elements.filter((e) => !idSet.has(e.id));
|
|
2299
|
-
return {
|
|
2300
|
-
pptxData: ctx.pptxData,
|
|
2301
|
-
dirty: true,
|
|
2302
|
-
result: { deletedCount: before - slide.elements.length }
|
|
2303
|
-
};
|
|
2304
|
-
}
|
|
2305
|
-
function arrangeElements(ctx, params) {
|
|
2306
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2307
|
-
if (err) {
|
|
2308
|
-
throw new Error(err);
|
|
2309
|
-
}
|
|
2310
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2311
|
-
if (params.action === "align") {
|
|
2312
|
-
if (!params.elementIds || params.elementIds.length === 0) {
|
|
2313
|
-
throw new Error("elementIds is required for align action.");
|
|
2314
|
-
}
|
|
2315
|
-
const targetIds = new Set(params.elementIds);
|
|
2316
|
-
const targets = slide.elements.filter((element) => targetIds.has(element.id));
|
|
2317
|
-
if (targets.length === 0) {
|
|
2318
|
-
throw new Error("No matching elements found for align.");
|
|
2319
|
-
}
|
|
2320
|
-
switch (params.alignment) {
|
|
2321
|
-
case "left": {
|
|
2322
|
-
const minX = Math.min(...targets.map((e) => e.x));
|
|
2323
|
-
for (const t of targets) {
|
|
2324
|
-
t.x = minX;
|
|
2325
|
-
}
|
|
2326
|
-
break;
|
|
2327
|
-
}
|
|
2328
|
-
case "right": {
|
|
2329
|
-
const maxRight = Math.max(...targets.map((e) => e.x + e.width));
|
|
2330
|
-
for (const t of targets) {
|
|
2331
|
-
t.x = maxRight - t.width;
|
|
2332
|
-
}
|
|
2333
|
-
break;
|
|
2334
|
-
}
|
|
2335
|
-
case "top": {
|
|
2336
|
-
const minY = Math.min(...targets.map((e) => e.y));
|
|
2337
|
-
for (const t of targets) {
|
|
2338
|
-
t.y = minY;
|
|
2339
|
-
}
|
|
2340
|
-
break;
|
|
2341
|
-
}
|
|
2342
|
-
case "bottom": {
|
|
2343
|
-
const maxBottom = Math.max(...targets.map((e) => e.y + e.height));
|
|
2344
|
-
for (const t of targets) {
|
|
2345
|
-
t.y = maxBottom - t.height;
|
|
2346
|
-
}
|
|
2347
|
-
break;
|
|
2348
|
-
}
|
|
2349
|
-
case "centerH": {
|
|
2350
|
-
const avgCX = targets.reduce((s, e) => s + e.x + e.width / 2, 0) / targets.length;
|
|
2351
|
-
for (const t of targets) {
|
|
2352
|
-
t.x = avgCX - t.width / 2;
|
|
2353
|
-
}
|
|
2354
|
-
break;
|
|
2355
|
-
}
|
|
2356
|
-
case "centerV": {
|
|
2357
|
-
const avgCY = targets.reduce((s, e) => s + e.y + e.height / 2, 0) / targets.length;
|
|
2358
|
-
for (const t of targets) {
|
|
2359
|
-
t.y = avgCY - t.height / 2;
|
|
2360
|
-
}
|
|
2361
|
-
break;
|
|
2362
|
-
}
|
|
2363
|
-
default: {
|
|
2364
|
-
throw new Error(`Unknown alignment: ${String(params.alignment)}`);
|
|
2365
|
-
}
|
|
2366
|
-
}
|
|
2367
|
-
} else if (params.action === "reorderLayer") {
|
|
2368
|
-
if (!params.elementId) {
|
|
2369
|
-
throw new Error("elementId is required for reorderLayer action.");
|
|
2370
|
-
}
|
|
2371
|
-
const idx = slide.elements.findIndex((e) => e.id === params.elementId);
|
|
2372
|
-
if (idx < 0) {
|
|
2373
|
-
throw new Error(`Element '${params.elementId}' not found.`);
|
|
2374
|
-
}
|
|
2375
|
-
const [el] = slide.elements.splice(idx, 1);
|
|
2376
|
-
switch (params.layerAction) {
|
|
2377
|
-
case "bringToFront":
|
|
2378
|
-
slide.elements.push(el);
|
|
2379
|
-
break;
|
|
2380
|
-
case "sendToBack":
|
|
2381
|
-
slide.elements.unshift(el);
|
|
2382
|
-
break;
|
|
2383
|
-
case "bringForward": {
|
|
2384
|
-
const newIdx = Math.min(idx + 1, slide.elements.length);
|
|
2385
|
-
slide.elements.splice(newIdx, 0, el);
|
|
2386
|
-
break;
|
|
2387
|
-
}
|
|
2388
|
-
case "sendBackward": {
|
|
2389
|
-
const newIdx = Math.max(idx - 1, 0);
|
|
2390
|
-
slide.elements.splice(newIdx, 0, el);
|
|
2391
|
-
break;
|
|
2392
|
-
}
|
|
2393
|
-
default: {
|
|
2394
|
-
slide.elements.splice(idx, 0, el);
|
|
2395
|
-
throw new Error(`Unknown layerAction: ${String(params.layerAction)}`);
|
|
2396
|
-
}
|
|
2397
|
-
}
|
|
2398
|
-
} else {
|
|
2399
|
-
throw new Error(`Unknown action: ${String(params.action)}`);
|
|
2400
|
-
}
|
|
2401
|
-
return {
|
|
2402
|
-
pptxData: ctx.pptxData,
|
|
2403
|
-
dirty: true,
|
|
2404
|
-
result: { slideIndex: params.slideIndex }
|
|
2405
|
-
};
|
|
2406
|
-
}
|
|
2407
|
-
function cloneElement(ctx, params) {
|
|
2408
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2409
|
-
if (err) {
|
|
2410
|
-
throw new Error(err);
|
|
2411
|
-
}
|
|
2412
|
-
const srcSlide = ctx.pptxData.slides[params.slideIndex];
|
|
2413
|
-
const original = srcSlide.elements.find((e) => e.id === params.elementId);
|
|
2414
|
-
if (!original) {
|
|
2415
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2416
|
-
}
|
|
2417
|
-
const targets = params.targetSlideIndexes ?? [params.slideIndex];
|
|
2418
|
-
const clonedIds = [];
|
|
2419
|
-
const offsetX = params.offsetX ?? 20;
|
|
2420
|
-
const offsetY = params.offsetY ?? 20;
|
|
2421
|
-
for (const targetIdx of targets) {
|
|
2422
|
-
const terr = validateSlideIndex(targetIdx, ctx.pptxData.slides.length);
|
|
2423
|
-
if (terr) {
|
|
2424
|
-
throw new Error(terr);
|
|
2425
|
-
}
|
|
2426
|
-
const clone = cloneElement$1(original);
|
|
2427
|
-
const intoTemplate = isTemplateElementId(original.id);
|
|
2428
|
-
clone.id = makeStoreAwareId(intoTemplate, original.id);
|
|
2429
|
-
reassignDescendantIds(clone, () => makeStoreAwareId(intoTemplate, original.id));
|
|
2430
|
-
clone.x += offsetX;
|
|
2431
|
-
clone.y += offsetY;
|
|
2432
|
-
ctx.pptxData.slides[targetIdx].elements.push(clone);
|
|
2433
|
-
clonedIds.push(clone.id);
|
|
2434
|
-
}
|
|
2435
|
-
return {
|
|
2436
|
-
pptxData: ctx.pptxData,
|
|
2437
|
-
dirty: true,
|
|
2438
|
-
result: { clonedIds }
|
|
2439
|
-
};
|
|
2440
|
-
}
|
|
2441
|
-
function setElementAnimation(ctx, params) {
|
|
2442
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2443
|
-
if (err) {
|
|
2444
|
-
throw new Error(err);
|
|
2445
|
-
}
|
|
2446
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2447
|
-
const elExists = slide.elements.some((e) => e.id === params.elementId);
|
|
2448
|
-
if (!elExists) {
|
|
2449
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2450
|
-
}
|
|
2451
|
-
if (!slide.animations) {
|
|
2452
|
-
slide.animations = [];
|
|
2453
|
-
}
|
|
2454
|
-
const existing = slide.animations.find((a) => a.elementId === params.elementId);
|
|
2455
|
-
if (existing) {
|
|
2456
|
-
if (params.entrance !== void 0) {
|
|
2457
|
-
existing.entrance = params.entrance;
|
|
2458
|
-
}
|
|
2459
|
-
if (params.exit !== void 0) {
|
|
2460
|
-
existing.exit = params.exit;
|
|
2461
|
-
}
|
|
2462
|
-
if (params.durationMs !== void 0) {
|
|
2463
|
-
existing.durationMs = params.durationMs;
|
|
2464
|
-
}
|
|
2465
|
-
if (params.delayMs !== void 0) {
|
|
2466
|
-
existing.delayMs = params.delayMs;
|
|
2467
|
-
}
|
|
2468
|
-
if (params.order !== void 0) {
|
|
2469
|
-
existing.order = params.order;
|
|
2470
|
-
}
|
|
2471
|
-
} else {
|
|
2472
|
-
const anim = {
|
|
2473
|
-
elementId: params.elementId,
|
|
2474
|
-
entrance: params.entrance,
|
|
2475
|
-
exit: params.exit,
|
|
2476
|
-
durationMs: params.durationMs,
|
|
2477
|
-
delayMs: params.delayMs,
|
|
2478
|
-
order: params.order
|
|
2479
|
-
};
|
|
2480
|
-
slide.animations.push(anim);
|
|
2481
|
-
}
|
|
2482
|
-
return {
|
|
2483
|
-
pptxData: ctx.pptxData,
|
|
2484
|
-
dirty: true,
|
|
2485
|
-
result: { elementId: params.elementId }
|
|
2486
|
-
};
|
|
2487
|
-
}
|
|
2488
|
-
function groupElements(ctx, params) {
|
|
2489
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2490
|
-
if (err) {
|
|
2491
|
-
throw new Error(err);
|
|
2492
|
-
}
|
|
2493
|
-
if (params.elementIds.length < 2) {
|
|
2494
|
-
throw new Error("At least 2 elements are required to form a group.");
|
|
2495
|
-
}
|
|
2496
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2497
|
-
const idSet = new Set(params.elementIds);
|
|
2498
|
-
const found = new Set(slide.elements.filter((e) => idSet.has(e.id)).map((e) => e.id));
|
|
2499
|
-
if (found.size !== idSet.size) {
|
|
2500
|
-
const missing = params.elementIds.filter((id) => !found.has(id));
|
|
2501
|
-
throw new Error(`Elements not found: ${missing.join(", ")}`);
|
|
2502
|
-
}
|
|
2503
|
-
const groupId = generateElementId();
|
|
2504
|
-
const grouped = groupElements$1(slide.elements, params.elementIds, groupId);
|
|
2505
|
-
slide.elements = grouped.elements;
|
|
2506
|
-
return {
|
|
2507
|
-
pptxData: ctx.pptxData,
|
|
2508
|
-
dirty: true,
|
|
2509
|
-
result: { groupId: grouped.groupId ?? groupId }
|
|
2510
|
-
};
|
|
2511
|
-
}
|
|
2512
|
-
function ungroupElements(ctx, params) {
|
|
2513
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2514
|
-
if (err) {
|
|
2515
|
-
throw new Error(err);
|
|
2516
|
-
}
|
|
2517
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2518
|
-
const group = slide.elements.find((e) => e.id === params.groupElementId);
|
|
2519
|
-
if (!group) {
|
|
2520
|
-
throw new Error(`Group element '${params.groupElementId}' not found.`);
|
|
2521
|
-
}
|
|
2522
|
-
if (group.type !== "group") {
|
|
2523
|
-
throw new Error(`Element '${params.groupElementId}' is not a group.`);
|
|
2524
|
-
}
|
|
2525
|
-
const intoTemplate = isTemplateElementId(group.id);
|
|
2526
|
-
const childIds = group.children.map(
|
|
2527
|
-
(child) => isTemplateElementId(child.id) === intoTemplate ? child.id : makeStoreAwareId(intoTemplate, group.id)
|
|
2528
|
-
);
|
|
2529
|
-
const promoted = ungroupElements$1(slide.elements, params.groupElementId, childIds, {
|
|
2530
|
-
intoTemplate
|
|
2531
|
-
});
|
|
2532
|
-
slide.elements = promoted.elements;
|
|
2533
|
-
return {
|
|
2534
|
-
pptxData: ctx.pptxData,
|
|
2535
|
-
dirty: true,
|
|
2536
|
-
result: { restoredIds: promoted.childIds }
|
|
2537
|
-
};
|
|
2538
|
-
}
|
|
2539
|
-
function batchUpdateElements(ctx, params) {
|
|
2540
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2541
|
-
if (err) {
|
|
2542
|
-
throw new Error(err);
|
|
2543
|
-
}
|
|
2544
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2545
|
-
const idSet = new Set(params.elementIds);
|
|
2546
|
-
let count = 0;
|
|
2547
|
-
for (const el of slide.elements) {
|
|
2548
|
-
if (!idSet.has(el.id)) {
|
|
2549
|
-
continue;
|
|
2550
|
-
}
|
|
2551
|
-
if (params.x !== void 0) {
|
|
2552
|
-
el.x = params.x;
|
|
2553
|
-
}
|
|
2554
|
-
if (params.y !== void 0) {
|
|
2555
|
-
el.y = params.y;
|
|
2556
|
-
}
|
|
2557
|
-
if (params.width !== void 0) {
|
|
2558
|
-
el.width = params.width;
|
|
2559
|
-
}
|
|
2560
|
-
if (params.height !== void 0) {
|
|
2561
|
-
el.height = params.height;
|
|
2562
|
-
}
|
|
2563
|
-
if (params.rotation !== void 0) {
|
|
2564
|
-
el.rotation = params.rotation;
|
|
2565
|
-
}
|
|
2566
|
-
if (params.opacity !== void 0) {
|
|
2567
|
-
el.opacity = params.opacity;
|
|
2568
|
-
}
|
|
2569
|
-
if (params.hidden !== void 0) {
|
|
2570
|
-
el.hidden = params.hidden;
|
|
2571
|
-
}
|
|
2572
|
-
count++;
|
|
2573
|
-
}
|
|
2574
|
-
return {
|
|
2575
|
-
pptxData: ctx.pptxData,
|
|
2576
|
-
dirty: true,
|
|
2577
|
-
result: { updatedCount: count }
|
|
2578
|
-
};
|
|
2579
|
-
}
|
|
2580
|
-
function exportToSvg(ctx, params) {
|
|
2581
|
-
if (params.slideIndices) {
|
|
2582
|
-
for (const si of params.slideIndices) {
|
|
2583
|
-
const err = validateSlideIndex(si, ctx.pptxData.slides.length);
|
|
2584
|
-
if (err) {
|
|
2585
|
-
throw new Error(err);
|
|
2586
|
-
}
|
|
2587
|
-
}
|
|
2588
|
-
}
|
|
2589
|
-
const options = {};
|
|
2590
|
-
if (params.slideIndices) {
|
|
2591
|
-
options.slideIndices = params.slideIndices;
|
|
2592
|
-
}
|
|
2593
|
-
if (params.includeHidden !== void 0) {
|
|
2594
|
-
options.includeHidden = params.includeHidden;
|
|
2595
|
-
}
|
|
2596
|
-
if (params.defaultFontFamily) {
|
|
2597
|
-
options.defaultFontFamily = params.defaultFontFamily;
|
|
2598
|
-
}
|
|
2599
|
-
if (params.defaultFontSize) {
|
|
2600
|
-
options.defaultFontSize = params.defaultFontSize;
|
|
2601
|
-
}
|
|
2602
|
-
const svgStrings = SvgExporter.exportAll(ctx.pptxData, options);
|
|
2603
|
-
return {
|
|
2604
|
-
pptxData: ctx.pptxData,
|
|
2605
|
-
dirty: false,
|
|
2606
|
-
result: { svgStrings, slideCount: svgStrings.length }
|
|
2607
|
-
};
|
|
2608
|
-
}
|
|
2609
|
-
function exportSlideSvg(ctx, params) {
|
|
2610
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2611
|
-
if (err) {
|
|
2612
|
-
throw new Error(err);
|
|
2613
|
-
}
|
|
2614
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2615
|
-
const width = ctx.pptxData.width ?? 960;
|
|
2616
|
-
const height = ctx.pptxData.height ?? 540;
|
|
2617
|
-
const options = {};
|
|
2618
|
-
if (params.defaultFontFamily) {
|
|
2619
|
-
options.defaultFontFamily = params.defaultFontFamily;
|
|
2620
|
-
}
|
|
2621
|
-
if (params.defaultFontSize) {
|
|
2622
|
-
options.defaultFontSize = params.defaultFontSize;
|
|
2623
|
-
}
|
|
2624
|
-
const svg = SvgExporter.exportSlide(slide, width, height, options);
|
|
2625
|
-
return {
|
|
2626
|
-
pptxData: ctx.pptxData,
|
|
2627
|
-
dirty: false,
|
|
2628
|
-
result: { svg, slideIndex: params.slideIndex }
|
|
2629
|
-
};
|
|
2630
|
-
}
|
|
2631
|
-
function replaceGeometry(ctx, params) {
|
|
2632
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2633
|
-
if (err) {
|
|
2634
|
-
throw new Error(err);
|
|
2635
|
-
}
|
|
2636
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2637
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2638
|
-
if (!el) {
|
|
2639
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2640
|
-
}
|
|
2641
|
-
if (el.type !== "shape") {
|
|
2642
|
-
throw new Error(`Element '${params.elementId}' is not a shape.`);
|
|
2643
|
-
}
|
|
2644
|
-
const shape = el;
|
|
2645
|
-
if (params.svgPath) {
|
|
2646
|
-
replaceWithCustomGeometry(shape, params.svgPath, params.pathWidth, params.pathHeight);
|
|
2647
|
-
return {
|
|
2648
|
-
pptxData: ctx.pptxData,
|
|
2649
|
-
dirty: true,
|
|
2650
|
-
result: { elementId: params.elementId, geometryType: "custom" }
|
|
2651
|
-
};
|
|
2652
|
-
}
|
|
2653
|
-
if (params.shapeType) {
|
|
2654
|
-
replaceShapeGeometry(shape, params.shapeType, params.adjustments);
|
|
2655
|
-
return {
|
|
2656
|
-
pptxData: ctx.pptxData,
|
|
2657
|
-
dirty: true,
|
|
2658
|
-
result: { elementId: params.elementId, geometryType: params.shapeType }
|
|
2659
|
-
};
|
|
2660
|
-
}
|
|
2661
|
-
throw new Error("Either shapeType or svgPath must be provided.");
|
|
2662
|
-
}
|
|
2663
|
-
|
|
2664
|
-
// src/tools/hyperlink-tools.ts
|
|
2665
|
-
function manageHyperlinks(ctx, params) {
|
|
2666
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2667
|
-
if (err) {
|
|
2668
|
-
throw new Error(err);
|
|
2669
|
-
}
|
|
2670
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2671
|
-
switch (params.action) {
|
|
2672
|
-
case "list": {
|
|
2673
|
-
const hyperlinks = [];
|
|
2674
|
-
for (const el of slide.elements) {
|
|
2675
|
-
if (el.actionClick) {
|
|
2676
|
-
hyperlinks.push({
|
|
2677
|
-
elementId: el.id,
|
|
2678
|
-
trigger: "click",
|
|
2679
|
-
url: el.actionClick.url,
|
|
2680
|
-
tooltip: el.actionClick.tooltip,
|
|
2681
|
-
targetSlideIndex: el.actionClick.targetSlideIndex,
|
|
2682
|
-
actionType: el.actionClick.action
|
|
2683
|
-
});
|
|
2684
|
-
}
|
|
2685
|
-
if (el.actionHover) {
|
|
2686
|
-
hyperlinks.push({
|
|
2687
|
-
elementId: el.id,
|
|
2688
|
-
trigger: "hover",
|
|
2689
|
-
url: el.actionHover.url,
|
|
2690
|
-
tooltip: el.actionHover.tooltip,
|
|
2691
|
-
targetSlideIndex: el.actionHover.targetSlideIndex,
|
|
2692
|
-
actionType: el.actionHover.action
|
|
2693
|
-
});
|
|
2694
|
-
}
|
|
2695
|
-
}
|
|
2696
|
-
return { pptxData: ctx.pptxData, dirty: false, result: { action: "list", hyperlinks } };
|
|
2697
|
-
}
|
|
2698
|
-
case "set": {
|
|
2699
|
-
if (!params.elementId) {
|
|
2700
|
-
throw new Error("elementId is required for set action.");
|
|
2701
|
-
}
|
|
2702
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2703
|
-
if (!el) {
|
|
2704
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2705
|
-
}
|
|
2706
|
-
const trigger = params.trigger ?? "click";
|
|
2707
|
-
const action = {};
|
|
2708
|
-
if (params.url) {
|
|
2709
|
-
action.url = params.url;
|
|
2710
|
-
}
|
|
2711
|
-
if (params.tooltip) {
|
|
2712
|
-
action.tooltip = params.tooltip;
|
|
2713
|
-
}
|
|
2714
|
-
if (params.targetSlideIndex !== void 0) {
|
|
2715
|
-
action.targetSlideIndex = params.targetSlideIndex;
|
|
2716
|
-
}
|
|
2717
|
-
if (params.actionType) {
|
|
2718
|
-
switch (params.actionType) {
|
|
2719
|
-
case "url":
|
|
2720
|
-
action.action = "ppaction://hlinkpres";
|
|
2721
|
-
break;
|
|
2722
|
-
case "slide":
|
|
2723
|
-
action.action = "ppaction://hlinksldjump";
|
|
2724
|
-
break;
|
|
2725
|
-
case "nextSlide":
|
|
2726
|
-
action.action = "ppaction://hlinkshowjump?jump=nextslide";
|
|
2727
|
-
break;
|
|
2728
|
-
case "prevSlide":
|
|
2729
|
-
action.action = "ppaction://hlinkshowjump?jump=previousslide";
|
|
2730
|
-
break;
|
|
2731
|
-
case "firstSlide":
|
|
2732
|
-
action.action = "ppaction://hlinkshowjump?jump=firstslide";
|
|
2733
|
-
break;
|
|
2734
|
-
case "lastSlide":
|
|
2735
|
-
action.action = "ppaction://hlinkshowjump?jump=lastslide";
|
|
2736
|
-
break;
|
|
2737
|
-
case "endShow":
|
|
2738
|
-
action.action = "ppaction://hlinkshowjump?jump=endshow";
|
|
2739
|
-
break;
|
|
2740
|
-
}
|
|
2741
|
-
}
|
|
2742
|
-
if (trigger === "click") {
|
|
2743
|
-
el.actionClick = action;
|
|
2744
|
-
} else {
|
|
2745
|
-
el.actionHover = action;
|
|
2746
|
-
}
|
|
2747
|
-
return {
|
|
2748
|
-
pptxData: ctx.pptxData,
|
|
2749
|
-
dirty: true,
|
|
2750
|
-
result: { action: "set", elementId: params.elementId }
|
|
2751
|
-
};
|
|
2752
|
-
}
|
|
2753
|
-
case "remove": {
|
|
2754
|
-
if (!params.elementId) {
|
|
2755
|
-
throw new Error("elementId is required for remove action.");
|
|
2756
|
-
}
|
|
2757
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
2758
|
-
if (!el) {
|
|
2759
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2760
|
-
}
|
|
2761
|
-
const trigger = params.trigger ?? "click";
|
|
2762
|
-
if (trigger === "click") {
|
|
2763
|
-
el.actionClick = void 0;
|
|
2764
|
-
} else {
|
|
2765
|
-
el.actionHover = void 0;
|
|
2766
|
-
}
|
|
2767
|
-
return {
|
|
2768
|
-
pptxData: ctx.pptxData,
|
|
2769
|
-
dirty: true,
|
|
2770
|
-
result: { action: "remove", elementId: params.elementId }
|
|
2771
|
-
};
|
|
2772
|
-
}
|
|
2773
|
-
default:
|
|
2774
|
-
throw new Error(`Unknown hyperlink action: ${String(params.action)}`);
|
|
2775
|
-
}
|
|
2776
|
-
}
|
|
2777
|
-
function exportToJson(ctx, params) {
|
|
2778
|
-
const document = buildPptxJsonDocument(ctx.pptxData, { generator: "pptx-viewer-mcp" });
|
|
2779
|
-
const json = JSON.stringify(document, null, params.pretty === false ? void 0 : 2);
|
|
2780
|
-
return {
|
|
2781
|
-
pptxData: ctx.pptxData,
|
|
2782
|
-
dirty: false,
|
|
2783
|
-
result: {
|
|
2784
|
-
json,
|
|
2785
|
-
slideCount: document.slideCount,
|
|
2786
|
-
byteSize: new TextEncoder().encode(json).byteLength,
|
|
2787
|
-
assets: document.assets
|
|
2788
|
-
}
|
|
2789
|
-
};
|
|
2790
|
-
}
|
|
2791
|
-
function importFromJson(ctx, params) {
|
|
2792
|
-
const imported = deserializePptxFromJson(params.json);
|
|
2793
|
-
applyImportedPptxData(ctx.pptxData, imported);
|
|
2794
|
-
return {
|
|
2795
|
-
pptxData: ctx.pptxData,
|
|
2796
|
-
dirty: true,
|
|
2797
|
-
result: {
|
|
2798
|
-
slideCount: ctx.pptxData.slides.length,
|
|
2799
|
-
width: ctx.pptxData.width,
|
|
2800
|
-
height: ctx.pptxData.height
|
|
2801
|
-
}
|
|
2802
|
-
};
|
|
2803
|
-
}
|
|
2804
|
-
function getLayouts(ctx) {
|
|
2805
|
-
const layouts = [];
|
|
2806
|
-
if (ctx.pptxData.slideMasters) {
|
|
2807
|
-
for (const master of ctx.pptxData.slideMasters) {
|
|
2808
|
-
if (master.layouts) {
|
|
2809
|
-
for (const layout of master.layouts) {
|
|
2810
|
-
layouts.push({
|
|
2811
|
-
name: layout.name ?? "Unknown",
|
|
2812
|
-
path: layout.path
|
|
2813
|
-
});
|
|
2814
|
-
}
|
|
2815
|
-
}
|
|
2816
|
-
}
|
|
2817
|
-
}
|
|
2818
|
-
if (ctx.pptxData.layoutOptions) {
|
|
2819
|
-
for (const opt of ctx.pptxData.layoutOptions) {
|
|
2820
|
-
if (!layouts.some((l) => l.path === opt.path)) {
|
|
2821
|
-
layouts.push({ name: opt.name, path: opt.path, type: opt.type });
|
|
2822
|
-
}
|
|
2823
|
-
}
|
|
2824
|
-
}
|
|
2825
|
-
return {
|
|
2826
|
-
pptxData: ctx.pptxData,
|
|
2827
|
-
dirty: false,
|
|
2828
|
-
result: { layouts, count: layouts.length }
|
|
2829
|
-
};
|
|
2830
|
-
}
|
|
2831
|
-
function applyLayout(ctx, params) {
|
|
2832
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2833
|
-
if (err) {
|
|
2834
|
-
throw new Error(err);
|
|
2835
|
-
}
|
|
2836
|
-
let layout;
|
|
2837
|
-
if (params.layoutName) {
|
|
2838
|
-
layout = findLayoutByName(ctx.pptxData, params.layoutName);
|
|
2839
|
-
} else if (params.layoutType) {
|
|
2840
|
-
layout = findLayoutByType(ctx.pptxData, params.layoutType);
|
|
2841
|
-
} else {
|
|
2842
|
-
throw new Error("Either layoutName or layoutType must be provided.");
|
|
2843
|
-
}
|
|
2844
|
-
if (!layout) {
|
|
2845
|
-
throw new Error(
|
|
2846
|
-
`Layout not found: ${params.layoutName ?? params.layoutType}. Use get_layouts to see available layouts.`
|
|
2847
|
-
);
|
|
2848
|
-
}
|
|
2849
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2850
|
-
slide.layoutName = layout.name;
|
|
2851
|
-
if (layout.path) {
|
|
2852
|
-
slide.layoutPath = layout.path;
|
|
2853
|
-
}
|
|
2854
|
-
const master = ctx.pptxData.slideMasters?.find(
|
|
2855
|
-
(candidate) => candidate.layouts?.some((definition2) => definition2.path === layout.path)
|
|
2856
|
-
);
|
|
2857
|
-
const definition = master?.layouts?.find((candidate) => candidate.path === layout.path);
|
|
2858
|
-
for (const frame of definition?.placeholders ?? []) {
|
|
2859
|
-
if (["dt", "ftr", "sldnum", "hdr"].includes(frame.type)) {
|
|
2860
|
-
continue;
|
|
2861
|
-
}
|
|
2862
|
-
const ph = {
|
|
2863
|
-
"@_type": frame.type === "ctrtitle" ? "ctrTitle" : frame.type,
|
|
2864
|
-
...frame.idx !== void 0 ? { "@_idx": frame.idx } : {}
|
|
2865
|
-
};
|
|
2866
|
-
if (slide.elements.some((element) => {
|
|
2867
|
-
const nv = element.rawXml?.["p:nvSpPr"];
|
|
2868
|
-
const nvPr = nv?.["p:nvPr"];
|
|
2869
|
-
const existing = nvPr?.["p:ph"];
|
|
2870
|
-
return element.placeholderType === frame.type && String(existing?.["@_idx"] ?? "0") === String(frame.idx ?? "0");
|
|
2871
|
-
})) {
|
|
2872
|
-
continue;
|
|
2873
|
-
}
|
|
2874
|
-
const inherited = master?.placeholders?.find(
|
|
2875
|
-
(candidate) => candidate.type === frame.type && (candidate.idx ?? "0") === (frame.idx ?? "0")
|
|
2876
|
-
) ?? master?.placeholders?.find((candidate) => candidate.type === frame.type);
|
|
2877
|
-
slide.elements.push({
|
|
2878
|
-
id: generateElementId(),
|
|
2879
|
-
type: "text",
|
|
2880
|
-
placeholderType: frame.type,
|
|
2881
|
-
x: frame.x ?? inherited?.x ?? 0,
|
|
2882
|
-
y: frame.y ?? inherited?.y ?? 0,
|
|
2883
|
-
width: frame.width ?? inherited?.width ?? ctx.pptxData.width,
|
|
2884
|
-
height: frame.height ?? inherited?.height ?? ctx.pptxData.height,
|
|
2885
|
-
text: "",
|
|
2886
|
-
textSegments: [{ text: "", style: {} }],
|
|
2887
|
-
rawXml: {
|
|
2888
|
-
"p:nvSpPr": {
|
|
2889
|
-
"p:cNvPr": { "@_name": frame.type },
|
|
2890
|
-
"p:cNvSpPr": {},
|
|
2891
|
-
"p:nvPr": { "p:ph": ph }
|
|
2892
|
-
},
|
|
2893
|
-
"p:spPr": {}
|
|
2894
|
-
}
|
|
2895
|
-
});
|
|
2896
|
-
}
|
|
2897
|
-
return {
|
|
2898
|
-
pptxData: ctx.pptxData,
|
|
2899
|
-
dirty: true,
|
|
2900
|
-
result: { slideIndex: params.slideIndex, layoutName: layout.name ?? "Unknown" }
|
|
2901
|
-
};
|
|
2902
|
-
}
|
|
2903
|
-
function setElementLockT(ctx, params) {
|
|
2904
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
2905
|
-
if (err) {
|
|
2906
|
-
throw new Error(err);
|
|
2907
|
-
}
|
|
2908
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
2909
|
-
const idx = slide.elements.findIndex((e) => e.id === params.elementId);
|
|
2910
|
-
if (idx < 0) {
|
|
2911
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
2912
|
-
}
|
|
2913
|
-
const extraLocks = {};
|
|
2914
|
-
if (params.noMove !== void 0) {
|
|
2915
|
-
extraLocks["noMove"] = params.noMove;
|
|
2916
|
-
}
|
|
2917
|
-
if (params.noResize !== void 0) {
|
|
2918
|
-
extraLocks["noResize"] = params.noResize;
|
|
2919
|
-
}
|
|
2920
|
-
if (params.noRotation !== void 0) {
|
|
2921
|
-
extraLocks["noRotation"] = params.noRotation;
|
|
2922
|
-
}
|
|
2923
|
-
if (params.noSelect !== void 0) {
|
|
2924
|
-
extraLocks["noSelect"] = params.noSelect;
|
|
2925
|
-
}
|
|
2926
|
-
if (params.noTextEdit !== void 0) {
|
|
2927
|
-
extraLocks["noTextEdit"] = params.noTextEdit;
|
|
2928
|
-
}
|
|
2929
|
-
const updated = setElementLocked(slide.elements[idx], params.locked, extraLocks);
|
|
2930
|
-
slide.elements[idx] = updated;
|
|
2931
|
-
return {
|
|
2932
|
-
pptxData: ctx.pptxData,
|
|
2933
|
-
dirty: true,
|
|
2934
|
-
result: { elementId: params.elementId, locked: params.locked }
|
|
2935
|
-
};
|
|
2936
|
-
}
|
|
2937
|
-
|
|
2938
|
-
// src/tools/metadata-tools.ts
|
|
2939
|
-
function getMetadata(ctx) {
|
|
2940
|
-
return {
|
|
2941
|
-
pptxData: ctx.pptxData,
|
|
2942
|
-
dirty: false,
|
|
2943
|
-
result: {
|
|
2944
|
-
coreProperties: ctx.pptxData.coreProperties,
|
|
2945
|
-
appProperties: ctx.pptxData.appProperties,
|
|
2946
|
-
customProperties: ctx.pptxData.customProperties,
|
|
2947
|
-
slideCount: ctx.pptxData.slides.length
|
|
2948
|
-
}
|
|
2949
|
-
};
|
|
2950
|
-
}
|
|
2951
|
-
function updateMetadata(ctx, params) {
|
|
2952
|
-
const updated = [];
|
|
2953
|
-
if (params.title !== void 0 || params.subject !== void 0 || params.creator !== void 0 || params.keywords !== void 0 || params.description !== void 0 || params.lastModifiedBy !== void 0 || params.category !== void 0) {
|
|
2954
|
-
if (!ctx.pptxData.coreProperties) {
|
|
2955
|
-
ctx.pptxData.coreProperties = {};
|
|
2956
|
-
}
|
|
2957
|
-
const cp = ctx.pptxData.coreProperties;
|
|
2958
|
-
if (params.title !== void 0) {
|
|
2959
|
-
cp.title = params.title;
|
|
2960
|
-
updated.push("title");
|
|
2961
|
-
}
|
|
2962
|
-
if (params.subject !== void 0) {
|
|
2963
|
-
cp.subject = params.subject;
|
|
2964
|
-
updated.push("subject");
|
|
2965
|
-
}
|
|
2966
|
-
if (params.creator !== void 0) {
|
|
2967
|
-
cp.creator = params.creator;
|
|
2968
|
-
updated.push("creator");
|
|
2969
|
-
}
|
|
2970
|
-
if (params.keywords !== void 0) {
|
|
2971
|
-
cp.keywords = params.keywords;
|
|
2972
|
-
updated.push("keywords");
|
|
2973
|
-
}
|
|
2974
|
-
if (params.description !== void 0) {
|
|
2975
|
-
cp.description = params.description;
|
|
2976
|
-
updated.push("description");
|
|
2977
|
-
}
|
|
2978
|
-
if (params.lastModifiedBy !== void 0) {
|
|
2979
|
-
cp.lastModifiedBy = params.lastModifiedBy;
|
|
2980
|
-
updated.push("lastModifiedBy");
|
|
2981
|
-
}
|
|
2982
|
-
if (params.category !== void 0) {
|
|
2983
|
-
cp.category = params.category;
|
|
2984
|
-
updated.push("category");
|
|
2985
|
-
}
|
|
2986
|
-
}
|
|
2987
|
-
if (params.company !== void 0 || params.manager !== void 0) {
|
|
2988
|
-
if (!ctx.pptxData.appProperties) {
|
|
2989
|
-
ctx.pptxData.appProperties = {};
|
|
2990
|
-
}
|
|
2991
|
-
const ap = ctx.pptxData.appProperties;
|
|
2992
|
-
if (params.company !== void 0) {
|
|
2993
|
-
ap.company = params.company;
|
|
2994
|
-
updated.push("company");
|
|
2995
|
-
}
|
|
2996
|
-
if (params.manager !== void 0) {
|
|
2997
|
-
ap.manager = params.manager;
|
|
2998
|
-
updated.push("manager");
|
|
2999
|
-
}
|
|
3000
|
-
}
|
|
3001
|
-
if (params.customProperties) {
|
|
3002
|
-
if (!ctx.pptxData.customProperties) {
|
|
3003
|
-
ctx.pptxData.customProperties = [];
|
|
3004
|
-
}
|
|
3005
|
-
for (const cp of params.customProperties) {
|
|
3006
|
-
const valueStr = String(cp.value);
|
|
3007
|
-
const vtType = typeof cp.value === "number" ? "i4" : typeof cp.value === "boolean" ? "bool" : "lpwstr";
|
|
3008
|
-
const existing = ctx.pptxData.customProperties.find((p) => p.name === cp.name);
|
|
3009
|
-
if (existing) {
|
|
3010
|
-
existing.value = valueStr;
|
|
3011
|
-
existing.type = vtType;
|
|
3012
|
-
} else {
|
|
3013
|
-
ctx.pptxData.customProperties.push({ name: cp.name, value: valueStr, type: vtType });
|
|
3014
|
-
}
|
|
3015
|
-
updated.push(`custom:${cp.name}`);
|
|
3016
|
-
}
|
|
3017
|
-
}
|
|
3018
|
-
return {
|
|
3019
|
-
pptxData: ctx.pptxData,
|
|
3020
|
-
dirty: updated.length > 0,
|
|
3021
|
-
result: { updated }
|
|
3022
|
-
};
|
|
3023
|
-
}
|
|
3024
|
-
function resolveOleElement(ctx, slideIndex, elementId) {
|
|
3025
|
-
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
3026
|
-
if (err) {
|
|
3027
|
-
throw new Error(err);
|
|
3028
|
-
}
|
|
3029
|
-
const slide = ctx.pptxData.slides[slideIndex];
|
|
3030
|
-
const index = slide.elements.findIndex((e) => e.id === elementId);
|
|
3031
|
-
if (index === -1) {
|
|
3032
|
-
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
3033
|
-
}
|
|
3034
|
-
const element = slide.elements[index];
|
|
3035
|
-
if (element.type !== "ole") {
|
|
3036
|
-
throw new Error(`Element '${elementId}' is not an OLE object.`);
|
|
3037
|
-
}
|
|
3038
|
-
return { slide, element, index };
|
|
3039
|
-
}
|
|
3040
|
-
function commitOleElement(slide, index, updated) {
|
|
3041
|
-
slide.elements.splice(index, 1, updated);
|
|
3042
|
-
slide.isDirty = true;
|
|
3043
|
-
}
|
|
3044
|
-
async function getOleContent(ctx, params) {
|
|
3045
|
-
const { element } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3046
|
-
const kind = await resolveOleEditorKindFromPayload(element);
|
|
3047
|
-
const base = { pptxData: ctx.pptxData, dirty: false };
|
|
3048
|
-
switch (kind) {
|
|
3049
|
-
case "sheet-xlsx":
|
|
3050
|
-
case "sheet-xls": {
|
|
3051
|
-
const sheet = await getOleSheetGrid(element);
|
|
3052
|
-
return { ...base, result: { elementId: element.id, kind, editable: true, sheet } };
|
|
3053
|
-
}
|
|
3054
|
-
case "document-docx":
|
|
3055
|
-
case "document-doc": {
|
|
3056
|
-
const paragraphs = await getOleDocumentParagraphs(element);
|
|
3057
|
-
return { ...base, result: { elementId: element.id, kind, editable: true, paragraphs } };
|
|
3058
|
-
}
|
|
3059
|
-
case "deck-pptx": {
|
|
3060
|
-
const deckSlides = await getOleNestedDeckDetail(element);
|
|
3061
|
-
return { ...base, result: { elementId: element.id, kind, editable: true, deckSlides } };
|
|
3062
|
-
}
|
|
3063
|
-
default:
|
|
3064
|
-
return {
|
|
3065
|
-
...base,
|
|
3066
|
-
result: {
|
|
3067
|
-
elementId: element.id,
|
|
3068
|
-
kind,
|
|
3069
|
-
editable: false,
|
|
3070
|
-
message: `This OLE object's content (${kind}) is not directly editable; use ole_replace_file to replace it wholesale.`
|
|
3071
|
-
}
|
|
3072
|
-
};
|
|
3073
|
-
}
|
|
3074
|
-
}
|
|
3075
|
-
async function setOleSheetCell(ctx, params) {
|
|
3076
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3077
|
-
const updated = await applyOleSheetCellEdit(element, {
|
|
3078
|
-
row: params.row,
|
|
3079
|
-
col: params.col,
|
|
3080
|
-
value: params.value
|
|
3081
|
-
});
|
|
3082
|
-
const changed = updated !== element;
|
|
3083
|
-
if (changed) {
|
|
3084
|
-
commitOleElement(slide, index, updated);
|
|
3085
|
-
}
|
|
3086
|
-
return {
|
|
3087
|
-
pptxData: ctx.pptxData,
|
|
3088
|
-
dirty: changed,
|
|
3089
|
-
result: { elementId: params.elementId, changed }
|
|
3090
|
-
};
|
|
3091
|
-
}
|
|
3092
|
-
async function setOleDocumentParagraph(ctx, params) {
|
|
3093
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3094
|
-
const updated = await applyOleDocumentParagraphEdit(element, params.paragraphIndex, params.text);
|
|
3095
|
-
const changed = updated !== element;
|
|
3096
|
-
if (changed) {
|
|
3097
|
-
commitOleElement(slide, index, updated);
|
|
3098
|
-
}
|
|
3099
|
-
return {
|
|
3100
|
-
pptxData: ctx.pptxData,
|
|
3101
|
-
dirty: changed,
|
|
3102
|
-
result: { elementId: params.elementId, changed }
|
|
3103
|
-
};
|
|
3104
|
-
}
|
|
3105
|
-
async function setOleDeckSlideTitle(ctx, params) {
|
|
3106
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3107
|
-
const updated = await applyOleNestedDeckElementTextEdit(
|
|
3108
|
-
element,
|
|
3109
|
-
params.deckSlideIndex,
|
|
3110
|
-
params.deckElementId,
|
|
3111
|
-
params.title
|
|
3112
|
-
);
|
|
3113
|
-
const changed = updated !== element;
|
|
3114
|
-
if (changed) {
|
|
3115
|
-
commitOleElement(slide, index, updated);
|
|
3116
|
-
}
|
|
3117
|
-
return {
|
|
3118
|
-
pptxData: ctx.pptxData,
|
|
3119
|
-
dirty: changed,
|
|
3120
|
-
result: { elementId: params.elementId, changed }
|
|
3121
|
-
};
|
|
3122
|
-
}
|
|
3123
|
-
async function setOleObjectNameT(ctx, params) {
|
|
3124
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3125
|
-
const updated = await setOleObjectName(element, params.name);
|
|
3126
|
-
commitOleElement(slide, index, updated);
|
|
3127
|
-
return {
|
|
3128
|
-
pptxData: ctx.pptxData,
|
|
3129
|
-
dirty: true,
|
|
3130
|
-
result: { elementId: params.elementId, changed: true }
|
|
3131
|
-
};
|
|
3132
|
-
}
|
|
3133
|
-
async function replaceOleFileT(ctx, params) {
|
|
3134
|
-
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3135
|
-
const parsed = parseDataUrlToBytes(params.fileData);
|
|
3136
|
-
if (!parsed) {
|
|
3137
|
-
throw new Error('fileData must be a base64 data URL, e.g. "data:<mime-type>;base64,<...>".');
|
|
3138
|
-
}
|
|
3139
|
-
const updated = await replaceOleFile(element, parsed.bytes, params.fileName);
|
|
3140
|
-
commitOleElement(slide, index, updated);
|
|
3141
|
-
return {
|
|
3142
|
-
pptxData: ctx.pptxData,
|
|
3143
|
-
dirty: true,
|
|
3144
|
-
result: { elementId: params.elementId, changed: true }
|
|
3145
|
-
};
|
|
3146
|
-
}
|
|
3147
|
-
|
|
3148
|
-
// src/tools/presentation-tools.ts
|
|
3149
|
-
function getPresentationProperties(ctx) {
|
|
3150
|
-
return {
|
|
3151
|
-
pptxData: ctx.pptxData,
|
|
3152
|
-
dirty: false,
|
|
3153
|
-
result: {
|
|
3154
|
-
properties: ctx.pptxData.presentationProperties,
|
|
3155
|
-
slideCount: ctx.pptxData.slides.length,
|
|
3156
|
-
width: ctx.pptxData.width,
|
|
3157
|
-
height: ctx.pptxData.height
|
|
3158
|
-
}
|
|
3159
|
-
};
|
|
3160
|
-
}
|
|
3161
|
-
function updatePresentationProperties(ctx, params) {
|
|
3162
|
-
if (!ctx.pptxData.presentationProperties) {
|
|
3163
|
-
ctx.pptxData.presentationProperties = {};
|
|
3164
|
-
}
|
|
3165
|
-
const pp = ctx.pptxData.presentationProperties;
|
|
3166
|
-
if (params.showType !== void 0) {
|
|
3167
|
-
pp.showType = params.showType;
|
|
3168
|
-
}
|
|
3169
|
-
if (params.loopContinuously !== void 0) {
|
|
3170
|
-
pp.loopContinuously = params.loopContinuously;
|
|
3171
|
-
}
|
|
3172
|
-
if (params.showWithNarration !== void 0) {
|
|
3173
|
-
pp.showWithNarration = params.showWithNarration;
|
|
3174
|
-
}
|
|
3175
|
-
if (params.showWithAnimation !== void 0) {
|
|
3176
|
-
pp.showWithAnimation = params.showWithAnimation;
|
|
3177
|
-
}
|
|
3178
|
-
if (params.advanceMode !== void 0) {
|
|
3179
|
-
pp.advanceMode = params.advanceMode;
|
|
3180
|
-
}
|
|
3181
|
-
if (params.showSlidesMode !== void 0) {
|
|
3182
|
-
pp.showSlidesMode = params.showSlidesMode;
|
|
3183
|
-
}
|
|
3184
|
-
if (params.showSlidesFrom !== void 0) {
|
|
3185
|
-
pp.showSlidesFrom = params.showSlidesFrom;
|
|
3186
|
-
}
|
|
3187
|
-
if (params.showSlidesTo !== void 0) {
|
|
3188
|
-
pp.showSlidesTo = params.showSlidesTo;
|
|
3189
|
-
}
|
|
3190
|
-
if (params.penColor !== void 0) {
|
|
3191
|
-
pp.penColor = params.penColor;
|
|
3192
|
-
}
|
|
3193
|
-
return {
|
|
3194
|
-
pptxData: ctx.pptxData,
|
|
3195
|
-
dirty: true,
|
|
3196
|
-
result: { properties: pp }
|
|
3197
|
-
};
|
|
3198
|
-
}
|
|
3199
|
-
function manageSections(ctx, params) {
|
|
3200
|
-
switch (params.action) {
|
|
3201
|
-
case "list": {
|
|
3202
|
-
const sections = (ctx.pptxData.sections ?? []).map((s) => ({
|
|
3203
|
-
id: s.id,
|
|
3204
|
-
name: s.name,
|
|
3205
|
-
slideIds: s.slideIds,
|
|
3206
|
-
collapsed: s.collapsed,
|
|
3207
|
-
color: s.color
|
|
3208
|
-
}));
|
|
3209
|
-
return { pptxData: ctx.pptxData, dirty: false, result: { action: "list", sections } };
|
|
3210
|
-
}
|
|
3211
|
-
case "add": {
|
|
3212
|
-
if (!params.name) {
|
|
3213
|
-
throw new Error("name is required for add action.");
|
|
3214
|
-
}
|
|
3215
|
-
const section = addSection(ctx.pptxData, params.name, params.slideIndices ?? []);
|
|
3216
|
-
return {
|
|
3217
|
-
pptxData: ctx.pptxData,
|
|
3218
|
-
dirty: true,
|
|
3219
|
-
result: {
|
|
3220
|
-
action: "add",
|
|
3221
|
-
section: { id: section.id, name: section.name, slideIds: section.slideIds }
|
|
3222
|
-
}
|
|
3223
|
-
};
|
|
3224
|
-
}
|
|
3225
|
-
case "remove": {
|
|
3226
|
-
if (!params.sectionId) {
|
|
3227
|
-
throw new Error("sectionId is required for remove action.");
|
|
3228
|
-
}
|
|
3229
|
-
const success = removeSection(ctx.pptxData, params.sectionId);
|
|
3230
|
-
return { pptxData: ctx.pptxData, dirty: success, result: { action: "remove", success } };
|
|
3231
|
-
}
|
|
3232
|
-
case "reorder": {
|
|
3233
|
-
if (!params.sectionIds) {
|
|
3234
|
-
throw new Error("sectionIds is required for reorder action.");
|
|
3235
|
-
}
|
|
3236
|
-
reorderSections(ctx.pptxData, params.sectionIds);
|
|
3237
|
-
return { pptxData: ctx.pptxData, dirty: true, result: { action: "reorder", success: true } };
|
|
3238
|
-
}
|
|
3239
|
-
case "moveSlides": {
|
|
3240
|
-
if (!params.sectionId) {
|
|
3241
|
-
throw new Error("sectionId is required for moveSlides action.");
|
|
3242
|
-
}
|
|
3243
|
-
if (!params.slideIndices) {
|
|
3244
|
-
throw new Error("slideIndices is required for moveSlides action.");
|
|
3245
|
-
}
|
|
3246
|
-
const success = moveSlidesToSection(ctx.pptxData, params.slideIndices, params.sectionId);
|
|
3247
|
-
return { pptxData: ctx.pptxData, dirty: success, result: { action: "moveSlides", success } };
|
|
3248
|
-
}
|
|
3249
|
-
case "getForSlide": {
|
|
3250
|
-
if (params.slideIndex === void 0) {
|
|
3251
|
-
throw new Error("slideIndex is required for getForSlide action.");
|
|
3252
|
-
}
|
|
3253
|
-
const section = getSectionForSlide(ctx.pptxData, params.slideIndex);
|
|
3254
|
-
const info = section ? { id: section.id, name: section.name, slideIds: section.slideIds } : null;
|
|
3255
|
-
return {
|
|
3256
|
-
pptxData: ctx.pptxData,
|
|
3257
|
-
dirty: false,
|
|
3258
|
-
result: { action: "getForSlide", section: info }
|
|
3259
|
-
};
|
|
3260
|
-
}
|
|
3261
|
-
default:
|
|
3262
|
-
throw new Error(`Unknown section action: ${String(params.action)}`);
|
|
3263
|
-
}
|
|
3264
|
-
}
|
|
3265
|
-
|
|
3266
|
-
// src/tools/slide-tools.ts
|
|
3267
|
-
function getSlide(ctx, params) {
|
|
3268
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3269
|
-
if (err) {
|
|
3270
|
-
throw new Error(err);
|
|
3271
|
-
}
|
|
3272
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3273
|
-
return {
|
|
3274
|
-
pptxData: ctx.pptxData,
|
|
3275
|
-
dirty: false,
|
|
3276
|
-
result: {
|
|
3277
|
-
slideIndex: params.slideIndex,
|
|
3278
|
-
slideNumber: slide.slideNumber,
|
|
3279
|
-
hidden: slide.hidden ?? false,
|
|
3280
|
-
layoutName: slide.layoutName,
|
|
3281
|
-
backgroundColor: slide.backgroundColor,
|
|
3282
|
-
notes: slide.notes ?? "",
|
|
3283
|
-
commentCount: slide.comments?.length ?? 0,
|
|
3284
|
-
elements: slide.elements.map(describeElement)
|
|
3285
|
-
}
|
|
3286
|
-
};
|
|
3287
|
-
}
|
|
3288
|
-
function addSlide(ctx, params) {
|
|
3289
|
-
const { slides } = ctx.pptxData;
|
|
3290
|
-
const insertAt = params.insertAfterIndex !== void 0 && params.insertAfterIndex >= 0 ? Math.min(params.insertAfterIndex + 1, slides.length) : slides.length;
|
|
3291
|
-
const newSlide = {
|
|
3292
|
-
id: generateSlideId(),
|
|
3293
|
-
rId: "",
|
|
3294
|
-
slideNumber: insertAt + 1,
|
|
3295
|
-
elements: [],
|
|
3296
|
-
backgroundColor: params.backgroundColor
|
|
3297
|
-
};
|
|
3298
|
-
slides.splice(insertAt, 0, newSlide);
|
|
3299
|
-
slides.forEach((s, i) => {
|
|
3300
|
-
s.slideNumber = i + 1;
|
|
3301
|
-
});
|
|
3302
|
-
return {
|
|
3303
|
-
pptxData: ctx.pptxData,
|
|
3304
|
-
dirty: true,
|
|
3305
|
-
result: { newSlideIndex: insertAt, slideCount: slides.length }
|
|
3306
|
-
};
|
|
3307
|
-
}
|
|
3308
|
-
function deleteSlides(ctx, params) {
|
|
3309
|
-
const { slides } = ctx.pptxData;
|
|
3310
|
-
if (!params.slideIndexes || params.slideIndexes.length === 0) {
|
|
3311
|
-
throw new Error("slideIndexes is required for the delete action.");
|
|
3312
|
-
}
|
|
3313
|
-
const indexSet = new Set(params.slideIndexes);
|
|
3314
|
-
const invalid = params.slideIndexes.filter((i) => i < 0 || i >= slides.length);
|
|
3315
|
-
if (invalid.length > 0) {
|
|
3316
|
-
throw new Error(
|
|
3317
|
-
`Invalid slide indexes: ${invalid.join(", ")}. Valid range: 0\u2013${slides.length - 1}.`
|
|
3318
|
-
);
|
|
3319
|
-
}
|
|
3320
|
-
if (indexSet.size >= slides.length) {
|
|
3321
|
-
throw new Error("Cannot delete all slides. At least one slide must remain.");
|
|
3322
|
-
}
|
|
3323
|
-
ctx.pptxData.slides = slides.filter((_, i) => !indexSet.has(i));
|
|
3324
|
-
ctx.pptxData.slides.forEach((s, i) => {
|
|
3325
|
-
s.slideNumber = i + 1;
|
|
3326
|
-
});
|
|
3327
|
-
return {
|
|
3328
|
-
pptxData: ctx.pptxData,
|
|
3329
|
-
dirty: true,
|
|
3330
|
-
result: { deletedCount: indexSet.size, slideCount: ctx.pptxData.slides.length }
|
|
3331
|
-
};
|
|
3332
|
-
}
|
|
3333
|
-
function reorderSlides(ctx, params) {
|
|
3334
|
-
const { slides } = ctx.pptxData;
|
|
3335
|
-
if (!params.newOrder || params.newOrder.length !== slides.length) {
|
|
3336
|
-
throw new Error(
|
|
3337
|
-
`newOrder must have exactly ${slides.length} indexes. Got ${params.newOrder?.length ?? 0}.`
|
|
3338
|
-
);
|
|
3339
|
-
}
|
|
3340
|
-
const sorted = [...params.newOrder].sort((a, b) => a - b);
|
|
3341
|
-
const expected = slides.map((_, i) => i);
|
|
3342
|
-
if (JSON.stringify(sorted) !== JSON.stringify(expected)) {
|
|
3343
|
-
throw new Error(
|
|
3344
|
-
`newOrder must contain each index from 0 to ${slides.length - 1} exactly once.`
|
|
3345
|
-
);
|
|
3346
|
-
}
|
|
3347
|
-
ctx.pptxData.slides = params.newOrder.map((idx) => slides[idx]);
|
|
3348
|
-
ctx.pptxData.slides.forEach((s, i) => {
|
|
3349
|
-
s.slideNumber = i + 1;
|
|
3350
|
-
});
|
|
3351
|
-
return {
|
|
3352
|
-
pptxData: ctx.pptxData,
|
|
3353
|
-
dirty: true,
|
|
3354
|
-
result: { slideCount: ctx.pptxData.slides.length }
|
|
3355
|
-
};
|
|
3356
|
-
}
|
|
3357
|
-
function duplicateSlide(ctx, params) {
|
|
3358
|
-
const { slides } = ctx.pptxData;
|
|
3359
|
-
const err = validateSlideIndex(params.slideIndex, slides.length);
|
|
3360
|
-
if (err) {
|
|
3361
|
-
throw new Error(err);
|
|
3362
|
-
}
|
|
3363
|
-
const original = slides[params.slideIndex];
|
|
3364
|
-
const clone = structuredClone(original);
|
|
3365
|
-
clone.id = generateSlideId();
|
|
3366
|
-
clone.rId = "";
|
|
3367
|
-
for (const el of clone.elements) {
|
|
3368
|
-
el.id = generateElementId();
|
|
3369
|
-
}
|
|
3370
|
-
const insertIndex = params.targetIndex ?? params.slideIndex + 1;
|
|
3371
|
-
slides.splice(insertIndex, 0, clone);
|
|
3372
|
-
slides.forEach((s, i) => {
|
|
3373
|
-
s.slideNumber = i + 1;
|
|
3374
|
-
});
|
|
3375
|
-
return {
|
|
3376
|
-
pptxData: ctx.pptxData,
|
|
3377
|
-
dirty: true,
|
|
3378
|
-
result: { newSlideIndex: insertIndex, slideCount: slides.length }
|
|
3379
|
-
};
|
|
3380
|
-
}
|
|
3381
|
-
function updateSlideProperties(ctx, params) {
|
|
3382
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3383
|
-
if (err) {
|
|
3384
|
-
throw new Error(err);
|
|
3385
|
-
}
|
|
3386
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3387
|
-
if (params.backgroundColor !== void 0) {
|
|
3388
|
-
slide.backgroundColor = params.backgroundColor;
|
|
3389
|
-
}
|
|
3390
|
-
if (params.backgroundGradient !== void 0) {
|
|
3391
|
-
slide.backgroundGradient = params.backgroundGradient;
|
|
3392
|
-
}
|
|
3393
|
-
if (params.backgroundImage !== void 0) {
|
|
3394
|
-
slide.backgroundImage = params.backgroundImage;
|
|
3395
|
-
}
|
|
3396
|
-
if (params.notes !== void 0) {
|
|
3397
|
-
slide.notes = params.notes;
|
|
3398
|
-
}
|
|
3399
|
-
if (params.hidden !== void 0) {
|
|
3400
|
-
slide.hidden = params.hidden;
|
|
3401
|
-
}
|
|
3402
|
-
return {
|
|
3403
|
-
pptxData: ctx.pptxData,
|
|
3404
|
-
dirty: true,
|
|
3405
|
-
result: { slideIndex: params.slideIndex }
|
|
3406
|
-
};
|
|
3407
|
-
}
|
|
3408
|
-
function setSlideTransition(ctx, params) {
|
|
3409
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3410
|
-
if (err) {
|
|
3411
|
-
throw new Error(err);
|
|
3412
|
-
}
|
|
3413
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3414
|
-
if (params.type === "none") {
|
|
3415
|
-
slide.transition = void 0;
|
|
3416
|
-
} else {
|
|
3417
|
-
const transition = {
|
|
3418
|
-
type: params.type
|
|
3419
|
-
};
|
|
3420
|
-
if (params.durationMs !== void 0) {
|
|
3421
|
-
transition.durationMs = params.durationMs;
|
|
3422
|
-
}
|
|
3423
|
-
if (params.direction !== void 0) {
|
|
3424
|
-
transition.direction = params.direction;
|
|
3425
|
-
}
|
|
3426
|
-
if (params.advanceOnClick !== void 0) {
|
|
3427
|
-
transition.advanceOnClick = params.advanceOnClick;
|
|
3428
|
-
}
|
|
3429
|
-
if (params.advanceAfterMs !== void 0) {
|
|
3430
|
-
transition.advanceAfterMs = params.advanceAfterMs;
|
|
3431
|
-
}
|
|
3432
|
-
slide.transition = transition;
|
|
3433
|
-
}
|
|
3434
|
-
return {
|
|
3435
|
-
pptxData: ctx.pptxData,
|
|
3436
|
-
dirty: true,
|
|
3437
|
-
result: { slideIndex: params.slideIndex, transitionType: params.type }
|
|
3438
|
-
};
|
|
3439
|
-
}
|
|
3440
|
-
function setCanvasSize(ctx, params) {
|
|
3441
|
-
ctx.pptxData.width = params.width;
|
|
3442
|
-
ctx.pptxData.height = params.height;
|
|
3443
|
-
if (ctx.pptxData.widthEmu !== void 0) {
|
|
3444
|
-
ctx.pptxData.widthEmu = Math.round(params.width * 12700);
|
|
3445
|
-
}
|
|
3446
|
-
if (ctx.pptxData.heightEmu !== void 0) {
|
|
3447
|
-
ctx.pptxData.heightEmu = Math.round(params.height * 12700);
|
|
3448
|
-
}
|
|
3449
|
-
return {
|
|
3450
|
-
pptxData: ctx.pptxData,
|
|
3451
|
-
dirty: true,
|
|
3452
|
-
result: { canvasWidth: params.width, canvasHeight: params.height }
|
|
3453
|
-
};
|
|
3454
|
-
}
|
|
3455
|
-
function extractNodes(data) {
|
|
3456
|
-
if (!data.nodes) {
|
|
3457
|
-
return [];
|
|
3458
|
-
}
|
|
3459
|
-
return data.nodes.map((n) => ({
|
|
3460
|
-
id: n.id,
|
|
3461
|
-
text: n.text ?? "",
|
|
3462
|
-
children: n.children?.map((c) => ({ id: c.id, text: c.text ?? "" }))
|
|
3463
|
-
}));
|
|
3464
|
-
}
|
|
3465
|
-
function manageSmartArt(ctx, params) {
|
|
3466
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3467
|
-
if (err) {
|
|
3468
|
-
throw new Error(err);
|
|
3469
|
-
}
|
|
3470
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3471
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
3472
|
-
if (!el) {
|
|
3473
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
3474
|
-
}
|
|
3475
|
-
if (el.type !== "smartArt") {
|
|
3476
|
-
throw new Error(`Element '${params.elementId}' is not a SmartArt.`);
|
|
3477
|
-
}
|
|
3478
|
-
const smartArt = el;
|
|
3479
|
-
if (!smartArt.smartArtData) {
|
|
3480
|
-
throw new Error(`SmartArt '${params.elementId}' has no data.`);
|
|
3481
|
-
}
|
|
3482
|
-
switch (params.action) {
|
|
3483
|
-
case "getNodes": {
|
|
3484
|
-
return {
|
|
3485
|
-
pptxData: ctx.pptxData,
|
|
3486
|
-
dirty: false,
|
|
3487
|
-
result: {
|
|
3488
|
-
action: "getNodes",
|
|
3489
|
-
elementId: params.elementId,
|
|
3490
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
3491
|
-
}
|
|
3492
|
-
};
|
|
3493
|
-
}
|
|
3494
|
-
case "addNode": {
|
|
3495
|
-
smartArt.smartArtData = addSmartArtNode(
|
|
3496
|
-
smartArt.smartArtData,
|
|
3497
|
-
params.text ?? "",
|
|
3498
|
-
params.afterNodeId
|
|
3499
|
-
);
|
|
3500
|
-
return {
|
|
3501
|
-
pptxData: ctx.pptxData,
|
|
3502
|
-
dirty: true,
|
|
3503
|
-
result: {
|
|
3504
|
-
action: "addNode",
|
|
3505
|
-
elementId: params.elementId,
|
|
3506
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
3507
|
-
}
|
|
3508
|
-
};
|
|
3509
|
-
}
|
|
3510
|
-
case "removeNode": {
|
|
3511
|
-
if (!params.nodeId) {
|
|
3512
|
-
throw new Error("nodeId is required for removeNode.");
|
|
3513
|
-
}
|
|
3514
|
-
smartArt.smartArtData = removeSmartArtNode(smartArt.smartArtData, params.nodeId);
|
|
3515
|
-
return {
|
|
3516
|
-
pptxData: ctx.pptxData,
|
|
3517
|
-
dirty: true,
|
|
3518
|
-
result: {
|
|
3519
|
-
action: "removeNode",
|
|
3520
|
-
elementId: params.elementId,
|
|
3521
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
3522
|
-
}
|
|
3523
|
-
};
|
|
3524
|
-
}
|
|
3525
|
-
case "updateNodeText": {
|
|
3526
|
-
if (!params.nodeId) {
|
|
3527
|
-
throw new Error("nodeId is required for updateNodeText.");
|
|
3528
|
-
}
|
|
3529
|
-
smartArt.smartArtData = updateSmartArtNodeText(
|
|
3530
|
-
smartArt.smartArtData,
|
|
3531
|
-
params.nodeId,
|
|
3532
|
-
params.text ?? ""
|
|
3533
|
-
);
|
|
3534
|
-
return {
|
|
3535
|
-
pptxData: ctx.pptxData,
|
|
3536
|
-
dirty: true,
|
|
3537
|
-
result: { action: "updateNodeText", elementId: params.elementId }
|
|
3538
|
-
};
|
|
3539
|
-
}
|
|
3540
|
-
case "reorderNode": {
|
|
3541
|
-
if (!params.nodeId) {
|
|
3542
|
-
throw new Error("nodeId is required for reorderNode.");
|
|
3543
|
-
}
|
|
3544
|
-
const dir = params.direction ?? 1;
|
|
3545
|
-
smartArt.smartArtData = reorderSmartArtNode(smartArt.smartArtData, params.nodeId, dir);
|
|
3546
|
-
return {
|
|
3547
|
-
pptxData: ctx.pptxData,
|
|
3548
|
-
dirty: true,
|
|
3549
|
-
result: {
|
|
3550
|
-
action: "reorderNode",
|
|
3551
|
-
elementId: params.elementId,
|
|
3552
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
3553
|
-
}
|
|
3554
|
-
};
|
|
3555
|
-
}
|
|
3556
|
-
case "promoteNode": {
|
|
3557
|
-
if (!params.nodeId) {
|
|
3558
|
-
throw new Error("nodeId is required for promoteNode.");
|
|
3559
|
-
}
|
|
3560
|
-
smartArt.smartArtData = promoteSmartArtNode(smartArt.smartArtData, params.nodeId);
|
|
3561
|
-
return {
|
|
3562
|
-
pptxData: ctx.pptxData,
|
|
3563
|
-
dirty: true,
|
|
3564
|
-
result: {
|
|
3565
|
-
action: "promoteNode",
|
|
3566
|
-
elementId: params.elementId,
|
|
3567
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
3568
|
-
}
|
|
3569
|
-
};
|
|
3570
|
-
}
|
|
3571
|
-
case "demoteNode": {
|
|
3572
|
-
if (!params.nodeId) {
|
|
3573
|
-
throw new Error("nodeId is required for demoteNode.");
|
|
3574
|
-
}
|
|
3575
|
-
smartArt.smartArtData = demoteSmartArtNode(smartArt.smartArtData, params.nodeId);
|
|
3576
|
-
return {
|
|
3577
|
-
pptxData: ctx.pptxData,
|
|
3578
|
-
dirty: true,
|
|
3579
|
-
result: {
|
|
3580
|
-
action: "demoteNode",
|
|
3581
|
-
elementId: params.elementId,
|
|
3582
|
-
nodes: extractNodes(smartArt.smartArtData)
|
|
3583
|
-
}
|
|
3584
|
-
};
|
|
3585
|
-
}
|
|
3586
|
-
case "decompose": {
|
|
3587
|
-
const bounds = {
|
|
3588
|
-
x: smartArt.x,
|
|
3589
|
-
y: smartArt.y,
|
|
3590
|
-
width: smartArt.width,
|
|
3591
|
-
height: smartArt.height
|
|
3592
|
-
};
|
|
3593
|
-
const decomposed = decomposeSmartArt(smartArt.smartArtData, bounds);
|
|
3594
|
-
if (!decomposed || decomposed.length === 0) {
|
|
3595
|
-
throw new Error("Failed to decompose SmartArt into shapes.");
|
|
3596
|
-
}
|
|
3597
|
-
const idx = slide.elements.indexOf(el);
|
|
3598
|
-
slide.elements.splice(idx, 1, ...decomposed);
|
|
3599
|
-
return {
|
|
3600
|
-
pptxData: ctx.pptxData,
|
|
3601
|
-
dirty: true,
|
|
3602
|
-
result: {
|
|
3603
|
-
action: "decompose",
|
|
3604
|
-
elementId: params.elementId,
|
|
3605
|
-
decomposedCount: decomposed.length
|
|
3606
|
-
}
|
|
3607
|
-
};
|
|
3608
|
-
}
|
|
3609
|
-
default:
|
|
3610
|
-
throw new Error(`Unknown SmartArt action: ${String(params.action)}`);
|
|
3611
|
-
}
|
|
3612
|
-
}
|
|
3613
|
-
function findTableElement(ctx, slideIndex, elementId) {
|
|
3614
|
-
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
3615
|
-
if (err) {
|
|
3616
|
-
throw new Error(err);
|
|
3617
|
-
}
|
|
3618
|
-
const slide = ctx.pptxData.slides[slideIndex];
|
|
3619
|
-
const el = slide.elements.find((e) => e.id === elementId);
|
|
3620
|
-
if (!el) {
|
|
3621
|
-
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
3622
|
-
}
|
|
3623
|
-
if (el.type !== "table") {
|
|
3624
|
-
throw new Error(`Element '${elementId}' is not a table.`);
|
|
3625
|
-
}
|
|
3626
|
-
return el;
|
|
3627
|
-
}
|
|
3628
|
-
function tableStyleIdsInUse(ctx) {
|
|
3629
|
-
const used = /* @__PURE__ */ new Set();
|
|
3630
|
-
for (const slide of ctx.pptxData.slides) {
|
|
3631
|
-
for (const el of slide.elements) {
|
|
3632
|
-
if (el.type === "table" && el.tableData?.tableStyleId) {
|
|
3633
|
-
used.add(normalizeTableStyleGuid(el.tableData.tableStyleId));
|
|
3634
|
-
}
|
|
3635
|
-
}
|
|
3636
|
-
}
|
|
3637
|
-
return used;
|
|
3638
|
-
}
|
|
3639
|
-
function setTableStyleSection(ctx, params) {
|
|
3640
|
-
if (!TABLE_STYLE_PART_SEQUENCE.includes(params.section)) {
|
|
3641
|
-
throw new Error(
|
|
3642
|
-
`Unknown table style section '${params.section}'. Valid sections: ${TABLE_STYLE_PART_SEQUENCE.join(", ")}.`
|
|
3643
|
-
);
|
|
3644
|
-
}
|
|
3645
|
-
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
3646
|
-
ctx.pptxData.tableStyleMap = map;
|
|
3647
|
-
const normalizedId = normalizeTableStyleGuid(params.styleId);
|
|
3648
|
-
const entry = map[normalizedId];
|
|
3649
|
-
if (!entry) {
|
|
3650
|
-
throw new Error(
|
|
3651
|
-
`Table style '${params.styleId}' is not loaded in this presentation. Use create_table_style to add a new one.`
|
|
3652
|
-
);
|
|
3653
|
-
}
|
|
3654
|
-
if (params.styleName !== void 0) {
|
|
3655
|
-
entry.styleName = params.styleName;
|
|
3656
|
-
}
|
|
3657
|
-
const mutableEntry = entry;
|
|
3658
|
-
if (params.fill !== void 0) {
|
|
3659
|
-
mutableEntry[`${params.section}Fill`] = params.fill;
|
|
3660
|
-
}
|
|
3661
|
-
if (params.text !== void 0) {
|
|
3662
|
-
mutableEntry[`${params.section}Text`] = params.text;
|
|
3663
|
-
}
|
|
3664
|
-
if (params.borders !== void 0) {
|
|
3665
|
-
mutableEntry[`${params.section}Borders`] = params.borders;
|
|
3666
|
-
}
|
|
3667
|
-
if (params.cell3D !== void 0) {
|
|
3668
|
-
mutableEntry[`${params.section}Cell3D`] = params.cell3D;
|
|
3669
|
-
}
|
|
3670
|
-
return {
|
|
3671
|
-
pptxData: ctx.pptxData,
|
|
3672
|
-
dirty: true,
|
|
3673
|
-
result: { styleId: normalizedId, section: params.section }
|
|
3674
|
-
};
|
|
3675
|
-
}
|
|
3676
|
-
function createTableStyle(ctx, params) {
|
|
3677
|
-
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
3678
|
-
ctx.pptxData.tableStyleMap = map;
|
|
3679
|
-
const basedOn = params.basedOnStyleId ? map[normalizeTableStyleGuid(params.basedOnStyleId)] : void 0;
|
|
3680
|
-
if (params.basedOnStyleId && !basedOn) {
|
|
3681
|
-
throw new Error(`basedOnStyleId '${params.basedOnStyleId}' is not a loaded table style.`);
|
|
3682
|
-
}
|
|
3683
|
-
const entry = createTableStyleEntry(map, { styleName: params.styleName, basedOn });
|
|
3684
|
-
addTableStyleToMap(map, entry);
|
|
3685
|
-
return {
|
|
3686
|
-
pptxData: ctx.pptxData,
|
|
3687
|
-
dirty: true,
|
|
3688
|
-
result: { styleId: entry.styleId },
|
|
3689
|
-
...params.setAsDefault ? { saveOptions: { tableStylesDefaultId: entry.styleId } } : {}
|
|
3690
|
-
};
|
|
3691
|
-
}
|
|
3692
|
-
function deleteTableStyle(ctx, params) {
|
|
3693
|
-
const normalizedId = normalizeTableStyleGuid(params.styleId);
|
|
3694
|
-
if (!params.force) {
|
|
3695
|
-
const used = tableStyleIdsInUse(ctx);
|
|
3696
|
-
if (used.has(normalizedId)) {
|
|
3697
|
-
throw new Error(
|
|
3698
|
-
`Table style '${params.styleId}' is assigned to at least one table on this deck. Reassign those tables first, or pass force: true.`
|
|
3699
|
-
);
|
|
3700
|
-
}
|
|
3701
|
-
}
|
|
3702
|
-
const map = ctx.pptxData.tableStyleMap ?? {};
|
|
3703
|
-
ctx.pptxData.tableStyleMap = map;
|
|
3704
|
-
deleteTableStyleFromMap(map, normalizedId);
|
|
3705
|
-
return {
|
|
3706
|
-
pptxData: ctx.pptxData,
|
|
3707
|
-
dirty: true,
|
|
3708
|
-
result: { deleted: true },
|
|
3709
|
-
saveOptions: { tableStylesToDelete: [normalizedId] }
|
|
3710
|
-
};
|
|
3711
|
-
}
|
|
3712
|
-
function assignTableStyle(ctx, params) {
|
|
3713
|
-
const el = findTableElement(ctx, params.slideIndex, params.elementId);
|
|
3714
|
-
if (!el.tableData) {
|
|
3715
|
-
throw new Error(`Table '${params.elementId}' has no tableData.`);
|
|
3716
|
-
}
|
|
3717
|
-
const styleId = params.styleId ?? ctx.pptxData.tableStylesDefaultId;
|
|
3718
|
-
if (!styleId) {
|
|
3719
|
-
throw new Error(
|
|
3720
|
-
"styleId was not provided and this presentation has no tableStylesDefaultId to fall back to."
|
|
3721
|
-
);
|
|
3722
|
-
}
|
|
3723
|
-
const normalizedId = normalizeTableStyleGuid(styleId);
|
|
3724
|
-
el.tableData.tableStyleId = normalizedId;
|
|
3725
|
-
if (params.bandedRows !== void 0) {
|
|
3726
|
-
el.tableData.bandedRows = params.bandedRows;
|
|
3727
|
-
}
|
|
3728
|
-
if (params.bandedColumns !== void 0) {
|
|
3729
|
-
el.tableData.bandedColumns = params.bandedColumns;
|
|
3730
|
-
}
|
|
3731
|
-
if (params.firstRowHeader !== void 0) {
|
|
3732
|
-
el.tableData.firstRowHeader = params.firstRowHeader;
|
|
3733
|
-
}
|
|
3734
|
-
if (params.lastRow !== void 0) {
|
|
3735
|
-
el.tableData.lastRow = params.lastRow;
|
|
3736
|
-
}
|
|
3737
|
-
if (params.firstCol !== void 0) {
|
|
3738
|
-
el.tableData.firstCol = params.firstCol;
|
|
3739
|
-
}
|
|
3740
|
-
if (params.lastCol !== void 0) {
|
|
3741
|
-
el.tableData.lastCol = params.lastCol;
|
|
3742
|
-
}
|
|
3743
|
-
return {
|
|
3744
|
-
pptxData: ctx.pptxData,
|
|
3745
|
-
dirty: true,
|
|
3746
|
-
result: { elementId: params.elementId, styleId: normalizedId }
|
|
3747
|
-
};
|
|
3748
|
-
}
|
|
3749
|
-
function updateTableCells(ctx, params) {
|
|
3750
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3751
|
-
if (err) {
|
|
3752
|
-
throw new Error(err);
|
|
3753
|
-
}
|
|
3754
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3755
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
3756
|
-
if (!el) {
|
|
3757
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
3758
|
-
}
|
|
3759
|
-
if (el.type !== "table") {
|
|
3760
|
-
throw new Error(`Element '${params.elementId}' is not a table.`);
|
|
3761
|
-
}
|
|
3762
|
-
const tbl = el;
|
|
3763
|
-
if (!tbl.tableData) {
|
|
3764
|
-
throw new Error(`Table '${params.elementId}' has no tableData.`);
|
|
3765
|
-
}
|
|
3766
|
-
let count = 0;
|
|
3767
|
-
for (const cellUpdate of params.cells) {
|
|
3768
|
-
const row = tbl.tableData.rows[cellUpdate.row];
|
|
3769
|
-
if (!row) {
|
|
3770
|
-
throw new Error(
|
|
3771
|
-
`Row ${cellUpdate.row} out of range (table has ${tbl.tableData.rows.length} rows).`
|
|
3772
|
-
);
|
|
3773
|
-
}
|
|
3774
|
-
const cell = row.cells[cellUpdate.col];
|
|
3775
|
-
if (!cell) {
|
|
3776
|
-
throw new Error(`Column ${cellUpdate.col} out of range (row has ${row.cells.length} cells).`);
|
|
3777
|
-
}
|
|
3778
|
-
cell.text = cellUpdate.text;
|
|
3779
|
-
count++;
|
|
3780
|
-
}
|
|
3781
|
-
return {
|
|
3782
|
-
pptxData: ctx.pptxData,
|
|
3783
|
-
dirty: true,
|
|
3784
|
-
result: { updatedCount: count }
|
|
3785
|
-
};
|
|
3786
|
-
}
|
|
3787
|
-
function manageTableStructure(ctx, params) {
|
|
3788
|
-
const err = validateSlideIndex(params.slideIndex, ctx.pptxData.slides.length);
|
|
3789
|
-
if (err) {
|
|
3790
|
-
throw new Error(err);
|
|
3791
|
-
}
|
|
3792
|
-
const slide = ctx.pptxData.slides[params.slideIndex];
|
|
3793
|
-
const el = slide.elements.find((e) => e.id === params.elementId);
|
|
3794
|
-
if (!el) {
|
|
3795
|
-
throw new Error(`Element '${params.elementId}' not found on slide ${params.slideIndex}.`);
|
|
3796
|
-
}
|
|
3797
|
-
if (el.type !== "table") {
|
|
3798
|
-
throw new Error(`Element '${params.elementId}' is not a table.`);
|
|
3799
|
-
}
|
|
3800
|
-
const tbl = el;
|
|
3801
|
-
if (!tbl.tableData) {
|
|
3802
|
-
throw new Error(`Table '${params.elementId}' has no tableData.`);
|
|
3803
|
-
}
|
|
3804
|
-
const { rows, columnWidths } = tbl.tableData;
|
|
3805
|
-
const source = { ...tbl, tableData: structuredClone(tbl.tableData) };
|
|
3806
|
-
let edit;
|
|
3807
|
-
const colCount = columnWidths.length;
|
|
3808
|
-
const rowCount = rows.length;
|
|
3809
|
-
switch (params.action) {
|
|
3810
|
-
case "insertRow": {
|
|
3811
|
-
const pos = params.position !== void 0 ? Math.min(Math.max(params.position, 0), rowCount) : rowCount;
|
|
3812
|
-
const newRow = {
|
|
3813
|
-
height: 40,
|
|
3814
|
-
cells: Array.from({ length: colCount }, (_, c) => ({
|
|
3815
|
-
text: params.cellTexts?.[c] ?? ""
|
|
3816
|
-
}))
|
|
3817
|
-
};
|
|
3818
|
-
rows.splice(pos, 0, newRow);
|
|
3819
|
-
edit = { axis: "row", action: "insert", index: pos };
|
|
3820
|
-
break;
|
|
3821
|
-
}
|
|
3822
|
-
case "deleteRow": {
|
|
3823
|
-
if (rowCount <= 1) {
|
|
3824
|
-
throw new Error("Cannot delete the last row of a table.");
|
|
3825
|
-
}
|
|
3826
|
-
const ref = params.referenceIndex ?? rowCount - 1;
|
|
3827
|
-
if (ref < 0 || ref >= rowCount) {
|
|
3828
|
-
throw new Error(`Row index ${ref} out of range (0\u2013${rowCount - 1}).`);
|
|
3829
|
-
}
|
|
3830
|
-
rows.splice(ref, 1);
|
|
3831
|
-
edit = { axis: "row", action: "delete", index: ref };
|
|
3832
|
-
break;
|
|
3833
|
-
}
|
|
3834
|
-
case "insertColumn": {
|
|
3835
|
-
const pos = params.position !== void 0 ? Math.min(Math.max(params.position, 0), colCount) : colCount;
|
|
3836
|
-
const newWidth = 1 / (colCount + 1);
|
|
3837
|
-
const scaleFactor = colCount / (colCount + 1);
|
|
3838
|
-
for (let i = 0; i < columnWidths.length; i++) {
|
|
3839
|
-
columnWidths[i] *= scaleFactor;
|
|
3840
|
-
}
|
|
3841
|
-
columnWidths.splice(pos, 0, newWidth);
|
|
3842
|
-
edit = { axis: "column", action: "insert", index: pos };
|
|
3843
|
-
for (let r = 0; r < rows.length; r++) {
|
|
3844
|
-
rows[r].cells.splice(pos, 0, {
|
|
3845
|
-
text: params.cellTexts?.[r] ?? ""
|
|
3846
|
-
});
|
|
3847
|
-
}
|
|
3848
|
-
break;
|
|
3849
|
-
}
|
|
3850
|
-
case "deleteColumn": {
|
|
3851
|
-
if (colCount <= 1) {
|
|
3852
|
-
throw new Error("Cannot delete the last column of a table.");
|
|
3853
|
-
}
|
|
3854
|
-
const ref = params.referenceIndex ?? colCount - 1;
|
|
3855
|
-
if (ref < 0 || ref >= colCount) {
|
|
3856
|
-
throw new Error(`Column index ${ref} out of range (0\u2013${colCount - 1}).`);
|
|
3857
|
-
}
|
|
3858
|
-
const removedWidth = columnWidths[ref];
|
|
3859
|
-
columnWidths.splice(ref, 1);
|
|
3860
|
-
edit = { axis: "column", action: "delete", index: ref };
|
|
3861
|
-
const remaining = columnWidths.length;
|
|
3862
|
-
if (remaining > 0) {
|
|
3863
|
-
const extra = removedWidth / remaining;
|
|
3864
|
-
for (let i = 0; i < columnWidths.length; i++) {
|
|
3865
|
-
columnWidths[i] += extra;
|
|
3866
|
-
}
|
|
3867
|
-
}
|
|
3868
|
-
for (const row of rows) {
|
|
3869
|
-
row.cells.splice(ref, 1);
|
|
3870
|
-
}
|
|
3871
|
-
break;
|
|
3872
|
-
}
|
|
3873
|
-
default: {
|
|
3874
|
-
throw new Error(`Unknown action: ${String(params.action)}`);
|
|
3875
|
-
}
|
|
3876
|
-
}
|
|
3877
|
-
const rawXml = rebuildTableStructureInRawXml(source, tbl.tableData, edit);
|
|
3878
|
-
if (rawXml) {
|
|
3879
|
-
tbl.rawXml = rawXml;
|
|
3880
|
-
}
|
|
3881
|
-
return {
|
|
3882
|
-
pptxData: ctx.pptxData,
|
|
3883
|
-
dirty: true,
|
|
3884
|
-
result: {
|
|
3885
|
-
rowCount: tbl.tableData.rows.length,
|
|
3886
|
-
columnCount: tbl.tableData.columnWidths.length
|
|
3887
|
-
}
|
|
3888
|
-
};
|
|
3889
|
-
}
|
|
3890
|
-
function findPlaceholdersT(ctx) {
|
|
3891
|
-
const placeholders = findPlaceholders(ctx.pptxData);
|
|
3892
|
-
return {
|
|
3893
|
-
pptxData: ctx.pptxData,
|
|
3894
|
-
dirty: false,
|
|
3895
|
-
result: { placeholders, count: placeholders.length }
|
|
3896
|
-
};
|
|
3897
|
-
}
|
|
3898
|
-
function applyTemplateT(ctx, params) {
|
|
3899
|
-
applyTemplate(ctx.pptxData, params.data);
|
|
3900
|
-
return {
|
|
3901
|
-
pptxData: ctx.pptxData,
|
|
3902
|
-
dirty: true,
|
|
3903
|
-
result: { applied: true, slideCount: ctx.pptxData.slides.length }
|
|
3904
|
-
};
|
|
3905
|
-
}
|
|
3906
|
-
function getThemeInfo(ctx) {
|
|
3907
|
-
const theme = ctx.pptxData.theme;
|
|
3908
|
-
return {
|
|
3909
|
-
pptxData: ctx.pptxData,
|
|
3910
|
-
dirty: false,
|
|
3911
|
-
result: {
|
|
3912
|
-
themeName: theme?.name,
|
|
3913
|
-
colorScheme: theme?.colorScheme,
|
|
3914
|
-
fontScheme: theme?.fontScheme,
|
|
3915
|
-
availablePresets: Object.keys(ThemePresets)
|
|
3916
|
-
}
|
|
3917
|
-
};
|
|
3918
|
-
}
|
|
3919
|
-
function applyThemePreset(ctx, params) {
|
|
3920
|
-
const preset = getThemePreset(params.presetName);
|
|
3921
|
-
if (!preset) {
|
|
3922
|
-
throw new Error(
|
|
3923
|
-
`Unknown theme preset: "${params.presetName}". Available: ${Object.keys(ThemePresets).join(", ")}`
|
|
3924
|
-
);
|
|
3925
|
-
}
|
|
3926
|
-
if (!ctx.pptxData.theme) {
|
|
3927
|
-
ctx.pptxData.theme = {};
|
|
3928
|
-
}
|
|
3929
|
-
const theme = ctx.pptxData.theme;
|
|
3930
|
-
theme.name = preset.name;
|
|
3931
|
-
theme.colorScheme = preset.colors;
|
|
3932
|
-
if (preset.fonts) {
|
|
3933
|
-
theme.fontScheme = preset.fonts;
|
|
3934
|
-
}
|
|
3935
|
-
return {
|
|
3936
|
-
pptxData: ctx.pptxData,
|
|
3937
|
-
dirty: true,
|
|
3938
|
-
result: {
|
|
3939
|
-
appliedPreset: params.presetName,
|
|
3940
|
-
colorScheme: theme.colorScheme
|
|
3941
|
-
}
|
|
3942
|
-
};
|
|
3943
|
-
}
|
|
3944
|
-
function updateThemeColors(ctx, params) {
|
|
3945
|
-
if (!ctx.pptxData.theme) {
|
|
3946
|
-
ctx.pptxData.theme = {};
|
|
3947
|
-
}
|
|
3948
|
-
const theme = ctx.pptxData.theme;
|
|
3949
|
-
if (!theme.colorScheme) {
|
|
3950
|
-
theme.colorScheme = {
|
|
3951
|
-
dk1: "#000000",
|
|
3952
|
-
lt1: "#FFFFFF",
|
|
3953
|
-
dk2: "#44546A",
|
|
3954
|
-
lt2: "#E7E6E6",
|
|
3955
|
-
accent1: "#4472C4",
|
|
3956
|
-
accent2: "#ED7D31",
|
|
3957
|
-
accent3: "#A5A5A5",
|
|
3958
|
-
accent4: "#FFC000",
|
|
3959
|
-
accent5: "#5B9BD5",
|
|
3960
|
-
accent6: "#70AD47",
|
|
3961
|
-
hlink: "#0563C1",
|
|
3962
|
-
folHlink: "#954F72"
|
|
3963
|
-
};
|
|
3964
|
-
}
|
|
3965
|
-
const cs = theme.colorScheme;
|
|
3966
|
-
for (const key of Object.keys(params)) {
|
|
3967
|
-
if (params[key] !== void 0) {
|
|
3968
|
-
cs[key] = params[key];
|
|
3969
|
-
}
|
|
3970
|
-
}
|
|
3971
|
-
return {
|
|
3972
|
-
pptxData: ctx.pptxData,
|
|
3973
|
-
dirty: true,
|
|
3974
|
-
result: { colorScheme: cs }
|
|
3975
|
-
};
|
|
3976
|
-
}
|
|
3977
|
-
function updateThemeFonts(ctx, params) {
|
|
3978
|
-
if (!ctx.pptxData.theme) {
|
|
3979
|
-
ctx.pptxData.theme = {};
|
|
3980
|
-
}
|
|
3981
|
-
const theme = ctx.pptxData.theme;
|
|
3982
|
-
if (!theme.fontScheme) {
|
|
3983
|
-
theme.fontScheme = {};
|
|
3984
|
-
}
|
|
3985
|
-
if (params.majorFont !== void 0) {
|
|
3986
|
-
theme.fontScheme.majorFont = { latin: params.majorFont };
|
|
3987
|
-
}
|
|
3988
|
-
if (params.minorFont !== void 0) {
|
|
3989
|
-
theme.fontScheme.minorFont = { latin: params.minorFont };
|
|
3990
|
-
}
|
|
3991
|
-
return {
|
|
3992
|
-
pptxData: ctx.pptxData,
|
|
3993
|
-
dirty: true,
|
|
3994
|
-
result: { fontScheme: theme.fontScheme }
|
|
3995
|
-
};
|
|
3996
|
-
}
|
|
3997
|
-
async function validatePresentation(rawBytes) {
|
|
3998
|
-
const result = await validatePptx(rawBytes);
|
|
3999
|
-
return {
|
|
4000
|
-
valid: result.valid,
|
|
4001
|
-
issueCount: result.issues.length,
|
|
4002
|
-
errors: result.issues.filter((i) => i.severity === "error").length,
|
|
4003
|
-
warnings: result.issues.filter((i) => i.severity === "warning").length,
|
|
4004
|
-
issues: result.issues
|
|
4005
|
-
};
|
|
4006
|
-
}
|
|
4007
|
-
async function repairPresentation(rawBytes) {
|
|
4008
|
-
const result = await repairPptx(rawBytes);
|
|
4009
|
-
return {
|
|
4010
|
-
result: {
|
|
4011
|
-
repairCount: result.repairs.length,
|
|
4012
|
-
repairs: result.repairs
|
|
4013
|
-
},
|
|
4014
|
-
repairedBytes: result.repaired
|
|
4015
|
-
};
|
|
4016
|
-
}
|
|
4017
|
-
var PPTX_MIME_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
4018
|
-
async function loadPresentation(filePath, execCtx) {
|
|
4019
|
-
const rawBytes = await execCtx.filesystem.readFile(filePath);
|
|
4020
|
-
if (execCtx.collaboration) {
|
|
4021
|
-
const room = execCtx.collaboration.getRoom(filePath);
|
|
4022
|
-
if (room) {
|
|
4023
|
-
const codec = execCtx.collaboration.getCodec(filePath);
|
|
4024
|
-
if (codec) {
|
|
4025
|
-
const currentBytes = await codec.dehydrate(room.ydoc);
|
|
4026
|
-
const handler2 = new PptxHandler();
|
|
4027
|
-
const pptxData2 = await handler2.load(currentBytes.buffer);
|
|
4028
|
-
return { pptxData: pptxData2, rawBytes };
|
|
4029
|
-
}
|
|
4030
|
-
}
|
|
4031
|
-
}
|
|
4032
|
-
const handler = new PptxHandler();
|
|
4033
|
-
const pptxData = await handler.load(rawBytes.buffer);
|
|
4034
|
-
return { pptxData, rawBytes };
|
|
4035
|
-
}
|
|
4036
|
-
async function savePresentation(filePath, pptxData, rawBytes, execCtx, tableStyleSaveOptions) {
|
|
4037
|
-
const handler = new PptxHandler();
|
|
4038
|
-
await handler.load(rawBytes.buffer);
|
|
4039
|
-
const outputBytes = await handler.save(pptxData.slides, {
|
|
4040
|
-
headerFooter: pptxData.headerFooter,
|
|
4041
|
-
// `pptxData.tableStyleMap` carries any in-memory table-style edits a
|
|
4042
|
-
// tool made (e.g. `set_table_style_section`, `create_table_style`);
|
|
4043
|
-
// without forwarding it here those edits were silently dropped on
|
|
4044
|
-
// save even though the core save pipeline already supports them.
|
|
4045
|
-
tableStyles: pptxData.tableStyleMap,
|
|
4046
|
-
...tableStyleSaveOptions
|
|
4047
|
-
});
|
|
4048
|
-
if (execCtx.collaboration) {
|
|
4049
|
-
const room = execCtx.collaboration.getRoom(filePath);
|
|
4050
|
-
if (room) {
|
|
4051
|
-
const codec = execCtx.collaboration.getCodec(filePath);
|
|
4052
|
-
if (codec) {
|
|
4053
|
-
const origin = execCtx.collaboration.agentOrigin(execCtx.agentName ?? "pptx-tool");
|
|
4054
|
-
await codec.hydrate(room.ydoc, outputBytes, origin);
|
|
4055
|
-
if (execCtx.viewer) {
|
|
4056
|
-
execCtx.viewer.replaceContent(filePath, outputBytes, {
|
|
4057
|
-
markDirty: false,
|
|
4058
|
-
mimeType: PPTX_MIME_TYPE
|
|
4059
|
-
});
|
|
4060
|
-
}
|
|
4061
|
-
return { savedToDisk: false, routedThroughCollaboration: true };
|
|
4062
|
-
}
|
|
4063
|
-
}
|
|
4064
|
-
}
|
|
4065
|
-
await execCtx.filesystem.writeFile(filePath, outputBytes);
|
|
4066
|
-
if (execCtx.viewer) {
|
|
4067
|
-
execCtx.viewer.replaceContent(filePath, outputBytes, {
|
|
4068
|
-
markDirty: false,
|
|
4069
|
-
mimeType: PPTX_MIME_TYPE
|
|
4070
|
-
});
|
|
4071
|
-
}
|
|
4072
|
-
return { savedToDisk: true, routedThroughCollaboration: false };
|
|
4073
|
-
}
|
|
4074
|
-
async function executeToolWithContext(filePath, execCtx, toolFn) {
|
|
4075
|
-
const { pptxData, rawBytes } = await loadPresentation(filePath, execCtx);
|
|
4076
|
-
const toolResult = await toolFn({ pptxData });
|
|
4077
|
-
if (toolResult.dirty) {
|
|
4078
|
-
const saveResult = await savePresentation(
|
|
4079
|
-
filePath,
|
|
4080
|
-
toolResult.pptxData,
|
|
4081
|
-
rawBytes,
|
|
4082
|
-
execCtx,
|
|
4083
|
-
toolResult.saveOptions
|
|
4084
|
-
);
|
|
4085
|
-
return { ...toolResult.result, ...saveResult };
|
|
4086
|
-
}
|
|
4087
|
-
return toolResult.result;
|
|
4088
|
-
}
|
|
932
|
+
var formatChartDataPoint = apiToolsChartFormattingTools.formatChartDataPoint;
|
|
933
|
+
var formatChartDataLabel = apiToolsChartFormattingTools.formatChartDataLabel;
|
|
934
|
+
var formatChartSeries = apiToolsChartFormattingTools.formatChartSeries;
|
|
935
|
+
var setChartHelperLineT = apiToolsChartFormattingTools.setChartHelperLineT;
|
|
936
|
+
var setChartColorMapOverrideT = apiToolsChartFormattingTools.setChartColorMapOverrideT;
|
|
937
|
+
var updateChart = apiToolsChartTools.updateChart;
|
|
938
|
+
var addChartSeriesT = apiToolsChartTools.addChartSeriesT;
|
|
939
|
+
var removeChartSeriesT = apiToolsChartTools.removeChartSeriesT;
|
|
940
|
+
var updateChartSeriesData = apiToolsChartTools.updateChartSeriesData;
|
|
941
|
+
var createChart = apiToolsChartTools.createChart;
|
|
942
|
+
var listChartUserShapesT = apiToolsChartUserShapeTools.listChartUserShapesT;
|
|
943
|
+
var addChartUserShapeT = apiToolsChartUserShapeTools.addChartUserShapeT;
|
|
944
|
+
var updateChartUserShapeT = apiToolsChartUserShapeTools.updateChartUserShapeT;
|
|
945
|
+
var removeChartUserShapeT = apiToolsChartUserShapeTools.removeChartUserShapeT;
|
|
946
|
+
var findText = apiToolsContentTools.findText;
|
|
947
|
+
var replaceText = apiToolsContentTools.replaceText;
|
|
948
|
+
var manageComments = apiToolsContentTools.manageComments;
|
|
949
|
+
var convertToMarkdown = apiToolsConversionTools.convertToMarkdown;
|
|
950
|
+
var addElement = apiToolsElementTools.addElement;
|
|
951
|
+
var updateElement = apiToolsElementTools.updateElement;
|
|
952
|
+
var renameElement = apiToolsElementTools.renameElement;
|
|
953
|
+
var deleteElements = apiToolsElementTools.deleteElements;
|
|
954
|
+
var arrangeElements = apiToolsElementTools.arrangeElements;
|
|
955
|
+
var cloneElement = apiToolsElementTools.cloneElement;
|
|
956
|
+
var setElementAnimation = apiToolsElementTools.setElementAnimation;
|
|
957
|
+
var groupElements = apiToolsElementTools.groupElements;
|
|
958
|
+
var ungroupElements = apiToolsElementTools.ungroupElements;
|
|
959
|
+
var batchUpdateElements = apiToolsElementTools.batchUpdateElements;
|
|
960
|
+
var exportToSvg = apiToolsExportTools.exportToSvg;
|
|
961
|
+
var exportSlideSvg = apiToolsExportTools.exportSlideSvg;
|
|
962
|
+
var replaceGeometry = apiToolsGeometryTools.replaceGeometry;
|
|
963
|
+
var manageHyperlinks = apiToolsHyperlinkTools.manageHyperlinks;
|
|
964
|
+
var exportToJson = apiToolsJsonTools.exportToJson;
|
|
965
|
+
var importFromJson = apiToolsJsonTools.importFromJson;
|
|
966
|
+
var getLayouts = apiToolsLayoutTools.getLayouts;
|
|
967
|
+
var applyLayout = apiToolsLayoutTools.applyLayout;
|
|
968
|
+
var setElementLockT = apiToolsLockTools.setElementLockT;
|
|
969
|
+
var getMetadata = apiToolsMetadataTools.getMetadata;
|
|
970
|
+
var updateMetadata = apiToolsMetadataTools.updateMetadata;
|
|
971
|
+
var getOleContent = apiToolsOleTools.getOleContent;
|
|
972
|
+
var setOleSheetCell = apiToolsOleTools.setOleSheetCell;
|
|
973
|
+
var setOleDocumentParagraph = apiToolsOleTools.setOleDocumentParagraph;
|
|
974
|
+
var setOleDeckSlideTitle = apiToolsOleTools.setOleDeckSlideTitle;
|
|
975
|
+
var setOleObjectNameT = apiToolsOleTools.setOleObjectNameT;
|
|
976
|
+
var replaceOleFileT = apiToolsOleTools.replaceOleFileT;
|
|
977
|
+
var getPresentationProperties = apiToolsPresentationTools.getPresentationProperties;
|
|
978
|
+
var updatePresentationProperties = apiToolsPresentationTools.updatePresentationProperties;
|
|
979
|
+
var manageSections = apiToolsSectionTools.manageSections;
|
|
980
|
+
var getSlide = apiToolsSlideTools.getSlide;
|
|
981
|
+
var addSlide = apiToolsSlideTools.addSlide;
|
|
982
|
+
var deleteSlides = apiToolsSlideTools.deleteSlides;
|
|
983
|
+
var reorderSlides = apiToolsSlideTools.reorderSlides;
|
|
984
|
+
var duplicateSlide = apiToolsSlideTools.duplicateSlide;
|
|
985
|
+
var updateSlideProperties = apiToolsSlideTools.updateSlideProperties;
|
|
986
|
+
var setSlideTransition = apiToolsSlideTools.setSlideTransition;
|
|
987
|
+
var setCanvasSize = apiToolsSlideTools.setCanvasSize;
|
|
988
|
+
var manageSmartArt = apiToolsSmartartTools.manageSmartArt;
|
|
989
|
+
apiToolsStyleTools.ALT_TEXT_ELEMENT_TYPES;
|
|
990
|
+
apiToolsStyleTools.TITLE_ELEMENT_TYPES;
|
|
991
|
+
apiToolsStyleTools.applyElementAltText;
|
|
992
|
+
apiToolsStyleTools.applyElementTitle;
|
|
993
|
+
var updateElementStyle = apiToolsStyleTools.updateElementStyle;
|
|
994
|
+
var runAccessibilityCheck = apiToolsStyleTools.runAccessibilityCheck;
|
|
995
|
+
var setTableStyleSection = apiToolsTableStyleTools.setTableStyleSection;
|
|
996
|
+
var createTableStyle = apiToolsTableStyleTools.createTableStyle;
|
|
997
|
+
var deleteTableStyle = apiToolsTableStyleTools.deleteTableStyle;
|
|
998
|
+
var assignTableStyle = apiToolsTableStyleTools.assignTableStyle;
|
|
999
|
+
var updateTableCells = apiToolsTableTools.updateTableCells;
|
|
1000
|
+
var manageTableStructure = apiToolsTableTools.manageTableStructure;
|
|
1001
|
+
var findPlaceholdersT = apiToolsTemplateTools.findPlaceholdersT;
|
|
1002
|
+
var applyTemplateT = apiToolsTemplateTools.applyTemplateT;
|
|
1003
|
+
var getThemeInfo = apiToolsThemeTools.getThemeInfo;
|
|
1004
|
+
var applyThemePreset = apiToolsThemeTools.applyThemePreset;
|
|
1005
|
+
var updateThemeColors = apiToolsThemeTools.updateThemeColors;
|
|
1006
|
+
var updateThemeFonts = apiToolsThemeTools.updateThemeFonts;
|
|
1007
|
+
var validatePresentation = apiToolsValidationTools.validatePresentation;
|
|
1008
|
+
var repairPresentation = apiToolsValidationTools.repairPresentation;
|
|
1009
|
+
apiExecution.loadPresentation;
|
|
1010
|
+
apiExecution.savePresentation;
|
|
1011
|
+
var executeToolWithContext = apiExecution.executeToolWithContext;
|
|
4089
1012
|
|
|
4090
1013
|
// src/mcp/handlers.ts
|
|
4091
1014
|
var ALLOWED_EXTENSIONS = /* @__PURE__ */ new Set([".pptx", ".ppt"]);
|
|
@@ -4137,19 +1060,26 @@ async function runMcpTool(filePath, fn, options) {
|
|
|
4137
1060
|
}
|
|
4138
1061
|
|
|
4139
1062
|
// src/mcp/server.ts
|
|
4140
|
-
function createServer() {
|
|
4141
|
-
const
|
|
1063
|
+
function createServer(options) {
|
|
1064
|
+
const server = new McpServer({
|
|
4142
1065
|
name: "pptx-viewer-tools",
|
|
4143
1066
|
version: "1.0.0"
|
|
4144
1067
|
});
|
|
4145
|
-
|
|
1068
|
+
registerTools(server, options);
|
|
1069
|
+
return server;
|
|
1070
|
+
}
|
|
1071
|
+
function registerTools(server, options) {
|
|
1072
|
+
const runMcpTool2 = (filePath, fn) => runMcpTool(filePath, fn, options);
|
|
1073
|
+
const resolveScopedDir2 = (dir) => resolveScopedDir(dir, options?.rootDir);
|
|
1074
|
+
const resolveScopedFilePath2 = (filePath) => resolveScopedFilePath(filePath, options?.rootDir);
|
|
1075
|
+
server.registerTool(
|
|
4146
1076
|
"get_slide",
|
|
4147
1077
|
{
|
|
4148
1078
|
description: "Inspect a single slide: returns layout, notes, elements",
|
|
4149
1079
|
inputSchema: GetSlideSchema.shape
|
|
4150
1080
|
},
|
|
4151
1081
|
async (params) => {
|
|
4152
|
-
const result = await
|
|
1082
|
+
const result = await runMcpTool2(
|
|
4153
1083
|
params.filePath,
|
|
4154
1084
|
(ctx) => getSlide(ctx, { slideIndex: params.slideIndex })
|
|
4155
1085
|
);
|
|
@@ -4163,14 +1093,14 @@ function createServer() {
|
|
|
4163
1093
|
};
|
|
4164
1094
|
}
|
|
4165
1095
|
);
|
|
4166
|
-
|
|
1096
|
+
server.registerTool(
|
|
4167
1097
|
"add_slide",
|
|
4168
1098
|
{
|
|
4169
1099
|
description: "Add a new blank slide to the presentation",
|
|
4170
1100
|
inputSchema: AddSlideSchema.shape
|
|
4171
1101
|
},
|
|
4172
1102
|
async (params) => {
|
|
4173
|
-
const result = await
|
|
1103
|
+
const result = await runMcpTool2(params.filePath, (ctx) => addSlide(ctx, params));
|
|
4174
1104
|
return {
|
|
4175
1105
|
content: [
|
|
4176
1106
|
{
|
|
@@ -4181,14 +1111,14 @@ function createServer() {
|
|
|
4181
1111
|
};
|
|
4182
1112
|
}
|
|
4183
1113
|
);
|
|
4184
|
-
|
|
1114
|
+
server.registerTool(
|
|
4185
1115
|
"delete_slides",
|
|
4186
1116
|
{
|
|
4187
1117
|
description: "Delete one or more slides by index",
|
|
4188
1118
|
inputSchema: DeleteSlidesSchema.shape
|
|
4189
1119
|
},
|
|
4190
1120
|
async (params) => {
|
|
4191
|
-
const result = await
|
|
1121
|
+
const result = await runMcpTool2(
|
|
4192
1122
|
params.filePath,
|
|
4193
1123
|
(ctx) => deleteSlides(ctx, {
|
|
4194
1124
|
slideIndexes: params.slideIndexes
|
|
@@ -4204,14 +1134,14 @@ function createServer() {
|
|
|
4204
1134
|
};
|
|
4205
1135
|
}
|
|
4206
1136
|
);
|
|
4207
|
-
|
|
1137
|
+
server.registerTool(
|
|
4208
1138
|
"reorder_slides",
|
|
4209
1139
|
{
|
|
4210
1140
|
description: "Reorder slides by providing a new index array",
|
|
4211
1141
|
inputSchema: ReorderSlidesSchema.shape
|
|
4212
1142
|
},
|
|
4213
1143
|
async (params) => {
|
|
4214
|
-
const result = await
|
|
1144
|
+
const result = await runMcpTool2(
|
|
4215
1145
|
params.filePath,
|
|
4216
1146
|
(ctx) => reorderSlides(ctx, { newOrder: params.newOrder })
|
|
4217
1147
|
);
|
|
@@ -4225,14 +1155,14 @@ function createServer() {
|
|
|
4225
1155
|
};
|
|
4226
1156
|
}
|
|
4227
1157
|
);
|
|
4228
|
-
|
|
1158
|
+
server.registerTool(
|
|
4229
1159
|
"duplicate_slide",
|
|
4230
1160
|
{
|
|
4231
1161
|
description: "Duplicate a slide with new element IDs",
|
|
4232
1162
|
inputSchema: DuplicateSlideSchema.shape
|
|
4233
1163
|
},
|
|
4234
1164
|
async (params) => {
|
|
4235
|
-
const result = await
|
|
1165
|
+
const result = await runMcpTool2(
|
|
4236
1166
|
params.filePath,
|
|
4237
1167
|
(ctx) => duplicateSlide(ctx, params)
|
|
4238
1168
|
);
|
|
@@ -4246,14 +1176,14 @@ function createServer() {
|
|
|
4246
1176
|
};
|
|
4247
1177
|
}
|
|
4248
1178
|
);
|
|
4249
|
-
|
|
1179
|
+
server.registerTool(
|
|
4250
1180
|
"update_slide_properties",
|
|
4251
1181
|
{
|
|
4252
1182
|
description: "Update slide background, notes, or visibility",
|
|
4253
1183
|
inputSchema: UpdateSlidePropertiesSchema.shape
|
|
4254
1184
|
},
|
|
4255
1185
|
async (params) => {
|
|
4256
|
-
const result = await
|
|
1186
|
+
const result = await runMcpTool2(
|
|
4257
1187
|
params.filePath,
|
|
4258
1188
|
(ctx) => updateSlideProperties(ctx, params)
|
|
4259
1189
|
);
|
|
@@ -4267,14 +1197,14 @@ function createServer() {
|
|
|
4267
1197
|
};
|
|
4268
1198
|
}
|
|
4269
1199
|
);
|
|
4270
|
-
|
|
1200
|
+
server.registerTool(
|
|
4271
1201
|
"set_slide_transition",
|
|
4272
1202
|
{
|
|
4273
1203
|
description: "Set or remove a slide transition effect",
|
|
4274
1204
|
inputSchema: SetSlideTransitionSchema.shape
|
|
4275
1205
|
},
|
|
4276
1206
|
async (params) => {
|
|
4277
|
-
const result = await
|
|
1207
|
+
const result = await runMcpTool2(
|
|
4278
1208
|
params.filePath,
|
|
4279
1209
|
(ctx) => setSlideTransition(ctx, params)
|
|
4280
1210
|
);
|
|
@@ -4288,14 +1218,14 @@ function createServer() {
|
|
|
4288
1218
|
};
|
|
4289
1219
|
}
|
|
4290
1220
|
);
|
|
4291
|
-
|
|
1221
|
+
server.registerTool(
|
|
4292
1222
|
"set_canvas_size",
|
|
4293
1223
|
{
|
|
4294
1224
|
description: "Change the presentation canvas dimensions",
|
|
4295
1225
|
inputSchema: SetCanvasSizeSchema.shape
|
|
4296
1226
|
},
|
|
4297
1227
|
async (params) => {
|
|
4298
|
-
const result = await
|
|
1228
|
+
const result = await runMcpTool2(
|
|
4299
1229
|
params.filePath,
|
|
4300
1230
|
(ctx) => setCanvasSize(ctx, params)
|
|
4301
1231
|
);
|
|
@@ -4309,14 +1239,14 @@ function createServer() {
|
|
|
4309
1239
|
};
|
|
4310
1240
|
}
|
|
4311
1241
|
);
|
|
4312
|
-
|
|
1242
|
+
server.registerTool(
|
|
4313
1243
|
"add_element",
|
|
4314
1244
|
{
|
|
4315
1245
|
description: "Add a text, shape, image, table, or connector element",
|
|
4316
1246
|
inputSchema: AddElementSchema.shape
|
|
4317
1247
|
},
|
|
4318
1248
|
async (params) => {
|
|
4319
|
-
const result = await
|
|
1249
|
+
const result = await runMcpTool2(
|
|
4320
1250
|
params.filePath,
|
|
4321
1251
|
(ctx) => addElement(ctx, params)
|
|
4322
1252
|
);
|
|
@@ -4330,14 +1260,14 @@ function createServer() {
|
|
|
4330
1260
|
};
|
|
4331
1261
|
}
|
|
4332
1262
|
);
|
|
4333
|
-
|
|
1263
|
+
server.registerTool(
|
|
4334
1264
|
"update_element",
|
|
4335
1265
|
{
|
|
4336
1266
|
description: "Update element position, size, text, or style",
|
|
4337
1267
|
inputSchema: UpdateElementSchema.shape
|
|
4338
1268
|
},
|
|
4339
1269
|
async (params) => {
|
|
4340
|
-
const result = await
|
|
1270
|
+
const result = await runMcpTool2(
|
|
4341
1271
|
params.filePath,
|
|
4342
1272
|
(ctx) => updateElement(ctx, params)
|
|
4343
1273
|
);
|
|
@@ -4351,14 +1281,14 @@ function createServer() {
|
|
|
4351
1281
|
};
|
|
4352
1282
|
}
|
|
4353
1283
|
);
|
|
4354
|
-
|
|
1284
|
+
server.registerTool(
|
|
4355
1285
|
"rename_element",
|
|
4356
1286
|
{
|
|
4357
1287
|
description: "Rename an element (the selection pane's display name; cNvPr/@name)",
|
|
4358
1288
|
inputSchema: RenameElementSchema.shape
|
|
4359
1289
|
},
|
|
4360
1290
|
async (params) => {
|
|
4361
|
-
const result = await
|
|
1291
|
+
const result = await runMcpTool2(
|
|
4362
1292
|
params.filePath,
|
|
4363
1293
|
(ctx) => renameElement(ctx, params)
|
|
4364
1294
|
);
|
|
@@ -4372,14 +1302,14 @@ function createServer() {
|
|
|
4372
1302
|
};
|
|
4373
1303
|
}
|
|
4374
1304
|
);
|
|
4375
|
-
|
|
1305
|
+
server.registerTool(
|
|
4376
1306
|
"delete_elements",
|
|
4377
1307
|
{
|
|
4378
1308
|
description: "Delete one or more elements by ID",
|
|
4379
1309
|
inputSchema: DeleteElementsSchema.shape
|
|
4380
1310
|
},
|
|
4381
1311
|
async (params) => {
|
|
4382
|
-
const result = await
|
|
1312
|
+
const result = await runMcpTool2(
|
|
4383
1313
|
params.filePath,
|
|
4384
1314
|
(ctx) => deleteElements(ctx, params)
|
|
4385
1315
|
);
|
|
@@ -4393,14 +1323,14 @@ function createServer() {
|
|
|
4393
1323
|
};
|
|
4394
1324
|
}
|
|
4395
1325
|
);
|
|
4396
|
-
|
|
1326
|
+
server.registerTool(
|
|
4397
1327
|
"arrange_elements",
|
|
4398
1328
|
{
|
|
4399
1329
|
description: "Align elements or change z-order (layer)",
|
|
4400
1330
|
inputSchema: ArrangeElementsSchema.shape
|
|
4401
1331
|
},
|
|
4402
1332
|
async (params) => {
|
|
4403
|
-
const result = await
|
|
1333
|
+
const result = await runMcpTool2(
|
|
4404
1334
|
params.filePath,
|
|
4405
1335
|
(ctx) => arrangeElements(ctx, params)
|
|
4406
1336
|
);
|
|
@@ -4414,14 +1344,14 @@ function createServer() {
|
|
|
4414
1344
|
};
|
|
4415
1345
|
}
|
|
4416
1346
|
);
|
|
4417
|
-
|
|
1347
|
+
server.registerTool(
|
|
4418
1348
|
"clone_element",
|
|
4419
1349
|
{
|
|
4420
1350
|
description: "Clone an element within or across slides",
|
|
4421
1351
|
inputSchema: CloneElementSchema.shape
|
|
4422
1352
|
},
|
|
4423
1353
|
async (params) => {
|
|
4424
|
-
const result = await
|
|
1354
|
+
const result = await runMcpTool2(
|
|
4425
1355
|
params.filePath,
|
|
4426
1356
|
(ctx) => cloneElement(ctx, params)
|
|
4427
1357
|
);
|
|
@@ -4435,14 +1365,14 @@ function createServer() {
|
|
|
4435
1365
|
};
|
|
4436
1366
|
}
|
|
4437
1367
|
);
|
|
4438
|
-
|
|
1368
|
+
server.registerTool(
|
|
4439
1369
|
"set_element_animation",
|
|
4440
1370
|
{
|
|
4441
1371
|
description: "Set entrance/exit animation on an element",
|
|
4442
1372
|
inputSchema: SetElementAnimationSchema.shape
|
|
4443
1373
|
},
|
|
4444
1374
|
async (params) => {
|
|
4445
|
-
const result = await
|
|
1375
|
+
const result = await runMcpTool2(
|
|
4446
1376
|
params.filePath,
|
|
4447
1377
|
(ctx) => setElementAnimation(ctx, params)
|
|
4448
1378
|
);
|
|
@@ -4456,14 +1386,14 @@ function createServer() {
|
|
|
4456
1386
|
};
|
|
4457
1387
|
}
|
|
4458
1388
|
);
|
|
4459
|
-
|
|
1389
|
+
server.registerTool(
|
|
4460
1390
|
"group_elements",
|
|
4461
1391
|
{
|
|
4462
1392
|
description: "Group multiple elements into a group",
|
|
4463
1393
|
inputSchema: GroupElementsSchema.shape
|
|
4464
1394
|
},
|
|
4465
1395
|
async (params) => {
|
|
4466
|
-
const result = await
|
|
1396
|
+
const result = await runMcpTool2(
|
|
4467
1397
|
params.filePath,
|
|
4468
1398
|
(ctx) => groupElements(ctx, params)
|
|
4469
1399
|
);
|
|
@@ -4477,14 +1407,14 @@ function createServer() {
|
|
|
4477
1407
|
};
|
|
4478
1408
|
}
|
|
4479
1409
|
);
|
|
4480
|
-
|
|
1410
|
+
server.registerTool(
|
|
4481
1411
|
"ungroup_elements",
|
|
4482
1412
|
{
|
|
4483
1413
|
description: "Ungroup a group element back to individual elements",
|
|
4484
1414
|
inputSchema: UngroupElementsSchema.shape
|
|
4485
1415
|
},
|
|
4486
1416
|
async (params) => {
|
|
4487
|
-
const result = await
|
|
1417
|
+
const result = await runMcpTool2(
|
|
4488
1418
|
params.filePath,
|
|
4489
1419
|
(ctx) => ungroupElements(ctx, params)
|
|
4490
1420
|
);
|
|
@@ -4498,14 +1428,14 @@ function createServer() {
|
|
|
4498
1428
|
};
|
|
4499
1429
|
}
|
|
4500
1430
|
);
|
|
4501
|
-
|
|
1431
|
+
server.registerTool(
|
|
4502
1432
|
"batch_update_elements",
|
|
4503
1433
|
{
|
|
4504
1434
|
description: "Apply the same properties to multiple elements",
|
|
4505
1435
|
inputSchema: BatchUpdateElementsSchema.shape
|
|
4506
1436
|
},
|
|
4507
1437
|
async (params) => {
|
|
4508
|
-
const result = await
|
|
1438
|
+
const result = await runMcpTool2(
|
|
4509
1439
|
params.filePath,
|
|
4510
1440
|
(ctx) => batchUpdateElements(ctx, params)
|
|
4511
1441
|
);
|
|
@@ -4519,14 +1449,14 @@ function createServer() {
|
|
|
4519
1449
|
};
|
|
4520
1450
|
}
|
|
4521
1451
|
);
|
|
4522
|
-
|
|
1452
|
+
server.registerTool(
|
|
4523
1453
|
"update_table_cells",
|
|
4524
1454
|
{
|
|
4525
1455
|
description: "Update text content of table cells",
|
|
4526
1456
|
inputSchema: UpdateTableCellsSchema.shape
|
|
4527
1457
|
},
|
|
4528
1458
|
async (params) => {
|
|
4529
|
-
const result = await
|
|
1459
|
+
const result = await runMcpTool2(
|
|
4530
1460
|
params.filePath,
|
|
4531
1461
|
(ctx) => updateTableCells(ctx, params)
|
|
4532
1462
|
);
|
|
@@ -4540,14 +1470,14 @@ function createServer() {
|
|
|
4540
1470
|
};
|
|
4541
1471
|
}
|
|
4542
1472
|
);
|
|
4543
|
-
|
|
1473
|
+
server.registerTool(
|
|
4544
1474
|
"manage_table_structure",
|
|
4545
1475
|
{
|
|
4546
1476
|
description: "Insert or delete table rows and columns",
|
|
4547
1477
|
inputSchema: ManageTableStructureSchema.shape
|
|
4548
1478
|
},
|
|
4549
1479
|
async (params) => {
|
|
4550
|
-
const result = await
|
|
1480
|
+
const result = await runMcpTool2(
|
|
4551
1481
|
params.filePath,
|
|
4552
1482
|
(ctx) => manageTableStructure(ctx, params)
|
|
4553
1483
|
);
|
|
@@ -4561,14 +1491,14 @@ function createServer() {
|
|
|
4561
1491
|
};
|
|
4562
1492
|
}
|
|
4563
1493
|
);
|
|
4564
|
-
|
|
1494
|
+
server.registerTool(
|
|
4565
1495
|
"set_table_style_section",
|
|
4566
1496
|
{
|
|
4567
1497
|
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",
|
|
4568
1498
|
inputSchema: SetTableStyleSectionSchema.shape
|
|
4569
1499
|
},
|
|
4570
1500
|
async (params) => {
|
|
4571
|
-
const result = await
|
|
1501
|
+
const result = await runMcpTool2(
|
|
4572
1502
|
params.filePath,
|
|
4573
1503
|
(ctx) => setTableStyleSection(ctx, params)
|
|
4574
1504
|
);
|
|
@@ -4577,14 +1507,14 @@ function createServer() {
|
|
|
4577
1507
|
};
|
|
4578
1508
|
}
|
|
4579
1509
|
);
|
|
4580
|
-
|
|
1510
|
+
server.registerTool(
|
|
4581
1511
|
"create_table_style",
|
|
4582
1512
|
{
|
|
4583
1513
|
description: "Create a new table style (optionally cloned from an existing one) and optionally set it as the default",
|
|
4584
1514
|
inputSchema: CreateTableStyleSchema.shape
|
|
4585
1515
|
},
|
|
4586
1516
|
async (params) => {
|
|
4587
|
-
const result = await
|
|
1517
|
+
const result = await runMcpTool2(
|
|
4588
1518
|
params.filePath,
|
|
4589
1519
|
(ctx) => createTableStyle(ctx, params)
|
|
4590
1520
|
);
|
|
@@ -4593,14 +1523,14 @@ function createServer() {
|
|
|
4593
1523
|
};
|
|
4594
1524
|
}
|
|
4595
1525
|
);
|
|
4596
|
-
|
|
1526
|
+
server.registerTool(
|
|
4597
1527
|
"delete_table_style",
|
|
4598
1528
|
{
|
|
4599
1529
|
description: "Remove a table style from the presentation",
|
|
4600
1530
|
inputSchema: DeleteTableStyleSchema.shape
|
|
4601
1531
|
},
|
|
4602
1532
|
async (params) => {
|
|
4603
|
-
const result = await
|
|
1533
|
+
const result = await runMcpTool2(
|
|
4604
1534
|
params.filePath,
|
|
4605
1535
|
(ctx) => deleteTableStyle(ctx, params)
|
|
4606
1536
|
);
|
|
@@ -4609,14 +1539,14 @@ function createServer() {
|
|
|
4609
1539
|
};
|
|
4610
1540
|
}
|
|
4611
1541
|
);
|
|
4612
|
-
|
|
1542
|
+
server.registerTool(
|
|
4613
1543
|
"assign_table_style",
|
|
4614
1544
|
{
|
|
4615
1545
|
description: "Assign a table style (and row/column emphasis flags) to an existing table",
|
|
4616
1546
|
inputSchema: AssignTableStyleSchema.shape
|
|
4617
1547
|
},
|
|
4618
1548
|
async (params) => {
|
|
4619
|
-
const result = await
|
|
1549
|
+
const result = await runMcpTool2(
|
|
4620
1550
|
params.filePath,
|
|
4621
1551
|
(ctx) => assignTableStyle(ctx, params)
|
|
4622
1552
|
);
|
|
@@ -4625,14 +1555,14 @@ function createServer() {
|
|
|
4625
1555
|
};
|
|
4626
1556
|
}
|
|
4627
1557
|
);
|
|
4628
|
-
|
|
1558
|
+
server.registerTool(
|
|
4629
1559
|
"update_element_style",
|
|
4630
1560
|
{
|
|
4631
1561
|
description: "Update fill, stroke, shadow, glow, or image effects",
|
|
4632
1562
|
inputSchema: UpdateElementStyleSchema.shape
|
|
4633
1563
|
},
|
|
4634
1564
|
async (params) => {
|
|
4635
|
-
const result = await
|
|
1565
|
+
const result = await runMcpTool2(
|
|
4636
1566
|
params.filePath,
|
|
4637
1567
|
(ctx) => updateElementStyle(ctx, params)
|
|
4638
1568
|
);
|
|
@@ -4646,14 +1576,14 @@ function createServer() {
|
|
|
4646
1576
|
};
|
|
4647
1577
|
}
|
|
4648
1578
|
);
|
|
4649
|
-
|
|
1579
|
+
server.registerTool(
|
|
4650
1580
|
"run_accessibility_check",
|
|
4651
1581
|
{
|
|
4652
1582
|
description: "Audit the presentation for accessibility issues",
|
|
4653
1583
|
inputSchema: AccessibilityCheckSchema.shape
|
|
4654
1584
|
},
|
|
4655
1585
|
async (params) => {
|
|
4656
|
-
const result = await
|
|
1586
|
+
const result = await runMcpTool2(
|
|
4657
1587
|
params.filePath,
|
|
4658
1588
|
(ctx) => runAccessibilityCheck(ctx)
|
|
4659
1589
|
);
|
|
@@ -4667,14 +1597,14 @@ function createServer() {
|
|
|
4667
1597
|
};
|
|
4668
1598
|
}
|
|
4669
1599
|
);
|
|
4670
|
-
|
|
1600
|
+
server.registerTool(
|
|
4671
1601
|
"find_text",
|
|
4672
1602
|
{
|
|
4673
1603
|
description: "Search for text across all slides",
|
|
4674
1604
|
inputSchema: FindTextSchema.shape
|
|
4675
1605
|
},
|
|
4676
1606
|
async (params) => {
|
|
4677
|
-
const result = await
|
|
1607
|
+
const result = await runMcpTool2(params.filePath, (ctx) => findText(ctx, params));
|
|
4678
1608
|
return {
|
|
4679
1609
|
content: [
|
|
4680
1610
|
{
|
|
@@ -4685,14 +1615,14 @@ function createServer() {
|
|
|
4685
1615
|
};
|
|
4686
1616
|
}
|
|
4687
1617
|
);
|
|
4688
|
-
|
|
1618
|
+
server.registerTool(
|
|
4689
1619
|
"replace_text",
|
|
4690
1620
|
{
|
|
4691
1621
|
description: "Find and replace text across slides",
|
|
4692
1622
|
inputSchema: ReplaceTextSchema.shape
|
|
4693
1623
|
},
|
|
4694
1624
|
async (params) => {
|
|
4695
|
-
const result = await
|
|
1625
|
+
const result = await runMcpTool2(
|
|
4696
1626
|
params.filePath,
|
|
4697
1627
|
(ctx) => replaceText(ctx, params)
|
|
4698
1628
|
);
|
|
@@ -4706,14 +1636,14 @@ function createServer() {
|
|
|
4706
1636
|
};
|
|
4707
1637
|
}
|
|
4708
1638
|
);
|
|
4709
|
-
|
|
1639
|
+
server.registerTool(
|
|
4710
1640
|
"manage_comments",
|
|
4711
1641
|
{
|
|
4712
1642
|
description: "List, add, delete, or resolve slide comments",
|
|
4713
1643
|
inputSchema: ManageCommentsSchema.shape
|
|
4714
1644
|
},
|
|
4715
1645
|
async (params) => {
|
|
4716
|
-
const result = await
|
|
1646
|
+
const result = await runMcpTool2(
|
|
4717
1647
|
params.filePath,
|
|
4718
1648
|
(ctx) => manageComments(ctx, params)
|
|
4719
1649
|
);
|
|
@@ -4727,16 +1657,16 @@ function createServer() {
|
|
|
4727
1657
|
};
|
|
4728
1658
|
}
|
|
4729
1659
|
);
|
|
4730
|
-
|
|
1660
|
+
server.registerTool(
|
|
4731
1661
|
"convert_to_markdown",
|
|
4732
1662
|
{
|
|
4733
1663
|
description: "Convert the presentation to Markdown format",
|
|
4734
1664
|
inputSchema: ConvertToMarkdownSchema.shape
|
|
4735
1665
|
},
|
|
4736
1666
|
async (params) => {
|
|
4737
|
-
const result = await
|
|
1667
|
+
const result = await runMcpTool2(
|
|
4738
1668
|
params.filePath,
|
|
4739
|
-
(ctx) => convertToMarkdown(ctx, { ...params, scopeOutputDir:
|
|
1669
|
+
(ctx) => convertToMarkdown(ctx, { ...params, scopeOutputDir: resolveScopedDir2 })
|
|
4740
1670
|
);
|
|
4741
1671
|
return {
|
|
4742
1672
|
content: [
|
|
@@ -4748,414 +1678,414 @@ function createServer() {
|
|
|
4748
1678
|
};
|
|
4749
1679
|
}
|
|
4750
1680
|
);
|
|
4751
|
-
|
|
1681
|
+
server.registerTool(
|
|
4752
1682
|
"get_theme_info",
|
|
4753
1683
|
{
|
|
4754
1684
|
description: "Get current theme information (colors, fonts, available presets)",
|
|
4755
1685
|
inputSchema: GetThemeInfoSchema.shape
|
|
4756
1686
|
},
|
|
4757
1687
|
async (params) => {
|
|
4758
|
-
const result = await
|
|
1688
|
+
const result = await runMcpTool2(params.filePath, (ctx) => getThemeInfo(ctx));
|
|
4759
1689
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4760
1690
|
}
|
|
4761
1691
|
);
|
|
4762
|
-
|
|
1692
|
+
server.registerTool(
|
|
4763
1693
|
"apply_theme_preset",
|
|
4764
1694
|
{
|
|
4765
1695
|
description: "Apply a built-in theme preset to the presentation",
|
|
4766
1696
|
inputSchema: ApplyThemePresetSchema.shape
|
|
4767
1697
|
},
|
|
4768
1698
|
async (params) => {
|
|
4769
|
-
const result = await
|
|
1699
|
+
const result = await runMcpTool2(
|
|
4770
1700
|
params.filePath,
|
|
4771
1701
|
(ctx) => applyThemePreset(ctx, params)
|
|
4772
1702
|
);
|
|
4773
1703
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4774
1704
|
}
|
|
4775
1705
|
);
|
|
4776
|
-
|
|
1706
|
+
server.registerTool(
|
|
4777
1707
|
"update_theme_colors",
|
|
4778
1708
|
{
|
|
4779
1709
|
description: "Update individual theme colors (accent1-6, dk1/2, lt1/2, hlink, folHlink)",
|
|
4780
1710
|
inputSchema: UpdateThemeColorsSchema.shape
|
|
4781
1711
|
},
|
|
4782
1712
|
async (params) => {
|
|
4783
|
-
const result = await
|
|
1713
|
+
const result = await runMcpTool2(
|
|
4784
1714
|
params.filePath,
|
|
4785
1715
|
(ctx) => updateThemeColors(ctx, params)
|
|
4786
1716
|
);
|
|
4787
1717
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4788
1718
|
}
|
|
4789
1719
|
);
|
|
4790
|
-
|
|
1720
|
+
server.registerTool(
|
|
4791
1721
|
"update_theme_fonts",
|
|
4792
1722
|
{
|
|
4793
1723
|
description: "Update theme heading (major) and body (minor) fonts",
|
|
4794
1724
|
inputSchema: UpdateThemeFontsSchema.shape
|
|
4795
1725
|
},
|
|
4796
1726
|
async (params) => {
|
|
4797
|
-
const result = await
|
|
1727
|
+
const result = await runMcpTool2(
|
|
4798
1728
|
params.filePath,
|
|
4799
1729
|
(ctx) => updateThemeFonts(ctx, params)
|
|
4800
1730
|
);
|
|
4801
1731
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4802
1732
|
}
|
|
4803
1733
|
);
|
|
4804
|
-
|
|
1734
|
+
server.registerTool(
|
|
4805
1735
|
"update_chart",
|
|
4806
1736
|
{
|
|
4807
1737
|
description: "Update chart type, title, legend, data labels, axis, or categories",
|
|
4808
1738
|
inputSchema: UpdateChartSchema.shape
|
|
4809
1739
|
},
|
|
4810
1740
|
async (params) => {
|
|
4811
|
-
const result = await
|
|
1741
|
+
const result = await runMcpTool2(
|
|
4812
1742
|
params.filePath,
|
|
4813
1743
|
(ctx) => updateChart(ctx, params)
|
|
4814
1744
|
);
|
|
4815
1745
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4816
1746
|
}
|
|
4817
1747
|
);
|
|
4818
|
-
|
|
1748
|
+
server.registerTool(
|
|
4819
1749
|
"add_chart_series",
|
|
4820
1750
|
{
|
|
4821
1751
|
description: "Add a data series to an existing chart",
|
|
4822
1752
|
inputSchema: AddChartSeriesSchema.shape
|
|
4823
1753
|
},
|
|
4824
1754
|
async (params) => {
|
|
4825
|
-
const result = await
|
|
1755
|
+
const result = await runMcpTool2(
|
|
4826
1756
|
params.filePath,
|
|
4827
1757
|
(ctx) => addChartSeriesT(ctx, params)
|
|
4828
1758
|
);
|
|
4829
1759
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4830
1760
|
}
|
|
4831
1761
|
);
|
|
4832
|
-
|
|
1762
|
+
server.registerTool(
|
|
4833
1763
|
"remove_chart_series",
|
|
4834
1764
|
{
|
|
4835
1765
|
description: "Remove a data series from a chart by index",
|
|
4836
1766
|
inputSchema: RemoveChartSeriesSchema.shape
|
|
4837
1767
|
},
|
|
4838
1768
|
async (params) => {
|
|
4839
|
-
const result = await
|
|
1769
|
+
const result = await runMcpTool2(
|
|
4840
1770
|
params.filePath,
|
|
4841
1771
|
(ctx) => removeChartSeriesT(ctx, params)
|
|
4842
1772
|
);
|
|
4843
1773
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4844
1774
|
}
|
|
4845
1775
|
);
|
|
4846
|
-
|
|
1776
|
+
server.registerTool(
|
|
4847
1777
|
"update_chart_series_data",
|
|
4848
1778
|
{
|
|
4849
1779
|
description: "Update data values for a chart series",
|
|
4850
1780
|
inputSchema: UpdateChartSeriesDataSchema.shape
|
|
4851
1781
|
},
|
|
4852
1782
|
async (params) => {
|
|
4853
|
-
const result = await
|
|
1783
|
+
const result = await runMcpTool2(
|
|
4854
1784
|
params.filePath,
|
|
4855
1785
|
(ctx) => updateChartSeriesData(ctx, params)
|
|
4856
1786
|
);
|
|
4857
1787
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4858
1788
|
}
|
|
4859
1789
|
);
|
|
4860
|
-
|
|
1790
|
+
server.registerTool(
|
|
4861
1791
|
"create_chart",
|
|
4862
1792
|
{
|
|
4863
1793
|
description: "Create a new chart element on a slide",
|
|
4864
1794
|
inputSchema: CreateChartSchema.shape
|
|
4865
1795
|
},
|
|
4866
1796
|
async (params) => {
|
|
4867
|
-
const result = await
|
|
1797
|
+
const result = await runMcpTool2(
|
|
4868
1798
|
params.filePath,
|
|
4869
1799
|
(ctx) => createChart(ctx, params)
|
|
4870
1800
|
);
|
|
4871
1801
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4872
1802
|
}
|
|
4873
1803
|
);
|
|
4874
|
-
|
|
1804
|
+
server.registerTool(
|
|
4875
1805
|
"format_chart_data_point",
|
|
4876
1806
|
{
|
|
4877
1807
|
description: "Set per-data-point chart formatting: fill/stroke colour, stroke width, dash style (c:dPt/c:spPr), explosion, and marker override",
|
|
4878
1808
|
inputSchema: FormatChartDataPointSchema.shape
|
|
4879
1809
|
},
|
|
4880
1810
|
async (params) => {
|
|
4881
|
-
const result = await
|
|
1811
|
+
const result = await runMcpTool2(
|
|
4882
1812
|
params.filePath,
|
|
4883
1813
|
(ctx) => formatChartDataPoint(ctx, params)
|
|
4884
1814
|
);
|
|
4885
1815
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4886
1816
|
}
|
|
4887
1817
|
);
|
|
4888
|
-
|
|
1818
|
+
server.registerTool(
|
|
4889
1819
|
"format_chart_data_label",
|
|
4890
1820
|
{
|
|
4891
1821
|
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)",
|
|
4892
1822
|
inputSchema: FormatChartDataLabelSchema.shape
|
|
4893
1823
|
},
|
|
4894
1824
|
async (params) => {
|
|
4895
|
-
const result = await
|
|
1825
|
+
const result = await runMcpTool2(
|
|
4896
1826
|
params.filePath,
|
|
4897
1827
|
(ctx) => formatChartDataLabel(ctx, params)
|
|
4898
1828
|
);
|
|
4899
1829
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4900
1830
|
}
|
|
4901
1831
|
);
|
|
4902
|
-
|
|
1832
|
+
server.registerTool(
|
|
4903
1833
|
"format_chart_series",
|
|
4904
1834
|
{
|
|
4905
1835
|
description: "Set a chart series marker (c:marker), trendline (c:trendline, incl. line width/dash), or error bars (c:errBars, incl. line width/dash)",
|
|
4906
1836
|
inputSchema: FormatChartSeriesSchema.shape
|
|
4907
1837
|
},
|
|
4908
1838
|
async (params) => {
|
|
4909
|
-
const result = await
|
|
1839
|
+
const result = await runMcpTool2(
|
|
4910
1840
|
params.filePath,
|
|
4911
1841
|
(ctx) => formatChartSeries(ctx, params)
|
|
4912
1842
|
);
|
|
4913
1843
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4914
1844
|
}
|
|
4915
1845
|
);
|
|
4916
|
-
|
|
1846
|
+
server.registerTool(
|
|
4917
1847
|
"set_chart_helper_line",
|
|
4918
1848
|
{
|
|
4919
1849
|
description: "Set or remove a chart-level helper line on a line/stock/combo chart: c:dropLines or c:hiLowLines",
|
|
4920
1850
|
inputSchema: SetChartHelperLineSchema.shape
|
|
4921
1851
|
},
|
|
4922
1852
|
async (params) => {
|
|
4923
|
-
const result = await
|
|
1853
|
+
const result = await runMcpTool2(
|
|
4924
1854
|
params.filePath,
|
|
4925
1855
|
(ctx) => setChartHelperLineT(ctx, params)
|
|
4926
1856
|
);
|
|
4927
1857
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4928
1858
|
}
|
|
4929
1859
|
);
|
|
4930
|
-
|
|
1860
|
+
server.registerTool(
|
|
4931
1861
|
"set_chart_color_map_override",
|
|
4932
1862
|
{
|
|
4933
1863
|
description: "Set or remove a chart's theme colour-map override (c:clrMapOvr), remapping theme colour roles for this chart only",
|
|
4934
1864
|
inputSchema: SetChartColorMapOverrideSchema.shape
|
|
4935
1865
|
},
|
|
4936
1866
|
async (params) => {
|
|
4937
|
-
const result = await
|
|
1867
|
+
const result = await runMcpTool2(
|
|
4938
1868
|
params.filePath,
|
|
4939
1869
|
(ctx) => setChartColorMapOverrideT(ctx, params)
|
|
4940
1870
|
);
|
|
4941
1871
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4942
1872
|
}
|
|
4943
1873
|
);
|
|
4944
|
-
|
|
1874
|
+
server.registerTool(
|
|
4945
1875
|
"chart_user_shape_list",
|
|
4946
1876
|
{
|
|
4947
1877
|
description: "List a chart's drawing-overlay shapes (c:userShapes)",
|
|
4948
1878
|
inputSchema: ListChartUserShapesSchema.shape
|
|
4949
1879
|
},
|
|
4950
1880
|
async (params) => {
|
|
4951
|
-
const result = await
|
|
1881
|
+
const result = await runMcpTool2(
|
|
4952
1882
|
params.filePath,
|
|
4953
1883
|
(ctx) => listChartUserShapesT(ctx, params)
|
|
4954
1884
|
);
|
|
4955
1885
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4956
1886
|
}
|
|
4957
1887
|
);
|
|
4958
|
-
|
|
1888
|
+
server.registerTool(
|
|
4959
1889
|
"chart_user_shape_add",
|
|
4960
1890
|
{
|
|
4961
1891
|
description: "Add a drawing-overlay shape (text box or connector) to a chart's c:userShapes",
|
|
4962
1892
|
inputSchema: AddChartUserShapeSchema.shape
|
|
4963
1893
|
},
|
|
4964
1894
|
async (params) => {
|
|
4965
|
-
const result = await
|
|
1895
|
+
const result = await runMcpTool2(
|
|
4966
1896
|
params.filePath,
|
|
4967
1897
|
(ctx) => addChartUserShapeT(ctx, params)
|
|
4968
1898
|
);
|
|
4969
1899
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4970
1900
|
}
|
|
4971
1901
|
);
|
|
4972
|
-
|
|
1902
|
+
server.registerTool(
|
|
4973
1903
|
"chart_user_shape_update",
|
|
4974
1904
|
{
|
|
4975
1905
|
description: "Move, resize, or restyle one of a chart's drawing-overlay shapes by index",
|
|
4976
1906
|
inputSchema: UpdateChartUserShapeSchema.shape
|
|
4977
1907
|
},
|
|
4978
1908
|
async (params) => {
|
|
4979
|
-
const result = await
|
|
1909
|
+
const result = await runMcpTool2(
|
|
4980
1910
|
params.filePath,
|
|
4981
1911
|
(ctx) => updateChartUserShapeT(ctx, params)
|
|
4982
1912
|
);
|
|
4983
1913
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4984
1914
|
}
|
|
4985
1915
|
);
|
|
4986
|
-
|
|
1916
|
+
server.registerTool(
|
|
4987
1917
|
"chart_user_shape_remove",
|
|
4988
1918
|
{
|
|
4989
1919
|
description: "Remove one of a chart's drawing-overlay shapes by index",
|
|
4990
1920
|
inputSchema: RemoveChartUserShapeSchema.shape
|
|
4991
1921
|
},
|
|
4992
1922
|
async (params) => {
|
|
4993
|
-
const result = await
|
|
1923
|
+
const result = await runMcpTool2(
|
|
4994
1924
|
params.filePath,
|
|
4995
1925
|
(ctx) => removeChartUserShapeT(ctx, params)
|
|
4996
1926
|
);
|
|
4997
1927
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4998
1928
|
}
|
|
4999
1929
|
);
|
|
5000
|
-
|
|
1930
|
+
server.registerTool(
|
|
5001
1931
|
"manage_smart_art",
|
|
5002
1932
|
{
|
|
5003
1933
|
description: "Manage SmartArt: get nodes, add/remove/reorder/promote/demote nodes, or decompose to shapes",
|
|
5004
1934
|
inputSchema: ManageSmartArtSchema.shape
|
|
5005
1935
|
},
|
|
5006
1936
|
async (params) => {
|
|
5007
|
-
const result = await
|
|
1937
|
+
const result = await runMcpTool2(
|
|
5008
1938
|
params.filePath,
|
|
5009
1939
|
(ctx) => manageSmartArt(ctx, params)
|
|
5010
1940
|
);
|
|
5011
1941
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5012
1942
|
}
|
|
5013
1943
|
);
|
|
5014
|
-
|
|
1944
|
+
server.registerTool(
|
|
5015
1945
|
"find_placeholders",
|
|
5016
1946
|
{
|
|
5017
1947
|
description: "Discover all {{placeholder}} tokens in the presentation",
|
|
5018
1948
|
inputSchema: FindPlaceholdersSchema.shape
|
|
5019
1949
|
},
|
|
5020
1950
|
async (params) => {
|
|
5021
|
-
const result = await
|
|
1951
|
+
const result = await runMcpTool2(
|
|
5022
1952
|
params.filePath,
|
|
5023
1953
|
(ctx) => findPlaceholdersT(ctx)
|
|
5024
1954
|
);
|
|
5025
1955
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5026
1956
|
}
|
|
5027
1957
|
);
|
|
5028
|
-
|
|
1958
|
+
server.registerTool(
|
|
5029
1959
|
"apply_template",
|
|
5030
1960
|
{
|
|
5031
1961
|
description: "Replace {{placeholder}} tokens with provided values (mail merge)",
|
|
5032
1962
|
inputSchema: ApplyTemplateSchema.shape
|
|
5033
1963
|
},
|
|
5034
1964
|
async (params) => {
|
|
5035
|
-
const result = await
|
|
1965
|
+
const result = await runMcpTool2(
|
|
5036
1966
|
params.filePath,
|
|
5037
1967
|
(ctx) => applyTemplateT(ctx, { data: params.data })
|
|
5038
1968
|
);
|
|
5039
1969
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5040
1970
|
}
|
|
5041
1971
|
);
|
|
5042
|
-
|
|
1972
|
+
server.registerTool(
|
|
5043
1973
|
"get_metadata",
|
|
5044
1974
|
{
|
|
5045
1975
|
description: "Get presentation metadata (title, author, keywords, custom properties)",
|
|
5046
1976
|
inputSchema: GetMetadataSchema.shape
|
|
5047
1977
|
},
|
|
5048
1978
|
async (params) => {
|
|
5049
|
-
const result = await
|
|
1979
|
+
const result = await runMcpTool2(params.filePath, (ctx) => getMetadata(ctx));
|
|
5050
1980
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5051
1981
|
}
|
|
5052
1982
|
);
|
|
5053
|
-
|
|
1983
|
+
server.registerTool(
|
|
5054
1984
|
"update_metadata",
|
|
5055
1985
|
{
|
|
5056
1986
|
description: "Update presentation metadata (title, author, company, custom properties)",
|
|
5057
1987
|
inputSchema: UpdateMetadataSchema.shape
|
|
5058
1988
|
},
|
|
5059
1989
|
async (params) => {
|
|
5060
|
-
const result = await
|
|
1990
|
+
const result = await runMcpTool2(
|
|
5061
1991
|
params.filePath,
|
|
5062
1992
|
(ctx) => updateMetadata(ctx, params)
|
|
5063
1993
|
);
|
|
5064
1994
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5065
1995
|
}
|
|
5066
1996
|
);
|
|
5067
|
-
|
|
1997
|
+
server.registerTool(
|
|
5068
1998
|
"manage_sections",
|
|
5069
1999
|
{
|
|
5070
2000
|
description: "List, add, remove, reorder sections or move slides between sections",
|
|
5071
2001
|
inputSchema: ManageSectionsSchema.shape
|
|
5072
2002
|
},
|
|
5073
2003
|
async (params) => {
|
|
5074
|
-
const result = await
|
|
2004
|
+
const result = await runMcpTool2(
|
|
5075
2005
|
params.filePath,
|
|
5076
2006
|
(ctx) => manageSections(ctx, params)
|
|
5077
2007
|
);
|
|
5078
2008
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5079
2009
|
}
|
|
5080
2010
|
);
|
|
5081
|
-
|
|
2011
|
+
server.registerTool(
|
|
5082
2012
|
"export_to_svg",
|
|
5083
2013
|
{
|
|
5084
2014
|
description: "Export all or specific slides to SVG strings",
|
|
5085
2015
|
inputSchema: ExportToSvgSchema.shape
|
|
5086
2016
|
},
|
|
5087
2017
|
async (params) => {
|
|
5088
|
-
const result = await
|
|
2018
|
+
const result = await runMcpTool2(
|
|
5089
2019
|
params.filePath,
|
|
5090
2020
|
(ctx) => exportToSvg(ctx, params)
|
|
5091
2021
|
);
|
|
5092
2022
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5093
2023
|
}
|
|
5094
2024
|
);
|
|
5095
|
-
|
|
2025
|
+
server.registerTool(
|
|
5096
2026
|
"export_slide_svg",
|
|
5097
2027
|
{
|
|
5098
2028
|
description: "Export a single slide to SVG",
|
|
5099
2029
|
inputSchema: ExportSlideSvgSchema.shape
|
|
5100
2030
|
},
|
|
5101
2031
|
async (params) => {
|
|
5102
|
-
const result = await
|
|
2032
|
+
const result = await runMcpTool2(
|
|
5103
2033
|
params.filePath,
|
|
5104
2034
|
(ctx) => exportSlideSvg(ctx, params)
|
|
5105
2035
|
);
|
|
5106
2036
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5107
2037
|
}
|
|
5108
2038
|
);
|
|
5109
|
-
|
|
2039
|
+
server.registerTool(
|
|
5110
2040
|
"export_to_json",
|
|
5111
2041
|
{
|
|
5112
2042
|
description: "Export the presentation to the portable pptx-viewer-json document format (self-contained, binary assets embedded as base64)",
|
|
5113
2043
|
inputSchema: ExportToJsonSchema.shape
|
|
5114
2044
|
},
|
|
5115
2045
|
async (params) => {
|
|
5116
|
-
const result = await
|
|
2046
|
+
const result = await runMcpTool2(
|
|
5117
2047
|
params.filePath,
|
|
5118
2048
|
(ctx) => exportToJson(ctx, params)
|
|
5119
2049
|
);
|
|
5120
2050
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5121
2051
|
}
|
|
5122
2052
|
);
|
|
5123
|
-
|
|
2053
|
+
server.registerTool(
|
|
5124
2054
|
"import_from_json",
|
|
5125
2055
|
{
|
|
5126
2056
|
description: "Replace the presentation content with a deck imported from a pptx-viewer-json document",
|
|
5127
2057
|
inputSchema: ImportFromJsonSchema.shape
|
|
5128
2058
|
},
|
|
5129
2059
|
async (params) => {
|
|
5130
|
-
const result = await
|
|
2060
|
+
const result = await runMcpTool2(
|
|
5131
2061
|
params.filePath,
|
|
5132
2062
|
(ctx) => importFromJson(ctx, params)
|
|
5133
2063
|
);
|
|
5134
2064
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5135
2065
|
}
|
|
5136
2066
|
);
|
|
5137
|
-
|
|
2067
|
+
server.registerTool(
|
|
5138
2068
|
"manage_hyperlinks",
|
|
5139
2069
|
{
|
|
5140
2070
|
description: "List, set, or remove hyperlinks/actions on elements",
|
|
5141
2071
|
inputSchema: ManageHyperlinksSchema.shape
|
|
5142
2072
|
},
|
|
5143
2073
|
async (params) => {
|
|
5144
|
-
const result = await
|
|
2074
|
+
const result = await runMcpTool2(
|
|
5145
2075
|
params.filePath,
|
|
5146
2076
|
(ctx) => manageHyperlinks(ctx, params)
|
|
5147
2077
|
);
|
|
5148
2078
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5149
2079
|
}
|
|
5150
2080
|
);
|
|
5151
|
-
|
|
2081
|
+
server.registerTool(
|
|
5152
2082
|
"replace_geometry",
|
|
5153
2083
|
{
|
|
5154
2084
|
description: "Replace a shape element geometry with a preset or custom SVG path",
|
|
5155
2085
|
inputSchema: ReplaceGeometrySchema.shape
|
|
5156
2086
|
},
|
|
5157
2087
|
async (params) => {
|
|
5158
|
-
const result = await
|
|
2088
|
+
const result = await runMcpTool2(
|
|
5159
2089
|
params.filePath,
|
|
5160
2090
|
(ctx) => replaceGeometry(ctx, {
|
|
5161
2091
|
...params,
|
|
@@ -5165,21 +2095,21 @@ function createServer() {
|
|
|
5165
2095
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5166
2096
|
}
|
|
5167
2097
|
);
|
|
5168
|
-
|
|
2098
|
+
server.registerTool(
|
|
5169
2099
|
"set_element_lock",
|
|
5170
2100
|
{
|
|
5171
2101
|
description: "Lock or unlock an element (prevent move, resize, rotation, selection, text edit)",
|
|
5172
2102
|
inputSchema: SetElementLockSchema.shape
|
|
5173
2103
|
},
|
|
5174
2104
|
async (params) => {
|
|
5175
|
-
const result = await
|
|
2105
|
+
const result = await runMcpTool2(
|
|
5176
2106
|
params.filePath,
|
|
5177
2107
|
(ctx) => setElementLockT(ctx, params)
|
|
5178
2108
|
);
|
|
5179
2109
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5180
2110
|
}
|
|
5181
2111
|
);
|
|
5182
|
-
|
|
2112
|
+
server.registerTool(
|
|
5183
2113
|
"validate_presentation",
|
|
5184
2114
|
{
|
|
5185
2115
|
description: "Validate PPTX structural integrity (content types, relationships, XML)",
|
|
@@ -5187,13 +2117,13 @@ function createServer() {
|
|
|
5187
2117
|
},
|
|
5188
2118
|
async (params) => {
|
|
5189
2119
|
const { readFile: readFile2 } = await import('fs/promises');
|
|
5190
|
-
const safePath =
|
|
2120
|
+
const safePath = resolveScopedFilePath2(params.filePath);
|
|
5191
2121
|
const bytes = await readFile2(safePath);
|
|
5192
2122
|
const result = await validatePresentation(bytes.buffer);
|
|
5193
2123
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5194
2124
|
}
|
|
5195
2125
|
);
|
|
5196
|
-
|
|
2126
|
+
server.registerTool(
|
|
5197
2127
|
"repair_presentation",
|
|
5198
2128
|
{
|
|
5199
2129
|
description: "Auto-repair common PPTX structural issues",
|
|
@@ -5201,7 +2131,7 @@ function createServer() {
|
|
|
5201
2131
|
},
|
|
5202
2132
|
async (params) => {
|
|
5203
2133
|
const { readFile: readFile2, writeFile: writeFile2 } = await import('fs/promises');
|
|
5204
|
-
const safePath =
|
|
2134
|
+
const safePath = resolveScopedFilePath2(params.filePath);
|
|
5205
2135
|
const bytes = await readFile2(safePath);
|
|
5206
2136
|
const { result, repairedBytes } = await repairPresentation(
|
|
5207
2137
|
bytes.buffer
|
|
@@ -5212,147 +2142,143 @@ function createServer() {
|
|
|
5212
2142
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5213
2143
|
}
|
|
5214
2144
|
);
|
|
5215
|
-
|
|
2145
|
+
server.registerTool(
|
|
5216
2146
|
"get_presentation_properties",
|
|
5217
2147
|
{
|
|
5218
2148
|
description: "Get slideshow properties (show type, loop, advance mode, slide range)",
|
|
5219
2149
|
inputSchema: GetPresentationPropertiesSchema.shape
|
|
5220
2150
|
},
|
|
5221
2151
|
async (params) => {
|
|
5222
|
-
const result = await
|
|
2152
|
+
const result = await runMcpTool2(
|
|
5223
2153
|
params.filePath,
|
|
5224
2154
|
(ctx) => getPresentationProperties(ctx)
|
|
5225
2155
|
);
|
|
5226
2156
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5227
2157
|
}
|
|
5228
2158
|
);
|
|
5229
|
-
|
|
2159
|
+
server.registerTool(
|
|
5230
2160
|
"update_presentation_properties",
|
|
5231
2161
|
{
|
|
5232
2162
|
description: "Update slideshow properties (show type, loop, advance mode, pen color)",
|
|
5233
2163
|
inputSchema: UpdatePresentationPropertiesSchema.shape
|
|
5234
2164
|
},
|
|
5235
2165
|
async (params) => {
|
|
5236
|
-
const result = await
|
|
2166
|
+
const result = await runMcpTool2(
|
|
5237
2167
|
params.filePath,
|
|
5238
2168
|
(ctx) => updatePresentationProperties(ctx, params)
|
|
5239
2169
|
);
|
|
5240
2170
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5241
2171
|
}
|
|
5242
2172
|
);
|
|
5243
|
-
|
|
2173
|
+
server.registerTool(
|
|
5244
2174
|
"get_layouts",
|
|
5245
2175
|
{
|
|
5246
2176
|
description: "List available slide layouts from the presentation masters",
|
|
5247
2177
|
inputSchema: GetLayoutsSchema.shape
|
|
5248
2178
|
},
|
|
5249
2179
|
async (params) => {
|
|
5250
|
-
const result = await
|
|
2180
|
+
const result = await runMcpTool2(params.filePath, (ctx) => getLayouts(ctx));
|
|
5251
2181
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5252
2182
|
}
|
|
5253
2183
|
);
|
|
5254
|
-
|
|
2184
|
+
server.registerTool(
|
|
5255
2185
|
"apply_layout",
|
|
5256
2186
|
{
|
|
5257
2187
|
description: "Apply a slide layout to a specific slide",
|
|
5258
2188
|
inputSchema: ApplyLayoutSchema.shape
|
|
5259
2189
|
},
|
|
5260
2190
|
async (params) => {
|
|
5261
|
-
const result = await
|
|
2191
|
+
const result = await runMcpTool2(
|
|
5262
2192
|
params.filePath,
|
|
5263
2193
|
(ctx) => applyLayout(ctx, params)
|
|
5264
2194
|
);
|
|
5265
2195
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5266
2196
|
}
|
|
5267
2197
|
);
|
|
5268
|
-
|
|
2198
|
+
server.registerTool(
|
|
5269
2199
|
"ole_get_content",
|
|
5270
2200
|
{
|
|
5271
2201
|
description: "Inspect an embedded OLE object's editable content: resolved kind, plus the sheet grid, paragraph list, or nested-deck slide summaries, whichever applies",
|
|
5272
2202
|
inputSchema: GetOleContentSchema.shape
|
|
5273
2203
|
},
|
|
5274
2204
|
async (params) => {
|
|
5275
|
-
const result = await
|
|
2205
|
+
const result = await runMcpTool2(
|
|
5276
2206
|
params.filePath,
|
|
5277
2207
|
(ctx) => getOleContent(ctx, params)
|
|
5278
2208
|
);
|
|
5279
2209
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5280
2210
|
}
|
|
5281
2211
|
);
|
|
5282
|
-
|
|
2212
|
+
server.registerTool(
|
|
5283
2213
|
"ole_set_sheet_cell",
|
|
5284
2214
|
{
|
|
5285
2215
|
description: "Edit one cell of an embedded Excel OLE object's first worksheet",
|
|
5286
2216
|
inputSchema: SetOleSheetCellSchema.shape
|
|
5287
2217
|
},
|
|
5288
2218
|
async (params) => {
|
|
5289
|
-
const result = await
|
|
2219
|
+
const result = await runMcpTool2(
|
|
5290
2220
|
params.filePath,
|
|
5291
2221
|
(ctx) => setOleSheetCell(ctx, params)
|
|
5292
2222
|
);
|
|
5293
2223
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5294
2224
|
}
|
|
5295
2225
|
);
|
|
5296
|
-
|
|
2226
|
+
server.registerTool(
|
|
5297
2227
|
"ole_set_document_paragraph",
|
|
5298
2228
|
{
|
|
5299
2229
|
description: "Replace one paragraph's text in an embedded Word (.docx or legacy .doc) OLE object",
|
|
5300
2230
|
inputSchema: SetOleDocumentParagraphSchema.shape
|
|
5301
2231
|
},
|
|
5302
2232
|
async (params) => {
|
|
5303
|
-
const result = await
|
|
2233
|
+
const result = await runMcpTool2(
|
|
5304
2234
|
params.filePath,
|
|
5305
2235
|
(ctx) => setOleDocumentParagraph(ctx, params)
|
|
5306
2236
|
);
|
|
5307
2237
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5308
2238
|
}
|
|
5309
2239
|
);
|
|
5310
|
-
|
|
2240
|
+
server.registerTool(
|
|
5311
2241
|
"ole_set_deck_slide_title",
|
|
5312
2242
|
{
|
|
5313
2243
|
description: "Edit one text-bearing shape on one slide of an embedded nested-deck (PowerPoint) OLE object, via a full load/save round-trip through the nested deck (call ole_get_content first to discover each slide's elementIds)",
|
|
5314
2244
|
inputSchema: SetOleDeckSlideTitleSchema.shape
|
|
5315
2245
|
},
|
|
5316
2246
|
async (params) => {
|
|
5317
|
-
const result = await
|
|
2247
|
+
const result = await runMcpTool2(
|
|
5318
2248
|
params.filePath,
|
|
5319
2249
|
(ctx) => setOleDeckSlideTitle(ctx, params)
|
|
5320
2250
|
);
|
|
5321
2251
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5322
2252
|
}
|
|
5323
2253
|
);
|
|
5324
|
-
|
|
2254
|
+
server.registerTool(
|
|
5325
2255
|
"ole_replace_file",
|
|
5326
2256
|
{
|
|
5327
2257
|
description: `Replace an embedded OLE object's payload wholesale with an arbitrary file; works for any OLE kind, including a generic "Package" object or an unsupported format`,
|
|
5328
2258
|
inputSchema: ReplaceOleFileSchema.shape
|
|
5329
2259
|
},
|
|
5330
2260
|
async (params) => {
|
|
5331
|
-
const result = await
|
|
2261
|
+
const result = await runMcpTool2(
|
|
5332
2262
|
params.filePath,
|
|
5333
2263
|
(ctx) => replaceOleFileT(ctx, params)
|
|
5334
2264
|
);
|
|
5335
2265
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5336
2266
|
}
|
|
5337
2267
|
);
|
|
5338
|
-
|
|
2268
|
+
server.registerTool(
|
|
5339
2269
|
"ole_set_object_name",
|
|
5340
2270
|
{
|
|
5341
2271
|
description: "Rename an OLE object's Object Name (p:oleObj/@name); regenerates the baked-in icon caption too when the object is displayed as an icon",
|
|
5342
2272
|
inputSchema: SetOleObjectNameSchema.shape
|
|
5343
2273
|
},
|
|
5344
2274
|
async (params) => {
|
|
5345
|
-
const result = await
|
|
2275
|
+
const result = await runMcpTool2(
|
|
5346
2276
|
params.filePath,
|
|
5347
2277
|
(ctx) => setOleObjectNameT(ctx, params)
|
|
5348
2278
|
);
|
|
5349
2279
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5350
2280
|
}
|
|
5351
2281
|
);
|
|
5352
|
-
return server2;
|
|
5353
2282
|
}
|
|
5354
2283
|
|
|
5355
|
-
|
|
5356
|
-
var server = createServer();
|
|
5357
|
-
var transport = new StdioServerTransport();
|
|
5358
|
-
void server.connect(transport);
|
|
2284
|
+
export { createServer, registerTools };
|