Skip to content

Commit 0f41af6

Browse files
authored
fix(api-reference): add failsafe types for schema (#6405)
* feat: add failsafe types for schema * fix: ordering * docs(changeset): fix: show anyOf schema when only one item with no type * fix: without brekaing anything else * chore: update the tests
1 parent 7031d9c commit 0f41af6

File tree

4 files changed

+90
-5
lines changed

4 files changed

+90
-5
lines changed

.changeset/gold-boxes-help.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@scalar/api-reference': patch
3+
---
4+
5+
fix: show anyOf schema when only one item with no type

packages/api-reference/src/components/Content/Schema/SchemaHeading.vue

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,37 @@
11
<script lang="ts" setup>
22
import type { OpenAPIV3_1 } from '@scalar/openapi-types'
3+
import { computed } from 'vue'
34
4-
defineProps<{
5+
const { value } = defineProps<{
56
value:
67
| OpenAPIV3_1.SchemaObject
78
| OpenAPIV3_1.ArraySchemaObject
89
| OpenAPIV3_1.NonArraySchemaObject
910
name?: string
1011
}>()
12+
13+
/** Generate a failsafe type from the properties when we don't have one */
14+
const failsafeType = computed(() => {
15+
if (value.type) {
16+
return value.type
17+
}
18+
19+
if (value.enum) {
20+
return 'enum'
21+
}
22+
23+
if ('items' in value && value.items === 'object') {
24+
return 'array'
25+
}
26+
27+
if (value.properties || value.additionalProperties) {
28+
return 'object'
29+
}
30+
31+
return 'unknown'
32+
})
1133
</script>
34+
1235
<template>
1336
<span
1437
v-if="typeof value === 'object'"
@@ -30,7 +53,7 @@ defineProps<{
3053
{{ name }}
3154
</template>
3255
<template v-else>
33-
{{ value.type }}
56+
{{ failsafeType }}
3457
</template>
3558
</span>
3659
</template>

packages/api-reference/src/components/Content/Schema/SchemaProperty.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,64 @@ describe('SchemaProperty', () => {
424424
})
425425
})
426426

427+
describe('object compositions', () => {
428+
// TODO: remove the skip when we expand the object by default
429+
it.skip('renders object compositions with allOf with all properties showing', async () => {
430+
const wrapper = mount(SchemaProperty, {
431+
props: {
432+
value: {
433+
allOf: [
434+
{
435+
properties: {
436+
testStr: { type: 'string', description: 'This is a test string' },
437+
testBool: { type: 'boolean', description: 'This is a test boolean' },
438+
},
439+
required: ['testStr'],
440+
},
441+
],
442+
},
443+
},
444+
})
445+
446+
// For allOf compositions, properties should be displayed directly without expansion
447+
const html = wrapper.html()
448+
449+
// Check that both properties are rendered with their descriptions
450+
expect(html).toContain('testStr')
451+
expect(html).toContain('This is a test string')
452+
expect(html).toContain('testBool')
453+
expect(html).toContain('This is a test boolean')
454+
455+
// Check that the required property is marked as required
456+
expect(html).toContain('required')
457+
})
458+
459+
it('renders object compositions with allOf with an object button', async () => {
460+
const wrapper = mount(SchemaProperty, {
461+
props: {
462+
value: {
463+
allOf: [
464+
{
465+
properties: {
466+
testStr: { type: 'string', description: 'This is a test string' },
467+
testBool: { type: 'boolean', description: 'This is a test boolean' },
468+
},
469+
required: ['testStr'],
470+
},
471+
],
472+
},
473+
},
474+
})
475+
476+
// For allOf compositions, properties should be displayed directly without expansion
477+
const html = wrapper.html()
478+
479+
// Check that both properties are rendered with their descriptions
480+
expect(html).toContain('button')
481+
expect(html).toContain('object')
482+
})
483+
})
484+
427485
describe('nested compositions', () => {
428486
it('renders nested composition selectors with correct titles', async () => {
429487
const wrapper = mount(SchemaProperty, {

packages/api-reference/src/components/Content/Schema/SchemaProperty.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { ScalarMarkdown } from '@scalar/components'
33
import { computed, inject, type Component } from 'vue'
44
5+
import { isTypeObject } from '@/components/Content/Schema/helpers/is-type-object'
56
import type { Schemas } from '@/features/Operation/types/schemas'
67
import { SpecificationExtension } from '@/features/specification-extension'
78
import { DISCRIMINATOR_CONTEXT } from '@/hooks/useDiscriminator'
@@ -213,9 +214,7 @@ const shouldRenderObjectProperties = computed(() => {
213214
}
214215
215216
const value = optimizedValue.value
216-
const isObjectType =
217-
value.type === 'object' ||
218-
(Array.isArray(value.type) && value.type.includes('object'))
217+
const isObjectType = isTypeObject(value)
219218
220219
const hasPropertiesToRender = value.properties || value.additionalProperties
221220

0 commit comments

Comments
 (0)