Skip to content

Commit e364d2e

Browse files
committed
fix(generator): fix a bug where generated validator names collided
1 parent 885d243 commit e364d2e

File tree

3 files changed

+73
-3
lines changed

3 files changed

+73
-3
lines changed

src/generator/validator-artifacts.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,17 @@ type ParameterSchemaGroup = {
3737
* collisions from overwriting earlier validators in the generated module.
3838
*/
3939
export function createUniqueName(candidate: string, seen: Map<string, number>): string {
40-
const count = seen.get(candidate) ?? 0
40+
let count = seen.get(candidate) ?? 0
41+
let uniqueName = count === 0 ? candidate : `${candidate}${count + 1}`
42+
43+
while (seen.has(uniqueName)) {
44+
count += 1
45+
uniqueName = `${candidate}${count + 1}`
46+
}
47+
4148
seen.set(candidate, count + 1)
42-
return count === 0 ? candidate : `${candidate}${count + 1}`
49+
seen.set(uniqueName, 1)
50+
return uniqueName
4351
}
4452

4553
/**
@@ -344,6 +352,9 @@ function registerRequestSchemasAndCollectValidators(spec: OpenAPIV3.Document): V
344352
const componentSchemas = ensureComponentsSchemas(spec)
345353
const validators: ValidatorExports = {}
346354
const seenOperationNames = new Map<string, number>()
355+
const seenSchemaNames = new Map<string, number>(
356+
Object.keys(componentSchemas).map((schemaName) => [schemaName, 1]),
357+
)
347358

348359
for (const [pathKey, rawPathItem] of Object.entries(spec.paths ?? {})) {
349360
const pathItem = resolvePathItem(
@@ -367,7 +378,7 @@ function registerRequestSchemasAndCollectValidators(spec: OpenAPIV3.Document): V
367378
continue
368379
}
369380

370-
const schemaName = `${baseName}Request`
381+
const schemaName = createUniqueName(`${baseName}Request`, seenSchemaNames)
371382
componentSchemas[schemaName] = requestSchema
372383
validators[`validate${baseName}Request`] = `Spec#/components/schemas/${schemaName}`
373384
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
openapi: 3.0.3
2+
info:
3+
title: Schema Name Collision API
4+
version: 1.0.0
5+
paths:
6+
/items:
7+
post:
8+
operationId: createItem
9+
requestBody:
10+
required: true
11+
content:
12+
application/json:
13+
schema:
14+
$ref: "#/components/schemas/CreateItemRequest"
15+
responses:
16+
"201":
17+
description: Created
18+
components:
19+
schemas:
20+
CreateItemRequest:
21+
type: object
22+
properties:
23+
code:
24+
type: string
25+
value:
26+
type: integer
27+
required:
28+
- code
29+
- value
30+
additionalProperties: false

test/schema-name-collision.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import {loadGeneratedValidators} from "./helpers/load-generated-validator"
2+
import {validateApiGatewayEvent} from "../src"
3+
4+
describe("generated request schema name collisions", () => {
5+
let cleanup: () => void = () => {
6+
}
7+
let validateCreateItemREquest: (value: unknown) => boolean
8+
9+
beforeAll(async () => {
10+
const loaded = await loadGeneratedValidators({fixtureName: "schema-name-collision-api.yaml"})
11+
cleanup = loaded.cleanup
12+
validateCreateItemREquest = loaded.getValidator("validateCreateItemRequest")
13+
})
14+
15+
afterAll(() => {
16+
cleanup()
17+
})
18+
19+
test("keeps component request body schemas distinct from synthesized request wrapper schemas", () => {
20+
expect(() =>
21+
validateApiGatewayEvent(validateCreateItemREquest, {
22+
body: JSON.stringify({
23+
code: "example",
24+
value: 25
25+
}),
26+
}),
27+
).not.toThrow()
28+
})
29+
})

0 commit comments

Comments
 (0)