@json-to-office/core-docx 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,113 +1,15 @@
1
- import { type TSchema, type Static } from '@sinclair/typebox';
1
+ import type { TSchema } from '@sinclair/typebox';
2
2
  import type { ComponentDefinition } from '@json-to-office/shared-docx';
3
- import type { AddWarningFunction } from '@json-to-office/shared-docx';
4
3
  import type { ThemeConfig } from '../styles';
4
+ import type { RenderContext as SharedRenderContext, RenderFunction as SharedRenderFunction, ComponentVersion as SharedComponentVersion, ComponentVersionMap as SharedComponentVersionMap, CustomComponent as SharedCustomComponent } from '@json-to-office/shared/plugin';
5
5
  /**
6
- * Render function context - parameters passed to render
7
- */
8
- export interface RenderContext<T> {
9
- /** The validated props for this component */
10
- props: T;
11
- /** The resolved theme configuration */
12
- theme: ThemeConfig;
13
- /** Function to add warnings during processing */
14
- addWarning: AddWarningFunction;
15
- /** For container components: processed nested children */
16
- children?: unknown[];
17
- }
18
- /**
19
- * Render function that transforms custom component props into standard components.
20
- */
21
- export type RenderFunction<TProps, TComponentDefinition = ComponentDefinition> = (context: RenderContext<TProps>) => Promise<TComponentDefinition[]>;
22
- /**
23
- * A single version entry within a versioned component.
24
- * Each version is self-contained with its own schema, render, and metadata.
25
- */
26
- export interface ComponentVersion<TComponentDefinition = ComponentDefinition, TPropsSchema extends TSchema = TSchema> {
27
- /** TypeBox schema for props validation */
28
- propsSchema: TPropsSchema;
29
- /** Async render function to transform props into standard components */
30
- render: RenderFunction<Static<TPropsSchema>, TComponentDefinition>;
31
- /** Whether this version supports nested children */
32
- hasChildren?: boolean;
33
- /** Optional description for this version */
34
- description?: string;
35
- }
36
- /**
37
- * Map of semver version strings to their version definitions.
38
- */
39
- export type ComponentVersionMap<TComponentDefinition = ComponentDefinition> = Record<string, ComponentVersion<TComponentDefinition, any>>;
40
- /**
41
- * Custom component definition with multiple semver-keyed versions.
42
- * Each version is self-contained with its own schema + render.
43
- *
44
- * @typeParam TComponentDefinition - The component definition type for render return
45
- * @typeParam TVersions - The versions map type
46
- * @typeParam TName - The literal string type for the component name
47
- */
48
- export interface CustomComponent<TComponentDefinition = ComponentDefinition, TVersions extends ComponentVersionMap<TComponentDefinition> = ComponentVersionMap<TComponentDefinition>, TName extends string = string> {
49
- /** Unique name for the component type */
50
- name: TName;
51
- /** Map of semver version strings to version definitions */
52
- versions: TVersions;
53
- }
54
- /**
55
- * Create a single version entry with full type inference for props.
56
- *
57
- * Wrapping each version with `createVersion` lets TypeScript infer the
58
- * props type from `propsSchema` and propagate it to the `render` function,
59
- * so `props` is fully typed instead of `any`.
60
- *
61
- * @example
62
- * ```typescript
63
- * createVersion({
64
- * propsSchema: Type.Object({ city: Type.String() }),
65
- * render: async ({ props }) => {
66
- * // props.city is inferred as string
67
- * return [{ name: 'paragraph', props: { text: props.city } }];
68
- * },
69
- * })
70
- * ```
6
+ * DOCX render context with ThemeConfig baked in
71
7
  */
