@strapi/content-type-builder 5.56.0 → 5.57.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/toCTB.js +117 -13
- package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.js.map +1 -1
- package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.mjs +118 -13
- package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.mjs.map +1 -1
- package/dist/admin/components/AIChat/providers/SchemaProvider.js +31 -19
- package/dist/admin/components/AIChat/providers/SchemaProvider.js.map +1 -1
- package/dist/admin/components/AIChat/providers/SchemaProvider.mjs +31 -19
- package/dist/admin/components/AIChat/providers/SchemaProvider.mjs.map +1 -1
- package/dist/admin/components/DataManager/DataManagerContext.js.map +1 -1
- package/dist/admin/components/DataManager/DataManagerContext.mjs.map +1 -1
- package/dist/admin/components/DataManager/DataManagerProvider.js +166 -6
- package/dist/admin/components/DataManager/DataManagerProvider.js.map +1 -1
- package/dist/admin/components/DataManager/DataManagerProvider.mjs +165 -7
- package/dist/admin/components/DataManager/DataManagerProvider.mjs.map +1 -1
- package/dist/admin/components/DataManager/RenameMigrationModal.js +285 -0
- package/dist/admin/components/DataManager/RenameMigrationModal.js.map +1 -0
- package/dist/admin/components/DataManager/RenameMigrationModal.mjs +257 -0
- package/dist/admin/components/DataManager/RenameMigrationModal.mjs.map +1 -0
- package/dist/admin/components/DataManager/reducer.js +107 -2
- package/dist/admin/components/DataManager/reducer.js.map +1 -1
- package/dist/admin/components/DataManager/reducer.mjs +106 -2
- package/dist/admin/components/DataManager/reducer.mjs.map +1 -1
- package/dist/admin/components/DataManager/utils/cleanData.js +8 -1
- package/dist/admin/components/DataManager/utils/cleanData.js.map +1 -1
- package/dist/admin/components/DataManager/utils/cleanData.mjs +8 -1
- package/dist/admin/components/DataManager/utils/cleanData.mjs.map +1 -1
- package/dist/admin/components/DataManager/utils/groupRenameChains.js +86 -0
- package/dist/admin/components/DataManager/utils/groupRenameChains.js.map +1 -0
- package/dist/admin/components/DataManager/utils/groupRenameChains.mjs +84 -0
- package/dist/admin/components/DataManager/utils/groupRenameChains.mjs.map +1 -0
- package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.js +29 -0
- package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.js.map +1 -0
- package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.mjs +27 -0
- package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.mjs.map +1 -0
- package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.js +35 -0
- package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.js.map +1 -0
- package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.mjs +33 -0
- package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.mjs.map +1 -0
- package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.js +48 -0
- package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.js.map +1 -0
- package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.mjs +45 -0
- package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.mjs.map +1 -0
- package/dist/admin/components/FormModal/FormModal.js +142 -8
- package/dist/admin/components/FormModal/FormModal.js.map +1 -1
- package/dist/admin/components/FormModal/FormModal.mjs +143 -9
- package/dist/admin/components/FormModal/FormModal.mjs.map +1 -1
- package/dist/admin/components/FormModal/attributes/validation/common.js +6 -5
- package/dist/admin/components/FormModal/attributes/validation/common.js.map +1 -1
- package/dist/admin/components/FormModal/attributes/validation/common.mjs +1 -1
- package/dist/admin/components/FormModal/attributes/validation/common.mjs.map +1 -1
- package/dist/admin/components/FormModal/component/createComponentSchema.js +10 -7
- package/dist/admin/components/FormModal/component/createComponentSchema.js.map +1 -1
- package/dist/admin/components/FormModal/component/createComponentSchema.mjs +1 -1
- package/dist/admin/components/FormModal/component/createComponentSchema.mjs.map +1 -1
- package/dist/admin/components/FormModal/contentType/createContentTypeSchema.js +24 -21
- package/dist/admin/components/FormModal/contentType/createContentTypeSchema.js.map +1 -1
- package/dist/admin/components/FormModal/contentType/createContentTypeSchema.mjs +1 -1
- package/dist/admin/components/FormModal/contentType/createContentTypeSchema.mjs.map +1 -1
- package/dist/admin/components/FormModal/forms/utils/createCollectionName.js +3 -2
- package/dist/admin/components/FormModal/forms/utils/createCollectionName.js.map +1 -1
- package/dist/admin/components/FormModal/forms/utils/createCollectionName.mjs +1 -1
- package/dist/admin/components/FormModal/forms/utils/createCollectionName.mjs.map +1 -1
- package/dist/admin/components/FormModal/utils/getRenameStorageChange.js +73 -0
- package/dist/admin/components/FormModal/utils/getRenameStorageChange.js.map +1 -0
- package/dist/admin/components/FormModal/utils/getRenameStorageChange.mjs +70 -0
- package/dist/admin/components/FormModal/utils/getRenameStorageChange.mjs.map +1 -0
- package/dist/admin/src/components/AIChat/lib/transforms/schemas/toCTB.d.ts +4 -3
- package/dist/admin/src/components/AIChat/lib/types/schema.d.ts +6 -1
- package/dist/admin/src/components/DataManager/DataManagerContext.d.ts +28 -2
- package/dist/admin/src/components/DataManager/RenameMigrationModal.d.ts +73 -0
- package/dist/admin/src/components/DataManager/reducer.d.ts +17 -2
- package/dist/admin/src/components/DataManager/utils/cleanData.d.ts +16 -0
- package/dist/admin/src/components/DataManager/utils/groupRenameChains.d.ts +31 -0
- package/dist/admin/src/components/DataManager/utils/isStorageCompatibleRename.d.ts +10 -0
- package/dist/admin/src/components/DataManager/utils/resolveAfterEditRenameConsent.d.ts +24 -0
- package/dist/admin/src/components/DataManager/utils/splitChainsByInheritedConsent.d.ts +26 -0
- package/dist/admin/src/components/FormModal/utils/getRenameStorageChange.d.ts +40 -0
- package/dist/admin/src/types.d.ts +23 -0
- package/dist/admin/translations/en.json.js +12 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +12 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/server/config.js +24 -3
- package/dist/server/config.js.map +1 -1
- package/dist/server/config.mjs +21 -3
- package/dist/server/config.mjs.map +1 -1
- package/dist/server/controllers/schema.js +2 -2
- package/dist/server/controllers/schema.js.map +1 -1
- package/dist/server/controllers/schema.mjs +1 -1
- package/dist/server/controllers/schema.mjs.map +1 -1
- package/dist/server/controllers/validation/content-type.js +9 -11
- package/dist/server/controllers/validation/content-type.js.map +1 -1
- package/dist/server/controllers/validation/content-type.mjs +7 -9
- package/dist/server/controllers/validation/content-type.mjs.map +1 -1
- package/dist/server/controllers/validation/model-schema.js +2 -3
- package/dist/server/controllers/validation/model-schema.js.map +1 -1
- package/dist/server/controllers/validation/model-schema.mjs +1 -2
- package/dist/server/controllers/validation/model-schema.mjs.map +1 -1
- package/dist/server/controllers/validation/relations.js +1 -2
- package/dist/server/controllers/validation/relations.js.map +1 -1
- package/dist/server/controllers/validation/relations.mjs +1 -2
- package/dist/server/controllers/validation/relations.mjs.map +1 -1
- package/dist/server/controllers/validation/schema.js +42 -23
- package/dist/server/controllers/validation/schema.js.map +1 -1
- package/dist/server/controllers/validation/schema.mjs +43 -24
- package/dist/server/controllers/validation/schema.mjs.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/services/content-types.js +1 -2
- package/dist/server/services/content-types.js.map +1 -1
- package/dist/server/services/content-types.mjs +2 -3
- package/dist/server/services/content-types.mjs.map +1 -1
- package/dist/server/services/migration-builder/index.js +580 -0
- package/dist/server/services/migration-builder/index.js.map +1 -0
- package/dist/server/services/migration-builder/index.mjs +573 -0
- package/dist/server/services/migration-builder/index.mjs.map +1 -0
- package/dist/server/services/schema-builder/content-type-builder.js +31 -1
- package/dist/server/services/schema-builder/content-type-builder.js.map +1 -1
- package/dist/server/services/schema-builder/content-type-builder.mjs +31 -1
- package/dist/server/services/schema-builder/content-type-builder.mjs.map +1 -1
- package/dist/server/services/schema-mutation.js +30 -2
- package/dist/server/services/schema-mutation.js.map +1 -1
- package/dist/server/services/schema-mutation.mjs +10 -2
- package/dist/server/services/schema-mutation.mjs.map +1 -1
- package/dist/server/services/schema.js +259 -15
- package/dist/server/services/schema.js.map +1 -1
- package/dist/server/services/schema.mjs +252 -9
- package/dist/server/services/schema.mjs.map +1 -1
- package/dist/server/src/config.d.ts +23 -2
- package/dist/server/src/config.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/content-type.d.ts +0 -1
- package/dist/server/src/controllers/validation/content-type.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/schema.d.ts +28 -0
- package/dist/server/src/controllers/validation/schema.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +10 -2
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/services/content-types.d.ts.map +1 -1
- package/dist/server/src/services/migration-builder/index.d.ts +83 -0
- package/dist/server/src/services/migration-builder/index.d.ts.map +1 -0
- package/dist/server/src/services/schema-builder/content-type-builder.d.ts.map +1 -1
- package/dist/server/src/services/schema-mutation.d.ts +4 -2
- package/dist/server/src/services/schema-mutation.d.ts.map +1 -1
- package/dist/server/src/services/schema.d.ts +19 -0
- package/dist/server/src/services/schema.d.ts.map +1 -1
- package/package.json +7 -6
|
@@ -4,6 +4,7 @@ var isEqual = require('lodash/isEqual');
|
|
|
4
4
|
var omit = require('lodash/omit');
|
|
5
5
|
var pluralize = require('pluralize');
|
|
6
6
|
var applyPrivateSearchDefault = require('../../../../../utils/applyPrivateSearchDefault.js');
|
|
7
|
+
var isStorageCompatibleRename = require('../../../../DataManager/utils/isStorageCompatibleRename.js');
|
|
7
8
|
|
|
8
9
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
10
|
|
|
@@ -11,6 +12,66 @@ var isEqual__default = /*#__PURE__*/_interopDefault(isEqual);
|
|
|
11
12
|
var omit__default = /*#__PURE__*/_interopDefault(omit);
|
|
12
13
|
var pluralize__default = /*#__PURE__*/_interopDefault(pluralize);
|
|
13
14
|
|
|
15
|
+
const RENAME_METADATA_KEYS = [
|
|
16
|
+
'previousName',
|
|
17
|
+
'renamedFrom',
|
|
18
|
+
'action'
|
|
19
|
+
];
|
|
20
|
+
const collectExplicitAttributeRenames = (attributes)=>{
|
|
21
|
+
const renames = [];
|
|
22
|
+
const sanitizedAttributes = {
|
|
23
|
+
...attributes
|
|
24
|
+
};
|
|
25
|
+
Object.entries(attributes).forEach(([newName, rawAttr])=>{
|
|
26
|
+
if (!rawAttr || typeof rawAttr !== 'object') {
|
|
27
|
+
delete sanitizedAttributes[newName];
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const previousName = rawAttr.previousName ?? rawAttr.renamedFrom;
|
|
31
|
+
if (typeof previousName !== 'string' || !previousName || previousName === newName) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
renames.push({
|
|
35
|
+
oldName: previousName,
|
|
36
|
+
newName
|
|
37
|
+
});
|
|
38
|
+
sanitizedAttributes[newName] = omit__default.default(rawAttr, RENAME_METADATA_KEYS);
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
renames,
|
|
42
|
+
attributes: sanitizedAttributes
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const dedupeRenames = (renames)=>{
|
|
46
|
+
const seen = new Set();
|
|
47
|
+
return renames.filter((hop)=>{
|
|
48
|
+
const key = `${hop.oldName}->${hop.newName}`;
|
|
49
|
+
if (seen.has(key)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
seen.add(key);
|
|
53
|
+
return true;
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
const applyExplicitRenames = (processedAttributes, removedAttributes, explicitRenames)=>{
|
|
57
|
+
if (explicitRenames.length === 0) {
|
|
58
|
+
return {
|
|
59
|
+
processedAttributes,
|
|
60
|
+
removedAttributes
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const consumedRemoved = new Set(explicitRenames.map((hop)=>hop.oldName).filter(Boolean));
|
|
64
|
+
explicitRenames.forEach((hop)=>{
|
|
65
|
+
const newAttr = processedAttributes.find((attr)=>attr.name === hop.newName);
|
|
66
|
+
if (newAttr?.status === 'NEW') {
|
|
67
|
+
newAttr.status = 'CHANGED';
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
processedAttributes,
|
|
72
|
+
removedAttributes: removedAttributes.filter((attr)=>!consumedRemoved.has(attr.name))
|
|
73
|
+
};
|
|
74
|
+
};
|
|
14
75
|
const isPluginContentTypeUid = (uid)=>uid.startsWith('plugin::');
|
|
15
76
|
const isContentTypeKind = (kind)=>{
|
|
16
77
|
return kind === 'collectionType' || kind === 'singleType';
|
|
@@ -78,39 +139,77 @@ const ACTION_TO_STATUS = {
|
|
|
78
139
|
return oldSchema.status;
|
|
79
140
|
};
|
|
80
141
|
/**
|
|
81
|
-
* Transform attributes from Chat format to CTB format
|
|
82
|
-
* Also performs a diff to determine the status of each attribute
|
|
83
|
-
|
|
142
|
+
* Transform attributes from Chat format to CTB format while collecting rename metadata.
|
|
143
|
+
* Also performs a diff to determine the status of each attribute. Renames are only
|
|
144
|
+
* taken from explicit metadata the AI provides (`previousName` / `renamedFrom`, or a
|
|
145
|
+
* top-level `renames` array), never inferred from a remove/add diff, so data is never
|
|
146
|
+
* moved unless a rename was explicitly requested.
|
|
147
|
+
*/ const transformAttributesAndRenamesFromChatToCTB = ({ action, attributes: rawAttributes, renames: schemaRenames = [] }, oldSchema)=>{
|
|
148
|
+
const { attributes, renames: explicitAttributeRenames } = collectExplicitAttributeRenames(rawAttributes);
|
|
84
149
|
// If it's a new schema or no oldAttributes provided, all attributes are NEW
|
|
85
150
|
if (action === 'create' || !oldSchema) {
|
|
86
|
-
return
|
|
151
|
+
return {
|
|
152
|
+
attributes: Object.entries(attributes).map(([name, attribute])=>createAttributeWithStatus(name, attribute, 'NEW')),
|
|
153
|
+
renames: []
|
|
154
|
+
};
|
|
87
155
|
}
|
|
88
156
|
// Convert old attributes array to a lookup map for faster access
|
|
89
157
|
const oldAttributesMap = oldSchema.attributes.reduce((acc, attr)=>({
|
|
90
158
|
...acc,
|
|
91
159
|
[attr.name]: attr
|
|
92
160
|
}), {});
|
|
161
|
+
// Only renames that keep the field's storage can be replayed as a migration;
|
|
162
|
+
// the rest fall back to remove + add. A hop whose old or new side is unknown
|
|
163
|
+
// cannot be checked (nor replayed by the server), so it is dropped too.
|
|
164
|
+
const compatibleRenames = [
|
|
165
|
+
...schemaRenames,
|
|
166
|
+
...explicitAttributeRenames
|
|
167
|
+
].filter((hop)=>{
|
|
168
|
+
const previousAttribute = oldAttributesMap[hop.oldName];
|
|
169
|
+
const nextAttribute = attributes[hop.newName];
|
|
170
|
+
if (!previousAttribute || !nextAttribute) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
return isStorageCompatibleRename.isStorageCompatibleRename(previousAttribute, {
|
|
174
|
+
...nextAttribute,
|
|
175
|
+
name: hop.newName
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
const compatibleAttributeRenames = explicitAttributeRenames.filter((hop)=>compatibleRenames.includes(hop));
|
|
179
|
+
const explicitOldNames = new Set(compatibleAttributeRenames.map((hop)=>hop.oldName));
|
|
93
180
|
// Process current attributes (new and changed)
|
|
94
181
|
const processedAttributes = Object.entries(attributes).map(([name, attr])=>{
|
|
95
182
|
const oldAttr = oldAttributesMap[name];
|
|
96
|
-
const
|
|
183
|
+
const isExplicitRename = compatibleAttributeRenames.some((hop)=>hop.newName === name);
|
|
184
|
+
let status = determineAttributeStatus({
|
|
97
185
|
...attr,
|
|
98
186
|
name
|
|
99
187
|
}, oldAttr, oldSchema);
|
|
188
|
+
if (isExplicitRename) {
|
|
189
|
+
status = oldSchema.status === 'NEW' ? 'NEW' : 'CHANGED';
|
|
190
|
+
}
|
|
100
191
|
return createAttributeWithStatus(name, attr, status);
|
|
101
192
|
});
|
|
102
193
|
// No need to mark removed attributes if the old schema is new, just remove it from the list
|
|
103
194
|
// TODO: Else a validation error occurs on the backend side.
|
|
104
195
|
if (oldSchema?.status === 'NEW') {
|
|
105
|
-
return
|
|
196
|
+
return {
|
|
197
|
+
attributes: processedAttributes,
|
|
198
|
+
renames: []
|
|
199
|
+
};
|
|
106
200
|
}
|
|
107
201
|
// Find removed attributes (exist in old but not in new)
|
|
108
|
-
const removedAttributes = Object.entries(oldAttributesMap).filter(([name])=>!attributes[name]).map(([name, oldAttr])=>createAttributeWithStatus(name, oldAttr, 'REMOVED'));
|
|
202
|
+
const removedAttributes = Object.entries(oldAttributesMap).filter(([name])=>!attributes[name] && !explicitOldNames.has(name)).map(([name, oldAttr])=>createAttributeWithStatus(name, oldAttr, 'REMOVED'));
|
|
203
|
+
const reconciled = applyExplicitRenames(processedAttributes, removedAttributes, compatibleRenames);
|
|
109
204
|
// Combine both sets of attributes
|
|
110
|
-
|
|
111
|
-
...processedAttributes,
|
|
112
|
-
...removedAttributes
|
|
205
|
+
const combinedAttributes = [
|
|
206
|
+
...reconciled.processedAttributes,
|
|
207
|
+
...reconciled.removedAttributes
|
|
113
208
|
];
|
|
209
|
+
return {
|
|
210
|
+
attributes: combinedAttributes,
|
|
211
|
+
renames: dedupeRenames(compatibleRenames)
|
|
212
|
+
};
|
|
114
213
|
};
|
|
115
214
|
/**
|
|
116
215
|
* Transform schema format
|
|
@@ -122,11 +221,16 @@ const ACTION_TO_STATUS = {
|
|
|
122
221
|
*/ const transformChatToCTB = (schema, oldSchema)=>{
|
|
123
222
|
const singularName = pluralize__default.default.singular(schema.name).toLowerCase().replace(/ /g, '-');
|
|
124
223
|
const pluralName = pluralize__default.default.plural(schema.name).toLowerCase().replace(/ /g, '-');
|
|
224
|
+
const { attributes, renames } = transformAttributesAndRenamesFromChatToCTB(schema, oldSchema);
|
|
225
|
+
const renamePayload = renames.length > 0 ? {
|
|
226
|
+
renames
|
|
227
|
+
} : {};
|
|
125
228
|
if (schema.modelType === 'component') {
|
|
126
229
|
return {
|
|
127
230
|
category: schema.category || 'default',
|
|
128
231
|
modelName: singularName,
|
|
129
|
-
attributes
|
|
232
|
+
attributes,
|
|
233
|
+
...renamePayload,
|
|
130
234
|
info: {
|
|
131
235
|
displayName: schema.name,
|
|
132
236
|
description: schema.description
|
|
@@ -153,7 +257,8 @@ const ACTION_TO_STATUS = {
|
|
|
153
257
|
pluralName: previousContentType?.info.pluralName ?? pluralName
|
|
154
258
|
},
|
|
155
259
|
collectionName: pluralName,
|
|
156
|
-
attributes
|
|
260
|
+
attributes,
|
|
261
|
+
...renamePayload,
|
|
157
262
|
options: {
|
|
158
263
|
draftAndPublish: schema.options?.draftAndPublish ?? true
|
|
159
264
|
},
|
|
@@ -207,6 +312,5 @@ const ACTION_TO_STATUS = {
|
|
|
207
312
|
return contentTypeBase;
|
|
208
313
|
};
|
|
209
314
|
|
|
210
|
-
exports.transformAttributesFromChatToCTB = transformAttributesFromChatToCTB;
|
|
211
315
|
exports.transformChatToCTB = transformChatToCTB;
|
|
212
316
|
//# sourceMappingURL=toCTB.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toCTB.js","sources":["../../../../../../../admin/src/components/AIChat/lib/transforms/schemas/toCTB.ts"],"sourcesContent":["import isEqual from 'lodash/isEqual';\nimport omit from 'lodash/omit';\nimport pluralize from 'pluralize';\n\nimport { applyPrivateSearchDefault } from '../../../../../utils/applyPrivateSearchDefault';\n\nimport type { ContentType, Component, AnyAttribute } from '../../../../../types';\nimport type { Schema, SchemaAttribute } from '../../types/schema';\nimport type { Struct, UID } from '@strapi/types';\n\nconst isPluginContentTypeUid = (uid: string) => uid.startsWith('plugin::');\n\nconst isContentTypeKind = (kind: Schema['kind']): kind is Struct.ContentTypeKind => {\n return kind === 'collectionType' || kind === 'singleType';\n};\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: SchemaAttribute | AnyAttribute,\n status: AnyAttribute['status']\n): AnyAttribute =>\n ({\n ...applyPrivateSearchDefault(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, unknown>,\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 UID.Component,\n collectionName: pluralName,\n status: transformStatusFromChatToCTB(schema, oldSchema),\n globalId: singularName,\n } satisfies Component;\n }\n\n const previousContentType = oldSchema?.modelType === 'contentType' ? oldSchema : undefined;\n const kind = isContentTypeKind(schema.kind) ? schema.kind : 'collectionType';\n\n const contentTypeBase = {\n uid: schema.uid as UID.ContentType,\n modelType: 'contentType',\n modelName: singularName,\n kind,\n info: {\n displayName: schema.name.charAt(0).toUpperCase() + schema.name.slice(1),\n // Always keep the old by default\n singularName: previousContentType?.info.singularName ?? singularName,\n // Always keep the old by default\n pluralName: previousContentType?.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","isContentTypeKind","kind","isPluginContentType","schema","oldSchema","plugin","modelType","ct","Boolean","String","ACTION_TO_STATUS","create","remove","update","createAttributeWithStatus","name","attributeData","status","applyPrivateSearchDefault","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","previousContentType","undefined","contentTypeBase","charAt","toUpperCase","slice","options","draftAndPublish","pluginOptions","i18n","localized","visible","restrictRelationsTo","prev"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toCTB.js","sources":["../../../../../../../admin/src/components/AIChat/lib/transforms/schemas/toCTB.ts"],"sourcesContent":["import isEqual from 'lodash/isEqual';\nimport omit from 'lodash/omit';\nimport pluralize from 'pluralize';\n\nimport { applyPrivateSearchDefault } from '../../../../../utils/applyPrivateSearchDefault';\nimport { isStorageCompatibleRename } from '../../../../DataManager/utils/isStorageCompatibleRename';\n\nimport type { ContentType, Component, AnyAttribute, RenameHop } from '../../../../../types';\nimport type { Schema, SchemaAttribute } from '../../types/schema';\nimport type { Struct, UID } from '@strapi/types';\n\nconst RENAME_METADATA_KEYS = ['previousName', 'renamedFrom', 'action'] as const;\n\nconst collectExplicitAttributeRenames = (\n attributes: Schema['attributes']\n): { renames: RenameHop[]; attributes: Schema['attributes'] } => {\n const renames: RenameHop[] = [];\n const sanitizedAttributes = { ...attributes };\n\n Object.entries(attributes).forEach(([newName, rawAttr]) => {\n if (!rawAttr || typeof rawAttr !== 'object') {\n delete sanitizedAttributes[newName];\n return;\n }\n\n const previousName = rawAttr.previousName ?? rawAttr.renamedFrom;\n if (typeof previousName !== 'string' || !previousName || previousName === newName) {\n return;\n }\n\n renames.push({ oldName: previousName, newName });\n sanitizedAttributes[newName] = omit(rawAttr, RENAME_METADATA_KEYS) as SchemaAttribute;\n });\n\n return { renames, attributes: sanitizedAttributes };\n};\n\nconst dedupeRenames = (renames: RenameHop[]): RenameHop[] => {\n const seen = new Set<string>();\n\n return renames.filter((hop) => {\n const key = `${hop.oldName}->${hop.newName}`;\n if (seen.has(key)) {\n return false;\n }\n\n seen.add(key);\n return true;\n });\n};\n\nconst applyExplicitRenames = (\n processedAttributes: AnyAttribute[],\n removedAttributes: AnyAttribute[],\n explicitRenames: RenameHop[]\n): { processedAttributes: AnyAttribute[]; removedAttributes: AnyAttribute[] } => {\n if (explicitRenames.length === 0) {\n return { processedAttributes, removedAttributes };\n }\n\n const consumedRemoved = new Set(explicitRenames.map((hop) => hop.oldName).filter(Boolean));\n\n explicitRenames.forEach((hop) => {\n const newAttr = processedAttributes.find((attr) => attr.name === hop.newName);\n if (newAttr?.status === 'NEW') {\n newAttr.status = 'CHANGED';\n }\n });\n\n return {\n processedAttributes,\n removedAttributes: removedAttributes.filter((attr) => !consumedRemoved.has(attr.name)),\n };\n};\n\nconst isPluginContentTypeUid = (uid: string) => uid.startsWith('plugin::');\n\nconst isContentTypeKind = (kind: Schema['kind']): kind is Struct.ContentTypeKind => {\n return kind === 'collectionType' || kind === 'singleType';\n};\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: SchemaAttribute | AnyAttribute,\n status: AnyAttribute['status']\n): AnyAttribute =>\n ({\n ...applyPrivateSearchDefault(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, unknown>,\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\ntype TransformAttributesResult = {\n attributes: AnyAttribute[];\n renames: RenameHop[];\n};\n\n/**\n * Transform attributes from Chat format to CTB format while collecting rename metadata.\n * Also performs a diff to determine the status of each attribute. Renames are only\n * taken from explicit metadata the AI provides (`previousName` / `renamedFrom`, or a\n * top-level `renames` array), never inferred from a remove/add diff, so data is never\n * moved unless a rename was explicitly requested.\n */\nconst transformAttributesAndRenamesFromChatToCTB = (\n { action, attributes: rawAttributes, renames: schemaRenames = [] }: Schema,\n oldSchema?: ContentType | Component\n): TransformAttributesResult => {\n const { attributes, renames: explicitAttributeRenames } =\n collectExplicitAttributeRenames(rawAttributes);\n\n // If it's a new schema or no oldAttributes provided, all attributes are NEW\n if (action === 'create' || !oldSchema) {\n return {\n attributes: Object.entries(attributes).map(([name, attribute]) =>\n createAttributeWithStatus(name, attribute, 'NEW')\n ),\n renames: [],\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 // Only renames that keep the field's storage can be replayed as a migration;\n // the rest fall back to remove + add. A hop whose old or new side is unknown\n // cannot be checked (nor replayed by the server), so it is dropped too.\n const compatibleRenames = [...schemaRenames, ...explicitAttributeRenames].filter((hop) => {\n const previousAttribute = oldAttributesMap[hop.oldName];\n const nextAttribute = attributes[hop.newName];\n\n if (!previousAttribute || !nextAttribute) {\n return false;\n }\n\n return isStorageCompatibleRename(previousAttribute, {\n ...nextAttribute,\n name: hop.newName,\n } as AnyAttribute);\n });\n const compatibleAttributeRenames = explicitAttributeRenames.filter((hop) =>\n compatibleRenames.includes(hop)\n );\n\n const explicitOldNames = new Set(compatibleAttributeRenames.map((hop) => hop.oldName));\n\n // Process current attributes (new and changed)\n const processedAttributes = Object.entries(attributes).map(([name, attr]) => {\n const oldAttr = oldAttributesMap[name];\n const isExplicitRename = compatibleAttributeRenames.some((hop) => hop.newName === name);\n let status = determineAttributeStatus({ ...attr, name }, oldAttr, oldSchema);\n if (isExplicitRename) {\n status = oldSchema.status === 'NEW' ? 'NEW' : 'CHANGED';\n }\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 { attributes: processedAttributes, renames: [] };\n }\n\n // Find removed attributes (exist in old but not in new)\n const removedAttributes = Object.entries(oldAttributesMap)\n .filter(([name]) => !attributes[name] && !explicitOldNames.has(name))\n .map(([name, oldAttr]) => createAttributeWithStatus(name, oldAttr, 'REMOVED'));\n\n const reconciled = applyExplicitRenames(\n processedAttributes,\n removedAttributes,\n compatibleRenames\n );\n\n // Combine both sets of attributes\n const combinedAttributes = [...reconciled.processedAttributes, ...reconciled.removedAttributes];\n\n return {\n attributes: combinedAttributes,\n renames: dedupeRenames(compatibleRenames),\n };\n};\n\n/**\n * Transform attributes from Chat format to CTB format.\n *\n * Keep the existing array return type for callers that only need attributes.\n */\nexport const transformAttributesFromChatToCTB = (\n schema: Schema,\n oldSchema?: ContentType | Component\n): AnyAttribute[] => transformAttributesAndRenamesFromChatToCTB(schema, oldSchema).attributes;\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 const { attributes, renames } = transformAttributesAndRenamesFromChatToCTB(schema, oldSchema);\n const renamePayload = renames.length > 0 ? { renames } : {};\n\n if (schema.modelType === 'component') {\n return {\n category: schema.category || 'default',\n modelName: singularName,\n attributes,\n ...renamePayload,\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 UID.Component,\n collectionName: pluralName,\n status: transformStatusFromChatToCTB(schema, oldSchema),\n globalId: singularName,\n } satisfies Component;\n }\n\n const previousContentType = oldSchema?.modelType === 'contentType' ? oldSchema : undefined;\n const kind = isContentTypeKind(schema.kind) ? schema.kind : 'collectionType';\n\n const contentTypeBase = {\n uid: schema.uid as UID.ContentType,\n modelType: 'contentType',\n modelName: singularName,\n kind,\n info: {\n displayName: schema.name.charAt(0).toUpperCase() + schema.name.slice(1),\n // Always keep the old by default\n singularName: previousContentType?.info.singularName ?? singularName,\n // Always keep the old by default\n pluralName: previousContentType?.info.pluralName ?? pluralName,\n },\n collectionName: pluralName,\n attributes,\n ...renamePayload,\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":["RENAME_METADATA_KEYS","collectExplicitAttributeRenames","attributes","renames","sanitizedAttributes","Object","entries","forEach","newName","rawAttr","previousName","renamedFrom","push","oldName","omit","dedupeRenames","seen","Set","filter","hop","key","has","add","applyExplicitRenames","processedAttributes","removedAttributes","explicitRenames","length","consumedRemoved","map","Boolean","newAttr","find","attr","name","status","isPluginContentTypeUid","uid","startsWith","isContentTypeKind","kind","isPluginContentType","schema","oldSchema","plugin","modelType","ct","String","ACTION_TO_STATUS","create","remove","update","createAttributeWithStatus","attributeData","applyPrivateSearchDefault","determineAttributeStatus","oldAttr","newAttrWithoutStatus","oldAttrWithoutStatus","isEqual","transformStatusFromChatToCTB","action","transformAttributesAndRenamesFromChatToCTB","rawAttributes","schemaRenames","explicitAttributeRenames","attribute","oldAttributesMap","reduce","acc","compatibleRenames","previousAttribute","nextAttribute","isStorageCompatibleRename","compatibleAttributeRenames","includes","explicitOldNames","isExplicitRename","some","reconciled","combinedAttributes","transformChatToCTB","singularName","pluralize","singular","toLowerCase","replace","pluralName","plural","renamePayload","category","modelName","info","displayName","description","collectionName","globalId","previousContentType","undefined","contentTypeBase","charAt","toUpperCase","slice","options","draftAndPublish","pluginOptions","i18n","localized","visible","restrictRelationsTo","prev"],"mappings":"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"}
|
|
@@ -2,7 +2,68 @@ import isEqual from 'lodash/isEqual';
|
|
|
2
2
|
import omit from 'lodash/omit';
|
|
3
3
|
import pluralize from 'pluralize';
|
|
4
4
|
import { applyPrivateSearchDefault } from '../../../../../utils/applyPrivateSearchDefault.mjs';
|
|
5
|
+
import { isStorageCompatibleRename } from '../../../../DataManager/utils/isStorageCompatibleRename.mjs';
|
|
5
6
|
|
|
7
|
+
const RENAME_METADATA_KEYS = [
|
|
8
|
+
'previousName',
|
|
9
|
+
'renamedFrom',
|
|
10
|
+
'action'
|
|
11
|
+
];
|
|
12
|
+
const collectExplicitAttributeRenames = (attributes)=>{
|
|
13
|
+
const renames = [];
|
|
14
|
+
const sanitizedAttributes = {
|
|
15
|
+
...attributes
|
|
16
|
+
};
|
|
17
|
+
Object.entries(attributes).forEach(([newName, rawAttr])=>{
|
|
18
|
+
if (!rawAttr || typeof rawAttr !== 'object') {
|
|
19
|
+
delete sanitizedAttributes[newName];
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const previousName = rawAttr.previousName ?? rawAttr.renamedFrom;
|
|
23
|
+
if (typeof previousName !== 'string' || !previousName || previousName === newName) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
renames.push({
|
|
27
|
+
oldName: previousName,
|
|
28
|
+
newName
|
|
29
|
+
});
|
|
30
|
+
sanitizedAttributes[newName] = omit(rawAttr, RENAME_METADATA_KEYS);
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
renames,
|
|
34
|
+
attributes: sanitizedAttributes
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
const dedupeRenames = (renames)=>{
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
return renames.filter((hop)=>{
|
|
40
|
+
const key = `${hop.oldName}->${hop.newName}`;
|
|
41
|
+
if (seen.has(key)) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
seen.add(key);
|
|
45
|
+
return true;
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
const applyExplicitRenames = (processedAttributes, removedAttributes, explicitRenames)=>{
|
|
49
|
+
if (explicitRenames.length === 0) {
|
|
50
|
+
return {
|
|
51
|
+
processedAttributes,
|
|
52
|
+
removedAttributes
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const consumedRemoved = new Set(explicitRenames.map((hop)=>hop.oldName).filter(Boolean));
|
|
56
|
+
explicitRenames.forEach((hop)=>{
|
|
57
|
+
const newAttr = processedAttributes.find((attr)=>attr.name === hop.newName);
|
|
58
|
+
if (newAttr?.status === 'NEW') {
|
|
59
|
+
newAttr.status = 'CHANGED';
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
processedAttributes,
|
|
64
|
+
removedAttributes: removedAttributes.filter((attr)=>!consumedRemoved.has(attr.name))
|
|
65
|
+
};
|
|
66
|
+
};
|
|
6
67
|
const isPluginContentTypeUid = (uid)=>uid.startsWith('plugin::');
|
|
7
68
|
const isContentTypeKind = (kind)=>{
|
|
8
69
|
return kind === 'collectionType' || kind === 'singleType';
|
|
@@ -70,39 +131,77 @@ const ACTION_TO_STATUS = {
|
|
|
70
131
|
return oldSchema.status;
|
|
71
132
|
};
|
|
72
133
|
/**
|
|
73
|
-
* Transform attributes from Chat format to CTB format
|
|
74
|
-
* Also performs a diff to determine the status of each attribute
|
|
75
|
-
|
|
134
|
+
* Transform attributes from Chat format to CTB format while collecting rename metadata.
|
|
135
|
+
* Also performs a diff to determine the status of each attribute. Renames are only
|
|
136
|
+
* taken from explicit metadata the AI provides (`previousName` / `renamedFrom`, or a
|
|
137
|
+
* top-level `renames` array), never inferred from a remove/add diff, so data is never
|
|
138
|
+
* moved unless a rename was explicitly requested.
|
|
139
|
+
*/ const transformAttributesAndRenamesFromChatToCTB = ({ action, attributes: rawAttributes, renames: schemaRenames = [] }, oldSchema)=>{
|
|
140
|
+
const { attributes, renames: explicitAttributeRenames } = collectExplicitAttributeRenames(rawAttributes);
|
|
76
141
|
// If it's a new schema or no oldAttributes provided, all attributes are NEW
|
|
77
142
|
if (action === 'create' || !oldSchema) {
|
|
78
|
-
return
|
|
143
|
+
return {
|
|
144
|
+
attributes: Object.entries(attributes).map(([name, attribute])=>createAttributeWithStatus(name, attribute, 'NEW')),
|
|
145
|
+
renames: []
|
|
146
|
+
};
|
|
79
147
|
}
|
|
80
148
|
// Convert old attributes array to a lookup map for faster access
|
|
81
149
|
const oldAttributesMap = oldSchema.attributes.reduce((acc, attr)=>({
|
|
82
150
|
...acc,
|
|
83
151
|
[attr.name]: attr
|
|
84
152
|
}), {});
|
|
153
|
+
// Only renames that keep the field's storage can be replayed as a migration;
|
|
154
|
+
// the rest fall back to remove + add. A hop whose old or new side is unknown
|
|
155
|
+
// cannot be checked (nor replayed by the server), so it is dropped too.
|
|
156
|
+
const compatibleRenames = [
|
|
157
|
+
...schemaRenames,
|
|
158
|
+
...explicitAttributeRenames
|
|
159
|
+
].filter((hop)=>{
|
|
160
|
+
const previousAttribute = oldAttributesMap[hop.oldName];
|
|
161
|
+
const nextAttribute = attributes[hop.newName];
|
|
162
|
+
if (!previousAttribute || !nextAttribute) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
return isStorageCompatibleRename(previousAttribute, {
|
|
166
|
+
...nextAttribute,
|
|
167
|
+
name: hop.newName
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
const compatibleAttributeRenames = explicitAttributeRenames.filter((hop)=>compatibleRenames.includes(hop));
|
|
171
|
+
const explicitOldNames = new Set(compatibleAttributeRenames.map((hop)=>hop.oldName));
|
|
85
172
|
// Process current attributes (new and changed)
|
|
86
173
|
const processedAttributes = Object.entries(attributes).map(([name, attr])=>{
|
|
87
174
|
const oldAttr = oldAttributesMap[name];
|
|
88
|
-
const
|
|
175
|
+
const isExplicitRename = compatibleAttributeRenames.some((hop)=>hop.newName === name);
|
|
176
|
+
let status = determineAttributeStatus({
|
|
89
177
|
...attr,
|
|
90
178
|
name
|
|
91
179
|
}, oldAttr, oldSchema);
|
|
180
|
+
if (isExplicitRename) {
|
|
181
|
+
status = oldSchema.status === 'NEW' ? 'NEW' : 'CHANGED';
|
|
182
|
+
}
|
|
92
183
|
return createAttributeWithStatus(name, attr, status);
|
|
93
184
|
});
|
|
94
185
|
// No need to mark removed attributes if the old schema is new, just remove it from the list
|
|
95
186
|
// TODO: Else a validation error occurs on the backend side.
|
|
96
187
|
if (oldSchema?.status === 'NEW') {
|
|
97
|
-
return
|
|
188
|
+
return {
|
|
189
|
+
attributes: processedAttributes,
|
|
190
|
+
renames: []
|
|
191
|
+
};
|
|
98
192
|
}
|
|
99
193
|
// Find removed attributes (exist in old but not in new)
|
|
100
|
-
const removedAttributes = Object.entries(oldAttributesMap).filter(([name])=>!attributes[name]).map(([name, oldAttr])=>createAttributeWithStatus(name, oldAttr, 'REMOVED'));
|
|
194
|
+
const removedAttributes = Object.entries(oldAttributesMap).filter(([name])=>!attributes[name] && !explicitOldNames.has(name)).map(([name, oldAttr])=>createAttributeWithStatus(name, oldAttr, 'REMOVED'));
|
|
195
|
+
const reconciled = applyExplicitRenames(processedAttributes, removedAttributes, compatibleRenames);
|
|
101
196
|
// Combine both sets of attributes
|
|
102
|
-
|
|
103
|
-
...processedAttributes,
|
|
104
|
-
...removedAttributes
|
|
197
|
+
const combinedAttributes = [
|
|
198
|
+
...reconciled.processedAttributes,
|
|
199
|
+
...reconciled.removedAttributes
|
|
105
200
|
];
|
|
201
|
+
return {
|
|
202
|
+
attributes: combinedAttributes,
|
|
203
|
+
renames: dedupeRenames(compatibleRenames)
|
|
204
|
+
};
|
|
106
205
|
};
|
|
107
206
|
/**
|
|
108
207
|
* Transform schema format
|
|
@@ -114,11 +213,16 @@ const ACTION_TO_STATUS = {
|
|
|
114
213
|
*/ const transformChatToCTB = (schema, oldSchema)=>{
|
|
115
214
|
const singularName = pluralize.singular(schema.name).toLowerCase().replace(/ /g, '-');
|
|
116
215
|
const pluralName = pluralize.plural(schema.name).toLowerCase().replace(/ /g, '-');
|
|
216
|
+
const { attributes, renames } = transformAttributesAndRenamesFromChatToCTB(schema, oldSchema);
|
|
217
|
+
const renamePayload = renames.length > 0 ? {
|
|
218
|
+
renames
|
|
219
|
+
} : {};
|
|
117
220
|
if (schema.modelType === 'component') {
|
|
118
221
|
return {
|
|
119
222
|
category: schema.category || 'default',
|
|
120
223
|
modelName: singularName,
|
|
121
|
-
attributes
|
|
224
|
+
attributes,
|
|
225
|
+
...renamePayload,
|
|
122
226
|
info: {
|
|
123
227
|
displayName: schema.name,
|
|
124
228
|
description: schema.description
|
|
@@ -145,7 +249,8 @@ const ACTION_TO_STATUS = {
|
|
|
145
249
|
pluralName: previousContentType?.info.pluralName ?? pluralName
|
|
146
250
|
},
|
|
147
251
|
collectionName: pluralName,
|
|
148
|
-
attributes
|
|
252
|
+
attributes,
|
|
253
|
+
...renamePayload,
|
|
149
254
|
options: {
|
|
150
255
|
draftAndPublish: schema.options?.draftAndPublish ?? true
|
|
151
256
|
},
|
|
@@ -199,5 +304,5 @@ const ACTION_TO_STATUS = {
|
|
|
199
304
|
return contentTypeBase;
|
|
200
305
|
};
|
|
201
306
|
|
|
202
|
-
export {
|
|
307
|
+
export { transformChatToCTB };
|
|
203
308
|
//# sourceMappingURL=toCTB.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toCTB.mjs","sources":["../../../../../../../admin/src/components/AIChat/lib/transforms/schemas/toCTB.ts"],"sourcesContent":["import isEqual from 'lodash/isEqual';\nimport omit from 'lodash/omit';\nimport pluralize from 'pluralize';\n\nimport { applyPrivateSearchDefault } from '../../../../../utils/applyPrivateSearchDefault';\n\nimport type { ContentType, Component, AnyAttribute } from '../../../../../types';\nimport type { Schema, SchemaAttribute } from '../../types/schema';\nimport type { Struct, UID } from '@strapi/types';\n\nconst isPluginContentTypeUid = (uid: string) => uid.startsWith('plugin::');\n\nconst isContentTypeKind = (kind: Schema['kind']): kind is Struct.ContentTypeKind => {\n return kind === 'collectionType' || kind === 'singleType';\n};\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: SchemaAttribute | AnyAttribute,\n status: AnyAttribute['status']\n): AnyAttribute =>\n ({\n ...applyPrivateSearchDefault(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, unknown>,\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 UID.Component,\n collectionName: pluralName,\n status: transformStatusFromChatToCTB(schema, oldSchema),\n globalId: singularName,\n } satisfies Component;\n }\n\n const previousContentType = oldSchema?.modelType === 'contentType' ? oldSchema : undefined;\n const kind = isContentTypeKind(schema.kind) ? schema.kind : 'collectionType';\n\n const contentTypeBase = {\n uid: schema.uid as UID.ContentType,\n modelType: 'contentType',\n modelName: singularName,\n kind,\n info: {\n displayName: schema.name.charAt(0).toUpperCase() + schema.name.slice(1),\n // Always keep the old by default\n singularName: previousContentType?.info.singularName ?? singularName,\n // Always keep the old by default\n pluralName: previousContentType?.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","isContentTypeKind","kind","isPluginContentType","schema","oldSchema","plugin","modelType","ct","Boolean","String","ACTION_TO_STATUS","create","remove","update","createAttributeWithStatus","name","attributeData","status","applyPrivateSearchDefault","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","previousContentType","undefined","contentTypeBase","charAt","toUpperCase","slice","options","draftAndPublish","pluginOptions","i18n","localized","visible","restrictRelationsTo","prev"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toCTB.mjs","sources":["../../../../../../../admin/src/components/AIChat/lib/transforms/schemas/toCTB.ts"],"sourcesContent":["import isEqual from 'lodash/isEqual';\nimport omit from 'lodash/omit';\nimport pluralize from 'pluralize';\n\nimport { applyPrivateSearchDefault } from '../../../../../utils/applyPrivateSearchDefault';\nimport { isStorageCompatibleRename } from '../../../../DataManager/utils/isStorageCompatibleRename';\n\nimport type { ContentType, Component, AnyAttribute, RenameHop } from '../../../../../types';\nimport type { Schema, SchemaAttribute } from '../../types/schema';\nimport type { Struct, UID } from '@strapi/types';\n\nconst RENAME_METADATA_KEYS = ['previousName', 'renamedFrom', 'action'] as const;\n\nconst collectExplicitAttributeRenames = (\n attributes: Schema['attributes']\n): { renames: RenameHop[]; attributes: Schema['attributes'] } => {\n const renames: RenameHop[] = [];\n const sanitizedAttributes = { ...attributes };\n\n Object.entries(attributes).forEach(([newName, rawAttr]) => {\n if (!rawAttr || typeof rawAttr !== 'object') {\n delete sanitizedAttributes[newName];\n return;\n }\n\n const previousName = rawAttr.previousName ?? rawAttr.renamedFrom;\n if (typeof previousName !== 'string' || !previousName || previousName === newName) {\n return;\n }\n\n renames.push({ oldName: previousName, newName });\n sanitizedAttributes[newName] = omit(rawAttr, RENAME_METADATA_KEYS) as SchemaAttribute;\n });\n\n return { renames, attributes: sanitizedAttributes };\n};\n\nconst dedupeRenames = (renames: RenameHop[]): RenameHop[] => {\n const seen = new Set<string>();\n\n return renames.filter((hop) => {\n const key = `${hop.oldName}->${hop.newName}`;\n if (seen.has(key)) {\n return false;\n }\n\n seen.add(key);\n return true;\n });\n};\n\nconst applyExplicitRenames = (\n processedAttributes: AnyAttribute[],\n removedAttributes: AnyAttribute[],\n explicitRenames: RenameHop[]\n): { processedAttributes: AnyAttribute[]; removedAttributes: AnyAttribute[] } => {\n if (explicitRenames.length === 0) {\n return { processedAttributes, removedAttributes };\n }\n\n const consumedRemoved = new Set(explicitRenames.map((hop) => hop.oldName).filter(Boolean));\n\n explicitRenames.forEach((hop) => {\n const newAttr = processedAttributes.find((attr) => attr.name === hop.newName);\n if (newAttr?.status === 'NEW') {\n newAttr.status = 'CHANGED';\n }\n });\n\n return {\n processedAttributes,\n removedAttributes: removedAttributes.filter((attr) => !consumedRemoved.has(attr.name)),\n };\n};\n\nconst isPluginContentTypeUid = (uid: string) => uid.startsWith('plugin::');\n\nconst isContentTypeKind = (kind: Schema['kind']): kind is Struct.ContentTypeKind => {\n return kind === 'collectionType' || kind === 'singleType';\n};\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: SchemaAttribute | AnyAttribute,\n status: AnyAttribute['status']\n): AnyAttribute =>\n ({\n ...applyPrivateSearchDefault(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, unknown>,\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\ntype TransformAttributesResult = {\n attributes: AnyAttribute[];\n renames: RenameHop[];\n};\n\n/**\n * Transform attributes from Chat format to CTB format while collecting rename metadata.\n * Also performs a diff to determine the status of each attribute. Renames are only\n * taken from explicit metadata the AI provides (`previousName` / `renamedFrom`, or a\n * top-level `renames` array), never inferred from a remove/add diff, so data is never\n * moved unless a rename was explicitly requested.\n */\nconst transformAttributesAndRenamesFromChatToCTB = (\n { action, attributes: rawAttributes, renames: schemaRenames = [] }: Schema,\n oldSchema?: ContentType | Component\n): TransformAttributesResult => {\n const { attributes, renames: explicitAttributeRenames } =\n collectExplicitAttributeRenames(rawAttributes);\n\n // If it's a new schema or no oldAttributes provided, all attributes are NEW\n if (action === 'create' || !oldSchema) {\n return {\n attributes: Object.entries(attributes).map(([name, attribute]) =>\n createAttributeWithStatus(name, attribute, 'NEW')\n ),\n renames: [],\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 // Only renames that keep the field's storage can be replayed as a migration;\n // the rest fall back to remove + add. A hop whose old or new side is unknown\n // cannot be checked (nor replayed by the server), so it is dropped too.\n const compatibleRenames = [...schemaRenames, ...explicitAttributeRenames].filter((hop) => {\n const previousAttribute = oldAttributesMap[hop.oldName];\n const nextAttribute = attributes[hop.newName];\n\n if (!previousAttribute || !nextAttribute) {\n return false;\n }\n\n return isStorageCompatibleRename(previousAttribute, {\n ...nextAttribute,\n name: hop.newName,\n } as AnyAttribute);\n });\n const compatibleAttributeRenames = explicitAttributeRenames.filter((hop) =>\n compatibleRenames.includes(hop)\n );\n\n const explicitOldNames = new Set(compatibleAttributeRenames.map((hop) => hop.oldName));\n\n // Process current attributes (new and changed)\n const processedAttributes = Object.entries(attributes).map(([name, attr]) => {\n const oldAttr = oldAttributesMap[name];\n const isExplicitRename = compatibleAttributeRenames.some((hop) => hop.newName === name);\n let status = determineAttributeStatus({ ...attr, name }, oldAttr, oldSchema);\n if (isExplicitRename) {\n status = oldSchema.status === 'NEW' ? 'NEW' : 'CHANGED';\n }\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 { attributes: processedAttributes, renames: [] };\n }\n\n // Find removed attributes (exist in old but not in new)\n const removedAttributes = Object.entries(oldAttributesMap)\n .filter(([name]) => !attributes[name] && !explicitOldNames.has(name))\n .map(([name, oldAttr]) => createAttributeWithStatus(name, oldAttr, 'REMOVED'));\n\n const reconciled = applyExplicitRenames(\n processedAttributes,\n removedAttributes,\n compatibleRenames\n );\n\n // Combine both sets of attributes\n const combinedAttributes = [...reconciled.processedAttributes, ...reconciled.removedAttributes];\n\n return {\n attributes: combinedAttributes,\n renames: dedupeRenames(compatibleRenames),\n };\n};\n\n/**\n * Transform attributes from Chat format to CTB format.\n *\n * Keep the existing array return type for callers that only need attributes.\n */\nexport const transformAttributesFromChatToCTB = (\n schema: Schema,\n oldSchema?: ContentType | Component\n): AnyAttribute[] => transformAttributesAndRenamesFromChatToCTB(schema, oldSchema).attributes;\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 const { attributes, renames } = transformAttributesAndRenamesFromChatToCTB(schema, oldSchema);\n const renamePayload = renames.length > 0 ? { renames } : {};\n\n if (schema.modelType === 'component') {\n return {\n category: schema.category || 'default',\n modelName: singularName,\n attributes,\n ...renamePayload,\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 UID.Component,\n collectionName: pluralName,\n status: transformStatusFromChatToCTB(schema, oldSchema),\n globalId: singularName,\n } satisfies Component;\n }\n\n const previousContentType = oldSchema?.modelType === 'contentType' ? oldSchema : undefined;\n const kind = isContentTypeKind(schema.kind) ? schema.kind : 'collectionType';\n\n const contentTypeBase = {\n uid: schema.uid as UID.ContentType,\n modelType: 'contentType',\n modelName: singularName,\n kind,\n info: {\n displayName: schema.name.charAt(0).toUpperCase() + schema.name.slice(1),\n // Always keep the old by default\n singularName: previousContentType?.info.singularName ?? singularName,\n // Always keep the old by default\n pluralName: previousContentType?.info.pluralName ?? pluralName,\n },\n collectionName: pluralName,\n attributes,\n ...renamePayload,\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":["RENAME_METADATA_KEYS","collectExplicitAttributeRenames","attributes","renames","sanitizedAttributes","Object","entries","forEach","newName","rawAttr","previousName","renamedFrom","push","oldName","omit","dedupeRenames","seen","Set","filter","hop","key","has","add","applyExplicitRenames","processedAttributes","removedAttributes","explicitRenames","length","consumedRemoved","map","Boolean","newAttr","find","attr","name","status","isPluginContentTypeUid","uid","startsWith","isContentTypeKind","kind","isPluginContentType","schema","oldSchema","plugin","modelType","ct","String","ACTION_TO_STATUS","create","remove","update","createAttributeWithStatus","attributeData","applyPrivateSearchDefault","determineAttributeStatus","oldAttr","newAttrWithoutStatus","oldAttrWithoutStatus","isEqual","transformStatusFromChatToCTB","action","transformAttributesAndRenamesFromChatToCTB","rawAttributes","schemaRenames","explicitAttributeRenames","attribute","oldAttributesMap","reduce","acc","compatibleRenames","previousAttribute","nextAttribute","isStorageCompatibleRename","compatibleAttributeRenames","includes","explicitOldNames","isExplicitRename","some","reconciled","combinedAttributes","transformChatToCTB","singularName","pluralize","singular","toLowerCase","replace","pluralName","plural","renamePayload","category","modelName","info","displayName","description","collectionName","globalId","previousContentType","undefined","contentTypeBase","charAt","toUpperCase","slice","options","draftAndPublish","pluginOptions","i18n","localized","visible","restrictRelationsTo","prev"],"mappings":"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"}
|