@json-to-office/core-pptx 1.4.0 → 1.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/dist/core/generateFromIr.d.ts.map +1 -1
- package/dist/core/generationOptions.d.ts +4 -0
- package/dist/core/generationOptions.d.ts.map +1 -1
- package/dist/core/grid.d.ts.map +1 -1
- package/dist/core/placeholders.d.ts +21 -0
- package/dist/core/placeholders.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1253 -315
- package/dist/index.js.map +1 -1
- package/dist/ir/compiler.d.ts.map +1 -1
- package/dist/quality/facts.d.ts +59 -0
- package/dist/quality/facts.d.ts.map +1 -0
- package/dist/quality/preflight.d.ts +15 -0
- package/dist/quality/preflight.d.ts.map +1 -0
- package/dist/quality/rules.d.ts +41 -0
- package/dist/quality/rules.d.ts.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -2235,99 +2235,6 @@ function applyFontWeight(params) {
|
|
|
2235
2235
|
return { fontFace: synth.family, bold: synth.bold, italic: synth.italic };
|
|
2236
2236
|
}
|
|
2237
2237
|
|
|
2238
|
-
// src/utils/componentDefaults.ts
|
|
2239
|
-
import { mergeWithDefaults } from "@json-to-office/shared";
|
|
2240
|
-
function getComponentDefaults(theme) {
|
|
2241
|
-
return theme.componentDefaults || {};
|
|
2242
|
-
}
|
|
2243
|
-
function getTextDefaults(theme) {
|
|
2244
|
-
return getComponentDefaults(theme).text || {};
|
|
2245
|
-
}
|
|
2246
|
-
function getImageDefaults(theme) {
|
|
2247
|
-
return getComponentDefaults(theme).image || {};
|
|
2248
|
-
}
|
|
2249
|
-
function getShapeDefaults(theme) {
|
|
2250
|
-
return getComponentDefaults(theme).shape || {};
|
|
2251
|
-
}
|
|
2252
|
-
function getTableDefaults(theme) {
|
|
2253
|
-
return getComponentDefaults(theme).table || {};
|
|
2254
|
-
}
|
|
2255
|
-
function getHighchartsDefaults(theme) {
|
|
2256
|
-
return getComponentDefaults(theme).highcharts || {};
|
|
2257
|
-
}
|
|
2258
|
-
function getChartDefaults(theme) {
|
|
2259
|
-
return getComponentDefaults(theme).chart || {};
|
|
2260
|
-
}
|
|
2261
|
-
function getCustomComponentDefaults(theme, componentName) {
|
|
2262
|
-
const defaults = getComponentDefaults(theme);
|
|
2263
|
-
return defaults?.[componentName] || {};
|
|
2264
|
-
}
|
|
2265
|
-
function resolveTextProps(props, theme) {
|
|
2266
|
-
return mergeWithDefaults(props, getTextDefaults(theme));
|
|
2267
|
-
}
|
|
2268
|
-
function resolveImageProps(props, theme) {
|
|
2269
|
-
return mergeWithDefaults(props, getImageDefaults(theme));
|
|
2270
|
-
}
|
|
2271
|
-
function resolveShapeProps(props, theme) {
|
|
2272
|
-
return mergeWithDefaults(props, getShapeDefaults(theme));
|
|
2273
|
-
}
|
|
2274
|
-
function resolveTableProps(props, theme) {
|
|
2275
|
-
return mergeWithDefaults(props, getTableDefaults(theme));
|
|
2276
|
-
}
|
|
2277
|
-
function resolveHighchartsProps(props, theme) {
|
|
2278
|
-
return mergeWithDefaults(props, getHighchartsDefaults(theme));
|
|
2279
|
-
}
|
|
2280
|
-
function resolveChartProps(props, theme) {
|
|
2281
|
-
return mergeWithDefaults(props, getChartDefaults(theme));
|
|
2282
|
-
}
|
|
2283
|
-
function resolveCustomComponentProps(props, theme, componentName) {
|
|
2284
|
-
const defaults = getCustomComponentDefaults(theme, componentName);
|
|
2285
|
-
return mergeWithDefaults(props, defaults);
|
|
2286
|
-
}
|
|
2287
|
-
var TYPE_GETTERS = {
|
|
2288
|
-
text: getTextDefaults,
|
|
2289
|
-
image: getImageDefaults,
|
|
2290
|
-
shape: getShapeDefaults,
|
|
2291
|
-
table: getTableDefaults,
|
|
2292
|
-
highcharts: getHighchartsDefaults,
|
|
2293
|
-
chart: getChartDefaults
|
|
2294
|
-
};
|
|
2295
|
-
function getDefaultsForType(componentName, theme) {
|
|
2296
|
-
const getter = TYPE_GETTERS[componentName];
|
|
2297
|
-
return getter ? getter(theme) : getCustomComponentDefaults(theme, componentName);
|
|
2298
|
-
}
|
|
2299
|
-
|
|
2300
|
-
// src/utils/resolveComponentTree.ts
|
|
2301
|
-
var RESOLVER_MAP = {
|
|
2302
|
-
text: resolveTextProps,
|
|
2303
|
-
image: resolveImageProps,
|
|
2304
|
-
shape: resolveShapeProps,
|
|
2305
|
-
table: resolveTableProps,
|
|
2306
|
-
highcharts: resolveHighchartsProps,
|
|
2307
|
-
chart: resolveChartProps
|
|
2308
|
-
};
|
|
2309
|
-
function resolveComponentDefaults(component, theme) {
|
|
2310
|
-
const resolver = RESOLVER_MAP[component.name];
|
|
2311
|
-
const resolvedProps = resolver ? resolver(component.props, theme) : resolveCustomComponentProps(
|
|
2312
|
-
component.props,
|
|
2313
|
-
theme,
|
|
2314
|
-
component.name
|
|
2315
|
-
);
|
|
2316
|
-
return { ...component, props: resolvedProps };
|
|
2317
|
-
}
|
|
2318
|
-
function resolveComponentTree(components, theme) {
|
|
2319
|
-
return components.map((component) => {
|
|
2320
|
-
const resolved = resolveComponentDefaults(component, theme);
|
|
2321
|
-
if (resolved.children && resolved.children.length > 0) {
|
|
2322
|
-
return {
|
|
2323
|
-
...resolved,
|
|
2324
|
-
children: resolveComponentTree(resolved.children, theme)
|
|
2325
|
-
};
|
|
2326
|
-
}
|
|
2327
|
-
return resolved;
|
|
2328
|
-
});
|
|
2329
|
-
}
|
|
2330
|
-
|
|
2331
2238
|
// src/utils/imageSource.ts
|
|
2332
2239
|
import path from "path";
|
|
2333
2240
|
var hasValue = (v) => typeof v === "string" && v.trim().length > 0;
|
|
@@ -2400,7 +2307,8 @@ var DEFAULT_GRID_CONFIG = {
|
|
|
2400
2307
|
};
|
|
2401
2308
|
function resolveMargin(margin) {
|
|
2402
2309
|
if (margin == null) return DEFAULT_GRID_CONFIG.margin;
|
|
2403
|
-
if (typeof margin === "number")
|
|
2310
|
+
if (typeof margin === "number")
|
|
2311
|
+
return { top: margin, right: margin, bottom: margin, left: margin };
|
|
2404
2312
|
return margin;
|
|
2405
2313
|
}
|
|
2406
2314
|
function resolveGutter(gutter) {
|
|
@@ -2464,24 +2372,198 @@ function resolveGridPosition(gridPos, gridConfig, slideWidth, slideHeight, warni
|
|
|
2464
2372
|
function resolveComponentGridPosition(component, gridConfig, slideWidth, slideHeight, warnings) {
|
|
2465
2373
|
const gridPos = component.props.grid;
|
|
2466
2374
|
if (!gridPos) return component;
|
|
2467
|
-
const resolved = resolveGridPosition(
|
|
2375
|
+
const resolved = resolveGridPosition(
|
|
2376
|
+
gridPos,
|
|
2377
|
+
gridConfig,
|
|
2378
|
+
slideWidth,
|
|
2379
|
+
slideHeight,
|
|
2380
|
+
warnings
|
|
2381
|
+
);
|
|
2468
2382
|
const { grid: _grid, ...restProps } = component.props;
|
|
2469
2383
|
const newProps = { ...restProps };
|
|
2470
2384
|
const hasPercentX = typeof newProps.x === "string" || typeof newProps.w === "string";
|
|
2471
2385
|
const hasPercentY = typeof newProps.y === "string" || typeof newProps.h === "string";
|
|
2472
2386
|
const toPercX = (v) => `${+(v / slideWidth * 100).toFixed(2)}%`;
|
|
2473
2387
|
const toPercY = (v) => `${+(v / slideHeight * 100).toFixed(2)}%`;
|
|
2474
|
-
if (newProps.x == null)
|
|
2475
|
-
|
|
2476
|
-
if (newProps.
|
|
2477
|
-
|
|
2388
|
+
if (newProps.x == null)
|
|
2389
|
+
newProps.x = hasPercentX ? toPercX(resolved.x) : resolved.x;
|
|
2390
|
+
if (newProps.y == null)
|
|
2391
|
+
newProps.y = hasPercentY ? toPercY(resolved.y) : resolved.y;
|
|
2392
|
+
if (newProps.w == null)
|
|
2393
|
+
newProps.w = hasPercentX ? toPercX(resolved.w) : resolved.w;
|
|
2394
|
+
if (newProps.h == null)
|
|
2395
|
+
newProps.h = hasPercentY ? toPercY(resolved.h) : resolved.h;
|
|
2478
2396
|
return { ...component, props: newProps };
|
|
2479
2397
|
}
|
|
2480
2398
|
|
|
2481
2399
|
// src/ir/compiler.ts
|
|
2482
2400
|
init_warn();
|
|
2401
|
+
|
|
2402
|
+
// src/core/placeholders.ts
|
|
2483
2403
|
import { mergeWithDefaults as mergeWithDefaults2 } from "@json-to-office/shared";
|
|
2484
2404
|
|
|
2405
|
+
// src/utils/componentDefaults.ts
|
|
2406
|
+
import { mergeWithDefaults } from "@json-to-office/shared";
|
|
2407
|
+
function getComponentDefaults(theme) {
|
|
2408
|
+
return theme.componentDefaults || {};
|
|
2409
|
+
}
|
|
2410
|
+
function getTextDefaults(theme) {
|
|
2411
|
+
return getComponentDefaults(theme).text || {};
|
|
2412
|
+
}
|
|
2413
|
+
function getImageDefaults(theme) {
|
|
2414
|
+
return getComponentDefaults(theme).image || {};
|
|
2415
|
+
}
|
|
2416
|
+
function getShapeDefaults(theme) {
|
|
2417
|
+
return getComponentDefaults(theme).shape || {};
|
|
2418
|
+
}
|
|
2419
|
+
function getTableDefaults(theme) {
|
|
2420
|
+
return getComponentDefaults(theme).table || {};
|
|
2421
|
+
}
|
|
2422
|
+
function getHighchartsDefaults(theme) {
|
|
2423
|
+
return getComponentDefaults(theme).highcharts || {};
|
|
2424
|
+
}
|
|
2425
|
+
function getChartDefaults(theme) {
|
|
2426
|
+
return getComponentDefaults(theme).chart || {};
|
|
2427
|
+
}
|
|
2428
|
+
function getCustomComponentDefaults(theme, componentName) {
|
|
2429
|
+
const defaults = getComponentDefaults(theme);
|
|
2430
|
+
return defaults?.[componentName] || {};
|
|
2431
|
+
}
|
|
2432
|
+
function resolveTextProps(props, theme) {
|
|
2433
|
+
return mergeWithDefaults(props, getTextDefaults(theme));
|
|
2434
|
+
}
|
|
2435
|
+
function resolveImageProps(props, theme) {
|
|
2436
|
+
return mergeWithDefaults(props, getImageDefaults(theme));
|
|
2437
|
+
}
|
|
2438
|
+
function resolveShapeProps(props, theme) {
|
|
2439
|
+
return mergeWithDefaults(props, getShapeDefaults(theme));
|
|
2440
|
+
}
|
|
2441
|
+
function resolveTableProps(props, theme) {
|
|
2442
|
+
return mergeWithDefaults(props, getTableDefaults(theme));
|
|
2443
|
+
}
|
|
2444
|
+
function resolveHighchartsProps(props, theme) {
|
|
2445
|
+
return mergeWithDefaults(props, getHighchartsDefaults(theme));
|
|
2446
|
+
}
|
|
2447
|
+
function resolveChartProps(props, theme) {
|
|
2448
|
+
return mergeWithDefaults(props, getChartDefaults(theme));
|
|
2449
|
+
}
|
|
2450
|
+
function resolveCustomComponentProps(props, theme, componentName) {
|
|
2451
|
+
const defaults = getCustomComponentDefaults(theme, componentName);
|
|
2452
|
+
return mergeWithDefaults(props, defaults);
|
|
2453
|
+
}
|
|
2454
|
+
var TYPE_GETTERS = {
|
|
2455
|
+
text: getTextDefaults,
|
|
2456
|
+
image: getImageDefaults,
|
|
2457
|
+
shape: getShapeDefaults,
|
|
2458
|
+
table: getTableDefaults,
|
|
2459
|
+
highcharts: getHighchartsDefaults,
|
|
2460
|
+
chart: getChartDefaults
|
|
2461
|
+
};
|
|
2462
|
+
function getDefaultsForType(componentName, theme) {
|
|
2463
|
+
const getter = TYPE_GETTERS[componentName];
|
|
2464
|
+
return getter ? getter(theme) : getCustomComponentDefaults(theme, componentName);
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
// src/utils/resolveComponentTree.ts
|
|
2468
|
+
var RESOLVER_MAP = {
|
|
2469
|
+
text: resolveTextProps,
|
|
2470
|
+
image: resolveImageProps,
|
|
2471
|
+
shape: resolveShapeProps,
|
|
2472
|
+
table: resolveTableProps,
|
|
2473
|
+
highcharts: resolveHighchartsProps,
|
|
2474
|
+
chart: resolveChartProps
|
|
2475
|
+
};
|
|
2476
|
+
function resolveComponentDefaults(component, theme) {
|
|
2477
|
+
const resolver = RESOLVER_MAP[component.name];
|
|
2478
|
+
const resolvedProps = resolver ? resolver(component.props, theme) : resolveCustomComponentProps(
|
|
2479
|
+
component.props,
|
|
2480
|
+
theme,
|
|
2481
|
+
component.name
|
|
2482
|
+
);
|
|
2483
|
+
return { ...component, props: resolvedProps };
|
|
2484
|
+
}
|
|
2485
|
+
function resolveComponentTree(components, theme) {
|
|
2486
|
+
return components.map((component) => {
|
|
2487
|
+
const resolved = resolveComponentDefaults(component, theme);
|
|
2488
|
+
if (resolved.children && resolved.children.length > 0) {
|
|
2489
|
+
return {
|
|
2490
|
+
...resolved,
|
|
2491
|
+
children: resolveComponentTree(resolved.children, theme)
|
|
2492
|
+
};
|
|
2493
|
+
}
|
|
2494
|
+
return resolved;
|
|
2495
|
+
});
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
// src/core/placeholders.ts
|
|
2499
|
+
init_warn();
|
|
2500
|
+
function resolvePlaceholderComponents(slide, template, effectiveGrid, options) {
|
|
2501
|
+
if (!slide.placeholders) return [];
|
|
2502
|
+
const out = [];
|
|
2503
|
+
if (!template) {
|
|
2504
|
+
for (const [name, component] of Object.entries(slide.placeholders)) {
|
|
2505
|
+
const defaulted = resolveComponentDefaults(component, options.theme);
|
|
2506
|
+
const positioned = defaulted.props.x != null || defaulted.props.y != null || defaulted.props.grid;
|
|
2507
|
+
if (!positioned) {
|
|
2508
|
+
warn(
|
|
2509
|
+
options.warnings,
|
|
2510
|
+
W.PLACEHOLDER_NO_POSITION,
|
|
2511
|
+
`Placeholder "${name}" has no template and no explicit position \u2014 skipped`,
|
|
2512
|
+
{ slide: options.slideIndex }
|
|
2513
|
+
);
|
|
2514
|
+
continue;
|
|
2515
|
+
}
|
|
2516
|
+
out.push({
|
|
2517
|
+
name,
|
|
2518
|
+
component: resolveComponentGridPosition(
|
|
2519
|
+
defaulted,
|
|
2520
|
+
effectiveGrid,
|
|
2521
|
+
options.slideWidth,
|
|
2522
|
+
options.slideHeight,
|
|
2523
|
+
options.warnings
|
|
2524
|
+
)
|
|
2525
|
+
});
|
|
2526
|
+
}
|
|
2527
|
+
return out;
|
|
2528
|
+
}
|
|
2529
|
+
const declared = new Map(
|
|
2530
|
+
(template.placeholders ?? []).map((placeholder) => [
|
|
2531
|
+
placeholder.name,
|
|
2532
|
+
placeholder
|
|
2533
|
+
])
|
|
2534
|
+
);
|
|
2535
|
+
for (const [name, component] of Object.entries(slide.placeholders)) {
|
|
2536
|
+
const definition = declared.get(name);
|
|
2537
|
+
if (!definition) {
|
|
2538
|
+
warn(
|
|
2539
|
+
options.warnings,
|
|
2540
|
+
W.UNKNOWN_PLACEHOLDER,
|
|
2541
|
+
`Unknown placeholder "${name}" in template "${slide.template}". Available: ${[...declared.keys()].join(", ")}`,
|
|
2542
|
+
{ slide: options.slideIndex }
|
|
2543
|
+
);
|
|
2544
|
+
continue;
|
|
2545
|
+
}
|
|
2546
|
+
const gridResolved = resolveComponentGridPosition(
|
|
2547
|
+
component,
|
|
2548
|
+
effectiveGrid,
|
|
2549
|
+
options.slideWidth,
|
|
2550
|
+
options.slideHeight,
|
|
2551
|
+
options.warnings
|
|
2552
|
+
);
|
|
2553
|
+
const typeDefaults = getDefaultsForType(component.name, options.theme);
|
|
2554
|
+
const positionDefaults = {};
|
|
2555
|
+
if (definition.x != null) positionDefaults.x = definition.x;
|
|
2556
|
+
if (definition.y != null) positionDefaults.y = definition.y;
|
|
2557
|
+
if (definition.w != null) positionDefaults.w = definition.w;
|
|
2558
|
+
if (definition.h != null) positionDefaults.h = definition.h;
|
|
2559
|
+
let props = mergeWithDefaults2(positionDefaults, typeDefaults);
|
|
2560
|
+
props = mergeWithDefaults2(definition.defaults?.props ?? {}, props);
|
|
2561
|
+
props = mergeWithDefaults2(gridResolved.props, props);
|
|
2562
|
+
out.push({ name, component: { ...gridResolved, props } });
|
|
2563
|
+
}
|
|
2564
|
+
return out;
|
|
2565
|
+
}
|
|
2566
|
+
|
|
2485
2567
|
// src/ir/resources.ts
|
|
2486
2568
|
init_units();
|
|
2487
2569
|
var ResourceTable = class {
|
|
@@ -2759,12 +2841,17 @@ function compileSlide(slide, slideIndex, processed, ctx) {
|
|
|
2759
2841
|
})
|
|
2760
2842
|
);
|
|
2761
2843
|
}
|
|
2762
|
-
for (const component of
|
|
2844
|
+
for (const { component } of resolvePlaceholderComponents(
|
|
2763
2845
|
slide,
|
|
2764
2846
|
template,
|
|
2765
2847
|
effectiveGrid,
|
|
2766
|
-
|
|
2767
|
-
|
|
2848
|
+
{
|
|
2849
|
+
theme: ctx.theme,
|
|
2850
|
+
slideWidth: ctx.slideWidthInches,
|
|
2851
|
+
slideHeight: ctx.slideHeightInches,
|
|
2852
|
+
slideIndex,
|
|
2853
|
+
warnings: ctx.warnings
|
|
2854
|
+
}
|
|
2768
2855
|
)) {
|
|
2769
2856
|
push(
|
|
2770
2857
|
compileComponent(component, {
|
|
@@ -2825,71 +2912,6 @@ function slideContextFor(slideIndex, processed) {
|
|
|
2825
2912
|
language: processed.language
|
|
2826
2913
|
};
|
|
2827
2914
|
}
|
|
2828
|
-
function compilePlaceholderComponents(slide, template, effectiveGrid, slideIndex, ctx) {
|
|
2829
|
-
if (!slide.placeholders) return [];
|
|
2830
|
-
const out = [];
|
|
2831
|
-
if (!template) {
|
|
2832
|
-
for (const [name, component] of Object.entries(slide.placeholders)) {
|
|
2833
|
-
const defaulted = resolveComponentDefaults(component, ctx.theme);
|
|
2834
|
-
const positioned = defaulted.props.x != null || defaulted.props.y != null || defaulted.props.grid;
|
|
2835
|
-
if (!positioned) {
|
|
2836
|
-
warn(
|
|
2837
|
-
ctx.warnings,
|
|
2838
|
-
W.PLACEHOLDER_NO_POSITION,
|
|
2839
|
-
`Placeholder "${name}" has no template and no explicit position \u2014 skipped`,
|
|
2840
|
-
{ slide: slideIndex }
|
|
2841
|
-
);
|
|
2842
|
-
continue;
|
|
2843
|
-
}
|
|
2844
|
-
out.push(
|
|
2845
|
-
resolveComponentGridPosition(
|
|
2846
|
-
defaulted,
|
|
2847
|
-
effectiveGrid,
|
|
2848
|
-
ctx.slideWidthInches,
|
|
2849
|
-
ctx.slideHeightInches,
|
|
2850
|
-
ctx.warnings
|
|
2851
|
-
)
|
|
2852
|
-
);
|
|
2853
|
-
}
|
|
2854
|
-
return out;
|
|
2855
|
-
}
|
|
2856
|
-
const declared = new Map(
|
|
2857
|
-
(template.placeholders ?? []).map((placeholder) => [
|
|
2858
|
-
placeholder.name,
|
|
2859
|
-
placeholder
|
|
2860
|
-
])
|
|
2861
|
-
);
|
|
2862
|
-
for (const [name, component] of Object.entries(slide.placeholders)) {
|
|
2863
|
-
const definition = declared.get(name);
|
|
2864
|
-
if (!definition) {
|
|
2865
|
-
warn(
|
|
2866
|
-
ctx.warnings,
|
|
2867
|
-
W.UNKNOWN_PLACEHOLDER,
|
|
2868
|
-
`Unknown placeholder "${name}" in template "${slide.template}". Available: ${[...declared.keys()].join(", ")}`,
|
|
2869
|
-
{ slide: slideIndex }
|
|
2870
|
-
);
|
|
2871
|
-
continue;
|
|
2872
|
-
}
|
|
2873
|
-
const gridResolved = resolveComponentGridPosition(
|
|
2874
|
-
component,
|
|
2875
|
-
effectiveGrid,
|
|
2876
|
-
ctx.slideWidthInches,
|
|
2877
|
-
ctx.slideHeightInches,
|
|
2878
|
-
ctx.warnings
|
|
2879
|
-
);
|
|
2880
|
-
const typeDefaults = getDefaultsForType(component.name, ctx.theme);
|
|
2881
|
-
const positionDefaults = {};
|
|
2882
|
-
if (definition.x != null) positionDefaults.x = definition.x;
|
|
2883
|
-
if (definition.y != null) positionDefaults.y = definition.y;
|
|
2884
|
-
if (definition.w != null) positionDefaults.w = definition.w;
|
|
2885
|
-
if (definition.h != null) positionDefaults.h = definition.h;
|
|
2886
|
-
let props = mergeWithDefaults2(positionDefaults, typeDefaults);
|
|
2887
|
-
props = mergeWithDefaults2(definition.defaults?.props ?? {}, props);
|
|
2888
|
-
props = mergeWithDefaults2(gridResolved.props, props);
|
|
2889
|
-
out.push({ ...gridResolved, props });
|
|
2890
|
-
}
|
|
2891
|
-
return out;
|
|
2892
|
-
}
|
|
2893
2915
|
function compileComponent(component, scope) {
|
|
2894
2916
|
if (component.enabled === false) return void 0;
|
|
2895
2917
|
switch (component.name) {
|
|
@@ -4124,141 +4146,6 @@ async function resolveDocumentFonts(document, theme, warnings, fonts) {
|
|
|
4124
4146
|
return resolved;
|
|
4125
4147
|
}
|
|
4126
4148
|
|
|
4127
|
-
// src/core/generationContext.ts
|
|
4128
|
-
import { applyExportMode } from "@json-to-office/shared";
|
|
4129
|
-
|
|
4130
|
-
// src/themes/defaults.ts
|
|
4131
|
-
var DEFAULT_TABLE = {
|
|
4132
|
-
border: { type: "solid", pt: 1, color: "background2" },
|
|
4133
|
-
headerRow: true
|
|
4134
|
-
};
|
|
4135
|
-
var DEFAULT_STYLES = {
|
|
4136
|
-
title: { fontSize: 36, bold: true, fontColor: "text", align: "center" },
|
|
4137
|
-
subtitle: { fontSize: 20, italic: true, fontColor: "text2", align: "center" },
|
|
4138
|
-
heading1: { fontSize: 28, bold: true, fontColor: "primary" },
|
|
4139
|
-
heading2: { fontSize: 22, bold: true, fontColor: "primary" },
|
|
4140
|
-
heading3: { fontSize: 18, bold: true, fontColor: "text" },
|
|
4141
|
-
body: { fontSize: 14 },
|
|
4142
|
-
caption: { fontSize: 10, italic: true, fontColor: "text2" }
|
|
4143
|
-
};
|
|
4144
|
-
var DEFAULT_PPTX_THEME = {
|
|
4145
|
-
name: "default",
|
|
4146
|
-
colors: {
|
|
4147
|
-
primary: "#4472C4",
|
|
4148
|
-
secondary: "#ED7D31",
|
|
4149
|
-
accent: "#70AD47",
|
|
4150
|
-
background: "#FFFFFF",
|
|
4151
|
-
text: "#333333",
|
|
4152
|
-
text2: "#44546A",
|
|
4153
|
-
background2: "#E7E6E6",
|
|
4154
|
-
accent4: "#FFC000",
|
|
4155
|
-
accent5: "#5B9BD5",
|
|
4156
|
-
accent6: "#70AD47"
|
|
4157
|
-
},
|
|
4158
|
-
fonts: {
|
|
4159
|
-
heading: "Arial",
|
|
4160
|
-
body: "Arial"
|
|
4161
|
-
},
|
|
4162
|
-
defaults: {
|
|
4163
|
-
fontSize: 18,
|
|
4164
|
-
fontColor: "#333333"
|
|
4165
|
-
},
|
|
4166
|
-
styles: DEFAULT_STYLES,
|
|
4167
|
-
componentDefaults: { table: DEFAULT_TABLE }
|
|
4168
|
-
};
|
|
4169
|
-
var PPTX_THEMES = {
|
|
4170
|
-
default: DEFAULT_PPTX_THEME,
|
|
4171
|
-
dark: {
|
|
4172
|
-
name: "dark",
|
|
4173
|
-
colors: {
|
|
4174
|
-
primary: "#5B9BD5",
|
|
4175
|
-
secondary: "#FF6F61",
|
|
4176
|
-
accent: "#6BCB77",
|
|
4177
|
-
background: "#2D2D2D",
|
|
4178
|
-
text: "#FFFFFF",
|
|
4179
|
-
text2: "#CCCCCC",
|
|
4180
|
-
background2: "#3D3D3D",
|
|
4181
|
-
accent4: "#FFB347",
|
|
4182
|
-
accent5: "#77DD77",
|
|
4183
|
-
accent6: "#AEC6CF"
|
|
4184
|
-
},
|
|
4185
|
-
fonts: {
|
|
4186
|
-
heading: "Arial",
|
|
4187
|
-
body: "Arial"
|
|
4188
|
-
},
|
|
4189
|
-
defaults: {
|
|
4190
|
-
fontSize: 18,
|
|
4191
|
-
fontColor: "#FFFFFF"
|
|
4192
|
-
},
|
|
4193
|
-
styles: DEFAULT_STYLES,
|
|
4194
|
-
componentDefaults: { table: DEFAULT_TABLE }
|
|
4195
|
-
},
|
|
4196
|
-
minimal: {
|
|
4197
|
-
name: "minimal",
|
|
4198
|
-
colors: {
|
|
4199
|
-
primary: "#000000",
|
|
4200
|
-
secondary: "#666666",
|
|
4201
|
-
accent: "#999999",
|
|
4202
|
-
background: "#FFFFFF",
|
|
4203
|
-
text: "#000000",
|
|
4204
|
-
text2: "#444444",
|
|
4205
|
-
background2: "#F5F5F5",
|
|
4206
|
-
accent4: "#BBBBBB",
|
|
4207
|
-
accent5: "#DDDDDD",
|
|
4208
|
-
accent6: "#888888"
|
|
4209
|
-
},
|
|
4210
|
-
fonts: {
|
|
4211
|
-
heading: "Helvetica",
|
|
4212
|
-
body: "Helvetica"
|
|
4213
|
-
},
|
|
4214
|
-
defaults: {
|
|
4215
|
-
fontSize: 18,
|
|
4216
|
-
fontColor: "#000000"
|
|
4217
|
-
},
|
|
4218
|
-
styles: DEFAULT_STYLES,
|
|
4219
|
-
componentDefaults: { table: DEFAULT_TABLE }
|
|
4220
|
-
}
|
|
4221
|
-
};
|
|
4222
|
-
function getPptxTheme(name) {
|
|
4223
|
-
return PPTX_THEMES[name] || DEFAULT_PPTX_THEME;
|
|
4224
|
-
}
|
|
4225
|
-
function hasPptxTheme(name) {
|
|
4226
|
-
return Object.prototype.hasOwnProperty.call(PPTX_THEMES, name);
|
|
4227
|
-
}
|
|
4228
|
-
var pptxThemes = PPTX_THEMES;
|
|
4229
|
-
|
|
4230
|
-
// src/core/generationContext.ts
|
|
4231
|
-
function resolveThemeContext(documentIn, options = {}) {
|
|
4232
|
-
const { customThemes, fonts, warnings, defaultThemeName, resolveNamedTheme } = options;
|
|
4233
|
-
if (documentIn.props === null) {
|
|
4234
|
-
throw new Error(
|
|
4235
|
-
"Document `props` is null. Omit it, or provide an object \u2014 a null props cannot carry a theme."
|
|
4236
|
-
);
|
|
4237
|
-
}
|
|
4238
|
-
let document = documentIn.props === void 0 ? { ...documentIn, props: {} } : documentIn;
|
|
4239
|
-
let inlineTheme;
|
|
4240
|
-
if (typeof document.props.theme === "object" && document.props.theme !== null) {
|
|
4241
|
-
inlineTheme = document.props.theme;
|
|
4242
|
-
}
|
|
4243
|
-
const authoredThemeName = typeof document.props.theme === "string" ? document.props.theme : void 0;
|
|
4244
|
-
const baseThemeName = inlineTheme ? inlineTheme.name || "inline-theme" : authoredThemeName ?? defaultThemeName ?? "default";
|
|
4245
|
-
let theme = inlineTheme ?? (resolveNamedTheme ? resolveNamedTheme(baseThemeName, authoredThemeName !== void 0) : customThemes?.[baseThemeName] ?? getPptxTheme(baseThemeName));
|
|
4246
|
-
const mode = applyExportMode({ doc: document, theme, fonts });
|
|
4247
|
-
document = mode.doc;
|
|
4248
|
-
theme = mode.theme;
|
|
4249
|
-
for (const w of mode.warnings) {
|
|
4250
|
-
warnings?.push({
|
|
4251
|
-
code: w.code,
|
|
4252
|
-
message: w.message,
|
|
4253
|
-
component: "fontRegistry"
|
|
4254
|
-
});
|
|
4255
|
-
}
|
|
4256
|
-
return {
|
|
4257
|
-
document,
|
|
4258
|
-
theme
|
|
4259
|
-
};
|
|
4260
|
-
}
|
|
4261
|
-
|
|
4262
4149
|
// src/core/generationOptions.ts
|
|
4263
4150
|
import {
|
|
4264
4151
|
collectImageSourceConflicts,
|
|
@@ -4618,6 +4505,144 @@ async function probeIntrinsicSize(source, warnings) {
|
|
|
4618
4505
|
}
|
|
4619
4506
|
}
|
|
4620
4507
|
|
|
4508
|
+
// src/quality/facts.ts
|
|
4509
|
+
import { DEFAULT_PPTX_RENDERER_ID as DEFAULT_PPTX_RENDERER_ID2 } from "@json-to-office/shared-pptx";
|
|
4510
|
+
|
|
4511
|
+
// src/core/generationContext.ts
|
|
4512
|
+
import { applyExportMode } from "@json-to-office/shared";
|
|
4513
|
+
|
|
4514
|
+
// src/themes/defaults.ts
|
|
4515
|
+
var DEFAULT_TABLE = {
|
|
4516
|
+
border: { type: "solid", pt: 1, color: "background2" },
|
|
4517
|
+
headerRow: true
|
|
4518
|
+
};
|
|
4519
|
+
var DEFAULT_STYLES = {
|
|
4520
|
+
title: { fontSize: 36, bold: true, fontColor: "text", align: "center" },
|
|
4521
|
+
subtitle: { fontSize: 20, italic: true, fontColor: "text2", align: "center" },
|
|
4522
|
+
heading1: { fontSize: 28, bold: true, fontColor: "primary" },
|
|
4523
|
+
heading2: { fontSize: 22, bold: true, fontColor: "primary" },
|
|
4524
|
+
heading3: { fontSize: 18, bold: true, fontColor: "text" },
|
|
4525
|
+
body: { fontSize: 14 },
|
|
4526
|
+
caption: { fontSize: 10, italic: true, fontColor: "text2" }
|
|
4527
|
+
};
|
|
4528
|
+
var DEFAULT_PPTX_THEME = {
|
|
4529
|
+
name: "default",
|
|
4530
|
+
colors: {
|
|
4531
|
+
primary: "#4472C4",
|
|
4532
|
+
secondary: "#ED7D31",
|
|
4533
|
+
accent: "#70AD47",
|
|
4534
|
+
background: "#FFFFFF",
|
|
4535
|
+
text: "#333333",
|
|
4536
|
+
text2: "#44546A",
|
|
4537
|
+
background2: "#E7E6E6",
|
|
4538
|
+
accent4: "#FFC000",
|
|
4539
|
+
accent5: "#5B9BD5",
|
|
4540
|
+
accent6: "#70AD47"
|
|
4541
|
+
},
|
|
4542
|
+
fonts: {
|
|
4543
|
+
heading: "Arial",
|
|
4544
|
+
body: "Arial"
|
|
4545
|
+
},
|
|
4546
|
+
defaults: {
|
|
4547
|
+
fontSize: 18,
|
|
4548
|
+
fontColor: "#333333"
|
|
4549
|
+
},
|
|
4550
|
+
styles: DEFAULT_STYLES,
|
|
4551
|
+
componentDefaults: { table: DEFAULT_TABLE }
|
|
4552
|
+
};
|
|
4553
|
+
var PPTX_THEMES = {
|
|
4554
|
+
default: DEFAULT_PPTX_THEME,
|
|
4555
|
+
dark: {
|
|
4556
|
+
name: "dark",
|
|
4557
|
+
colors: {
|
|
4558
|
+
primary: "#5B9BD5",
|
|
4559
|
+
secondary: "#FF6F61",
|
|
4560
|
+
accent: "#6BCB77",
|
|
4561
|
+
background: "#2D2D2D",
|
|
4562
|
+
text: "#FFFFFF",
|
|
4563
|
+
text2: "#CCCCCC",
|
|
4564
|
+
background2: "#3D3D3D",
|
|
4565
|
+
accent4: "#FFB347",
|
|
4566
|
+
accent5: "#77DD77",
|
|
4567
|
+
accent6: "#AEC6CF"
|
|
4568
|
+
},
|
|
4569
|
+
fonts: {
|
|
4570
|
+
heading: "Arial",
|
|
4571
|
+
body: "Arial"
|
|
4572
|
+
},
|
|
4573
|
+
defaults: {
|
|
4574
|
+
fontSize: 18,
|
|
4575
|
+
fontColor: "#FFFFFF"
|
|
4576
|
+
},
|
|
4577
|
+
styles: DEFAULT_STYLES,
|
|
4578
|
+
componentDefaults: { table: DEFAULT_TABLE }
|
|
4579
|
+
},
|
|
4580
|
+
minimal: {
|
|
4581
|
+
name: "minimal",
|
|
4582
|
+
colors: {
|
|
4583
|
+
primary: "#000000",
|
|
4584
|
+
secondary: "#666666",
|
|
4585
|
+
accent: "#999999",
|
|
4586
|
+
background: "#FFFFFF",
|
|
4587
|
+
text: "#000000",
|
|
4588
|
+
text2: "#444444",
|
|
4589
|
+
background2: "#F5F5F5",
|
|
4590
|
+
accent4: "#BBBBBB",
|
|
4591
|
+
accent5: "#DDDDDD",
|
|
4592
|
+
accent6: "#888888"
|
|
4593
|
+
},
|
|
4594
|
+
fonts: {
|
|
4595
|
+
heading: "Helvetica",
|
|
4596
|
+
body: "Helvetica"
|
|
4597
|
+
},
|
|
4598
|
+
defaults: {
|
|
4599
|
+
fontSize: 18,
|
|
4600
|
+
fontColor: "#000000"
|
|
4601
|
+
},
|
|
4602
|
+
styles: DEFAULT_STYLES,
|
|
4603
|
+
componentDefaults: { table: DEFAULT_TABLE }
|
|
4604
|
+
}
|
|
4605
|
+
};
|
|
4606
|
+
function getPptxTheme(name) {
|
|
4607
|
+
return PPTX_THEMES[name] || DEFAULT_PPTX_THEME;
|
|
4608
|
+
}
|
|
4609
|
+
function hasPptxTheme(name) {
|
|
4610
|
+
return Object.prototype.hasOwnProperty.call(PPTX_THEMES, name);
|
|
4611
|
+
}
|
|
4612
|
+
var pptxThemes = PPTX_THEMES;
|
|
4613
|
+
|
|
4614
|
+
// src/core/generationContext.ts
|
|
4615
|
+
function resolveThemeContext(documentIn, options = {}) {
|
|
4616
|
+
const { customThemes, fonts, warnings, defaultThemeName, resolveNamedTheme } = options;
|
|
4617
|
+
if (documentIn.props === null) {
|
|
4618
|
+
throw new Error(
|
|
4619
|
+
"Document `props` is null. Omit it, or provide an object \u2014 a null props cannot carry a theme."
|
|
4620
|
+
);
|
|
4621
|
+
}
|
|
4622
|
+
let document = documentIn.props === void 0 ? { ...documentIn, props: {} } : documentIn;
|
|
4623
|
+
let inlineTheme;
|
|
4624
|
+
if (typeof document.props.theme === "object" && document.props.theme !== null) {
|
|
4625
|
+
inlineTheme = document.props.theme;
|
|
4626
|
+
}
|
|
4627
|
+
const authoredThemeName = typeof document.props.theme === "string" ? document.props.theme : void 0;
|
|
4628
|
+
const baseThemeName = inlineTheme ? inlineTheme.name || "inline-theme" : authoredThemeName ?? defaultThemeName ?? "default";
|
|
4629
|
+
let theme = inlineTheme ?? (resolveNamedTheme ? resolveNamedTheme(baseThemeName, authoredThemeName !== void 0) : customThemes?.[baseThemeName] ?? getPptxTheme(baseThemeName));
|
|
4630
|
+
const mode = applyExportMode({ doc: document, theme, fonts });
|
|
4631
|
+
document = mode.doc;
|
|
4632
|
+
theme = mode.theme;
|
|
4633
|
+
for (const w of mode.warnings) {
|
|
4634
|
+
warnings?.push({
|
|
4635
|
+
code: w.code,
|
|
4636
|
+
message: w.message,
|
|
4637
|
+
component: "fontRegistry"
|
|
4638
|
+
});
|
|
4639
|
+
}
|
|
4640
|
+
return {
|
|
4641
|
+
document,
|
|
4642
|
+
theme
|
|
4643
|
+
};
|
|
4644
|
+
}
|
|
4645
|
+
|
|
4621
4646
|
// src/core/structure.ts
|
|
4622
4647
|
import { mergeWithDefaults as mergeWithDefaults3 } from "@json-to-office/shared";
|
|
4623
4648
|
function isSlideEnabled(child) {
|
|
@@ -4740,6 +4765,458 @@ function processPresentation(document, options) {
|
|
|
4740
4765
|
};
|
|
4741
4766
|
}
|
|
4742
4767
|
|
|
4768
|
+
// src/quality/facts.ts
|
|
4769
|
+
function asRecord(value) {
|
|
4770
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
4771
|
+
}
|
|
4772
|
+
function asNumber(value) {
|
|
4773
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
4774
|
+
}
|
|
4775
|
+
function dimToPt(value, axisIn) {
|
|
4776
|
+
if (typeof value === "number" && Number.isFinite(value)) return value * 72;
|
|
4777
|
+
if (typeof value === "string") {
|
|
4778
|
+
const trimmed = value.trim();
|
|
4779
|
+
if (trimmed.endsWith("%")) {
|
|
4780
|
+
const pct = Number(trimmed.slice(0, -1));
|
|
4781
|
+
return Number.isFinite(pct) ? pct / 100 * axisIn * 72 : void 0;
|
|
4782
|
+
}
|
|
4783
|
+
const inches = Number(trimmed);
|
|
4784
|
+
return Number.isFinite(inches) ? inches * 72 : void 0;
|
|
4785
|
+
}
|
|
4786
|
+
return void 0;
|
|
4787
|
+
}
|
|
4788
|
+
function resolveBox(props, grid, slideWidthIn, slideHeightIn) {
|
|
4789
|
+
let xPt = dimToPt(props.x, slideWidthIn);
|
|
4790
|
+
let yPt = dimToPt(props.y, slideHeightIn);
|
|
4791
|
+
let widthPt = dimToPt(props.w, slideWidthIn);
|
|
4792
|
+
let heightPt = dimToPt(props.h, slideHeightIn);
|
|
4793
|
+
const gridPos = asRecord(props.grid);
|
|
4794
|
+
if (gridPos !== void 0 && asNumber(gridPos.column) !== void 0 && asNumber(gridPos.row) !== void 0 && (xPt === void 0 || yPt === void 0 || widthPt === void 0 || heightPt === void 0)) {
|
|
4795
|
+
const resolved = resolveGridPosition(
|
|
4796
|
+
gridPos,
|
|
4797
|
+
grid,
|
|
4798
|
+
slideWidthIn,
|
|
4799
|
+
slideHeightIn
|
|
4800
|
+
);
|
|
4801
|
+
xPt ??= resolved.x * 72;
|
|
4802
|
+
yPt ??= resolved.y * 72;
|
|
4803
|
+
widthPt ??= resolved.w * 72;
|
|
4804
|
+
heightPt ??= resolved.h * 72;
|
|
4805
|
+
}
|
|
4806
|
+
return { xPt, yPt, widthPt, heightPt };
|
|
4807
|
+
}
|
|
4808
|
+
function isCompleteBox(box) {
|
|
4809
|
+
return box.xPt !== void 0 && box.yPt !== void 0 && box.widthPt !== void 0 && box.heightPt !== void 0 && box.widthPt > 0 && box.heightPt > 0;
|
|
4810
|
+
}
|
|
4811
|
+
function containsCentre(surface, text) {
|
|
4812
|
+
const cx = text.xPt + text.widthPt / 2;
|
|
4813
|
+
const cy = text.yPt + text.heightPt / 2;
|
|
4814
|
+
return cx >= surface.xPt && cx <= surface.xPt + surface.widthPt && cy >= surface.yPt && cy <= surface.yPt + surface.heightPt;
|
|
4815
|
+
}
|
|
4816
|
+
function themeContext(theme) {
|
|
4817
|
+
return {
|
|
4818
|
+
styles: theme.styles ?? {},
|
|
4819
|
+
defaultFontSize: asNumber(theme.defaults?.fontSize) ?? 18
|
|
4820
|
+
};
|
|
4821
|
+
}
|
|
4822
|
+
function fillColorHexes(fill2, theme) {
|
|
4823
|
+
const found = [];
|
|
4824
|
+
const visit = (node) => {
|
|
4825
|
+
if (Array.isArray(node)) {
|
|
4826
|
+
node.forEach(visit);
|
|
4827
|
+
return;
|
|
4828
|
+
}
|
|
4829
|
+
const rec = asRecord(node);
|
|
4830
|
+
if (!rec) return;
|
|
4831
|
+
if (typeof rec.color === "string") {
|
|
4832
|
+
const hex = resolveColor(rec.color, theme);
|
|
4833
|
+
if (hex) found.push(hex.toUpperCase());
|
|
4834
|
+
}
|
|
4835
|
+
for (const value of Object.values(rec)) {
|
|
4836
|
+
if (typeof value === "object" && value !== null) visit(value);
|
|
4837
|
+
}
|
|
4838
|
+
};
|
|
4839
|
+
visit(fill2);
|
|
4840
|
+
return [...new Set(found)];
|
|
4841
|
+
}
|
|
4842
|
+
var FOCUS_CORNERS = {
|
|
4843
|
+
topLeft: [0, 0],
|
|
4844
|
+
topRight: [1, 0],
|
|
4845
|
+
bottomLeft: [0, 1],
|
|
4846
|
+
bottomRight: [1, 1]
|
|
4847
|
+
};
|
|
4848
|
+
function lerpHex(a, b, t) {
|
|
4849
|
+
const pa = parseInt(a, 16);
|
|
4850
|
+
const pb = parseInt(b, 16);
|
|
4851
|
+
const mix = (shift) => Math.round(
|
|
4852
|
+
(pa >> shift & 255) + ((pb >> shift & 255) - (pa >> shift & 255)) * t
|
|
4853
|
+
);
|
|
4854
|
+
return [mix(16), mix(8), mix(0)].map((c) => c.toString(16).padStart(2, "0")).join("").toUpperCase();
|
|
4855
|
+
}
|
|
4856
|
+
function gradientPosition(gradient, fx, fy, widthUnits, heightUnits) {
|
|
4857
|
+
if (gradient.type === "radial") {
|
|
4858
|
+
const focus = FOCUS_CORNERS[typeof gradient.focus === "string" ? gradient.focus : "topLeft"] ?? FOCUS_CORNERS.topLeft;
|
|
4859
|
+
const radius = Math.hypot(widthUnits, heightUnits) / 2;
|
|
4860
|
+
if (radius === 0) return 0;
|
|
4861
|
+
const distance = Math.hypot(
|
|
4862
|
+
(fx - focus[0]) * widthUnits,
|
|
4863
|
+
(fy - focus[1]) * heightUnits
|
|
4864
|
+
);
|
|
4865
|
+
return Math.min(1, distance / radius);
|
|
4866
|
+
}
|
|
4867
|
+
const angle = (asNumber(gradient.angle) ?? 0) * Math.PI / 180;
|
|
4868
|
+
const dx = Math.cos(angle);
|
|
4869
|
+
const dy = Math.sin(angle);
|
|
4870
|
+
const min = Math.min(0, dx) + Math.min(0, dy);
|
|
4871
|
+
const max = Math.max(0, dx) + Math.max(0, dy);
|
|
4872
|
+
if (max === min) return 0;
|
|
4873
|
+
return Math.min(1, Math.max(0, (fx * dx + fy * dy - min) / (max - min)));
|
|
4874
|
+
}
|
|
4875
|
+
function paintedColorHexes(fill2, theme, fx, fy, widthUnits, heightUnits) {
|
|
4876
|
+
const rec = asRecord(fill2);
|
|
4877
|
+
const gradient = asRecord(rec?.gradient);
|
|
4878
|
+
const stops = Array.isArray(gradient?.stops) ? gradient.stops : void 0;
|
|
4879
|
+
if (gradient && stops && stops.length > 0) {
|
|
4880
|
+
const parsed = stops.flatMap((stop) => {
|
|
4881
|
+
const entry = asRecord(stop);
|
|
4882
|
+
const color2 = typeof entry?.color === "string" ? entry.color : void 0;
|
|
4883
|
+
if (!color2) return [];
|
|
4884
|
+
const hex = resolveColor(color2, theme);
|
|
4885
|
+
if (!hex) return [];
|
|
4886
|
+
return [{ pos: asNumber(entry?.pos) ?? 0, hex: hex.toUpperCase() }];
|
|
4887
|
+
}).sort((a, b) => a.pos - b.pos);
|
|
4888
|
+
if (parsed.length === 0) return [];
|
|
4889
|
+
const target = gradientPosition(gradient, fx, fy, widthUnits, heightUnits) * 100;
|
|
4890
|
+
if (target <= parsed[0].pos) return [parsed[0].hex];
|
|
4891
|
+
const last = parsed[parsed.length - 1];
|
|
4892
|
+
if (target >= last.pos) return [last.hex];
|
|
4893
|
+
for (let i = 1; i < parsed.length; i += 1) {
|
|
4894
|
+
const previous = parsed[i - 1];
|
|
4895
|
+
const next = parsed[i];
|
|
4896
|
+
if (target <= next.pos) {
|
|
4897
|
+
const span = next.pos - previous.pos;
|
|
4898
|
+
const t = span === 0 ? 0 : (target - previous.pos) / span;
|
|
4899
|
+
return [lerpHex(previous.hex, next.hex, t)];
|
|
4900
|
+
}
|
|
4901
|
+
}
|
|
4902
|
+
return [last.hex];
|
|
4903
|
+
}
|
|
4904
|
+
return fillColorHexes(fill2, theme);
|
|
4905
|
+
}
|
|
4906
|
+
function defaultLineHeightPt(fontSize) {
|
|
4907
|
+
if (fontSize >= 60) return fontSize * 1.05;
|
|
4908
|
+
if (fontSize >= 28) return fontSize * 1.15;
|
|
4909
|
+
return fontSize * 1.25;
|
|
4910
|
+
}
|
|
4911
|
+
function resolveTypography(props, ctx) {
|
|
4912
|
+
const styleName = typeof props.style === "string" ? props.style : void 0;
|
|
4913
|
+
const style = styleName !== void 0 ? ctx.styles[styleName] : void 0;
|
|
4914
|
+
const fontSize = asNumber(props.fontSize) ?? style?.fontSize ?? ctx.defaultFontSize;
|
|
4915
|
+
const multiple = asNumber(props.lineSpacingMultiple);
|
|
4916
|
+
const lineSpacing = multiple !== void 0 ? fontSize * multiple : asNumber(props.lineSpacing) ?? style?.lineSpacing ?? defaultLineHeightPt(fontSize);
|
|
4917
|
+
const weight = asNumber(props.fontWeight) ?? style?.fontWeight;
|
|
4918
|
+
const bold = weight !== void 0 ? weight >= 600 : typeof props.bold === "boolean" ? props.bold : style?.bold ?? false;
|
|
4919
|
+
return {
|
|
4920
|
+
fontSize,
|
|
4921
|
+
lineSpacing,
|
|
4922
|
+
paraSpaceBefore: asNumber(props.paraSpaceBefore) ?? 0,
|
|
4923
|
+
paraSpaceAfter: asNumber(props.paraSpaceAfter) ?? style?.paraSpaceAfter ?? 0,
|
|
4924
|
+
bold,
|
|
4925
|
+
...styleName && { styleName }
|
|
4926
|
+
};
|
|
4927
|
+
}
|
|
4928
|
+
function collectSlideNodes(component, path4, text, surfaces, counter) {
|
|
4929
|
+
const rec = asRecord(component);
|
|
4930
|
+
if (!rec || rec.enabled === false) return;
|
|
4931
|
+
const props = asRecord(rec.props) ?? {};
|
|
4932
|
+
const order = counter.next++;
|
|
4933
|
+
if (rec.name === "image" || rec.name === "visual" || rec.name === "chart") {
|
|
4934
|
+
surfaces.push({ order, props, isImage: true });
|
|
4935
|
+
} else if (rec.name === "shape" && props.fill !== void 0) {
|
|
4936
|
+
surfaces.push({ order, props, isImage: false });
|
|
4937
|
+
}
|
|
4938
|
+
const content = typeof props.text === "string" ? props.text : void 0;
|
|
4939
|
+
if (content !== void 0 && content.trim() !== "" && props.runs === void 0) {
|
|
4940
|
+
if (rec.name === "text" || rec.name === "shape") {
|
|
4941
|
+
text.push({ props, path: path4, text: content, order });
|
|
4942
|
+
}
|
|
4943
|
+
}
|
|
4944
|
+
const children = Array.isArray(rec.children) ? rec.children : [];
|
|
4945
|
+
children.forEach(
|
|
4946
|
+
(child, index) => collectSlideNodes(
|
|
4947
|
+
child,
|
|
4948
|
+
`${path4}/children/${index}`,
|
|
4949
|
+
text,
|
|
4950
|
+
surfaces,
|
|
4951
|
+
counter
|
|
4952
|
+
)
|
|
4953
|
+
);
|
|
4954
|
+
}
|
|
4955
|
+
function pointerSegment(value) {
|
|
4956
|
+
return value.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
4957
|
+
}
|
|
4958
|
+
function addSlideFacts(roots, slidePath, renderedIndex, grid, slideWidthIn, slideHeightIn, ctx, theme, slideBackground, analyzedTextPaths, addFact) {
|
|
4959
|
+
const nodes = [];
|
|
4960
|
+
const surfaces = [];
|
|
4961
|
+
const counter = { next: 0 };
|
|
4962
|
+
for (const root of roots) {
|
|
4963
|
+
collectSlideNodes(root.component, root.path, nodes, surfaces, counter);
|
|
4964
|
+
}
|
|
4965
|
+
const surfaceBoxes = surfaces.flatMap((surface) => {
|
|
4966
|
+
const box = resolveBox(surface.props, grid, slideWidthIn, slideHeightIn);
|
|
4967
|
+
return isCompleteBox(box) ? [{ ...surface, box }] : [];
|
|
4968
|
+
});
|
|
4969
|
+
let bodyWords = 0;
|
|
4970
|
+
nodes.forEach((node, nodeIndex) => {
|
|
4971
|
+
const typography = resolveTypography(node.props, ctx);
|
|
4972
|
+
if (typography.styleName !== "title" && typography.styleName !== "subtitle") {
|
|
4973
|
+
bodyWords += node.text.split(/\s+/).filter(Boolean).length;
|
|
4974
|
+
}
|
|
4975
|
+
if (analyzedTextPaths.has(node.path)) return;
|
|
4976
|
+
analyzedTextPaths.add(node.path);
|
|
4977
|
+
const gridPos = asRecord(node.props.grid);
|
|
4978
|
+
const nodeBox = resolveBox(node.props, grid, slideWidthIn, slideHeightIn);
|
|
4979
|
+
const {
|
|
4980
|
+
xPt: boxXPt,
|
|
4981
|
+
yPt: boxYPt,
|
|
4982
|
+
widthPt: boxWidthPt,
|
|
4983
|
+
heightPt: boxHeightPt
|
|
4984
|
+
} = nodeBox;
|
|
4985
|
+
const sampleFractions = (box, originX, originY, widthPt, heightPt) => {
|
|
4986
|
+
if (!isCompleteBox(box) || widthPt <= 0 || heightPt <= 0) {
|
|
4987
|
+
return [[0.5, 0.5]];
|
|
4988
|
+
}
|
|
4989
|
+
const x0 = (box.xPt - originX) / widthPt;
|
|
4990
|
+
const x1 = (box.xPt + box.widthPt - originX) / widthPt;
|
|
4991
|
+
const y0 = (box.yPt - originY) / heightPt;
|
|
4992
|
+
const y1 = (box.yPt + box.heightPt - originY) / heightPt;
|
|
4993
|
+
return [
|
|
4994
|
+
[(x0 + x1) / 2, (y0 + y1) / 2],
|
|
4995
|
+
[x0, y0],
|
|
4996
|
+
[x1, y0],
|
|
4997
|
+
[x0, y1],
|
|
4998
|
+
[x1, y1]
|
|
4999
|
+
];
|
|
5000
|
+
};
|
|
5001
|
+
const slideSamples = sampleFractions(
|
|
5002
|
+
nodeBox,
|
|
5003
|
+
0,
|
|
5004
|
+
0,
|
|
5005
|
+
slideWidthIn * 72,
|
|
5006
|
+
slideHeightIn * 72
|
|
5007
|
+
);
|
|
5008
|
+
const ownFill = [
|
|
5009
|
+
...new Set(
|
|
5010
|
+
sampleFractions(
|
|
5011
|
+
nodeBox,
|
|
5012
|
+
boxXPt ?? 0,
|
|
5013
|
+
boxYPt ?? 0,
|
|
5014
|
+
boxWidthPt ?? 0,
|
|
5015
|
+
boxHeightPt ?? 0
|
|
5016
|
+
).flatMap(
|
|
5017
|
+
([fx, fy]) => paintedColorHexes(
|
|
5018
|
+
node.props.fill,
|
|
5019
|
+
theme,
|
|
5020
|
+
fx,
|
|
5021
|
+
fy,
|
|
5022
|
+
(boxWidthPt ?? 0) / 72,
|
|
5023
|
+
(boxHeightPt ?? 0) / 72
|
|
5024
|
+
)
|
|
5025
|
+
)
|
|
5026
|
+
)
|
|
5027
|
+
];
|
|
5028
|
+
let backgroundHexes = [
|
|
5029
|
+
...new Set(slideSamples.flatMap(([fx, fy]) => slideBackground(fx, fy)))
|
|
5030
|
+
];
|
|
5031
|
+
let backgroundUnknown = false;
|
|
5032
|
+
if (ownFill.length > 0) {
|
|
5033
|
+
backgroundHexes = ownFill;
|
|
5034
|
+
} else if (isCompleteBox(nodeBox)) {
|
|
5035
|
+
const covering = surfaceBoxes.filter(
|
|
5036
|
+
(surface) => surface.order < node.order && containsCentre(surface.box, nodeBox)
|
|
5037
|
+
).pop();
|
|
5038
|
+
if (covering?.isImage) {
|
|
5039
|
+
backgroundUnknown = true;
|
|
5040
|
+
} else if (covering) {
|
|
5041
|
+
const fill2 = [
|
|
5042
|
+
...new Set(
|
|
5043
|
+
sampleFractions(
|
|
5044
|
+
nodeBox,
|
|
5045
|
+
covering.box.xPt,
|
|
5046
|
+
covering.box.yPt,
|
|
5047
|
+
covering.box.widthPt,
|
|
5048
|
+
covering.box.heightPt
|
|
5049
|
+
).flatMap(
|
|
5050
|
+
([fx, fy]) => paintedColorHexes(
|
|
5051
|
+
covering.props.fill,
|
|
5052
|
+
theme,
|
|
5053
|
+
fx,
|
|
5054
|
+
fy,
|
|
5055
|
+
covering.box.widthPt / 72,
|
|
5056
|
+
covering.box.heightPt / 72
|
|
5057
|
+
)
|
|
5058
|
+
)
|
|
5059
|
+
)
|
|
5060
|
+
];
|
|
5061
|
+
if (fill2.length > 0) backgroundHexes = fill2;
|
|
5062
|
+
else backgroundUnknown = true;
|
|
5063
|
+
}
|
|
5064
|
+
}
|
|
5065
|
+
const colorHex = typeof node.props.color === "string" ? resolveColor(node.props.color, theme)?.toUpperCase() : void 0;
|
|
5066
|
+
addFact({
|
|
5067
|
+
id: `pptx:text:${renderedIndex}:${nodeIndex}:${node.path}`,
|
|
5068
|
+
kind: "pptx/text",
|
|
5069
|
+
path: node.path,
|
|
5070
|
+
slidePath,
|
|
5071
|
+
text: node.text,
|
|
5072
|
+
fontSizePt: typography.fontSize,
|
|
5073
|
+
lineSpacingPt: typography.lineSpacing,
|
|
5074
|
+
paraSpaceBeforePt: typography.paraSpaceBefore,
|
|
5075
|
+
paraSpaceAfterPt: typography.paraSpaceAfter,
|
|
5076
|
+
...typography.styleName && { styleName: typography.styleName },
|
|
5077
|
+
...boxXPt !== void 0 && { boxXPt },
|
|
5078
|
+
...boxYPt !== void 0 && { boxYPt },
|
|
5079
|
+
...boxWidthPt !== void 0 && boxWidthPt > 0 && { boxWidthPt },
|
|
5080
|
+
...boxHeightPt !== void 0 && boxHeightPt > 0 && { boxHeightPt },
|
|
5081
|
+
verticalAlign: node.props.valign === "middle" || node.props.valign === "bottom" ? node.props.valign : "top",
|
|
5082
|
+
rotationDeg: asNumber(node.props.rotate) ?? 0,
|
|
5083
|
+
bold: typography.bold,
|
|
5084
|
+
autoFit: node.props.h === void 0 && gridPos === void 0,
|
|
5085
|
+
...colorHex !== void 0 && { colorHex },
|
|
5086
|
+
...!backgroundUnknown && backgroundHexes.length > 0 && { backgroundHexes }
|
|
5087
|
+
});
|
|
5088
|
+
});
|
|
5089
|
+
addFact({
|
|
5090
|
+
id: `pptx:slide:${renderedIndex}:${slidePath}`,
|
|
5091
|
+
kind: "pptx/slide",
|
|
5092
|
+
path: slidePath,
|
|
5093
|
+
bodyWords
|
|
5094
|
+
});
|
|
5095
|
+
}
|
|
5096
|
+
function preparePptxQualityDocument(document, options = {}) {
|
|
5097
|
+
const facts = [];
|
|
5098
|
+
const provenance = {};
|
|
5099
|
+
const addFact = (fact) => {
|
|
5100
|
+
facts.push(fact);
|
|
5101
|
+
provenance[fact.id] = {
|
|
5102
|
+
path: fact.path,
|
|
5103
|
+
...fact.relatedPaths && { relatedPaths: fact.relatedPaths }
|
|
5104
|
+
};
|
|
5105
|
+
};
|
|
5106
|
+
const props = asRecord(document.props) ?? {};
|
|
5107
|
+
addFact({
|
|
5108
|
+
id: "pptx:canvas",
|
|
5109
|
+
kind: "pptx/canvas",
|
|
5110
|
+
path: "/props",
|
|
5111
|
+
...asNumber(props.slideWidth) !== void 0 && {
|
|
5112
|
+
widthIn: asNumber(props.slideWidth)
|
|
5113
|
+
},
|
|
5114
|
+
...asNumber(props.slideHeight) !== void 0 && {
|
|
5115
|
+
heightIn: asNumber(props.slideHeight)
|
|
5116
|
+
}
|
|
5117
|
+
});
|
|
5118
|
+
const warnings = options.warnings ?? [];
|
|
5119
|
+
const context = resolveThemeContext(document, {
|
|
5120
|
+
customThemes: options.customThemes,
|
|
5121
|
+
fonts: options.fonts,
|
|
5122
|
+
warnings
|
|
5123
|
+
});
|
|
5124
|
+
const processed = processPresentation(context.document, {
|
|
5125
|
+
theme: context.theme,
|
|
5126
|
+
customThemes: options.customThemes,
|
|
5127
|
+
services: options.services
|
|
5128
|
+
});
|
|
5129
|
+
const ctx = themeContext(processed.theme);
|
|
5130
|
+
const authoredChildren = Array.isArray(document.children) ? document.children : [];
|
|
5131
|
+
const slideIndexes = authoredChildren.flatMap((child, index) => {
|
|
5132
|
+
const slide = asRecord(child);
|
|
5133
|
+
return slide?.name === "slide" && slide.enabled !== false ? [index] : [];
|
|
5134
|
+
});
|
|
5135
|
+
const templateIndexes = /* @__PURE__ */ new Map();
|
|
5136
|
+
const templates = new Map(
|
|
5137
|
+
(processed.templates ?? []).map((template, index) => {
|
|
5138
|
+
templateIndexes.set(template.name, index);
|
|
5139
|
+
return [template.name, template];
|
|
5140
|
+
})
|
|
5141
|
+
);
|
|
5142
|
+
const analyzedTextPaths = /* @__PURE__ */ new Set();
|
|
5143
|
+
processed.slides.forEach((slide, renderedIndex) => {
|
|
5144
|
+
const authoredIndex = slideIndexes[renderedIndex];
|
|
5145
|
+
if (authoredIndex === void 0) return;
|
|
5146
|
+
const slidePath = `/children/${authoredIndex}`;
|
|
5147
|
+
const authoredSlide = asRecord(authoredChildren[authoredIndex]);
|
|
5148
|
+
const authoredComponents = Array.isArray(authoredSlide?.children) ? authoredSlide.children : [];
|
|
5149
|
+
const template = slide.template ? templates.get(slide.template) : void 0;
|
|
5150
|
+
const effectiveGrid = mergeGridConfigs(processed.grid, template?.grid);
|
|
5151
|
+
const roots = [];
|
|
5152
|
+
const templateIndex = template ? templateIndexes.get(template.name) : void 0;
|
|
5153
|
+
if (template && templateIndex !== void 0) {
|
|
5154
|
+
template.objects?.forEach((component, index) => {
|
|
5155
|
+
roots.push({
|
|
5156
|
+
component,
|
|
5157
|
+
path: `/props/templates/${templateIndex}/objects/${index}`
|
|
5158
|
+
});
|
|
5159
|
+
});
|
|
5160
|
+
}
|
|
5161
|
+
slide.components.forEach((component, index) => {
|
|
5162
|
+
if (authoredComponents[index] === void 0) return;
|
|
5163
|
+
roots.push({
|
|
5164
|
+
component,
|
|
5165
|
+
path: `${slidePath}/children/${index}`
|
|
5166
|
+
});
|
|
5167
|
+
});
|
|
5168
|
+
for (const resolved of resolvePlaceholderComponents(
|
|
5169
|
+
slide,
|
|
5170
|
+
template,
|
|
5171
|
+
effectiveGrid,
|
|
5172
|
+
{
|
|
5173
|
+
theme: processed.theme,
|
|
5174
|
+
slideWidth: processed.slideWidth,
|
|
5175
|
+
slideHeight: processed.slideHeight,
|
|
5176
|
+
slideIndex: renderedIndex,
|
|
5177
|
+
warnings
|
|
5178
|
+
}
|
|
5179
|
+
)) {
|
|
5180
|
+
roots.push({
|
|
5181
|
+
component: resolved.component,
|
|
5182
|
+
path: `${slidePath}/props/placeholders/${pointerSegment(resolved.name)}`
|
|
5183
|
+
});
|
|
5184
|
+
}
|
|
5185
|
+
addSlideFacts(
|
|
5186
|
+
roots,
|
|
5187
|
+
slidePath,
|
|
5188
|
+
renderedIndex,
|
|
5189
|
+
effectiveGrid,
|
|
5190
|
+
processed.slideWidth,
|
|
5191
|
+
processed.slideHeight,
|
|
5192
|
+
ctx,
|
|
5193
|
+
processed.theme,
|
|
5194
|
+
(fx, fy) => paintedColorHexes(
|
|
5195
|
+
slide.background ?? template?.background ?? props.background,
|
|
5196
|
+
processed.theme,
|
|
5197
|
+
fx,
|
|
5198
|
+
fy,
|
|
5199
|
+
processed.slideWidth,
|
|
5200
|
+
processed.slideHeight
|
|
5201
|
+
),
|
|
5202
|
+
analyzedTextPaths,
|
|
5203
|
+
addFact
|
|
5204
|
+
);
|
|
5205
|
+
});
|
|
5206
|
+
return {
|
|
5207
|
+
format: "pptx",
|
|
5208
|
+
model: {
|
|
5209
|
+
authored: document,
|
|
5210
|
+
document: context.document,
|
|
5211
|
+
theme: context.theme,
|
|
5212
|
+
processed
|
|
5213
|
+
},
|
|
5214
|
+
facts,
|
|
5215
|
+
provenance,
|
|
5216
|
+
renderer: options.renderer ?? DEFAULT_PPTX_RENDERER_ID2
|
|
5217
|
+
};
|
|
5218
|
+
}
|
|
5219
|
+
|
|
4743
5220
|
// src/core/generateFromIr.ts
|
|
4744
5221
|
var UncompiledComponentError = class extends Error {
|
|
4745
5222
|
code = "UNCOMPILED_COMPONENT";
|
|
@@ -4762,29 +5239,24 @@ async function generateBufferViaIr(jsonConfig, options) {
|
|
|
4762
5239
|
selectedRenderer && PPTX_RENDERER_IDS.includes(selectedRenderer) ? { ...component, renderer: selectedRenderer } : component,
|
|
4763
5240
|
options?.validation
|
|
4764
5241
|
);
|
|
5242
|
+
assertNoContentConflicts(component);
|
|
4765
5243
|
const warnings = [];
|
|
4766
|
-
const
|
|
5244
|
+
const prepared = options?.prepared ?? preparePptxQualityDocument(component, {
|
|
4767
5245
|
customThemes: options?.customThemes,
|
|
4768
5246
|
fonts: options?.fonts,
|
|
4769
|
-
warnings
|
|
5247
|
+
warnings,
|
|
5248
|
+
services: options?.services,
|
|
5249
|
+
renderer: selectedRenderer
|
|
4770
5250
|
});
|
|
4771
|
-
assertNoContentConflicts(context.document);
|
|
4772
5251
|
await resolveDocumentFonts(
|
|
4773
|
-
|
|
4774
|
-
|
|
5252
|
+
prepared.model.document,
|
|
5253
|
+
prepared.model.theme,
|
|
4775
5254
|
warnings,
|
|
4776
5255
|
options?.fonts
|
|
4777
5256
|
);
|
|
4778
5257
|
const buffer = await runWithBaseDir(
|
|
4779
5258
|
options?.baseDir,
|
|
4780
|
-
() => renderProcessedViaIr(
|
|
4781
|
-
processPresentation(context.document, {
|
|
4782
|
-
...effectiveOptions,
|
|
4783
|
-
theme: context.theme
|
|
4784
|
-
}),
|
|
4785
|
-
warnings,
|
|
4786
|
-
effectiveOptions
|
|
4787
|
-
)
|
|
5259
|
+
() => renderProcessedViaIr(prepared.model.processed, warnings, effectiveOptions)
|
|
4788
5260
|
);
|
|
4789
5261
|
return { buffer, warnings };
|
|
4790
5262
|
}
|
|
@@ -4853,6 +5325,465 @@ var PresentationGenerator = {
|
|
|
4853
5325
|
init_finalizePackage();
|
|
4854
5326
|
init_warn();
|
|
4855
5327
|
|
|
5328
|
+
// src/quality/preflight.ts
|
|
5329
|
+
import {
|
|
5330
|
+
assertValidQualityPolicy,
|
|
5331
|
+
assertValidQualityProfile
|
|
5332
|
+
} from "@json-to-office/quality";
|
|
5333
|
+
|
|
5334
|
+
// src/quality/rules.ts
|
|
5335
|
+
import {
|
|
5336
|
+
mergeQualityProfiles,
|
|
5337
|
+
QUALITY_CODES,
|
|
5338
|
+
QualityEngine,
|
|
5339
|
+
resolveRuleConfiguration
|
|
5340
|
+
} from "@json-to-office/quality";
|
|
5341
|
+
var RENDERER_DEFAULT_WIDTH_IN = 10;
|
|
5342
|
+
var RENDERER_DEFAULT_HEIGHT_IN = 7.5;
|
|
5343
|
+
var DEFAULT_CHAR_WIDTH_FACTOR = 0.46;
|
|
5344
|
+
var DEFAULT_SAFETY_BUFFER_PT = 8;
|
|
5345
|
+
var DEFAULT_MIN_READABLE_FONT_PT = 7;
|
|
5346
|
+
var DEFAULT_MAX_BODY_WORDS_PER_SLIDE = 130;
|
|
5347
|
+
var KNOWN_CANVASES = [
|
|
5348
|
+
{ w: 13.333, h: 7.5, label: "16:9 standard" },
|
|
5349
|
+
{ w: 10, h: 5.625, label: "16:9 small" },
|
|
5350
|
+
{ w: 7.5, h: 7.5, label: "1:1 carousel" },
|
|
5351
|
+
{ w: 7.5, h: 9.375, label: "4:5 vertical" },
|
|
5352
|
+
{ w: 4.5, h: 8, label: "9:16 story" },
|
|
5353
|
+
{ w: 10, h: 7.5, label: "4:3 legacy", legacy: true }
|
|
5354
|
+
];
|
|
5355
|
+
function numberParameter(parameters, name, fallback) {
|
|
5356
|
+
const value = parameters[name];
|
|
5357
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
5358
|
+
}
|
|
5359
|
+
function textFacts(facts) {
|
|
5360
|
+
return facts.filter(
|
|
5361
|
+
(fact) => fact.kind === "pptx/text"
|
|
5362
|
+
);
|
|
5363
|
+
}
|
|
5364
|
+
function estimateTextHeightPt(fact, charWidthFactor) {
|
|
5365
|
+
if (fact.boxWidthPt === void 0 || fact.boxHeightPt === void 0) {
|
|
5366
|
+
return void 0;
|
|
5367
|
+
}
|
|
5368
|
+
const paragraphs = fact.text.split("\n");
|
|
5369
|
+
const charsPerLine = Math.max(
|
|
5370
|
+
1,
|
|
5371
|
+
Math.floor(fact.boxWidthPt / (fact.fontSizePt * charWidthFactor))
|
|
5372
|
+
);
|
|
5373
|
+
let lines = 0;
|
|
5374
|
+
for (const paragraph of paragraphs) {
|
|
5375
|
+
const measured = paragraph.trimEnd();
|
|
5376
|
+
lines += measured === "" ? 1 : Math.max(1, Math.ceil(measured.length / charsPerLine));
|
|
5377
|
+
}
|
|
5378
|
+
let heightPt = fact.fontSizePt + Math.max(0, lines - 1) * fact.lineSpacingPt;
|
|
5379
|
+
if (paragraphs.length > 1) {
|
|
5380
|
+
heightPt += (paragraphs.length - 1) * (fact.paraSpaceBeforePt + fact.paraSpaceAfterPt);
|
|
5381
|
+
}
|
|
5382
|
+
return { heightPt, lines };
|
|
5383
|
+
}
|
|
5384
|
+
var pptxCanvasRule = {
|
|
5385
|
+
id: "pptx/canvas",
|
|
5386
|
+
code: QUALITY_CODES.CANVAS_UNSPECIFIED,
|
|
5387
|
+
category: "composition",
|
|
5388
|
+
defaultSeverity: "info",
|
|
5389
|
+
defaultCertainty: "deterministic",
|
|
5390
|
+
formats: ["pptx"],
|
|
5391
|
+
evaluate: ({ facts }) => {
|
|
5392
|
+
const canvas = facts.find(
|
|
5393
|
+
(fact) => fact.kind === "pptx/canvas"
|
|
5394
|
+
);
|
|
5395
|
+
if (!canvas) return [];
|
|
5396
|
+
const { widthIn: width, heightIn: height } = canvas;
|
|
5397
|
+
if (width === void 0 || height === void 0) {
|
|
5398
|
+
const missing = [
|
|
5399
|
+
width === void 0 ? "props.slideWidth" : void 0,
|
|
5400
|
+
height === void 0 ? "props.slideHeight" : void 0
|
|
5401
|
+
].filter((entry) => entry !== void 0);
|
|
5402
|
+
const state = missing.length === 2 ? "No slide canvas declared" : `Incomplete slide canvas (${missing[0]} missing)`;
|
|
5403
|
+
return [
|
|
5404
|
+
{
|
|
5405
|
+
code: QUALITY_CODES.CANVAS_UNSPECIFIED,
|
|
5406
|
+
severity: "warning",
|
|
5407
|
+
category: "integrity",
|
|
5408
|
+
message: `${state}: the renderer falls back to 4:3 (${RENDERER_DEFAULT_WIDTH_IN}\xD7${RENDERER_DEFAULT_HEIGHT_IN}"), and 16:9 content on that canvas leaves a dead strip at the bottom.`,
|
|
5409
|
+
path: canvas.path,
|
|
5410
|
+
suggestion: "Declare props.slideWidth and props.slideHeight \u2014 13.333 \xD7 7.5 for a standard 16:9 deck.",
|
|
5411
|
+
context: {
|
|
5412
|
+
missing,
|
|
5413
|
+
rendererDefault: {
|
|
5414
|
+
slideWidth: RENDERER_DEFAULT_WIDTH_IN,
|
|
5415
|
+
slideHeight: RENDERER_DEFAULT_HEIGHT_IN
|
|
5416
|
+
}
|
|
5417
|
+
}
|
|
5418
|
+
}
|
|
5419
|
+
];
|
|
5420
|
+
}
|
|
5421
|
+
const match = KNOWN_CANVASES.find(
|
|
5422
|
+
(known) => Math.abs(known.w - width) < 0.01 && Math.abs(known.h - height) < 0.01
|
|
5423
|
+
);
|
|
5424
|
+
if (match?.legacy) {
|
|
5425
|
+
return [
|
|
5426
|
+
{
|
|
5427
|
+
code: QUALITY_CODES.CANVAS_LEGACY,
|
|
5428
|
+
message: `Canvas is 4:3 legacy (${match.w}\xD7${match.h}") \u2014 modern screens are 16:9.`,
|
|
5429
|
+
path: canvas.path,
|
|
5430
|
+
suggestion: "If 4:3 is not deliberate, use slideWidth 13.333 and slideHeight 7.5."
|
|
5431
|
+
}
|
|
5432
|
+
];
|
|
5433
|
+
}
|
|
5434
|
+
if (match) return [];
|
|
5435
|
+
return [
|
|
5436
|
+
{
|
|
5437
|
+
code: QUALITY_CODES.CANVAS_NONSTANDARD,
|
|
5438
|
+
message: `Canvas ${width}\xD7${height}" matches no common preset (16:9, 1:1, 4:5, 9:16).`,
|
|
5439
|
+
path: canvas.path,
|
|
5440
|
+
suggestion: "Confirm the size is deliberate; a mistyped canvas distorts every slide.",
|
|
5441
|
+
context: {
|
|
5442
|
+
knownCanvases: KNOWN_CANVASES.map(({ w, h, label }) => ({
|
|
5443
|
+
slideWidth: w,
|
|
5444
|
+
slideHeight: h,
|
|
5445
|
+
label
|
|
5446
|
+
}))
|
|
5447
|
+
}
|
|
5448
|
+
}
|
|
5449
|
+
];
|
|
5450
|
+
}
|
|
5451
|
+
};
|
|
5452
|
+
var pptxMinimumFontRule = {
|
|
5453
|
+
id: "pptx/minimum-font-size",
|
|
5454
|
+
code: QUALITY_CODES.FONT_SIZE_MIN,
|
|
5455
|
+
category: "legibility",
|
|
5456
|
+
defaultSeverity: "warning",
|
|
5457
|
+
defaultCertainty: "measured",
|
|
5458
|
+
formats: ["pptx"],
|
|
5459
|
+
defaultParameters: { minimumFontPt: DEFAULT_MIN_READABLE_FONT_PT },
|
|
5460
|
+
evaluate: ({ facts, configuration }) => {
|
|
5461
|
+
const minimum = numberParameter(
|
|
5462
|
+
configuration.parameters,
|
|
5463
|
+
"minimumFontPt",
|
|
5464
|
+
DEFAULT_MIN_READABLE_FONT_PT
|
|
5465
|
+
);
|
|
5466
|
+
return textFacts(facts).filter((fact) => fact.fontSizePt < minimum).map((fact) => ({
|
|
5467
|
+
message: `Effective font size is ${fact.fontSizePt}pt \u2014 unreadable on a projected slide.`,
|
|
5468
|
+
path: `${fact.path}/props`,
|
|
5469
|
+
suggestion: `Use at least ${minimum}pt; captions rarely work below 10pt.`,
|
|
5470
|
+
context: { fontSize: fact.fontSizePt, threshold: minimum },
|
|
5471
|
+
evidence: { actual: fact.fontSizePt, expected: minimum, unit: "pt" },
|
|
5472
|
+
// `add` replaces an existing member, so this lifts an explicit
|
|
5473
|
+
// fontSize and overrides an inherited style value alike.
|
|
5474
|
+
fixes: [
|
|
5475
|
+
{
|
|
5476
|
+
op: "add",
|
|
5477
|
+
path: `${fact.path}/props/fontSize`,
|
|
5478
|
+
value: minimum
|
|
5479
|
+
}
|
|
5480
|
+
]
|
|
5481
|
+
}));
|
|
5482
|
+
}
|
|
5483
|
+
};
|
|
5484
|
+
function fittingFontSizePt(fact, charWidthFactor, minimumFontPt) {
|
|
5485
|
+
if (fact.autoFit === true) return void 0;
|
|
5486
|
+
const minimumWholeSize = Math.ceil(minimumFontPt);
|
|
5487
|
+
for (let size = Math.floor(fact.fontSizePt) - 1; size >= minimumWholeSize; size--) {
|
|
5488
|
+
const estimate = estimateTextHeightPt(
|
|
5489
|
+
{ ...fact, fontSizePt: size },
|
|
5490
|
+
charWidthFactor
|
|
5491
|
+
);
|
|
5492
|
+
if (estimate !== void 0 && fact.boxHeightPt !== void 0 && estimate.heightPt <= fact.boxHeightPt) {
|
|
5493
|
+
return size;
|
|
5494
|
+
}
|
|
5495
|
+
}
|
|
5496
|
+
return void 0;
|
|
5497
|
+
}
|
|
5498
|
+
var pptxTextFitRule = {
|
|
5499
|
+
id: "pptx/text-fit",
|
|
5500
|
+
code: QUALITY_CODES.TEXT_TIGHT,
|
|
5501
|
+
category: "integrity",
|
|
5502
|
+
defaultSeverity: "info",
|
|
5503
|
+
defaultCertainty: "estimated",
|
|
5504
|
+
formats: ["pptx"],
|
|
5505
|
+
defaultParameters: {
|
|
5506
|
+
characterWidthFactor: DEFAULT_CHAR_WIDTH_FACTOR,
|
|
5507
|
+
safetyBufferPt: DEFAULT_SAFETY_BUFFER_PT
|
|
5508
|
+
},
|
|
5509
|
+
evaluate: ({ facts, configuration, profile, policy }) => {
|
|
5510
|
+
const factor = numberParameter(
|
|
5511
|
+
configuration.parameters,
|
|
5512
|
+
"characterWidthFactor",
|
|
5513
|
+
DEFAULT_CHAR_WIDTH_FACTOR
|
|
5514
|
+
);
|
|
5515
|
+
const safetyBufferPt = numberParameter(
|
|
5516
|
+
configuration.parameters,
|
|
5517
|
+
"safetyBufferPt",
|
|
5518
|
+
DEFAULT_SAFETY_BUFFER_PT
|
|
5519
|
+
);
|
|
5520
|
+
const minimumFontConfiguration = resolveRuleConfiguration(
|
|
5521
|
+
pptxMinimumFontRule,
|
|
5522
|
+
profile,
|
|
5523
|
+
policy
|
|
5524
|
+
);
|
|
5525
|
+
const minimumFontPt = minimumFontConfiguration.enabled ? numberParameter(
|
|
5526
|
+
minimumFontConfiguration.parameters,
|
|
5527
|
+
"minimumFontPt",
|
|
5528
|
+
DEFAULT_MIN_READABLE_FONT_PT
|
|
5529
|
+
) : DEFAULT_MIN_READABLE_FONT_PT;
|
|
5530
|
+
const findings = [];
|
|
5531
|
+
for (const fact of textFacts(facts)) {
|
|
5532
|
+
const estimate = estimateTextHeightPt(fact, factor);
|
|
5533
|
+
if (!estimate || fact.boxHeightPt === void 0) continue;
|
|
5534
|
+
const marginPt = fact.boxHeightPt - estimate.heightPt;
|
|
5535
|
+
const measured = {
|
|
5536
|
+
estimatedTextPt: Math.round(estimate.heightPt * 10) / 10,
|
|
5537
|
+
availablePt: Math.round(fact.boxHeightPt * 10) / 10,
|
|
5538
|
+
marginPt: Math.round(marginPt * 10) / 10,
|
|
5539
|
+
estimatedLines: estimate.lines,
|
|
5540
|
+
fontSize: fact.fontSizePt,
|
|
5541
|
+
boxWidthPt: Math.round(fact.boxWidthPt * 10) / 10
|
|
5542
|
+
};
|
|
5543
|
+
if (marginPt < -fact.lineSpacingPt) {
|
|
5544
|
+
const fittingSize = fittingFontSizePt(fact, factor, minimumFontPt);
|
|
5545
|
+
findings.push({
|
|
5546
|
+
code: QUALITY_CODES.TEXT_OVERFLOW,
|
|
5547
|
+
severity: "warning",
|
|
5548
|
+
message: `Text is estimated at ${measured.estimatedTextPt}pt tall (${estimate.lines} line${estimate.lines === 1 ? "" : "s"} of ${fact.fontSizePt}pt) in a ${measured.availablePt}pt box \u2014 it will overflow.`,
|
|
5549
|
+
path: fact.path,
|
|
5550
|
+
suggestion: "Shorten the text, reduce fontSize, or enlarge the box (h / rowSpan).",
|
|
5551
|
+
context: measured,
|
|
5552
|
+
evidence: {
|
|
5553
|
+
actual: measured.estimatedTextPt,
|
|
5554
|
+
expected: measured.availablePt,
|
|
5555
|
+
unit: "pt"
|
|
5556
|
+
},
|
|
5557
|
+
// A ready-made patch only when a readable size fits; shortening
|
|
5558
|
+
// the text or growing the box stays the author's call.
|
|
5559
|
+
...fittingSize !== void 0 && {
|
|
5560
|
+
fixes: [
|
|
5561
|
+
{
|
|
5562
|
+
op: "add",
|
|
5563
|
+
path: `${fact.path}/props/fontSize`,
|
|
5564
|
+
value: fittingSize
|
|
5565
|
+
}
|
|
5566
|
+
]
|
|
5567
|
+
}
|
|
5568
|
+
});
|
|
5569
|
+
continue;
|
|
5570
|
+
}
|
|
5571
|
+
if (marginPt >= safetyBufferPt) continue;
|
|
5572
|
+
findings.push({
|
|
5573
|
+
code: QUALITY_CODES.TEXT_TIGHT,
|
|
5574
|
+
message: marginPt < 0 ? `Text is estimated to exceed its ${measured.availablePt}pt box by ${-measured.marginPt}pt \u2014 within one line-height, so likely a harmless spill into the gap below.` : `Text fits its box with only ${measured.marginPt}pt to spare \u2014 renderer rounding can push it over.`,
|
|
5575
|
+
path: fact.path,
|
|
5576
|
+
suggestion: `Leave at least ${safetyBufferPt}pt of vertical margin.`,
|
|
5577
|
+
context: measured,
|
|
5578
|
+
evidence: {
|
|
5579
|
+
actual: measured.marginPt,
|
|
5580
|
+
expected: safetyBufferPt,
|
|
5581
|
+
unit: "pt margin"
|
|
5582
|
+
}
|
|
5583
|
+
});
|
|
5584
|
+
}
|
|
5585
|
+
return findings;
|
|
5586
|
+
}
|
|
5587
|
+
};
|
|
5588
|
+
var pptxSlideDensityRule = {
|
|
5589
|
+
id: "pptx/slide-density",
|
|
5590
|
+
code: QUALITY_CODES.SLIDE_DENSITY,
|
|
5591
|
+
category: "information-design",
|
|
5592
|
+
defaultSeverity: "warning",
|
|
5593
|
+
defaultCertainty: "estimated",
|
|
5594
|
+
formats: ["pptx"],
|
|
5595
|
+
defaultParameters: { maximumBodyWords: DEFAULT_MAX_BODY_WORDS_PER_SLIDE },
|
|
5596
|
+
evaluate: ({ facts, configuration }) => {
|
|
5597
|
+
const threshold = numberParameter(
|
|
5598
|
+
configuration.parameters,
|
|
5599
|
+
"maximumBodyWords",
|
|
5600
|
+
DEFAULT_MAX_BODY_WORDS_PER_SLIDE
|
|
5601
|
+
);
|
|
5602
|
+
return facts.filter((fact) => fact.kind === "pptx/slide").filter((fact) => fact.bodyWords > threshold).map((fact) => ({
|
|
5603
|
+
message: `${fact.bodyWords} words of body text on one slide \u2014 an audience reads a slide, it does not study one.`,
|
|
5604
|
+
path: fact.path,
|
|
5605
|
+
suggestion: "One idea per slide: split the content across more slides.",
|
|
5606
|
+
context: { bodyWords: fact.bodyWords, threshold },
|
|
5607
|
+
evidence: {
|
|
5608
|
+
actual: fact.bodyWords,
|
|
5609
|
+
expected: threshold,
|
|
5610
|
+
unit: "words"
|
|
5611
|
+
}
|
|
5612
|
+
}));
|
|
5613
|
+
}
|
|
5614
|
+
};
|
|
5615
|
+
var AA_NORMAL_RATIO = 4.5;
|
|
5616
|
+
var AA_LARGE_RATIO = 3;
|
|
5617
|
+
var LARGE_TEXT_PT = 18;
|
|
5618
|
+
var LARGE_BOLD_TEXT_PT = 14;
|
|
5619
|
+
function channelLuminance(channel) {
|
|
5620
|
+
const c = channel / 255;
|
|
5621
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
5622
|
+
}
|
|
5623
|
+
function relativeLuminance(hex) {
|
|
5624
|
+
const match = /^#?([0-9a-f]{6})$/i.exec(hex);
|
|
5625
|
+
if (!match) return void 0;
|
|
5626
|
+
const value = parseInt(match[1], 16);
|
|
5627
|
+
return 0.2126 * channelLuminance(value >> 16 & 255) + 0.7152 * channelLuminance(value >> 8 & 255) + 0.0722 * channelLuminance(value & 255);
|
|
5628
|
+
}
|
|
5629
|
+
function contrastRatio(a, b) {
|
|
5630
|
+
const la = relativeLuminance(a);
|
|
5631
|
+
const lb = relativeLuminance(b);
|
|
5632
|
+
if (la === void 0 || lb === void 0) return void 0;
|
|
5633
|
+
return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
|
|
5634
|
+
}
|
|
5635
|
+
var pptxTextContrastRule = {
|
|
5636
|
+
id: "pptx/text-contrast",
|
|
5637
|
+
code: QUALITY_CODES.TEXT_CONTRAST,
|
|
5638
|
+
category: "accessibility",
|
|
5639
|
+
defaultSeverity: "warning",
|
|
5640
|
+
defaultCertainty: "deterministic",
|
|
5641
|
+
formats: ["pptx"],
|
|
5642
|
+
defaultParameters: {
|
|
5643
|
+
normalRatio: AA_NORMAL_RATIO,
|
|
5644
|
+
largeRatio: AA_LARGE_RATIO,
|
|
5645
|
+
largeTextPt: LARGE_TEXT_PT,
|
|
5646
|
+
largeBoldTextPt: LARGE_BOLD_TEXT_PT
|
|
5647
|
+
},
|
|
5648
|
+
evaluate: ({ facts, configuration }) => {
|
|
5649
|
+
const normalRatio = numberParameter(
|
|
5650
|
+
configuration.parameters,
|
|
5651
|
+
"normalRatio",
|
|
5652
|
+
AA_NORMAL_RATIO
|
|
5653
|
+
);
|
|
5654
|
+
const largeRatio = numberParameter(
|
|
5655
|
+
configuration.parameters,
|
|
5656
|
+
"largeRatio",
|
|
5657
|
+
AA_LARGE_RATIO
|
|
5658
|
+
);
|
|
5659
|
+
const largeTextPt = numberParameter(
|
|
5660
|
+
configuration.parameters,
|
|
5661
|
+
"largeTextPt",
|
|
5662
|
+
LARGE_TEXT_PT
|
|
5663
|
+
);
|
|
5664
|
+
const largeBoldTextPt = numberParameter(
|
|
5665
|
+
configuration.parameters,
|
|
5666
|
+
"largeBoldTextPt",
|
|
5667
|
+
LARGE_BOLD_TEXT_PT
|
|
5668
|
+
);
|
|
5669
|
+
return textFacts(facts).flatMap((fact) => {
|
|
5670
|
+
const { colorHex, backgroundHexes } = fact;
|
|
5671
|
+
if (!colorHex || !backgroundHexes?.length) return [];
|
|
5672
|
+
let worst;
|
|
5673
|
+
for (const background2 of backgroundHexes) {
|
|
5674
|
+
const ratio = contrastRatio(colorHex, background2);
|
|
5675
|
+
if (ratio === void 0) continue;
|
|
5676
|
+
if (!worst || ratio < worst.ratio) worst = { ratio, background: background2 };
|
|
5677
|
+
}
|
|
5678
|
+
if (!worst) return [];
|
|
5679
|
+
const isLarge = fact.fontSizePt >= largeTextPt || fact.bold && fact.fontSizePt >= largeBoldTextPt;
|
|
5680
|
+
const required = isLarge ? largeRatio : normalRatio;
|
|
5681
|
+
if (worst.ratio >= required) return [];
|
|
5682
|
+
const rounded = Math.round(worst.ratio * 100) / 100;
|
|
5683
|
+
return [
|
|
5684
|
+
{
|
|
5685
|
+
message: `Text at #${colorHex} on #${worst.background} has ${rounded}:1 contrast \u2014 below the ${required}:1 needed at ${fact.fontSizePt}pt${fact.bold ? " bold" : ""}.`,
|
|
5686
|
+
path: fact.path,
|
|
5687
|
+
suggestion: "Darken the text, lighten it further, or change the surface behind it.",
|
|
5688
|
+
context: {
|
|
5689
|
+
colorHex,
|
|
5690
|
+
backgroundHex: worst.background,
|
|
5691
|
+
ratio: rounded,
|
|
5692
|
+
required,
|
|
5693
|
+
fontSizePt: fact.fontSizePt,
|
|
5694
|
+
bold: fact.bold,
|
|
5695
|
+
backgroundHexes
|
|
5696
|
+
},
|
|
5697
|
+
evidence: {
|
|
5698
|
+
actual: rounded,
|
|
5699
|
+
expected: required,
|
|
5700
|
+
unit: ":1"
|
|
5701
|
+
}
|
|
5702
|
+
}
|
|
5703
|
+
];
|
|
5704
|
+
});
|
|
5705
|
+
}
|
|
5706
|
+
};
|
|
5707
|
+
var PPTX_QUALITY_RULES = {
|
|
5708
|
+
id: "pptx/default",
|
|
5709
|
+
rules: [
|
|
5710
|
+
pptxCanvasRule,
|
|
5711
|
+
pptxMinimumFontRule,
|
|
5712
|
+
pptxTextFitRule,
|
|
5713
|
+
pptxSlideDensityRule,
|
|
5714
|
+
pptxTextContrastRule
|
|
5715
|
+
]
|
|
5716
|
+
};
|
|
5717
|
+
var PPTX_QUALITY_PROFILES = {
|
|
5718
|
+
"executive-presentation": {
|
|
5719
|
+
id: "executive-presentation",
|
|
5720
|
+
formats: ["pptx"],
|
|
5721
|
+
description: "Decision deck optimized for scan speed and projection.",
|
|
5722
|
+
rules: {
|
|
5723
|
+
"pptx/minimum-font-size": { parameters: { minimumFontPt: 14 } },
|
|
5724
|
+
"pptx/slide-density": { parameters: { maximumBodyWords: 70 } }
|
|
5725
|
+
}
|
|
5726
|
+
},
|
|
5727
|
+
"technical-presentation": {
|
|
5728
|
+
id: "technical-presentation",
|
|
5729
|
+
formats: ["pptx"],
|
|
5730
|
+
description: "Portable professional presentation defaults."
|
|
5731
|
+
}
|
|
5732
|
+
};
|
|
5733
|
+
var PPTX_DEFAULT_QUALITY_PROFILE = PPTX_QUALITY_PROFILES["technical-presentation"];
|
|
5734
|
+
var PPTX_PROFILES_BY_ID = PPTX_QUALITY_PROFILES;
|
|
5735
|
+
function resolvePptxQualityProfile(requested) {
|
|
5736
|
+
if (!requested) return void 0;
|
|
5737
|
+
const registered = PPTX_PROFILES_BY_ID[requested.id];
|
|
5738
|
+
if (!registered) return requested;
|
|
5739
|
+
return mergeQualityProfiles(registered, requested);
|
|
5740
|
+
}
|
|
5741
|
+
var pptxQualityEngine = new QualityEngine(PPTX_QUALITY_RULES.rules);
|
|
5742
|
+
|
|
5743
|
+
// src/quality/preflight.ts
|
|
5744
|
+
var PREPARE_RULE_ID = "quality/prepare";
|
|
5745
|
+
function emptyAnalysis(ruleErrors = [], blocked = false) {
|
|
5746
|
+
return {
|
|
5747
|
+
diagnostics: [],
|
|
5748
|
+
counts: { error: 0, warning: 0, info: 0 },
|
|
5749
|
+
blocked,
|
|
5750
|
+
truncated: false,
|
|
5751
|
+
suppressedCount: 0,
|
|
5752
|
+
evaluatedRuleIds: [],
|
|
5753
|
+
ruleErrors
|
|
5754
|
+
};
|
|
5755
|
+
}
|
|
5756
|
+
function analyzePptxQuality(doc, options = {}) {
|
|
5757
|
+
assertValidQualityPolicy(options.policy);
|
|
5758
|
+
assertValidQualityProfile(options.profile);
|
|
5759
|
+
if (typeof doc !== "object" || doc === null || Array.isArray(doc) || doc.name !== "pptx") {
|
|
5760
|
+
return emptyAnalysis();
|
|
5761
|
+
}
|
|
5762
|
+
let prepared = options.prepared;
|
|
5763
|
+
try {
|
|
5764
|
+
prepared ??= preparePptxQualityDocument(
|
|
5765
|
+
doc,
|
|
5766
|
+
options
|
|
5767
|
+
);
|
|
5768
|
+
} catch (error) {
|
|
5769
|
+
if (options.policy?.onRuleError === "throw") throw error;
|
|
5770
|
+
const gate = options.policy?.gate;
|
|
5771
|
+
return emptyAnalysis(
|
|
5772
|
+
[
|
|
5773
|
+
{
|
|
5774
|
+
ruleId: PREPARE_RULE_ID,
|
|
5775
|
+
message: error instanceof Error ? error.message : String(error)
|
|
5776
|
+
}
|
|
5777
|
+
],
|
|
5778
|
+
gate !== void 0 && gate !== "none"
|
|
5779
|
+
);
|
|
5780
|
+
}
|
|
5781
|
+
return pptxQualityEngine.analyzeSync(prepared, {
|
|
5782
|
+
profile: resolvePptxQualityProfile(options.profile) ?? PPTX_DEFAULT_QUALITY_PROFILE,
|
|
5783
|
+
policy: options.policy
|
|
5784
|
+
});
|
|
5785
|
+
}
|
|
5786
|
+
|
|
4856
5787
|
// src/plugin/index.ts
|
|
4857
5788
|
import {
|
|
4858
5789
|
createComponent,
|
|
@@ -5360,10 +6291,14 @@ export {
|
|
|
5360
6291
|
DEFAULT_PPTX_RENDERER_ID,
|
|
5361
6292
|
DEFAULT_PPTX_THEME,
|
|
5362
6293
|
DuplicateComponentError,
|
|
6294
|
+
PPTX_DEFAULT_QUALITY_PROFILE,
|
|
6295
|
+
PPTX_QUALITY_PROFILES,
|
|
6296
|
+
PPTX_QUALITY_RULES,
|
|
5363
6297
|
PresentationGenerator,
|
|
5364
6298
|
PresentationValidationError,
|
|
5365
6299
|
UncompiledComponentError,
|
|
5366
6300
|
W as WarningCodes,
|
|
6301
|
+
analyzePptxQuality,
|
|
5367
6302
|
cleanComponentProps,
|
|
5368
6303
|
createComponent,
|
|
5369
6304
|
createPresentationGenerator,
|
|
@@ -5380,10 +6315,13 @@ export {
|
|
|
5380
6315
|
isPresentationComponent,
|
|
5381
6316
|
isPresentationComponentDefinition,
|
|
5382
6317
|
isSlideComponent,
|
|
6318
|
+
pptxQualityEngine,
|
|
5383
6319
|
pptxRendererIds,
|
|
5384
6320
|
pptxRendererStatuses,
|
|
5385
6321
|
pptxThemes,
|
|
6322
|
+
preparePptxQualityDocument,
|
|
5386
6323
|
resolveComponentVersion3 as resolveComponentVersion,
|
|
6324
|
+
resolvePptxQualityProfile,
|
|
5387
6325
|
validateComponentProps,
|
|
5388
6326
|
validatePresentation
|
|
5389
6327
|
};
|