8
+ export type RenderContext<T> = SharedRenderContext<T, ThemeConfig>;
9
+ export type RenderFunction<TProps, TComponentDefinition = ComponentDefinition> = SharedRenderFunction<TProps, TComponentDefinition, ThemeConfig>;
10
+ export type ComponentVersion<TComponentDefinition = ComponentDefinition, TPropsSchema extends TSchema = TSchema> = SharedComponentVersion<TComponentDefinition, TPropsSchema, ThemeConfig>;
11
+ export type ComponentVersionMap<TComponentDefinition = ComponentDefinition> = SharedComponentVersionMap<TComponentDefinition, ThemeConfig>;
12
+ export type CustomComponent<TComponentDefinition = ComponentDefinition, TVersions extends ComponentVersionMap<TComponentDefinition> = ComponentVersionMap<TComponentDefinition>, TName extends string = string> = SharedCustomComponent<TComponentDefinition, TVersions, TName>;
72
13
  export declare function createVersion<TPropsSchema extends TSchema, TComponentDefinition = ComponentDefinition>(version: ComponentVersion<TComponentDefinition, TPropsSchema>): ComponentVersion<TComponentDefinition, TPropsSchema>;
73
- /**
74
- * Create a custom component with multiple semver-keyed versions.
75
- *
76
- * Use {@link createVersion} for each version entry to get full type inference
77
- * for `props` in render functions.
78
- *
79
- * @example Basic single-version usage
80
- * ```typescript
81
- * const weatherComponent = createComponent({
82
- * name: 'weather' as const,
83
- * versions: {
84
- * '1.0.0': createVersion({
85
- * propsSchema: Type.Object({ city: Type.String() }),
86
- * render: async ({ props }) => [{
87
- * name: 'paragraph',
88
- * props: { text: `Weather in ${props.city}` }
89
- * }]
90
- * })
91
- * }
92
- * });
93
- * ```
94
- *
95
- * @example Multi-version with breaking changes
96
- * ```typescript
97
- * const weatherComponent = createComponent({
98
- * name: 'weather' as const,
99
- * versions: {
100
- * '1.0.0': createVersion({
101
- * propsSchema: WeatherV1PropsSchema,
102
- * render: async ({ props }) => [...],
103
- * }),
104
- * '2.0.0': createVersion({
105
- * propsSchema: WeatherV2PropsSchema,
106
- * render: async ({ props }) => [...],
107
- * }),
108
- * },
109
- * });
110
- * ```
111
- */
112
14
  export declare function createComponent<TComponentDefinition = ComponentDefinition, TVersions extends ComponentVersionMap<TComponentDefinition> = ComponentVersionMap<TComponentDefinition>, TName extends string = string>(component: CustomComponent<TComponentDefinition, TVersions, TName>): CustomComponent<TComponentDefinition, TVersions, TName>;
113
15
  //# sourceMappingURL=createComponent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createComponent.d.ts","sourceRoot":"","sources":["../../src/plugin/createComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,6CAA6C;IAC7C,KAAK,EAAE,CAAC,CAAC;IACT,uCAAuC;IACvC,KAAK,EAAE,WAAW,CAAC;IACnB,iDAAiD;IACjD,UAAU,EAAE,kBAAkB,CAAC;IAC/B,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,CACxB,MAAM,EACN,oBAAoB,GAAG,mBAAmB,IACxC,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;AAExE;;;GAGG;AACH,MAAM,WAAW,gBAAgB,CAC/B,oBAAoB,GAAG,mBAAmB,EAC1C,YAAY,SAAS,OAAO,GAAG,OAAO;IAEtC,0CAA0C;IAC1C,WAAW,EAAE,YAAY,CAAC;IAC1B,wEAAwE;IACxE,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,oBAAoB,CAAC,CAAC;IACnE,oDAAoD;IACpD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,CAAC,oBAAoB,GAAG,mBAAmB,IACxE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC,CAAC;AAE9D;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe,CAC9B,oBAAoB,GAAG,mBAAmB,EAC1C,SAAS,SACP,mBAAmB,CAAC,oBAAoB,CAAC,GAAG,mBAAmB,CAAC,oBAAoB,CAAC,EACvF,KAAK,SAAS,MAAM,GAAG,MAAM;IAE7B,yCAAyC;IACzC,IAAI,EAAE,KAAK,CAAC;IACZ,2DAA2D;IAC3D,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAC3B,YAAY,SAAS,OAAO,EAC5B,oBAAoB,GAAG,mBAAmB,EAE1C,OAAO,EAAE,gBAAgB,CAAC,oBAAoB,EAAE,YAAY,CAAC,GAC5D,gBAAgB,CAAC,oBAAoB,EAAE,YAAY,CAAC,CAEtD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,eAAe,CAC7B,oBAAoB,GAAG,mBAAmB,EAC1C,SAAS,SACP,mBAAmB,CAAC,oBAAoB,CAAC,GAAG,mBAAmB,CAAC,oBAAoB,CAAC,EACvF,KAAK,SAAS,MAAM,GAAG,MAAM,EAE7B,SAAS,EAAE,eAAe,CAAC,oBAAoB,EAAE,SAAS,EAAE,KAAK,CAAC,GACjE,eAAe,CAAC,oBAAoB,EAAE,SAAS,EAAE,KAAK,CAAC,CAoCzD"}
