@json-to-office/shared-pptx 0.35.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  PPTX_JSON_SCHEMA_URLS,
3
3
  PptxJsonComponentDefinitionSchema
4
- } from "./chunk-AKSSIK5V.js";
4
+ } from "./chunk-UCBH6X6Z.js";
5
5
  import "./chunk-J4OT5Y5B.js";
6
6
  import {
7
7
  PptxComponentDefinitionSchema,
8
8
  PptxSlideContentSchema,
9
9
  PptxStandardComponentDefinitionSchema
10
- } from "./chunk-C6UX273H.js";
10
+ } from "./chunk-DFXFF2IE.js";
11
11
  import {
12
12
  PPTX_BASE_SCHEMA_METADATA,
13
13
  PPTX_COMPONENT_METADATA
14
14
  } from "./chunk-RV7W3UXU.js";
15
15
  import {
16
16
  generateUnifiedDocumentSchema
17
- } from "./chunk-L7BCW5HU.js";
17
+ } from "./chunk-ETHMRQYH.js";
18
18
  import {
19
19
  PPTX_STANDARD_COMPONENTS_REGISTRY,
20
20
  PositionSchema,
@@ -31,8 +31,14 @@ import {
31
31
  getPptxContainerComponents,
32
32
  getPptxContentComponents,
33
33
  getPptxStandardComponent,
34
- isPptxStandardComponent
35
- } from "./chunk-P3YA33LS.js";
34
+ isPptxStandardComponent,
35
+ pptxComponentRequiresProps
36
+ } from "./chunk-XDLNPMWK.js";
37
+ import {
38
+ DEFAULT_PPTX_RENDERER_ID,
39
+ PPTX_RENDERER_IDS,
40
+ collectPptxRendererErrors
41
+ } from "./chunk-2YEV3CJF.js";
36
42
  import {
37
43
  ColorValueSchema,
38
44
  SEMANTIC_COLOR_ALIASES,
@@ -162,6 +168,7 @@ var CUSTOM_COMPONENT_OBJECT_KEYS = /* @__PURE__ */ new Set([
162
168
  "version"
163
169
  ]);
164
170
  var ROOT_OBJECT_KEYS = /* @__PURE__ */ new Set([...COMPONENT_OBJECT_KEYS, "$schema"]);
171
+ ROOT_OBJECT_KEYS.add("renderer");
165
172
  function deepValidatePresentation(data, opts = {}) {
166
173
  const allErrors = [];
167
174
  if (!data || typeof data !== "object") {
@@ -195,12 +202,15 @@ function deepValidatePresentation(data, opts = {}) {
195
202
  });
196
203
  }
197
204
  }
