From 04d1548290d799313ab7162a7ffb6a768c6a8251 Mon Sep 17 00:00:00 2001 From: SB-venkatyadavilli Date: Wed, 1 Apr 2026 15:33:06 +0530 Subject: [PATCH 1/5] fix: handled examples based on schema. --- .../exampleGeneration/exampleGeneration.ts | 151 +++++++++++++++++- 1 file changed, 146 insertions(+), 5 deletions(-) diff --git a/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts b/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts index 9603c3146..0ae448126 100644 --- a/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts +++ b/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts @@ -63,13 +63,44 @@ export const generateExampleFromMediaTypeContent = ( export const generateExamplesFromJsonSchema = (schema: JSONSchema7 & { 'x-examples'?: unknown }): Example[] => { const examples: Example[] = []; + const hasNoResolvedProperties = (schemaToCheck: JSONSchema7): boolean => { + // Cond1: object type with no properties + if (schemaToCheck.type !== 'object') return false; + + // Cond2: check allOf, oneOf, anyOf — if any sub-schema has 'properties', return false + const composedArray = schemaToCheck.allOf || schemaToCheck.oneOf || schemaToCheck.anyOf; + + if (Array.isArray(composedArray)) { + const hasProperties = composedArray.some(sub => typeof sub === 'object' && sub !== null && 'properties' in sub); + if (!hasProperties) { + return true; + } + } else if (!schemaToCheck.properties) { + return true; + } + + return false; + }; + + const isHasNoResolvedProperties = hasNoResolvedProperties(schema); + if (Array.isArray(schema?.examples)) { - schema.examples.forEach((example, index) => { - examples.push({ - data: safeStringify(example, undefined, 2) ?? '', - label: index === 0 ? 'default' : `example-${index}`, + if (isHasNoResolvedProperties) { + schema.examples.forEach((example, index) => { + examples.push({ + data: '{}', + label: index === 0 ? 'default' : `example-${index}`, + }); }); - }); + } else { + let res = filterExamplesBySchema(schema, schema.examples); + res.forEach((example, index) => { + examples.push({ + data: safeStringify(example, undefined, 2) ?? '', + label: index === 0 ? 'default' : `example-${index}`, + }); + }); + } } else if (isPlainObject(schema?.['x-examples'])) { for (const [label, example] of Object.entries(schema['x-examples'])) { if (isPlainObject(example)) { @@ -108,3 +139,113 @@ export const generateExamplesFromJsonSchema = (schema: JSONSchema7 & { 'x-exampl export const exceedsSize = (example: string, size: number = 500) => { return example.split(/\r\n|\r|\n/).length > size; }; + +/** + * Filters examples to only include properties that exist in the schema. + * Handles nested objects, arrays, allOf, oneOf, anyOf, and additionalProperties. + * Only removes a property from the example at the exact path where it was removed from the schema. + * + * @param schema - The JSON Schema (possibly with masked/hidden properties) + * @param examples - Array of raw JSON values (e.g. schema.examples) + * @returns New array of filtered objects matching the schema structure + */ +export const filterExamplesBySchema = ( + schema: JSONSchema7 & { 'x-examples'?: unknown }, + examples: unknown[], +): unknown[] => { + return examples.map(example => { + try { + return filterValueBySchema(example, schema); + } catch { + return example; + } + }); +}; + +const collectSchemaPropertyNames = (schema: JSONSchema7): Set => { + const keys = new Set(); + + if (schema.properties) { + for (const key of Object.keys(schema.properties)) { + keys.add(key); + } + } + + const composedSchemas = [ + ...(Array.isArray(schema.allOf) ? schema.allOf : []), + ...(Array.isArray(schema.oneOf) ? schema.oneOf : []), + ...(Array.isArray(schema.anyOf) ? schema.anyOf : []), + ]; + + for (const sub of composedSchemas) { + if (typeof sub === 'object' && sub !== null) { + for (const key of collectSchemaPropertyNames(sub as JSONSchema7)) { + keys.add(key); + } + } + } + + return keys; +}; + +const findPropertySchema = (schema: JSONSchema7, propertyName: string): JSONSchema7 | undefined => { + if (schema.properties?.[propertyName]) { + const prop = schema.properties[propertyName]; + return typeof prop === 'boolean' ? undefined : prop; + } + + const composedSchemas = [ + ...(Array.isArray(schema.allOf) ? schema.allOf : []), + ...(Array.isArray(schema.oneOf) ? schema.oneOf : []), + ...(Array.isArray(schema.anyOf) ? schema.anyOf : []), + ]; + + for (const sub of composedSchemas) { + if (typeof sub === 'object' && sub !== null) { + const found = findPropertySchema(sub as JSONSchema7, propertyName); + if (found) return found; + } + } + + return undefined; +}; + +const filterValueBySchema = (value: unknown, schema: JSONSchema7): unknown => { + if (value === null || value === undefined) return value; + + // Handle arrays + if (Array.isArray(value)) { + const itemSchema = + schema.items && typeof schema.items !== 'boolean' && !Array.isArray(schema.items) + ? (schema.items as JSONSchema7) + : undefined; + + return itemSchema ? value.map(item => filterValueBySchema(item, itemSchema)) : value; + } + + // Handle objects + if (isPlainObject(value)) { + const allowedKeys = collectSchemaPropertyNames(schema); + const hasStructure = allowedKeys.size > 0; + const hasAdditionalProperties = schema.additionalProperties; + + if (!hasStructure && !hasAdditionalProperties) return value; + + const result: Record = {}; + + for (const [key, val] of Object.entries(value as Record)) { + if (allowedKeys.has(key)) { + const propSchema = findPropertySchema(schema, key); + result[key] = propSchema ? filterValueBySchema(val, propSchema) : val; + } else if (hasAdditionalProperties) { + result[key] = val; + } + // else: property was masked/removed from schema — omit it + } + + return result; + } + + // Primitives + return value; +}; From 9dc1fb6e73a18d439fae0e1e5b1c1a4574607281 Mon Sep 17 00:00:00 2001 From: SB-venkatyadavilli Date: Wed, 22 Apr 2026 10:24:45 +0530 Subject: [PATCH 2/5] fix: update generateExamplesFromJsonSchema method --- .../exampleGeneration/exampleGeneration.ts | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts b/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts index 0ae448126..eb264e6b4 100644 --- a/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts +++ b/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts @@ -62,26 +62,29 @@ export const generateExampleFromMediaTypeContent = ( export const generateExamplesFromJsonSchema = (schema: JSONSchema7 & { 'x-examples'?: unknown }): Example[] => { const examples: Example[] = []; + console.log('from generateExamplesFromJsonSchema', JSON.parse(JSON.stringify(schema))); + const hasResolvedProperties = (schemaToCheck: JSONSchema7): boolean => { + // Case 1: Direct object with properties + if (schemaToCheck.properties && Object.keys(schemaToCheck.properties).length > 0) { + return true; + } - const hasNoResolvedProperties = (schemaToCheck: JSONSchema7): boolean => { - // Cond1: object type with no properties - if (schemaToCheck.type !== 'object') return false; - - // Cond2: check allOf, oneOf, anyOf — if any sub-schema has 'properties', return false + // Case 2: Check inside allOf, oneOf, anyOf recursively const composedArray = schemaToCheck.allOf || schemaToCheck.oneOf || schemaToCheck.anyOf; - if (Array.isArray(composedArray)) { - const hasProperties = composedArray.some(sub => typeof sub === 'object' && sub !== null && 'properties' in sub); - if (!hasProperties) { - return true; - } - } else if (!schemaToCheck.properties) { - return true; + return composedArray.some(sub => { + if (typeof sub !== 'object' || sub === null) return false; + return hasResolvedProperties(sub as JSONSchema7); + }); } return false; }; + const hasNoResolvedProperties = (schemaToCheck: JSONSchema7): boolean => { + return !hasResolvedProperties(schemaToCheck); + }; + const isHasNoResolvedProperties = hasNoResolvedProperties(schema); if (Array.isArray(schema?.examples)) { From 990df4e6fab85821bd43ec72684dcf0a884b34af Mon Sep 17 00:00:00 2001 From: SB-venkatyadavilli Date: Wed, 22 Apr 2026 10:25:41 +0530 Subject: [PATCH 3/5] fix: remove log --- .../src/utils/exampleGeneration/exampleGeneration.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts b/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts index eb264e6b4..a0ceda613 100644 --- a/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts +++ b/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts @@ -62,7 +62,6 @@ export const generateExampleFromMediaTypeContent = ( export const generateExamplesFromJsonSchema = (schema: JSONSchema7 & { 'x-examples'?: unknown }): Example[] => { const examples: Example[] = []; - console.log('from generateExamplesFromJsonSchema', JSON.parse(JSON.stringify(schema))); const hasResolvedProperties = (schemaToCheck: JSONSchema7): boolean => { // Case 1: Direct object with properties if (schemaToCheck.properties && Object.keys(schemaToCheck.properties).length > 0) { From 2c7e780c8da438961a618c7304893f41a269f947 Mon Sep 17 00:00:00 2001 From: SB-venkatyadavilli Date: Wed, 22 Apr 2026 11:02:37 +0530 Subject: [PATCH 4/5] fix: update types to the methods --- .../exampleGeneration/exampleGeneration.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts b/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts index a0ceda613..6e09d09f0 100644 --- a/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts +++ b/packages/elements-core/src/utils/exampleGeneration/exampleGeneration.ts @@ -1,7 +1,7 @@ import { isPlainObject, safeStringify } from '@stoplight/json'; import * as Sampler from '@stoplight/json-schema-sampler'; import { IMediaTypeContent, INodeExample, INodeExternalExample } from '@stoplight/types'; -import { JSONSchema7 } from 'json-schema'; +import { JSONSchema7, JSONSchema7Object, JSONSchema7Type } from 'json-schema'; import React from 'react'; import { useDocument } from '../../context/InlineRefResolver'; @@ -60,7 +60,7 @@ export const generateExampleFromMediaTypeContent = ( return ''; }; -export const generateExamplesFromJsonSchema = (schema: JSONSchema7 & { 'x-examples'?: unknown }): Example[] => { +export const generateExamplesFromJsonSchema = (schema: JSONSchema7 & { 'x-examples'?: JSONSchema7Type }): Example[] => { const examples: Example[] = []; const hasResolvedProperties = (schemaToCheck: JSONSchema7): boolean => { // Case 1: Direct object with properties @@ -152,9 +152,9 @@ export const exceedsSize = (example: string, size: number = 500) => { * @returns New array of filtered objects matching the schema structure */ export const filterExamplesBySchema = ( - schema: JSONSchema7 & { 'x-examples'?: unknown }, - examples: unknown[], -): unknown[] => { + schema: JSONSchema7 & { 'x-examples'?: JSONSchema7Type }, + examples: JSONSchema7Type[], +): JSONSchema7Type[] => { return examples.map(example => { try { return filterValueBySchema(example, schema); @@ -212,7 +212,7 @@ const findPropertySchema = (schema: JSONSchema7, propertyName: string): JSONSche return undefined; }; -const filterValueBySchema = (value: unknown, schema: JSONSchema7): unknown => { +const filterValueBySchema = (value: JSONSchema7Type, schema: JSONSchema7): JSONSchema7Type => { if (value === null || value === undefined) return value; // Handle arrays @@ -231,14 +231,14 @@ const filterValueBySchema = (value: unknown, schema: JSONSchema7): unknown => { const hasStructure = allowedKeys.size > 0; const hasAdditionalProperties = schema.additionalProperties; - if (!hasStructure && !hasAdditionalProperties) return value; + if (!hasStructure && !hasAdditionalProperties) return value as JSONSchema7Object; - const result: Record = {}; + const result: JSONSchema7Object = {}; - for (const [key, val] of Object.entries(value as Record)) { + for (const [key, val] of Object.entries(value as JSONSchema7Object)) { if (allowedKeys.has(key)) { const propSchema = findPropertySchema(schema, key); - result[key] = propSchema ? filterValueBySchema(val, propSchema) : val; + result[key] = propSchema ? filterValueBySchema(val as JSONSchema7Type, propSchema) : val; } else if (hasAdditionalProperties) { result[key] = val; } From 4841a0d1c128fca9f9a4f08a2d6617a55c151a0d Mon Sep 17 00:00:00 2001 From: SB-venkatyadavilli Date: Wed, 22 Apr 2026 15:19:43 +0530 Subject: [PATCH 5/5] chore(deps): Bump up Elements-dev-portal, core --- packages/elements-core/package.json | 2 +- packages/elements-dev-portal/package.json | 4 ++-- packages/elements/package.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/elements-core/package.json b/packages/elements-core/package.json index 6428e56ec..c537d7a2f 100644 --- a/packages/elements-core/package.json +++ b/packages/elements-core/package.json @@ -1,6 +1,6 @@ { "name": "@stoplight/elements-core", - "version": "9.0.19", + "version": "9.0.20", "sideEffects": [ "web-components.min.js", "src/web-components/**", diff --git a/packages/elements-dev-portal/package.json b/packages/elements-dev-portal/package.json index 6c41fb559..5f9a5977b 100644 --- a/packages/elements-dev-portal/package.json +++ b/packages/elements-dev-portal/package.json @@ -1,6 +1,6 @@ { "name": "@stoplight/elements-dev-portal", - "version": "3.0.19", + "version": "3.0.20", "description": "UI components for composing beautiful developer documentation.", "keywords": [], "sideEffects": [ @@ -66,7 +66,7 @@ "dependencies": { "@stoplight/markdown-viewer": "^5.7.1", "@stoplight/mosaic": "^1.53.5", - "@stoplight/elements-core": "~9.0.19", + "@stoplight/elements-core": "~9.0.20", "@stoplight/path": "^1.3.2", "@stoplight/types": "^14.0.0", "classnames": "^2.2.6", diff --git a/packages/elements/package.json b/packages/elements/package.json index 8d2868862..ca297670d 100644 --- a/packages/elements/package.json +++ b/packages/elements/package.json @@ -1,6 +1,6 @@ { "name": "@stoplight/elements", - "version": "9.0.19", + "version": "9.0.20", "description": "UI components for composing beautiful developer documentation.", "keywords": [], "sideEffects": [ @@ -63,7 +63,7 @@ ] }, "dependencies": { - "@stoplight/elements-core": "~9.0.19", + "@stoplight/elements-core": "~9.0.20", "@stoplight/http-spec": "^7.1.0", "@stoplight/json": "^3.18.1", "@stoplight/mosaic": "^1.53.5",