1+ import type { OpenApiMediaType } from './openapi-types'
2+
13// In the case that there are more than one example requests, and
24// no content responses, a request with an example key that matches the
35// status code of a response will be matched.
46const DEFAULT_EXAMPLE_DESCRIPTION = 'Example'
57const DEFAULT_EXAMPLE_KEY = 'default'
68const DEFAULT_ACCEPT_HEADER = 'application/vnd.github.v3+json'
79
8- // OpenAPI operation structure is dynamic and complex
9- type Operation = any
10+ // These functions only read the request body, parameters, and responses of an
11+ // operation, so they accept a narrower shape than the full OpenApiOperation.
12+ // Content maps are typed as `unknown` values (cast to OpenApiMediaType at the
13+ // point of use) so the partial operation fixtures in tests remain assignable.
14+ interface CodeSampleParameter {
15+ in ?: string
16+ name : string
17+ examples ?: Record < string , { value ?: unknown } >
18+ [ key : string ] : unknown
19+ }
20+
21+ interface CodeSampleResponse {
22+ description ?: string
23+ content ?: unknown
24+ [ key : string ] : unknown
25+ }
26+
27+ interface CodeSampleOperation {
28+ requestBody ?: { content : Record < string , unknown > ; [ key : string ] : unknown }
29+ parameters ?: CodeSampleParameter [ ]
30+ responses ?: Record < string , CodeSampleResponse >
31+ [ key : string ] : unknown
32+ }
1033
1134interface RequestExample {
1235 key : string
1336 request : {
1437 contentType ?: string
1538 description : string
1639 acceptHeader : string
17- bodyParameters ?: any
18- parameters ?: Record < string , any >
40+ bodyParameters ?: unknown
41+ parameters ?: Record < string , unknown >
1942 }
2043}
2144
@@ -25,33 +48,35 @@ interface ResponseExample {
2548 statusCode : string
2649 contentType ?: string
2750 description : string
28- example ?: any
29- schema ?: any
51+ example ?: unknown
52+ schema ?: unknown
3053 }
3154}
3255
33- interface MergedExample {
56+ export interface MergedExample {
3457 request : {
3558 contentType ?: string
3659 description : string
3760 acceptHeader : string
38- bodyParameters ?: any
39- parameters ?: Record < string , any >
61+ bodyParameters ?: unknown
62+ parameters ?: Record < string , unknown >
4063 }
4164 response ?: {
4265 statusCode : string
4366 contentType ?: string
4467 description : string
45- example ?: any
46- schema ?: any
68+ example ?: unknown
69+ schema ?: unknown
4770 }
4871}
4972
5073// Retrieves request and response examples and attempts to
5174// merge them to create matching request/response examples
5275// The key used in the media type `examples` property is
5376// used to match requests to responses.
54- export default async function getCodeSamples ( operation : Operation ) : Promise < MergedExample [ ] > {
77+ export default async function getCodeSamples (
78+ operation : CodeSampleOperation ,
79+ ) : Promise < MergedExample [ ] > {
5580 const responseExamples = getResponseExamples ( operation )
5681 const requestExamples = getRequestExamples ( operation )
5782
@@ -66,7 +91,7 @@ export default async function getCodeSamples(operation: Operation): Promise<Merg
6691 }
6792
6893 return mergedExamples . map ( ( example , i ) => {
69- delete ( example as any ) . key
94+ delete ( example as { key ?: string } ) . key
7095 return {
7196 ...example ,
7297 request : {
@@ -81,7 +106,7 @@ export default async function getCodeSamples(operation: Operation): Promise<Merg
81106 }
82107
83108 // Strip the key field — it's only needed during merging, not at runtime
84- for ( const example of mergedExamples ) delete ( example as any ) . key
109+ for ( const example of mergedExamples ) delete ( example as { key ?: string } ) . key
85110 return mergedExamples
86111}
87112
@@ -171,7 +196,7 @@ export function mergeExamples(
171196 }
172197 }
173198*/
174- export function getRequestExamples ( operation : Operation ) : RequestExample [ ] {
199+ export function getRequestExamples ( operation : CodeSampleOperation ) : RequestExample [ ] {
175200 const requestExamples : RequestExample [ ] = [ ]
176201 const parameterExamples = getParameterExamples ( operation )
177202
@@ -207,20 +232,21 @@ export function getRequestExamples(operation: Operation): RequestExample[] {
207232 // Requests can have multiple content types each with their own set of
208233 // examples.
209234 for ( const contentType of Object . keys ( operation . requestBody . content ) ) {
210- let examples : Record < string , any > = { }
235+ const mediaType = operation . requestBody . content [ contentType ] as OpenApiMediaType
236+ let examples : Record < string , { summary ?: string ; value ?: unknown } > = { }
211237 // This is a fallback to allow using the `example` property in
212238 // the schema. If we start to enforce using examples vs. example using
213239 // a linter, we can remove the check for `example`.
214240 // For now, we'll use the key default, which is a common default
215241 // example name in the OpenAPI schema.
216- if ( operation . requestBody . content [ contentType ] . example ) {
242+ if ( mediaType . example ) {
217243 examples = {
218244 default : {
219- value : operation . requestBody . content [ contentType ] . example ,
245+ value : mediaType . example ,
220246 } ,
221247 }
222- } else if ( operation . requestBody . content [ contentType ] . examples ) {
223- examples = operation . requestBody . content [ contentType ] . examples
248+ } else if ( mediaType . examples ) {
249+ examples = mediaType . examples
224250 } else {
225251 // Example for this content type doesn't exist so we'll try and create one
226252 requestExamples . push ( {
@@ -268,12 +294,12 @@ export function getRequestExamples(operation: Operation): RequestExample[] {
268294 by the runtime rendering code, but they account for ~131 MB of the total
269295 schema.json size across all versions.
270296*/
271- function stripSchemaExamples ( schema : any ) : any {
297+ function stripSchemaExamples ( schema : unknown ) : unknown {
272298 if ( ! schema || typeof schema !== 'object' ) return schema
273299 if ( Array . isArray ( schema ) ) return schema . map ( stripSchemaExamples )
274300
275- const result : any = { }
276- for ( const [ key , value ] of Object . entries ( schema ) ) {
301+ const result : Record < string , unknown > = { }
302+ for ( const [ key , value ] of Object . entries ( schema as Record < string , unknown > ) ) {
277303 if ( key === 'example' || key === 'examples' ) continue
278304 result [ key ] = stripSchemaExamples ( value )
279305 }
@@ -297,14 +323,16 @@ function stripSchemaExamples(schema: any): any {
297323 }
298324 }
299325*/
300- export function getResponseExamples ( operation : Operation ) : ResponseExample [ ] {
326+ export function getResponseExamples ( operation : CodeSampleOperation ) : ResponseExample [ ] {
301327 const responseExamples : ResponseExample [ ] = [ ]
302- for ( const statusCode of Object . keys ( operation . responses ) ) {
328+ const responses = operation . responses as Record < string , CodeSampleResponse >
329+ for ( const statusCode of Object . keys ( responses ) ) {
303330 // We don't want to create examples for error codes
304331 // Error codes are displayed in the status table in the docs
305332 if ( parseInt ( statusCode , 10 ) >= 400 ) continue
306333
307- const content = operation . responses [ statusCode ] . content
334+ const response = responses [ statusCode ]
335+ const content = response . content as Record < string , unknown > | undefined
308336
309337 // A response doesn't always have content (ex:, status 304)
310338 // In this case we create a generic example for the status code
@@ -314,7 +342,7 @@ export function getResponseExamples(operation: Operation): ResponseExample[] {
314342 key : statusCode ,
315343 response : {
316344 statusCode,
317- description : operation . responses [ statusCode ] . description ,
345+ description : response . description ?? '' ,
318346 } ,
319347 }
320348 responseExamples . push ( example )
@@ -324,20 +352,21 @@ export function getResponseExamples(operation: Operation): ResponseExample[] {
324352 // Responses can have multiple content types each with their own set of
325353 // examples.
326354 for ( const contentType of Object . keys ( content ) ) {
327- let examples : Record < string , any > = { }
355+ const mediaType = content [ contentType ] as OpenApiMediaType
356+ let examples : Record < string , { summary ?: string ; value ?: unknown } > = { }
328357 // This is a fallback to allow using the `example` property in
329358 // the schema. If we start to enforce using examples vs. example using
330359 // a linter, we can remove the check for `example`.
331360 // We key by statusCode so that operations with multiple success
332361 // responses (e.g. 200 + 201) get unique keys instead of colliding.
333- if ( operation . responses [ statusCode ] . content [ contentType ] . example ) {
362+ if ( mediaType . example ) {
334363 examples = {
335364 [ statusCode ] : {
336- value : operation . responses [ statusCode ] . content [ contentType ] . example ,
365+ value : mediaType . example ,
337366 } ,
338367 }
339- } else if ( operation . responses [ statusCode ] . content [ contentType ] . examples ) {
340- examples = operation . responses [ statusCode ] . content [ contentType ] . examples
368+ } else if ( mediaType . examples ) {
369+ examples = mediaType . examples
341370 } else if ( parseInt ( statusCode , 10 ) < 300 ) {
342371 // Sometimes there are missing examples for say a 200 response and
343372 // the operation also has a 304 no content status. If we don't add
@@ -349,7 +378,7 @@ export function getResponseExamples(operation: Operation): ResponseExample[] {
349378 key : statusCode ,
350379 response : {
351380 statusCode,
352- description : operation . responses [ statusCode ] . description ,
381+ description : response . description ?? '' ,
353382 } ,
354383 }
355384 responseExamples . push ( example )
@@ -370,15 +399,13 @@ export function getResponseExamples(operation: Operation): ResponseExample[] {
370399 response : {
371400 statusCode,
372401 contentType,
373- description : examples [ key ] . summary || operation . responses [ statusCode ] . description ,
402+ description : examples [ key ] . summary || response . description || '' ,
374403 example : examples [ key ] . value ,
375404 // Note: Including the schema significantly increases JSON file size (~4x),
376405 // but it's necessary to support the schema/example toggle in the UI.
377406 // Users can switch between viewing the example response and the full schema.
378407 // example/examples annotation fields are stripped as they are not rendered.
379- schema : stripSchemaExamples (
380- operation . responses [ statusCode ] . content [ contentType ] . schema ,
381- ) ,
408+ schema : stripSchemaExamples ( mediaType . schema ) ,
382409 } ,
383410 }
384411 responseExamples . push ( example )
@@ -399,12 +426,14 @@ export function getResponseExamples(operation: Operation): ResponseExample[] {
399426 }
400427 }
401428*/
402- export function getParameterExamples ( operation : Operation ) : Record < string , Record < string , any > > {
429+ export function getParameterExamples (
430+ operation : CodeSampleOperation ,
431+ ) : Record < string , Record < string , unknown > > {
403432 if ( ! operation . parameters ) {
404433 return { }
405434 }
406- const parameters = operation . parameters . filter ( ( param : any ) => param . in === 'path' )
407- const parameterExamples : Record < string , Record < string , any > > = { }
435+ const parameters = operation . parameters . filter ( ( param ) => param . in === 'path' )
436+ const parameterExamples : Record < string , Record < string , unknown > > = { }
408437 for ( const parameter of parameters ) {
409438 const examples = parameter . examples
410439 // If there are no examples, create an example from the uppercase parameter
0 commit comments