@json-to-office/core-pptx 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -6,5 +6,7 @@ export { isPresentationComponent, isSlideComponent } from './types';
6
6
  export { W as WarningCodes } from './utils/warn';
7
7
  export type { WarningCode } from './utils/warn';
8
8
  export { DEFAULT_PPTX_THEME, getPptxTheme, pptxThemes } from './themes';
9
+ export { createComponent, createVersion, createPresentationGenerator, resolveComponentVersion, validateComponentProps, validatePresentation, cleanComponentProps, ComponentValidationError, DuplicateComponentError, generatePluginPresentationSchema, exportPluginSchema, } from './plugin';
10
+ export type { CustomComponent, ComponentVersion, ComponentVersionMap, RenderFunction, RenderContext, PresentationGeneratorOptions, PresentationGenerator as PluginPresentationGenerator, PresentationGeneratorBuilder, BufferGenerationResult as PluginBufferGenerationResult, FileGenerationResult as PluginFileGenerationResult, ValidationResult as PluginValidationResult, ExtractCustomComponentType, CustomComponentUnion, ExtendedPptxComponentInput, ExtendedPresentationComponent, InferBuilderComponents, InferDocumentType, InferComponentDefinition, ComponentValidationResult, ValidationError as PluginValidationError, } from './plugin';
9
11
  export { renderTextComponent, renderImageComponent, renderShapeComponent, renderTableComponent, renderHighchartsComponent, renderComponent, } from './components';
10
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAGD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,iCAAiC,EACjC,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAG5E,YAAY,EACV,kBAAkB,EAClB,+BAA+B,EAC/B,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,eAAe,EACf,YAAY,GACb,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGpE,OAAO,EAAE,CAAC,IAAI,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGxE,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,eAAe,GAChB,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAGD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,uBAAuB,EACvB,gBAAgB,EAChB,gBAAgB,EAChB,iCAAiC,EACjC,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAG5E,YAAY,EACV,kBAAkB,EAClB,+BAA+B,EAC/B,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,eAAe,EACf,YAAY,GACb,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGpE,OAAO,EAAE,CAAC,IAAI,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGxE,OAAO,EACL,eAAe,EACf,aAAa,EACb,2BAA2B,EAC3B,uBAAuB,EACvB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EACvB,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,UAAU,CAAC;AAElB,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,4BAA4B,EAC5B,qBAAqB,IAAI,2BAA2B,EACpD,4BAA4B,EAC5B,sBAAsB,IAAI,4BAA4B,EACtD,oBAAoB,IAAI,0BAA0B,EAClD,gBAAgB,IAAI,sBAAsB,EAC1C,0BAA0B,EAC1B,oBAAoB,EACpB,0BAA0B,EAC1B,6BAA6B,EAC7B,sBAAsB,EACtB,iBAAiB,EACjB,wBAAwB,EACxB,yBAAyB,EACzB,eAAe,IAAI,qBAAqB,GACzC,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,eAAe,GAChB,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1175,18 +1175,407 @@ var PresentationGenerator = {
1175
1175
  isPresentationComponentDefinition
1176
1176
  };
1177
1177
 
