feat: allow users/plugins to modify and extend generated types for fields & config, add generated types for json field (#6984)

- Improves type for `jsonSchema` property of JSON field
- Adds type generation of JSON field with `jsonSchema`
- Adds `typescriptSchema` property to fields that allows you override
default field type generation by providing a JSON schema.
- Adds `typescript.schema` property in payload config, to allow for any
modifications of the type schemas

---------

Co-authored-by: Alessio Gravili <alessio@gravili.de>
This commit is contained in:
Ritsu
2024-07-02 19:48:21 +03:00
committed by GitHub
parent 955b845725
commit eb2f7631f7
27 changed files with 528 additions and 309 deletions

View File

@@ -27,7 +27,7 @@ keywords: array, fields, config, configuration, documentation, Content Managemen
## Config
| Option | Description |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as the heading in the Admin panel or an object with keys for each language. Auto-generated from name if not defined. |
| **`fields`** \* | Array of field types to correspond to each row of the Array. |
@@ -46,6 +46,7 @@ keywords: array, fields, config, configuration, documentation, Content Managemen
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
| **`dbName`** | Custom table name for the field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -29,7 +29,7 @@ keywords: blocks, fields, config, configuration, documentation, Content Manageme
## Field config
| Option | Description |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as the heading in the Admin panel or an object with keys for each language. Auto-generated from name if not defined. |
| **`blocks`** \* | Array of [block configs](/docs/fields/blocks#block-configs) to be made available to this field. |
@@ -46,6 +46,7 @@ keywords: blocks, fields, config, configuration, documentation, Content Manageme
| **`labels`** | Customize the block row labels appearing in the Admin dashboard. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -18,7 +18,7 @@ keywords: checkbox, fields, config, configuration, documentation, Content Manage
## Config
| Option | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
@@ -32,6 +32,7 @@ keywords: checkbox, fields, config, configuration, documentation, Content Manage
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -24,7 +24,7 @@ This field uses the `monaco-react` editor syntax highlighting.
## Config
| Option | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
@@ -41,6 +41,7 @@ This field uses the `monaco-react` editor syntax highlighting.
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -23,7 +23,7 @@ This field uses [`react-datepicker`](https://www.npmjs.com/package/react-datepic
## Config
| Option | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
@@ -37,6 +37,7 @@ This field uses [`react-datepicker`](https://www.npmjs.com/package/react-datepic
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -18,7 +18,7 @@ keywords: email, fields, config, configuration, documentation, Content Managemen
## Config
| Option | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
@@ -33,6 +33,7 @@ keywords: email, fields, config, configuration, documentation, Content Managemen
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -21,7 +21,7 @@ keywords: group, fields, config, configuration, documentation, Content Managemen
## Config
| Option | Description |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`fields`** \* | Array of field types to nest within this Group. |
| **`label`** | Used as a heading in the Admin panel and to name the generated GraphQL type. |
@@ -35,6 +35,7 @@ keywords: group, fields, config, configuration, documentation, Content Managemen
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -24,13 +24,13 @@ This field uses the `monaco-react` editor syntax highlighting.
## Config
| Option | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
| **`jsonSchema`** | Provide a JSON schema that will be used for validation. [JSON schemas](https://json-schema.org/learn/getting-started-step-by-step)
| **`jsonSchema`** | Provide a JSON schema that will be used for validation. [JSON schemas](https://json-schema.org/learn/getting-started-step-by-step) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
@@ -40,6 +40,7 @@ This field uses the `monaco-react` editor syntax highlighting.
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -21,7 +21,7 @@ keywords: number, fields, config, configuration, documentation, Content Manageme
## Config
| Option | Description |
|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
| **`min`** | Minimum value accepted. Used in the default `validation` function. |
@@ -41,6 +41,7 @@ keywords: number, fields, config, configuration, documentation, Content Manageme
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -28,7 +28,7 @@ The data structure in the database matches the GeoJSON structure to represent po
## Config
| Option | Description |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Used as a field label in the Admin panel and to name the generated GraphQL type. |
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
@@ -43,6 +43,7 @@ The data structure in the database matches the GeoJSON structure to represent po
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -21,7 +21,7 @@ keywords: radio, fields, config, configuration, documentation, Content Managemen
## Config
| Option | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing an `label` string and a `value` string. |
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
@@ -36,7 +36,8 @@ keywords: radio, fields, config, configuration, documentation, Content Managemen
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`enumName`** | Custom enum name for this field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined.
| **`enumName`** | Custom enum name for this field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -27,7 +27,7 @@ keywords: relationship, fields, config, configuration, documentation, Content Ma
## Config
| Option | Description |
|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`relationTo`** \* | Provide one or many collection `slug`s to be able to assign relationships to. |
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More](#filtering-relationship-options). |
@@ -48,6 +48,7 @@ keywords: relationship, fields, config, configuration, documentation, Content Ma
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -42,7 +42,7 @@ Right now, Payload is officially supporting two rich text editors:
## Config
| Option | Description |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
@@ -56,6 +56,7 @@ Right now, Payload is officially supporting two rich text editors:
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`editor`** | Override the rich text editor specified in your base configuration for this field. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -21,7 +21,7 @@ keywords: select, multi-select, fields, config, configuration, documentation, Co
## Config
| Option | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing a `label` string and a `value` string. |
| **`hasMany`** | Boolean when, if set to `true`, allows this field to have many selections instead of only one. |
@@ -40,6 +40,7 @@ keywords: select, multi-select, fields, config, configuration, documentation, Co
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`enumName`** | Custom enum name for this field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`dbName`** | Custom table name (if `hasMany` set to `true`) for this field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -21,7 +21,7 @@ keywords: text, fields, config, configuration, documentation, Content Management
## Config
| Option | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
@@ -41,6 +41,7 @@ keywords: text, fields, config, configuration, documentation, Content Management
| **`hasMany`** | Makes this field an ordered array of text instead of just a single text. |
| **`minRows`** | Minimum number of texts in the array, if `hasMany` is set to true. |
| **`maxRows`** | Maximum number of texts in the array, if `hasMany` is set to true. |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -21,7 +21,7 @@ keywords: textarea, fields, config, configuration, documentation, Content Manage
## Config
| Option | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
@@ -38,6 +38,7 @@ keywords: textarea, fields, config, configuration, documentation, Content Manage
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -35,7 +35,7 @@ keywords: upload, images media, fields, config, configuration, documentation, Co
## Config
| Option | Description |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`*relationTo`** \* | Provide a single collection `slug` to allow this field to accept a relation to. <strong>Note: the related collection must be configured to support Uploads.</strong> |
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More](#filtering-upload-options). |
@@ -53,6 +53,7 @@ keywords: upload, images media, fields, config, configuration, documentation, Co
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._

View File

@@ -61,16 +61,55 @@ You can specify where you want your types to be generated by adding a property t
The above example places your types next to your Payload config itself as the file `generated-types.ts`.
## Custom generated types
Payload generates your types based on a JSON schema. You can extend that JSON schema, and thus the generated types, by passing a function to `typescript.schema`:
```ts
// payload.config.ts
{
// ...
typescript: {
schema: [
({ jsonSchema }) => {
// Modify the JSON schema here
jsonSchema.definitions.Test = {
type: 'object',
properties: {
title: { type: 'string' },
content: { type: 'string' },
},
required: ['title', 'content'],
}
return jsonSchema
},
]
}
}
// This will generate the following type in your payload-types.ts:
export interface Test {
title: string;
content: string;
[k: string]: unknown;
}
```
This function takes the existing JSON schema as an argument and returns the modified JSON schema. It can be useful for plugins that wish to generate their own types.
## Example Usage
For example, let's look at the following simple Payload config:
```ts
import type { Config } from 'payload'
const config: Config = {
serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL,
admin: {
user: 'users',
}
},
collections: [
{
slug: 'users',

View File

@@ -204,6 +204,7 @@ export default joi.object({
autoGenerate: joi.boolean(),
declare: joi.alternatives().try(joi.boolean(), joi.object({ ignoreTSError: joi.boolean() })),
outputFile: joi.string(),
schema: joi.array().items(joi.func()),
}),
upload: joi.object(),
})

View File

@@ -6,6 +6,7 @@ import type {
} from '@payloadcms/translations'
import type { Options as ExpressFileUploadOptions } from 'express-fileupload'
import type GraphQL from 'graphql'
import type { JSONSchema4 } from 'json-schema'
import type { DestinationStream, LoggerOptions } from 'pino'
import type React from 'react'
import type { JSX } from 'react'
@@ -744,6 +745,12 @@ export type Config = {
/** Filename to write the generated types to */
outputFile?: string
/**
* Allows you to modify the base JSON schema that is generated during generate:types. This JSON schema will be used
* to generate the TypeScript interfaces.
*/
schema?: Array<(args: { jsonSchema: JSONSchema4 }) => JSONSchema4>
}
/**
* Customize the handling of incoming file uploads for collections that have uploads enabled.

View File

@@ -8,6 +8,7 @@ export type ServerOnlyFieldProperties =
| 'editor' // This is a `richText` only property
| 'filterOptions' // This is a `relationship` and `upload` only property
| 'label'
| 'typescriptSchema'
| keyof Pick<FieldBase, 'access' | 'custom' | 'defaultValue' | 'hooks' | 'validate'>
export type ServerOnlyFieldAdminProperties = keyof Pick<
@@ -33,6 +34,7 @@ export const createClientFieldConfig = ({
'filterOptions', // This is a `relationship` and `upload` only property
'editor', // This is a `richText` only property
'custom',
'typescriptSchema',
// `fields`
// `blocks`
// `tabs`

View File

@@ -65,6 +65,7 @@ export const baseField = joi
localized: joi.boolean().default(false),
required: joi.boolean().default(false),
saveToJWT: joi.alternatives().try(joi.boolean(), joi.string()).default(false),
typescriptSchema: joi.array().items(joi.func()),
unique: joi.boolean().default(false),
validate: joi.func(),
})

View File

@@ -5,6 +5,7 @@ import type { CSSProperties } from 'react'
//eslint-disable-next-line @typescript-eslint/no-unused-vars
import monacoeditor from 'monaco-editor' // IMPORTANT - DO NOT REMOVE: This is required for pnpm's default isolated mode to work - even though the import is not used. This is due to a typescript bug: https://github.com/microsoft/TypeScript/issues/47663#issuecomment-1519138189. (tsbugisolatedmode)
import type { JSONSchema4 } from 'json-schema'
import type React from 'react'
import type { RichTextAdapter, RichTextAdapterProvider } from '../../admin/RichText.js'
@@ -231,6 +232,11 @@ export interface FieldBase {
name: string
required?: boolean
saveToJWT?: boolean | string
/**
* Allows you to modify the base JSON schema that is generated during generate:types for this field.
* This JSON schema will be used to generate the TypeScript interface of this field.
*/
typescriptSchema?: Array<(args: { jsonSchema: JSONSchema4 }) => JSONSchema4>
unique?: boolean
validate?: Validate
}
@@ -530,7 +536,11 @@ type JSONAdmin = Admin & {
export type JSONField = Omit<FieldBase, 'admin'> & {
admin?: JSONAdmin
jsonSchema?: Record<string, unknown>
jsonSchema?: {
fileMatch: string[]
schema: JSONSchema4
uri: string
}
type: 'json'
}

View File

@@ -2,6 +2,7 @@ import type { Config } from '../config/types.js'
import { sanitizeConfig } from '../config/sanitize.js'
import { configToJSONSchema } from './configToJSONSchema.js'
import { JSONSchema4 } from 'json-schema'
describe('configToJSONSchema', () => {
it('should handle optional arrays with required fields', async () => {
@@ -146,4 +147,58 @@ describe('configToJSONSchema', () => {
type: 'object',
})
})
it('should handle custom typescript schema and JSON field schema', async () => {
const customSchema: JSONSchema4 = {
type: 'object',
properties: {
id: {
type: 'number',
},
required: ['id'],
},
}
const config: Partial<Config> = {
collections: [
{
fields: [
{
type: 'text',
name: 'withCustom',
typescriptSchema: [() => customSchema],
},
{
type: 'json',
name: 'jsonWithSchema',
jsonSchema: {
uri: 'a://b/foo.json',
fileMatch: ['a://b/foo.json'],
schema: customSchema,
},
},
],
slug: 'test',
timestamps: false,
},
],
}
const sanitizedConfig = await sanitizeConfig(config as Config)
const schema = configToJSONSchema(sanitizedConfig, 'text')
expect(schema?.definitions?.test).toStrictEqual({
additionalProperties: false,
properties: {
id: {
type: 'string',
},
withCustom: customSchema,
jsonWithSchema: customSchema,
},
required: ['id'],
title: 'Test',
type: 'object',
})
})
})

View File

@@ -152,6 +152,7 @@ export function fieldsToJSONSchema(
if (isRequired) requiredFieldNames.add(field.name)
let fieldSchema: JSONSchema4
switch (field.type) {
case 'text':
if (field.hasMany === true) {
@@ -189,7 +190,7 @@ export function fieldsToJSONSchema(
}
case 'json': {
fieldSchema = {
fieldSchema = field.jsonSchema?.schema || {
type: ['object', 'array', 'string', 'number', 'boolean', 'null'],
}
break
@@ -516,6 +517,12 @@ export function fieldsToJSONSchema(
}
}
if ('typescriptSchema' in field && field?.typescriptSchema?.length) {
for (const schema of field.typescriptSchema) {
fieldSchema = schema({ jsonSchema: fieldSchema })
}
}
if (fieldSchema && fieldAffectsData(field)) {
fieldSchemas.set(field.name, fieldSchema)
}
@@ -694,7 +701,7 @@ export function configToJSONSchema(
{ auth: {} },
)
return {
let jsonSchema: JSONSchema4 = {
additionalProperties: false,
definitions: {
...entityDefinitions,
@@ -713,4 +720,12 @@ export function configToJSONSchema(
required: ['user', 'locale', 'collections', 'globals', 'auth'],
title: 'Config',
}
if (config?.typescript?.schema?.length) {
for (const schema of config.typescript.schema) {
jsonSchema = schema({ jsonSchema })
}
}
return jsonSchema
}

View File

@@ -18,6 +18,61 @@ export default buildConfigWithDefaults({
cors: ['http://localhost:3000', 'http://localhost:3001'],
globals: [
MenuGlobal,
{
slug: 'custom-ts',
fields: [
{
name: 'custom',
type: 'text',
typescriptSchema: [
() => ({
enum: ['hello', 'world'],
}),
],
},
{
name: 'withDefinitionsUsage',
type: 'text',
typescriptSchema: [
() => ({
type: 'array',
items: {
$ref: `#/definitions/objectWithNumber`,
},
}),
],
},
{
name: 'json',
type: 'json',
required: true,
jsonSchema: {
uri: 'a://b/foo.json',
fileMatch: ['a://b/foo.json'],
schema: {
type: 'array',
items: {
type: 'object',
additionalProperties: false,
properties: {
id: {
type: 'string',
},
name: {
type: 'string',
},
age: {
type: 'integer',
},
// Add other properties here
},
required: ['id', 'name'], // Specify which properties are required
},
},
},
},
],
},
// ...add more globals here
],
onInit: async (payload) => {
@@ -48,5 +103,21 @@ export default buildConfigWithDefaults({
},
typescript: {
outputFile: path.resolve(dirname, 'payload-types.ts'),
schema: [
({ jsonSchema }) => {
jsonSchema.definitions.objectWithNumber = {
type: 'object',
properties: {
id: {
type: 'number',
required: true,
},
},
required: true,
additionalProperties: false,
}
return jsonSchema
},
],
},
})

View File

@@ -18,6 +18,7 @@ export interface Config {
};
globals: {
menu: Menu;
'custom-ts': CustomT;
};
locale: null;
user: User & {