@strapi/content-type-builder 5.44.0 → 5.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/components/AIChat/lib/transforms/schemas/fromCTB.js +3 -0
- package/dist/admin/components/AIChat/lib/transforms/schemas/fromCTB.js.map +1 -1
- package/dist/admin/components/AIChat/lib/transforms/schemas/fromCTB.mjs +3 -0
- package/dist/admin/components/AIChat/lib/transforms/schemas/fromCTB.mjs.map +1 -1
- package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.js +53 -1
- package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.js.map +1 -1
- package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.mjs +53 -1
- package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.mjs.map +1 -1
- package/dist/admin/src/components/AIChat/lib/types/schema.d.ts +2 -0
- package/dist/server/controllers/validation/content-type.js.map +1 -1
- package/dist/server/controllers/validation/content-type.mjs.map +1 -1
- package/dist/server/controllers/validation/schema.js +5 -2
- package/dist/server/controllers/validation/schema.js.map +1 -1
- package/dist/server/controllers/validation/schema.mjs +6 -3
- package/dist/server/controllers/validation/schema.mjs.map +1 -1
- package/dist/server/services/api-handler.js +8 -0
- package/dist/server/services/api-handler.js.map +1 -1
- package/dist/server/services/api-handler.mjs +8 -0
- package/dist/server/services/api-handler.mjs.map +1 -1
- package/dist/server/services/schema-builder/content-type-builder.js +3 -2
- package/dist/server/services/schema-builder/content-type-builder.js.map +1 -1
- package/dist/server/services/schema-builder/content-type-builder.mjs +3 -2
- package/dist/server/services/schema-builder/content-type-builder.mjs.map +1 -1
- package/dist/server/services/schema.js +8 -6
- package/dist/server/services/schema.js.map +1 -1
- package/dist/server/services/schema.mjs +8 -6
- package/dist/server/services/schema.mjs.map +1 -1
- package/dist/server/src/controllers/validation/content-type.d.ts +1 -0
- package/dist/server/src/controllers/validation/content-type.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/schema.d.ts +9 -1
- package/dist/server/src/controllers/validation/schema.d.ts.map +1 -1
- package/dist/server/src/services/api-handler.d.ts.map +1 -1
- package/dist/server/src/services/schema-builder/content-type-builder.d.ts.map +1 -1
- package/dist/server/src/services/schema.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -32,6 +32,9 @@ const transformCTBToChat = (schema)=>{
|
|
|
32
32
|
action: 'create',
|
|
33
33
|
name: schema.info.pluralName,
|
|
34
34
|
uid: schema.uid,
|
|
35
|
+
...schema.plugin ? {
|
|
36
|
+
plugin: schema.plugin
|
|
37
|
+
} : {},
|
|
35
38
|
attributes: transformAttributesFromCTBToChat(schema.attributes),
|
|
36
39
|
// @ts-expect-error - injected from previous ai messages
|
|
37
40
|
sources: schema.sources,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fromCTB.js","sources":["../../../../../../../admin/src/components/AIChat/lib/transforms/schemas/fromCTB.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\nimport { Schema } from '../../types/schema';\n\nimport type { ContentType, Component, AnyAttribute } from '../../../../../types';\n\nconst transformAttributesFromCTBToChat = (attributes: AnyAttribute[]) => {\n return attributes.reduce(\n (acc, attribute) => {\n const { name, ...rest } = attribute;\n\n return {\n ...acc,\n [name]: rest,\n };\n },\n {} as Record<string, Omit<AnyAttribute, 'name'>>\n );\n};\n\nexport const transformCTBToChat = (schema: ContentType | Component): Schema => {\n if (schema.modelType === 'component') {\n return {\n category: schema.category,\n kind: 'component',\n action: 'create',\n modelType: 'component',\n description: schema.info.description,\n name: schema.info.displayName,\n\n uid: schema.uid as any,\n attributes: transformAttributesFromCTBToChat(schema.attributes),\n // @ts-expect-error - injected from previous ai messages\n sources: schema.sources,\n } as any;\n }\n\n return {\n kind: schema.kind,\n modelType: schema.modelType,\n description: schema.info.description,\n action: 'create',\n name: schema.info.pluralName,\n uid: schema.uid as any,\n attributes: transformAttributesFromCTBToChat(schema.attributes),\n // @ts-expect-error - injected from previous ai messages\n sources: schema.sources,\n options: {\n draftAndPublish: schema.options?.draftAndPublish,\n localized: false,\n },\n } as any;\n};\n"],"names":["transformAttributesFromCTBToChat","attributes","reduce","acc","attribute","name","rest","transformCTBToChat","schema","modelType","category","kind","action","description","info","displayName","uid","sources","pluralName","options","draftAndPublish","localized"],"mappings":";;AAAA;AAKA,MAAMA,mCAAmC,CAACC,UAAAA,GAAAA;AACxC,IAAA,OAAOA,UAAAA,CAAWC,MAAM,CACtB,CAACC,GAAAA,EAAKC,SAAAA,GAAAA;AACJ,QAAA,MAAM,EAAEC,IAAI,EAAE,GAAGC,MAAM,GAAGF,SAAAA;QAE1B,OAAO;AACL,YAAA,GAAGD,GAAG;AACN,YAAA,CAACE,OAAOC;AACV,SAAA;AACF,IAAA,CAAA,EACA,EAAC,CAAA;AAEL,CAAA;AAEO,MAAMC,qBAAqB,CAACC,MAAAA,GAAAA;IACjC,IAAIA,MAAAA,CAAOC,SAAS,KAAK,WAAA,EAAa;QACpC,OAAO;AACLC,YAAAA,QAAAA,EAAUF,OAAOE,QAAQ;YACzBC,IAAAA,EAAM,WAAA;YACNC,MAAAA,EAAQ,QAAA;YACRH,SAAAA,EAAW,WAAA;YACXI,WAAAA,EAAaL,MAAAA,CAAOM,IAAI,CAACD,WAAW;YACpCR,IAAAA,EAAMG,MAAAA,CAAOM,IAAI,CAACC,WAAW;AAE7BC,YAAAA,GAAAA,EAAKR,OAAOQ,GAAG;YACff,UAAAA,EAAYD,gCAAAA,CAAiCQ,OAAOP,UAAU,CAAA;;AAE9DgB,YAAAA,OAAAA,EAAST,OAAOS;AAClB,SAAA;AACF,IAAA;IAEA,OAAO;AACLN,QAAAA,IAAAA,EAAMH,OAAOG,IAAI;AACjBF,QAAAA,SAAAA,EAAWD,OAAOC,SAAS;QAC3BI,WAAAA,EAAaL,MAAAA,CAAOM,IAAI,CAACD,WAAW;QACpCD,MAAAA,EAAQ,QAAA;QACRP,IAAAA,EAAMG,MAAAA,CAAOM,IAAI,CAACI,UAAU;AAC5BF,QAAAA,GAAAA,EAAKR,OAAOQ,GAAG;
|
|
1
|
+
{"version":3,"file":"fromCTB.js","sources":["../../../../../../../admin/src/components/AIChat/lib/transforms/schemas/fromCTB.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\nimport { Schema } from '../../types/schema';\n\nimport type { ContentType, Component, AnyAttribute } from '../../../../../types';\n\nconst transformAttributesFromCTBToChat = (attributes: AnyAttribute[]) => {\n return attributes.reduce(\n (acc, attribute) => {\n const { name, ...rest } = attribute;\n\n return {\n ...acc,\n [name]: rest,\n };\n },\n {} as Record<string, Omit<AnyAttribute, 'name'>>\n );\n};\n\nexport const transformCTBToChat = (schema: ContentType | Component): Schema => {\n if (schema.modelType === 'component') {\n return {\n category: schema.category,\n kind: 'component',\n action: 'create',\n modelType: 'component',\n description: schema.info.description,\n name: schema.info.displayName,\n\n uid: schema.uid as any,\n attributes: transformAttributesFromCTBToChat(schema.attributes),\n // @ts-expect-error - injected from previous ai messages\n sources: schema.sources,\n } as any;\n }\n\n return {\n kind: schema.kind,\n modelType: schema.modelType,\n description: schema.info.description,\n action: 'create',\n name: schema.info.pluralName,\n uid: schema.uid as any,\n ...(schema.plugin ? { plugin: schema.plugin } : {}),\n attributes: transformAttributesFromCTBToChat(schema.attributes),\n // @ts-expect-error - injected from previous ai messages\n sources: schema.sources,\n options: {\n draftAndPublish: schema.options?.draftAndPublish,\n localized: false,\n },\n } as any;\n};\n"],"names":["transformAttributesFromCTBToChat","attributes","reduce","acc","attribute","name","rest","transformCTBToChat","schema","modelType","category","kind","action","description","info","displayName","uid","sources","pluralName","plugin","options","draftAndPublish","localized"],"mappings":";;AAAA;AAKA,MAAMA,mCAAmC,CAACC,UAAAA,GAAAA;AACxC,IAAA,OAAOA,UAAAA,CAAWC,MAAM,CACtB,CAACC,GAAAA,EAAKC,SAAAA,GAAAA;AACJ,QAAA,MAAM,EAAEC,IAAI,EAAE,GAAGC,MAAM,GAAGF,SAAAA;QAE1B,OAAO;AACL,YAAA,GAAGD,GAAG;AACN,YAAA,CAACE,OAAOC;AACV,SAAA;AACF,IAAA,CAAA,EACA,EAAC,CAAA;AAEL,CAAA;AAEO,MAAMC,qBAAqB,CAACC,MAAAA,GAAAA;IACjC,IAAIA,MAAAA,CAAOC,SAAS,KAAK,WAAA,EAAa;QACpC,OAAO;AACLC,YAAAA,QAAAA,EAAUF,OAAOE,QAAQ;YACzBC,IAAAA,EAAM,WAAA;YACNC,MAAAA,EAAQ,QAAA;YACRH,SAAAA,EAAW,WAAA;YACXI,WAAAA,EAAaL,MAAAA,CAAOM,IAAI,CAACD,WAAW;YACpCR,IAAAA,EAAMG,MAAAA,CAAOM,IAAI,CAACC,WAAW;AAE7BC,YAAAA,GAAAA,EAAKR,OAAOQ,GAAG;YACff,UAAAA,EAAYD,gCAAAA,CAAiCQ,OAAOP,UAAU,CAAA;;AAE9DgB,YAAAA,OAAAA,EAAST,OAAOS;AAClB,SAAA;AACF,IAAA;IAEA,OAAO;AACLN,QAAAA,IAAAA,EAAMH,OAAOG,IAAI;AACjBF,QAAAA,SAAAA,EAAWD,OAAOC,SAAS;QAC3BI,WAAAA,EAAaL,MAAAA,CAAOM,IAAI,CAACD,WAAW;QACpCD,MAAAA,EAAQ,QAAA;QACRP,IAAAA,EAAMG,MAAAA,CAAOM,IAAI,CAACI,UAAU;AAC5BF,QAAAA,GAAAA,EAAKR,OAAOQ,GAAG;QACf,GAAIR,MAAAA,CAAOW,MAAM,GAAG;AAAEA,YAAAA,MAAAA,EAAQX,OAAOW;AAAO,SAAA,GAAI,EAAE;QAClDlB,UAAAA,EAAYD,gCAAAA,CAAiCQ,OAAOP,UAAU,CAAA;;AAE9DgB,QAAAA,OAAAA,EAAST,OAAOS,OAAO;QACvBG,OAAAA,EAAS;YACPC,eAAAA,EAAiBb,MAAAA,CAAOY,OAAO,EAAEC,eAAAA;YACjCC,SAAAA,EAAW;AACb;AACF,KAAA;AACF;;;;"}
|
|
@@ -30,6 +30,9 @@ const transformCTBToChat = (schema)=>{
|
|
|
30
30
|
action: 'create',
|
|
31
31
|
name: schema.info.pluralName,
|
|
32
32
|
uid: schema.uid,
|
|
33
|
+
...schema.plugin ? {
|
|
34
|
+
plugin: schema.plugin
|
|
35
|
+
} : {},
|
|
33
36
|
attributes: transformAttributesFromCTBToChat(schema.attributes),
|
|
34
37
|
// @ts-expect-error - injected from previous ai messages
|
|
35
38
|
sources: schema.sources,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fromCTB.mjs","sources":["../../../../../../../admin/src/components/AIChat/lib/transforms/schemas/fromCTB.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\nimport { Schema } from '../../types/schema';\n\nimport type { ContentType, Component, AnyAttribute } from '../../../../../types';\n\nconst transformAttributesFromCTBToChat = (attributes: AnyAttribute[]) => {\n return attributes.reduce(\n (acc, attribute) => {\n const { name, ...rest } = attribute;\n\n return {\n ...acc,\n [name]: rest,\n };\n },\n {} as Record<string, Omit<AnyAttribute, 'name'>>\n );\n};\n\nexport const transformCTBToChat = (schema: ContentType | Component): Schema => {\n if (schema.modelType === 'component') {\n return {\n category: schema.category,\n kind: 'component',\n action: 'create',\n modelType: 'component',\n description: schema.info.description,\n name: schema.info.displayName,\n\n uid: schema.uid as any,\n attributes: transformAttributesFromCTBToChat(schema.attributes),\n // @ts-expect-error - injected from previous ai messages\n sources: schema.sources,\n } as any;\n }\n\n return {\n kind: schema.kind,\n modelType: schema.modelType,\n description: schema.info.description,\n action: 'create',\n name: schema.info.pluralName,\n uid: schema.uid as any,\n attributes: transformAttributesFromCTBToChat(schema.attributes),\n // @ts-expect-error - injected from previous ai messages\n sources: schema.sources,\n options: {\n draftAndPublish: schema.options?.draftAndPublish,\n localized: false,\n },\n } as any;\n};\n"],"names":["transformAttributesFromCTBToChat","attributes","reduce","acc","attribute","name","rest","transformCTBToChat","schema","modelType","category","kind","action","description","info","displayName","uid","sources","pluralName","options","draftAndPublish","localized"],"mappings":"AAAA;AAKA,MAAMA,mCAAmC,CAACC,UAAAA,GAAAA;AACxC,IAAA,OAAOA,UAAAA,CAAWC,MAAM,CACtB,CAACC,GAAAA,EAAKC,SAAAA,GAAAA;AACJ,QAAA,MAAM,EAAEC,IAAI,EAAE,GAAGC,MAAM,GAAGF,SAAAA;QAE1B,OAAO;AACL,YAAA,GAAGD,GAAG;AACN,YAAA,CAACE,OAAOC;AACV,SAAA;AACF,IAAA,CAAA,EACA,EAAC,CAAA;AAEL,CAAA;AAEO,MAAMC,qBAAqB,CAACC,MAAAA,GAAAA;IACjC,IAAIA,MAAAA,CAAOC,SAAS,KAAK,WAAA,EAAa;QACpC,OAAO;AACLC,YAAAA,QAAAA,EAAUF,OAAOE,QAAQ;YACzBC,IAAAA,EAAM,WAAA;YACNC,MAAAA,EAAQ,QAAA;YACRH,SAAAA,EAAW,WAAA;YACXI,WAAAA,EAAaL,MAAAA,CAAOM,IAAI,CAACD,WAAW;YACpCR,IAAAA,EAAMG,MAAAA,CAAOM,IAAI,CAACC,WAAW;AAE7BC,YAAAA,GAAAA,EAAKR,OAAOQ,GAAG;YACff,UAAAA,EAAYD,gCAAAA,CAAiCQ,OAAOP,UAAU,CAAA;;AAE9DgB,YAAAA,OAAAA,EAAST,OAAOS;AAClB,SAAA;AACF,IAAA;IAEA,OAAO;AACLN,QAAAA,IAAAA,EAAMH,OAAOG,IAAI;AACjBF,QAAAA,SAAAA,EAAWD,OAAOC,SAAS;QAC3BI,WAAAA,EAAaL,MAAAA,CAAOM,IAAI,CAACD,WAAW;QACpCD,MAAAA,EAAQ,QAAA;QACRP,IAAAA,EAAMG,MAAAA,CAAOM,IAAI,CAACI,UAAU;AAC5BF,QAAAA,GAAAA,EAAKR,OAAOQ,GAAG;
|
|
1
|
+
{"version":3,"file":"fromCTB.mjs","sources":["../../../../../../../admin/src/components/AIChat/lib/transforms/schemas/fromCTB.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\nimport { Schema } from '../../types/schema';\n\nimport type { ContentType, Component, AnyAttribute } from '../../../../../types';\n\nconst transformAttributesFromCTBToChat = (attributes: AnyAttribute[]) => {\n return attributes.reduce(\n (acc, attribute) => {\n const { name, ...rest } = attribute;\n\n return {\n ...acc,\n [name]: rest,\n };\n },\n {} as Record<string, Omit<AnyAttribute, 'name'>>\n );\n};\n\nexport const transformCTBToChat = (schema: ContentType | Component): Schema => {\n if (schema.modelType === 'component') {\n return {\n category: schema.category,\n kind: 'component',\n action: 'create',\n modelType: 'component',\n description: schema.info.description,\n name: schema.info.displayName,\n\n uid: schema.uid as any,\n attributes: transformAttributesFromCTBToChat(schema.attributes),\n // @ts-expect-error - injected from previous ai messages\n sources: schema.sources,\n } as any;\n }\n\n return {\n kind: schema.kind,\n modelType: schema.modelType,\n description: schema.info.description,\n action: 'create',\n name: schema.info.pluralName,\n uid: schema.uid as any,\n ...(schema.plugin ? { plugin: schema.plugin } : {}),\n attributes: transformAttributesFromCTBToChat(schema.attributes),\n // @ts-expect-error - injected from previous ai messages\n sources: schema.sources,\n options: {\n draftAndPublish: schema.options?.draftAndPublish,\n localized: false,\n },\n } as any;\n};\n"],"names":["transformAttributesFromCTBToChat","attributes","reduce","acc","attribute","name","rest","transformCTBToChat","schema","modelType","category","kind","action","description","info","displayName","uid","sources","pluralName","plugin","options","draftAndPublish","localized"],"mappings":"AAAA;AAKA,MAAMA,mCAAmC,CAACC,UAAAA,GAAAA;AACxC,IAAA,OAAOA,UAAAA,CAAWC,MAAM,CACtB,CAACC,GAAAA,EAAKC,SAAAA,GAAAA;AACJ,QAAA,MAAM,EAAEC,IAAI,EAAE,GAAGC,MAAM,GAAGF,SAAAA;QAE1B,OAAO;AACL,YAAA,GAAGD,GAAG;AACN,YAAA,CAACE,OAAOC;AACV,SAAA;AACF,IAAA,CAAA,EACA,EAAC,CAAA;AAEL,CAAA;AAEO,MAAMC,qBAAqB,CAACC,MAAAA,GAAAA;IACjC,IAAIA,MAAAA,CAAOC,SAAS,KAAK,WAAA,EAAa;QACpC,OAAO;AACLC,YAAAA,QAAAA,EAAUF,OAAOE,QAAQ;YACzBC,IAAAA,EAAM,WAAA;YACNC,MAAAA,EAAQ,QAAA;YACRH,SAAAA,EAAW,WAAA;YACXI,WAAAA,EAAaL,MAAAA,CAAOM,IAAI,CAACD,WAAW;YACpCR,IAAAA,EAAMG,MAAAA,CAAOM,IAAI,CAACC,WAAW;AAE7BC,YAAAA,GAAAA,EAAKR,OAAOQ,GAAG;YACff,UAAAA,EAAYD,gCAAAA,CAAiCQ,OAAOP,UAAU,CAAA;;AAE9DgB,YAAAA,OAAAA,EAAST,OAAOS;AAClB,SAAA;AACF,IAAA;IAEA,OAAO;AACLN,QAAAA,IAAAA,EAAMH,OAAOG,IAAI;AACjBF,QAAAA,SAAAA,EAAWD,OAAOC,SAAS;QAC3BI,WAAAA,EAAaL,MAAAA,CAAOM,IAAI,CAACD,WAAW;QACpCD,MAAAA,EAAQ,QAAA;QACRP,IAAAA,EAAMG,MAAAA,CAAOM,IAAI,CAACI,UAAU;AAC5BF,QAAAA,GAAAA,EAAKR,OAAOQ,GAAG;QACf,GAAIR,MAAAA,CAAOW,MAAM,GAAG;AAAEA,YAAAA,MAAAA,EAAQX,OAAOW;AAAO,SAAA,GAAI,EAAE;QAClDlB,UAAAA,EAAYD,gCAAAA,CAAiCQ,OAAOP,UAAU,CAAA;;AAE9DgB,QAAAA,OAAAA,EAAST,OAAOS,OAAO;QACvBG,OAAAA,EAAS;YACPC,eAAAA,EAAiBb,MAAAA,CAAOY,OAAO,EAAEC,eAAAA;YACjCC,SAAAA,EAAW;AACb;AACF,KAAA;AACF;;;;"}
|
|
@@ -5,6 +5,20 @@ var omit = require('lodash/omit');
|
|
|
5
5
|
var pluralize = require('pluralize');
|
|
6
6
|
|
|
7
7
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
8
|
+
const isPluginContentTypeUid = (uid)=>uid.startsWith('plugin::');
|
|
9
|
+
/**
|
|
10
|
+
* Plugin / extension content-types use server-derived identity (globalId, collectionName, …).
|
|
11
|
+
* The AI chat uses a simplified shape that would otherwise overwrite those fields incorrectly.
|
|
12
|
+
*/ const isPluginContentType = (schema, oldSchema)=>{
|
|
13
|
+
if (schema.plugin || isPluginContentTypeUid(schema.uid)) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
if (oldSchema && 'modelType' in oldSchema && oldSchema.modelType === 'contentType') {
|
|
17
|
+
const ct = oldSchema;
|
|
18
|
+
return Boolean(ct.plugin) || isPluginContentTypeUid(String(ct.uid));
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
};
|
|
8
22
|
const ACTION_TO_STATUS = {
|
|
9
23
|
create: 'NEW',
|
|
10
24
|
remove: 'REMOVED',
|
|
@@ -115,7 +129,7 @@ const ACTION_TO_STATUS = {
|
|
|
115
129
|
globalId: singularName
|
|
116
130
|
};
|
|
117
131
|
}
|
|
118
|
-
|
|
132
|
+
const contentTypeBase = {
|
|
119
133
|
uid: schema.uid,
|
|
120
134
|
modelType: schema.modelType,
|
|
121
135
|
modelName: singularName,
|
|
@@ -144,6 +158,44 @@ const ACTION_TO_STATUS = {
|
|
|
144
158
|
globalId: singularName,
|
|
145
159
|
restrictRelationsTo: null
|
|
146
160
|
};
|
|
161
|
+
if (isPluginContentType(schema, oldSchema) && oldSchema && oldSchema.modelType === 'contentType') {
|
|
162
|
+
const prev = oldSchema;
|
|
163
|
+
return {
|
|
164
|
+
...contentTypeBase,
|
|
165
|
+
plugin: prev.plugin ?? schema.plugin,
|
|
166
|
+
globalId: prev.globalId,
|
|
167
|
+
modelName: prev.modelName,
|
|
168
|
+
collectionName: prev.collectionName,
|
|
169
|
+
info: {
|
|
170
|
+
...contentTypeBase.info,
|
|
171
|
+
singularName: prev.info.singularName,
|
|
172
|
+
pluralName: prev.info.pluralName
|
|
173
|
+
},
|
|
174
|
+
options: {
|
|
175
|
+
...prev.options,
|
|
176
|
+
...contentTypeBase.options,
|
|
177
|
+
draftAndPublish: schema.options?.draftAndPublish ?? prev.options?.draftAndPublish ?? true
|
|
178
|
+
},
|
|
179
|
+
pluginOptions: {
|
|
180
|
+
...prev.pluginOptions,
|
|
181
|
+
...contentTypeBase.pluginOptions,
|
|
182
|
+
i18n: {
|
|
183
|
+
...prev.pluginOptions?.i18n ?? {},
|
|
184
|
+
...contentTypeBase.pluginOptions?.i18n ?? {},
|
|
185
|
+
localized: schema.options?.localized ?? prev.pluginOptions?.i18n?.localized ?? false
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
visible: prev.visible,
|
|
189
|
+
restrictRelationsTo: prev.restrictRelationsTo
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (isPluginContentType(schema, oldSchema) && schema.plugin) {
|
|
193
|
+
return {
|
|
194
|
+
...contentTypeBase,
|
|
195
|
+
plugin: schema.plugin
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
return contentTypeBase;
|
|
147
199
|
};
|
|
148
200
|
|
|
149
201
|
exports.transformAttributesFromChatToCTB = transformAttributesFromChatToCTB;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toCTB.js","sources":["../../../../../../../admin/src/components/AIChat/lib/transforms/schemas/toCTB.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\nimport isEqual from 'lodash/isEqual';\nimport omit from 'lodash/omit';\nimport pluralize from 'pluralize';\n\nimport { Schema } from '../../types/schema';\n\nimport type { ContentType, Component, AnyAttribute } from '../../../../../types';\n\nconst ACTION_TO_STATUS: Record<Schema['action'], ContentType['status']> = {\n create: 'NEW',\n remove: 'REMOVED',\n update: 'CHANGED',\n};\n\n/**\n * Creates a new attribute with the specified status\n */\nconst createAttributeWithStatus = (\n name: string,\n attributeData: Record<string, any>,\n status: AnyAttribute['status']\n): AnyAttribute =>\n ({\n ...attributeData,\n name,\n status,\n }) as AnyAttribute;\n\n/**\n * Determines the status of an attribute by comparing new and old versions\n */\nconst determineAttributeStatus = (\n newAttr: Record<string, any>,\n oldAttr?: AnyAttribute,\n oldSchema?: ContentType | Component\n): AnyAttribute['status'] => {\n if (!oldAttr) {\n return 'NEW';\n }\n\n // If the schema was already new, don't mark attributes as changed, keep them as new.\n if (oldSchema?.status === 'NEW') {\n return 'NEW';\n }\n\n // Compare attributes without the status field to determine if they've changed\n const newAttrWithoutStatus = omit(newAttr, ['status']);\n const oldAttrWithoutStatus = omit(oldAttr, ['status']);\n\n if (!isEqual(newAttrWithoutStatus, oldAttrWithoutStatus)) {\n return 'CHANGED';\n }\n\n // If unchanged, keep the previous status\n return oldAttr.status;\n};\n\n/**\n * Determines the status of a schema by comparing action and checking if oldSchema exists\n */\nconst transformStatusFromChatToCTB = (\n schema: Schema,\n oldSchema?: ContentType | Component\n): ContentType['status'] => {\n // If schema has an action, use the mapped status\n if (schema.action) {\n return ACTION_TO_STATUS[schema.action];\n }\n\n // If oldSchema doesn't exist, it's a new schema\n if (!oldSchema) {\n return 'NEW';\n }\n\n // If no action is specified and oldSchema exists, keep the existing status\n return oldSchema.status;\n};\n\n/**\n * Transform attributes from Chat format to CTB format\n * Also performs a diff to determine the status of each attribute\n */\nexport const transformAttributesFromChatToCTB = (\n { action, attributes }: Schema,\n oldSchema?: ContentType | Component\n): AnyAttribute[] => {\n // If it's a new schema or no oldAttributes provided, all attributes are NEW\n if (action === 'create' || !oldSchema) {\n return Object.entries(attributes).map(([name, attribute]) =>\n createAttributeWithStatus(name, attribute, 'NEW')\n );\n }\n\n // Convert old attributes array to a lookup map for faster access\n const oldAttributesMap = oldSchema.attributes.reduce(\n (acc, attr) => ({ ...acc, [attr.name]: attr }),\n {} as Record<string, AnyAttribute>\n );\n\n // Process current attributes (new and changed)\n const processedAttributes = Object.entries(attributes).map(([name, attr]) => {\n const oldAttr = oldAttributesMap[name];\n const status = determineAttributeStatus({ ...attr, name }, oldAttr, oldSchema);\n\n return createAttributeWithStatus(name, attr, status);\n });\n\n // No need to mark removed attributes if the old schema is new, just remove it from the list\n // TODO: Else a validation error occurs on the backend side.\n if (oldSchema?.status === 'NEW') {\n return processedAttributes;\n }\n\n // Find removed attributes (exist in old but not in new)\n const removedAttributes = Object.entries(oldAttributesMap)\n .filter(([name]) => !attributes[name])\n .map(([name, oldAttr]) => createAttributeWithStatus(name, oldAttr, 'REMOVED'));\n\n // Combine both sets of attributes\n return [...processedAttributes, ...removedAttributes];\n};\n\n/**\n * Transform schema format\n * AI chat -> CTB\n *\n * The AI chat returns a simplified format, and this layer transforms it to be compatible with the CTB reducer.\n *\n * We need to keep track of which changes have been made\n */\nexport const transformChatToCTB = (\n schema: Schema,\n oldSchema?: ContentType | Component\n): ContentType | Component => {\n const singularName = pluralize.singular(schema.name).toLowerCase().replace(/ /g, '-');\n const pluralName = pluralize.plural(schema.name).toLowerCase().replace(/ /g, '-');\n\n if (schema.modelType === 'component') {\n return {\n category: schema.category || 'default',\n modelName: singularName,\n attributes: transformAttributesFromChatToCTB(schema, oldSchema),\n info: {\n displayName: schema.name,\n description: schema.description,\n // TODO\n // icon: schema.icon,\n },\n modelType: schema.modelType,\n uid: schema.uid as any,\n collectionName: pluralName,\n status: transformStatusFromChatToCTB(schema, oldSchema),\n globalId: singularName,\n } satisfies Component;\n }\n\n return {\n uid: schema.uid as any,\n modelType: schema.modelType,\n modelName: singularName,\n kind: schema.kind!,\n info: {\n displayName: schema.name.charAt(0).toUpperCase() + schema.name.slice(1),\n // Always keep the old by default\n // @ts-expect-error - not in types\n singularName: oldSchema?.info?.singularName || singularName,\n // Always keep the old by default\n // @ts-expect-error - not in types\n pluralName: oldSchema?.info?.pluralName || pluralName,\n },\n collectionName: pluralName,\n attributes: transformAttributesFromChatToCTB(schema, oldSchema),\n options: {\n draftAndPublish: schema.options?.draftAndPublish ?? true,\n },\n pluginOptions: {\n i18n: {\n localized: schema.options?.localized ?? false,\n },\n },\n visible: true,\n status: transformStatusFromChatToCTB(schema, oldSchema),\n globalId: singularName,\n restrictRelationsTo: null, // TODO: not sure what this is about\n } satisfies ContentType;\n};\n"],"names":["ACTION_TO_STATUS","create","remove","update","createAttributeWithStatus","name","attributeData","status","determineAttributeStatus","newAttr","oldAttr","oldSchema","newAttrWithoutStatus","omit","oldAttrWithoutStatus","isEqual","transformStatusFromChatToCTB","schema","action","transformAttributesFromChatToCTB","attributes","Object","entries","map","attribute","oldAttributesMap","reduce","acc","attr","processedAttributes","removedAttributes","filter","transformChatToCTB","singularName","pluralize","singular","toLowerCase","replace","pluralName","plural","modelType","category","modelName","info","displayName","description","uid","collectionName","globalId","kind","charAt","toUpperCase","slice","options","draftAndPublish","pluginOptions","i18n","localized","visible","restrictRelationsTo"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toCTB.js","sources":["../../../../../../../admin/src/components/AIChat/lib/transforms/schemas/toCTB.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\nimport isEqual from 'lodash/isEqual';\nimport omit from 'lodash/omit';\nimport pluralize from 'pluralize';\n\nimport { Schema } from '../../types/schema';\n\nimport type { ContentType, Component, AnyAttribute } from '../../../../../types';\n\nconst isPluginContentTypeUid = (uid: string) => uid.startsWith('plugin::');\n\n/**\n * Plugin / extension content-types use server-derived identity (globalId, collectionName, …).\n * The AI chat uses a simplified shape that would otherwise overwrite those fields incorrectly.\n */\nconst isPluginContentType = (schema: Schema, oldSchema?: ContentType | Component): boolean => {\n if (schema.plugin || isPluginContentTypeUid(schema.uid)) {\n return true;\n }\n if (oldSchema && 'modelType' in oldSchema && oldSchema.modelType === 'contentType') {\n const ct = oldSchema as ContentType;\n return Boolean(ct.plugin) || isPluginContentTypeUid(String(ct.uid));\n }\n return false;\n};\n\nconst ACTION_TO_STATUS: Record<Schema['action'], ContentType['status']> = {\n create: 'NEW',\n remove: 'REMOVED',\n update: 'CHANGED',\n};\n\n/**\n * Creates a new attribute with the specified status\n */\nconst createAttributeWithStatus = (\n name: string,\n attributeData: Record<string, any>,\n status: AnyAttribute['status']\n): AnyAttribute =>\n ({\n ...attributeData,\n name,\n status,\n }) as AnyAttribute;\n\n/**\n * Determines the status of an attribute by comparing new and old versions\n */\nconst determineAttributeStatus = (\n newAttr: Record<string, any>,\n oldAttr?: AnyAttribute,\n oldSchema?: ContentType | Component\n): AnyAttribute['status'] => {\n if (!oldAttr) {\n return 'NEW';\n }\n\n // If the schema was already new, don't mark attributes as changed, keep them as new.\n if (oldSchema?.status === 'NEW') {\n return 'NEW';\n }\n\n // Compare attributes without the status field to determine if they've changed\n const newAttrWithoutStatus = omit(newAttr, ['status']);\n const oldAttrWithoutStatus = omit(oldAttr, ['status']);\n\n if (!isEqual(newAttrWithoutStatus, oldAttrWithoutStatus)) {\n return 'CHANGED';\n }\n\n // If unchanged, keep the previous status\n return oldAttr.status;\n};\n\n/**\n * Determines the status of a schema by comparing action and checking if oldSchema exists\n */\nconst transformStatusFromChatToCTB = (\n schema: Schema,\n oldSchema?: ContentType | Component\n): ContentType['status'] => {\n // If schema has an action, use the mapped status\n if (schema.action) {\n return ACTION_TO_STATUS[schema.action];\n }\n\n // If oldSchema doesn't exist, it's a new schema\n if (!oldSchema) {\n return 'NEW';\n }\n\n // If no action is specified and oldSchema exists, keep the existing status\n return oldSchema.status;\n};\n\n/**\n * Transform attributes from Chat format to CTB format\n * Also performs a diff to determine the status of each attribute\n */\nexport const transformAttributesFromChatToCTB = (\n { action, attributes }: Schema,\n oldSchema?: ContentType | Component\n): AnyAttribute[] => {\n // If it's a new schema or no oldAttributes provided, all attributes are NEW\n if (action === 'create' || !oldSchema) {\n return Object.entries(attributes).map(([name, attribute]) =>\n createAttributeWithStatus(name, attribute, 'NEW')\n );\n }\n\n // Convert old attributes array to a lookup map for faster access\n const oldAttributesMap = oldSchema.attributes.reduce(\n (acc, attr) => ({ ...acc, [attr.name]: attr }),\n {} as Record<string, AnyAttribute>\n );\n\n // Process current attributes (new and changed)\n const processedAttributes = Object.entries(attributes).map(([name, attr]) => {\n const oldAttr = oldAttributesMap[name];\n const status = determineAttributeStatus({ ...attr, name }, oldAttr, oldSchema);\n\n return createAttributeWithStatus(name, attr, status);\n });\n\n // No need to mark removed attributes if the old schema is new, just remove it from the list\n // TODO: Else a validation error occurs on the backend side.\n if (oldSchema?.status === 'NEW') {\n return processedAttributes;\n }\n\n // Find removed attributes (exist in old but not in new)\n const removedAttributes = Object.entries(oldAttributesMap)\n .filter(([name]) => !attributes[name])\n .map(([name, oldAttr]) => createAttributeWithStatus(name, oldAttr, 'REMOVED'));\n\n // Combine both sets of attributes\n return [...processedAttributes, ...removedAttributes];\n};\n\n/**\n * Transform schema format\n * AI chat -> CTB\n *\n * The AI chat returns a simplified format, and this layer transforms it to be compatible with the CTB reducer.\n *\n * We need to keep track of which changes have been made\n */\nexport const transformChatToCTB = (\n schema: Schema,\n oldSchema?: ContentType | Component\n): ContentType | Component => {\n const singularName = pluralize.singular(schema.name).toLowerCase().replace(/ /g, '-');\n const pluralName = pluralize.plural(schema.name).toLowerCase().replace(/ /g, '-');\n\n if (schema.modelType === 'component') {\n return {\n category: schema.category || 'default',\n modelName: singularName,\n attributes: transformAttributesFromChatToCTB(schema, oldSchema),\n info: {\n displayName: schema.name,\n description: schema.description,\n // TODO\n // icon: schema.icon,\n },\n modelType: schema.modelType,\n uid: schema.uid as any,\n collectionName: pluralName,\n status: transformStatusFromChatToCTB(schema, oldSchema),\n globalId: singularName,\n } satisfies Component;\n }\n\n const contentTypeBase = {\n uid: schema.uid as any,\n modelType: schema.modelType,\n modelName: singularName,\n kind: schema.kind!,\n info: {\n displayName: schema.name.charAt(0).toUpperCase() + schema.name.slice(1),\n // Always keep the old by default\n // @ts-expect-error - not in types\n singularName: oldSchema?.info?.singularName || singularName,\n // Always keep the old by default\n // @ts-expect-error - not in types\n pluralName: oldSchema?.info?.pluralName || pluralName,\n },\n collectionName: pluralName,\n attributes: transformAttributesFromChatToCTB(schema, oldSchema),\n options: {\n draftAndPublish: schema.options?.draftAndPublish ?? true,\n },\n pluginOptions: {\n i18n: {\n localized: schema.options?.localized ?? false,\n },\n },\n visible: true,\n status: transformStatusFromChatToCTB(schema, oldSchema),\n globalId: singularName,\n restrictRelationsTo: null, // TODO: not sure what this is about\n } satisfies ContentType;\n\n if (\n isPluginContentType(schema, oldSchema) &&\n oldSchema &&\n oldSchema.modelType === 'contentType'\n ) {\n const prev = oldSchema as ContentType;\n return {\n ...contentTypeBase,\n plugin: prev.plugin ?? schema.plugin,\n globalId: prev.globalId,\n modelName: prev.modelName,\n collectionName: prev.collectionName,\n info: {\n ...contentTypeBase.info,\n singularName: prev.info.singularName,\n pluralName: prev.info.pluralName,\n },\n options: {\n ...prev.options,\n ...contentTypeBase.options,\n draftAndPublish: schema.options?.draftAndPublish ?? prev.options?.draftAndPublish ?? true,\n },\n pluginOptions: {\n ...prev.pluginOptions,\n ...contentTypeBase.pluginOptions,\n i18n: {\n ...((prev.pluginOptions?.i18n as Record<string, unknown> | undefined) ?? {}),\n ...((contentTypeBase.pluginOptions?.i18n as Record<string, unknown> | undefined) ?? {}),\n localized:\n schema.options?.localized ??\n (prev.pluginOptions?.i18n as { localized?: boolean } | undefined)?.localized ??\n false,\n },\n },\n visible: prev.visible,\n restrictRelationsTo: prev.restrictRelationsTo,\n } satisfies ContentType;\n }\n\n if (isPluginContentType(schema, oldSchema) && schema.plugin) {\n return {\n ...contentTypeBase,\n plugin: schema.plugin,\n } satisfies ContentType;\n }\n\n return contentTypeBase;\n};\n"],"names":["isPluginContentTypeUid","uid","startsWith","isPluginContentType","schema","oldSchema","plugin","modelType","ct","Boolean","String","ACTION_TO_STATUS","create","remove","update","createAttributeWithStatus","name","attributeData","status","determineAttributeStatus","newAttr","oldAttr","newAttrWithoutStatus","omit","oldAttrWithoutStatus","isEqual","transformStatusFromChatToCTB","action","transformAttributesFromChatToCTB","attributes","Object","entries","map","attribute","oldAttributesMap","reduce","acc","attr","processedAttributes","removedAttributes","filter","transformChatToCTB","singularName","pluralize","singular","toLowerCase","replace","pluralName","plural","category","modelName","info","displayName","description","collectionName","globalId","contentTypeBase","kind","charAt","toUpperCase","slice","options","draftAndPublish","pluginOptions","i18n","localized","visible","restrictRelationsTo","prev"],"mappings":"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"}
|
|
@@ -3,6 +3,20 @@ import omit from 'lodash/omit';
|
|
|
3
3
|
import pluralize from 'pluralize';
|
|
4
4
|
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6
|
+
const isPluginContentTypeUid = (uid)=>uid.startsWith('plugin::');
|
|
7
|
+
/**
|
|
8
|
+
* Plugin / extension content-types use server-derived identity (globalId, collectionName, …).
|
|
9
|
+
* The AI chat uses a simplified shape that would otherwise overwrite those fields incorrectly.
|
|
10
|
+
*/ const isPluginContentType = (schema, oldSchema)=>{
|
|
11
|
+
if (schema.plugin || isPluginContentTypeUid(schema.uid)) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (oldSchema && 'modelType' in oldSchema && oldSchema.modelType === 'contentType') {
|
|
15
|
+
const ct = oldSchema;
|
|
16
|
+
return Boolean(ct.plugin) || isPluginContentTypeUid(String(ct.uid));
|
|
17
|
+
}
|
|
18
|
+
return false;
|
|
19
|
+
};
|
|
6
20
|
const ACTION_TO_STATUS = {
|
|
7
21
|
create: 'NEW',
|
|
8
22
|
remove: 'REMOVED',
|
|
@@ -113,7 +127,7 @@ const ACTION_TO_STATUS = {
|
|
|
113
127
|
globalId: singularName
|
|
114
128
|
};
|
|
115
129
|
}
|
|
116
|
-
|
|
130
|
+
const contentTypeBase = {
|
|
117
131
|
uid: schema.uid,
|
|
118
132
|
modelType: schema.modelType,
|
|
119
133
|
modelName: singularName,
|
|
@@ -142,6 +156,44 @@ const ACTION_TO_STATUS = {
|
|
|
142
156
|
globalId: singularName,
|
|
143
157
|
restrictRelationsTo: null
|
|
144
158
|
};
|
|
159
|
+
if (isPluginContentType(schema, oldSchema) && oldSchema && oldSchema.modelType === 'contentType') {
|
|
160
|
+
const prev = oldSchema;
|
|
161
|
+
return {
|
|
162
|
+
...contentTypeBase,
|
|
163
|
+
plugin: prev.plugin ?? schema.plugin,
|
|
164
|
+
globalId: prev.globalId,
|
|
165
|
+
modelName: prev.modelName,
|
|
166
|
+
collectionName: prev.collectionName,
|
|
167
|
+
info: {
|
|
168
|
+
...contentTypeBase.info,
|
|
169
|
+
singularName: prev.info.singularName,
|
|
170
|
+
pluralName: prev.info.pluralName
|
|
171
|
+
},
|
|
172
|
+
options: {
|
|
173
|
+
...prev.options,
|
|
174
|
+
...contentTypeBase.options,
|
|
175
|
+
draftAndPublish: schema.options?.draftAndPublish ?? prev.options?.draftAndPublish ?? true
|
|
176
|
+
},
|
|
177
|
+
pluginOptions: {
|
|
178
|
+
...prev.pluginOptions,
|
|
179
|
+
...contentTypeBase.pluginOptions,
|
|
180
|
+
i18n: {
|
|
181
|
+
...prev.pluginOptions?.i18n ?? {},
|
|
182
|
+
...contentTypeBase.pluginOptions?.i18n ?? {},
|
|
183
|
+
localized: schema.options?.localized ?? prev.pluginOptions?.i18n?.localized ?? false
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
visible: prev.visible,
|
|
187
|
+
restrictRelationsTo: prev.restrictRelationsTo
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
if (isPluginContentType(schema, oldSchema) && schema.plugin) {
|
|
191
|
+
return {
|
|
192
|
+
...contentTypeBase,
|
|
193
|
+
plugin: schema.plugin
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
return contentTypeBase;
|
|
145
197
|
};
|
|
146
198
|
|
|
147
199
|
export { transformAttributesFromChatToCTB, transformChatToCTB };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toCTB.mjs","sources":["../../../../../../../admin/src/components/AIChat/lib/transforms/schemas/toCTB.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\nimport isEqual from 'lodash/isEqual';\nimport omit from 'lodash/omit';\nimport pluralize from 'pluralize';\n\nimport { Schema } from '../../types/schema';\n\nimport type { ContentType, Component, AnyAttribute } from '../../../../../types';\n\nconst ACTION_TO_STATUS: Record<Schema['action'], ContentType['status']> = {\n create: 'NEW',\n remove: 'REMOVED',\n update: 'CHANGED',\n};\n\n/**\n * Creates a new attribute with the specified status\n */\nconst createAttributeWithStatus = (\n name: string,\n attributeData: Record<string, any>,\n status: AnyAttribute['status']\n): AnyAttribute =>\n ({\n ...attributeData,\n name,\n status,\n }) as AnyAttribute;\n\n/**\n * Determines the status of an attribute by comparing new and old versions\n */\nconst determineAttributeStatus = (\n newAttr: Record<string, any>,\n oldAttr?: AnyAttribute,\n oldSchema?: ContentType | Component\n): AnyAttribute['status'] => {\n if (!oldAttr) {\n return 'NEW';\n }\n\n // If the schema was already new, don't mark attributes as changed, keep them as new.\n if (oldSchema?.status === 'NEW') {\n return 'NEW';\n }\n\n // Compare attributes without the status field to determine if they've changed\n const newAttrWithoutStatus = omit(newAttr, ['status']);\n const oldAttrWithoutStatus = omit(oldAttr, ['status']);\n\n if (!isEqual(newAttrWithoutStatus, oldAttrWithoutStatus)) {\n return 'CHANGED';\n }\n\n // If unchanged, keep the previous status\n return oldAttr.status;\n};\n\n/**\n * Determines the status of a schema by comparing action and checking if oldSchema exists\n */\nconst transformStatusFromChatToCTB = (\n schema: Schema,\n oldSchema?: ContentType | Component\n): ContentType['status'] => {\n // If schema has an action, use the mapped status\n if (schema.action) {\n return ACTION_TO_STATUS[schema.action];\n }\n\n // If oldSchema doesn't exist, it's a new schema\n if (!oldSchema) {\n return 'NEW';\n }\n\n // If no action is specified and oldSchema exists, keep the existing status\n return oldSchema.status;\n};\n\n/**\n * Transform attributes from Chat format to CTB format\n * Also performs a diff to determine the status of each attribute\n */\nexport const transformAttributesFromChatToCTB = (\n { action, attributes }: Schema,\n oldSchema?: ContentType | Component\n): AnyAttribute[] => {\n // If it's a new schema or no oldAttributes provided, all attributes are NEW\n if (action === 'create' || !oldSchema) {\n return Object.entries(attributes).map(([name, attribute]) =>\n createAttributeWithStatus(name, attribute, 'NEW')\n );\n }\n\n // Convert old attributes array to a lookup map for faster access\n const oldAttributesMap = oldSchema.attributes.reduce(\n (acc, attr) => ({ ...acc, [attr.name]: attr }),\n {} as Record<string, AnyAttribute>\n );\n\n // Process current attributes (new and changed)\n const processedAttributes = Object.entries(attributes).map(([name, attr]) => {\n const oldAttr = oldAttributesMap[name];\n const status = determineAttributeStatus({ ...attr, name }, oldAttr, oldSchema);\n\n return createAttributeWithStatus(name, attr, status);\n });\n\n // No need to mark removed attributes if the old schema is new, just remove it from the list\n // TODO: Else a validation error occurs on the backend side.\n if (oldSchema?.status === 'NEW') {\n return processedAttributes;\n }\n\n // Find removed attributes (exist in old but not in new)\n const removedAttributes = Object.entries(oldAttributesMap)\n .filter(([name]) => !attributes[name])\n .map(([name, oldAttr]) => createAttributeWithStatus(name, oldAttr, 'REMOVED'));\n\n // Combine both sets of attributes\n return [...processedAttributes, ...removedAttributes];\n};\n\n/**\n * Transform schema format\n * AI chat -> CTB\n *\n * The AI chat returns a simplified format, and this layer transforms it to be compatible with the CTB reducer.\n *\n * We need to keep track of which changes have been made\n */\nexport const transformChatToCTB = (\n schema: Schema,\n oldSchema?: ContentType | Component\n): ContentType | Component => {\n const singularName = pluralize.singular(schema.name).toLowerCase().replace(/ /g, '-');\n const pluralName = pluralize.plural(schema.name).toLowerCase().replace(/ /g, '-');\n\n if (schema.modelType === 'component') {\n return {\n category: schema.category || 'default',\n modelName: singularName,\n attributes: transformAttributesFromChatToCTB(schema, oldSchema),\n info: {\n displayName: schema.name,\n description: schema.description,\n // TODO\n // icon: schema.icon,\n },\n modelType: schema.modelType,\n uid: schema.uid as any,\n collectionName: pluralName,\n status: transformStatusFromChatToCTB(schema, oldSchema),\n globalId: singularName,\n } satisfies Component;\n }\n\n return {\n uid: schema.uid as any,\n modelType: schema.modelType,\n modelName: singularName,\n kind: schema.kind!,\n info: {\n displayName: schema.name.charAt(0).toUpperCase() + schema.name.slice(1),\n // Always keep the old by default\n // @ts-expect-error - not in types\n singularName: oldSchema?.info?.singularName || singularName,\n // Always keep the old by default\n // @ts-expect-error - not in types\n pluralName: oldSchema?.info?.pluralName || pluralName,\n },\n collectionName: pluralName,\n attributes: transformAttributesFromChatToCTB(schema, oldSchema),\n options: {\n draftAndPublish: schema.options?.draftAndPublish ?? true,\n },\n pluginOptions: {\n i18n: {\n localized: schema.options?.localized ?? false,\n },\n },\n visible: true,\n status: transformStatusFromChatToCTB(schema, oldSchema),\n globalId: singularName,\n restrictRelationsTo: null, // TODO: not sure what this is about\n } satisfies ContentType;\n};\n"],"names":["ACTION_TO_STATUS","create","remove","update","createAttributeWithStatus","name","attributeData","status","determineAttributeStatus","newAttr","oldAttr","oldSchema","newAttrWithoutStatus","omit","oldAttrWithoutStatus","isEqual","transformStatusFromChatToCTB","schema","action","transformAttributesFromChatToCTB","attributes","Object","entries","map","attribute","oldAttributesMap","reduce","acc","attr","processedAttributes","removedAttributes","filter","transformChatToCTB","singularName","pluralize","singular","toLowerCase","replace","pluralName","plural","modelType","category","modelName","info","displayName","description","uid","collectionName","globalId","kind","charAt","toUpperCase","slice","options","draftAndPublish","pluginOptions","i18n","localized","visible","restrictRelationsTo"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toCTB.mjs","sources":["../../../../../../../admin/src/components/AIChat/lib/transforms/schemas/toCTB.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/ban-ts-comment\nimport isEqual from 'lodash/isEqual';\nimport omit from 'lodash/omit';\nimport pluralize from 'pluralize';\n\nimport { Schema } from '../../types/schema';\n\nimport type { ContentType, Component, AnyAttribute } from '../../../../../types';\n\nconst isPluginContentTypeUid = (uid: string) => uid.startsWith('plugin::');\n\n/**\n * Plugin / extension content-types use server-derived identity (globalId, collectionName, …).\n * The AI chat uses a simplified shape that would otherwise overwrite those fields incorrectly.\n */\nconst isPluginContentType = (schema: Schema, oldSchema?: ContentType | Component): boolean => {\n if (schema.plugin || isPluginContentTypeUid(schema.uid)) {\n return true;\n }\n if (oldSchema && 'modelType' in oldSchema && oldSchema.modelType === 'contentType') {\n const ct = oldSchema as ContentType;\n return Boolean(ct.plugin) || isPluginContentTypeUid(String(ct.uid));\n }\n return false;\n};\n\nconst ACTION_TO_STATUS: Record<Schema['action'], ContentType['status']> = {\n create: 'NEW',\n remove: 'REMOVED',\n update: 'CHANGED',\n};\n\n/**\n * Creates a new attribute with the specified status\n */\nconst createAttributeWithStatus = (\n name: string,\n attributeData: Record<string, any>,\n status: AnyAttribute['status']\n): AnyAttribute =>\n ({\n ...attributeData,\n name,\n status,\n }) as AnyAttribute;\n\n/**\n * Determines the status of an attribute by comparing new and old versions\n */\nconst determineAttributeStatus = (\n newAttr: Record<string, any>,\n oldAttr?: AnyAttribute,\n oldSchema?: ContentType | Component\n): AnyAttribute['status'] => {\n if (!oldAttr) {\n return 'NEW';\n }\n\n // If the schema was already new, don't mark attributes as changed, keep them as new.\n if (oldSchema?.status === 'NEW') {\n return 'NEW';\n }\n\n // Compare attributes without the status field to determine if they've changed\n const newAttrWithoutStatus = omit(newAttr, ['status']);\n const oldAttrWithoutStatus = omit(oldAttr, ['status']);\n\n if (!isEqual(newAttrWithoutStatus, oldAttrWithoutStatus)) {\n return 'CHANGED';\n }\n\n // If unchanged, keep the previous status\n return oldAttr.status;\n};\n\n/**\n * Determines the status of a schema by comparing action and checking if oldSchema exists\n */\nconst transformStatusFromChatToCTB = (\n schema: Schema,\n oldSchema?: ContentType | Component\n): ContentType['status'] => {\n // If schema has an action, use the mapped status\n if (schema.action) {\n return ACTION_TO_STATUS[schema.action];\n }\n\n // If oldSchema doesn't exist, it's a new schema\n if (!oldSchema) {\n return 'NEW';\n }\n\n // If no action is specified and oldSchema exists, keep the existing status\n return oldSchema.status;\n};\n\n/**\n * Transform attributes from Chat format to CTB format\n * Also performs a diff to determine the status of each attribute\n */\nexport const transformAttributesFromChatToCTB = (\n { action, attributes }: Schema,\n oldSchema?: ContentType | Component\n): AnyAttribute[] => {\n // If it's a new schema or no oldAttributes provided, all attributes are NEW\n if (action === 'create' || !oldSchema) {\n return Object.entries(attributes).map(([name, attribute]) =>\n createAttributeWithStatus(name, attribute, 'NEW')\n );\n }\n\n // Convert old attributes array to a lookup map for faster access\n const oldAttributesMap = oldSchema.attributes.reduce(\n (acc, attr) => ({ ...acc, [attr.name]: attr }),\n {} as Record<string, AnyAttribute>\n );\n\n // Process current attributes (new and changed)\n const processedAttributes = Object.entries(attributes).map(([name, attr]) => {\n const oldAttr = oldAttributesMap[name];\n const status = determineAttributeStatus({ ...attr, name }, oldAttr, oldSchema);\n\n return createAttributeWithStatus(name, attr, status);\n });\n\n // No need to mark removed attributes if the old schema is new, just remove it from the list\n // TODO: Else a validation error occurs on the backend side.\n if (oldSchema?.status === 'NEW') {\n return processedAttributes;\n }\n\n // Find removed attributes (exist in old but not in new)\n const removedAttributes = Object.entries(oldAttributesMap)\n .filter(([name]) => !attributes[name])\n .map(([name, oldAttr]) => createAttributeWithStatus(name, oldAttr, 'REMOVED'));\n\n // Combine both sets of attributes\n return [...processedAttributes, ...removedAttributes];\n};\n\n/**\n * Transform schema format\n * AI chat -> CTB\n *\n * The AI chat returns a simplified format, and this layer transforms it to be compatible with the CTB reducer.\n *\n * We need to keep track of which changes have been made\n */\nexport const transformChatToCTB = (\n schema: Schema,\n oldSchema?: ContentType | Component\n): ContentType | Component => {\n const singularName = pluralize.singular(schema.name).toLowerCase().replace(/ /g, '-');\n const pluralName = pluralize.plural(schema.name).toLowerCase().replace(/ /g, '-');\n\n if (schema.modelType === 'component') {\n return {\n category: schema.category || 'default',\n modelName: singularName,\n attributes: transformAttributesFromChatToCTB(schema, oldSchema),\n info: {\n displayName: schema.name,\n description: schema.description,\n // TODO\n // icon: schema.icon,\n },\n modelType: schema.modelType,\n uid: schema.uid as any,\n collectionName: pluralName,\n status: transformStatusFromChatToCTB(schema, oldSchema),\n globalId: singularName,\n } satisfies Component;\n }\n\n const contentTypeBase = {\n uid: schema.uid as any,\n modelType: schema.modelType,\n modelName: singularName,\n kind: schema.kind!,\n info: {\n displayName: schema.name.charAt(0).toUpperCase() + schema.name.slice(1),\n // Always keep the old by default\n // @ts-expect-error - not in types\n singularName: oldSchema?.info?.singularName || singularName,\n // Always keep the old by default\n // @ts-expect-error - not in types\n pluralName: oldSchema?.info?.pluralName || pluralName,\n },\n collectionName: pluralName,\n attributes: transformAttributesFromChatToCTB(schema, oldSchema),\n options: {\n draftAndPublish: schema.options?.draftAndPublish ?? true,\n },\n pluginOptions: {\n i18n: {\n localized: schema.options?.localized ?? false,\n },\n },\n visible: true,\n status: transformStatusFromChatToCTB(schema, oldSchema),\n globalId: singularName,\n restrictRelationsTo: null, // TODO: not sure what this is about\n } satisfies ContentType;\n\n if (\n isPluginContentType(schema, oldSchema) &&\n oldSchema &&\n oldSchema.modelType === 'contentType'\n ) {\n const prev = oldSchema as ContentType;\n return {\n ...contentTypeBase,\n plugin: prev.plugin ?? schema.plugin,\n globalId: prev.globalId,\n modelName: prev.modelName,\n collectionName: prev.collectionName,\n info: {\n ...contentTypeBase.info,\n singularName: prev.info.singularName,\n pluralName: prev.info.pluralName,\n },\n options: {\n ...prev.options,\n ...contentTypeBase.options,\n draftAndPublish: schema.options?.draftAndPublish ?? prev.options?.draftAndPublish ?? true,\n },\n pluginOptions: {\n ...prev.pluginOptions,\n ...contentTypeBase.pluginOptions,\n i18n: {\n ...((prev.pluginOptions?.i18n as Record<string, unknown> | undefined) ?? {}),\n ...((contentTypeBase.pluginOptions?.i18n as Record<string, unknown> | undefined) ?? {}),\n localized:\n schema.options?.localized ??\n (prev.pluginOptions?.i18n as { localized?: boolean } | undefined)?.localized ??\n false,\n },\n },\n visible: prev.visible,\n restrictRelationsTo: prev.restrictRelationsTo,\n } satisfies ContentType;\n }\n\n if (isPluginContentType(schema, oldSchema) && schema.plugin) {\n return {\n ...contentTypeBase,\n plugin: schema.plugin,\n } satisfies ContentType;\n }\n\n return contentTypeBase;\n};\n"],"names":["isPluginContentTypeUid","uid","startsWith","isPluginContentType","schema","oldSchema","plugin","modelType","ct","Boolean","String","ACTION_TO_STATUS","create","remove","update","createAttributeWithStatus","name","attributeData","status","determineAttributeStatus","newAttr","oldAttr","newAttrWithoutStatus","omit","oldAttrWithoutStatus","isEqual","transformStatusFromChatToCTB","action","transformAttributesFromChatToCTB","attributes","Object","entries","map","attribute","oldAttributesMap","reduce","acc","attr","processedAttributes","removedAttributes","filter","transformChatToCTB","singularName","pluralize","singular","toLowerCase","replace","pluralName","plural","category","modelName","info","displayName","description","collectionName","globalId","contentTypeBase","kind","charAt","toUpperCase","slice","options","draftAndPublish","pluginOptions","i18n","localized","visible","restrictRelationsTo","prev"],"mappings":"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"}
|
|
@@ -5,6 +5,8 @@ export type Schema = {
|
|
|
5
5
|
action: 'create' | 'update' | 'remove';
|
|
6
6
|
kind?: 'singleType' | 'collectionType';
|
|
7
7
|
uid: string;
|
|
8
|
+
/** Set for plugin content-types (`plugin::…`) */
|
|
9
|
+
plugin?: string;
|
|
8
10
|
modelType: 'component' | 'contentType';
|
|
9
11
|
category?: string;
|
|
10
12
|
description?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-type.js","sources":["../../../../server/src/controllers/validation/content-type.ts"],"sourcesContent":["/* eslint-disable no-template-curly-in-string */ // yup templates need to be in this format\n\nimport { flatMap, getOr, has, snakeCase } from 'lodash/fp';\nimport { yup, validateYupSchema } from '@strapi/utils';\n\nimport type { Struct, Internal, UID } from '@strapi/types';\n\nimport { getService } from '../../utils';\nimport { modelTypes, DEFAULT_TYPES, typeKinds } from '../../services/constants';\nimport { createSchema } from './model-schema';\nimport { removeEmptyDefaults, removeDeletedUIDTargetFields } from './data-transform';\nimport { nestedComponentSchema } from './component';\n\n// Input flattens some fields of the \"info\" into the root type\nexport type CreateContentTypeInput = {\n uid?: UID.ContentType;\n contentType?: Partial<Struct.ContentTypeSchema> & Partial<Struct.ContentTypeSchemaInfo>;\n components?: Array<\n Partial<Struct.ComponentSchema> &\n Partial<Struct.SchemaInfo> & { tmpUID?: Internal.UID.Component }\n >;\n singularName: Struct.ContentTypeSchemaInfo['singularName'];\n attributes: Struct.SchemaAttributes & Record<string, any>;\n kind: Struct.ContentTypeKind;\n collectionName?: Struct.CollectionTypeSchema['collectionName'];\n pluralName: Struct.ContentTypeSchemaInfo['pluralName'];\n displayName: Struct.ContentTypeSchemaInfo['displayName'];\n description?: Struct.ContentTypeSchemaInfo['description'];\n options?: Struct.SchemaOptions;\n draftAndPublish?: Struct.SchemaOptions['draftAndPublish'];\n pluginOptions?: Struct.ContentTypeSchema['pluginOptions'];\n config?: object;\n};\n\n/**\n * Allowed relation per type kind\n */\nconst VALID_RELATIONS = {\n [typeKinds.SINGLE_TYPE]: [\n 'oneToOne',\n 'oneToMany',\n 'morphOne',\n 'morphMany',\n 'morphToOne',\n 'morphToMany',\n ],\n [typeKinds.COLLECTION_TYPE]: [\n 'oneToOne',\n 'oneToMany',\n 'manyToOne',\n 'manyToMany',\n 'morphOne',\n 'morphMany',\n 'morphToOne',\n 'morphToMany',\n ],\n} as const;\n\n/**\n * Allowed types\n */\nconst VALID_TYPES = [...DEFAULT_TYPES, 'uid', 'component', 'dynamiczone', 'customField'];\n\n/**\n * Returns a yup schema to validate a content type payload\n */\nconst createContentTypeSchema = (data: CreateContentTypeInput, { isEdition = false } = {}) => {\n const kind: keyof typeof VALID_RELATIONS = getOr(\n typeKinds.COLLECTION_TYPE,\n 'contentType.kind',\n data\n );\n\n const contentTypeSchema = createSchema(VALID_TYPES, VALID_RELATIONS[kind] || [], {\n modelType: modelTypes.CONTENT_TYPE,\n })\n .shape({\n displayName: yup.string().min(1).required(),\n singularName: yup\n .string()\n .min(1)\n .test(nameIsAvailable(isEdition))\n .test(forbiddenContentTypeNameValidator())\n .isKebabCase()\n .required(),\n pluralName: yup\n .string()\n .min(1)\n .test(nameIsAvailable(isEdition))\n .test(nameIsNotExistingCollectionName(isEdition)) // TODO: v5: require singularName to not match a collection name\n .test(forbiddenContentTypeNameValidator())\n .isKebabCase()\n .required(),\n })\n .test(\n 'singularName-not-equal-pluralName',\n '${path}: singularName and pluralName should be different',\n (value) => value.singularName !== value.pluralName\n );\n\n return yup\n .object({\n // FIXME .noUnknown(false) will strip off the unwanted properties without throwing an error\n // Why not having .noUnknown() ? Because we want to be able to add options relatable to EE features\n // without having any reference to them in CE.\n // Why not handle an \"options\" object in the content-type ? The admin panel needs lots of rework\n // to be able to send this options object instead of top-level attributes.\n // @nathan-pichon 20/02/2023\n contentType: contentTypeSchema.required().noUnknown(false),\n components: nestedComponentSchema,\n })\n .noUnknown();\n};\n\n/**\n * Validator for content type creation\n */\nexport const validateContentTypeInput = (data: CreateContentTypeInput) => {\n return validateYupSchema(createContentTypeSchema(data))(data);\n};\n\n/**\n * Validator for content type edition\n */\nexport const validateUpdateContentTypeInput = (data: CreateContentTypeInput) => {\n if (has('contentType', data)) {\n removeEmptyDefaults(data.contentType);\n removeDeletedUIDTargetFields(data.contentType as Struct.ContentTypeSchema);\n }\n\n if (has('components', data) && Array.isArray(data.components)) {\n data.components.forEach((comp) => {\n if (has('uid', comp)) {\n removeEmptyDefaults(comp as Struct.ComponentSchema);\n }\n });\n }\n\n return validateYupSchema(createContentTypeSchema(data, { isEdition: true }))(data);\n};\n\nconst forbiddenContentTypeNameValidator = () => {\n const reservedNames = getService('builder').getReservedNames().models;\n\n return {\n name: 'forbiddenContentTypeName',\n message: `Content Type name cannot be one of ${reservedNames.join(', ')}`,\n test(value: unknown) {\n if (typeof value !== 'string') {\n return true;\n }\n\n return !getService('builder').isReservedModelName(value);\n },\n };\n};\n\nconst nameIsAvailable = (isEdition: boolean) => {\n // TODO TS: if strapi.contentTypes (ie, ContentTypes) works as an ArrayLike and is used like this, we may want to ensure it is typed so that it can be without using as\n const usedNames = flatMap((ct: Struct.ContentTypeSchema) => {\n return [ct.info?.singularName, ct.info?.pluralName];\n })(strapi.contentTypes as any);\n\n return {\n name: 'nameAlreadyUsed',\n message: 'contentType: name `${value}` is already being used by another content type.',\n test(value: unknown) {\n // don't check on edition\n if (isEdition) return true;\n\n // ignore if not a string (will be caught in another validator)\n if (typeof value !== 'string') {\n return true;\n }\n\n // compare snake case to check the actual column names that will be used in the database\n return usedNames.every((usedName) => snakeCase(usedName) !== snakeCase(value));\n },\n };\n};\n\nconst nameIsNotExistingCollectionName = (isEdition: boolean) => {\n const usedNames = Object.keys(strapi.contentTypes).map(\n (key) => strapi.contentTypes[key as Internal.UID.ContentType].collectionName\n ) as string[];\n\n return {\n name: 'nameAlreadyUsed',\n message: 'contentType: name `${value}` is already being used by another content type.',\n test(value: unknown) {\n // don't check on edition\n if (isEdition) return true;\n\n // ignore if not a string (will be caught in another validator)\n if (typeof value !== 'string') {\n return true;\n }\n\n // compare snake case to check the actual column names that will be used in the database\n return usedNames.every((usedName) => snakeCase(usedName) !== snakeCase(value));\n },\n };\n};\n\n/**\n * Validates type kind\n */\nconst kindSchema = yup.string().oneOf([typeKinds.SINGLE_TYPE, typeKinds.COLLECTION_TYPE]);\n\nexport const validateKind = validateYupSchema(kindSchema);\n"],"names":["VALID_RELATIONS","typeKinds","SINGLE_TYPE","COLLECTION_TYPE","VALID_TYPES","DEFAULT_TYPES","createContentTypeSchema","data","isEdition","kind","getOr","contentTypeSchema","createSchema","modelType","modelTypes","CONTENT_TYPE","shape","displayName","yup","string","min","required","singularName","test","nameIsAvailable","forbiddenContentTypeNameValidator","isKebabCase","pluralName","nameIsNotExistingCollectionName","value","object","contentType","noUnknown","components","nestedComponentSchema","validateContentTypeInput","validateYupSchema","validateUpdateContentTypeInput","has","removeEmptyDefaults","removeDeletedUIDTargetFields","Array","isArray","forEach","comp","reservedNames","getService","getReservedNames","models","name","message","join","isReservedModelName","usedNames","flatMap","ct","info","strapi","contentTypes","every","usedName","snakeCase","Object","keys","map","key","collectionName","kindSchema","oneOf","validateKind"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"content-type.js","sources":["../../../../server/src/controllers/validation/content-type.ts"],"sourcesContent":["/* eslint-disable no-template-curly-in-string */ // yup templates need to be in this format\n\nimport { flatMap, getOr, has, snakeCase } from 'lodash/fp';\nimport { yup, validateYupSchema } from '@strapi/utils';\n\nimport type { Struct, Internal, UID } from '@strapi/types';\n\nimport { getService } from '../../utils';\nimport { modelTypes, DEFAULT_TYPES, typeKinds } from '../../services/constants';\nimport { createSchema } from './model-schema';\nimport { removeEmptyDefaults, removeDeletedUIDTargetFields } from './data-transform';\nimport { nestedComponentSchema } from './component';\n\n// Input flattens some fields of the \"info\" into the root type\nexport type CreateContentTypeInput = {\n uid?: UID.ContentType;\n contentType?: Partial<Struct.ContentTypeSchema> & Partial<Struct.ContentTypeSchemaInfo>;\n components?: Array<\n Partial<Struct.ComponentSchema> &\n Partial<Struct.SchemaInfo> & { tmpUID?: Internal.UID.Component }\n >;\n singularName: Struct.ContentTypeSchemaInfo['singularName'];\n attributes: Struct.SchemaAttributes & Record<string, any>;\n kind: Struct.ContentTypeKind;\n collectionName?: Struct.CollectionTypeSchema['collectionName'];\n pluralName: Struct.ContentTypeSchemaInfo['pluralName'];\n displayName: Struct.ContentTypeSchemaInfo['displayName'];\n description?: Struct.ContentTypeSchemaInfo['description'];\n options?: Struct.SchemaOptions;\n draftAndPublish?: Struct.SchemaOptions['draftAndPublish'];\n pluginOptions?: Struct.ContentTypeSchema['pluginOptions'];\n config?: object;\n plugin?: string;\n};\n\n/**\n * Allowed relation per type kind\n */\nconst VALID_RELATIONS = {\n [typeKinds.SINGLE_TYPE]: [\n 'oneToOne',\n 'oneToMany',\n 'morphOne',\n 'morphMany',\n 'morphToOne',\n 'morphToMany',\n ],\n [typeKinds.COLLECTION_TYPE]: [\n 'oneToOne',\n 'oneToMany',\n 'manyToOne',\n 'manyToMany',\n 'morphOne',\n 'morphMany',\n 'morphToOne',\n 'morphToMany',\n ],\n} as const;\n\n/**\n * Allowed types\n */\nconst VALID_TYPES = [...DEFAULT_TYPES, 'uid', 'component', 'dynamiczone', 'customField'];\n\n/**\n * Returns a yup schema to validate a content type payload\n */\nconst createContentTypeSchema = (data: CreateContentTypeInput, { isEdition = false } = {}) => {\n const kind: keyof typeof VALID_RELATIONS = getOr(\n typeKinds.COLLECTION_TYPE,\n 'contentType.kind',\n data\n );\n\n const contentTypeSchema = createSchema(VALID_TYPES, VALID_RELATIONS[kind] || [], {\n modelType: modelTypes.CONTENT_TYPE,\n })\n .shape({\n displayName: yup.string().min(1).required(),\n singularName: yup\n .string()\n .min(1)\n .test(nameIsAvailable(isEdition))\n .test(forbiddenContentTypeNameValidator())\n .isKebabCase()\n .required(),\n pluralName: yup\n .string()\n .min(1)\n .test(nameIsAvailable(isEdition))\n .test(nameIsNotExistingCollectionName(isEdition)) // TODO: v5: require singularName to not match a collection name\n .test(forbiddenContentTypeNameValidator())\n .isKebabCase()\n .required(),\n })\n .test(\n 'singularName-not-equal-pluralName',\n '${path}: singularName and pluralName should be different',\n (value) => value.singularName !== value.pluralName\n );\n\n return yup\n .object({\n // FIXME .noUnknown(false) will strip off the unwanted properties without throwing an error\n // Why not having .noUnknown() ? Because we want to be able to add options relatable to EE features\n // without having any reference to them in CE.\n // Why not handle an \"options\" object in the content-type ? The admin panel needs lots of rework\n // to be able to send this options object instead of top-level attributes.\n // @nathan-pichon 20/02/2023\n contentType: contentTypeSchema.required().noUnknown(false),\n components: nestedComponentSchema,\n })\n .noUnknown();\n};\n\n/**\n * Validator for content type creation\n */\nexport const validateContentTypeInput = (data: CreateContentTypeInput) => {\n return validateYupSchema(createContentTypeSchema(data))(data);\n};\n\n/**\n * Validator for content type edition\n */\nexport const validateUpdateContentTypeInput = (data: CreateContentTypeInput) => {\n if (has('contentType', data)) {\n removeEmptyDefaults(data.contentType);\n removeDeletedUIDTargetFields(data.contentType as Struct.ContentTypeSchema);\n }\n\n if (has('components', data) && Array.isArray(data.components)) {\n data.components.forEach((comp) => {\n if (has('uid', comp)) {\n removeEmptyDefaults(comp as Struct.ComponentSchema);\n }\n });\n }\n\n return validateYupSchema(createContentTypeSchema(data, { isEdition: true }))(data);\n};\n\nconst forbiddenContentTypeNameValidator = () => {\n const reservedNames = getService('builder').getReservedNames().models;\n\n return {\n name: 'forbiddenContentTypeName',\n message: `Content Type name cannot be one of ${reservedNames.join(', ')}`,\n test(value: unknown) {\n if (typeof value !== 'string') {\n return true;\n }\n\n return !getService('builder').isReservedModelName(value);\n },\n };\n};\n\nconst nameIsAvailable = (isEdition: boolean) => {\n // TODO TS: if strapi.contentTypes (ie, ContentTypes) works as an ArrayLike and is used like this, we may want to ensure it is typed so that it can be without using as\n const usedNames = flatMap((ct: Struct.ContentTypeSchema) => {\n return [ct.info?.singularName, ct.info?.pluralName];\n })(strapi.contentTypes as any);\n\n return {\n name: 'nameAlreadyUsed',\n message: 'contentType: name `${value}` is already being used by another content type.',\n test(value: unknown) {\n // don't check on edition\n if (isEdition) return true;\n\n // ignore if not a string (will be caught in another validator)\n if (typeof value !== 'string') {\n return true;\n }\n\n // compare snake case to check the actual column names that will be used in the database\n return usedNames.every((usedName) => snakeCase(usedName) !== snakeCase(value));\n },\n };\n};\n\nconst nameIsNotExistingCollectionName = (isEdition: boolean) => {\n const usedNames = Object.keys(strapi.contentTypes).map(\n (key) => strapi.contentTypes[key as Internal.UID.ContentType].collectionName\n ) as string[];\n\n return {\n name: 'nameAlreadyUsed',\n message: 'contentType: name `${value}` is already being used by another content type.',\n test(value: unknown) {\n // don't check on edition\n if (isEdition) return true;\n\n // ignore if not a string (will be caught in another validator)\n if (typeof value !== 'string') {\n return true;\n }\n\n // compare snake case to check the actual column names that will be used in the database\n return usedNames.every((usedName) => snakeCase(usedName) !== snakeCase(value));\n },\n };\n};\n\n/**\n * Validates type kind\n */\nconst kindSchema = yup.string().oneOf([typeKinds.SINGLE_TYPE, typeKinds.COLLECTION_TYPE]);\n\nexport const validateKind = validateYupSchema(kindSchema);\n"],"names":["VALID_RELATIONS","typeKinds","SINGLE_TYPE","COLLECTION_TYPE","VALID_TYPES","DEFAULT_TYPES","createContentTypeSchema","data","isEdition","kind","getOr","contentTypeSchema","createSchema","modelType","modelTypes","CONTENT_TYPE","shape","displayName","yup","string","min","required","singularName","test","nameIsAvailable","forbiddenContentTypeNameValidator","isKebabCase","pluralName","nameIsNotExistingCollectionName","value","object","contentType","noUnknown","components","nestedComponentSchema","validateContentTypeInput","validateYupSchema","validateUpdateContentTypeInput","has","removeEmptyDefaults","removeDeletedUIDTargetFields","Array","isArray","forEach","comp","reservedNames","getService","getReservedNames","models","name","message","join","isReservedModelName","usedNames","flatMap","ct","info","strapi","contentTypes","every","usedName","snakeCase","Object","keys","map","key","collectionName","kindSchema","oneOf","validateKind"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-type.mjs","sources":["../../../../server/src/controllers/validation/content-type.ts"],"sourcesContent":["/* eslint-disable no-template-curly-in-string */ // yup templates need to be in this format\n\nimport { flatMap, getOr, has, snakeCase } from 'lodash/fp';\nimport { yup, validateYupSchema } from '@strapi/utils';\n\nimport type { Struct, Internal, UID } from '@strapi/types';\n\nimport { getService } from '../../utils';\nimport { modelTypes, DEFAULT_TYPES, typeKinds } from '../../services/constants';\nimport { createSchema } from './model-schema';\nimport { removeEmptyDefaults, removeDeletedUIDTargetFields } from './data-transform';\nimport { nestedComponentSchema } from './component';\n\n// Input flattens some fields of the \"info\" into the root type\nexport type CreateContentTypeInput = {\n uid?: UID.ContentType;\n contentType?: Partial<Struct.ContentTypeSchema> & Partial<Struct.ContentTypeSchemaInfo>;\n components?: Array<\n Partial<Struct.ComponentSchema> &\n Partial<Struct.SchemaInfo> & { tmpUID?: Internal.UID.Component }\n >;\n singularName: Struct.ContentTypeSchemaInfo['singularName'];\n attributes: Struct.SchemaAttributes & Record<string, any>;\n kind: Struct.ContentTypeKind;\n collectionName?: Struct.CollectionTypeSchema['collectionName'];\n pluralName: Struct.ContentTypeSchemaInfo['pluralName'];\n displayName: Struct.ContentTypeSchemaInfo['displayName'];\n description?: Struct.ContentTypeSchemaInfo['description'];\n options?: Struct.SchemaOptions;\n draftAndPublish?: Struct.SchemaOptions['draftAndPublish'];\n pluginOptions?: Struct.ContentTypeSchema['pluginOptions'];\n config?: object;\n};\n\n/**\n * Allowed relation per type kind\n */\nconst VALID_RELATIONS = {\n [typeKinds.SINGLE_TYPE]: [\n 'oneToOne',\n 'oneToMany',\n 'morphOne',\n 'morphMany',\n 'morphToOne',\n 'morphToMany',\n ],\n [typeKinds.COLLECTION_TYPE]: [\n 'oneToOne',\n 'oneToMany',\n 'manyToOne',\n 'manyToMany',\n 'morphOne',\n 'morphMany',\n 'morphToOne',\n 'morphToMany',\n ],\n} as const;\n\n/**\n * Allowed types\n */\nconst VALID_TYPES = [...DEFAULT_TYPES, 'uid', 'component', 'dynamiczone', 'customField'];\n\n/**\n * Returns a yup schema to validate a content type payload\n */\nconst createContentTypeSchema = (data: CreateContentTypeInput, { isEdition = false } = {}) => {\n const kind: keyof typeof VALID_RELATIONS = getOr(\n typeKinds.COLLECTION_TYPE,\n 'contentType.kind',\n data\n );\n\n const contentTypeSchema = createSchema(VALID_TYPES, VALID_RELATIONS[kind] || [], {\n modelType: modelTypes.CONTENT_TYPE,\n })\n .shape({\n displayName: yup.string().min(1).required(),\n singularName: yup\n .string()\n .min(1)\n .test(nameIsAvailable(isEdition))\n .test(forbiddenContentTypeNameValidator())\n .isKebabCase()\n .required(),\n pluralName: yup\n .string()\n .min(1)\n .test(nameIsAvailable(isEdition))\n .test(nameIsNotExistingCollectionName(isEdition)) // TODO: v5: require singularName to not match a collection name\n .test(forbiddenContentTypeNameValidator())\n .isKebabCase()\n .required(),\n })\n .test(\n 'singularName-not-equal-pluralName',\n '${path}: singularName and pluralName should be different',\n (value) => value.singularName !== value.pluralName\n );\n\n return yup\n .object({\n // FIXME .noUnknown(false) will strip off the unwanted properties without throwing an error\n // Why not having .noUnknown() ? Because we want to be able to add options relatable to EE features\n // without having any reference to them in CE.\n // Why not handle an \"options\" object in the content-type ? The admin panel needs lots of rework\n // to be able to send this options object instead of top-level attributes.\n // @nathan-pichon 20/02/2023\n contentType: contentTypeSchema.required().noUnknown(false),\n components: nestedComponentSchema,\n })\n .noUnknown();\n};\n\n/**\n * Validator for content type creation\n */\nexport const validateContentTypeInput = (data: CreateContentTypeInput) => {\n return validateYupSchema(createContentTypeSchema(data))(data);\n};\n\n/**\n * Validator for content type edition\n */\nexport const validateUpdateContentTypeInput = (data: CreateContentTypeInput) => {\n if (has('contentType', data)) {\n removeEmptyDefaults(data.contentType);\n removeDeletedUIDTargetFields(data.contentType as Struct.ContentTypeSchema);\n }\n\n if (has('components', data) && Array.isArray(data.components)) {\n data.components.forEach((comp) => {\n if (has('uid', comp)) {\n removeEmptyDefaults(comp as Struct.ComponentSchema);\n }\n });\n }\n\n return validateYupSchema(createContentTypeSchema(data, { isEdition: true }))(data);\n};\n\nconst forbiddenContentTypeNameValidator = () => {\n const reservedNames = getService('builder').getReservedNames().models;\n\n return {\n name: 'forbiddenContentTypeName',\n message: `Content Type name cannot be one of ${reservedNames.join(', ')}`,\n test(value: unknown) {\n if (typeof value !== 'string') {\n return true;\n }\n\n return !getService('builder').isReservedModelName(value);\n },\n };\n};\n\nconst nameIsAvailable = (isEdition: boolean) => {\n // TODO TS: if strapi.contentTypes (ie, ContentTypes) works as an ArrayLike and is used like this, we may want to ensure it is typed so that it can be without using as\n const usedNames = flatMap((ct: Struct.ContentTypeSchema) => {\n return [ct.info?.singularName, ct.info?.pluralName];\n })(strapi.contentTypes as any);\n\n return {\n name: 'nameAlreadyUsed',\n message: 'contentType: name `${value}` is already being used by another content type.',\n test(value: unknown) {\n // don't check on edition\n if (isEdition) return true;\n\n // ignore if not a string (will be caught in another validator)\n if (typeof value !== 'string') {\n return true;\n }\n\n // compare snake case to check the actual column names that will be used in the database\n return usedNames.every((usedName) => snakeCase(usedName) !== snakeCase(value));\n },\n };\n};\n\nconst nameIsNotExistingCollectionName = (isEdition: boolean) => {\n const usedNames = Object.keys(strapi.contentTypes).map(\n (key) => strapi.contentTypes[key as Internal.UID.ContentType].collectionName\n ) as string[];\n\n return {\n name: 'nameAlreadyUsed',\n message: 'contentType: name `${value}` is already being used by another content type.',\n test(value: unknown) {\n // don't check on edition\n if (isEdition) return true;\n\n // ignore if not a string (will be caught in another validator)\n if (typeof value !== 'string') {\n return true;\n }\n\n // compare snake case to check the actual column names that will be used in the database\n return usedNames.every((usedName) => snakeCase(usedName) !== snakeCase(value));\n },\n };\n};\n\n/**\n * Validates type kind\n */\nconst kindSchema = yup.string().oneOf([typeKinds.SINGLE_TYPE, typeKinds.COLLECTION_TYPE]);\n\nexport const validateKind = validateYupSchema(kindSchema);\n"],"names":["VALID_RELATIONS","typeKinds","SINGLE_TYPE","COLLECTION_TYPE","VALID_TYPES","DEFAULT_TYPES","createContentTypeSchema","data","isEdition","kind","getOr","contentTypeSchema","createSchema","modelType","modelTypes","CONTENT_TYPE","shape","displayName","yup","string","min","required","singularName","test","nameIsAvailable","forbiddenContentTypeNameValidator","isKebabCase","pluralName","nameIsNotExistingCollectionName","value","object","contentType","noUnknown","components","nestedComponentSchema","validateContentTypeInput","validateYupSchema","validateUpdateContentTypeInput","has","removeEmptyDefaults","removeDeletedUIDTargetFields","Array","isArray","forEach","comp","reservedNames","getService","getReservedNames","models","name","message","join","isReservedModelName","usedNames","flatMap","ct","info","strapi","contentTypes","every","usedName","snakeCase","Object","keys","map","key","collectionName","kindSchema","oneOf","validateKind"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"content-type.mjs","sources":["../../../../server/src/controllers/validation/content-type.ts"],"sourcesContent":["/* eslint-disable no-template-curly-in-string */ // yup templates need to be in this format\n\nimport { flatMap, getOr, has, snakeCase } from 'lodash/fp';\nimport { yup, validateYupSchema } from '@strapi/utils';\n\nimport type { Struct, Internal, UID } from '@strapi/types';\n\nimport { getService } from '../../utils';\nimport { modelTypes, DEFAULT_TYPES, typeKinds } from '../../services/constants';\nimport { createSchema } from './model-schema';\nimport { removeEmptyDefaults, removeDeletedUIDTargetFields } from './data-transform';\nimport { nestedComponentSchema } from './component';\n\n// Input flattens some fields of the \"info\" into the root type\nexport type CreateContentTypeInput = {\n uid?: UID.ContentType;\n contentType?: Partial<Struct.ContentTypeSchema> & Partial<Struct.ContentTypeSchemaInfo>;\n components?: Array<\n Partial<Struct.ComponentSchema> &\n Partial<Struct.SchemaInfo> & { tmpUID?: Internal.UID.Component }\n >;\n singularName: Struct.ContentTypeSchemaInfo['singularName'];\n attributes: Struct.SchemaAttributes & Record<string, any>;\n kind: Struct.ContentTypeKind;\n collectionName?: Struct.CollectionTypeSchema['collectionName'];\n pluralName: Struct.ContentTypeSchemaInfo['pluralName'];\n displayName: Struct.ContentTypeSchemaInfo['displayName'];\n description?: Struct.ContentTypeSchemaInfo['description'];\n options?: Struct.SchemaOptions;\n draftAndPublish?: Struct.SchemaOptions['draftAndPublish'];\n pluginOptions?: Struct.ContentTypeSchema['pluginOptions'];\n config?: object;\n plugin?: string;\n};\n\n/**\n * Allowed relation per type kind\n */\nconst VALID_RELATIONS = {\n [typeKinds.SINGLE_TYPE]: [\n 'oneToOne',\n 'oneToMany',\n 'morphOne',\n 'morphMany',\n 'morphToOne',\n 'morphToMany',\n ],\n [typeKinds.COLLECTION_TYPE]: [\n 'oneToOne',\n 'oneToMany',\n 'manyToOne',\n 'manyToMany',\n 'morphOne',\n 'morphMany',\n 'morphToOne',\n 'morphToMany',\n ],\n} as const;\n\n/**\n * Allowed types\n */\nconst VALID_TYPES = [...DEFAULT_TYPES, 'uid', 'component', 'dynamiczone', 'customField'];\n\n/**\n * Returns a yup schema to validate a content type payload\n */\nconst createContentTypeSchema = (data: CreateContentTypeInput, { isEdition = false } = {}) => {\n const kind: keyof typeof VALID_RELATIONS = getOr(\n typeKinds.COLLECTION_TYPE,\n 'contentType.kind',\n data\n );\n\n const contentTypeSchema = createSchema(VALID_TYPES, VALID_RELATIONS[kind] || [], {\n modelType: modelTypes.CONTENT_TYPE,\n })\n .shape({\n displayName: yup.string().min(1).required(),\n singularName: yup\n .string()\n .min(1)\n .test(nameIsAvailable(isEdition))\n .test(forbiddenContentTypeNameValidator())\n .isKebabCase()\n .required(),\n pluralName: yup\n .string()\n .min(1)\n .test(nameIsAvailable(isEdition))\n .test(nameIsNotExistingCollectionName(isEdition)) // TODO: v5: require singularName to not match a collection name\n .test(forbiddenContentTypeNameValidator())\n .isKebabCase()\n .required(),\n })\n .test(\n 'singularName-not-equal-pluralName',\n '${path}: singularName and pluralName should be different',\n (value) => value.singularName !== value.pluralName\n );\n\n return yup\n .object({\n // FIXME .noUnknown(false) will strip off the unwanted properties without throwing an error\n // Why not having .noUnknown() ? Because we want to be able to add options relatable to EE features\n // without having any reference to them in CE.\n // Why not handle an \"options\" object in the content-type ? The admin panel needs lots of rework\n // to be able to send this options object instead of top-level attributes.\n // @nathan-pichon 20/02/2023\n contentType: contentTypeSchema.required().noUnknown(false),\n components: nestedComponentSchema,\n })\n .noUnknown();\n};\n\n/**\n * Validator for content type creation\n */\nexport const validateContentTypeInput = (data: CreateContentTypeInput) => {\n return validateYupSchema(createContentTypeSchema(data))(data);\n};\n\n/**\n * Validator for content type edition\n */\nexport const validateUpdateContentTypeInput = (data: CreateContentTypeInput) => {\n if (has('contentType', data)) {\n removeEmptyDefaults(data.contentType);\n removeDeletedUIDTargetFields(data.contentType as Struct.ContentTypeSchema);\n }\n\n if (has('components', data) && Array.isArray(data.components)) {\n data.components.forEach((comp) => {\n if (has('uid', comp)) {\n removeEmptyDefaults(comp as Struct.ComponentSchema);\n }\n });\n }\n\n return validateYupSchema(createContentTypeSchema(data, { isEdition: true }))(data);\n};\n\nconst forbiddenContentTypeNameValidator = () => {\n const reservedNames = getService('builder').getReservedNames().models;\n\n return {\n name: 'forbiddenContentTypeName',\n message: `Content Type name cannot be one of ${reservedNames.join(', ')}`,\n test(value: unknown) {\n if (typeof value !== 'string') {\n return true;\n }\n\n return !getService('builder').isReservedModelName(value);\n },\n };\n};\n\nconst nameIsAvailable = (isEdition: boolean) => {\n // TODO TS: if strapi.contentTypes (ie, ContentTypes) works as an ArrayLike and is used like this, we may want to ensure it is typed so that it can be without using as\n const usedNames = flatMap((ct: Struct.ContentTypeSchema) => {\n return [ct.info?.singularName, ct.info?.pluralName];\n })(strapi.contentTypes as any);\n\n return {\n name: 'nameAlreadyUsed',\n message: 'contentType: name `${value}` is already being used by another content type.',\n test(value: unknown) {\n // don't check on edition\n if (isEdition) return true;\n\n // ignore if not a string (will be caught in another validator)\n if (typeof value !== 'string') {\n return true;\n }\n\n // compare snake case to check the actual column names that will be used in the database\n return usedNames.every((usedName) => snakeCase(usedName) !== snakeCase(value));\n },\n };\n};\n\nconst nameIsNotExistingCollectionName = (isEdition: boolean) => {\n const usedNames = Object.keys(strapi.contentTypes).map(\n (key) => strapi.contentTypes[key as Internal.UID.ContentType].collectionName\n ) as string[];\n\n return {\n name: 'nameAlreadyUsed',\n message: 'contentType: name `${value}` is already being used by another content type.',\n test(value: unknown) {\n // don't check on edition\n if (isEdition) return true;\n\n // ignore if not a string (will be caught in another validator)\n if (typeof value !== 'string') {\n return true;\n }\n\n // compare snake case to check the actual column names that will be used in the database\n return usedNames.every((usedName) => snakeCase(usedName) !== snakeCase(value));\n },\n };\n};\n\n/**\n * Validates type kind\n */\nconst kindSchema = yup.string().oneOf([typeKinds.SINGLE_TYPE, typeKinds.COLLECTION_TYPE]);\n\nexport const validateKind = validateYupSchema(kindSchema);\n"],"names":["VALID_RELATIONS","typeKinds","SINGLE_TYPE","COLLECTION_TYPE","VALID_TYPES","DEFAULT_TYPES","createContentTypeSchema","data","isEdition","kind","getOr","contentTypeSchema","createSchema","modelType","modelTypes","CONTENT_TYPE","shape","displayName","yup","string","min","required","singularName","test","nameIsAvailable","forbiddenContentTypeNameValidator","isKebabCase","pluralName","nameIsNotExistingCollectionName","value","object","contentType","noUnknown","components","nestedComponentSchema","validateContentTypeInput","validateYupSchema","validateUpdateContentTypeInput","has","removeEmptyDefaults","removeDeletedUIDTargetFields","Array","isArray","forEach","comp","reservedNames","getService","getReservedNames","models","name","message","join","isReservedModelName","usedNames","flatMap","ct","info","strapi","contentTypes","every","usedName","snakeCase","Object","keys","map","key","collectionName","kindSchema","oneOf","validateKind"],"mappings":"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"}
|
|
@@ -545,6 +545,7 @@ const baseContentTypeSchema = zod.z.object({
|
|
|
545
545
|
});
|
|
546
546
|
const baseCreateContentTypeSchema = baseContentTypeSchema.extend({
|
|
547
547
|
action: zod.z.literal('create'),
|
|
548
|
+
plugin: zod.z.string().min(1).optional(),
|
|
548
549
|
collectionName: zod.z.string().regex(common.COLLECTION_NAME_REGEX).optional(),
|
|
549
550
|
singularName: zod.z.string().min(1).regex(common.KEBAB_BASE_REGEX, 'Must be kebab case').refine((value)=>!builder.isReservedModelName(value), 'Model name is reserved'),
|
|
550
551
|
pluralName: zod.z.string().min(1).regex(common.KEBAB_BASE_REGEX, 'Must be kebab case').refine((value)=>!builder.isReservedModelName(value), 'Model name is reserved'),
|
|
@@ -613,12 +614,14 @@ const schemaSchema = zod.z.object({
|
|
|
613
614
|
deleteContentTypeSchema
|
|
614
615
|
]).superRefine(verifySingularAndPluralNames)).optional().default([])
|
|
615
616
|
});
|
|
616
|
-
const
|
|
617
|
+
const updateSchemaInput = zod.z.object({
|
|
617
618
|
data: schemaSchema
|
|
618
619
|
}, {
|
|
619
620
|
invalid_type_error: 'Invalid schema, expected an object with a data property',
|
|
620
621
|
required_error: 'Schema is required'
|
|
621
|
-
})
|
|
622
|
+
});
|
|
623
|
+
// TODO: Remove cast when content-type-builder migrates to Zod 4
|
|
624
|
+
const validateUpdateSchema = utils.validateZodSchema(updateSchemaInput);
|
|
622
625
|
|
|
623
626
|
exports.maxGreaterThanMin = maxGreaterThanMin;
|
|
624
627
|
exports.maxLengthGreaterThanMinLength = maxLengthGreaterThanMinLength;
|