Repository: fastify/fastify-swagger (JavaScript)

Issue:
Type.Record doesn't generate correct schema
### Prerequisites

- [X] I have written a descriptive issue title
- [X] I have searched existing issues to ensure the bug has not already been reported


### Fastify version

3.27.1

### Plugin version

4.15.0

### Node.js version

16.13.1

### Operating system

macOS

### Operating system version (i.e. 20.04, 11.3, 10)

11.6.4

### Description

When using @sinclair/typebox and using the Type.Record type, the schema is not represented correctly in the swagger output.

Type.Record lets you type an object where the key of the object is dynamic. In our case the key can be anything, but the value of the key has a specific format.


### Steps to Reproduce

 Using the follow type:

```js
export const testBody = Type.Object({
  foo: Type.Record(
    Type.String(),
    Type.Array(
      Type.Object({
        name: Type.String(),
      })
    )
  ),
});

type Body = Static<typeof testBody>;
```

And this route:

```js
server.route({
  method: "POST",
  url: "/foo",
  async handler(_request, reply) {
    reply.code(204).send();
  },
  schema: { body: testBody },
});
```

The swagger schema example is as follows:

```json
{
  "foo": {
    "additionalProp1": "string",
    "additionalProp2": "string",
    "additionalProp3": "string"
  }
}
```

The "string" used here seems to be the type of the key provided to Type.Record.


The typescript type version of the Typebox type works properly. Also it seems that fastify validates the schema correctly.

A post with:

```json
{
  "foo": {
    "bar": "test"
  }
}
```

Returns a proper error from fastify:

```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "body.foo['bar'] should be array"
}
```

Closer to correct post continues to validate in fastify:

```json
{
  "foo": {
    "bar": [{}]
  }
}
```

Returns

```json
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "body.foo['bar'][0] should have required property 'name'"
}
```

Using a more simple example `Type.Record` produces the same schema in swagger.

```js
export const testBody = Type.Object({
  foo: Type.Record(Type.String(), Type.Number()),
});
```

Produces:

```json
{
  "foo": {
    "additionalProp1": "string",
    "additionalProp2": "string",
    "additionalProp3": "string"
  }
}
```

### Expected Behavior

The swagger schema should be something like:

```
{
  "foo": {
    "additionalProp1": [
      {
        "name": "string"
      }
    ],
  }
}
```


Discussion:
Would you like to send a Pull Request to address this issue? Remember to add unit tests.
I also have the same issue with Type.Record.  My schema is defined as follows

import { Type } from '@sinclair/typebox'
import { commonResponses } from '../../../config/responses'

export const featureFlagResponse = Type.Object(
  {
    featureFlags: Type.Record(Type.String(), Type.Boolean()),
  },
  { description: 'OK' },
)

export const headers = Type.Object({
  accept: Type.Optional(Type.RegEx(/\*\/\*|application\/json/)),
})

export const schema = {
  security: [{ apiKey: [] }],
  tags: ['featureFlags'],
  operationId: 'getFeatureFlags',
  produces: ['application/json'],
  response: {
    ...commonResponses,
    200: featureFlagResponse,
  },
}


But swagger generates `  featureFlags: { [key: string]: string }` The key has the right string type, but the value is wrong, the value needs to have `boolean` type. Would you please help me. We are using  "fastify-swagger": "5.0.0",


.....
responses: {
      /** OK */
      200: {
        content: {
          'application/json': {
            featureFlags: { [key: string]: string }
          }
        }
      }
  .....




Patch:
diff --git a/lib/spec/openapi/utils.js b/lib/spec/openapi/utils.js
index 6cc05ecb..b3931a49 100644
--- a/lib/spec/openapi/utils.js
+++ b/lib/spec/openapi/utils.js
@@ -82,7 +82,7 @@ function transformDefsToComponents (jsonSchema) {
   if (typeof jsonSchema === 'object' && jsonSchema !== null) {
     // Handle patternProperties, that is not part of OpenAPI definitions
     if (jsonSchema.patternProperties) {
-      jsonSchema.additionalProperties = { type: 'string' }
+      jsonSchema.additionalProperties = Object.values(jsonSchema.patternProperties)[0];
       delete jsonSchema.patternProperties
     } else if (jsonSchema.const) {
       // OAS 3.1 supports `const` but it is not supported by `swagger-ui`


Test patch:
diff --git a/test/spec/openapi/schema.js b/test/spec/openapi/schema.js
index da8314fe..67a7a0ea 100644
--- a/test/spec/openapi/schema.js
+++ b/test/spec/openapi/schema.js
@@ -474,6 +474,71 @@ test('support "patternProperties" parameter', async t => {
   })
 })
 
+test('properly support "patternProperties" parameter', async t => {
+  const opt = {
+    schema: {
+      response: {
+        200: {
+          description: 'Expected Response',
+          type: 'object',
+          properties: {
+            foo: {
+              type: 'object',
+              patternProperties: {
+                '^[a-z]{2,3}-[a-zA-Z]{2}$': {
+                  type: 'object',
+                  properties: {
+                    foo: { type: 'number' }
+                  }
+                }
+              },
+              additionalProperties: false
+            }
+          }
+        }
+      }
+    }
+  }
+
+  const fastify = Fastify()
+  fastify.register(fastifySwagger, {
+    openapi: true,
+    routePrefix: '/docs',
+    exposeRoute: true
+  })
+  fastify.get('/', opt, () => { })
+
+  await fastify.ready()
+
+  const swaggerObject = fastify.swagger()
+  const api = await Swagger.validate(swaggerObject)
+
+  const definedPath = api.paths['/'].get
+
+  t.same(definedPath.responses[200], {
+    description: 'Expected Response',
+    content: {
+      'application/json': {
+        schema: {
+          description: 'Expected Response',
+          type: 'object',
+          properties: {
+            foo: {
+              type: 'object',
+              additionalProperties: {
+                type: 'object',
+                properties: {
+                  foo: { type: 'number' }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  })
+})
+
 test('support "const" keyword', async t => {
   const opt = {
     schema: {