Skip to content

Commit 3a0f044

Browse files
authored
Strip unused fields from REST schema.json pipeline (~32% size reduction) (#60279)
1 parent 33235b7 commit 3a0f044

8 files changed

Lines changed: 49 additions & 38 deletions

File tree

src/article-api/liquid-renderers/rest-tags.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,6 @@ export class RestStatusCode {
150150
if (description.trim()) {
151151
lines.push(` ${description.trim()}`)
152152
}
153-
} else if (statusCode.httpStatusMessage) {
154-
lines.push(`- **${statusCode.httpStatusCode}** - ${statusCode.httpStatusMessage}`)
155153
} else {
156154
lines.push(`- **${statusCode.httpStatusCode}**`)
157155
}

src/automated-pipelines/components/parameter-table/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ export interface Parameter {
1111
}
1212

1313
export interface BodyParameter {
14-
in: string
1514
name: string
1615
description: string
1716
type: string

src/rest/components/RestStatusCodes.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,7 @@ export function RestStatusCodes({ statusCodes, slug, heading }: Props) {
3030
<code>{statusCode.httpStatusCode}</code>
3131
</td>
3232
<td>
33-
{statusCode.description ? (
34-
<div dangerouslySetInnerHTML={{ __html: statusCode.description }} />
35-
) : (
36-
statusCode.httpStatusMessage
37-
)}
33+
<div dangerouslySetInnerHTML={{ __html: statusCode.description }} />
3834
</td>
3935
</tr>
4036
))}

src/rest/components/types.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export interface ProgAccessT {
2525
}
2626

