@@ -63,13 +63,44 @@ export const generateExampleFromMediaTypeContent = (
6363export const generateExamplesFromJsonSchema = ( schema : JSONSchema7 & { 'x-examples' ?: unknown } ) : Example [ ] => {
6464 const examples : Example [ ] = [ ] ;
6565
66+ const hasNoResolvedProperties = ( schemaToCheck : JSONSchema7 ) : boolean => {
67+ // Cond1: object type with no properties
68+ if ( schemaToCheck . type !== 'object' ) return false ;
69+
70+ // Cond2: check allOf, oneOf, anyOf — if any sub-schema has 'properties', return false
71+ const composedArray = schemaToCheck . allOf || schemaToCheck . oneOf || schemaToCheck . anyOf ;
72+
73+ if ( Array . isArray ( composedArray ) ) {
74+ const hasProperties = composedArray . some ( sub => typeof sub === 'object' && sub !== null && 'properties' in sub ) ;
75+ if ( ! hasProperties ) {
76+ return true ;
77+ }
78+ } else if ( ! schemaToCheck . properties ) {
79+ return true ;
80+ }
81+
82+ return false ;
83+ } ;
84+
85+ const isHasNoResolvedProperties = hasNoResolvedProperties ( schema ) ;
86+
6687 if ( Array . isArray ( schema ?. examples ) ) {
67- schema . examples . forEach ( ( example , index ) => {
68- examples . push ( {
69- data : safeStringify ( example , undefined , 2 ) ?? '' ,
70- label : index === 0 ? 'default' : `example-${ index } ` ,
88+ if ( isHasNoResolvedProperties ) {
89+ schema . examples . forEach ( ( example , index ) => {
90+ examples . push ( {
91+ data : '{}' ,
92+ label : index === 0 ? 'default' : `example-${ index } ` ,
93+ } ) ;
7194 } ) ;
72- } ) ;
95+ } else {
96+ let res = filterExamplesBySchema ( schema , schema . examples ) ;
97+ res . forEach ( ( example , index ) => {
98+ examples . push ( {
99+ data : safeStringify ( example , undefined , 2 ) ?? '' ,
100+ label : index === 0 ? 'default' : `example-${ index } ` ,
101+ } ) ;
102+ } ) ;
103+ }
73104 } else if ( isPlainObject ( schema ?. [ 'x-examples' ] ) ) {
74105 for ( const [ label , example ] of Object . entries ( schema [ 'x-examples' ] ) ) {
75106 if ( isPlainObject ( example ) ) {
@@ -108,3 +139,113 @@ export const generateExamplesFromJsonSchema = (schema: JSONSchema7 & { 'x-exampl
108139export const exceedsSize = ( example : string , size : number = 500 ) => {
109140 return example . split ( / \r \n | \r | \n / ) . length > size ;
110141} ;
142+
143+ /**
144+ * Filters examples to only include properties that exist in the schema.
145+ * Handles nested objects, arrays, allOf, oneOf, anyOf, and additionalProperties.
146+ * Only removes a property from the example at the exact path where it was removed from the schema.
147+ *
148+ * @param schema - The JSON Schema (possibly with masked/hidden properties)
149+ * @param examples - Array of raw JSON values (e.g. schema.examples)
150+ * @returns New array of filtered objects matching the schema structure
151+ */
152+ export const filterExamplesBySchema = (
153+ schema : JSONSchema7 & { 'x-examples' ?: unknown } ,
154+ examples : unknown [ ] ,
155+ ) : unknown [ ] => {
156+ return examples . map ( example => {
157+ try {
158+ return filterValueBySchema ( example , schema ) ;
159+ } catch {
160+ return example ;
161+ }
162+ } ) ;
163+ } ;
164+
165+ const collectSchemaPropertyNames = ( schema : JSONSchema7 ) : Set < string > => {
166+ const keys = new Set < string > ( ) ;
167+
168+ if ( schema . properties ) {
169+ for ( const key of Object . keys ( schema . properties ) ) {
170+ keys . add ( key ) ;
171+ }
172+ }
173+
174+ const composedSchemas = [
175+ ...( Array . isArray ( schema . allOf ) ? schema . allOf : [ ] ) ,
176+ ...( Array . isArray ( schema . oneOf ) ? schema . oneOf : [ ] ) ,
177+ ...( Array . isArray ( schema . anyOf ) ? schema . anyOf : [ ] ) ,
178+ ] ;
179+
180+ for ( const sub of composedSchemas ) {
181+ if ( typeof sub === 'object' && sub !== null ) {
182+ for ( const key of collectSchemaPropertyNames ( sub as JSONSchema7 ) ) {
183+ keys . add ( key ) ;
184+ }
185+ }
186+ }
187+
188+ return keys ;
189+ } ;
190+
191+ const findPropertySchema = ( schema : JSONSchema7 , propertyName : string ) : JSONSchema7 | undefined => {
192+ if ( schema . properties ?. [ propertyName ] ) {
193+ const prop = schema . properties [ propertyName ] ;
194+ return typeof prop === 'boolean' ? undefined : prop ;
195+ }
196+
197+ const composedSchemas = [
198+ ...( Array . isArray ( schema . allOf ) ? schema . allOf : [ ] ) ,
199+ ...( Array . isArray ( schema . oneOf ) ? schema . oneOf : [ ] ) ,
200+ ...( Array . isArray ( schema . anyOf ) ? schema . anyOf : [ ] ) ,
201+ ] ;
202+
203+ for ( const sub of composedSchemas ) {
204+ if ( typeof sub === 'object' && sub !== null ) {
205+ const found = findPropertySchema ( sub as JSONSchema7 , propertyName ) ;
206+ if ( found ) return found ;
207+ }
208+ }
209+
210+ return undefined ;
211+ } ;
212+
213+ const filterValueBySchema = ( value : unknown , schema : JSONSchema7 ) : unknown => {
214+ if ( value === null || value === undefined ) return value ;
215+
216+ // Handle arrays
217+ if ( Array . isArray ( value ) ) {
218+ const itemSchema =
219+ schema . items && typeof schema . items !== 'boolean' && ! Array . isArray ( schema . items )
220+ ? ( schema . items as JSONSchema7 )
221+ : undefined ;
222+
223+ return itemSchema ? value . map ( item => filterValueBySchema ( item , itemSchema ) ) : value ;
224+ }
225+
226+ // Handle objects
227+ if ( isPlainObject ( value ) ) {
228+ const allowedKeys = collectSchemaPropertyNames ( schema ) ;
229+ const hasStructure = allowedKeys . size > 0 ;
230+ const hasAdditionalProperties = schema . additionalProperties ;
231+
232+ if ( ! hasStructure && ! hasAdditionalProperties ) return value ;
233+
234+ const result : Record < string , unknown > = { } ;
235+
236+ for ( const [ key , val ] of Object . entries ( value as Record < string , unknown > ) ) {
237+ if ( allowedKeys . has ( key ) ) {
238+ const propSchema = findPropertySchema ( schema , key ) ;
239+ result [ key ] = propSchema ? filterValueBySchema ( val , propSchema ) : val ;
240+ } else if ( hasAdditionalProperties ) {
241+ result [ key ] = val ;
242+ }
243+ // else: property was masked/removed from schema — omit it
244+ }
245+
246+ return result ;
247+ }
248+
249+ // Primitives
250+ return value ;
251+ } ;
0 commit comments