205
+ const rootDef = getPptxStandardComponent(data.name);
198
206
  if (!("props" in data)) {
199
- allErrors.push({
200
- path: "/props",
201
- message: 'Missing required field "props"',
202
- code: "required_property"
203
- });
207
+ if (!rootDef || pptxComponentRequiresProps(rootDef)) {
208
+ allErrors.push({
209
+ path: "/props",
210
+ message: 'Missing required field "props"',
211
+ code: "required_property"
212
+ });
213
+ }
204
214
  } else if (ROOT_COMPONENT_NAMES.has(data.name)) {
205
215
  allErrors.push(
206
216
  ...validateComponentProps(data.name, data.props, "/props", opts)
@@ -253,18 +263,34 @@ function walkComponentTree(node, path, opts, errors) {
253
263
  }
254
264
  }
255
265
  if (isCustomComponent) {
266
+ if (!("props" in child)) {
267
+ errors.push({
268
+ path: `${childPath}/props`,
269
+ message: `Component "${child.name}" is missing required field "props"`,
270
+ code: "required_property",
271
+ suggestion: `Add a "props" object holding the content "${child.name}" renders.`
272
+ });
273
+ }
256
274
  walkComponentTree(child, childPath, opts, errors);
257
275
  return;
258
276
  }
277
+ const def = getPptxStandardComponent(child.name);
259
278
  const propsPath = `${childPath}/props`;
260
- if (child.props != null) {
279
+ if ("props" in child) {
261
280
  errors.push(
262
281
  ...validateComponentProps(child.name, child.props, propsPath, opts)
263
282
  );
283
+ } else if (def && pptxComponentRequiresProps(def)) {
284
+ const declared = def.propsSchema.required ?? [];
285
+ errors.push({
286
+ path: propsPath,
287
+ message: `Component "${child.name}" is missing required field "props"`,
288
+ code: "required_property",
289
+ suggestion: declared.length > 0 ? `Add "props" carrying ${declared.map((f) => `"${f}"`).join(", ")}.` : `Add a "props" object holding the content "${child.name}" renders.`
290
+ });
264
291
  } else {
265
292
  errors.push(...validateComponentProps(child.name, {}, propsPath, opts));
266
293
  }
267
- const def = getPptxStandardComponent(child.name);
268
294
  if (def && !def.hasChildren && child.children != null) {
269
295
  errors.push({
270
296
  path: `${childPath}/children`,
@@ -276,11 +302,23 @@ function walkComponentTree(node, path, opts, errors) {
276
302
  walkComponentTree(child, childPath, opts, errors);
277
303
  };
278
304
  const parentDef = getPptxStandardComponent(node.name);
305
+ const checkAllowedChild = (child, childPath) => {
306
+ if (parentDef?.allowedChildren && child && typeof child === "object" && typeof child.name === "string" && getPptxStandardComponent(child.name) && !parentDef.allowedChildren.includes(child.name)) {
307
+ const expected = parentDef.allowedChildren.map((n) => `"${n}"`).join(", ");
308
+ errors.push({
309
+ path: `${childPath}/name`,
310
+ message: `Component "${child.name}" is not allowed inside "${node.name}". Expected ${expected}`,
311
+ code: "invalid_value"
312
+ });
313
+ }
314
+ };
279
315
  if (node.name === "slide" && node.props && typeof node.props === "object") {
280
316
  const placeholders = node.props.placeholders;
281
317
  if (placeholders && typeof placeholders === "object" && !Array.isArray(placeholders)) {
282
318
  for (const [key, child] of Object.entries(placeholders)) {
283
- validateEntry(child, `${path}/props/placeholders/${key}`);
319
+ const childPath = `${path}/props/placeholders/${key}`;
320
+ checkAllowedChild(child, childPath);
321
+ validateEntry(child, childPath);
284
322
  }
285
323
  } else if (placeholders != null) {
286
324
  errors.push({
@@ -293,14 +331,7 @@ function walkComponentTree(node, path, opts, errors) {
293
331
  if (Array.isArray(node.children)) {
294
332
  node.children.forEach((child, i) => {
295
333
  const childPath = `${path}/children/${i}`;
296
- if (parentDef?.allowedChildren && child && typeof child === "object" && typeof child.name === "string" && getPptxStandardComponent(child.name) && !parentDef.allowedChildren.includes(child.name)) {
297
- const expected = parentDef.allowedChildren.map((n) => `"${n}"`).join(", ");
298
- errors.push({
299
- path: `${childPath}/name`,
300
- message: `Component "${child.name}" is not allowed inside "${node.name}". Expected ${expected}`,
301
- code: "invalid_value"
302
- });
303
- }
334
+ checkAllowedChild(child, childPath);
304
335
  validateEntry(child, childPath);
305
336
  });
306
337
  } else if (node.children != null && path !== "") {
@@ -391,6 +422,7 @@ function validatePresentationDocument(data, opts = {}) {
391
422
  const errors = comprehensiveValidatePresentation(data, [], opts);
392
423
  errors.push(...collectImageSourceConflicts(data));
393
424
  errors.push(...collectTextContentConflicts(data));
425
+ errors.push(...collectPptxRendererErrors(data));
394
426
  const valid = errors.length === 0;
395
427
  return {
396
428
  valid,
@@ -456,6 +488,7 @@ export {
456
488
  ChartComponentDefaultsSchema,
457
489
  ColorValueSchema,
458
490
  DEFAULT_ERROR_CONFIG,
491
+ DEFAULT_PPTX_RENDERER_ID,
459
492
  GradientFillSchema,
460
493
  GradientStopSchema,
461
494
  HighchartsComponentDefaultsSchema,
@@ -464,6 +497,7 @@ export {
464
497
  PPTX_BASE_SCHEMA_METADATA,
465
498
  PPTX_COMPONENT_METADATA,
466
499
  PPTX_JSON_SCHEMA_URLS,
500
+ PPTX_RENDERER_IDS,
467
501
  PPTX_SHARED_VERSION,
468
502
  PPTX_STANDARD_COMPONENTS_REGISTRY,
469
503
  PatternFillSchema,
@@ -497,6 +531,7 @@ export {
497
531
  TransitionSchema,
498
532
  VerticalAlignmentSchema,
499
533
  collectImageSourceConflicts,
534
+ collectPptxRendererErrors,
500
535
  collectTextContentConflicts,
501
536
  compareSemver,
502
537
  comprehensiveValidatePresentation,
@@ -519,6 +554,7 @@ export {
519
554
  isValidThemeConfig,
520
555
  latestVersion,
521
556
  parseSemver,
557
+ pptxComponentRequiresProps,
522
558
  presentImageSources,
523
559
  transformValueError,
524
560
  transformValueErrors3 as transformValueErrors,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/validation/image-source-conflicts.ts","../src/validation/text-content-conflicts.ts","../src/validation/unified/index.ts","../src/validation/unified/deep-validator.ts","../src/index.ts"],"sourcesContent":["/**\n * Image source conflict detection (PPTX)\n *\n * Mirrors core-docx: `path`, `base64`, and `svg` are mutually exclusive on the\n * image component, but all three are optional fields on a single object schema —\n * so a multi-source payload passes the structural check and would otherwise be\n * silently resolved by runtime precedence (svg > base64 > path). This walk runs\n * unconditionally during validation and rejects such payloads. It traverses every\n * nested value, so images inside slides, grids, containers, and table cells are\n * all covered regardless of container shape.\n */\n\nimport type { ValidationError } from '@json-to-office/shared';\n\n// Image source fields that are mutually exclusive: exactly one may be set.\nconst IMAGE_SOURCE_FIELDS = ['path', 'base64', 'svg'] as const;\n\n/**\n * Names of the image source fields that carry a non-empty value on a props object.\n */\nexport function presentImageSources(props: unknown): string[] {\n if (!props || typeof props !== 'object') return [];\n const p = props as Record<string, unknown>;\n return IMAGE_SOURCE_FIELDS.filter((f) => {\n const v = p[f];\n return typeof v === 'string' && v.trim().length > 0;\n });\n}\n\n/**\n * Collect \"more than one image source\" conflicts anywhere in a presentation.\n */\nexport function collectImageSourceConflicts(data: unknown): ValidationError[] {\n const errors: ValidationError[] = [];\n\n const visit = (node: any, path: string): void => {\n if (Array.isArray(node)) {\n node.forEach((item, i) => visit(item, `${path}/${i}`));\n return;\n }\n if (!node || typeof node !== 'object') return;\n\n if (node.name === 'image') {\n const present = presentImageSources(node.props);\n if (present.length > 1) {\n errors.push({\n path: `${path}/props`,\n message: `Image component accepts only one source, but found ${present\n .map((f) => `\"${f}\"`)\n .join(', ')}. Use exactly one of \"path\", \"base64\", or \"svg\".`,\n code: 'mutually_exclusive',\n });\n }\n }\n\n for (const key of Object.keys(node)) {\n visit(node[key], `${path}/${key}`);\n }\n };\n\n visit(data, '');\n return errors;\n}\n","/**\n * Text content conflict detection (PPTX)\n *\n * `text` and `runs` are mutually exclusive on the text component, but both are\n * optional fields on a single object schema — so a payload carrying both (or\n * neither) passes the structural check and would otherwise be silently resolved\n * by runtime precedence. This walk runs unconditionally during validation and\n * rejects such payloads. It traverses every nested value, so text components\n * inside slides, placeholders, and template objects are all covered.\n *\n * Placeholder `defaults` stubs are exempt from the \"neither\" rule: they carry\n * styling defaults only, and the actual content arrives with the component\n * placed in the placeholder.\n */\n\nimport type { ValidationError } from '@json-to-office/shared';\n\n/**\n * Collect `text`/`runs` mutual-exclusivity conflicts anywhere in a presentation.\n */\nexport function collectTextContentConflicts(data: unknown): ValidationError[] {\n const errors: ValidationError[] = [];\n\n const visit = (node: any, path: string, parentKey: string): void => {\n if (Array.isArray(node)) {\n node.forEach((item, i) => visit(item, `${path}/${i}`, parentKey));\n return;\n }\n if (!node || typeof node !== 'object') return;\n\n if (node.name === 'text' && node.props && typeof node.props === 'object') {\n const hasText = typeof node.props.text === 'string';\n const hasRuns = Array.isArray(node.props.runs);\n if (hasText && hasRuns) {\n errors.push({\n path: `${path}/props`,\n message:\n 'Text component accepts either \"text\" or \"runs\", not both. Use exactly one of the two.',\n code: 'mutually_exclusive',\n });\n } else if (!hasText && !hasRuns && parentKey !== 'defaults') {\n errors.push({\n path: `${path}/props`,\n message:\n 'Text component requires content: set either \"text\" or \"runs\".',\n code: 'required_property',\n });\n }\n }\n\n for (const key of Object.keys(node)) {\n visit(node[key], `${path}/${key}`, key);\n }\n };\n\n visit(data, '', '');\n return errors;\n}\n","/**\n * Unified validation facade for PPTX.\n *\n * Mirrors the shared-docx `validate` / `validateStrict` API surface the CLI\n * consumes, so `jto pptx validate` gets real schema validation instead of the\n * historical unconditional pass.\n */\n\nimport { Value } from '@sinclair/typebox/value';\nimport type { ValidationError } from '@json-to-office/shared';\nimport { transformValueErrors } from '@json-to-office/shared';\nimport { ThemeConfigSchema } from '../../schemas/theme';\nimport { collectImageSourceConflicts } from '../image-source-conflicts';\nimport { collectTextContentConflicts } from '../text-content-conflicts';\nimport {\n comprehensiveValidatePresentation,\n type DeepValidateOptions,\n} from './deep-validator';\n\nexport {\n deepValidatePresentation,\n comprehensiveValidatePresentation,\n} from './deep-validator';\nexport type { DeepValidateOptions } from './deep-validator';\n\nexport interface PptxValidationResult {\n valid: boolean;\n errors: ValidationError[];\n warnings?: ValidationError[];\n documentType?: 'pptx';\n data?: unknown;\n}\n\nfunction parseJsonInput(jsonInput: string | object): {\n parsed?: unknown;\n error?: ValidationError;\n} {\n if (typeof jsonInput !== 'string') return { parsed: jsonInput };\n try {\n return { parsed: JSON.parse(jsonInput) };\n } catch (err: any) {\n return {\n error: {\n path: 'root',\n message: `Invalid JSON: ${err?.message ?? String(err)}`,\n code: 'json_parse_error',\n },\n };\n }\n}\n\n/**\n * Validate a presentation component tree.\n *\n * The deep walk is the source of truth: it re-implements everything the\n * recursive discriminated union checks (component names, per-component props\n * schemas, container narrowing) with precise paths, so we run it directly\n * instead of the union check whose failures collapse into a generic root\n * error. Image-source mutual exclusivity is a semantic rule the structural\n * schema cannot express, so it runs unconditionally on top.\n */\nexport function validatePresentationDocument(\n data: unknown,\n opts: DeepValidateOptions = {}\n): PptxValidationResult {\n const errors = comprehensiveValidatePresentation(data, [], opts);\n errors.push(...collectImageSourceConflicts(data));\n errors.push(...collectTextContentConflicts(data));\n const valid = errors.length === 0;\n return {\n valid,\n errors,\n documentType: 'pptx',\n data: valid ? data : undefined,\n };\n}\n\n/**\n * Validate a presentation from a JSON string or object.\n */\nexport function validateJsonPresentationDocument(\n jsonInput: string | object,\n opts: DeepValidateOptions = {}\n): PptxValidationResult {\n const { parsed, error } = parseJsonInput(jsonInput);\n if (error) return { valid: false, errors: [error], documentType: 'pptx' };\n return validatePresentationDocument(parsed, opts);\n}\n\n/**\n * Validate a PPTX theme config.\n */\nexport function validatePptxTheme(data: unknown): PptxValidationResult {\n if (Value.Check(ThemeConfigSchema, data)) {\n return { valid: true, errors: [], data };\n }\n const valueErrors = [...Value.Errors(ThemeConfigSchema, data)];\n const errors = transformValueErrors(valueErrors, { maxErrors: 100 });\n return { valid: false, errors };\n}\n\n/**\n * Validate a PPTX theme from a JSON string or object.\n */\nexport function validateJsonPptxTheme(\n jsonInput: string | object\n): PptxValidationResult {\n const { parsed, error } = parseJsonInput(jsonInput);\n if (error) return { valid: false, errors: [error] };\n return validatePptxTheme(parsed);\n}\n\n/**\n * Simple validation API — the entry point the CLI consumes.\n */\nexport const validate = {\n document: (data: unknown) => validatePresentationDocument(data),\n jsonDocument: (jsonInput: string | object) =>\n validateJsonPresentationDocument(jsonInput),\n theme: (data: unknown) => validatePptxTheme(data),\n jsonTheme: (jsonInput: string | object) => validateJsonPptxTheme(jsonInput),\n isDocument: (data: unknown) => validatePresentationDocument(data).valid,\n isTheme: (data: unknown) => validatePptxTheme(data).valid,\n};\n\n/**\n * Strict validation API. PPTX deep validation never cleans or applies\n * defaults, so this is currently an alias kept for docx API parity — the CLI\n * picks one of the two based on its --strict flag.\n */\nexport const validateStrict = {\n document: (data: unknown) => validatePresentationDocument(data),\n jsonDocument: (jsonInput: string | object) =>\n validateJsonPresentationDocument(jsonInput),\n theme: (data: unknown) => validatePptxTheme(data),\n jsonTheme: (jsonInput: string | object) => validateJsonPptxTheme(jsonInput),\n};\n","/**\n * Deep validation utilities for collecting ALL errors in nested structures.\n *\n * Mirrors the docx deep validator: the recursive discriminated union\n * (PptxComponentDefinitionSchema) short-circuits on the first mismatch and\n * collapses failures into a generic root error, so this walk visits every\n * component in the tree and validates its props against the real per-component\n * schema, producing precise, path-aware errors.\n */\n\nimport { Value } from '@sinclair/typebox/value';\nimport type { TSchema } from '@sinclair/typebox';\nimport type { ValidationError } from '@json-to-office/shared';\nimport { transformValueErrors } from '@json-to-office/shared';\nimport {\n PPTX_STANDARD_COMPONENTS_REGISTRY,\n getPptxStandardComponent,\n} from '../../schemas/component-registry';\n\n// Map of component names to their props schemas, sourced from the registry.\n// This stays in sync as new standard components are added, so the presentation\n// root ('pptx') and every standard child component are recognized here.\nconst COMPONENT_SCHEMAS: Record<string, TSchema> = Object.fromEntries(\n PPTX_STANDARD_COMPONENTS_REGISTRY.map((c) => [c.name, c.propsSchema])\n);\n\n// Root component names that may appear at the top of a presentation.\nconst ROOT_COMPONENT_NAMES = new Set(\n PPTX_STANDARD_COMPONENTS_REGISTRY.filter((c) =>\n Boolean(c.special?.hasSchemaField)\n ).map((c) => c.name)\n);\n\n// Top-level keys allowed on a component object. The recursive union enforces\n// this via additionalProperties:false; the walk re-checks it so a typo like\n// \"porps\" is reported at a precise path instead of a generic union failure.\nconst COMPONENT_OBJECT_KEYS = new Set([\n 'name',\n 'id',\n 'enabled',\n 'props',\n 'children',\n]);\nconst CUSTOM_COMPONENT_OBJECT_KEYS = new Set([\n ...COMPONENT_OBJECT_KEYS,\n 'version',\n]);\nconst ROOT_OBJECT_KEYS = new Set([...COMPONENT_OBJECT_KEYS, '$schema']);\n\n/**\n * Options that tune deep validation.\n *\n * `knownCustomNames` — names of registered plugin components. The deep\n * validator neither flags these as \"unknown component\" nor validates their\n * props here; the plugin layer validates custom props separately.\n *\n * `allowUnknownFields` — when true, unknown properties are stripped before the\n * per-component check instead of being rejected. The escape hatch for callers\n * migrating onto strict schemas.\n */\nexport interface DeepValidateOptions {\n knownCustomNames?: Set<string>;\n allowUnknownFields?: boolean;\n}\n\n/**\n * Deep validate a presentation to collect ALL errors, not just union-level errors.\n */\nexport function deepValidatePresentation(\n data: any,\n opts: DeepValidateOptions = {}\n): ValidationError[] {\n const allErrors: ValidationError[] = [];\n\n if (!data || typeof data !== 'object') {\n allErrors.push({\n path: 'root',\n message: 'Presentation must be an object',\n code: 'invalid_type',\n });\n return allErrors;\n }\n\n if (!data.name) {\n allErrors.push({\n path: '/name',\n message: 'Missing required field \"name\"',\n code: 'required_property',\n });\n } else if (!ROOT_COMPONENT_NAMES.has(data.name)) {\n const expected = [...ROOT_COMPONENT_NAMES].map((n) => `\"${n}\"`).join(', ');\n allErrors.push({\n path: '/name',\n message: `Invalid name \"${data.name}\". Expected ${expected}`,\n code: 'invalid_value',\n });\n }\n\n for (const key of Object.keys(data)) {\n if (!ROOT_OBJECT_KEYS.has(key)) {\n allErrors.push({\n path: `/${key}`,\n message: `Unknown field \"${key}\" on the root component`,\n code: 'unknown_field',\n });\n }\n }\n\n // Validate props when the key is present so explicit `null` (or any falsy\n // non-object) is checked against the component's schema instead of silently\n // passing.\n if (!('props' in data)) {\n allErrors.push({\n path: '/props',\n message: 'Missing required field \"props\"',\n code: 'required_property',\n });\n } else if (ROOT_COMPONENT_NAMES.has(data.name)) {\n allErrors.push(\n ...validateComponentProps(data.name, data.props, '/props', opts)\n );\n }\n\n // The root requires a children array (the slides); nested containers may\n // legitimately omit theirs.\n if (!data.children) {\n allErrors.push({\n path: '/children',\n message: 'Missing required field \"children\"',\n code: 'required_property',\n });\n } else if (!Array.isArray(data.children)) {\n allErrors.push({\n path: '/children',\n message: 'Field \"children\" must be an array',\n code: 'invalid_type',\n });\n }\n\n walkComponentTree(data, '', opts, allErrors);\n\n return allErrors;\n}\n\n/**\n * Recursively validate every component nested under `node`.\n *\n * Walks two kinds of child position to any depth:\n * - the `children` array — `pptx` holds slides, `slide` holds content\n * components. The registry's `allowedChildren` narrows what each container\n * accepts, and leaf components must not carry children at all; and\n * - a slide's `props.placeholders` record — added dynamically by the\n * component registry on top of the static SlidePropsSchema, so its values\n * are not covered by the slide's own props validation and this walk is\n * their only checker.\n *\n * The node's own props are NOT validated here — the caller validates the root\n * props, and every entry is validated as it is visited.\n */\nfunction walkComponentTree(\n node: any,\n path: string,\n opts: DeepValidateOptions,\n errors: ValidationError[]\n): void {\n if (!node || typeof node !== 'object') return;\n\n const validateEntry = (child: any, childPath: string): void => {\n if (!child || typeof child !== 'object' || Array.isArray(child)) {\n errors.push({\n path: childPath,\n message: 'Component must be an object',\n code: 'invalid_type',\n });\n return;\n }\n if (typeof child.name !== 'string' || child.name.length === 0) {\n errors.push({\n path: `${childPath}/name`,\n message: 'Component missing required field \"name\"',\n code: 'required_property',\n });\n return;\n }\n\n // Registered plugin props are validated version-aware by the plugin layer.\n // Their children still need walking: custom containers may hold authored\n // standard components, and those must obey the same prop/tree contract as\n // standard components elsewhere in the presentation.\n const isCustomComponent = opts.knownCustomNames?.has(child.name) ?? false;\n const allowedObjectKeys = isCustomComponent\n ? CUSTOM_COMPONENT_OBJECT_KEYS\n : COMPONENT_OBJECT_KEYS;\n\n for (const key of Object.keys(child)) {\n if (!allowedObjectKeys.has(key)) {\n errors.push({\n path: `${childPath}/${key}`,\n message: `Unknown field \"${key}\" on component \"${child.name}\"`,\n code: 'unknown_field',\n });\n }\n }\n\n if (isCustomComponent) {\n walkComponentTree(child, childPath, opts, errors);\n return;\n }\n\n // Validate props against the component's schema. When props is omitted,\n // validate an empty object so the schema decides whether props are\n // required (e.g. `slide` needs none; `text` requires text).\n const propsPath = `${childPath}/props`;\n if (child.props != null) {\n errors.push(\n ...validateComponentProps(child.name, child.props, propsPath, opts)\n );\n } else {\n errors.push(...validateComponentProps(child.name, {}, propsPath, opts));\n }\n\n const def = getPptxStandardComponent(child.name);\n if (def && !def.hasChildren && child.children != null) {\n errors.push({\n path: `${childPath}/children`,\n message: `Component \"${child.name}\" does not accept children`,\n code: 'invalid_value',\n });\n return;\n }\n\n // Recurse so arbitrarily nested containers are covered.\n walkComponentTree(child, childPath, opts, errors);\n };\n\n const parentDef = getPptxStandardComponent(node.name);\n\n // A slide's `placeholders` record maps placeholder names to full components\n // ({ \"title\": { \"name\": \"text\", ... } }). The static SlidePropsSchema does\n // not include the field (it is injected with the recursive ref at schema\n // generation time), so validateComponentProps strips it before checking the\n // slide's own props — each value is validated here instead.\n if (node.name === 'slide' && node.props && typeof node.props === 'object') {\n const placeholders = node.props.placeholders;\n if (\n placeholders &&\n typeof placeholders === 'object' &&\n !Array.isArray(placeholders)\n ) {\n for (const [key, child] of Object.entries(placeholders)) {\n validateEntry(child, `${path}/props/placeholders/${key}`);\n }\n } else if (placeholders != null) {\n errors.push({\n path: `${path}/props/placeholders`,\n message:\n 'Field \"placeholders\" must be an object mapping placeholder names to components',\n code: 'invalid_type',\n });\n }\n }\n\n if (Array.isArray(node.children)) {\n node.children.forEach((child: any, i: number) => {\n const childPath = `${path}/children/${i}`;\n // Enforce the registry's container narrowing (pptx → slide,\n // slide → content) for known components; unknown names are already\n // reported by validateComponentProps inside validateEntry.\n if (\n parentDef?.allowedChildren &&\n child &&\n typeof child === 'object' &&\n typeof child.name === 'string' &&\n getPptxStandardComponent(child.name) &&\n !parentDef.allowedChildren.includes(child.name)\n ) {\n const expected = parentDef.allowedChildren\n .map((n) => `\"${n}\"`)\n .join(', ');\n errors.push({\n path: `${childPath}/name`,\n message: `Component \"${child.name}\" is not allowed inside \"${node.name}\". Expected ${expected}`,\n code: 'invalid_value',\n });\n }\n validateEntry(child, childPath);\n });\n } else if (node.children != null && path !== '') {\n // `children` is present but not an array on a nested container. The root's\n // `children` is already checked by deepValidatePresentation (skipped here\n // via `path !== ''` so it is not reported twice).\n errors.push({\n path: `${path}/children`,\n message: 'Field \"children\" must be an array',\n code: 'invalid_type',\n });\n }\n}\n\n/**\n * Validate a component's props against its schema.\n */\nfunction validateComponentProps(\n componentName: string,\n props: any,\n basePath: string,\n opts: DeepValidateOptions = {}\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n const schema = COMPONENT_SCHEMAS[componentName];\n if (!schema) {\n // Unknown component type. `basePath` always ends in `/props`; anchor the\n // swap to the end so a nested path like `…/props/placeholders/title/props`\n // becomes `…/props/placeholders/title/name` rather than mangling an\n // earlier `/props`.\n errors.push({\n path: basePath.replace(/\\/props$/, '/name'),\n message: `Unknown component \"${componentName}\"`,\n code: 'unknown_component',\n });\n return errors;\n }\n\n // A slide's `placeholders` field is injected at schema-generation time and\n // absent from the static props schema; its values are walked separately, so\n // strip it here to avoid a false additionalProperties rejection.\n let toCheck = props;\n if (\n componentName === 'slide' &&\n props &&\n typeof props === 'object' &&\n 'placeholders' in props\n ) {\n const rest = { ...props };\n delete rest.placeholders;\n toCheck = rest;\n }\n\n // When unknown fields are explicitly allowed, strip them before checking so\n // additionalProperties:false no longer rejects — required/typed fields are\n // still enforced.\n if (opts.allowUnknownFields) {\n toCheck = Value.Clean(schema, Value.Clone(toCheck));\n }\n\n if (!Value.Check(schema, toCheck)) {\n const valueErrors = [...Value.Errors(schema, toCheck)];\n const transformedErrors = transformValueErrors(valueErrors, {\n maxErrors: 100,\n });\n\n // Adjust paths to be relative to the document root\n transformedErrors.forEach((error) => {\n const fullPath =\n error.path === 'root'\n ? basePath\n : `${basePath}${error.path.startsWith('/') ? error.path : '/' + error.path}`;\n\n errors.push({\n ...error,\n path: fullPath,\n });\n });\n }\n\n return errors;\n}\n\n/**\n * Combine deep validation with standard validation.\n *\n * Deep validation produces precise, path-aware errors. TypeBox's discriminated-\n * union check, by contrast, often collapses any failure under the root into a\n * single generic \"Invalid component configuration for 'pptx'\" message at\n * `root` — useful as a signal that something is wrong, but actionable only via\n * the deep-validator's output. We always strip that catch-all so it doesn't\n * appear alongside (or, worse, instead of) the real diagnostics.\n */\nexport function comprehensiveValidatePresentation(\n data: any,\n existingErrors: ValidationError[] = [],\n opts: DeepValidateOptions = {}\n): ValidationError[] {\n const deepErrors = deepValidatePresentation(data, opts);\n\n const filteredExisting = existingErrors.filter(\n (e) => !isGenericUnionCatchAll(e)\n );\n\n return deduplicateErrors([...filteredExisting, ...deepErrors]);\n}\n\n/**\n * Detect TypeBox's generic union/discriminator catch-all error at the document\n * root. These messages name the component type ('pptx') but give no actionable\n * detail — the deep validator emits the actual path-level errors instead.\n */\nfunction isGenericUnionCatchAll(error: ValidationError): boolean {\n const atRoot = !error.path || error.path === 'root' || error.path === '/';\n if (!atRoot) return false;\n const msg = error.message || '';\n return (\n /invalid component configurations?/i.test(msg) ||\n /invalid document structure/i.test(msg)\n );\n}\n\n/**\n * Deduplicate errors by path and message.\n */\nfunction deduplicateErrors(errors: ValidationError[]): ValidationError[] {\n const seen = new Set<string>();\n const unique: ValidationError[] = [];\n\n for (const error of errors) {\n const key = `${error.path}:${error.message}`;\n if (!seen.has(key)) {\n seen.add(key);\n unique.push(error);\n }\n }\n\n return unique;\n}\n","export const PPTX_SHARED_VERSION = '1.0.0';\n\n// Component Schemas\nexport {\n PositionSchema,\n SlideBackgroundSchema,\n TransitionSchema,\n VerticalAlignmentSchema,\n ShadowSchema,\n PresentationPropsSchema,\n SlidePropsSchema,\n TextPropsSchema,\n TextRunSchema,\n PptxImagePropsSchema,\n ShapePropsSchema,\n ShapeTypeSchema,\n GradientStopSchema,\n GradientFillSchema,\n PatternFillSchema,\n PATTERN_FILL_PRESETS,\n PptxTablePropsSchema,\n PptxHighchartsPropsSchema,\n PptxStandardComponentDefinitionSchema,\n PptxComponentDefinitionSchema,\n PptxSlideContentSchema,\n} from './schemas/components';\n\nexport type {\n Position,\n SlideBackground,\n Transition,\n VerticalAlignment,\n Shadow,\n PresentationProps,\n SlideProps,\n TextProps,\n TextRun,\n PptxImageProps,\n ShapeType,\n ShapeProps,\n TextSegment,\n GradientStop,\n GradientFill,\n PatternFill,\n PptxTableProps,\n PptxHighchartsProps,\n PptxComponentDefinition,\n PptxSlideContent,\n} from './schemas/components';\n\n// Chart (not re-exported from components barrel)\nexport { PptxChartPropsSchema } from './schemas/components/chart';\nexport type { PptxChartProps } from './schemas/components/chart';\n\n// Component Registry\nexport {\n PPTX_STANDARD_COMPONENTS_REGISTRY,\n getPptxStandardComponent,\n getAllPptxComponentNames,\n getPptxComponentsByCategory,\n getPptxContainerComponents,\n getPptxContentComponents,\n isPptxStandardComponent,\n createPptxComponentSchemaObject,\n createAllPptxComponentSchemas,\n} from './schemas/component-registry';\n\nexport type { PptxStandardComponentDefinition } from './schemas/component-registry';\n\n// Document Schema\nexport {\n PptxJsonComponentDefinitionSchema,\n PPTX_JSON_SCHEMA_URLS,\n} from './schemas/document';\n\nexport type { PptxJsonComponentDefinition } from './schemas/document';\n\n// Schema Export Metadata\nexport {\n PPTX_COMPONENT_METADATA,\n PPTX_BASE_SCHEMA_METADATA,\n} from './schemas/export';\n\n// Component Defaults\nexport {\n PptxComponentDefaultsSchema,\n TextComponentDefaultsSchema,\n ImageComponentDefaultsSchema,\n ShapeComponentDefaultsSchema,\n TableComponentDefaultsSchema,\n HighchartsComponentDefaultsSchema,\n ChartComponentDefaultsSchema,\n} from './schemas/component-defaults';\nexport type {\n PptxComponentDefaults,\n TextComponentDefaults,\n ImageComponentDefaults,\n ShapeComponentDefaults,\n TableComponentDefaults,\n HighchartsComponentDefaults,\n ChartComponentDefaults,\n} from './schemas/component-defaults';\n\n// Theme\nexport {\n ThemeConfigSchema,\n ColorValueSchema,\n SEMANTIC_COLOR_NAMES,\n SEMANTIC_COLOR_ALIASES,\n STYLE_NAMES,\n StyleNameSchema,\n TextStyleSchema,\n isValidThemeConfig,\n} from './schemas/theme';\nexport type { ThemeConfigJson, StyleName, TextStyle } from './schemas/theme';\n\n// Schema Generator\nexport { generateUnifiedDocumentSchema } from './schemas/generator';\nexport type {\n VersionedPropsEntry,\n CustomComponentInfo,\n GenerateSchemaOptions,\n} from './schemas/generator';\n\n// Types\nexport type { ReportComponent } from './types/components';\n\n// Image source conflict detection (path/base64/svg mutual exclusivity)\nexport {\n collectImageSourceConflicts,\n presentImageSources,\n} from './validation/image-source-conflicts';\n\n// Text content conflict detection (text/runs mutual exclusivity)\nexport { collectTextContentConflicts } from './validation/text-content-conflicts';\n\n// Unified validation facade (deep, path-aware validation of whole presentations\n// and themes) — the API the CLI's `pptx validate` consumes.\nexport {\n validate,\n validateStrict,\n validatePresentationDocument,\n validateJsonPresentationDocument,\n validatePptxTheme,\n validateJsonPptxTheme,\n deepValidatePresentation,\n comprehensiveValidatePresentation,\n} from './validation/unified';\nexport type {\n PptxValidationResult,\n DeepValidateOptions,\n} from './validation/unified';\n\n// Re-export shared validation utilities for convenience\nexport {\n transformValueError,\n transformValueErrors,\n DEFAULT_ERROR_CONFIG,\n createErrorConfig,\n} from '@json-to-office/shared';\n\nexport type {\n ErrorFormatterConfig,\n ValidationError,\n} from '@json-to-office/shared';\n\n// Re-export shared utilities\nexport {\n latestVersion,\n isValidSemver,\n parseSemver,\n compareSemver,\n} from '@json-to-office/shared';\nexport type { ParsedSemver } from '@json-to-office/shared';\n\n// Re-export schema utils\nexport {\n fixSchemaReferences,\n convertToJsonSchema,\n createComponentSchema,\n exportSchemaToFile,\n} from '@json-to-office/shared';\nexport type { ComponentSchemaConfig } from '@json-to-office/shared';\n"],"mappings":"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","names":["Value","transformValueErrors","Value","transformValueErrors","transformValueErrors"]}
1
+ {"version":3,"sources":["../src/validation/image-source-conflicts.ts","../src/validation/text-content-conflicts.ts","../src/validation/unified/index.ts","../src/validation/unified/deep-validator.ts","../src/index.ts"],"sourcesContent":["/**\n * Image source conflict detection (PPTX)\n *\n * Mirrors core-docx: `path`, `base64`, and `svg` are mutually exclusive on the\n * image component, but all three are optional fields on a single object schema —\n * so a multi-source payload passes the structural check and would otherwise be\n * silently resolved by runtime precedence (svg > base64 > path). This walk runs\n * unconditionally during validation and rejects such payloads. It traverses every\n * nested value, so images inside slides, grids, containers, and table cells are\n * all covered regardless of container shape.\n */\n\nimport type { ValidationError } from '@json-to-office/shared';\n\n// Image source fields that are mutually exclusive: exactly one may be set.\nconst IMAGE_SOURCE_FIELDS = ['path', 'base64', 'svg'] as const;\n\n/**\n * Names of the image source fields that carry a non-empty value on a props object.\n */\nexport function presentImageSources(props: unknown): string[] {\n if (!props || typeof props !== 'object') return [];\n const p = props as Record<string, unknown>;\n return IMAGE_SOURCE_FIELDS.filter((f) => {\n const v = p[f];\n return typeof v === 'string' && v.trim().length > 0;\n });\n}\n\n/**\n * Collect \"more than one image source\" conflicts anywhere in a presentation.\n */\nexport function collectImageSourceConflicts(data: unknown): ValidationError[] {\n const errors: ValidationError[] = [];\n\n const visit = (node: any, path: string): void => {\n if (Array.isArray(node)) {\n node.forEach((item, i) => visit(item, `${path}/${i}`));\n return;\n }\n if (!node || typeof node !== 'object') return;\n\n if (node.name === 'image') {\n const present = presentImageSources(node.props);\n if (present.length > 1) {\n errors.push({\n path: `${path}/props`,\n message: `Image component accepts only one source, but found ${present\n .map((f) => `\"${f}\"`)\n .join(', ')}. Use exactly one of \"path\", \"base64\", or \"svg\".`,\n code: 'mutually_exclusive',\n });\n }\n }\n\n for (const key of Object.keys(node)) {\n visit(node[key], `${path}/${key}`);\n }\n };\n\n visit(data, '');\n return errors;\n}\n","/**\n * Text content conflict detection (PPTX)\n *\n * `text` and `runs` are mutually exclusive on the text component, but both are\n * optional fields on a single object schema — so a payload carrying both (or\n * neither) passes the structural check and would otherwise be silently resolved\n * by runtime precedence. This walk runs unconditionally during validation and\n * rejects such payloads. It traverses every nested value, so text components\n * inside slides, placeholders, and template objects are all covered.\n *\n * Placeholder `defaults` stubs are exempt from the \"neither\" rule: they carry\n * styling defaults only, and the actual content arrives with the component\n * placed in the placeholder.\n */\n\nimport type { ValidationError } from '@json-to-office/shared';\n\n/**\n * Collect `text`/`runs` mutual-exclusivity conflicts anywhere in a presentation.\n */\nexport function collectTextContentConflicts(data: unknown): ValidationError[] {\n const errors: ValidationError[] = [];\n\n const visit = (node: any, path: string, parentKey: string): void => {\n if (Array.isArray(node)) {\n node.forEach((item, i) => visit(item, `${path}/${i}`, parentKey));\n return;\n }\n if (!node || typeof node !== 'object') return;\n\n if (node.name === 'text' && node.props && typeof node.props === 'object') {\n const hasText = typeof node.props.text === 'string';\n const hasRuns = Array.isArray(node.props.runs);\n if (hasText && hasRuns) {\n errors.push({\n path: `${path}/props`,\n message:\n 'Text component accepts either \"text\" or \"runs\", not both. Use exactly one of the two.',\n code: 'mutually_exclusive',\n });\n } else if (!hasText && !hasRuns && parentKey !== 'defaults') {\n errors.push({\n path: `${path}/props`,\n message:\n 'Text component requires content: set either \"text\" or \"runs\".',\n code: 'required_property',\n });\n }\n }\n\n for (const key of Object.keys(node)) {\n visit(node[key], `${path}/${key}`, key);\n }\n };\n\n visit(data, '', '');\n return errors;\n}\n","/**\n * Unified validation facade for PPTX.\n *\n * Mirrors the shared-docx `validate` / `validateStrict` API surface the CLI\n * consumes, so `jto pptx validate` gets real schema validation instead of the\n * historical unconditional pass.\n */\n\nimport { Value } from '@sinclair/typebox/value';\nimport type { ValidationError } from '@json-to-office/shared';\nimport { transformValueErrors } from '@json-to-office/shared';\nimport { ThemeConfigSchema } from '../../schemas/theme';\nimport { collectImageSourceConflicts } from '../image-source-conflicts';\nimport { collectTextContentConflicts } from '../text-content-conflicts';\nimport { collectPptxRendererErrors } from '../../schemas/renderer';\nimport {\n comprehensiveValidatePresentation,\n type DeepValidateOptions,\n} from './deep-validator';\n\nexport {\n deepValidatePresentation,\n comprehensiveValidatePresentation,\n} from './deep-validator';\nexport type { DeepValidateOptions } from './deep-validator';\n\nexport interface PptxValidationResult {\n valid: boolean;\n errors: ValidationError[];\n warnings?: ValidationError[];\n documentType?: 'pptx';\n data?: unknown;\n}\n\nfunction parseJsonInput(jsonInput: string | object): {\n parsed?: unknown;\n error?: ValidationError;\n} {\n if (typeof jsonInput !== 'string') return { parsed: jsonInput };\n try {\n return { parsed: JSON.parse(jsonInput) };\n } catch (err: any) {\n return {\n error: {\n path: 'root',\n message: `Invalid JSON: ${err?.message ?? String(err)}`,\n code: 'json_parse_error',\n },\n };\n }\n}\n\n/**\n * Validate a presentation component tree.\n *\n * The deep walk is the source of truth: it re-implements everything the\n * recursive discriminated union checks (component names, per-component props\n * schemas, container narrowing) with precise paths, so we run it directly\n * instead of the union check whose failures collapse into a generic root\n * error. Image-source mutual exclusivity is a semantic rule the structural\n * schema cannot express, so it runs unconditionally on top.\n */\nexport function validatePresentationDocument(\n data: unknown,\n opts: DeepValidateOptions = {}\n): PptxValidationResult {\n const errors = comprehensiveValidatePresentation(data, [], opts);\n errors.push(...collectImageSourceConflicts(data));\n errors.push(...collectTextContentConflicts(data));\n errors.push(...collectPptxRendererErrors(data));\n const valid = errors.length === 0;\n return {\n valid,\n errors,\n documentType: 'pptx',\n data: valid ? data : undefined,\n };\n}\n\n/**\n * Validate a presentation from a JSON string or object.\n */\nexport function validateJsonPresentationDocument(\n jsonInput: string | object,\n opts: DeepValidateOptions = {}\n): PptxValidationResult {\n const { parsed, error } = parseJsonInput(jsonInput);\n if (error) return { valid: false, errors: [error], documentType: 'pptx' };\n return validatePresentationDocument(parsed, opts);\n}\n\n/**\n * Validate a PPTX theme config.\n */\nexport function validatePptxTheme(data: unknown): PptxValidationResult {\n if (Value.Check(ThemeConfigSchema, data)) {\n return { valid: true, errors: [], data };\n }\n const valueErrors = [...Value.Errors(ThemeConfigSchema, data)];\n const errors = transformValueErrors(valueErrors, { maxErrors: 100 });\n return { valid: false, errors };\n}\n\n/**\n * Validate a PPTX theme from a JSON string or object.\n */\nexport function validateJsonPptxTheme(\n jsonInput: string | object\n): PptxValidationResult {\n const { parsed, error } = parseJsonInput(jsonInput);\n if (error) return { valid: false, errors: [error] };\n return validatePptxTheme(parsed);\n}\n\n/**\n * Simple validation API — the entry point the CLI consumes.\n */\nexport const validate = {\n document: (data: unknown) => validatePresentationDocument(data),\n jsonDocument: (jsonInput: string | object) =>\n validateJsonPresentationDocument(jsonInput),\n theme: (data: unknown) => validatePptxTheme(data),\n jsonTheme: (jsonInput: string | object) => validateJsonPptxTheme(jsonInput),\n isDocument: (data: unknown) => validatePresentationDocument(data).valid,\n isTheme: (data: unknown) => validatePptxTheme(data).valid,\n};\n\n/**\n * Strict validation API. PPTX deep validation never cleans or applies\n * defaults, so this is currently an alias kept for docx API parity — the CLI\n * picks one of the two based on its --strict flag.\n */\nexport const validateStrict = {\n document: (data: unknown) => validatePresentationDocument(data),\n jsonDocument: (jsonInput: string | object) =>\n validateJsonPresentationDocument(jsonInput),\n theme: (data: unknown) => validatePptxTheme(data),\n jsonTheme: (jsonInput: string | object) => validateJsonPptxTheme(jsonInput),\n};\n","/**\n * Deep validation utilities for collecting ALL errors in nested structures.\n *\n * Mirrors the docx deep validator: the recursive discriminated union\n * (PptxComponentDefinitionSchema) short-circuits on the first mismatch and\n * collapses failures into a generic root error, so this walk visits every\n * component in the tree and validates its props against the real per-component\n * schema, producing precise, path-aware errors.\n */\n\nimport { Value } from '@sinclair/typebox/value';\nimport type { TSchema } from '@sinclair/typebox';\nimport type { ValidationError } from '@json-to-office/shared';\nimport { transformValueErrors } from '@json-to-office/shared';\nimport {\n PPTX_STANDARD_COMPONENTS_REGISTRY,\n getPptxStandardComponent,\n pptxComponentRequiresProps,\n} from '../../schemas/component-registry';\n\n// Map of component names to their props schemas, sourced from the registry.\n// This stays in sync as new standard components are added, so the presentation\n// root ('pptx') and every standard child component are recognized here.\nconst COMPONENT_SCHEMAS: Record<string, TSchema> = Object.fromEntries(\n PPTX_STANDARD_COMPONENTS_REGISTRY.map((c) => [c.name, c.propsSchema])\n);\n\n// Root component names that may appear at the top of a presentation.\nconst ROOT_COMPONENT_NAMES = new Set(\n PPTX_STANDARD_COMPONENTS_REGISTRY.filter((c) =>\n Boolean(c.special?.hasSchemaField)\n ).map((c) => c.name)\n);\n\n// Top-level keys allowed on a component object. The recursive union enforces\n// this via additionalProperties:false; the walk re-checks it so a typo like\n// \"porps\" is reported at a precise path instead of a generic union failure.\nconst COMPONENT_OBJECT_KEYS = new Set([\n 'name',\n 'id',\n 'enabled',\n 'props',\n 'children',\n]);\nconst CUSTOM_COMPONENT_OBJECT_KEYS = new Set([\n ...COMPONENT_OBJECT_KEYS,\n 'version',\n]);\nconst ROOT_OBJECT_KEYS = new Set([...COMPONENT_OBJECT_KEYS, '$schema']);\nROOT_OBJECT_KEYS.add('renderer');\n\n/**\n * Options that tune deep validation.\n *\n * `knownCustomNames` — names of registered plugin components. The deep\n * validator neither flags these as \"unknown component\" nor checks what their\n * props hold; the plugin layer validates custom props against the resolved\n * version. It does require the `props` key itself, which the published plugin\n * branch requires too and which needs no plugin knowledge to see.\n *\n * `allowUnknownFields` — when true, unknown properties are stripped before the\n * per-component check instead of being rejected. The escape hatch for callers\n * migrating onto strict schemas.\n */\nexport interface DeepValidateOptions {\n knownCustomNames?: Set<string>;\n allowUnknownFields?: boolean;\n}\n\n/**\n * Deep validate a presentation to collect ALL errors, not just union-level errors.\n */\nexport function deepValidatePresentation(\n data: any,\n opts: DeepValidateOptions = {}\n): ValidationError[] {\n const allErrors: ValidationError[] = [];\n\n if (!data || typeof data !== 'object') {\n allErrors.push({\n path: 'root',\n message: 'Presentation must be an object',\n code: 'invalid_type',\n });\n return allErrors;\n }\n\n if (!data.name) {\n allErrors.push({\n path: '/name',\n message: 'Missing required field \"name\"',\n code: 'required_property',\n });\n } else if (!ROOT_COMPONENT_NAMES.has(data.name)) {\n const expected = [...ROOT_COMPONENT_NAMES].map((n) => `\"${n}\"`).join(', ');\n allErrors.push({\n path: '/name',\n message: `Invalid name \"${data.name}\". Expected ${expected}`,\n code: 'invalid_value',\n });\n }\n\n for (const key of Object.keys(data)) {\n if (!ROOT_OBJECT_KEYS.has(key)) {\n allErrors.push({\n path: `/${key}`,\n message: `Unknown field \"${key}\" on the root component`,\n code: 'unknown_field',\n });\n }\n }\n\n // Validate props when the key is present so explicit `null` (or any falsy\n // non-object) is checked against the component's schema instead of silently\n // passing. Whether the key may be absent is the registry's answer, the same\n // one the published schema is generated from.\n const rootDef = getPptxStandardComponent(data.name);\n if (!('props' in data)) {\n if (!rootDef || pptxComponentRequiresProps(rootDef)) {\n allErrors.push({\n path: '/props',\n message: 'Missing required field \"props\"',\n code: 'required_property',\n });\n }\n } else if (ROOT_COMPONENT_NAMES.has(data.name)) {\n allErrors.push(\n ...validateComponentProps(data.name, data.props, '/props', opts)\n );\n }\n\n // The root requires a children array (the slides); nested containers may\n // legitimately omit theirs.\n if (!data.children) {\n allErrors.push({\n path: '/children',\n message: 'Missing required field \"children\"',\n code: 'required_property',\n });\n } else if (!Array.isArray(data.children)) {\n allErrors.push({\n path: '/children',\n message: 'Field \"children\" must be an array',\n code: 'invalid_type',\n });\n }\n\n walkComponentTree(data, '', opts, allErrors);\n\n return allErrors;\n}\n\n/**\n * Recursively validate every component nested under `node`.\n *\n * Walks two kinds of child position to any depth:\n * - the `children` array — `pptx` holds slides, `slide` holds content\n * components. The registry's `allowedChildren` narrows what each container\n * accepts, and leaf components must not carry children at all; and\n * - a slide's `props.placeholders` record — added dynamically by the\n * component registry on top of the static SlidePropsSchema, so its values\n * are not covered by the slide's own props validation and this walk is\n * their only checker.\n *\n * The node's own props are NOT validated here — the caller validates the root\n * props, and every entry is validated as it is visited.\n */\nfunction walkComponentTree(\n node: any,\n path: string,\n opts: DeepValidateOptions,\n errors: ValidationError[]\n): void {\n if (!node || typeof node !== 'object') return;\n\n const validateEntry = (child: any, childPath: string): void => {\n if (!child || typeof child !== 'object' || Array.isArray(child)) {\n errors.push({\n path: childPath,\n message: 'Component must be an object',\n code: 'invalid_type',\n });\n return;\n }\n if (typeof child.name !== 'string' || child.name.length === 0) {\n errors.push({\n path: `${childPath}/name`,\n message: 'Component missing required field \"name\"',\n code: 'required_property',\n });\n return;\n }\n\n // Registered plugin props are validated version-aware by the plugin layer.\n // Their children still need walking: custom containers may hold authored\n // standard components, and those must obey the same prop/tree contract as\n // standard components elsewhere in the presentation.\n const isCustomComponent = opts.knownCustomNames?.has(child.name) ?? false;\n const allowedObjectKeys = isCustomComponent\n ? CUSTOM_COMPONENT_OBJECT_KEYS\n : COMPONENT_OBJECT_KEYS;\n\n for (const key of Object.keys(child)) {\n if (!allowedObjectKeys.has(key)) {\n errors.push({\n path: `${childPath}/${key}`,\n message: `Unknown field \"${key}\" on component \"${child.name}\"`,\n code: 'unknown_field',\n });\n }\n }\n\n if (isCustomComponent) {\n // What the props *hold* is the plugin layer's call — it alone knows the\n // resolved version's schema. That the key is there at all is not: the\n // published plugin branch requires it unconditionally, so checking\n // presence here is what keeps the one absolute this walk claims true for\n // plugin components too, and turns the plugin layer's \"expected object at\n // root\" into a diagnostic pointing at the node that omitted it.\n if (!('props' in child)) {\n errors.push({\n path: `${childPath}/props`,\n message: `Component \"${child.name}\" is missing required field \"props\"`,\n code: 'required_property',\n suggestion: `Add a \"props\" object holding the content \"${child.name}\" renders.`,\n });\n }\n walkComponentTree(child, childPath, opts, errors);\n return;\n }\n\n // Validate props against the component's schema. An omitted `props` is\n // only legal where the registry says so — `pptxComponentRequiresProps` is\n // the same answer the published schema is generated from, so a document\n // this accepts is a document that schema accepts. Where it is legal, an\n // empty object is still checked: that catches a definition that claims\n // props are omissible while its schema demands a field.\n //\n // Presence is `'props' in child`, matching the root check: an explicit\n // `null` is a value the schema rejects (props must be an object), so it\n // has to reach the schema rather than be read as \"the author left it out\".\n const def = getPptxStandardComponent(child.name);\n const propsPath = `${childPath}/props`;\n if ('props' in child) {\n errors.push(\n ...validateComponentProps(child.name, child.props, propsPath, opts)\n );\n } else if (def && pptxComponentRequiresProps(def)) {\n // The error points at `/props`, not at the fields inside it: with the\n // key absent those paths address nothing, and a caller repairing the\n // document by JSON Patch has to create `props` first either way. The\n // fields it must then hold travel in the suggestion.\n const declared =\n (def.propsSchema as { required?: readonly string[] }).required ?? [];\n errors.push({\n path: propsPath,\n message: `Component \"${child.name}\" is missing required field \"props\"`,\n code: 'required_property',\n suggestion:\n declared.length > 0\n ? `Add \"props\" carrying ${declared.map((f) => `\"${f}\"`).join(', ')}.`\n : `Add a \"props\" object holding the content \"${child.name}\" renders.`,\n });\n } else {\n errors.push(...validateComponentProps(child.name, {}, propsPath, opts));\n }\n\n if (def && !def.hasChildren && child.children != null) {\n errors.push({\n path: `${childPath}/children`,\n message: `Component \"${child.name}\" does not accept children`,\n code: 'invalid_value',\n });\n return;\n }\n\n // Recurse so arbitrarily nested containers are covered.\n walkComponentTree(child, childPath, opts, errors);\n };\n\n const parentDef = getPptxStandardComponent(node.name);\n\n /**\n * Enforce the registry's container narrowing (`pptx` → `slide`, `slide` →\n * the content components) on one entry. Unknown names are already reported\n * by validateComponentProps inside validateEntry, so only standard\n * components in the wrong container are flagged here.\n */\n const checkAllowedChild = (child: any, childPath: string): void => {\n if (\n parentDef?.allowedChildren &&\n child &&\n typeof child === 'object' &&\n typeof child.name === 'string' &&\n getPptxStandardComponent(child.name) &&\n !parentDef.allowedChildren.includes(child.name)\n ) {\n const expected = parentDef.allowedChildren\n .map((n) => `\"${n}\"`)\n .join(', ');\n errors.push({\n path: `${childPath}/name`,\n message: `Component \"${child.name}\" is not allowed inside \"${node.name}\". Expected ${expected}`,\n code: 'invalid_value',\n });\n }\n };\n\n // A slide's `placeholders` record maps placeholder names to full components\n // ({ \"title\": { \"name\": \"text\", ... } }). The static SlidePropsSchema does\n // not include the field (it is injected with the recursive ref at schema\n // generation time), so validateComponentProps strips it before checking the\n // slide's own props — each value is validated here instead.\n //\n // A placeholder holds what the slide itself holds: filling one with a\n // `slide` or the `pptx` root is not a component with no position, it is a\n // container nested where no container can go. The published schema narrows\n // the record to the same union it narrows `children` to, so both refuse it.\n if (node.name === 'slide' && node.props && typeof node.props === 'object') {\n const placeholders = node.props.placeholders;\n if (\n placeholders &&\n typeof placeholders === 'object' &&\n !Array.isArray(placeholders)\n ) {\n for (const [key, child] of Object.entries(placeholders)) {\n const childPath = `${path}/props/placeholders/${key}`;\n checkAllowedChild(child, childPath);\n validateEntry(child, childPath);\n }\n } else if (placeholders != null) {\n errors.push({\n path: `${path}/props/placeholders`,\n message:\n 'Field \"placeholders\" must be an object mapping placeholder names to components',\n code: 'invalid_type',\n });\n }\n }\n\n if (Array.isArray(node.children)) {\n node.children.forEach((child: any, i: number) => {\n const childPath = `${path}/children/${i}`;\n checkAllowedChild(child, childPath);\n validateEntry(child, childPath);\n });\n } else if (node.children != null && path !== '') {\n // `children` is present but not an array on a nested container. The root's\n // `children` is already checked by deepValidatePresentation (skipped here\n // via `path !== ''` so it is not reported twice).\n errors.push({\n path: `${path}/children`,\n message: 'Field \"children\" must be an array',\n code: 'invalid_type',\n });\n }\n}\n\n/**\n * Validate a component's props against its schema.\n */\nfunction validateComponentProps(\n componentName: string,\n props: any,\n basePath: string,\n opts: DeepValidateOptions = {}\n): ValidationError[] {\n const errors: ValidationError[] = [];\n\n const schema = COMPONENT_SCHEMAS[componentName];\n if (!schema) {\n // Unknown component type. `basePath` always ends in `/props`; anchor the\n // swap to the end so a nested path like `…/props/placeholders/title/props`\n // becomes `…/props/placeholders/title/name` rather than mangling an\n // earlier `/props`.\n errors.push({\n path: basePath.replace(/\\/props$/, '/name'),\n message: `Unknown component \"${componentName}\"`,\n code: 'unknown_component',\n });\n return errors;\n }\n\n // A slide's `placeholders` field is injected at schema-generation time and\n // absent from the static props schema; its values are walked separately, so\n // strip it here to avoid a false additionalProperties rejection.\n let toCheck = props;\n if (\n componentName === 'slide' &&\n props &&\n typeof props === 'object' &&\n 'placeholders' in props\n ) {\n const rest = { ...props };\n delete rest.placeholders;\n toCheck = rest;\n }\n\n // When unknown fields are explicitly allowed, strip them before checking so\n // additionalProperties:false no longer rejects — required/typed fields are\n // still enforced.\n if (opts.allowUnknownFields) {\n toCheck = Value.Clean(schema, Value.Clone(toCheck));\n }\n\n if (!Value.Check(schema, toCheck)) {\n const valueErrors = [...Value.Errors(schema, toCheck)];\n const transformedErrors = transformValueErrors(valueErrors, {\n maxErrors: 100,\n });\n\n // Adjust paths to be relative to the document root\n transformedErrors.forEach((error) => {\n const fullPath =\n error.path === 'root'\n ? basePath\n : `${basePath}${error.path.startsWith('/') ? error.path : '/' + error.path}`;\n\n errors.push({\n ...error,\n path: fullPath,\n });\n });\n }\n\n return errors;\n}\n\n/**\n * Combine deep validation with standard validation.\n *\n * Deep validation produces precise, path-aware errors. TypeBox's discriminated-\n * union check, by contrast, often collapses any failure under the root into a\n * single generic \"Invalid component configuration for 'pptx'\" message at\n * `root` — useful as a signal that something is wrong, but actionable only via\n * the deep-validator's output. We always strip that catch-all so it doesn't\n * appear alongside (or, worse, instead of) the real diagnostics.\n */\nexport function comprehensiveValidatePresentation(\n data: any,\n existingErrors: ValidationError[] = [],\n opts: DeepValidateOptions = {}\n): ValidationError[] {\n const deepErrors = deepValidatePresentation(data, opts);\n\n const filteredExisting = existingErrors.filter(\n (e) => !isGenericUnionCatchAll(e)\n );\n\n return deduplicateErrors([...filteredExisting, ...deepErrors]);\n}\n\n/**\n * Detect TypeBox's generic union/discriminator catch-all error at the document\n * root. These messages name the component type ('pptx') but give no actionable\n * detail — the deep validator emits the actual path-level errors instead.\n */\nfunction isGenericUnionCatchAll(error: ValidationError): boolean {\n const atRoot = !error.path || error.path === 'root' || error.path === '/';\n if (!atRoot) return false;\n const msg = error.message || '';\n return (\n /invalid component configurations?/i.test(msg) ||\n /invalid document structure/i.test(msg)\n );\n}\n\n/**\n * Deduplicate errors by path and message.\n */\nfunction deduplicateErrors(errors: ValidationError[]): ValidationError[] {\n const seen = new Set<string>();\n const unique: ValidationError[] = [];\n\n for (const error of errors) {\n const key = `${error.path}:${error.message}`;\n if (!seen.has(key)) {\n seen.add(key);\n unique.push(error);\n }\n }\n\n return unique;\n}\n","export const PPTX_SHARED_VERSION = '1.0.0';\n\n// Component Schemas\nexport {\n PositionSchema,\n SlideBackgroundSchema,\n TransitionSchema,\n VerticalAlignmentSchema,\n ShadowSchema,\n PresentationPropsSchema,\n SlidePropsSchema,\n TextPropsSchema,\n TextRunSchema,\n PptxImagePropsSchema,\n ShapePropsSchema,\n ShapeTypeSchema,\n GradientStopSchema,\n GradientFillSchema,\n PatternFillSchema,\n PATTERN_FILL_PRESETS,\n PptxTablePropsSchema,\n PptxHighchartsPropsSchema,\n PptxStandardComponentDefinitionSchema,\n PptxComponentDefinitionSchema,\n PptxSlideContentSchema,\n} from './schemas/components';\n\nexport type {\n Position,\n SlideBackground,\n Transition,\n VerticalAlignment,\n Shadow,\n PresentationProps,\n SlideProps,\n TextProps,\n TextRun,\n PptxImageProps,\n ShapeType,\n ShapeProps,\n TextSegment,\n GradientStop,\n GradientFill,\n PatternFill,\n PptxTableProps,\n PptxHighchartsProps,\n PptxComponentDefinition,\n PptxSlideContent,\n} from './schemas/components';\n\n// Chart (not re-exported from components barrel)\nexport { PptxChartPropsSchema } from './schemas/components/chart';\nexport type { PptxChartProps } from './schemas/components/chart';\n\n// Component Registry\nexport {\n PPTX_STANDARD_COMPONENTS_REGISTRY,\n getPptxStandardComponent,\n getAllPptxComponentNames,\n getPptxComponentsByCategory,\n getPptxContainerComponents,\n getPptxContentComponents,\n isPptxStandardComponent,\n createPptxComponentSchemaObject,\n createAllPptxComponentSchemas,\n // The requiredness rule the schema generator and the deep walk both read.\n // A consumer that wants the same answer has to be able to reach it from the\n // package entry, not only through a deep subpath import.\n pptxComponentRequiresProps,\n} from './schemas/component-registry';\n\nexport type { PptxStandardComponentDefinition } from './schemas/component-registry';\n\n// Document Schema\nexport {\n PptxJsonComponentDefinitionSchema,\n PPTX_JSON_SCHEMA_URLS,\n} from './schemas/document';\n\nexport type { PptxJsonComponentDefinition } from './schemas/document';\n\n// Schema Export Metadata\nexport {\n PPTX_COMPONENT_METADATA,\n PPTX_BASE_SCHEMA_METADATA,\n} from './schemas/export';\n\n// Component Defaults\nexport {\n PptxComponentDefaultsSchema,\n TextComponentDefaultsSchema,\n ImageComponentDefaultsSchema,\n ShapeComponentDefaultsSchema,\n TableComponentDefaultsSchema,\n HighchartsComponentDefaultsSchema,\n ChartComponentDefaultsSchema,\n} from './schemas/component-defaults';\nexport type {\n PptxComponentDefaults,\n TextComponentDefaults,\n ImageComponentDefaults,\n ShapeComponentDefaults,\n TableComponentDefaults,\n HighchartsComponentDefaults,\n ChartComponentDefaults,\n} from './schemas/component-defaults';\n\n// Theme\nexport {\n ThemeConfigSchema,\n ColorValueSchema,\n SEMANTIC_COLOR_NAMES,\n SEMANTIC_COLOR_ALIASES,\n STYLE_NAMES,\n StyleNameSchema,\n TextStyleSchema,\n isValidThemeConfig,\n} from './schemas/theme';\nexport type { ThemeConfigJson, StyleName, TextStyle } from './schemas/theme';\n\n// Schema Generator\nexport { generateUnifiedDocumentSchema } from './schemas/generator';\nexport type {\n VersionedPropsEntry,\n CustomComponentInfo,\n GenerateSchemaOptions,\n} from './schemas/generator';\n\n// Renderer-discriminated schema profiles\nexport {\n PPTX_RENDERER_IDS,\n DEFAULT_PPTX_RENDERER_ID,\n collectPptxRendererErrors,\n} from './schemas/renderer';\nexport type { PptxRendererId } from './schemas/renderer';\n\n// Types\nexport type { ReportComponent } from './types/components';\n\n// Image source conflict detection (path/base64/svg mutual exclusivity)\nexport {\n collectImageSourceConflicts,\n presentImageSources,\n} from './validation/image-source-conflicts';\n\n// Text content conflict detection (text/runs mutual exclusivity)\nexport { collectTextContentConflicts } from './validation/text-content-conflicts';\n\n// Unified validation facade (deep, path-aware validation of whole presentations\n// and themes) — the API the CLI's `pptx validate` consumes.\nexport {\n validate,\n validateStrict,\n validatePresentationDocument,\n validateJsonPresentationDocument,\n validatePptxTheme,\n validateJsonPptxTheme,\n deepValidatePresentation,\n comprehensiveValidatePresentation,\n} from './validation/unified';\nexport type {\n PptxValidationResult,\n DeepValidateOptions,\n} from './validation/unified';\n\n// Re-export shared validation utilities for convenience\nexport {\n transformValueError,\n transformValueErrors,\n DEFAULT_ERROR_CONFIG,\n createErrorConfig,\n} from '@json-to-office/shared';\n\nexport type {\n ErrorFormatterConfig,\n ValidationError,\n} from '@json-to-office/shared';\n\n// Re-export shared utilities\nexport {\n latestVersion,\n isValidSemver,\n parseSemver,\n compareSemver,\n} from '@json-to-office/shared';\nexport type { ParsedSemver } from '@json-to-office/shared';\n\n// Re-export schema utils\nexport {\n fixSchemaReferences,\n convertToJsonSchema,\n createComponentSchema,\n exportSchemaToFile,\n} from '@json-to-office/shared';\nexport type { ComponentSchemaConfig } from '@json-to-office/shared';\n"],"mappings":"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","names":["Value","transformValueErrors","Value","transformValueErrors","transformValueErrors"]}
@@ -1,4 +1,7 @@
1
1
  import { TSchema } from '@sinclair/typebox';
2
+ export { pptxComponentRequiresProps } from '@json-to-office/shared/schemas/slide-content';
3
+ import { PptxRendererId } from './renderer.js';
4
+ import '@json-to-office/shared';
2
5
 
3
6
  /**
4
7
  * PPTX Component Registry - SINGLE SOURCE OF TRUTH
@@ -24,6 +27,11 @@ interface PptxStandardComponentDefinition {
24
27
  hasPlaceholders?: boolean;
25
28
  category: 'container' | 'content' | 'layout';
26
29
  description: string;
30
+ /**
31
+ * Force `props` to stay required even though the props schema accepts `{}`.
32
+ * See `pptxComponentRequiresProps` for when that is legitimate.
33
+ */
34
+ propsRequired?: boolean;
27
35
  special?: {
28
36
  hasSchemaField?: boolean;
29
37
  };
@@ -38,7 +46,11 @@ declare function getPptxComponentsByCategory(category: PptxStandardComponentDefi
38
46
  declare function getPptxContainerComponents(): readonly PptxStandardComponentDefinition[];
39
47
  declare function getPptxContentComponents(): readonly PptxStandardComponentDefinition[];
40
48
  declare function isPptxStandardComponent(name: string): boolean;
41
- declare function createPptxComponentSchemaObject(component: PptxStandardComponentDefinition, recursiveRef?: TSchema, placeholderRef?: TSchema): TSchema;
49
+
50
+ declare function createPptxComponentSchemaObject(component: PptxStandardComponentDefinition, recursiveRef?: TSchema, placeholderRef?: TSchema, profile?: {
51
+ renderer: PptxRendererId;
52
+ requireDiscriminator: boolean;
53
+ }): TSchema;
42
54
  declare function createAllPptxComponentSchemas(recursiveRef?: TSchema): readonly TSchema[];
43
55
  /**
44
56
  * Build all standard PPTX component schemas with per-container narrowed children.
@@ -51,6 +63,9 @@ declare function createAllPptxComponentSchemas(recursiveRef?: TSchema): readonly
51
63
  * @param pluginSchemas - Plugin component schemas (always allowed in all containers)
52
64
  * @returns Array of TypeBox schemas with narrowed children per container
53
65
  */
54
- declare function createAllPptxComponentSchemasNarrowed(selfRef: TSchema, pluginSchemas?: TSchema[]): TSchema[];
66
+ declare function createAllPptxComponentSchemasNarrowed(selfRef: TSchema, pluginSchemas?: TSchema[], profile?: {
67
+ renderer: PptxRendererId;
68
+ requireDiscriminator: boolean;
69
+ }): TSchema[];
55
70
 
56
71
  export { PPTX_STANDARD_COMPONENTS_REGISTRY, type PptxStandardComponentDefinition, createAllPptxComponentSchemas, createAllPptxComponentSchemasNarrowed, createPptxComponentSchemaObject, getAllPptxComponentNames, getPptxComponentsByCategory, getPptxContainerComponents, getPptxContentComponents, getPptxStandardComponent, isPptxStandardComponent };
@@ -8,8 +8,10 @@ import {
8
8
  getPptxContainerComponents,
9
9
  getPptxContentComponents,
10
10
  getPptxStandardComponent,
11
- isPptxStandardComponent
12
- } from "../chunk-P3YA33LS.js";
11
+ isPptxStandardComponent,
12
+ pptxComponentRequiresProps
13
+ } from "../chunk-XDLNPMWK.js";
14
+ import "../chunk-2YEV3CJF.js";
13
15
  import "../chunk-N6CABSXM.js";
14
16
  import "../chunk-7CKCXKN7.js";
15
17
  export {
@@ -22,6 +24,7 @@ export {
22
24
  getPptxContainerComponents,
23
25
  getPptxContentComponents,
24
26
  getPptxStandardComponent,
25
- isPptxStandardComponent
27
+ isPptxStandardComponent,
28
+ pptxComponentRequiresProps
26
29
  };
27
30
  //# sourceMappingURL=component-registry.js.map
@@ -2,8 +2,9 @@ import {
2
2
  PptxComponentDefinitionSchema,
3
3
  PptxSlideContentSchema,
4
4
  PptxStandardComponentDefinitionSchema
5
- } from "../chunk-C6UX273H.js";
6
- import "../chunk-P3YA33LS.js";
5
+ } from "../chunk-DFXFF2IE.js";
6
+ import "../chunk-XDLNPMWK.js";
7
+ import "../chunk-2YEV3CJF.js";
7
8
  import "../chunk-N6CABSXM.js";
8
9
  import "../chunk-7CKCXKN7.js";
9
10
  export {
@@ -3,7 +3,7 @@ import {
3
3
  PptxComponentDefinitionSchema,
4
4
  PptxSlideContentSchema,
5
5
  PptxStandardComponentDefinitionSchema
6
- } from "../chunk-C6UX273H.js";
6
+ } from "../chunk-DFXFF2IE.js";
7
7
  import {
8
8
  GridPositionSchema,
9
9
  PositionSchema,
@@ -14,7 +14,8 @@ import {
14
14
  SlidePropsSchema,
15
15
  TransitionSchema,
16
16
  VerticalAlignmentSchema
17
- } from "../chunk-P3YA33LS.js";
17
+ } from "../chunk-XDLNPMWK.js";
18
+ import "../chunk-2YEV3CJF.js";
18
19
  import "../chunk-N6CABSXM.js";
19
20
  import {
20
21
  GradientFillSchema,
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  PPTX_JSON_SCHEMA_URLS,
3
3
  PptxJsonComponentDefinitionSchema
4
- } from "../chunk-AKSSIK5V.js";
4
+ } from "../chunk-UCBH6X6Z.js";
5
5
  import "../chunk-J4OT5Y5B.js";
6
- import "../chunk-C6UX273H.js";
7
- import "../chunk-P3YA33LS.js";
6
+ import "../chunk-DFXFF2IE.js";
7
+ import "../chunk-XDLNPMWK.js";
8
+ import "../chunk-2YEV3CJF.js";
8
9
  import "../chunk-N6CABSXM.js";
9
10
  import "../chunk-7CKCXKN7.js";
10
11
  export {
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  generateUnifiedDocumentSchema
3
- } from "../chunk-L7BCW5HU.js";
4
- import "../chunk-P3YA33LS.js";
3
+ } from "../chunk-ETHMRQYH.js";
4
+ import "../chunk-XDLNPMWK.js";
5
+ import "../chunk-2YEV3CJF.js";
5
6
  import "../chunk-N6CABSXM.js";
6
7
  import "../chunk-7CKCXKN7.js";
7
8
  export {
@@ -0,0 +1,19 @@
1
+ import { TSchema } from '@sinclair/typebox';
2
+ import { ValidationError } from '@json-to-office/shared';
3
+
4
+ declare const PPTX_RENDERER_IDS: readonly ["pptxgenjs", "office-open"];
5
+ type PptxRendererId = (typeof PPTX_RENDERER_IDS)[number];
6
+ declare const DEFAULT_PPTX_RENDERER_ID: PptxRendererId;
7
+ /**
8
+ * Renderer-specific view of one canonical component props schema.
9
+ *
10
+ * This is intentionally a pruning pass rather than a second schema tree. The
11
+ * compiler capability gate remains authoritative for requirements that depend
12
+ * on resolved assets or expanded custom components.
13
+ */
14
+ declare function pptxPropsSchemaForRenderer(componentName: string, schema: TSchema, renderer: PptxRendererId): TSchema;
15
+ declare function isPptxComponentSupported(componentName: string, renderer: PptxRendererId): boolean;
16
+ /** Static renderer-profile diagnostics used by CLI/library validation. */
17
+ declare function collectPptxRendererErrors(data: unknown): ValidationError[];
18
+
19
+ export { DEFAULT_PPTX_RENDERER_ID, PPTX_RENDERER_IDS, type PptxRendererId, collectPptxRendererErrors, isPptxComponentSupported, pptxPropsSchemaForRenderer };
@@ -0,0 +1,15 @@
1
+ import {
2
+ DEFAULT_PPTX_RENDERER_ID,
3
+ PPTX_RENDERER_IDS,
4
+ collectPptxRendererErrors,
5
+ isPptxComponentSupported,
6
+ pptxPropsSchemaForRenderer
7
+ } from "../chunk-2YEV3CJF.js";
8
+ export {
9
+ DEFAULT_PPTX_RENDERER_ID,
10
+ PPTX_RENDERER_IDS,
11
+ collectPptxRendererErrors,
12
+ isPptxComponentSupported,
13
+ pptxPropsSchemaForRenderer
14
+ };
15
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@json-to-office/shared-pptx",
3
- "version": "0.35.0",
3
+ "version": "1.2.0",
4
4
  "description": "PPTX-specific schemas, component registry and validation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@sinclair/typebox": "0.34.38",
27
- "@json-to-office/shared": "^0.35.0"
27
+ "@json-to-office/shared": "^1.2.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/node": "20.11.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/schemas/generator.ts"],"sourcesContent":["/**\n * Unified Presentation Schema Generator\n *\n * Generates JSON schemas that include both standard and custom plugin components.\n * Used at build-time for static schema files and at runtime for plugin-aware validation.\n */\nimport { Type, TSchema } from '@sinclair/typebox';\nimport { latestVersion } from '@json-to-office/shared';\nimport { createAllPptxComponentSchemasNarrowed } from './component-registry';\n\nexport interface VersionedPropsEntry {\n version: string;\n propsSchema: TSchema;\n hasChildren?: boolean;\n description?: string;\n}\n\nexport interface CustomComponentInfo {\n name: string;\n versions: VersionedPropsEntry[];\n}\n\nexport interface GenerateSchemaOptions {\n customComponents?: CustomComponentInfo[];\n includeMetadata?: boolean;\n}\n\nfunction createPluginVersionSchema(\n custom: CustomComponentInfo,\n entry: VersionedPropsEntry,\n recursiveRef: TSchema,\n isLatest: boolean\n): TSchema {\n const fields: Record<string, TSchema> = {\n name: Type.Literal(custom.name),\n id: Type.Optional(Type.String()),\n enabled: Type.Optional(\n Type.Boolean({\n default: true,\n description:\n 'When false, this component is filtered out and not rendered. Defaults to true.',\n })\n ),\n // Omitting version selects the latest release at runtime. Explicit older\n // versions remain discriminated so their own props schema is enforced.\n version: isLatest\n ? Type.Optional(Type.Literal(entry.version))\n : Type.Literal(entry.version),\n props: entry.propsSchema,\n };\n\n if (entry.hasChildren) {\n fields.children = Type.Optional(Type.Array(recursiveRef));\n }\n\n return Type.Object(fields, {\n additionalProperties: false,\n description: entry.description ?? custom.name,\n });\n}\n\n/**\n * Generate a unified presentation schema that includes standard + custom components.\n * Uses Type.Recursive so container components (presentation, slide) can have children.\n */\nexport function generateUnifiedDocumentSchema(\n options: GenerateSchemaOptions = {}\n): TSchema {\n const { customComponents = [] } = options;\n\n return Type.Recursive((Self) => {\n // ── Phase 1: Build plugin schemas (plugins get Self for arbitrary nesting) ──\n const pluginSchemas: TSchema[] = [];\n\n for (const custom of customComponents) {\n if (custom.versions.length > 0) {\n const latest = latestVersion(\n custom.versions.map((entry) => entry.version)\n );\n const versions = custom.versions.map((entry) =>\n createPluginVersionSchema(\n custom,\n entry,\n Self,\n entry.version === latest\n )\n );\n pluginSchemas.push(\n versions.length === 1 ? versions[0] : Type.Union(versions)\n );\n }\n }\n\n // ── Phase 2: Build standard components with narrowed children ──\n const standardSchemas = createAllPptxComponentSchemasNarrowed(\n Self,\n pluginSchemas\n );\n\n const componentSchemas = [...standardSchemas, ...pluginSchemas];\n\n if (componentSchemas.length === 0) {\n return Type.Object({});\n }\n\n return Type.Union(componentSchemas);\n });\n}\n"],"mappings":";;;;;AAMA,SAAS,YAAqB;AAC9B,SAAS,qBAAqB;AAoB9B,SAAS,0BACP,QACA,OACA,cACA,UACS;AACT,QAAM,SAAkC;AAAA,IACtC,MAAM,KAAK,QAAQ,OAAO,IAAI;AAAA,IAC9B,IAAI,KAAK,SAAS,KAAK,OAAO,CAAC;AAAA,IAC/B,SAAS,KAAK;AAAA,MACZ,KAAK,QAAQ;AAAA,QACX,SAAS;AAAA,QACT,aACE;AAAA,MACJ,CAAC;AAAA,IACH;AAAA;AAAA;AAAA,IAGA,SAAS,WACL,KAAK,SAAS,KAAK,QAAQ,MAAM,OAAO,CAAC,IACzC,KAAK,QAAQ,MAAM,OAAO;AAAA,IAC9B,OAAO,MAAM;AAAA,EACf;AAEA,MAAI,MAAM,aAAa;AACrB,WAAO,WAAW,KAAK,SAAS,KAAK,MAAM,YAAY,CAAC;AAAA,EAC1D;AAEA,SAAO,KAAK,OAAO,QAAQ;AAAA,IACzB,sBAAsB;AAAA,IACtB,aAAa,MAAM,eAAe,OAAO;AAAA,EAC3C,CAAC;AACH;AAMO,SAAS,8BACd,UAAiC,CAAC,GACzB;AACT,QAAM,EAAE,mBAAmB,CAAC,EAAE,IAAI;AAElC,SAAO,KAAK,UAAU,CAAC,SAAS;AAE9B,UAAM,gBAA2B,CAAC;AAElC,eAAW,UAAU,kBAAkB;AACrC,UAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,cAAM,SAAS;AAAA,UACb,OAAO,SAAS,IAAI,CAAC,UAAU,MAAM,OAAO;AAAA,QAC9C;AACA,cAAM,WAAW,OAAO,SAAS;AAAA,UAAI,CAAC,UACpC;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,YACA,MAAM,YAAY;AAAA,UACpB;AAAA,QACF;AACA,sBAAc;AAAA,UACZ,SAAS,WAAW,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,QAAQ;AAAA,QAC3D;AAAA,MACF;AAAA,IACF;AAGA,UAAM,kBAAkB;AAAA,MACtB;AAAA,MACA;AAAA,IACF;AAEA,UAAM,mBAAmB,CAAC,GAAG,iBAAiB,GAAG,aAAa;AAE9D,QAAI,iBAAiB,WAAW,GAAG;AACjC,aAAO,KAAK,OAAO,CAAC,CAAC;AAAA,IACvB;AAEA,WAAO,KAAK,MAAM,gBAAgB;AAAA,EACpC,CAAC;AACH;","names":[]}