@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.
Files changed (146) hide show
  1. package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.js +117 -13
  2. package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.js.map +1 -1
  3. package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.mjs +118 -13
  4. package/dist/admin/components/AIChat/lib/transforms/schemas/toCTB.mjs.map +1 -1
  5. package/dist/admin/components/AIChat/providers/SchemaProvider.js +31 -19
  6. package/dist/admin/components/AIChat/providers/SchemaProvider.js.map +1 -1
  7. package/dist/admin/components/AIChat/providers/SchemaProvider.mjs +31 -19
  8. package/dist/admin/components/AIChat/providers/SchemaProvider.mjs.map +1 -1
  9. package/dist/admin/components/DataManager/DataManagerContext.js.map +1 -1
  10. package/dist/admin/components/DataManager/DataManagerContext.mjs.map +1 -1
  11. package/dist/admin/components/DataManager/DataManagerProvider.js +166 -6
  12. package/dist/admin/components/DataManager/DataManagerProvider.js.map +1 -1
  13. package/dist/admin/components/DataManager/DataManagerProvider.mjs +165 -7
  14. package/dist/admin/components/DataManager/DataManagerProvider.mjs.map +1 -1
  15. package/dist/admin/components/DataManager/RenameMigrationModal.js +285 -0
  16. package/dist/admin/components/DataManager/RenameMigrationModal.js.map +1 -0
  17. package/dist/admin/components/DataManager/RenameMigrationModal.mjs +257 -0
  18. package/dist/admin/components/DataManager/RenameMigrationModal.mjs.map +1 -0
  19. package/dist/admin/components/DataManager/reducer.js +107 -2
  20. package/dist/admin/components/DataManager/reducer.js.map +1 -1
  21. package/dist/admin/components/DataManager/reducer.mjs +106 -2
  22. package/dist/admin/components/DataManager/reducer.mjs.map +1 -1
  23. package/dist/admin/components/DataManager/utils/cleanData.js +8 -1
  24. package/dist/admin/components/DataManager/utils/cleanData.js.map +1 -1
  25. package/dist/admin/components/DataManager/utils/cleanData.mjs +8 -1
  26. package/dist/admin/components/DataManager/utils/cleanData.mjs.map +1 -1
  27. package/dist/admin/components/DataManager/utils/groupRenameChains.js +86 -0
  28. package/dist/admin/components/DataManager/utils/groupRenameChains.js.map +1 -0
  29. package/dist/admin/components/DataManager/utils/groupRenameChains.mjs +84 -0
  30. package/dist/admin/components/DataManager/utils/groupRenameChains.mjs.map +1 -0
  31. package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.js +29 -0
  32. package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.js.map +1 -0
  33. package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.mjs +27 -0
  34. package/dist/admin/components/DataManager/utils/isStorageCompatibleRename.mjs.map +1 -0
  35. package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.js +35 -0
  36. package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.js.map +1 -0
  37. package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.mjs +33 -0
  38. package/dist/admin/components/DataManager/utils/resolveAfterEditRenameConsent.mjs.map +1 -0
  39. package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.js +48 -0
  40. package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.js.map +1 -0
  41. package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.mjs +45 -0
  42. package/dist/admin/components/DataManager/utils/splitChainsByInheritedConsent.mjs.map +1 -0
  43. package/dist/admin/components/FormModal/FormModal.js +142 -8
  44. package/dist/admin/components/FormModal/FormModal.js.map +1 -1
  45. package/dist/admin/components/FormModal/FormModal.mjs +143 -9
  46. package/dist/admin/components/FormModal/FormModal.mjs.map +1 -1
  47. package/dist/admin/components/FormModal/attributes/validation/common.js +6 -5
  48. package/dist/admin/components/FormModal/attributes/validation/common.js.map +1 -1
  49. package/dist/admin/components/FormModal/attributes/validation/common.mjs +1 -1
  50. package/dist/admin/components/FormModal/attributes/validation/common.mjs.map +1 -1
  51. package/dist/admin/components/FormModal/component/createComponentSchema.js +10 -7
  52. package/dist/admin/components/FormModal/component/createComponentSchema.js.map +1 -1
  53. package/dist/admin/components/FormModal/component/createComponentSchema.mjs +1 -1
  54. package/dist/admin/components/FormModal/component/createComponentSchema.mjs.map +1 -1
  55. package/dist/admin/components/FormModal/contentType/createContentTypeSchema.js +24 -21
  56. package/dist/admin/components/FormModal/contentType/createContentTypeSchema.js.map +1 -1
  57. package/dist/admin/components/FormModal/contentType/createContentTypeSchema.mjs +1 -1
  58. package/dist/admin/components/FormModal/contentType/createContentTypeSchema.mjs.map +1 -1
  59. package/dist/admin/components/FormModal/forms/utils/createCollectionName.js +3 -2
  60. package/dist/admin/components/FormModal/forms/utils/createCollectionName.js.map +1 -1
  61. package/dist/admin/components/FormModal/forms/utils/createCollectionName.mjs +1 -1
  62. package/dist/admin/components/FormModal/forms/utils/createCollectionName.mjs.map +1 -1
  63. package/dist/admin/components/FormModal/utils/getRenameStorageChange.js +73 -0
  64. package/dist/admin/components/FormModal/utils/getRenameStorageChange.js.map +1 -0
  65. package/dist/admin/components/FormModal/utils/getRenameStorageChange.mjs +70 -0
  66. package/dist/admin/components/FormModal/utils/getRenameStorageChange.mjs.map +1 -0
  67. package/dist/admin/src/components/AIChat/lib/transforms/schemas/toCTB.d.ts +4 -3
  68. package/dist/admin/src/components/AIChat/lib/types/schema.d.ts +6 -1
  69. package/dist/admin/src/components/DataManager/DataManagerContext.d.ts +28 -2
  70. package/dist/admin/src/components/DataManager/RenameMigrationModal.d.ts +73 -0
  71. package/dist/admin/src/components/DataManager/reducer.d.ts +17 -2
  72. package/dist/admin/src/components/DataManager/utils/cleanData.d.ts +16 -0
  73. package/dist/admin/src/components/DataManager/utils/groupRenameChains.d.ts +31 -0
  74. package/dist/admin/src/components/DataManager/utils/isStorageCompatibleRename.d.ts +10 -0
  75. package/dist/admin/src/components/DataManager/utils/resolveAfterEditRenameConsent.d.ts +24 -0
  76. package/dist/admin/src/components/DataManager/utils/splitChainsByInheritedConsent.d.ts +26 -0
  77. package/dist/admin/src/components/FormModal/utils/getRenameStorageChange.d.ts +40 -0
  78. package/dist/admin/src/types.d.ts +23 -0
  79. package/dist/admin/translations/en.json.js +12 -0
  80. package/dist/admin/translations/en.json.js.map +1 -1
  81. package/dist/admin/translations/en.json.mjs +12 -0
  82. package/dist/admin/translations/en.json.mjs.map +1 -1
  83. package/dist/server/config.js +24 -3
  84. package/dist/server/config.js.map +1 -1
  85. package/dist/server/config.mjs +21 -3
  86. package/dist/server/config.mjs.map +1 -1
  87. package/dist/server/controllers/schema.js +2 -2
  88. package/dist/server/controllers/schema.js.map +1 -1
  89. package/dist/server/controllers/schema.mjs +1 -1
  90. package/dist/server/controllers/schema.mjs.map +1 -1
  91. package/dist/server/controllers/validation/content-type.js +9 -11
  92. package/dist/server/controllers/validation/content-type.js.map +1 -1
  93. package/dist/server/controllers/validation/content-type.mjs +7 -9
  94. package/dist/server/controllers/validation/content-type.mjs.map +1 -1
  95. package/dist/server/controllers/validation/model-schema.js +2 -3
  96. package/dist/server/controllers/validation/model-schema.js.map +1 -1
  97. package/dist/server/controllers/validation/model-schema.mjs +1 -2
  98. package/dist/server/controllers/validation/model-schema.mjs.map +1 -1
  99. package/dist/server/controllers/validation/relations.js +1 -2
  100. package/dist/server/controllers/validation/relations.js.map +1 -1
  101. package/dist/server/controllers/validation/relations.mjs +1 -2
  102. package/dist/server/controllers/validation/relations.mjs.map +1 -1
  103. package/dist/server/controllers/validation/schema.js +42 -23
  104. package/dist/server/controllers/validation/schema.js.map +1 -1
  105. package/dist/server/controllers/validation/schema.mjs +43 -24
  106. package/dist/server/controllers/validation/schema.mjs.map +1 -1
  107. package/dist/server/index.js +1 -1
  108. package/dist/server/index.js.map +1 -1
  109. package/dist/server/services/content-types.js +1 -2
  110. package/dist/server/services/content-types.js.map +1 -1
  111. package/dist/server/services/content-types.mjs +2 -3
  112. package/dist/server/services/content-types.mjs.map +1 -1
  113. package/dist/server/services/migration-builder/index.js +580 -0
  114. package/dist/server/services/migration-builder/index.js.map +1 -0
  115. package/dist/server/services/migration-builder/index.mjs +573 -0
  116. package/dist/server/services/migration-builder/index.mjs.map +1 -0
  117. package/dist/server/services/schema-builder/content-type-builder.js +31 -1
  118. package/dist/server/services/schema-builder/content-type-builder.js.map +1 -1
  119. package/dist/server/services/schema-builder/content-type-builder.mjs +31 -1
  120. package/dist/server/services/schema-builder/content-type-builder.mjs.map +1 -1
  121. package/dist/server/services/schema-mutation.js +30 -2
  122. package/dist/server/services/schema-mutation.js.map +1 -1
  123. package/dist/server/services/schema-mutation.mjs +10 -2
  124. package/dist/server/services/schema-mutation.mjs.map +1 -1
  125. package/dist/server/services/schema.js +259 -15
  126. package/dist/server/services/schema.js.map +1 -1
  127. package/dist/server/services/schema.mjs +252 -9
  128. package/dist/server/services/schema.mjs.map +1 -1
  129. package/dist/server/src/config.d.ts +23 -2
  130. package/dist/server/src/config.d.ts.map +1 -1
  131. package/dist/server/src/controllers/validation/content-type.d.ts +0 -1
  132. package/dist/server/src/controllers/validation/content-type.d.ts.map +1 -1
  133. package/dist/server/src/controllers/validation/relations.d.ts.map +1 -1
  134. package/dist/server/src/controllers/validation/schema.d.ts +28 -0
  135. package/dist/server/src/controllers/validation/schema.d.ts.map +1 -1
  136. package/dist/server/src/index.d.ts +10 -2
  137. package/dist/server/src/index.d.ts.map +1 -1
  138. package/dist/server/src/services/content-types.d.ts.map +1 -1
  139. package/dist/server/src/services/migration-builder/index.d.ts +83 -0
  140. package/dist/server/src/services/migration-builder/index.d.ts.map +1 -0
  141. package/dist/server/src/services/schema-builder/content-type-builder.d.ts.map +1 -1
  142. package/dist/server/src/services/schema-mutation.d.ts +4 -2
  143. package/dist/server/src/services/schema-mutation.d.ts.map +1 -1
  144. package/dist/server/src/services/schema.d.ts +19 -0
  145. package/dist/server/src/services/schema.d.ts.map +1 -1
  146. 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