1178
+ // src/plugin/index.ts
1179
+ import {
1180
+ createComponent,
1181
+ createVersion
1182
+ } from "@json-to-office/shared/plugin";
1183
+
1184
+ // src/plugin/createPresentationGenerator.ts
1185
+ import JSZip2 from "jszip";
1186
+ import {
1187
+ resolveComponentVersion as resolveComponentVersion2,
1188
+ DuplicateComponentError as DuplicateComponentError2,
1189
+ ComponentValidationError as ComponentValidationError3
1190
+ } from "@json-to-office/shared/plugin";
1191
+
1192
+ // src/plugin/validation.ts
1193
+ import {
1194
+ resolveComponentVersion,
1195
+ validateCustomComponentProps,
1196
+ ComponentValidationError
1197
+ } from "@json-to-office/shared/plugin";
1198
+ import {
1199
+ DuplicateComponentError,
1200
+ ComponentValidationError as ComponentValidationError2
1201
+ } from "@json-to-office/shared/plugin";
1202
+ function validateComponentProps(schema, props, componentName) {
1203
+ return validateCustomComponentProps(schema.propsSchema, props, {
1204
+ clean: true,
1205
+ applyDefaults: true,
1206
+ componentName
1207
+ });
1208
+ }
1209
+ function validatePresentation(document, customComponents) {
1210
+ const errors = [];
1211
+ function validateComponents(components, pathPrefix = "children") {
1212
+ components.forEach((componentData, index) => {
1213
+ const customComponent = customComponents.find(
1214
+ (cc) => cc.name === componentData.name
1215
+ );
1216
+ if (customComponent) {
1217
+ const versionEntry = resolveComponentVersion(
1218
+ customComponent.name,
1219
+ customComponent.versions,
1220
+ componentData.version
1221
+ );
1222
+ const validation = validateComponentProps(
1223
+ versionEntry,
1224
+ componentData.props,
1225
+ customComponent.name
1226
+ );
1227
+ if (!validation.valid && validation.errors) {
1228
+ const indexedErrors = validation.errors.map(
1229
+ (error) => ({
1230
+ ...error,
1231
+ path: `${pathPrefix}[${index}].${error.path}`
1232
+ })
1233
+ );
1234
+ errors.push(...indexedErrors);
1235
+ }
1236
+ }
1237
+ if (componentData.children && Array.isArray(componentData.children)) {
1238
+ validateComponents(
1239
+ componentData.children,
1240
+ `${pathPrefix}[${index}].children`
1241
+ );
1242
+ }
1243
+ });
1244
+ }
1245
+ if (document.children) {
1246
+ validateComponents(document.children);
1247
+ }
1248
+ return errors.length > 0 ? { valid: false, errors } : { valid: true, errors: [] };
1249
+ }
1250
+ function getValidatedProps(schema, props) {
1251
+ const validation = validateComponentProps(schema, props);
1252
+ if (!validation.valid) {
1253
+ throw new ComponentValidationError(validation.errors || [], props);
1254
+ }
1255
+ return validation.data;
1256
+ }
1257
+ var cleanComponentProps = getValidatedProps;
1258
+
1259
+ // src/plugin/schema.ts
1260
+ import {
1261
+ generateUnifiedDocumentSchema
1262
+ } from "@json-to-office/shared-pptx";
1263
+ function generatePluginPresentationSchema(customComponents) {
1264
+ const customComponentInfos = customComponents.map(
1265
+ (component) => {
1266
+ const versionKeys = Object.keys(component.versions);
1267
+ const versions = versionKeys.map((v) => ({
1268
+ version: v,
1269
+ propsSchema: component.versions[v].propsSchema,
1270
+ hasChildren: component.versions[v].hasChildren === true,
1271
+ description: component.versions[v].description
1272
+ }));
1273
+ return {
1274
+ name: component.name,
1275
+ versions
1276
+ };
1277
+ }
1278
+ );
1279
+ return generateUnifiedDocumentSchema({
1280
+ customComponents: customComponentInfos
1281
+ });
1282
+ }
1283
+ async function exportPluginSchema(customComponents, outputPath, options = {}) {
1284
+ const { prettyPrint = true } = options;
1285
+ const { convertToJsonSchema, exportSchemaToFile } = await import("@json-to-office/shared");
1286
+ const schema = generatePluginPresentationSchema(customComponents);
1287
+ const jsonSchema = convertToJsonSchema(schema, {
1288
+ $schema: "http://json-schema.org/draft-07/schema#"
1289
+ });
1290
+ await exportSchemaToFile(jsonSchema, outputPath, { prettyPrint });
1291
+ }
1292
+
1293
+ // src/plugin/createPresentationGenerator.ts
1294
+ var MEDIUM_STYLE_2_ACCENT_12 = "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}";
1295
+ var NO_STYLE_NO_GRID2 = "{2D5ABB26-0587-4C30-8999-92F81FD0307C}";
1296
+ async function neutralizeTableStyle2(buffer) {
1297
+ const zip = await JSZip2.loadAsync(buffer);
1298
+ let changed = false;
1299
+ for (const [path2, entry] of Object.entries(zip.files)) {
1300
+ if (!path2.match(/^ppt\/slides\/slide\d+\.xml$/)) continue;
1301
+ const xml = await entry.async("string");
1302
+ if (xml.includes(MEDIUM_STYLE_2_ACCENT_12)) {
1303
+ zip.file(path2, xml.replaceAll(MEDIUM_STYLE_2_ACCENT_12, NO_STYLE_NO_GRID2));
1304
+ changed = true;
1305
+ }
1306
+ }
1307
+ return changed ? await zip.generateAsync({ type: "nodebuffer" }) : buffer;
1308
+ }
1309
+ function createBuilderImpl(state) {
1310
+ const componentMap = new Map(state.components.map((c) => [c.name, c]));
1311
+ async function processSlideComponents(components, warningsCollector, theme, depth = 0) {
1312
+ if (depth > 20) {
1313
+ throw new Error(
1314
+ "Maximum component nesting depth exceeded (20). Check for circular component references."
1315
+ );
1316
+ }
1317
+ const processed = [];
1318
+ for (const componentData of components) {
1319
+ const customComponent = componentMap.get(componentData.name);
1320
+ if (customComponent) {
1321
+ try {
1322
+ if (!componentData.props) {
1323
+ throw new Error(
1324
+ `Custom component '${componentData.name}' must have a 'props' property. Use format: { name: '${componentData.name}', props: {...} }`
1325
+ );
1326
+ }
1327
+ const componentWithVersion = componentData;
1328
+ const versionEntry = resolveComponentVersion2(
1329
+ customComponent.name,
1330
+ customComponent.versions,
1331
+ componentWithVersion.version
1332
+ );
1333
+ const cleanedProps = cleanComponentProps(
1334
+ versionEntry,
1335
+ componentWithVersion.props
1336
+ );
1337
+ let nestedChildren;
1338
+ if (componentWithVersion.children && Array.isArray(componentWithVersion.children)) {
1339
+ nestedChildren = await processSlideComponents(
1340
+ componentWithVersion.children,
1341
+ warningsCollector,
1342
+ theme,
1343
+ depth + 1
1344
+ );
1345
+ }
1346
+ const versionLabel = componentWithVersion.version ? `${customComponent.name}@${componentWithVersion.version}` : customComponent.name;
1347
+ const addWarning = (message, context) => {
1348
+ warningsCollector.push({
1349
+ code: context?.code ?? "PLUGIN_WARNING",
1350
+ message,
1351
+ component: versionLabel,
1352
+ slide: context?.slide
1353
+ });
1354
+ };
1355
+ const result = await versionEntry.render({
1356
+ props: cleanedProps,
1357
+ theme,
1358
+ addWarning,
1359
+ children: nestedChildren
1360
+ });
1361
+ const resultComponents = Array.isArray(result) ? result : [result];
1362
+ const processedResult = await processSlideComponents(
1363
+ resultComponents,
1364
+ warningsCollector,
1365
+ theme,
1366
+ depth + 1
1367
+ );
1368
+ processed.push(...processedResult);
1369
+ if (state.debug) {
1370
+ console.log(
1371
+ `Processed custom component '${versionLabel}':`,
1372
+ processedResult
1373
+ );
1374
+ }
1375
+ } catch (error) {
1376
+ if (error instanceof ComponentValidationError3) {
1377
+ throw error;
1378
+ }
1379
+ throw new Error(
1380
+ `Error processing custom component '${customComponent.name}': ${error instanceof Error ? error.message : String(error)}`
1381
+ );
1382
+ }
1383
+ } else {
1384
+ if (componentData.children && Array.isArray(componentData.children)) {
1385
+ const processedChildren = await processSlideComponents(
1386
+ componentData.children,
1387
+ warningsCollector,
1388
+ theme,
1389
+ depth + 1
1390
+ );
1391
+ processed.push({
1392
+ ...componentData,
1393
+ children: processedChildren
1394
+ });
1395
+ } else {
1396
+ processed.push(componentData);
1397
+ }
1398
+ }
1399
+ }
1400
+ return processed;
1401
+ }
1402
+ function addComponent(component) {
1403
+ if (!component.name) {
1404
+ throw new Error("Component name is required");
1405
+ }
1406
+ if (state.componentNames.has(component.name)) {
1407
+ throw new DuplicateComponentError2(component.name);
1408
+ }
1409
+ const newComponentNames = new Set(state.componentNames);
1410
+ newComponentNames.add(component.name);
1411
+ const newState = {
1412
+ components: [...state.components, component],
1413
+ componentNames: newComponentNames,
1414
+ theme: state.theme,
1415
+ customThemes: state.customThemes,
1416
+ debug: state.debug
1417
+ };
1418
+ return createBuilderImpl(
1419
+ newState
1420
+ );
1421
+ }
1422
+ async function generate(document) {
1423
+ try {
1424
+ const internalDocument = document;
1425
+ if (!internalDocument || internalDocument.name !== "pptx") {
1426
+ throw new Error("Top-level component must be a pptx component");
1427
+ }
1428
+ const themeName = typeof state.theme === "string" ? state.theme : internalDocument.props.theme ?? "default";
1429
+ const resolvedTheme = typeof state.theme === "object" ? state.theme : state.customThemes?.[themeName] ?? getPptxTheme(themeName);
1430
+ const warnings = [];
1431
+ const processedChildren = internalDocument.children ? await processAllSlides(
1432
+ internalDocument.children,
1433
+ warnings,
1434
+ resolvedTheme
1435
+ ) : [];
1436
+ const processedDocument = {
1437
+ ...internalDocument,
1438
+ children: processedChildren
1439
+ };
1440
+ const processed = processPresentation(processedDocument, {
1441
+ customThemes: state.customThemes
1442
+ });
1443
+ const pptx = await renderPresentation(processed, warnings);
1444
+ const data = await pptx.write({ outputType: "nodebuffer" });
1445
+ const buffer = await neutralizeTableStyle2(data);
1446
+ return { buffer, warnings };
1447
+ } catch (error) {
1448
+ if (state.debug) {
1449
+ console.error("Presentation generation error:", error);
1450
+ }
1451
+ throw error;
1452
+ }
1453
+ }
1454
+ async function processAllSlides(children, warnings, theme) {
1455
+ const result = [];
1456
+ for (const child of children) {
1457
+ if (child.name === "slide" && child.children) {
1458
+ const processedSlideChildren = await processSlideComponents(
1459
+ child.children,
1460
+ warnings,
1461
+ theme
1462
+ );
1463
+ result.push({ ...child, children: processedSlideChildren });
1464
+ } else {
1465
+ const processedTopLevel = await processSlideComponents(
1466
+ [child],
1467
+ warnings,
1468
+ theme
1469
+ );
1470
+ result.push(...processedTopLevel);
1471
+ }
1472
+ }
1473
+ return result;
1474
+ }
1475
+ async function generateFile(document, outputPath) {
1476
+ const { buffer, warnings } = await generate(document);
1477
+ const fs = await import("fs/promises");
1478
+ await fs.writeFile(outputPath, new Uint8Array(buffer));
1479
+ return { warnings };
1480
+ }
1481
+ function getComponentNames() {
1482
+ return Array.from(state.componentNames);
1483
+ }
1484
+ function validate(document) {
1485
+ try {
1486
+ const internalDocument = document;
1487
+ const result = validatePresentation(
1488
+ internalDocument,
1489
+ state.components
1490
+ );
1491
+ if (!result.valid) {
1492
+ return {
1493
+ valid: false,
1494
+ errors: result.errors.map((e) => ({
1495
+ path: e.path,
1496
+ message: e.message
1497
+ }))
1498
+ };
1499
+ }
1500
+ return { valid: true };
1501
+ } catch (error) {
1502
+ if (error instanceof ComponentValidationError3) {
1503
+ return {
1504
+ valid: false,
1505
+ errors: error.errors.map((e) => ({
1506
+ path: e.path,
1507
+ message: e.message
1508
+ }))
1509
+ };
1510
+ }
1511
+ return {
1512
+ valid: false,
1513
+ errors: [
1514
+ {
1515
+ path: "document",
1516
+ message: error instanceof Error ? error.message : String(error)
1517
+ }
1518
+ ]
1519
+ };
1520
+ }
1521
+ }
1522
+ function generateSchema() {
1523
+ return generatePluginPresentationSchema(
1524
+ state.components
1525
+ );
1526
+ }
1527
+ async function exportSchemaToFile(outputPath, options) {
1528
+ await exportPluginSchema(
1529
+ state.components,
1530
+ outputPath,
1531
+ options
1532
+ );
1533
+ }
1534
+ return Object.freeze({
1535
+ addComponent,
1536
+ generate,
1537
+ generateBuffer: generate,
1538
+ generateFile,
1539
+ getComponentNames,
1540
+ validate,
1541
+ generateSchema,
1542
+ exportSchema: exportSchemaToFile
1543
+ });
1544
+ }
1545
+ function createPresentationGenerator(options = {}) {
1546
+ const initialState = {
1547
+ components: [],
1548
+ componentNames: /* @__PURE__ */ new Set(),
1549
+ theme: options.theme,
1550
+ customThemes: options.customThemes,
1551
+ debug: options.debug ?? false
1552
+ };
1553
+ return createBuilderImpl(initialState);
1554
+ }
1555
+
1556
+ // src/plugin/index.ts
1557
+ import { resolveComponentVersion as resolveComponentVersion3 } from "@json-to-office/shared/plugin";
1558
+
1178
1559
  // src/index.ts
