@json-to-office/core-docx 0.16.0 → 0.17.1

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.
@@ -12,8 +12,19 @@ import type { GenerationWarning } from '@json-to-office/shared';
12
12
  export interface JsonGenerationOptions {
13
13
  outputPath?: string;
14
14
  validation?: {
15
- strict?: boolean;
15
+ /**
16
+ * Validate the document against the schema before building, throwing on
17
+ * errors. Defaults to `true` — invalid props are surfaced rather than
18
+ * silently dropped into a corrupt/incomplete document.
19
+ */
20
+ enabled?: boolean;
21
+ /**
22
+ * When true, unknown/extra properties are stripped instead of rejected by
23
+ * strict (additionalProperties:false) schemas. Escape hatch for migration.
24
+ */
16
25
  allowUnknownFields?: boolean;
26
+ /** @deprecated No longer consulted; retained for back-compat. */
27
+ strict?: boolean;
17
28
  };
18
29
  customThemes?: {
19
30
  [key: string]: ThemeConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/core/generator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/core/generator.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -7287,9 +7287,32 @@ async function generateDocumentWithCustomThemes(documentIn, customThemes, servic
7287
7287
  return renderedDocument;
7288
7288
  }
7289
7289
  async function generateDocumentFromJson(jsonConfig, options) {
7290
+ const validation = options?.validation;
7291
+ if (validation?.enabled !== false) {
7292
+ const result = validateJsonComponent(jsonConfig, {
7293
+ allowUnknownFields: validation?.allowUnknownFields
7294
+ });
7295
+ if (!result.valid) {
7296
+ throw new JsonValidationError(
7297
+ "Document validation failed",
7298
+ result.errors
7299
+ );
7300
+ }
7301
+ }
7290
7302
  let componentToConvert;
7291
7303
  if (typeof jsonConfig === "string") {
7292
- const parsed = parseJsonComponent(jsonConfig);
7304
+ let parsed;
7305
+ try {
7306
+ parsed = JSON.parse(jsonConfig);
7307
+ } catch (error) {
7308
+ throw new JsonParsingError("Invalid JSON syntax", [
7309
+ {
7310
+ path: "",
7311
+ message: error instanceof Error ? error.message : "Invalid JSON",
7312
+ code: "JSON_PARSE_ERROR"
7313
+ }
7314
+ ]);
7315
+ }
7293
7316
  if (!isReportComponent(parsed)) {
7294
7317
  throw new Error("Parsed JSON must be a docx component");
7295
7318
  }
@@ -7690,22 +7713,20 @@ import {
7690
7713
  ComponentValidationError as ComponentValidationError2,
7691
7714
  UnknownPreservedComponentError
7692
7715
  } from "@json-to-office/shared/plugin";
7693
- function validateComponentProps(schema, props, componentName) {
7716
+ function validateComponentProps(schema, props, componentName, opts) {
7694
7717
  return validateCustomComponentProps(schema.propsSchema, props, {
7695
- clean: true,
7696
- applyDefaults: true,
7718
+ clean: opts?.clean ?? true,
7719
+ applyDefaults: opts?.applyDefaults ?? true,
7697
7720
  componentName
7698
7721
  });
7699
7722
  }
7700
- function validateDocument(document, customComponents) {
7723
+ function validateDocument(document, customComponents, options) {
7724
+ const knownCustomNames = new Set(customComponents.map((c) => c.name));
7701
7725
  const documentResult = validateDocumentUnified(document, {
7702
- clean: true,
7703
- applyDefaults: true
7726
+ knownCustomNames,
7727
+ allowUnknownFields: options?.allowUnknownFields
7704
7728
  });
7705
- if (!documentResult.valid) {
7706
- return { ...documentResult, success: false };
7707
- }
7708
- const errors = [];
7729
+ const errors = [...documentResult.errors || []];
7709
7730
  function validateComponents(components, pathPrefix = "children") {
7710
7731
  components.forEach((componentData, index) => {
7711
7732
  const customComponent = customComponents.find(
@@ -7722,7 +7743,9 @@ function validateDocument(document, customComponents) {
7722
7743
  const validation = validateComponentProps(
7723
7744
  versionEntry,
7724
7745
  componentData.props,
7725
- customComponent.name
7746
+ customComponent.name,
7747
+ // Reject unknown custom props unless the caller allows them.
7748
+ { clean: options?.allowUnknownFields === true }
7726
7749
  );
7727
7750
  if (!validation.valid && validation.errors) {
7728
7751
  const indexedErrors = validation.errors.map(
@@ -7933,7 +7956,7 @@ function createBuilderImpl(state) {
7933
7956
  }
7934
7957
  return getThemeWithFallback(themeName);
7935
7958
  }
7936
- async function processDocumentComponents(components, preserveSet, warningsCollector, resolvedTheme, depth = 0) {
7959
+ async function processDocumentComponents(components, preserveSet, warningsCollector, resolvedTheme, validateEmitted, depth = 0) {
7937
7960
  if (depth > 20) {
7938
7961
  throw new Error(
7939
7962
  "Maximum component nesting depth exceeded (20). Check for circular component references."
@@ -7973,6 +7996,7 @@ function createBuilderImpl(state) {
7973
7996
  preserveSet,
7974
7997
  warningsCollector,
7975
7998
  resolvedTheme,
7999
+ validateEmitted,
7976
8000
  depth + 1
7977
8001
  );
7978
8002
  nestedChildren = nested.standard;
@@ -7993,11 +8017,15 @@ function createBuilderImpl(state) {
7993
8017
  children: nestedChildren
7994
8018
  });
7995
8019
  const resultComponents = Array.isArray(result) ? result : [result];
8020
+ if (validateEmitted) {
8021
+ validateEmitted(resultComponents, versionLabel);
8022
+ }
7996
8023
  const processedResult = await processDocumentComponents(
7997
8024
  resultComponents,
7998
8025
  preserveSet,
7999
8026
  warningsCollector,
8000
8027
  resolvedTheme,
8028
+ validateEmitted,
8001
8029
  depth + 1
8002
8030
  );
8003
8031
  standardOut.push(...processedResult.standard);
@@ -8027,6 +8055,7 @@ function createBuilderImpl(state) {
8027
8055
  preserveSet,
8028
8056
  warningsCollector,
8029
8057
  resolvedTheme,
8058
+ validateEmitted,
8030
8059
  depth + 1
8031
8060
  );
8032
8061
  standardOut.push({
@@ -8087,10 +8116,42 @@ function createBuilderImpl(state) {
8087
8116
  try {
8088
8117
  const preserveSet = resolvePreserveSet(options);
8089
8118
  const internalDocument = document;
8090
- validateDocument(
8091
- internalDocument,
8092
- state.components
8093
- );
8119
+ const vOpts = {
8120
+ ...state.validation,
8121
+ ...options?.validation
8122
+ };
8123
+ if (vOpts.enabled !== false) {
8124
+ const result = validateDocument(
8125
+ internalDocument,
8126
+ state.components,
8127
+ { allowUnknownFields: vOpts.allowUnknownFields }
8128
+ );
8129
+ if (!result.valid) {
8130
+ throw new ComponentValidationError2(
8131
+ (result.errors ?? []).map((e) => ({
8132
+ path: e.path ?? "",
8133
+ message: e.message
8134
+ })),
8135
+ internalDocument
8136
+ );
8137
+ }
8138
+ }
8139
+ const validateEmitted = vOpts.enabled === false ? void 0 : (emitted, componentLabel) => {
8140
+ const result = validateDocument(
8141
+ { ...internalDocument, children: emitted },
8142
+ state.components,
8143
+ { allowUnknownFields: vOpts.allowUnknownFields }
8144
+ );
8145
+ if (!result.valid) {
8146
+ throw new ComponentValidationError2(
8147
+ (result.errors ?? []).map((e) => ({
8148
+ path: e.path ?? "",
8149
+ message: `custom component '${componentLabel}' emitted invalid output \u2014 ${e.message}`
8150
+ })),
8151
+ emitted
8152
+ );
8153
+ }
8154
+ };
8094
8155
  const baseThemeName = internalDocument.props.theme || "minimal";
8095
8156
  const docTheme = resolveDocumentTheme(baseThemeName);
8096
8157
  const warnings = [];
@@ -8113,7 +8174,8 @@ function createBuilderImpl(state) {
8113
8174
  mode.doc.children || [],
8114
8175
  preserveSet,
8115
8176
  warnings,
8116
- modedTheme
8177
+ modedTheme,
8178
+ validateEmitted
8117
8179
  );
8118
8180
  const processedDocument = {
8119
8181
  ...mode.doc,
@@ -8184,21 +8246,21 @@ function createBuilderImpl(state) {
8184
8246
  function validate(document) {
8185
8247
  try {
8186
8248
  const internalDocument = document;
8187
- validateDocument(
8249
+ const result = validateDocument(
8188
8250
  internalDocument,
8189
8251
  state.components
8190
8252
  );
8191
- return { valid: true };
8192
- } catch (error) {
8193
- if (error instanceof ComponentValidationError2) {
8194
- return {
8195
- valid: false,
8196
- errors: error.errors.map((e) => ({
8197
- path: e.path,
8198
- message: e.message
8199
- }))
8200
- };
8253
+ if (result.valid) {
8254
+ return { valid: true };
8201
8255
  }
8256
+ return {
8257
+ valid: false,
8258
+ errors: (result.errors ?? []).map((e) => ({
8259
+ path: e.path ?? "",
8260
+ message: e.message
8261
+ }))
8262
+ };
8263
+ } catch (error) {
8202
8264
  return {
8203
8265
  valid: false,
8204
8266
  errors: [
@@ -8248,7 +8310,8 @@ function createDocumentGenerator(options) {
8248
8310
  debug: options.debug ?? false,
8249
8311
  enableCache: options.enableCache ?? false,
8250
8312
  services: options.services,
8251
- fonts: options.fonts
8313
+ fonts: options.fonts,
8314
+ validation: options.validation
8252
8315
  };
8253
8316
  return createBuilderImpl(initialState);
8254
8317
  }