chore: extracts entityToJSONSchema from generateTypes
This commit is contained in:
@@ -2,428 +2,10 @@
|
||||
import fs from 'fs';
|
||||
import type { JSONSchema4 } from 'json-schema';
|
||||
import { compile } from 'json-schema-to-typescript';
|
||||
import { singular } from 'pluralize';
|
||||
import Logger from '../utilities/logger';
|
||||
import { fieldAffectsData, Field, Option, FieldAffectingData, tabHasName } from '../fields/config/types';
|
||||
import { SanitizedCollectionConfig } from '../collections/config/types';
|
||||
import { SanitizedConfig } from '../config/types';
|
||||
import loadConfig from '../config/load';
|
||||
import { SanitizedGlobalConfig } from '../globals/config/types';
|
||||
import deepCopyObject from '../utilities/deepCopyObject';
|
||||
import { groupOrTabHasRequiredSubfield } from '../utilities/groupOrTabHasRequiredSubfield';
|
||||
import { toWords } from '../utilities/formatLabels';
|
||||
|
||||
const nonOptionalFieldTypes = ['group', 'array', 'blocks'];
|
||||
|
||||
const propertyIsOptional = (field: Field) => {
|
||||
return fieldAffectsData(field) && (field.required === true || nonOptionalFieldTypes.includes(field.type));
|
||||
};
|
||||
|
||||
function getCollectionIDType(collections: SanitizedCollectionConfig[], slug: string): 'string' | 'number' {
|
||||
const matchedCollection = collections.find((collection) => collection.slug === slug);
|
||||
const customIdField = matchedCollection.fields.find((field) => 'name' in field && field.name === 'id');
|
||||
|
||||
if (customIdField && customIdField.type === 'number') {
|
||||
return 'number';
|
||||
}
|
||||
|
||||
return 'string';
|
||||
}
|
||||
|
||||
function returnOptionEnums(options: Option[]): string[] {
|
||||
return options.map((option) => {
|
||||
if (typeof option === 'object' && 'value' in option) {
|
||||
return option.value;
|
||||
}
|
||||
|
||||
return option;
|
||||
});
|
||||
}
|
||||
|
||||
function generateFieldTypes(config: SanitizedConfig, fields: Field[]): {
|
||||
properties: {
|
||||
[k: string]: JSONSchema4;
|
||||
}
|
||||
required: string[]
|
||||
} {
|
||||
let topLevelProps = [];
|
||||
let requiredTopLevelProps = [];
|
||||
|
||||
return {
|
||||
properties: Object.fromEntries(
|
||||
fields.reduce((properties, field) => {
|
||||
let fieldSchema: JSONSchema4;
|
||||
|
||||
switch (field.type) {
|
||||
case 'text':
|
||||
case 'textarea':
|
||||
case 'code':
|
||||
case 'email':
|
||||
case 'date': {
|
||||
fieldSchema = { type: 'string' };
|
||||
break;
|
||||
}
|
||||
|
||||
case 'number': {
|
||||
fieldSchema = { type: 'number' };
|
||||
break;
|
||||
}
|
||||
|
||||
case 'checkbox': {
|
||||
fieldSchema = { type: 'boolean' };
|
||||
break;
|
||||
}
|
||||
|
||||
case 'json': {
|
||||
fieldSchema = { type: 'object' };
|
||||
break;
|
||||
}
|
||||
|
||||
case 'richText': {
|
||||
fieldSchema = {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
},
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'radio': {
|
||||
fieldSchema = {
|
||||
type: 'string',
|
||||
enum: returnOptionEnums(field.options),
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'select': {
|
||||
const selectType: JSONSchema4 = {
|
||||
type: 'string',
|
||||
enum: returnOptionEnums(field.options),
|
||||
};
|
||||
|
||||
if (field.hasMany) {
|
||||
fieldSchema = {
|
||||
type: 'array',
|
||||
items: selectType,
|
||||
};
|
||||
} else {
|
||||
fieldSchema = selectType;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'point': {
|
||||
fieldSchema = {
|
||||
type: 'array',
|
||||
minItems: 2,
|
||||
maxItems: 2,
|
||||
items: [
|
||||
{
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'relationship': {
|
||||
if (Array.isArray(field.relationTo)) {
|
||||
if (field.hasMany) {
|
||||
fieldSchema = {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
oneOf: field.relationTo.map((relation) => {
|
||||
const idFieldType = getCollectionIDType(config.collections, relation);
|
||||
|
||||
return {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
value: {
|
||||
type: idFieldType,
|
||||
},
|
||||
relationTo: {
|
||||
const: relation,
|
||||
},
|
||||
},
|
||||
required: ['value', 'relationTo'],
|
||||
};
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
oneOf: field.relationTo.map((relation) => {
|
||||
return {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
value: {
|
||||
$ref: `#/definitions/${relation}`,
|
||||
},
|
||||
relationTo: {
|
||||
const: relation,
|
||||
},
|
||||
},
|
||||
required: ['value', 'relationTo'],
|
||||
};
|
||||
}),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
fieldSchema = {
|
||||
oneOf: field.relationTo.map((relation) => {
|
||||
const idFieldType = getCollectionIDType(config.collections, relation);
|
||||
|
||||
return {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
value: {
|
||||
oneOf: [
|
||||
{
|
||||
type: idFieldType,
|
||||
},
|
||||
{
|
||||
$ref: `#/definitions/${relation}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
relationTo: {
|
||||
const: relation,
|
||||
},
|
||||
},
|
||||
required: ['value', 'relationTo'],
|
||||
};
|
||||
}),
|
||||
};
|
||||
}
|
||||
} else {
|
||||
const idFieldType = getCollectionIDType(config.collections, field.relationTo);
|
||||
|
||||
if (field.hasMany) {
|
||||
fieldSchema = {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
type: idFieldType,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
$ref: `#/definitions/${field.relationTo}`,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
fieldSchema = {
|
||||
oneOf: [
|
||||
{
|
||||
type: idFieldType,
|
||||
},
|
||||
{
|
||||
$ref: `#/definitions/${field.relationTo}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'upload': {
|
||||
const idFieldType = getCollectionIDType(config.collections, field.relationTo);
|
||||
|
||||
fieldSchema = {
|
||||
oneOf: [
|
||||
{
|
||||
type: idFieldType,
|
||||
},
|
||||
{
|
||||
$ref: `#/definitions/${field.relationTo}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'blocks': {
|
||||
fieldSchema = {
|
||||
type: 'array',
|
||||
items: {
|
||||
oneOf: field.blocks.map((block) => {
|
||||
const blockSchema = generateFieldTypes(config, block.fields);
|
||||
|
||||
return {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
...blockSchema.properties,
|
||||
blockType: {
|
||||
const: block.slug,
|
||||
},
|
||||
},
|
||||
required: [
|
||||
'blockType',
|
||||
...blockSchema.required,
|
||||
],
|
||||
};
|
||||
}),
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'array': {
|
||||
fieldSchema = {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
...generateFieldTypes(config, field.fields),
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'row':
|
||||
case 'collapsible': {
|
||||
const topLevelFields = generateFieldTypes(config, field.fields);
|
||||
requiredTopLevelProps = requiredTopLevelProps.concat(topLevelFields.required);
|
||||
topLevelProps = topLevelProps.concat(Object.entries(topLevelFields.properties).map((prop) => prop));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'tabs': {
|
||||
field.tabs.forEach((tab) => {
|
||||
if (tabHasName(tab)) {
|
||||
const hasRequiredSubfields = groupOrTabHasRequiredSubfield(tab);
|
||||
if (hasRequiredSubfields) requiredTopLevelProps.push(tab.name);
|
||||
|
||||
topLevelProps.push([
|
||||
tab.name,
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
...generateFieldTypes(config, tab.fields),
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
const topLevelFields = generateFieldTypes(config, tab.fields);
|
||||
requiredTopLevelProps = requiredTopLevelProps.concat(topLevelFields.required);
|
||||
topLevelProps = topLevelProps.concat(Object.entries(topLevelFields.properties).map((prop) => prop));
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'group': {
|
||||
fieldSchema = {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
...generateFieldTypes(config, field.fields),
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldSchema && fieldAffectsData(field)) {
|
||||
return [
|
||||
...properties,
|
||||
[
|
||||
field.name,
|
||||
{
|
||||
...fieldSchema,
|
||||
},
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
...properties,
|
||||
...topLevelProps,
|
||||
];
|
||||
}, []),
|
||||
),
|
||||
required: [
|
||||
...fields
|
||||
.filter(propertyIsOptional)
|
||||
.map((field) => (fieldAffectsData(field) ? field.name : '')),
|
||||
...requiredTopLevelProps,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function entityToJsonSchema(config: SanitizedConfig, incomingEntity: SanitizedCollectionConfig | SanitizedGlobalConfig): JSONSchema4 {
|
||||
const entity = deepCopyObject(incomingEntity);
|
||||
const title = entity.typescript?.interface ? entity.typescript.interface : singular(toWords(entity.slug, true));
|
||||
|
||||
const idField: FieldAffectingData = { type: 'text', name: 'id', required: true };
|
||||
const customIdField = entity.fields.find((field) => fieldAffectsData(field) && field.name === 'id') as FieldAffectingData;
|
||||
|
||||
if (customIdField) {
|
||||
customIdField.required = true;
|
||||
} else {
|
||||
entity.fields.unshift(idField);
|
||||
}
|
||||
|
||||
if ('timestamps' in entity && entity.timestamps !== false) {
|
||||
entity.fields.push(
|
||||
{
|
||||
type: 'text',
|
||||
name: 'createdAt',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'updatedAt',
|
||||
required: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
...generateFieldTypes(config, entity.fields),
|
||||
};
|
||||
}
|
||||
|
||||
function generateEntityObject(config: SanitizedConfig, type: 'collections' | 'globals'): JSONSchema4 {
|
||||
return {
|
||||
type: 'object',
|
||||
properties: Object.fromEntries(config[type].map(({ slug }) => [
|
||||
slug,
|
||||
{
|
||||
$ref: `#/definitions/${slug}`,
|
||||
},
|
||||
])),
|
||||
required: config[type].map(({ slug }) => slug),
|
||||
additionalProperties: false,
|
||||
};
|
||||
}
|
||||
import { entityToJsonSchema, generateEntityObject } from '../utilities/entityToJSONSchema';
|
||||
|
||||
function configToJsonSchema(config: SanitizedConfig): JSONSchema4 {
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import express, { NextFunction, Response } from 'express';
|
||||
import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||
import { InitOptions } from './config/types';
|
||||
|
||||
import authenticate from './express/middleware/authenticate';
|
||||
|
||||
422
src/utilities/entityToJSONSchema.ts
Normal file
422
src/utilities/entityToJSONSchema.ts
Normal file
@@ -0,0 +1,422 @@
|
||||
|
||||
import { singular } from 'pluralize';
|
||||
import type { JSONSchema4 } from 'json-schema';
|
||||
import { fieldAffectsData, Field, Option, FieldAffectingData, tabHasName } from '../fields/config/types';
|
||||
import { SanitizedCollectionConfig } from '../collections/config/types';
|
||||
import { SanitizedGlobalConfig } from '../globals/config/types';
|
||||
import deepCopyObject from './deepCopyObject';
|
||||
import { groupOrTabHasRequiredSubfield } from './groupOrTabHasRequiredSubfield';
|
||||
import { toWords } from './formatLabels';
|
||||
import { SanitizedConfig } from '../config/types';
|
||||
|
||||
const nonOptionalFieldTypes = ['group', 'array', 'blocks'];
|
||||
|
||||
const propertyIsOptional = (field: Field) => {
|
||||
return fieldAffectsData(field) && (field.required === true || nonOptionalFieldTypes.includes(field.type));
|
||||
};
|
||||
|
||||
function getCollectionIDType(collections: SanitizedCollectionConfig[], slug: string): 'string' | 'number' {
|
||||
const matchedCollection = collections.find((collection) => collection.slug === slug);
|
||||
const customIdField = matchedCollection.fields.find((field) => 'name' in field && field.name === 'id');
|
||||
|
||||
if (customIdField && customIdField.type === 'number') {
|
||||
return 'number';
|
||||
}
|
||||
|
||||
return 'string';
|
||||
}
|
||||
|
||||
function returnOptionEnums(options: Option[]): string[] {
|
||||
return options.map((option) => {
|
||||
if (typeof option === 'object' && 'value' in option) {
|
||||
return option.value;
|
||||
}
|
||||
|
||||
return option;
|
||||
});
|
||||
}
|
||||
|
||||
function generateFieldTypes(config: SanitizedConfig, fields: Field[]): {
|
||||
properties: {
|
||||
[k: string]: JSONSchema4;
|
||||
}
|
||||
required: string[]
|
||||
} {
|
||||
let topLevelProps = [];
|
||||
let requiredTopLevelProps = [];
|
||||
|
||||
return {
|
||||
properties: Object.fromEntries(
|
||||
fields.reduce((properties, field) => {
|
||||
let fieldSchema: JSONSchema4;
|
||||
|
||||
switch (field.type) {
|
||||
case 'text':
|
||||
case 'textarea':
|
||||
case 'code':
|
||||
case 'email':
|
||||
case 'date': {
|
||||
fieldSchema = { type: 'string' };
|
||||
break;
|
||||
}
|
||||
|
||||
case 'number': {
|
||||
fieldSchema = { type: 'number' };
|
||||
break;
|
||||
}
|
||||
|
||||
case 'checkbox': {
|
||||
fieldSchema = { type: 'boolean' };
|
||||
break;
|
||||
}
|
||||
|
||||
case 'json': {
|
||||
fieldSchema = { type: 'object' };
|
||||
break;
|
||||
}
|
||||
|
||||
case 'richText': {
|
||||
fieldSchema = {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
},
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'radio': {
|
||||
fieldSchema = {
|
||||
type: 'string',
|
||||
enum: returnOptionEnums(field.options),
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'select': {
|
||||
const selectType: JSONSchema4 = {
|
||||
type: 'string',
|
||||
enum: returnOptionEnums(field.options),
|
||||
};
|
||||
|
||||
if (field.hasMany) {
|
||||
fieldSchema = {
|
||||
type: 'array',
|
||||
items: selectType,
|
||||
};
|
||||
} else {
|
||||
fieldSchema = selectType;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'point': {
|
||||
fieldSchema = {
|
||||
type: 'array',
|
||||
minItems: 2,
|
||||
maxItems: 2,
|
||||
items: [
|
||||
{
|
||||
type: 'number',
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'relationship': {
|
||||
if (Array.isArray(field.relationTo)) {
|
||||
if (field.hasMany) {
|
||||
fieldSchema = {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
oneOf: field.relationTo.map((relation) => {
|
||||
const idFieldType = getCollectionIDType(config.collections, relation);
|
||||
|
||||
return {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
value: {
|
||||
type: idFieldType,
|
||||
},
|
||||
relationTo: {
|
||||
const: relation,
|
||||
},
|
||||
},
|
||||
required: ['value', 'relationTo'],
|
||||
};
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
oneOf: field.relationTo.map((relation) => {
|
||||
return {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
value: {
|
||||
$ref: `#/definitions/${relation}`,
|
||||
},
|
||||
relationTo: {
|
||||
const: relation,
|
||||
},
|
||||
},
|
||||
required: ['value', 'relationTo'],
|
||||
};
|
||||
}),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
fieldSchema = {
|
||||
oneOf: field.relationTo.map((relation) => {
|
||||
const idFieldType = getCollectionIDType(config.collections, relation);
|
||||
|
||||
return {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
value: {
|
||||
oneOf: [
|
||||
{
|
||||
type: idFieldType,
|
||||
},
|
||||
{
|
||||
$ref: `#/definitions/${relation}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
relationTo: {
|
||||
const: relation,
|
||||
},
|
||||
},
|
||||
required: ['value', 'relationTo'],
|
||||
};
|
||||
}),
|
||||
};
|
||||
}
|
||||
} else {
|
||||
const idFieldType = getCollectionIDType(config.collections, field.relationTo);
|
||||
|
||||
if (field.hasMany) {
|
||||
fieldSchema = {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
type: idFieldType,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
$ref: `#/definitions/${field.relationTo}`,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
} else {
|
||||
fieldSchema = {
|
||||
oneOf: [
|
||||
{
|
||||
type: idFieldType,
|
||||
},
|
||||
{
|
||||
$ref: `#/definitions/${field.relationTo}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'upload': {
|
||||
const idFieldType = getCollectionIDType(config.collections, field.relationTo);
|
||||
|
||||
fieldSchema = {
|
||||
oneOf: [
|
||||
{
|
||||
type: idFieldType,
|
||||
},
|
||||
{
|
||||
$ref: `#/definitions/${field.relationTo}`,
|
||||
},
|
||||
],
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'blocks': {
|
||||
fieldSchema = {
|
||||
type: 'array',
|
||||
items: {
|
||||
oneOf: field.blocks.map((block) => {
|
||||
const blockSchema = generateFieldTypes(config, block.fields);
|
||||
|
||||
return {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
...blockSchema.properties,
|
||||
blockType: {
|
||||
const: block.slug,
|
||||
},
|
||||
},
|
||||
required: [
|
||||
'blockType',
|
||||
...blockSchema.required,
|
||||
],
|
||||
};
|
||||
}),
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'array': {
|
||||
fieldSchema = {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
...generateFieldTypes(config, field.fields),
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'row':
|
||||
case 'collapsible': {
|
||||
const topLevelFields = generateFieldTypes(config, field.fields);
|
||||
requiredTopLevelProps = requiredTopLevelProps.concat(topLevelFields.required);
|
||||
topLevelProps = topLevelProps.concat(Object.entries(topLevelFields.properties).map((prop) => prop));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'tabs': {
|
||||
field.tabs.forEach((tab) => {
|
||||
if (tabHasName(tab)) {
|
||||
const hasRequiredSubfields = groupOrTabHasRequiredSubfield(tab);
|
||||
if (hasRequiredSubfields) requiredTopLevelProps.push(tab.name);
|
||||
|
||||
topLevelProps.push([
|
||||
tab.name,
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
...generateFieldTypes(config, tab.fields),
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
const topLevelFields = generateFieldTypes(config, tab.fields);
|
||||
requiredTopLevelProps = requiredTopLevelProps.concat(topLevelFields.required);
|
||||
topLevelProps = topLevelProps.concat(Object.entries(topLevelFields.properties).map((prop) => prop));
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'group': {
|
||||
fieldSchema = {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
...generateFieldTypes(config, field.fields),
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldSchema && fieldAffectsData(field)) {
|
||||
return [
|
||||
...properties,
|
||||
[
|
||||
field.name,
|
||||
{
|
||||
...fieldSchema,
|
||||
},
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
...properties,
|
||||
...topLevelProps,
|
||||
];
|
||||
}, []),
|
||||
),
|
||||
required: [
|
||||
...fields
|
||||
.filter(propertyIsOptional)
|
||||
.map((field) => (fieldAffectsData(field) ? field.name : '')),
|
||||
...requiredTopLevelProps,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function entityToJsonSchema(config: SanitizedConfig, incomingEntity: SanitizedCollectionConfig | SanitizedGlobalConfig): JSONSchema4 {
|
||||
const entity = deepCopyObject(incomingEntity);
|
||||
const title = entity.typescript?.interface ? entity.typescript.interface : singular(toWords(entity.slug, true));
|
||||
|
||||
const idField: FieldAffectingData = { type: 'text', name: 'id', required: true };
|
||||
const customIdField = entity.fields.find((field) => fieldAffectsData(field) && field.name === 'id') as FieldAffectingData;
|
||||
|
||||
if (customIdField) {
|
||||
customIdField.required = true;
|
||||
} else {
|
||||
entity.fields.unshift(idField);
|
||||
}
|
||||
|
||||
if ('timestamps' in entity && entity.timestamps !== false) {
|
||||
entity.fields.push(
|
||||
{
|
||||
type: 'text',
|
||||
name: 'createdAt',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'updatedAt',
|
||||
required: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
...generateFieldTypes(config, entity.fields),
|
||||
};
|
||||
}
|
||||
|
||||
export function generateEntityObject(config: SanitizedConfig, type: 'collections' | 'globals'): JSONSchema4 {
|
||||
return {
|
||||
type: 'object',
|
||||
properties: Object.fromEntries(config[type].map(({ slug }) => [
|
||||
slug,
|
||||
{
|
||||
$ref: `#/definitions/${slug}`,
|
||||
},
|
||||
])),
|
||||
required: config[type].map(({ slug }) => slug),
|
||||
additionalProperties: false,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user