@json-to-office/core-docx 0.29.0 → 0.31.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.
@@ -6,6 +6,28 @@ import { Paragraph, Table, TableOfContents, Textbox } from 'docx';
6
6
  import { ComponentDefinition, RenderContext } from '../types';
7
7
  import { ThemeConfig } from '../styles';
8
8
  import { MemoryCache } from '../cache';
9
+ /** Why a component type is never cached (see renderComponentWithCache). */
10
+ export type ComponentBypassReason = 'dynamic-context' | 'bookmark-id' | 'revision-ids';
11
+ export interface ComponentBypassStats {
12
+ /** Component type name. */
13
+ type: string;
14
+ /** Renders that skipped the cache by design. */
15
+ renders: number;
16
+ /** The (first observed) reason this type bypasses the cache. */
17
+ reason: ComponentBypassReason;
18
+ }
19
+ /**
20
+ * Get per-type "uncached by design" render counters.
21
+ */
22
+ export declare function getComponentBypassStats(): ComponentBypassStats[];
23
+ /**
24
+ * True when the serialized props/children reference a registered placeholder
25
+ * whose output can vary with the generation date. Components without one
26
+ * render identically across dates, so their cache keys must not embed the
27
+ * per-render timestamp — that's what made cross-render hits impossible for
28
+ * date-less documents (#156).
29
+ */
30
+ export declare function usesDateSensitivePlaceholder(serialized: string): boolean;
9
31
  /**
10
32
  * Initialize the component cache
11
33
  */
@@ -32,9 +54,25 @@ export declare function warmComponentCache(components: Array<{
32
54
  context: RenderContext;
33
55
  }>): Promise<void>;
34
56
  /**
35
- * Get component cache statistics
57
+ * Get component cache statistics, extended with per-type "uncached by
58
+ * design" render counters (#156). The bypass counters exist even before the
59
+ * cache is initialized — a document full of bypassed types never triggers
60
+ * initialization, yet its renders are exactly what needs surfacing.
36
61
  */
37
- export declare function getComponentCacheStats(): import("@json-to-office/shared/cache").CacheStatistics | null;
62
+ export declare function getComponentCacheStats(): {
63
+ bypassedComponents: ComponentBypassStats[];
64
+ } | {
65
+ bypassedComponents: ComponentBypassStats[];
66
+ entries: number;
67
+ totalSize: number;
68
+ hitRate: number;
69
+ missRate: number;
70
+ totalHits: number;
71
+ totalMisses: number;
72
+ avgResponseTime: number;
73
+ evictions: number;
74
+ componentStats: Map<string, import("@json-to-office/shared/cache").ComponentStatistics>;
75
+ } | null;
38
76
  /**
39
77
  * Export component cache for persistence
40
78
  */