2727
export interface Parameter {
28-
exampleName?: string
2928
in: string
3029
name: string
3130
description: string
@@ -40,11 +39,9 @@ export interface Parameter {
4039
export interface StatusCode {
4140
description: string
4241
httpStatusCode: string
43-
httpStatusMessage: string
4442
}
4543

4644
export interface CodeSample {
47-
key: string
4845
response: {
4946
contentType: string
5047
description: string
@@ -61,7 +58,6 @@ export interface CodeSample {
6158
}
6259

6360
export interface BodyParameter {
64-
in: string
6561
name: string
6662
description: string
6763
type: string

src/rest/scripts/utils/create-rest-examples.ts

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ interface ResponseExample {
3131
}
3232

3333
interface MergedExample {
34-
key: string
3534
request: {
3635
contentType?: string
3736
description: string
@@ -66,20 +65,23 @@ export default async function getCodeSamples(operation: Operation): Promise<Merg
6665
count[item.request.description] = (count[item.request.description] || 0) + 1
6766
}
6867

69-
const newMergedExamples = mergedExamples.map((example, i) => ({
70-
...example,
71-
request: {
72-
...example.request,
73-
description:
74-
count[example.request.description] > 1
75-
? `${example.request.description} ${i + 1}: Status Code ${example.response!.statusCode}`
76-
: example.request.description,
77-
},
78-
}))
79-
80-
return newMergedExamples
68+
return mergedExamples.map((example, i) => {
69+
delete (example as any).key
70+
return {
71+
...example,
72+
request: {
73+
...example.request,
74+
description:
75+
count[example.request.description] > 1
76+
? `${example.request.description} ${i + 1}: Status Code ${example.response!.statusCode}`
77+
: example.request.description,
78+
},
79+
}
80+
})
8181
}
8282

83+
// Strip the key field — it's only needed during merging, not at runtime
84+
for (const example of mergedExamples) delete (example as any).key
8385
return mergedExamples
8486
}
8587

@@ -260,6 +262,24 @@ export function getRequestExamples(operation: Operation): RequestExample[] {
260262
return requestExamples
261263
}
262264

265+
/*
266+
Recursively removes `example` and `examples` annotation fields from a JSON
267+
Schema object. These fields are OpenAPI annotation-only and are never read
268+
by the runtime rendering code, but they account for ~131 MB of the total
269+
schema.json size across all versions.
270+
*/
271+
function stripSchemaExamples(schema: any): any {
272+
if (!schema || typeof schema !== 'object') return schema
273+
if (Array.isArray(schema)) return schema.map(stripSchemaExamples)
274+
275+
const result: any = {}
276+
for (const [key, value] of Object.entries(schema)) {
277+
if (key === 'example' || key === 'examples') continue
278+
result[key] = stripSchemaExamples(value)
279+
}
280+
return result
281+
}
282+
263283
/*
264284
Create an example object for each example in the response property
265285
of the schema. Each response can have more than one status code,
@@ -355,7 +375,10 @@ export function getResponseExamples(operation: Operation): ResponseExample[] {
355375
// Note: Including the schema significantly increases JSON file size (~4x),
356376
// but it's necessary to support the schema/example toggle in the UI.
357377
// Users can switch between viewing the example response and the full schema.
358-
schema: operation.responses[statusCode].content[contentType].schema,
378+
// example/examples annotation fields are stripped as they are not rendered.
379+
schema: stripSchemaExamples(
380+
operation.responses[statusCode].content[contentType].schema,
381+
),
359382
},
360383
}
361384
responseExamples.push(example)

src/rest/scripts/utils/get-body-params.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export interface TransformedParam {
2020
name: string
2121
description: string
2222
isRequired?: boolean
23-
in?: string
2423
childParamsGroups?: TransformedParam[]
2524
enum?: string[]
2625
oneOfObject?: boolean
@@ -31,7 +30,6 @@ interface BodyParamProps {
3130
paramKey?: string
3231
required?: string[]
3332
childParamsGroups?: TransformedParam[]
34-
topLevel?: boolean
3533
}
3634

3735
// If there is a oneOf at the top level, then we have to present just one
@@ -113,7 +111,6 @@ export async function getBodyParams(schema: Schema, topLevel = false): Promise<T
113111
}
114112
const paramDecorated = await getTransformedParam(schema, paramType, {
115113
required,
116-
topLevel,
117114
childParamsGroups,
118115
})
119116
return [paramDecorated]
@@ -258,7 +255,6 @@ export async function getBodyParams(schema: Schema, topLevel = false): Promise<T
258255
paramKey,
259256
required,
260257
childParamsGroups,
261-
topLevel,
262258
})
263259
bodyParametersParsed.push(paramDecorated)
264260
}
@@ -270,17 +266,14 @@ async function getTransformedParam(
270266
paramType: string[],
271267
props: BodyParamProps,
272268
): Promise<TransformedParam> {
273-
const { paramKey, required, childParamsGroups, topLevel } = props
269+
const { paramKey, required, childParamsGroups } = props
274270
const paramDecorated: TransformedParam = {} as TransformedParam
275271
// Supports backwards compatibility for OpenAPI 3.0
276272
// In 3.1 a nullable type is part of the param.type array and
277273
// the property param.nullable does not exist.
278274
if (param.nullable) paramType.push('null')
279275
paramDecorated.type = Array.from(new Set(paramType.filter(Boolean))).join(' or ')
280276
paramDecorated.name = paramKey || ''
281-
if (topLevel) {
282-
paramDecorated.in = 'body'
283-
}
284277
paramDecorated.description = await renderContent(param.description || '')
285278
if (required && required.includes(paramKey || '')) {
286279
paramDecorated.isRequired = true

src/rest/scripts/utils/operation.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,11 @@ export default class Operation {
6464
this.title = operation.summary
6565
this.category = operation['x-github'].category
6666
this.subcategory = operation['x-github'].subcategory
67-
this.parameters = operation.parameters || []
67+
// Shallow-clone each parameter so that renderParameterDescriptions() can
68+
// safely delete fields (e.g. deprecated, example, examples) without
69+
// mutating this.#operation.parameters, which renderCodeExamples() reads
70+
// concurrently via getParameterExamples().
71+
this.parameters = (operation.parameters || []).map((p: any) => ({ ...p }))
6872
this.bodyParameters = []
6973
return this
7074
}
@@ -151,6 +155,11 @@ export default class Operation {
151155
return Promise.all(
152156
this.parameters.map(async (param) => {
153157
param.description = await renderContent(param.description)
158+
// Remove fields that are not used at runtime to keep schema.json lean
159+
delete param.deprecated
160+
delete param.example
161+
delete param.examples
162+
delete param['x-multi-segment']
154163
return param
155164
}),
156165
)

src/rest/tests/get-rest-code-samples.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ describe('getGHExample - GitHub CLI code generation', () => {
3535
}
3636

3737
const codeSample: CodeSample = {
38-
key: 'default',
3938
request: {
4039
contentType: 'application/json',
4140
description: 'Example',
@@ -134,7 +133,6 @@ describe('getGHExample - GitHub CLI code generation', () => {
134133
}
135134

136135
const codeSample: CodeSample = {
137-
key: 'default',
138136
request: {
139137
contentType: 'application/json',
140138
description: 'Example',
@@ -196,7 +194,6 @@ describe('getGHExample - GitHub CLI code generation', () => {
196194
}
197195

198196
const codeSample: CodeSample = {
199-
key: 'default',
200197
request: {
201198
contentType: 'application/json',
202199
description: 'Example',

0 commit comments

Comments
 (0)