- */ const transformAttributesFromChatToCTB = ({ action, attributes }, oldSchema)=>{
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 Object.entries(attributes).map(([name, attribute])=>createAttributeWithStatus(name, attribute, 'NEW'));
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 status = determineAttributeStatus({
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 processedAttributes;
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
- return [
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: transformAttributesFromChatToCTB(schema, oldSchema),
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: transformAttributesFromChatToCTB(schema, oldSchema),
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
- */ const transformAttributesFromChatToCTB = ({ action, attributes }, oldSchema)=>{
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 Object.entries(attributes).map(([name, attribute])=>createAttributeWithStatus(name, attribute, 'NEW'));
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 status = determineAttributeStatus({
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 processedAttributes;
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
- return [
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: transformAttributesFromChatToCTB(schema, oldSchema),
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: transformAttributesFromChatToCTB(schema, oldSchema),
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 { transformAttributesFromChatToCTB, transformChatToCTB };
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":";;;;;;AAWA,MAAMA,oBAAAA,GAAuB;AAAC,IAAA,cAAA;AAAgB,IAAA,aAAA;AAAe,IAAA;AAAS,CAAA;AAEtE,MAAMC,kCAAkC,CACtCC,UAAAA,GAAAA;AAEA,IAAA,MAAMC,UAAuB,EAAE;AAC/B,IAAA,MAAMC,mBAAAA,GAAsB;AAAE,QAAA,GAAGF;AAAW,KAAA;IAE5CG,MAAAA,CAAOC,OAAO,CAACJ,UAAAA,CAAAA,CAAYK,OAAO,CAAC,CAAC,CAACC,SAASC,OAAAA,CAAQ,GAAA;AACpD,QAAA,IAAI,CAACA,OAAAA,IAAW,OAAOA,OAAAA,KAAY,QAAA,EAAU;YAC3C,OAAOL,mBAAmB,CAACI,OAAAA,CAAQ;AACnC,YAAA;AACF,QAAA;AAEA,QAAA,MAAME,YAAAA,GAAeD,OAAAA,CAAQC,YAAY,IAAID,QAAQE,WAAW;AAChE,QAAA,IAAI,OAAOD,YAAAA,KAAiB,QAAA,IAAY,CAACA,YAAAA,IAAgBA,iBAAiBF,OAAAA,EAAS;AACjF,YAAA;AACF,QAAA;AAEAL,QAAAA,OAAAA,CAAQS,IAAI,CAAC;YAAEC,OAAAA,EAASH,YAAAA;AAAcF,YAAAA;AAAQ,SAAA,CAAA;AAC9CJ,QAAAA,mBAAmB,CAACI,OAAAA,CAAQ,GAAGM,IAAAA,CAAKL,OAAAA,EAAST,oBAAAA,CAAAA;AAC/C,IAAA,CAAA,CAAA;IAEA,OAAO;AAAEG,QAAAA,OAAAA;QAASD,UAAAA,EAAYE;AAAoB,KAAA;AACpD,CAAA;AAEA,MAAMW,gBAAgB,CAACZ,OAAAA,GAAAA;AACrB,IAAA,MAAMa,OAAO,IAAIC,GAAAA,EAAAA;IAEjB,OAAOd,OAAAA,CAAQe,MAAM,CAAC,CAACC,GAAAA,GAAAA;QACrB,MAAMC,GAAAA,GAAM,GAAGD,GAAAA,CAAIN,OAAO,CAAC,EAAE,EAAEM,GAAAA,CAAIX,OAAO,CAAA,CAAE;QAC5C,IAAIQ,IAAAA,CAAKK,GAAG,CAACD,GAAAA,CAAAA,EAAM;YACjB,OAAO,KAAA;AACT,QAAA;AAEAJ,QAAAA,IAAAA,CAAKM,GAAG,CAACF,GAAAA,CAAAA;QACT,OAAO,IAAA;AACT,IAAA,CAAA,CAAA;AACF,CAAA;AAEA,MAAMG,oBAAAA,GAAuB,CAC3BC,mBAAAA,EACAC,iBAAAA,EACAC,eAAAA,GAAAA;IAEA,IAAIA,eAAAA,CAAgBC,MAAM,KAAK,CAAA,EAAG;QAChC,OAAO;AAAEH,YAAAA,mBAAAA;AAAqBC,YAAAA;AAAkB,SAAA;AAClD,IAAA;AAEA,IAAA,MAAMG,eAAAA,GAAkB,IAAIX,GAAAA,CAAIS,eAAAA,CAAgBG,GAAG,CAAC,CAACV,GAAAA,GAAQA,GAAAA,CAAIN,OAAO,CAAA,CAAEK,MAAM,CAACY,OAAAA,CAAAA,CAAAA;IAEjFJ,eAAAA,CAAgBnB,OAAO,CAAC,CAACY,GAAAA,GAAAA;QACvB,MAAMY,OAAAA,GAAUP,mBAAAA,CAAoBQ,IAAI,CAAC,CAACC,OAASA,IAAAA,CAAKC,IAAI,KAAKf,GAAAA,CAAIX,OAAO,CAAA;QAC5E,IAAIuB,OAAAA,EAASI,WAAW,KAAA,EAAO;AAC7BJ,YAAAA,OAAAA,CAAQI,MAAM,GAAG,SAAA;AACnB,QAAA;AACF,IAAA,CAAA,CAAA;IAEA,OAAO;AACLX,QAAAA,mBAAAA;QACAC,iBAAAA,EAAmBA,iBAAAA,CAAkBP,MAAM,CAAC,CAACe,IAAAA,GAAS,CAACL,eAAAA,CAAgBP,GAAG,CAACY,IAAAA,CAAKC,IAAI,CAAA;AACtF,KAAA;AACF,CAAA;AAEA,MAAME,sBAAAA,GAAyB,CAACC,GAAAA,GAAgBA,GAAAA,CAAIC,UAAU,CAAC,UAAA,CAAA;AAE/D,MAAMC,oBAAoB,CAACC,IAAAA,GAAAA;IACzB,OAAOA,IAAAA,KAAS,oBAAoBA,IAAAA,KAAS,YAAA;AAC/C,CAAA;AAEA;;;IAIA,MAAMC,mBAAAA,GAAsB,CAACC,MAAAA,EAAgBC,SAAAA,GAAAA;AAC3C,IAAA,IAAID,OAAOE,MAAM,IAAIR,sBAAAA,CAAuBM,MAAAA,CAAOL,GAAG,CAAA,EAAG;QACvD,OAAO,IAAA;AACT,IAAA;AACA,IAAA,IAAIM,aAAa,WAAA,IAAeA,SAAAA,IAAaA,SAAAA,CAAUE,SAAS,KAAK,aAAA,EAAe;AAClF,QAAA,MAAMC,EAAAA,GAAKH,SAAAA;AACX,QAAA,OAAOb,QAAQgB,EAAAA,CAAGF,MAAM,KAAKR,sBAAAA,CAAuBW,MAAAA,CAAOD,GAAGT,GAAG,CAAA,CAAA;AACnE,IAAA;IACA,OAAO,KAAA;AACT,CAAA;AAEA,MAAMW,gBAAAA,GAAoE;IACxEC,MAAAA,EAAQ,KAAA;IACRC,MAAAA,EAAQ,SAAA;IACRC,MAAAA,EAAQ;AACV,CAAA;AAEA;;AAEC,IACD,MAAMC,yBAAAA,GAA4B,CAChClB,IAAAA,EACAmB,aAAAA,EACAlB,UAEC;AACC,QAAA,GAAGmB,0BAA0BD,aAAAA,CAAc;AAC3CnB,QAAAA,IAAAA;AACAC,QAAAA;KACF,CAAA;AAEF;;AAEC,IACD,MAAMoB,wBAAAA,GAA2B,CAC/BxB,OAAAA,EACAyB,OAAAA,EACAb,SAAAA,GAAAA;AAEA,IAAA,IAAI,CAACa,OAAAA,EAAS;QACZ,OAAO,KAAA;AACT,IAAA;;IAGA,IAAIb,SAAAA,EAAWR,WAAW,KAAA,EAAO;QAC/B,OAAO,KAAA;AACT,IAAA;;IAGA,MAAMsB,oBAAAA,GAAuB3C,KAAKiB,OAAAA,EAAS;AAAC,QAAA;AAAS,KAAA,CAAA;IACrD,MAAM2B,oBAAAA,GAAuB5C,KAAK0C,OAAAA,EAAS;AAAC,QAAA;AAAS,KAAA,CAAA;IAErD,IAAI,CAACG,OAAAA,CAAQF,oBAAAA,EAAsBC,oBAAAA,CAAAA,EAAuB;QACxD,OAAO,SAAA;AACT,IAAA;;AAGA,IAAA,OAAOF,QAAQrB,MAAM;AACvB,CAAA;AAEA;;IAGA,MAAMyB,4BAAAA,GAA+B,CACnClB,MAAAA,EACAC,SAAAA,GAAAA;;IAGA,IAAID,MAAAA,CAAOmB,MAAM,EAAE;AACjB,QAAA,OAAOb,gBAAgB,CAACN,MAAAA,CAAOmB,MAAM,CAAC;AACxC,IAAA;;AAGA,IAAA,IAAI,CAAClB,SAAAA,EAAW;QACd,OAAO,KAAA;AACT,IAAA;;AAGA,IAAA,OAAOA,UAAUR,MAAM;AACzB,CAAA;AAOA;;;;;;AAMC,IACD,MAAM2B,0CAAAA,GAA6C,CACjD,EAAED,MAAM,EAAE3D,UAAAA,EAAY6D,aAAa,EAAE5D,OAAAA,EAAS6D,aAAAA,GAAgB,EAAE,EAAU,EAC1ErB,SAAAA,GAAAA;AAEA,IAAA,MAAM,EAAEzC,UAAU,EAAEC,SAAS8D,wBAAwB,EAAE,GACrDhE,+BAAAA,CAAgC8D,aAAAA,CAAAA;;IAGlC,IAAIF,MAAAA,KAAW,QAAA,IAAY,CAAClB,SAAAA,EAAW;QACrC,OAAO;AACLzC,YAAAA,UAAAA,EAAYG,MAAAA,CAAOC,OAAO,CAACJ,UAAAA,CAAAA,CAAY2B,GAAG,CAAC,CAAC,CAACK,IAAAA,EAAMgC,SAAAA,CAAU,GAC3Dd,yBAAAA,CAA0BlB,MAAMgC,SAAAA,EAAW,KAAA,CAAA,CAAA;AAE7C/D,YAAAA,OAAAA,EAAS;AACX,SAAA;AACF,IAAA;;IAGA,MAAMgE,gBAAAA,GAAmBxB,UAAUzC,UAAU,CAACkE,MAAM,CAClD,CAACC,GAAAA,EAAKpC,IAAAA,IAAU;AAAE,YAAA,GAAGoC,GAAG;YAAE,CAACpC,IAAAA,CAAKC,IAAI,GAAGD;AAAK,SAAA,GAC5C,EAAC,CAAA;;;;AAMH,IAAA,MAAMqC,iBAAAA,GAAoB;AAAIN,QAAAA,GAAAA,aAAAA;AAAkBC,QAAAA,GAAAA;KAAyB,CAAC/C,MAAM,CAAC,CAACC,GAAAA,GAAAA;AAChF,QAAA,MAAMoD,iBAAAA,GAAoBJ,gBAAgB,CAAChD,GAAAA,CAAIN,OAAO,CAAC;AACvD,QAAA,MAAM2D,aAAAA,GAAgBtE,UAAU,CAACiB,GAAAA,CAAIX,OAAO,CAAC;QAE7C,IAAI,CAAC+D,iBAAAA,IAAqB,CAACC,aAAAA,EAAe;YACxC,OAAO,KAAA;AACT,QAAA;AAEA,QAAA,OAAOC,0BAA0BF,iBAAAA,EAAmB;AAClD,YAAA,GAAGC,aAAa;AAChBtC,YAAAA,IAAAA,EAAMf,IAAIX;AACZ,SAAA,CAAA;AACF,IAAA,CAAA,CAAA;IACA,MAAMkE,0BAAAA,GAA6BT,yBAAyB/C,MAAM,CAAC,CAACC,GAAAA,GAClEmD,iBAAAA,CAAkBK,QAAQ,CAACxD,GAAAA,CAAAA,CAAAA;IAG7B,MAAMyD,gBAAAA,GAAmB,IAAI3D,GAAAA,CAAIyD,0BAAAA,CAA2B7C,GAAG,CAAC,CAACV,GAAAA,GAAQA,GAAAA,CAAIN,OAAO,CAAA,CAAA;;IAGpF,MAAMW,mBAAAA,GAAsBnB,MAAAA,CAAOC,OAAO,CAACJ,UAAAA,CAAAA,CAAY2B,GAAG,CAAC,CAAC,CAACK,IAAAA,EAAMD,IAAAA,CAAK,GAAA;QACtE,MAAMuB,OAAAA,GAAUW,gBAAgB,CAACjC,IAAAA,CAAK;QACtC,MAAM2C,gBAAAA,GAAmBH,2BAA2BI,IAAI,CAAC,CAAC3D,GAAAA,GAAQA,GAAAA,CAAIX,OAAO,KAAK0B,IAAAA,CAAAA;AAClF,QAAA,IAAIC,SAASoB,wBAAAA,CAAyB;AAAE,YAAA,GAAGtB,IAAI;AAAEC,YAAAA;AAAK,SAAA,EAAGsB,OAAAA,EAASb,SAAAA,CAAAA;AAClE,QAAA,IAAIkC,gBAAAA,EAAkB;AACpB1C,YAAAA,MAAAA,GAASQ,SAAAA,CAAUR,MAAM,KAAK,KAAA,GAAQ,KAAA,GAAQ,SAAA;AAChD,QAAA;QAEA,OAAOiB,yBAAAA,CAA0BlB,MAAMD,IAAAA,EAAME,MAAAA,CAAAA;AAC/C,IAAA,CAAA,CAAA;;;IAIA,IAAIQ,SAAAA,EAAWR,WAAW,KAAA,EAAO;QAC/B,OAAO;YAAEjC,UAAAA,EAAYsB,mBAAAA;AAAqBrB,YAAAA,OAAAA,EAAS;AAAG,SAAA;AACxD,IAAA;;AAGA,IAAA,MAAMsB,iBAAAA,GAAoBpB,MAAAA,CAAOC,OAAO,CAAC6D,gBAAAA,CAAAA,CACtCjD,MAAM,CAAC,CAAC,CAACgB,IAAAA,CAAK,GAAK,CAAChC,UAAU,CAACgC,IAAAA,CAAK,IAAI,CAAC0C,gBAAAA,CAAiBvD,GAAG,CAACa,IAAAA,CAAAA,CAAAA,CAC9DL,GAAG,CAAC,CAAC,CAACK,IAAAA,EAAMsB,OAAAA,CAAQ,GAAKJ,yBAAAA,CAA0BlB,MAAMsB,OAAAA,EAAS,SAAA,CAAA,CAAA;IAErE,MAAMuB,UAAAA,GAAaxD,oBAAAA,CACjBC,mBAAAA,EACAC,iBAAAA,EACA6C,iBAAAA,CAAAA;;AAIF,IAAA,MAAMU,kBAAAA,GAAqB;AAAID,QAAAA,GAAAA,UAAAA,CAAWvD,mBAAmB;AAAKuD,QAAAA,GAAAA,UAAAA,CAAWtD;AAAkB,KAAA;IAE/F,OAAO;QACLvB,UAAAA,EAAY8E,kBAAAA;AACZ7E,QAAAA,OAAAA,EAASY,aAAAA,CAAcuD,iBAAAA;AACzB,KAAA;AACF,CAAA;AAYA;;;;;;;AAOC,IACM,MAAMW,kBAAAA,GAAqB,CAChCvC,MAAAA,EACAC,SAAAA,GAAAA;IAEA,MAAMuC,YAAAA,GAAeC,SAAAA,CAAUC,QAAQ,CAAC1C,MAAAA,CAAOR,IAAI,CAAA,CAAEmD,WAAW,EAAA,CAAGC,OAAO,CAAC,IAAA,EAAM,GAAA,CAAA;IACjF,MAAMC,UAAAA,GAAaJ,SAAAA,CAAUK,MAAM,CAAC9C,MAAAA,CAAOR,IAAI,CAAA,CAAEmD,WAAW,EAAA,CAAGC,OAAO,CAAC,IAAA,EAAM,GAAA,CAAA;AAC7E,IAAA,MAAM,EAAEpF,UAAU,EAAEC,OAAO,EAAE,GAAG2D,2CAA2CpB,MAAAA,EAAQC,SAAAA,CAAAA;AACnF,IAAA,MAAM8C,aAAAA,GAAgBtF,OAAAA,CAAQwB,MAAM,GAAG,CAAA,GAAI;AAAExB,QAAAA;AAAQ,KAAA,GAAI,EAAC;IAE1D,IAAIuC,MAAAA,CAAOG,SAAS,KAAK,WAAA,EAAa;QACpC,OAAO;YACL6C,QAAAA,EAAUhD,MAAAA,CAAOgD,QAAQ,IAAI,SAAA;YAC7BC,SAAAA,EAAWT,YAAAA;AACXhF,YAAAA,UAAAA;AACA,YAAA,GAAGuF,aAAa;YAChBG,IAAAA,EAAM;AACJC,gBAAAA,WAAAA,EAAanD,OAAOR,IAAI;AACxB4D,gBAAAA,WAAAA,EAAapD,OAAOoD;AAGtB,aAAA;AACAjD,YAAAA,SAAAA,EAAWH,OAAOG,SAAS;AAC3BR,YAAAA,GAAAA,EAAKK,OAAOL,GAAG;YACf0D,cAAAA,EAAgBR,UAAAA;AAChBpD,YAAAA,MAAAA,EAAQyB,6BAA6BlB,MAAAA,EAAQC,SAAAA,CAAAA;YAC7CqD,QAAAA,EAAUd;AACZ,SAAA;AACF,IAAA;AAEA,IAAA,MAAMe,mBAAAA,GAAsBtD,SAAAA,EAAWE,SAAAA,KAAc,aAAA,GAAgBF,SAAAA,GAAYuD,SAAAA;AACjF,IAAA,MAAM1D,OAAOD,iBAAAA,CAAkBG,MAAAA,CAAOF,IAAI,CAAA,GAAIE,MAAAA,CAAOF,IAAI,GAAG,gBAAA;AAE5D,IAAA,MAAM2D,eAAAA,GAAkB;AACtB9D,QAAAA,GAAAA,EAAKK,OAAOL,GAAG;QACfQ,SAAAA,EAAW,aAAA;QACX8C,SAAAA,EAAWT,YAAAA;AACX1C,QAAAA,IAAAA;QACAoD,IAAAA,EAAM;AACJC,YAAAA,WAAAA,EAAanD,MAAAA,CAAOR,IAAI,CAACkE,MAAM,CAAC,CAAA,CAAA,CAAGC,WAAW,EAAA,GAAK3D,MAAAA,CAAOR,IAAI,CAACoE,KAAK,CAAC,CAAA,CAAA;;YAErEpB,YAAAA,EAAce,mBAAAA,EAAqBL,KAAKV,YAAAA,IAAgBA,YAAAA;;YAExDK,UAAAA,EAAYU,mBAAAA,EAAqBL,KAAKL,UAAAA,IAAcA;AACtD,SAAA;QACAQ,cAAAA,EAAgBR,UAAAA;AAChBrF,QAAAA,UAAAA;AACA,QAAA,GAAGuF,aAAa;QAChBc,OAAAA,EAAS;YACPC,eAAAA,EAAiB9D,MAAAA,CAAO6D,OAAO,EAAEC,eAAAA,IAAmB;AACtD,SAAA;QACAC,aAAAA,EAAe;YACbC,IAAAA,EAAM;gBACJC,SAAAA,EAAWjE,MAAAA,CAAO6D,OAAO,EAAEI,SAAAA,IAAa;AAC1C;AACF,SAAA;QACAC,OAAAA,EAAS,IAAA;AACTzE,QAAAA,MAAAA,EAAQyB,6BAA6BlB,MAAAA,EAAQC,SAAAA,CAAAA;QAC7CqD,QAAAA,EAAUd,YAAAA;QACV2B,mBAAAA,EAAqB;AACvB,KAAA;AAEA,IAAA,IACEpE,oBAAoBC,MAAAA,EAAQC,SAAAA,CAAAA,IAC5BA,aACAA,SAAAA,CAAUE,SAAS,KAAK,aAAA,EACxB;AACA,QAAA,MAAMiE,IAAAA,GAAOnE,SAAAA;QACb,OAAO;AACL,YAAA,GAAGwD,eAAe;AAClBvD,YAAAA,MAAAA,EAAQkE,IAAAA,CAAKlE,MAAM,IAAIF,MAAAA,CAAOE,MAAM;AACpCoD,YAAAA,QAAAA,EAAUc,KAAKd,QAAQ;AACvBL,YAAAA,SAAAA,EAAWmB,KAAKnB,SAAS;AACzBI,YAAAA,cAAAA,EAAgBe,KAAKf,cAAc;YACnCH,IAAAA,EAAM;AACJ,gBAAA,GAAGO,gBAAgBP,IAAI;gBACvBV,YAAAA,EAAc4B,IAAAA,CAAKlB,IAAI,CAACV,YAAY;gBACpCK,UAAAA,EAAYuB,IAAAA,CAAKlB,IAAI,CAACL;AACxB,aAAA;YACAgB,OAAAA,EAAS;AACP,gBAAA,GAAGO,KAAKP,OAAO;AACf,gBAAA,GAAGJ,gBAAgBI,OAAO;AAC1BC,gBAAAA,eAAAA,EAAiB9D,OAAO6D,OAAO,EAAEC,mBAAmBM,IAAAA,CAAKP,OAAO,EAAEC,eAAAA,IAAmB;AACvF,aAAA;YACAC,aAAAA,EAAe;AACb,gBAAA,GAAGK,KAAKL,aAAa;AACrB,gBAAA,GAAGN,gBAAgBM,aAAa;gBAChCC,IAAAA,EAAM;oBACJ,GAAII,IAAAA,CAAKL,aAAa,EAAEC,IAAI;oBAC5B,GAAIP,eAAAA,CAAgBM,aAAa,EAAEC,IAAI;oBACvCC,SAAAA,EACEjE,MAAAA,CAAO6D,OAAO,EAAEI,SAAAA,IACfG,KAAKL,aAAa,EAAEC,MAA8CC,SAAAA,IACnE;AACJ;AACF,aAAA;AACAC,YAAAA,OAAAA,EAASE,KAAKF,OAAO;AACrBC,YAAAA,mBAAAA,EAAqBC,KAAKD;AAC5B,SAAA;AACF,IAAA;AAEA,IAAA,IAAIpE,mBAAAA,CAAoBC,MAAAA,EAAQC,SAAAA,CAAAA,IAAcD,MAAAA,CAAOE,MAAM,EAAE;QAC3D,OAAO;AACL,YAAA,GAAGuD,eAAe;AAClBvD,YAAAA,MAAAA,EAAQF,OAAOE;AACjB,SAAA;AACF,IAAA;IAEA,OAAOuD,eAAAA;AACT;;;;"}