@@ -1 +1 @@
1
- {"version":3,"file":"cached-render.d.ts","sourceRoot":"","sources":["../../src/core/cached-render.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EACL,WAAW,EAIZ,MAAM,UAAU,CAAC;AAoBlB;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CA4BlE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,GAAG,IAAI,CAEtD;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAIzD;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,mBAAmB,EAC9B,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,EACtB,WAAW,UAAQ,GAClB,OAAO,CAAC,CAAC,SAAS,GAAG,KAAK,GAAG,eAAe,GAAG,OAAO,CAAC,EAAE,CAAC,CAyG5D;AAKD;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,KAAK,CAAC;IAChB,SAAS,EAAE,mBAAmB,CAAC;IAC/B,KAAK,EAAE,WAAW,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC,GACD,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED;;GAEG;AACH,wBAAgB,sBAAsB,kEAMrC;AAED;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,GAAG,CACvD,MAAM,EACN,OAAO,CACR,GAAG,IAAI,CAAC,CAgBR;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GACzB,OAAO,CAAC,IAAI,CAAC,CAQf"}
1
+ {"version":3,"file":"cached-render.d.ts","sourceRoot":"","sources":["../../src/core/cached-render.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EACL,WAAW,EAIZ,MAAM,UAAU,CAAC;AAWlB,2EAA2E;AAC3E,MAAM,MAAM,qBAAqB,GAC7B,iBAAiB,GACjB,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,WAAW,oBAAoB;IACnC,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,MAAM,EAAE,qBAAqB,CAAC;CAC/B;AAwBD;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,oBAAoB,EAAE,CAMhE;AAUD;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CASxE;AAYD;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CA4BlE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,WAAW,GAAG,IAAI,CAEtD;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAKzD;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,mBAAmB,EAC9B,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,EACtB,WAAW,UAAQ,GAClB,OAAO,CAAC,CAAC,SAAS,GAAG,KAAK,GAAG,eAAe,GAAG,OAAO,CAAC,EAAE,CAAC,CAuH5D;AAKD;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,KAAK,CAAC;IAChB,SAAS,EAAE,mBAAmB,CAAC;IAC/B,KAAK,EAAE,WAAW,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC,GACD,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB;;;;;;;;;;;;;SAOrC;AAED;;GAEG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,GAAG,CACvD,MAAM,EACN,OAAO,CACR,GAAG,IAAI,CAAC,CAgBR;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GACzB,OAAO,CAAC,IAAI,CAAC,CAQf"}
@@ -23,6 +23,22 @@ export interface PrerasterizeOptions {
23
23
  /** Max concurrent per-visual fallback rasterizations (default 4). */
24
24
  concurrency?: number;
25
25
  }
26
+ /** Cumulative pre-pass counters for cache observability (#156). */
27
+ export interface VisualPrepassStats {
28
+ /** Documents that entered the pre-pass with at least one visual. */
29
+ documents: number;
30
+ /** Enabled visuals collected across those documents. */
31
+ collected: number;
32
+ /** Unique rasterization units after dedupe (identical content+dpi). */
33
+ unique: number;
34
+ }
35
+ /**
36
+ * Get cumulative per-document pre-pass counters. `collected - unique` is the
37
+ * work the dedupe saved — the `visual` cache benefit the component cache
38
+ * stats can never show, since `visual` bypasses that cache by design.
39
+ */
40
+ export declare function getVisualPrepassStats(): VisualPrepassStats;
41
+ export declare function resetVisualPrepassStats(): void;
26
42
  /**
27
43
  * Collect the props of every enabled `visual` component reachable from
28
44
  * `root`. The walk is generic — every array element and object value is
@@ -1 +1 @@
1
- {"version":3,"file":"prerasterizeVisuals.d.ts","sourceRoot":"","sources":["../../src/core/prerasterizeVisuals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAIL,KAAK,iBAAiB,EAEtB,KAAK,6BAA6B,EACnC,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAkB/D,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AASD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,WAAW,EAAE,CA4B/D;AAsDD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,OAAO,EACb,aAAa,EAAE,iBAAiB,GAAG,SAAS,EAC5C,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC,CAmJrD"}
1
+ {"version":3,"file":"prerasterizeVisuals.d.ts","sourceRoot":"","sources":["../../src/core/prerasterizeVisuals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAIL,KAAK,iBAAiB,EAEtB,KAAK,6BAA6B,EACnC,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAkB/D,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,mEAAmE;AACnE,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,kBAAkB,CAE1D;AAED,wBAAgB,uBAAuB,IAAI,IAAI,CAI9C;AASD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,WAAW,EAAE,CA4B/D;AAsDD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,OAAO,EACb,aAAa,EAAE,iBAAiB,GAAG,SAAS,EAC5C,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC,CAuJrD"}
package/dist/index.d.ts CHANGED
@@ -2,7 +2,8 @@ export declare function getCoreVersion(): string;
2
2
  export { generateDocument, generateFromConfig, generateDocumentFromJson, generateDocumentFromFile, generateBufferFromJson, generateBufferFromFile, generateAndSaveFromJson, generateAndSaveFromFile, validateJsonSchema, isReportComponentDefinition, saveDocument, generateAndSave, DocumentGenerator as CoreDocumentGenerator, } from './core/generator';
3
3
  export { flattenVisuals, type FlattenVisualsOptions, } from './core/flattenVisuals';
4
4
  export { MemoryCache, CacheKeyGenerator, DEFAULT_CACHE_CONFIG, getCacheConfigFromEnv, mergeConfigs, ComponentCacheAnalytics, type CacheConfiguration, type CachedComponent, type CacheStatistics, type CacheKeyOptions, type CacheEvents, type CacheAnalyticsReport, type ComponentPerformanceMetrics, type ComponentCacheTrends, type CacheOptimizationRecommendation, type TimeSeriesPoint, } from './cache/index';
5
- export { initializeComponentCache, getComponentCache, clearComponentCache, getComponentCacheStats, warmComponentCache, } from './core/cached-render';
5
+ export { initializeComponentCache, getComponentCache, clearComponentCache, getComponentCacheStats, getComponentBypassStats, warmComponentCache, type ComponentBypassReason, type ComponentBypassStats, } from './core/cached-render';
6
+ export { getVisualPrepassStats, resetVisualPrepassStats, type VisualPrepassStats, } from './core/prerasterizeVisuals';
6
7
  export { isReportComponent, isSectionComponent, isHeadingComponent, isParagraphComponent, isColumnsComponent, isImageComponent, isStatisticComponent, isTableComponent, isListComponent, isHighchartsComponent, isVisualComponent, } from './types/index';
7
8
  export type { ImageContent, StatisticContent, TableData, SectionProperties, ColumnSettings, PageSizeOptions, PageMarginOptions, PageNumberOptions, PageBorderOptions, RenderContext, } from './types/index';
8
9
  export * from './utils/formatters';
@@ -16,6 +17,6 @@ export { examples, getExample, getExampleNames, loadJsonExample, } from './templ
16
17
  export { runExample } from './utils/exampleRunner';
17
18
  import './components/index';
18
19
  export type { ChartGenerationResult, } from './components/highcharts';
19
- export { createComponent, createVersion, createDocumentGenerator, validateComponentProps, validateDocument, cleanComponentProps, ComponentValidationError, UnknownPreservedComponentError, generatePluginDocumentSchema, exportPluginSchema, generateComponentSchemas, mergeSchemas, type CustomComponent, type ComponentVersion, type ComponentVersionMap, type RenderFunction, type RenderContext as ComponentRenderContext, type DocumentGenerator, type DocumentGeneratorOptions, type GenerateOptions, type GenerateFileOptions, type GenerationResult, type BufferGenerationResult, type FileGenerationResult, type ValidationResult, type ValidationError, type ExtractCustomComponentType, type CustomComponentUnion, type ExtendedComponentDefinition, type ExtendedReportComponent, type InferCustomComponents, } from './plugin/index';
20
+ export { createComponent, createVersion, createDocumentGenerator, validateComponentProps, validateDocument, cleanComponentProps, ComponentValidationError, UnknownPreservedComponentError, generatePluginDocumentSchema, exportPluginSchema, generateComponentSchemas, mergeSchemas, type CustomComponent, type ComponentVersion, type ComponentVersionMap, type RenderFunction, type RenderContext as ComponentRenderContext, type DocumentGenerator, type DocumentGeneratorOptions, type GenerateOptions, type GenerateFileOptions, type GenerationResult, type BufferGenerationResult, type FileGenerationResult, type StandardDefinitionResult, type ValidationResult, type ValidationError, type ExtractCustomComponentType, type CustomComponentUnion, type ExtendedComponentDefinition, type ExtendedReportComponent, type InferCustomComponents, } from './plugin/index';
20
21
  export type { PluginComponent, PluginRenderFunction, PluginValidationError, PluginValidationResult, } from './types/plugin';
21
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAGD,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EAClB,2BAA2B,EAC3B,YAAY,EACZ,eAAe,EACf,iBAAiB,IAAI,qBAAqB,GAC3C,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,cAAc,EACd,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,YAAY,EACZ,uBAAuB,EAEvB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,oBAAoB,EACzB,KAAK,+BAA+B,EACpC,KAAK,eAAe,GACrB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,KAAK,kBAAkB,GACxB,MAAM,4BAA4B,CAAC;AAKpC,OAAO,EAEL,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAGvB,YAAY,EAEV,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,eAAe,CAAC;AAGvB,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,MAAM,EACN,YAAY,EACZ,cAAc,EACd,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,EACf,cAAc,EACd,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,QAAQ,EACR,UAAU,EACV,eAAe,EACf,eAAe,GAChB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAGnD,OAAO,oBAAoB,CAAC;AAG5B,YAAY,EAEV,qBAAqB,GACtB,MAAM,yBAAyB,CAAC;AAMjC,OAAO,EAEL,eAAe,EACf,aAAa,EACb,uBAAuB,EAGvB,sBAAsB,EACtB,gBAAgB,EAChB,mBAAmB,EACnB,wBAAwB,EACxB,8BAA8B,EAG9B,4BAA4B,EAC5B,kBAAkB,EAClB,wBAAwB,EACxB,YAAY,EAGZ,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,aAAa,IAAI,sBAAsB,EAC5C,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,KAAK,eAAe,EAGpB,KAAK,0BAA0B,EAC/B,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,GAC3B,MAAM,gBAAgB,CAAC;AAGxB,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -4271,6 +4271,33 @@ function componentHasRevision(component) {
4271
4271
  import { createHash as createHash3 } from "crypto";
4272
4272
  var componentCache = null;
4273
4273
  var cacheKeyGen = null;
4274
+ var bypassStats = /* @__PURE__ */ new Map();
4275
+ function recordBypass(type, reason) {
4276
+ const entry = bypassStats.get(type);
4277
+ if (entry) {
4278
+ entry.renders++;
4279
+ } else {
4280
+ bypassStats.set(type, { renders: 1, reason });
4281
+ }
4282
+ }
4283
+ function getComponentBypassStats() {
4284
+ return Array.from(bypassStats.entries()).map(([type, s]) => ({
4285
+ type,
4286
+ renders: s.renders,
4287
+ reason: s.reason
4288
+ }));
4289
+ }
4290
+ var DATE_INDEPENDENT_PLACEHOLDERS = /* @__PURE__ */ new Set(["PAGE", "TOTAL_PAGES"]);
4291
+ function usesDateSensitivePlaceholder(serialized) {
4292
+ const placeholderRegex = /\{([^}{]+)\}/g;
4293
+ let match;
4294
+ while ((match = placeholderRegex.exec(serialized)) !== null) {
4295
+ const name = match[1].toUpperCase();
4296
+ if (DATE_INDEPENDENT_PLACEHOLDERS.has(name)) continue;
4297
+ if (PlaceholderRegistry.has(name)) return true;
4298
+ }
4299
+ return false;
4300
+ }
4274
4301
  function createThemeHash(theme) {
4275
4302
  const themeString = JSON.stringify(theme);
4276
4303
  return createHash3("sha256").update(themeString).digest("hex").substring(0, 8);
@@ -4312,24 +4339,34 @@ async function clearComponentCache() {
4312
4339
  if (componentCache) {
4313
4340
  await componentCache.clear();
4314
4341
  }
4342
+ bypassStats.clear();
4315
4343
  }
4316
4344
  async function renderComponentWithCache(component, theme, themeName, context, bypassCache = false) {
4317
- const forceBypassForType = component.name === "toc" || component.name === "section" || component.name === "visual" || component.name === "heading" || // Both explicit lists and markdown-list paragraphs register numbering in
4318
- // the current document scope. Cached paragraphs can otherwise reference
4319
- // definitions that only existed in a previous render.
4320
- component.name === "list" || component.name === "paragraph" || "id" in component || componentHasRevision(component);
4345
+ const bypassReason = componentHasRevision(
4346
+ component
4347
+ ) ? "revision-ids" : "id" in component ? "bookmark-id" : component.name === "toc" || component.name === "section" || component.name === "visual" || component.name === "heading" || // Both explicit lists and markdown-list paragraphs register
4348
+ // numbering in the current document scope. Cached paragraphs can
4349
+ // otherwise reference definitions that only existed in a previous
4350
+ // render.
4351
+ component.name === "list" || component.name === "paragraph" ? "dynamic-context" : null;
4321
4352
  if (!componentCache) {
4322
4353
  initializeComponentCache();
4323
4354
  }
4324
- if (!componentCache || bypassCache || forceBypassForType || !componentCache.getConfig().enabled) {
4355
+ if (bypassReason !== null) {
4356
+ recordBypass(component.name, bypassReason);
4357
+ return renderComponent(component, theme, themeName, context);
4358
+ }
4359
+ if (!componentCache || bypassCache || !componentCache.getConfig().enabled) {
4325
4360
  return renderComponent(component, theme, themeName, context);
4326
4361
  }
4327
4362
  const componentProps = JSON.stringify(component.props || {});
4328
4363
  const themeHash = createThemeHash(theme);
4329
4364
  const contextKey = context?.section ? `${context.section.currentLayout}:${context.section.columnCount}` : "no-section";
4330
- const generationDateKey = getGenerationDate().toISOString();
4331
4365
  const baseDirKey = getBaseDir() ?? "";
4332
4366
  const childrenKey = "children" in component && component.children ? `:children:${JSON.stringify(component.children)}` : "";
4367
+ const generationDateKey = usesDateSensitivePlaceholder(
4368
+ componentProps + childrenKey
4369
+ ) ? getGenerationDate().toISOString() : "no-date";
4333
4370
  const cacheKey = `component:${component.name}:${themeHash}:${contextKey}:${generationDateKey}:${baseDirKey}:${componentProps}${childrenKey}`;
4334
4371
  const cached = await componentCache.get(cacheKey);
4335
4372
  if (cached) {
@@ -4372,10 +4409,11 @@ async function warmComponentCache(components) {
4372
4409
  await Promise.all(warmingPromises);
4373
4410
  }
4374
4411
  function getComponentCacheStats() {
4412
+ const bypassedComponents = getComponentBypassStats();
4375
4413
  if (!componentCache) {
4376
- return null;
4414
+ return bypassedComponents.length > 0 ? { bypassedComponents } : null;
4377
4415
  }
4378
- return componentCache.getStats();
4416
+ return { ...componentCache.getStats(), bypassedComponents };
4379
4417
  }
4380
4418
 
4381
4419
  // src/core/content.ts
@@ -7229,6 +7267,19 @@ function createLimiter(max) {
7229
7267
  var DEFAULT_FALLBACK_CONCURRENCY = 4;
7230
7268
  var BATCH_TIMEOUT_BASE_MS = 3e4;
7231
7269
  var BATCH_TIMEOUT_PER_SLIDE_MS = 1e4;
7270
+ var prepassStats = {
7271
+ documents: 0,
7272
+ collected: 0,
7273
+ unique: 0
7274
+ };
7275
+ function getVisualPrepassStats() {
7276
+ return { ...prepassStats };
7277
+ }
7278
+ function resetVisualPrepassStats() {
7279
+ prepassStats.documents = 0;
7280
+ prepassStats.collected = 0;
7281
+ prepassStats.unique = 0;
7282
+ }
7232
7283
  function collectVisualProps(root) {
7233
7284
  const found = [];
7234
7285
  const seen = /* @__PURE__ */ new WeakSet();
@@ -7305,6 +7356,9 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
7305
7356
  }
7306
7357
  }
7307
7358
  if (targets.size === 0) return map;
7359
+ prepassStats.documents++;
7360
+ prepassStats.collected += visuals.length;
7361
+ prepassStats.unique += targets.size;
7308
7362
  const unique = [...targets.values()];
7309
7363
  const limit = createLimiter(
7310
7364
  Math.max(1, options.concurrency ?? DEFAULT_FALLBACK_CONCURRENCY)
@@ -9001,70 +9055,104 @@ function createBuilderImpl(state) {
9001
9055
  }
9002
9056
  return new Set(list);
9003
9057
  }
9004
- async function generate(document, options) {
9005
- try {
9006
- const preserveSet = resolvePreserveSet(options);
9007
- const rootIn = document;
9008
- const internalDocument = rootIn.props === void 0 ? { ...rootIn, props: {} } : rootIn;
9009
- const vOpts = {
9010
- ...state.validation,
9011
- ...options?.validation
9012
- };
9013
- if (vOpts.enabled !== false) {
9014
- const result = validateDocument(
9015
- internalDocument,
9016
- state.components,
9017
- { allowUnknownFields: vOpts.allowUnknownFields }
9058
+ async function expandDocument(document, options) {
9059
+ const preserveSet = resolvePreserveSet(options);
9060
+ const rootIn = document;
9061
+ const internalDocument = rootIn.props === void 0 ? { ...rootIn, props: {} } : rootIn;
9062
+ const vOpts = {
9063
+ ...state.validation,
9064
+ ...options?.validation
9065
+ };
9066
+ if (vOpts.enabled !== false) {
9067
+ const result = validateDocument(
9068
+ internalDocument,
9069
+ state.components,
9070
+ { allowUnknownFields: vOpts.allowUnknownFields }
9071
+ );
9072
+ if (!result.valid) {
9073
+ throw new ComponentValidationError2(
9074
+ (result.errors ?? []).map((e) => ({
9075
+ path: e.path ?? "",
9076
+ message: e.message
9077
+ })),
9078
+ internalDocument
9018
9079
  );
9019
- if (!result.valid) {
9020
- throw new ComponentValidationError2(
9021
- (result.errors ?? []).map((e) => ({
9022
- path: e.path ?? "",
9023
- message: e.message
9024
- })),
9025
- internalDocument
9026
- );
9027
- }
9028
9080
  }
9029
- const validateEmitted = vOpts.enabled === false ? void 0 : (emitted, componentLabel) => {
9030
- const result = validateDocument(
9031
- { ...internalDocument, children: emitted },
9032
- state.components,
9033
- { allowUnknownFields: vOpts.allowUnknownFields }
9081
+ }
9082
+ const validateEmitted = vOpts.enabled === false ? void 0 : (emitted, componentLabel) => {
9083
+ const result = validateDocument(
9084
+ { ...internalDocument, children: emitted },
9085
+ state.components,
9086
+ { allowUnknownFields: vOpts.allowUnknownFields }
9087
+ );
9088
+ if (!result.valid) {
9089
+ throw new ComponentValidationError2(
9090
+ (result.errors ?? []).map((e) => ({
9091
+ path: e.path ?? "",
9092
+ message: `custom component '${componentLabel}' emitted invalid output \u2014 ${e.message}`
9093
+ })),
9094
+ emitted
9034
9095
  );
9035
- if (!result.valid) {
9036
- throw new ComponentValidationError2(
9037
- (result.errors ?? []).map((e) => ({
9038
- path: e.path ?? "",
9039
- message: `custom component '${componentLabel}' emitted invalid output \u2014 ${e.message}`
9040
- })),
9041
- emitted
9042
- );
9043
- }
9096
+ }
9097
+ };
9098
+ const warnings = [];
9099
+ const {
9100
+ document: modedRoot,
9101
+ theme: modedTheme,
9102
+ themeName
9103
+ } = resolveThemeContext(internalDocument, {
9104
+ customThemes: state.customThemes,
9105
+ fonts: state.fonts,
9106
+ warnings,
9107
+ resolveNamedTheme: resolveDocumentTheme
9108
+ });
9109
+ const processed = await processDocumentComponents(
9110
+ modedRoot.children || [],
9111
+ preserveSet,
9112
+ warnings,
9113
+ modedTheme,
9114
+ validateEmitted
9115
+ );
9116
+ const processedDocument = {
9117
+ ...modedRoot,
9118
+ children: processed.standard
9119
+ };
9120
+ const [modedDoc] = normalizeDocument(processedDocument);
9121
+ return {
9122
+ modedRoot,
9123
+ modedTheme,
9124
+ themeName,
9125
+ processed,
9126
+ modedDoc,
9127
+ warnings,
9128
+ preserveSet
9129
+ };
9130
+ }
9131
+ async function expandStandardDefinition(document, options) {
9132
+ try {
9133
+ const { modedDoc, warnings } = await expandDocument(document, options);
9134
+ return {
9135
+ standardDefinition: modedDoc,
9136
+ warnings: warnings.length > 0 ? warnings : null
9044
9137
  };
9045
- const warnings = [];
9138
+ } catch (error) {
9139
+ if (state.debug) {
9140
+ console.error("Document expansion error:", error);
9141
+ }
9142
+ throw error;
9143
+ }
9144
+ }
9145
+ async function generate(document, options) {
9146
+ try {
9046
9147
  const {
9047
- document: modedRoot,
9048
- theme: modedTheme,
9049
- themeName
9050
- } = resolveThemeContext(internalDocument, {
9051
- customThemes: state.customThemes,
9052
- fonts: state.fonts,
9053
- warnings,
9054
- resolveNamedTheme: resolveDocumentTheme
9055
- });
9056
- const processed = await processDocumentComponents(
9057
- modedRoot.children || [],
9058
- preserveSet,
9059
- warnings,
9148
+ modedRoot,
9060
9149
  modedTheme,
9061
- validateEmitted
9062
- );
9063
- const processedDocument = {
9064
- ...modedRoot,
9065
- children: processed.standard
9066
- };
9067
- const [modedDoc] = normalizeDocument(processedDocument);
9150
+ themeName,
9151
+ processed,
9152
+ modedDoc,
9153
+ warnings,
9154
+ preserveSet
9155
+ } = await expandDocument(document, options);
9068
9156
  await resolveDocumentFonts(modedDoc, modedTheme, state.fonts, warnings);
9069
9157
  const packageOptions = {
9070
9158
  deterministic: options?.deterministic ?? state.deterministic,
@@ -9191,6 +9279,7 @@ function createBuilderImpl(state) {
9191
9279
  generate,
9192
9280
  generateBuffer,
9193
9281
  generateFile,
9282
+ expandStandardDefinition,
9194
9283
  getComponentNames,
9195
9284
  validate,
9196
9285
  generateSchema,
@@ -9262,11 +9351,13 @@ export {
9262
9351
  generatePluginDocumentSchema,
9263
9352
  generateWarningsDocument,
9264
9353
  export_getCacheConfigFromEnv as getCacheConfigFromEnv,
9354
+ getComponentBypassStats,
9265
9355
  getComponentCache,
9266
9356
  getComponentCacheStats,
9267
9357
  getCoreVersion,
9268
9358
  getExample,
9269
9359
  getExampleNames,
9360
+ getVisualPrepassStats,
9270
9361
  hasNodeBuiltins,
9271
9362
  initializeComponentCache,
9272
9363
  isColumnsComponent,
@@ -9290,6 +9381,7 @@ export {
9290
9381
  minimalTheme,
9291
9382
  modernTheme,
9292
9383
  parseTextWithDecorators,
9384
+ resetVisualPrepassStats,
9293
9385
  runExample,
9294
9386
  saveDocument,
9295
9387
  themes,