1
+ {"version":3,"file":"createComponent.d.ts","sourceRoot":"","sources":["../../src/plugin/createComponent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAK7C,OAAO,KAAK,EACV,aAAa,IAAI,mBAAmB,EACpC,cAAc,IAAI,oBAAoB,EACtC,gBAAgB,IAAI,sBAAsB,EAC1C,mBAAmB,IAAI,yBAAyB,EAChD,eAAe,IAAI,qBAAqB,EACzC,MAAM,+BAA+B,CAAC;AAIvC;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,mBAAmB,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;AAEnE,MAAM,MAAM,cAAc,CACxB,MAAM,EACN,oBAAoB,GAAG,mBAAmB,IACxC,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,EAAE,WAAW,CAAC,CAAC;AAEpE,MAAM,MAAM,gBAAgB,CAC1B,oBAAoB,GAAG,mBAAmB,EAC1C,YAAY,SAAS,OAAO,GAAG,OAAO,IACpC,sBAAsB,CAAC,oBAAoB,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;AAE5E,MAAM,MAAM,mBAAmB,CAAC,oBAAoB,GAAG,mBAAmB,IACxE,yBAAyB,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;AAE/D,MAAM,MAAM,eAAe,CACzB,oBAAoB,GAAG,mBAAmB,EAC1C,SAAS,SACP,mBAAmB,CAAC,oBAAoB,CAAC,GAAG,mBAAmB,CAAC,oBAAoB,CAAC,EACvF,KAAK,SAAS,MAAM,GAAG,MAAM,IAC3B,qBAAqB,CAAC,oBAAoB,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AAIlE,wBAAgB,aAAa,CAC3B,YAAY,SAAS,OAAO,EAC5B,oBAAoB,GAAG,mBAAmB,EAE1C,OAAO,EAAE,gBAAgB,CAAC,oBAAoB,EAAE,YAAY,CAAC,GAC5D,gBAAgB,CAAC,oBAAoB,EAAE,YAAY,CAAC,CAEtD;AAED,wBAAgB,eAAe,CAC7B,oBAAoB,GAAG,mBAAmB,EAC1C,SAAS,SACP,mBAAmB,CAAC,oBAAoB,CAAC,GAAG,mBAAmB,CAAC,oBAAoB,CAAC,EACvF,KAAK,SAAS,MAAM,GAAG,MAAM,EAE7B,SAAS,EAAE,eAAe,CAAC,oBAAoB,EAAE,SAAS,EAAE,KAAK,CAAC,GACjE,eAAe,CAAC,oBAAoB,EAAE,SAAS,EAAE,KAAK,CAAC,CAEzD"}
@@ -1,4 +1,4 @@
1
- import type { ThemeConfig } from '../styles';
1
+ import { type ThemeConfig } from '../styles';
2
2
  import type { DocumentGeneratorBuilder } from './types';
3
3
  /**
4
4
  * Options for creating a document generator
@@ -6,6 +6,8 @@ import type { DocumentGeneratorBuilder } from './types';
6
6
  export interface DocumentGeneratorOptions {
7
7
  /** Theme configuration */
8
8
  theme: ThemeConfig;
9
+ /** Custom themes keyed by name, resolved per-document via document.props.theme */
10
+ customThemes?: Record<string, ThemeConfig>;
9
11
  /** Enable caching for better performance */
10
12
  enableCache?: boolean;
11
13
  /** Enable debug logging */
@@ -1 +1 @@
1
- {"version":3,"file":"createDocumentGenerator.d.ts","sourceRoot":"","sources":["../../src/plugin/createDocumentGenerator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,KAAK,EAEV,wBAAwB,EAKzB,MAAM,SAAS,CAAC;AAgBjB;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,0BAA0B;IAC1B,KAAK,EAAE,WAAW,CAAC;IACnB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAoZD;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,wBAAwB,CAAC,SAAS,EAAE,CAAC,CAUvC"}
1
+ {"version":3,"file":"createDocumentGenerator.d.ts","sourceRoot":"","sources":["../../src/plugin/createDocumentGenerator.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,WAAW,EAAwB,MAAM,WAAW,CAAC;AAEnE,OAAO,KAAK,EAEV,wBAAwB,EAKzB,MAAM,SAAS,CAAC;AAcjB;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,0BAA0B;IAC1B,KAAK,EAAE,WAAW,CAAC;IACnB,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3C,4CAA4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA2bD;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,wBAAwB,CAAC,SAAS,EAAE,CAAC,CAWvC"}
@@ -678,7 +678,7 @@ function loadThemesFromJson() {
678
678
  _themesCache = themes2;
679
679
  return themes2;
680
680
  }
681
- var _themesCache, themes, getTheme, minimalTheme, corporateTheme, modernTheme;
681
+ var _themesCache, themes, getTheme, getThemeWithFallback, minimalTheme, corporateTheme, modernTheme;
682
682
  var init_themes = __esm({
683
683
  "src/templates/themes/index.ts"() {
684
684
  "use strict";
@@ -691,6 +691,15 @@ var init_themes = __esm({
691
691
  getTheme = (themeName) => {
692
692
  return themes[themeName];
693
693
  };
694
+ getThemeWithFallback = (themeName, fallbackTheme = "minimal") => {
695
+ const theme = getTheme(themeName) || getTheme(fallbackTheme);
696
+ if (!theme) {
697
+ throw new Error(
698
+ `Failed to load theme: ${themeName}. Fallback theme '${fallbackTheme}' also not found.`
699
+ );
700
+ }
701
+ return theme;
702
+ };
694
703
  minimalTheme = themes["minimal"];
695
704
  corporateTheme = themes["corporate"];
696
705
  modernTheme = themes["modern"];
@@ -2033,62 +2042,29 @@ var init_numberingConfig = __esm({
2033
2042
  import { Packer as Packer2 } from "docx";
2034
2043
 
2035
2044
  // src/plugin/createDocumentGenerator.ts
2045
+ init_styles();
2036
2046
  import { Packer } from "docx";
2037
2047
 
2038
2048
  // src/plugin/version-resolver.ts
2039
- import { latestVersion } from "@json-to-office/shared-docx";
2040
- function resolveComponentVersion(componentName, versions, requestedVersion) {
2041
- const versionKeys = Object.keys(versions);
2042
- if (requestedVersion) {
2043
- const entry = versions[requestedVersion];
2044
- if (!entry) {
2045
- throw new Error(
2046
- `Component "${componentName}" does not have version "${requestedVersion}". Available versions: ${versionKeys.join(", ")}`
2047
- );
2048
- }
2049
- return entry;
2050
- }
2051
- const latest = latestVersion(versionKeys);
2052
- return versions[latest];
2053
- }
2049
+ import { resolveComponentVersion } from "@json-to-office/shared/plugin";
2054
2050
 
2055
2051
  // src/plugin/validation.ts
2056
2052
  import {
2057
2053
  validateCustomComponentProps,
2054
+ ComponentValidationError
2055
+ } from "@json-to-office/shared/plugin";
2056
+ import {
2058
2057
  validateDocument as validateDocumentUnified
2059
2058
  } from "@json-to-office/shared-docx/validation/unified";
2060
- var DuplicateComponentError = class _DuplicateComponentError extends Error {
2061
- componentName;
2062
- code = "DUPLICATE_COMPONENT";
2063
- constructor(componentName) {
2064
- super(
2065
- `Cannot register component "${componentName}": a component with this name is already registered. Component names must be unique within a document generator.`
2066
- );
2067
- this.name = "DuplicateComponentError";
2068
- this.componentName = componentName;
2069
- if (Error.captureStackTrace) {
2070
- Error.captureStackTrace(this, _DuplicateComponentError);
2071
- }
2072
- }
2073
- };
2074
- var ComponentValidationError = class extends Error {
2075
- errors;
2076
- props;
2077
- constructor(errors, props) {
2078
- const propsStr = props !== void 0 ? `
2079
- Props: ${JSON.stringify(props, null, 2)}` : "";
2080
- const message = `Document validation failed:
2081
- ${errors.map((e) => ` ${e.path}: ${e.message}`).join("\n")}${propsStr}`;
2082
- super(message);
2083
- this.name = "ComponentValidationError";
2084
- this.errors = errors;
2085
- this.props = props;
2086
- }
2087
- };
2088
- function validateComponentProps(schema, props) {
2059
+ import {
2060
+ DuplicateComponentError,
2061
+ ComponentValidationError as ComponentValidationError2
2062
+ } from "@json-to-office/shared/plugin";
2063
+ function validateComponentProps(schema, props, componentName) {
2089
2064
  return validateCustomComponentProps(schema.propsSchema, props, {
2090
2065
  clean: true,
2091
- applyDefaults: true
2066
+ applyDefaults: true,
2067
+ componentName
2092
2068
  });
2093
2069
  }
2094
2070
  function validateDocument(document, customComponents) {
@@ -2115,7 +2091,8 @@ function validateDocument(document, customComponents) {
2115
2091
  );
2116
2092
  const validation = validateComponentProps(
2117
2093
  versionEntry,
2118
- componentData.props
2094
+ componentData.props,
2095
+ customComponent.name
2119
2096
  );
2120
2097
  if (!validation.valid && validation.errors) {
2121
2098
  const indexedErrors = validation.errors.map(
@@ -2150,7 +2127,7 @@ var cleanComponentProps = getValidatedProps;
2150
2127
 
2151
2128
  // src/plugin/schema.ts
2152
2129
  import { Type } from "@sinclair/typebox";
2153
- import { latestVersion as latestVersion2 } from "@json-to-office/shared-docx";
2130
+ import { latestVersion } from "@json-to-office/shared-docx";
2154
2131
  import {
2155
2132
  ReportPropsSchema,
2156
2133
  SectionPropsSchema,
@@ -6185,42 +6162,15 @@ async function renderHighchartsComponent(component, theme, _themeName) {
6185
6162
  import { Type as Type2 } from "@sinclair/typebox";
6186
6163
 
6187
6164
  // src/plugin/createComponent.ts
6188
- import { isValidSemver } from "@json-to-office/shared";
6165
+ import {
6166
+ createVersion as sharedCreateVersion,
6167
+ createComponent as sharedCreateComponent
6168
+ } from "@json-to-office/shared/plugin";
6189
6169
  function createVersion(version) {
6190
- return version;
6170
+ return sharedCreateVersion(version);
6191
6171
  }
6192
6172
  function createComponent(component) {
6193
- if (!component.name) {
6194
- throw new Error("Component name is required");
6195
- }
6196
- if (!component.versions || typeof component.versions !== "object") {
6197
- throw new Error(`Component "${component.name}" requires a versions map`);
6198
- }
6199
- const versionKeys = Object.keys(component.versions);
6200
- if (versionKeys.length === 0) {
6201
- throw new Error(
6202
- `Component "${component.name}" must have at least one version`
6203
- );
6204
- }
6205
- for (const key of versionKeys) {
6206
- if (!isValidSemver(key)) {
6207
- throw new Error(
6208
- `Component "${component.name}": invalid semver key "${key}". Expected format: major.minor.patch`
6209
- );
6210
- }
6211
- const entry = component.versions[key];
6212
- if (!entry.propsSchema) {
6213
- throw new Error(
6214
- `Component "${component.name}" version "${key}" requires a propsSchema`
6215
- );
6216
- }
6217
- if (!entry.render || typeof entry.render !== "function") {
6218
- throw new Error(
6219
- `Component "${component.name}" version "${key}" requires a render function`
6220
- );
6221
- }
6222
- }
6223
- return component;
6173
+ return sharedCreateComponent(component);
6224
6174
  }
6225
6175
 
6226
6176
  // src/components/text-space-after.ts
@@ -6694,45 +6644,29 @@ function normalizeDocument(document) {
6694
6644
  return [normalized];
6695
6645
  }
6696
6646
 
6697
- // src/styles/theme-resolver.ts
6698
- init_themes();
6699
- function resolveTheme2(theme) {
6700
- if (typeof theme === "string") {
6701
- const resolvedTheme = getTheme(theme);
6702
- if (resolvedTheme) {
6703
- return resolvedTheme;
6704
- }
6705
- return getTheme("minimal");
6706
- }
6707
- if (theme) {
6708
- return theme;
6709
- }
6710
- return getTheme("minimal");
6711
- }
6712
-
6713
- // src/styles/theme-validator.ts
6714
- import { validateTheme as validateThemeUnified } from "@json-to-office/shared-docx/validation/unified";
6715
- function validateTheme(theme) {
6716
- if (!theme) {
6717
- return void 0;
6718
- }
6719
- if (typeof theme === "string") {
6720
- return theme;
6721
- }
6722
- const result = validateThemeUnified(theme);
6723
- if (!result.valid) {
6724
- const errorSummary = result.errors?.map((e) => e.message).join(", ") || "Invalid theme";
6725
- throw new Error(`Invalid theme: ${errorSummary}`);
6726
- }
6727
- return result.data;
6728
- }
6729
-
6730
6647
  // src/plugin/createDocumentGenerator.ts
6731
6648
  function createBuilderImpl(state) {
6732
- const validatedTheme = validateTheme(state.theme);
6733
- const fullTheme = resolveTheme2(validatedTheme);
6734
6649
  const componentMap = new Map(state.components.map((c) => [c.name, c]));
6735
- async function processDocumentComponents(components, warningsCollector) {
6650
+ function resolveDocumentTheme(themeName) {
6651
+ if (state.customThemes) {
6652
+ if (state.customThemes[themeName]) {
6653
+ return state.customThemes[themeName];
6654
+ }
6655
+ const key = Object.keys(state.customThemes).find(
6656
+ (k) => k.toLowerCase() === themeName.toLowerCase()
6657
+ );
6658
+ if (key) {
6659
+ return state.customThemes[key];
6660
+ }
6661
+ }
6662
+ return getThemeWithFallback(themeName);
6663
+ }
6664
+ async function processDocumentComponents(components, warningsCollector, resolvedTheme, depth = 0) {
6665
+ if (depth > 20) {
6666
+ throw new Error(
6667
+ "Maximum component nesting depth exceeded (20). Check for circular component references."
6668
+ );
6669
+ }
6736
6670
  const processedComponents = [];
6737
6671
  for (const componentData of components) {
6738
6672
  const componentName = componentData?.name;
@@ -6762,7 +6696,9 @@ function createBuilderImpl(state) {
6762
6696
  if (componentWithName.children && Array.isArray(componentWithName.children)) {
6763
6697
  nestedChildren = await processDocumentComponents(
6764
6698
  componentWithName.children,
6765
- warningsCollector
6699
+ warningsCollector,
6700
+ resolvedTheme,
6701
+ depth + 1
6766
6702
  );
6767
6703
  }
6768
6704
  const versionLabel = componentWithName.version ? `${customComponent.name}@${componentWithName.version}` : customComponent.name;
@@ -6776,14 +6712,16 @@ function createBuilderImpl(state) {
6776
6712
  };
6777
6713
  const result = await versionEntry.render({
6778
6714
  props: cleanedProps,
6779
- theme: fullTheme,
6715
+ theme: resolvedTheme,
6780
6716
  addWarning,
6781
6717
  children: nestedChildren
6782
6718
  });
6783
6719
  const resultComponents = Array.isArray(result) ? result : [result];
6784
6720
  const processedResult = await processDocumentComponents(
6785
6721
  resultComponents,
6786
- warningsCollector
6722
+ warningsCollector,
6723
+ resolvedTheme,
6724
+ depth + 1
6787
6725
  );
6788
6726
  processedComponents.push(...processedResult);
6789
6727
  if (state.debug) {
@@ -6793,7 +6731,7 @@ function createBuilderImpl(state) {
6793
6731
  );
6794
6732
  }
6795
6733
  } catch (error) {
6796
- if (error instanceof ComponentValidationError) {
6734
+ if (error instanceof ComponentValidationError2) {
6797
6735
  throw error;
6798
6736
  }
6799
6737
  throw new Error(
@@ -6804,7 +6742,9 @@ function createBuilderImpl(state) {
6804
6742
  if ("children" in componentData && Array.isArray(componentData.children)) {
6805
6743
  const processedNested = await processDocumentComponents(
6806
6744
  componentData.children,
6807
- warningsCollector
6745
+ warningsCollector,
6746
+ resolvedTheme,
6747
+ depth + 1
6808
6748
  );
6809
6749
  processedComponents.push({
6810
6750
  ...componentData,
@@ -6818,18 +6758,19 @@ function createBuilderImpl(state) {
6818
6758
  return processedComponents;
6819
6759
  }
6820
6760
  function addComponent(component) {
6821
- if (state.componentNames.has(component.name)) {
6822
- throw new DuplicateComponentError(component.name);
6823
- }
6824
6761
  if (!component.name) {
6825
6762
  throw new Error("Component name is required");
6826
6763
  }
6764
+ if (state.componentNames.has(component.name)) {
6765
+ throw new DuplicateComponentError(component.name);
6766
+ }
6827
6767
  const newComponentNames = new Set(state.componentNames);
6828
6768
  newComponentNames.add(component.name);
6829
6769
  const newState = {
6830
6770
  components: [...state.components, component],
6831
6771
  componentNames: newComponentNames,
6832
6772
  theme: state.theme,
6773
+ customThemes: state.customThemes,
6833
6774
  debug: state.debug,
6834
6775
  enableCache: state.enableCache
6835
6776
  };
@@ -6844,10 +6785,13 @@ function createBuilderImpl(state) {
6844
6785
  internalDocument,
6845
6786
  state.components
6846
6787
  );
6788
+ const themeName = internalDocument.props.theme || "minimal";
6789
+ const docTheme = resolveDocumentTheme(themeName);
6847
6790
  const warnings = [];
6848
6791
  const processedComponents = await processDocumentComponents(
6849
6792
  internalDocument.children || [],
6850
- warnings
6793
+ warnings,
6794
+ docTheme
6851
6795
  );
6852
6796
  const processedDocument = {
6853
6797
  ...internalDocument,
@@ -6856,10 +6800,10 @@ function createBuilderImpl(state) {
6856
6800
  const [finalReportComponent] = normalizeDocument(processedDocument);
6857
6801
  const structure = await processDocument(
6858
6802
  finalReportComponent,
6859
- fullTheme,
6860
- "custom"
6803
+ docTheme,
6804
+ themeName
6861
6805
  );
6862
- const layout = applyLayout(structure.sections, fullTheme, "custom");
6806
+ const layout = applyLayout(structure.sections, docTheme, themeName);
6863
6807
  const generatedDocument = await renderDocument(structure, layout);
6864
6808
  return {
6865
6809
  document: generatedDocument,
@@ -6895,7 +6839,7 @@ function createBuilderImpl(state) {
6895
6839
  );
6896
6840
  return { valid: true };
6897
6841
  } catch (error) {
6898
- if (error instanceof ComponentValidationError) {
6842
+ if (error instanceof ComponentValidationError2) {
6899
6843
  return {
6900
6844
  valid: false,
6901
6845
  errors: error.errors.map((e) => ({
@@ -6935,10 +6879,13 @@ function createBuilderImpl(state) {
6935
6879
  internalDocument,
6936
6880
  state.components
6937
6881
  );
6882
+ const themeName = internalDocument.props.theme || "minimal";
6883
+ const docTheme = resolveDocumentTheme(themeName);
6938
6884
  const warnings = [];
6939
6885
  const processedComponents = await processDocumentComponents(
6940
6886
  internalDocument.children || [],
6941
- warnings
6887
+ warnings,
6888
+ docTheme
6942
6889
  );
6943
6890
  const processedDocument = {
6944
6891
  ...internalDocument,
@@ -6970,6 +6917,7 @@ function createDocumentGenerator(options) {
6970
6917
  components: [],
6971
6918
  componentNames: /* @__PURE__ */ new Set(),
6972
6919
  theme: options.theme,
6920
+ customThemes: options.customThemes,
6973
6921
  debug: options.debug ?? false,
6974
6922
  enableCache: options.enableCache ?? false
6975
6923
  };