1179
1560
  function getPptxCoreVersion() {
1180
1561
  return "PptxCore v1.0.0";
1181
1562
  }
1182
1563
  export {
1564
+ ComponentValidationError2 as ComponentValidationError,
1183
1565
  DEFAULT_PPTX_THEME,
1566
+ DuplicateComponentError,
1184
1567
  PresentationGenerator,
1185
1568
  W as WarningCodes,
1569
+ cleanComponentProps,
1570
+ createComponent,
1571
+ createPresentationGenerator,
1572
+ createVersion,
1573
+ exportPluginSchema,
1186
1574
  generateAndSaveFromJson,
1187
1575
  generateBufferFromJson,
1188
1576
  generateBufferWithWarnings,
1189
1577
  generateFromFile,
1578
+ generatePluginPresentationSchema,
1190
1579
  generatePresentation,
1191
1580
  getPptxCoreVersion,
1192
1581
  getPptxTheme,
@@ -1200,6 +1589,9 @@ export {
1200
1589
  renderShapeComponent,
1201
1590
  renderTableComponent,
1202
1591
  renderTextComponent,
1203
- savePresentation
1592
+ resolveComponentVersion3 as resolveComponentVersion,
1593
+ savePresentation,
1594
+ validateComponentProps,
1595
+ validatePresentation
1204
1596
  };
1205
1597
  //# sourceMappingURL=index.js.map