@strapi/content-type-builder 5.54.0 → 5.55.1
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/hooks/useAIFetch.js +6 -2
- package/dist/admin/components/AIChat/hooks/useAIFetch.js.map +1 -1
- package/dist/admin/components/AIChat/hooks/useAIFetch.mjs +7 -3
- package/dist/admin/components/AIChat/hooks/useAIFetch.mjs.map +1 -1
- package/dist/admin/components/AIChat/hooks/usePrefetchAIToken.js +20 -0
- package/dist/admin/components/AIChat/hooks/usePrefetchAIToken.js.map +1 -0
- package/dist/admin/components/AIChat/hooks/usePrefetchAIToken.mjs +18 -0
- package/dist/admin/components/AIChat/hooks/usePrefetchAIToken.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/ContentTypeBuilderNav.js +83 -59
- package/dist/admin/components/ContentTypeBuilderNav/ContentTypeBuilderNav.js.map +1 -1
- package/dist/admin/components/ContentTypeBuilderNav/ContentTypeBuilderNav.mjs +86 -62
- package/dist/admin/components/ContentTypeBuilderNav/ContentTypeBuilderNav.mjs.map +1 -1
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.js +112 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.mjs +110 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.js +159 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.mjs +157 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.js +311 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.mjs +309 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.js +379 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.mjs +376 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.js +172 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.mjs +166 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useFolderActions.js +62 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useFolderActions.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useFolderActions.mjs +60 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useFolderActions.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useSortableTree.js +145 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useSortableTree.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useSortableTree.mjs +143 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useSortableTree.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/buildFolderTree.js +176 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/buildFolderTree.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/buildFolderTree.mjs +169 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/buildFolderTree.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/dropProjection.js +277 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/dropProjection.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/dropProjection.mjs +273 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/dropProjection.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/flatModel.js +62 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/flatModel.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/flatModel.mjs +58 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/flatModel.mjs.map +1 -0
- 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 +70 -8
- package/dist/admin/components/DataManager/DataManagerProvider.js.map +1 -1
- package/dist/admin/components/DataManager/DataManagerProvider.mjs +70 -8
- package/dist/admin/components/DataManager/DataManagerProvider.mjs.map +1 -1
- package/dist/admin/components/DataManager/reducer.js +411 -33
- package/dist/admin/components/DataManager/reducer.js.map +1 -1
- package/dist/admin/components/DataManager/reducer.mjs +411 -33
- package/dist/admin/components/DataManager/reducer.mjs.map +1 -1
- package/dist/admin/components/DataManager/utils/cleanData.js +11 -2
- package/dist/admin/components/DataManager/utils/cleanData.js.map +1 -1
- package/dist/admin/components/DataManager/utils/cleanData.mjs +11 -2
- package/dist/admin/components/DataManager/utils/cleanData.mjs.map +1 -1
- package/dist/admin/components/DataManager/utils/contentStructure.js +150 -0
- package/dist/admin/components/DataManager/utils/contentStructure.js.map +1 -0
- package/dist/admin/components/DataManager/utils/contentStructure.mjs +133 -0
- package/dist/admin/components/DataManager/utils/contentStructure.mjs.map +1 -0
- package/dist/admin/components/FolderSelect.js +200 -0
- package/dist/admin/components/FolderSelect.js.map +1 -0
- package/dist/admin/components/FolderSelect.mjs +198 -0
- package/dist/admin/components/FolderSelect.mjs.map +1 -0
- package/dist/admin/components/FormModal/FormModal.js +23 -2
- package/dist/admin/components/FormModal/FormModal.js.map +1 -1
- package/dist/admin/components/FormModal/FormModal.mjs +23 -2
- package/dist/admin/components/FormModal/FormModal.mjs.map +1 -1
- package/dist/admin/components/FormModal/contentType/contentTypeForm.js +15 -18
- package/dist/admin/components/FormModal/contentType/contentTypeForm.js.map +1 -1
- package/dist/admin/components/FormModal/contentType/contentTypeForm.mjs +15 -18
- package/dist/admin/components/FormModal/contentType/contentTypeForm.mjs.map +1 -1
- package/dist/admin/components/FormModal/reducer.js +6 -0
- package/dist/admin/components/FormModal/reducer.js.map +1 -1
- package/dist/admin/components/FormModal/reducer.mjs +6 -0
- package/dist/admin/components/FormModal/reducer.mjs.map +1 -1
- package/dist/admin/pages/App/index.js +2 -5
- package/dist/admin/pages/App/index.js.map +1 -1
- package/dist/admin/pages/App/index.mjs +2 -5
- package/dist/admin/pages/App/index.mjs.map +1 -1
- package/dist/admin/src/components/AIChat/hooks/usePrefetchAIToken.d.ts +1 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.d.ts +16 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.d.ts +12 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.d.ts +14 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.d.ts +38 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/{useContentTypeBuilderMenu.d.ts → hooks/useContentTypeBuilderMenu.d.ts} +17 -7
- package/dist/admin/src/components/ContentTypeBuilderNav/hooks/useFolderActions.d.ts +42 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/hooks/useSortableTree.d.ts +53 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/lib/buildFolderTree.d.ts +42 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/lib/dropProjection.d.ts +58 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/lib/flatModel.d.ts +18 -0
- package/dist/admin/src/components/DataManager/DataManagerContext.d.ts +41 -0
- package/dist/admin/src/components/DataManager/reducer.d.ts +105 -1
- package/dist/admin/src/components/DataManager/utils/cleanData.d.ts +5 -1
- package/dist/admin/src/components/DataManager/utils/contentStructure.d.ts +68 -0
- package/dist/admin/src/components/FolderSelect.d.ts +18 -0
- package/dist/admin/src/components/FormModal/contentType/contentTypeForm.d.ts +0 -21
- package/dist/admin/src/components/FormModal/forms/forms.d.ts +0 -10
- package/dist/admin/src/components/FormModal/reducer.d.ts +7 -0
- package/dist/admin/src/utils/folderTelemetry.d.ts +5 -0
- package/dist/admin/translations/en.json.js +23 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +23 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/utils/folderTelemetry.js +19 -0
- package/dist/admin/utils/folderTelemetry.js.map +1 -0
- package/dist/admin/utils/folderTelemetry.mjs +16 -0
- package/dist/admin/utils/folderTelemetry.mjs.map +1 -0
- package/dist/server/controllers/schema.js +1 -1
- 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/common.js +3 -0
- package/dist/server/controllers/validation/common.js.map +1 -1
- package/dist/server/controllers/validation/common.mjs +3 -1
- package/dist/server/controllers/validation/common.mjs.map +1 -1
- package/dist/server/controllers/validation/content-structure.js +177 -0
- package/dist/server/controllers/validation/content-structure.js.map +1 -0
- package/dist/server/controllers/validation/content-structure.mjs +173 -0
- package/dist/server/controllers/validation/content-structure.mjs.map +1 -0
- package/dist/server/controllers/validation/schema.js +3 -1
- package/dist/server/controllers/validation/schema.js.map +1 -1
- package/dist/server/controllers/validation/schema.mjs +3 -1
- package/dist/server/controllers/validation/schema.mjs.map +1 -1
- package/dist/server/register.js +1 -1
- package/dist/server/register.js.map +1 -1
- package/dist/server/register.mjs +1 -1
- package/dist/server/register.mjs.map +1 -1
- package/dist/server/routes/content-api.js +4 -4
- package/dist/server/routes/content-api.js.map +1 -1
- package/dist/server/routes/content-api.mjs +4 -4
- package/dist/server/routes/content-api.mjs.map +1 -1
- package/dist/server/services/api-handler.js +37 -4
- package/dist/server/services/api-handler.js.map +1 -1
- package/dist/server/services/api-handler.mjs +36 -5
- package/dist/server/services/api-handler.mjs.map +1 -1
- package/dist/server/services/content-structure.js +174 -0
- package/dist/server/services/content-structure.js.map +1 -0
- package/dist/server/services/content-structure.mjs +172 -0
- package/dist/server/services/content-structure.mjs.map +1 -0
- package/dist/server/services/content-types.js +196 -44
- package/dist/server/services/content-types.js.map +1 -1
- package/dist/server/services/content-types.mjs +195 -45
- package/dist/server/services/content-types.mjs.map +1 -1
- package/dist/server/services/index.js +3 -1
- package/dist/server/services/index.js.map +1 -1
- package/dist/server/services/index.mjs +3 -1
- package/dist/server/services/index.mjs.map +1 -1
- package/dist/server/services/schema-builder/index.js +4 -2
- package/dist/server/services/schema-builder/index.js.map +1 -1
- package/dist/server/services/schema-builder/index.mjs +4 -2
- package/dist/server/services/schema-builder/index.mjs.map +1 -1
- package/dist/server/services/schema-builder/schema-handler.js +16 -16
- package/dist/server/services/schema-builder/schema-handler.js.map +1 -1
- package/dist/server/services/schema-builder/schema-handler.mjs +16 -16
- package/dist/server/services/schema-builder/schema-handler.mjs.map +1 -1
- package/dist/server/services/schema-mutation.js +46 -0
- package/dist/server/services/schema-mutation.js.map +1 -0
- package/dist/server/services/schema-mutation.mjs +43 -0
- package/dist/server/services/schema-mutation.mjs.map +1 -0
- package/dist/server/services/schema.js +134 -79
- package/dist/server/services/schema.js.map +1 -1
- package/dist/server/services/schema.mjs +135 -80
- package/dist/server/services/schema.mjs.map +1 -1
- package/dist/server/src/controllers/schema.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/common.d.ts +1 -0
- package/dist/server/src/controllers/validation/common.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/content-structure.d.ts +56 -0
- package/dist/server/src/controllers/validation/content-structure.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/schema.d.ts +35 -0
- package/dist/server/src/controllers/validation/schema.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +3 -0
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/routes/content-api.d.ts.map +1 -1
- package/dist/server/src/services/api-handler.d.ts +13 -1
- package/dist/server/src/services/api-handler.d.ts.map +1 -1
- package/dist/server/src/services/content-structure.d.ts +37 -0
- package/dist/server/src/services/content-structure.d.ts.map +1 -0
- package/dist/server/src/services/content-types.d.ts +4 -0
- package/dist/server/src/services/content-types.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +4 -0
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/schema-builder/index.d.ts +3 -1
- package/dist/server/src/services/schema-builder/index.d.ts.map +1 -1
- package/dist/server/src/services/schema-builder/schema-handler.d.ts.map +1 -1
- package/dist/server/src/services/schema-mutation.d.ts +26 -0
- package/dist/server/src/services/schema-mutation.d.ts.map +1 -0
- package/dist/server/src/services/schema.d.ts +1 -0
- package/dist/server/src/services/schema.d.ts.map +1 -1
- package/dist/server/src/utils/index.d.ts +2 -0
- package/dist/server/src/utils/index.d.ts.map +1 -1
- package/dist/server/utils/index.js.map +1 -1
- package/dist/server/utils/index.mjs.map +1 -1
- package/package.json +6 -6
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.js +0 -157
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.js.map +0 -1
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.mjs +0 -151
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.mjs.map +0 -1
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const DID_ACT_ON_FOLDERS = "didActOnFolders";
|
|
2
|
+
export type FolderAction = 'create' | 'rename' | 'move' | 'deleteOnly' | 'deleteSubtree' | 'assign' | 'reorder';
|
|
3
|
+
export type FolderTelemetryOperation = 'create' | 'update' | 'delete';
|
|
4
|
+
/** Map a fine-grained folder action to an operation value the telemetry API accepts. */
|
|
5
|
+
export declare const folderTelemetryOperation: (action: FolderAction) => FolderTelemetryOperation;
|
|
@@ -60,6 +60,8 @@ var en = {
|
|
|
60
60
|
"contentType.collectionName.description": "Useful when the name of your Content Type and your table name differ",
|
|
61
61
|
"contentType.collectionName.label": "Collection name",
|
|
62
62
|
"contentType.displayName.label": "Display name",
|
|
63
|
+
"contentType.folder.label": "Select a folder or enter a value to create a new one",
|
|
64
|
+
"contentType.folder.placeholder": "Select or enter a value",
|
|
63
65
|
"contentType.kind.change.warning": "You just changed the kind of a content type: API will be reset (routes, controllers, and services will be overwritten).",
|
|
64
66
|
"error.attributeName.reserved-name": "This name cannot be used in your content type as it might break other functionalities",
|
|
65
67
|
"error.contentType.pluralName-used": "This value cannot be the same as the singular one",
|
|
@@ -171,6 +173,27 @@ var en = {
|
|
|
171
173
|
"menu.section.components.name": "Components",
|
|
172
174
|
"menu.section.models.name": "Collection Types",
|
|
173
175
|
"menu.section.single-types.name": "Single Types",
|
|
176
|
+
"nav.action.new-collection-type": "New Collection-Type",
|
|
177
|
+
"nav.action.new-folder": "New folder",
|
|
178
|
+
"nav.action.new-single-type": "New Single-Type",
|
|
179
|
+
"nav.drag.handle-label": "Move {name}",
|
|
180
|
+
"nav.folder.actions-label": "Actions for {name}",
|
|
181
|
+
"nav.folder.default-name": "New folder",
|
|
182
|
+
"nav.folder.delete": "Delete folder",
|
|
183
|
+
"nav.folder.delete-with-content": "Delete folder and contents",
|
|
184
|
+
"nav.folder.delete-with-content.body": "You are about to delete the folder named {name} and its deletable contents ({contentTypes, plural, =0 {{subfolders, plural, one {# subfolder} other {# subfolders}}} one {# application content type{subfolders, plural, =0 {} one {, # subfolder} other {, # subfolders}}} other {# application content types{subfolders, plural, =0 {} one {, # subfolder} other {, # subfolders}}}}). Are you sure you want to proceed?",
|
|
185
|
+
"nav.folder.delete-with-content.preserved": "{preservedContentTypes, plural, one {# protected content type will be preserved and ungrouped.} other {# protected content types will be preserved and ungrouped.}}",
|
|
186
|
+
"nav.folder.delete.blocked": "This folder cannot be deleted because these folder names already exist in its destination: {names}.",
|
|
187
|
+
"nav.folder.delete-with-content.title": "Delete folder and contents",
|
|
188
|
+
"nav.folder.delete.body": "You are about to delete the folder named {name}. Are you sure you want to proceed?",
|
|
189
|
+
"nav.folder.delete.cancel": "No, cancel",
|
|
190
|
+
"nav.folder.delete.confirm": "Yes, delete",
|
|
191
|
+
"nav.folder.delete.title": "Delete folder",
|
|
192
|
+
"nav.folder.dragging": "Dragging {name}",
|
|
193
|
+
"nav.folder.empty": "Empty folder",
|
|
194
|
+
"nav.folder.name-label": "Folder name",
|
|
195
|
+
"nav.folder.name.duplicate": "A folder with this name already exists in this location",
|
|
196
|
+
"nav.folder.rename": "Rename",
|
|
174
197
|
"modalForm.attribute.form.base.name.description": "No space is allowed for the name of the attribute",
|
|
175
198
|
"modalForm.attribute.form.base.name.placeholder": "e.g. slug, seoUrl, canonicalUrl",
|
|
176
199
|
"modalForm.attribute.target-field": "Attached field",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -56,6 +56,8 @@ var en = {
|
|
|
56
56
|
"contentType.collectionName.description": "Useful when the name of your Content Type and your table name differ",
|
|
57
57
|
"contentType.collectionName.label": "Collection name",
|
|
58
58
|
"contentType.displayName.label": "Display name",
|
|
59
|
+
"contentType.folder.label": "Select a folder or enter a value to create a new one",
|
|
60
|
+
"contentType.folder.placeholder": "Select or enter a value",
|
|
59
61
|
"contentType.kind.change.warning": "You just changed the kind of a content type: API will be reset (routes, controllers, and services will be overwritten).",
|
|
60
62
|
"error.attributeName.reserved-name": "This name cannot be used in your content type as it might break other functionalities",
|
|
61
63
|
"error.contentType.pluralName-used": "This value cannot be the same as the singular one",
|
|
@@ -167,6 +169,27 @@ var en = {
|
|
|
167
169
|
"menu.section.components.name": "Components",
|
|
168
170
|
"menu.section.models.name": "Collection Types",
|
|
169
171
|
"menu.section.single-types.name": "Single Types",
|
|
172
|
+
"nav.action.new-collection-type": "New Collection-Type",
|
|
173
|
+
"nav.action.new-folder": "New folder",
|
|
174
|
+
"nav.action.new-single-type": "New Single-Type",
|
|
175
|
+
"nav.drag.handle-label": "Move {name}",
|
|
176
|
+
"nav.folder.actions-label": "Actions for {name}",
|
|
177
|
+
"nav.folder.default-name": "New folder",
|
|
178
|
+
"nav.folder.delete": "Delete folder",
|
|
179
|
+
"nav.folder.delete-with-content": "Delete folder and contents",
|
|
180
|
+
"nav.folder.delete-with-content.body": "You are about to delete the folder named {name} and its deletable contents ({contentTypes, plural, =0 {{subfolders, plural, one {# subfolder} other {# subfolders}}} one {# application content type{subfolders, plural, =0 {} one {, # subfolder} other {, # subfolders}}} other {# application content types{subfolders, plural, =0 {} one {, # subfolder} other {, # subfolders}}}}). Are you sure you want to proceed?",
|
|
181
|
+
"nav.folder.delete-with-content.preserved": "{preservedContentTypes, plural, one {# protected content type will be preserved and ungrouped.} other {# protected content types will be preserved and ungrouped.}}",
|
|
182
|
+
"nav.folder.delete.blocked": "This folder cannot be deleted because these folder names already exist in its destination: {names}.",
|
|
183
|
+
"nav.folder.delete-with-content.title": "Delete folder and contents",
|
|
184
|
+
"nav.folder.delete.body": "You are about to delete the folder named {name}. Are you sure you want to proceed?",
|
|
185
|
+
"nav.folder.delete.cancel": "No, cancel",
|
|
186
|
+
"nav.folder.delete.confirm": "Yes, delete",
|
|
187
|
+
"nav.folder.delete.title": "Delete folder",
|
|
188
|
+
"nav.folder.dragging": "Dragging {name}",
|
|
189
|
+
"nav.folder.empty": "Empty folder",
|
|
190
|
+
"nav.folder.name-label": "Folder name",
|
|
191
|
+
"nav.folder.name.duplicate": "A folder with this name already exists in this location",
|
|
192
|
+
"nav.folder.rename": "Rename",
|
|
170
193
|
"modalForm.attribute.form.base.name.description": "No space is allowed for the name of the attribute",
|
|
171
194
|
"modalForm.attribute.form.base.name.placeholder": "e.g. slug, seoUrl, canonicalUrl",
|
|
172
195
|
"modalForm.attribute.target-field": "Attached field",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"en.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const DID_ACT_ON_FOLDERS = 'didActOnFolders';
|
|
4
|
+
const OPERATION_BY_ACTION = {
|
|
5
|
+
create: 'create',
|
|
6
|
+
rename: 'update',
|
|
7
|
+
move: 'update',
|
|
8
|
+
assign: 'update',
|
|
9
|
+
reorder: 'update',
|
|
10
|
+
deleteOnly: 'delete',
|
|
11
|
+
deleteSubtree: 'delete'
|
|
12
|
+
};
|
|
13
|
+
/** Map a fine-grained folder action to an operation value the telemetry API accepts. */ const folderTelemetryOperation = (action)=>{
|
|
14
|
+
return OPERATION_BY_ACTION[action];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
exports.DID_ACT_ON_FOLDERS = DID_ACT_ON_FOLDERS;
|
|
18
|
+
exports.folderTelemetryOperation = folderTelemetryOperation;
|
|
19
|
+
//# sourceMappingURL=folderTelemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folderTelemetry.js","sources":["../../../admin/src/utils/folderTelemetry.ts"],"sourcesContent":["export const DID_ACT_ON_FOLDERS = 'didActOnFolders';\n\nexport type FolderAction =\n | 'create'\n | 'rename'\n | 'move'\n | 'deleteOnly'\n | 'deleteSubtree'\n | 'assign'\n | 'reorder';\n\nexport type FolderTelemetryOperation = 'create' | 'update' | 'delete';\n\nconst OPERATION_BY_ACTION: Record<FolderAction, FolderTelemetryOperation> = {\n create: 'create',\n rename: 'update',\n move: 'update',\n assign: 'update',\n reorder: 'update',\n deleteOnly: 'delete',\n deleteSubtree: 'delete',\n};\n\n/** Map a fine-grained folder action to an operation value the telemetry API accepts. */\nexport const folderTelemetryOperation = (action: FolderAction): FolderTelemetryOperation => {\n return OPERATION_BY_ACTION[action];\n};\n"],"names":["DID_ACT_ON_FOLDERS","OPERATION_BY_ACTION","create","rename","move","assign","reorder","deleteOnly","deleteSubtree","folderTelemetryOperation","action"],"mappings":";;AAAO,MAAMA,qBAAqB;AAalC,MAAMC,mBAAAA,GAAsE;IAC1EC,MAAAA,EAAQ,QAAA;IACRC,MAAAA,EAAQ,QAAA;IACRC,IAAAA,EAAM,QAAA;IACNC,MAAAA,EAAQ,QAAA;IACRC,OAAAA,EAAS,QAAA;IACTC,UAAAA,EAAY,QAAA;IACZC,aAAAA,EAAe;AACjB,CAAA;AAEA,yFACO,MAAMC,wBAAAA,GAA2B,CAACC,MAAAA,GAAAA;IACvC,OAAOT,mBAAmB,CAACS,MAAAA,CAAO;AACpC;;;;;"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const DID_ACT_ON_FOLDERS = 'didActOnFolders';
|
|
2
|
+
const OPERATION_BY_ACTION = {
|
|
3
|
+
create: 'create',
|
|
4
|
+
rename: 'update',
|
|
5
|
+
move: 'update',
|
|
6
|
+
assign: 'update',
|
|
7
|
+
reorder: 'update',
|
|
8
|
+
deleteOnly: 'delete',
|
|
9
|
+
deleteSubtree: 'delete'
|
|
10
|
+
};
|
|
11
|
+
/** Map a fine-grained folder action to an operation value the telemetry API accepts. */ const folderTelemetryOperation = (action)=>{
|
|
12
|
+
return OPERATION_BY_ACTION[action];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export { DID_ACT_ON_FOLDERS, folderTelemetryOperation };
|
|
16
|
+
//# sourceMappingURL=folderTelemetry.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folderTelemetry.mjs","sources":["../../../admin/src/utils/folderTelemetry.ts"],"sourcesContent":["export const DID_ACT_ON_FOLDERS = 'didActOnFolders';\n\nexport type FolderAction =\n | 'create'\n | 'rename'\n | 'move'\n | 'deleteOnly'\n | 'deleteSubtree'\n | 'assign'\n | 'reorder';\n\nexport type FolderTelemetryOperation = 'create' | 'update' | 'delete';\n\nconst OPERATION_BY_ACTION: Record<FolderAction, FolderTelemetryOperation> = {\n create: 'create',\n rename: 'update',\n move: 'update',\n assign: 'update',\n reorder: 'update',\n deleteOnly: 'delete',\n deleteSubtree: 'delete',\n};\n\n/** Map a fine-grained folder action to an operation value the telemetry API accepts. */\nexport const folderTelemetryOperation = (action: FolderAction): FolderTelemetryOperation => {\n return OPERATION_BY_ACTION[action];\n};\n"],"names":["DID_ACT_ON_FOLDERS","OPERATION_BY_ACTION","create","rename","move","assign","reorder","deleteOnly","deleteSubtree","folderTelemetryOperation","action"],"mappings":"AAAO,MAAMA,qBAAqB;AAalC,MAAMC,mBAAAA,GAAsE;IAC1EC,MAAAA,EAAQ,QAAA;IACRC,MAAAA,EAAQ,QAAA;IACRC,IAAAA,EAAM,QAAA;IACNC,MAAAA,EAAQ,QAAA;IACRC,OAAAA,EAAS,QAAA;IACTC,UAAAA,EAAY,QAAA;IACZC,aAAAA,EAAe;AACjB,CAAA;AAEA,yFACO,MAAMC,wBAAAA,GAA2B,CAACC,MAAAA,GAAAA;IACvC,OAAOT,mBAAmB,CAACS,MAAAA,CAAO;AACpC;;;;"}
|
|
@@ -21,7 +21,7 @@ var schema = (()=>{
|
|
|
21
21
|
}
|
|
22
22
|
try {
|
|
23
23
|
const { data } = await schema$1.validateUpdateSchema(ctx.request.body);
|
|
24
|
-
if (fp.isEmpty(data.components) && fp.isEmpty(data.contentTypes)) {
|
|
24
|
+
if (fp.isEmpty(data.components) && fp.isEmpty(data.contentTypes) && fp.isEmpty(data.contentStructure)) {
|
|
25
25
|
ctx.body = {};
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sources":["../../../server/src/controllers/schema.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport { isEmpty } from 'lodash/fp';\n\nimport { getService } from '../utils';\nimport { validateUpdateSchema } from './validation/schema';\n\nexport default () => {\n const internals = {\n isUpdating: false,\n };\n\n return {\n async getSchema(ctx: Context) {\n const schema = await getService('schema').getSchema();\n\n ctx.send({ data: schema });\n },\n\n async updateSchema(ctx: Context) {\n if (internals.isUpdating === true) {\n return ctx.conflict('Schema update is already in progress.');\n }\n\n try {\n const { data } = await validateUpdateSchema(ctx.request.body);\n\n if (isEmpty(data.components)
|
|
1
|
+
{"version":3,"file":"schema.js","sources":["../../../server/src/controllers/schema.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport { isEmpty } from 'lodash/fp';\n\nimport { getService } from '../utils';\nimport { validateUpdateSchema } from './validation/schema';\n\nexport default () => {\n const internals = {\n isUpdating: false,\n };\n\n return {\n async getSchema(ctx: Context) {\n const schema = await getService('schema').getSchema();\n\n ctx.send({ data: schema });\n },\n\n async updateSchema(ctx: Context) {\n if (internals.isUpdating === true) {\n return ctx.conflict('Schema update is already in progress.');\n }\n\n try {\n const { data } = await validateUpdateSchema(ctx.request.body);\n\n if (\n isEmpty(data.components) &&\n isEmpty(data.contentTypes) &&\n isEmpty(data.contentStructure)\n ) {\n ctx.body = {};\n return;\n }\n\n internals.isUpdating = true;\n strapi.reload.isWatching = false;\n\n await getService('schema').updateSchema(data);\n\n // NOTE: we do not set isUpdating to false here.\n // We want to wait for the server to restart to get the isUpdate = false only\n setImmediate(() => {\n strapi.reload();\n });\n\n ctx.body = {};\n } catch (error) {\n internals.isUpdating = false;\n const errorMessage = error instanceof Error ? error.message : String(error);\n return ctx.send({ error: errorMessage }, 400);\n }\n },\n\n async getUpdateSchemaStatus(ctx: Context) {\n ctx.send({ data: { isUpdating: internals.isUpdating } });\n },\n };\n};\n"],"names":["internals","isUpdating","getSchema","ctx","schema","getService","send","data","updateSchema","conflict","validateUpdateSchema","request","body","isEmpty","components","contentTypes","contentStructure","strapi","reload","isWatching","setImmediate","error","errorMessage","Error","message","String","getUpdateSchemaStatus"],"mappings":";;;;;;AAMA,aAAe,CAAA,IAAA;AACb,IAAA,MAAMA,SAAAA,GAAY;QAChBC,UAAAA,EAAY;AACd,KAAA;IAEA,OAAO;AACL,QAAA,MAAMC,WAAUC,GAAY,EAAA;AAC1B,YAAA,MAAMC,MAAAA,GAAS,MAAMC,gBAAAA,CAAW,QAAA,CAAA,CAAUH,SAAS,EAAA;AAEnDC,YAAAA,GAAAA,CAAIG,IAAI,CAAC;gBAAEC,IAAAA,EAAMH;AAAO,aAAA,CAAA;AAC1B,QAAA,CAAA;AAEA,QAAA,MAAMI,cAAaL,GAAY,EAAA;YAC7B,IAAIH,SAAAA,CAAUC,UAAU,KAAK,IAAA,EAAM;gBACjC,OAAOE,GAAAA,CAAIM,QAAQ,CAAC,uCAAA,CAAA;AACtB,YAAA;YAEA,IAAI;gBACF,MAAM,EAAEF,IAAI,EAAE,GAAG,MAAMG,6BAAAA,CAAqBP,GAAAA,CAAIQ,OAAO,CAACC,IAAI,CAAA;gBAE5D,IACEC,UAAAA,CAAQN,IAAAA,CAAKO,UAAU,CAAA,IACvBD,UAAAA,CAAQN,IAAAA,CAAKQ,YAAY,CAAA,IACzBF,UAAAA,CAAQN,IAAAA,CAAKS,gBAAgB,CAAA,EAC7B;oBACAb,GAAAA,CAAIS,IAAI,GAAG,EAAC;AACZ,oBAAA;AACF,gBAAA;AAEAZ,gBAAAA,SAAAA,CAAUC,UAAU,GAAG,IAAA;gBACvBgB,MAAAA,CAAOC,MAAM,CAACC,UAAU,GAAG,KAAA;gBAE3B,MAAMd,gBAAAA,CAAW,QAAA,CAAA,CAAUG,YAAY,CAACD,IAAAA,CAAAA;;;gBAIxCa,YAAAA,CAAa,IAAA;AACXH,oBAAAA,MAAAA,CAAOC,MAAM,EAAA;AACf,gBAAA,CAAA,CAAA;gBAEAf,GAAAA,CAAIS,IAAI,GAAG,EAAC;AACd,YAAA,CAAA,CAAE,OAAOS,KAAAA,EAAO;AACdrB,gBAAAA,SAAAA,CAAUC,UAAU,GAAG,KAAA;AACvB,gBAAA,MAAMqB,eAAeD,KAAAA,YAAiBE,KAAAA,GAAQF,KAAAA,CAAMG,OAAO,GAAGC,MAAAA,CAAOJ,KAAAA,CAAAA;gBACrE,OAAOlB,GAAAA,CAAIG,IAAI,CAAC;oBAAEe,KAAAA,EAAOC;iBAAa,EAAG,GAAA,CAAA;AAC3C,YAAA;AACF,QAAA,CAAA;AAEA,QAAA,MAAMI,uBAAsBvB,GAAY,EAAA;AACtCA,YAAAA,GAAAA,CAAIG,IAAI,CAAC;gBAAEC,IAAAA,EAAM;AAAEN,oBAAAA,UAAAA,EAAYD,UAAUC;AAAW;AAAE,aAAA,CAAA;AACxD,QAAA;AACF,KAAA;AACF,CAAA;;;;"}
|
|
@@ -19,7 +19,7 @@ var schema = (()=>{
|
|
|
19
19
|
}
|
|
20
20
|
try {
|
|
21
21
|
const { data } = await validateUpdateSchema(ctx.request.body);
|
|
22
|
-
if (isEmpty(data.components) && isEmpty(data.contentTypes)) {
|
|
22
|
+
if (isEmpty(data.components) && isEmpty(data.contentTypes) && isEmpty(data.contentStructure)) {
|
|
23
23
|
ctx.body = {};
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.mjs","sources":["../../../server/src/controllers/schema.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport { isEmpty } from 'lodash/fp';\n\nimport { getService } from '../utils';\nimport { validateUpdateSchema } from './validation/schema';\n\nexport default () => {\n const internals = {\n isUpdating: false,\n };\n\n return {\n async getSchema(ctx: Context) {\n const schema = await getService('schema').getSchema();\n\n ctx.send({ data: schema });\n },\n\n async updateSchema(ctx: Context) {\n if (internals.isUpdating === true) {\n return ctx.conflict('Schema update is already in progress.');\n }\n\n try {\n const { data } = await validateUpdateSchema(ctx.request.body);\n\n if (isEmpty(data.components)
|
|
1
|
+
{"version":3,"file":"schema.mjs","sources":["../../../server/src/controllers/schema.ts"],"sourcesContent":["import type { Context } from 'koa';\nimport { isEmpty } from 'lodash/fp';\n\nimport { getService } from '../utils';\nimport { validateUpdateSchema } from './validation/schema';\n\nexport default () => {\n const internals = {\n isUpdating: false,\n };\n\n return {\n async getSchema(ctx: Context) {\n const schema = await getService('schema').getSchema();\n\n ctx.send({ data: schema });\n },\n\n async updateSchema(ctx: Context) {\n if (internals.isUpdating === true) {\n return ctx.conflict('Schema update is already in progress.');\n }\n\n try {\n const { data } = await validateUpdateSchema(ctx.request.body);\n\n if (\n isEmpty(data.components) &&\n isEmpty(data.contentTypes) &&\n isEmpty(data.contentStructure)\n ) {\n ctx.body = {};\n return;\n }\n\n internals.isUpdating = true;\n strapi.reload.isWatching = false;\n\n await getService('schema').updateSchema(data);\n\n // NOTE: we do not set isUpdating to false here.\n // We want to wait for the server to restart to get the isUpdate = false only\n setImmediate(() => {\n strapi.reload();\n });\n\n ctx.body = {};\n } catch (error) {\n internals.isUpdating = false;\n const errorMessage = error instanceof Error ? error.message : String(error);\n return ctx.send({ error: errorMessage }, 400);\n }\n },\n\n async getUpdateSchemaStatus(ctx: Context) {\n ctx.send({ data: { isUpdating: internals.isUpdating } });\n },\n };\n};\n"],"names":["internals","isUpdating","getSchema","ctx","schema","getService","send","data","updateSchema","conflict","validateUpdateSchema","request","body","isEmpty","components","contentTypes","contentStructure","strapi","reload","isWatching","setImmediate","error","errorMessage","Error","message","String","getUpdateSchemaStatus"],"mappings":";;;;AAMA,aAAe,CAAA,IAAA;AACb,IAAA,MAAMA,SAAAA,GAAY;QAChBC,UAAAA,EAAY;AACd,KAAA;IAEA,OAAO;AACL,QAAA,MAAMC,WAAUC,GAAY,EAAA;AAC1B,YAAA,MAAMC,MAAAA,GAAS,MAAMC,UAAAA,CAAW,QAAA,CAAA,CAAUH,SAAS,EAAA;AAEnDC,YAAAA,GAAAA,CAAIG,IAAI,CAAC;gBAAEC,IAAAA,EAAMH;AAAO,aAAA,CAAA;AAC1B,QAAA,CAAA;AAEA,QAAA,MAAMI,cAAaL,GAAY,EAAA;YAC7B,IAAIH,SAAAA,CAAUC,UAAU,KAAK,IAAA,EAAM;gBACjC,OAAOE,GAAAA,CAAIM,QAAQ,CAAC,uCAAA,CAAA;AACtB,YAAA;YAEA,IAAI;gBACF,MAAM,EAAEF,IAAI,EAAE,GAAG,MAAMG,oBAAAA,CAAqBP,GAAAA,CAAIQ,OAAO,CAACC,IAAI,CAAA;gBAE5D,IACEC,OAAAA,CAAQN,IAAAA,CAAKO,UAAU,CAAA,IACvBD,OAAAA,CAAQN,IAAAA,CAAKQ,YAAY,CAAA,IACzBF,OAAAA,CAAQN,IAAAA,CAAKS,gBAAgB,CAAA,EAC7B;oBACAb,GAAAA,CAAIS,IAAI,GAAG,EAAC;AACZ,oBAAA;AACF,gBAAA;AAEAZ,gBAAAA,SAAAA,CAAUC,UAAU,GAAG,IAAA;gBACvBgB,MAAAA,CAAOC,MAAM,CAACC,UAAU,GAAG,KAAA;gBAE3B,MAAMd,UAAAA,CAAW,QAAA,CAAA,CAAUG,YAAY,CAACD,IAAAA,CAAAA;;;gBAIxCa,YAAAA,CAAa,IAAA;AACXH,oBAAAA,MAAAA,CAAOC,MAAM,EAAA;AACf,gBAAA,CAAA,CAAA;gBAEAf,GAAAA,CAAIS,IAAI,GAAG,EAAC;AACd,YAAA,CAAA,CAAE,OAAOS,KAAAA,EAAO;AACdrB,gBAAAA,SAAAA,CAAUC,UAAU,GAAG,KAAA;AACvB,gBAAA,MAAMqB,eAAeD,KAAAA,YAAiBE,KAAAA,GAAQF,KAAAA,CAAMG,OAAO,GAAGC,MAAAA,CAAOJ,KAAAA,CAAAA;gBACrE,OAAOlB,GAAAA,CAAIG,IAAI,CAAC;oBAAEe,KAAAA,EAAOC;iBAAa,EAAG,GAAA,CAAA;AAC3C,YAAA;AACF,QAAA,CAAA;AAEA,QAAA,MAAMI,uBAAsBvB,GAAY,EAAA;AACtCA,YAAAA,GAAAA,CAAIG,IAAI,CAAC;gBAAEC,IAAAA,EAAM;AAAEN,oBAAAA,UAAAA,EAAYD,UAAUC;AAAW;AAAE,aAAA,CAAA;AACxD,QAAA;AACF,KAAA;AACF,CAAA;;;;"}
|
|
@@ -19,6 +19,8 @@ const CATEGORY_NAME_REGEX = /^[A-Za-z][-_0-9A-Za-z]*$/;
|
|
|
19
19
|
const ICON_REGEX = /^[A-Za-z0-9][-A-Za-z0-9]*$/;
|
|
20
20
|
const UID_REGEX = /^[A-Za-z0-9-_.~]*$/;
|
|
21
21
|
const KEBAB_BASE_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
22
|
+
// Fully-qualified content-type uid: `api::a.a` / `plugin::p.p` / `strapi::x` / `admin::x`.
|
|
23
|
+
const CONTENT_TYPE_UID_REGEX = /^((strapi|admin)::[\w-]+|(api|plugin)::[\w-]+\.[\w-]+)$/;
|
|
22
24
|
const isValidName = {
|
|
23
25
|
name: 'isValidName',
|
|
24
26
|
message: `\${path} must match the following regex: ${NAME_REGEX}`,
|
|
@@ -85,6 +87,7 @@ const isValidDefaultJSON = {
|
|
|
85
87
|
|
|
86
88
|
exports.CATEGORY_NAME_REGEX = CATEGORY_NAME_REGEX;
|
|
87
89
|
exports.COLLECTION_NAME_REGEX = COLLECTION_NAME_REGEX;
|
|
90
|
+
exports.CONTENT_TYPE_UID_REGEX = CONTENT_TYPE_UID_REGEX;
|
|
88
91
|
exports.ICON_REGEX = ICON_REGEX;
|
|
89
92
|
exports.KEBAB_BASE_REGEX = KEBAB_BASE_REGEX;
|
|
90
93
|
exports.NAME_REGEX = NAME_REGEX;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.js","sources":["../../../../server/src/controllers/validation/common.ts"],"sourcesContent":["/* eslint-disable no-template-curly-in-string */\nimport { yup, strings } from '@strapi/utils';\nimport _ from 'lodash';\nimport { TestConfig } from 'yup';\n\nexport const validators = {\n required: yup.boolean(),\n unique: yup.boolean(),\n minLength: yup.number().integer().positive(),\n maxLength: yup.number().integer().positive(),\n};\n\nexport const NAME_REGEX = /^[A-Za-z][_0-9A-Za-z]*$/;\nexport const COLLECTION_NAME_REGEX = /^[A-Za-z][-_0-9A-Za-z]*$/;\nexport const CATEGORY_NAME_REGEX = /^[A-Za-z][-_0-9A-Za-z]*$/;\nexport const ICON_REGEX = /^[A-Za-z0-9][-A-Za-z0-9]*$/;\nexport const UID_REGEX = /^[A-Za-z0-9-_.~]*$/;\nexport const KEBAB_BASE_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\nexport type CommonTestConfig = TestConfig<unknown | undefined, Record<string, unknown>>;\n\nexport const isValidName: CommonTestConfig = {\n name: 'isValidName',\n message: `\\${path} must match the following regex: ${NAME_REGEX}`,\n test: (val: unknown) => val === '' || NAME_REGEX.test(val as string),\n};\n\nexport const isValidIcon: CommonTestConfig = {\n name: 'isValidIcon',\n message: `\\${path} is not a valid icon name. Make sure your icon name starts with an alphanumeric character and only includes alphanumeric characters or dashes.`,\n test: (val) => val === '' || ICON_REGEX.test(val as string),\n};\n\nexport const isValidUID: CommonTestConfig = {\n name: 'isValidUID',\n message: `\\${path} must match the following regex: ${UID_REGEX}`,\n test: (val) => val === '' || UID_REGEX.test(val as string),\n};\n\nexport const isValidCategoryName: CommonTestConfig = {\n name: 'isValidCategoryName',\n message: `\\${path} must start with a letter and only contain letters, numbers, dashes and underscores`,\n test: (val) => val === '' || CATEGORY_NAME_REGEX.test(val as string),\n};\n\nexport const isValidCollectionName: CommonTestConfig = {\n name: 'isValidCollectionName',\n message: `\\${path} must match the following regex: ${COLLECTION_NAME_REGEX}`,\n test: (val) => val === '' || COLLECTION_NAME_REGEX.test(val as string),\n};\n\nexport const isValidKey = (key: string): CommonTestConfig => ({\n name: 'isValidKey',\n message: `Attribute name '${key}' must match the following regex: ${NAME_REGEX}`,\n test: () => NAME_REGEX.test(key),\n});\n\nexport const isValidEnum: CommonTestConfig = {\n name: 'isValidEnum',\n message: '${path} should not start with number',\n test: (val) => val === '' || !strings.startsWithANumber(val as string),\n};\n\nexport const areEnumValuesUnique: CommonTestConfig = {\n name: 'areEnumValuesUnique',\n message: '${path} cannot contain duplicate values',\n test(values) {\n const filtered = [...new Set(values as string[])];\n\n return filtered.length === (values as string[]).length;\n },\n};\n\nexport const isValidRegExpPattern: CommonTestConfig = {\n name: 'isValidRegExpPattern',\n message: '${path} must be a valid RexExp pattern string',\n test: (val) => val === '' || !!new RegExp(val as string),\n};\n\nexport const isValidDefaultJSON: CommonTestConfig = {\n name: 'isValidDefaultJSON',\n message: '${path} is not a valid JSON',\n test(val) {\n if (val === undefined) {\n return true;\n }\n\n if (_.isNumber(val) || _.isNull(val) || _.isObject(val) || _.isArray(val)) {\n return true;\n }\n\n try {\n JSON.parse(val as string);\n\n return true;\n } catch {\n return false;\n }\n },\n};\n"],"names":["validators","required","yup","boolean","unique","minLength","number","integer","positive","maxLength","NAME_REGEX","COLLECTION_NAME_REGEX","CATEGORY_NAME_REGEX","ICON_REGEX","UID_REGEX","KEBAB_BASE_REGEX","isValidName","name","message","test","val","isValidIcon","isValidCategoryName","isValidCollectionName","isValidKey","key","isValidEnum","strings","startsWithANumber","areEnumValuesUnique","values","filtered","Set","length","isValidRegExpPattern","RegExp","isValidDefaultJSON","undefined","_","isNumber","isNull","isObject","isArray","JSON","parse"],"mappings":";;;;;;;;;MAKaA,UAAAA,GAAa;AACxBC,IAAAA,QAAAA,EAAUC,UAAIC,OAAO,EAAA;AACrBC,IAAAA,MAAAA,EAAQF,UAAIC,OAAO,EAAA;AACnBE,IAAAA,SAAAA,EAAWH,SAAAA,CAAII,MAAM,EAAA,CAAGC,OAAO,GAAGC,QAAQ,EAAA;AAC1CC,IAAAA,SAAAA,EAAWP,SAAAA,CAAII,MAAM,EAAA,CAAGC,OAAO,GAAGC,QAAQ;AAC5C;AAEO,MAAME,aAAa;AACnB,MAAMC,wBAAwB;AAC9B,MAAMC,sBAAsB;AAC5B,MAAMC,aAAa;AACnB,MAAMC,YAAY;AAClB,MAAMC,mBAAmB;
|
|
1
|
+
{"version":3,"file":"common.js","sources":["../../../../server/src/controllers/validation/common.ts"],"sourcesContent":["/* eslint-disable no-template-curly-in-string */\nimport { yup, strings } from '@strapi/utils';\nimport _ from 'lodash';\nimport { TestConfig } from 'yup';\n\nexport const validators = {\n required: yup.boolean(),\n unique: yup.boolean(),\n minLength: yup.number().integer().positive(),\n maxLength: yup.number().integer().positive(),\n};\n\nexport const NAME_REGEX = /^[A-Za-z][_0-9A-Za-z]*$/;\nexport const COLLECTION_NAME_REGEX = /^[A-Za-z][-_0-9A-Za-z]*$/;\nexport const CATEGORY_NAME_REGEX = /^[A-Za-z][-_0-9A-Za-z]*$/;\nexport const ICON_REGEX = /^[A-Za-z0-9][-A-Za-z0-9]*$/;\nexport const UID_REGEX = /^[A-Za-z0-9-_.~]*$/;\nexport const KEBAB_BASE_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n// Fully-qualified content-type uid: `api::a.a` / `plugin::p.p` / `strapi::x` / `admin::x`.\nexport const CONTENT_TYPE_UID_REGEX = /^((strapi|admin)::[\\w-]+|(api|plugin)::[\\w-]+\\.[\\w-]+)$/;\n\nexport type CommonTestConfig = TestConfig<unknown | undefined, Record<string, unknown>>;\n\nexport const isValidName: CommonTestConfig = {\n name: 'isValidName',\n message: `\\${path} must match the following regex: ${NAME_REGEX}`,\n test: (val: unknown) => val === '' || NAME_REGEX.test(val as string),\n};\n\nexport const isValidIcon: CommonTestConfig = {\n name: 'isValidIcon',\n message: `\\${path} is not a valid icon name. Make sure your icon name starts with an alphanumeric character and only includes alphanumeric characters or dashes.`,\n test: (val) => val === '' || ICON_REGEX.test(val as string),\n};\n\nexport const isValidUID: CommonTestConfig = {\n name: 'isValidUID',\n message: `\\${path} must match the following regex: ${UID_REGEX}`,\n test: (val) => val === '' || UID_REGEX.test(val as string),\n};\n\nexport const isValidCategoryName: CommonTestConfig = {\n name: 'isValidCategoryName',\n message: `\\${path} must start with a letter and only contain letters, numbers, dashes and underscores`,\n test: (val) => val === '' || CATEGORY_NAME_REGEX.test(val as string),\n};\n\nexport const isValidCollectionName: CommonTestConfig = {\n name: 'isValidCollectionName',\n message: `\\${path} must match the following regex: ${COLLECTION_NAME_REGEX}`,\n test: (val) => val === '' || COLLECTION_NAME_REGEX.test(val as string),\n};\n\nexport const isValidKey = (key: string): CommonTestConfig => ({\n name: 'isValidKey',\n message: `Attribute name '${key}' must match the following regex: ${NAME_REGEX}`,\n test: () => NAME_REGEX.test(key),\n});\n\nexport const isValidEnum: CommonTestConfig = {\n name: 'isValidEnum',\n message: '${path} should not start with number',\n test: (val) => val === '' || !strings.startsWithANumber(val as string),\n};\n\nexport const areEnumValuesUnique: CommonTestConfig = {\n name: 'areEnumValuesUnique',\n message: '${path} cannot contain duplicate values',\n test(values) {\n const filtered = [...new Set(values as string[])];\n\n return filtered.length === (values as string[]).length;\n },\n};\n\nexport const isValidRegExpPattern: CommonTestConfig = {\n name: 'isValidRegExpPattern',\n message: '${path} must be a valid RexExp pattern string',\n test: (val) => val === '' || !!new RegExp(val as string),\n};\n\nexport const isValidDefaultJSON: CommonTestConfig = {\n name: 'isValidDefaultJSON',\n message: '${path} is not a valid JSON',\n test(val) {\n if (val === undefined) {\n return true;\n }\n\n if (_.isNumber(val) || _.isNull(val) || _.isObject(val) || _.isArray(val)) {\n return true;\n }\n\n try {\n JSON.parse(val as string);\n\n return true;\n } catch {\n return false;\n }\n },\n};\n"],"names":["validators","required","yup","boolean","unique","minLength","number","integer","positive","maxLength","NAME_REGEX","COLLECTION_NAME_REGEX","CATEGORY_NAME_REGEX","ICON_REGEX","UID_REGEX","KEBAB_BASE_REGEX","CONTENT_TYPE_UID_REGEX","isValidName","name","message","test","val","isValidIcon","isValidCategoryName","isValidCollectionName","isValidKey","key","isValidEnum","strings","startsWithANumber","areEnumValuesUnique","values","filtered","Set","length","isValidRegExpPattern","RegExp","isValidDefaultJSON","undefined","_","isNumber","isNull","isObject","isArray","JSON","parse"],"mappings":";;;;;;;;;MAKaA,UAAAA,GAAa;AACxBC,IAAAA,QAAAA,EAAUC,UAAIC,OAAO,EAAA;AACrBC,IAAAA,MAAAA,EAAQF,UAAIC,OAAO,EAAA;AACnBE,IAAAA,SAAAA,EAAWH,SAAAA,CAAII,MAAM,EAAA,CAAGC,OAAO,GAAGC,QAAQ,EAAA;AAC1CC,IAAAA,SAAAA,EAAWP,SAAAA,CAAII,MAAM,EAAA,CAAGC,OAAO,GAAGC,QAAQ;AAC5C;AAEO,MAAME,aAAa;AACnB,MAAMC,wBAAwB;AAC9B,MAAMC,sBAAsB;AAC5B,MAAMC,aAAa;AACnB,MAAMC,YAAY;AAClB,MAAMC,mBAAmB;AAChC;AACO,MAAMC,yBAAyB;MAIzBC,WAAAA,GAAgC;IAC3CC,IAAAA,EAAM,aAAA;IACNC,OAAAA,EAAS,CAAC,yCAAyC,EAAET,UAAAA,CAAAA,CAAY;AACjEU,IAAAA,IAAAA,EAAM,CAACC,GAAAA,GAAiBA,GAAAA,KAAQ,EAAA,IAAMX,UAAAA,CAAWU,IAAI,CAACC,GAAAA;AACxD;MAEaC,WAAAA,GAAgC;IAC3CJ,IAAAA,EAAM,aAAA;IACNC,OAAAA,EAAS,CAAC,sJAAsJ,CAAC;AACjKC,IAAAA,IAAAA,EAAM,CAACC,GAAAA,GAAQA,GAAAA,KAAQ,EAAA,IAAMR,UAAAA,CAAWO,IAAI,CAACC,GAAAA;AAC/C;MAQaE,mBAAAA,GAAwC;IACnDL,IAAAA,EAAM,qBAAA;IACNC,OAAAA,EAAS,CAAC,2FAA2F,CAAC;AACtGC,IAAAA,IAAAA,EAAM,CAACC,GAAAA,GAAQA,GAAAA,KAAQ,EAAA,IAAMT,mBAAAA,CAAoBQ,IAAI,CAACC,GAAAA;AACxD;MAEaG,qBAAAA,GAA0C;IACrDN,IAAAA,EAAM,uBAAA;IACNC,OAAAA,EAAS,CAAC,yCAAyC,EAAER,qBAAAA,CAAAA,CAAuB;AAC5ES,IAAAA,IAAAA,EAAM,CAACC,GAAAA,GAAQA,GAAAA,KAAQ,EAAA,IAAMV,qBAAAA,CAAsBS,IAAI,CAACC,GAAAA;AAC1D;AAEO,MAAMI,UAAAA,GAAa,CAACC,GAAAA,IAAmC;QAC5DR,IAAAA,EAAM,YAAA;AACNC,QAAAA,OAAAA,EAAS,CAAC,gBAAgB,EAAEO,GAAAA,CAAI,kCAAkC,EAAEhB,UAAAA,CAAAA,CAAY;QAChFU,IAAAA,EAAM,IAAMV,UAAAA,CAAWU,IAAI,CAACM,GAAAA;AAC9B,KAAA;MAEaC,WAAAA,GAAgC;IAC3CT,IAAAA,EAAM,aAAA;IACNC,OAAAA,EAAS,sCAAA;AACTC,IAAAA,IAAAA,EAAM,CAACC,GAAAA,GAAQA,GAAAA,KAAQ,MAAM,CAACO,aAAAA,CAAQC,iBAAiB,CAACR,GAAAA;AAC1D;MAEaS,mBAAAA,GAAwC;IACnDZ,IAAAA,EAAM,qBAAA;IACNC,OAAAA,EAAS,yCAAA;AACTC,IAAAA,IAAAA,CAAAA,CAAKW,MAAM,EAAA;AACT,QAAA,MAAMC,QAAAA,GAAW;AAAI,YAAA,GAAA,IAAIC,GAAAA,CAAIF,MAAAA;AAAoB,SAAA;AAEjD,QAAA,OAAOC,QAAAA,CAASE,MAAM,KAAMH,OAAoBG,MAAM;AACxD,IAAA;AACF;MAEaC,oBAAAA,GAAyC;IACpDjB,IAAAA,EAAM,sBAAA;IACNC,OAAAA,EAAS,+CAAA;AACTC,IAAAA,IAAAA,EAAM,CAACC,GAAAA,GAAQA,GAAAA,KAAQ,MAAM,CAAC,CAAC,IAAIe,MAAAA,CAAOf,GAAAA;AAC5C;MAEagB,kBAAAA,GAAuC;IAClDnB,IAAAA,EAAM,oBAAA;IACNC,OAAAA,EAAS,6BAAA;AACTC,IAAAA,IAAAA,CAAAA,CAAKC,GAAG,EAAA;AACN,QAAA,IAAIA,QAAQiB,SAAAA,EAAW;YACrB,OAAO,IAAA;AACT,QAAA;AAEA,QAAA,IAAIC,kBAAAA,CAAEC,QAAQ,CAACnB,GAAAA,CAAAA,IAAQkB,mBAAEE,MAAM,CAACpB,GAAAA,CAAAA,IAAQkB,kBAAAA,CAAEG,QAAQ,CAACrB,GAAAA,CAAAA,IAAQkB,kBAAAA,CAAEI,OAAO,CAACtB,GAAAA,CAAAA,EAAM;YACzE,OAAO,IAAA;AACT,QAAA;QAEA,IAAI;AACFuB,YAAAA,IAAAA,CAAKC,KAAK,CAACxB,GAAAA,CAAAA;YAEX,OAAO,IAAA;AACT,QAAA,CAAA,CAAE,OAAM;YACN,OAAO,KAAA;AACT,QAAA;AACF,IAAA;AACF;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -13,6 +13,8 @@ const CATEGORY_NAME_REGEX = /^[A-Za-z][-_0-9A-Za-z]*$/;
|
|
|
13
13
|
const ICON_REGEX = /^[A-Za-z0-9][-A-Za-z0-9]*$/;
|
|
14
14
|
const UID_REGEX = /^[A-Za-z0-9-_.~]*$/;
|
|
15
15
|
const KEBAB_BASE_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
16
|
+
// Fully-qualified content-type uid: `api::a.a` / `plugin::p.p` / `strapi::x` / `admin::x`.
|
|
17
|
+
const CONTENT_TYPE_UID_REGEX = /^((strapi|admin)::[\w-]+|(api|plugin)::[\w-]+\.[\w-]+)$/;
|
|
16
18
|
const isValidName = {
|
|
17
19
|
name: 'isValidName',
|
|
18
20
|
message: `\${path} must match the following regex: ${NAME_REGEX}`,
|
|
@@ -77,5 +79,5 @@ const isValidDefaultJSON = {
|
|
|
77
79
|
}
|
|
78
80
|
};
|
|
79
81
|
|
|
80
|
-
export { CATEGORY_NAME_REGEX, COLLECTION_NAME_REGEX, ICON_REGEX, KEBAB_BASE_REGEX, NAME_REGEX, UID_REGEX, areEnumValuesUnique, isValidCategoryName, isValidCollectionName, isValidDefaultJSON, isValidEnum, isValidIcon, isValidKey, isValidName, isValidRegExpPattern, validators };
|
|
82
|
+
export { CATEGORY_NAME_REGEX, COLLECTION_NAME_REGEX, CONTENT_TYPE_UID_REGEX, ICON_REGEX, KEBAB_BASE_REGEX, NAME_REGEX, UID_REGEX, areEnumValuesUnique, isValidCategoryName, isValidCollectionName, isValidDefaultJSON, isValidEnum, isValidIcon, isValidKey, isValidName, isValidRegExpPattern, validators };
|
|
81
83
|
//# sourceMappingURL=common.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.mjs","sources":["../../../../server/src/controllers/validation/common.ts"],"sourcesContent":["/* eslint-disable no-template-curly-in-string */\nimport { yup, strings } from '@strapi/utils';\nimport _ from 'lodash';\nimport { TestConfig } from 'yup';\n\nexport const validators = {\n required: yup.boolean(),\n unique: yup.boolean(),\n minLength: yup.number().integer().positive(),\n maxLength: yup.number().integer().positive(),\n};\n\nexport const NAME_REGEX = /^[A-Za-z][_0-9A-Za-z]*$/;\nexport const COLLECTION_NAME_REGEX = /^[A-Za-z][-_0-9A-Za-z]*$/;\nexport const CATEGORY_NAME_REGEX = /^[A-Za-z][-_0-9A-Za-z]*$/;\nexport const ICON_REGEX = /^[A-Za-z0-9][-A-Za-z0-9]*$/;\nexport const UID_REGEX = /^[A-Za-z0-9-_.~]*$/;\nexport const KEBAB_BASE_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\nexport type CommonTestConfig = TestConfig<unknown | undefined, Record<string, unknown>>;\n\nexport const isValidName: CommonTestConfig = {\n name: 'isValidName',\n message: `\\${path} must match the following regex: ${NAME_REGEX}`,\n test: (val: unknown) => val === '' || NAME_REGEX.test(val as string),\n};\n\nexport const isValidIcon: CommonTestConfig = {\n name: 'isValidIcon',\n message: `\\${path} is not a valid icon name. Make sure your icon name starts with an alphanumeric character and only includes alphanumeric characters or dashes.`,\n test: (val) => val === '' || ICON_REGEX.test(val as string),\n};\n\nexport const isValidUID: CommonTestConfig = {\n name: 'isValidUID',\n message: `\\${path} must match the following regex: ${UID_REGEX}`,\n test: (val) => val === '' || UID_REGEX.test(val as string),\n};\n\nexport const isValidCategoryName: CommonTestConfig = {\n name: 'isValidCategoryName',\n message: `\\${path} must start with a letter and only contain letters, numbers, dashes and underscores`,\n test: (val) => val === '' || CATEGORY_NAME_REGEX.test(val as string),\n};\n\nexport const isValidCollectionName: CommonTestConfig = {\n name: 'isValidCollectionName',\n message: `\\${path} must match the following regex: ${COLLECTION_NAME_REGEX}`,\n test: (val) => val === '' || COLLECTION_NAME_REGEX.test(val as string),\n};\n\nexport const isValidKey = (key: string): CommonTestConfig => ({\n name: 'isValidKey',\n message: `Attribute name '${key}' must match the following regex: ${NAME_REGEX}`,\n test: () => NAME_REGEX.test(key),\n});\n\nexport const isValidEnum: CommonTestConfig = {\n name: 'isValidEnum',\n message: '${path} should not start with number',\n test: (val) => val === '' || !strings.startsWithANumber(val as string),\n};\n\nexport const areEnumValuesUnique: CommonTestConfig = {\n name: 'areEnumValuesUnique',\n message: '${path} cannot contain duplicate values',\n test(values) {\n const filtered = [...new Set(values as string[])];\n\n return filtered.length === (values as string[]).length;\n },\n};\n\nexport const isValidRegExpPattern: CommonTestConfig = {\n name: 'isValidRegExpPattern',\n message: '${path} must be a valid RexExp pattern string',\n test: (val) => val === '' || !!new RegExp(val as string),\n};\n\nexport const isValidDefaultJSON: CommonTestConfig = {\n name: 'isValidDefaultJSON',\n message: '${path} is not a valid JSON',\n test(val) {\n if (val === undefined) {\n return true;\n }\n\n if (_.isNumber(val) || _.isNull(val) || _.isObject(val) || _.isArray(val)) {\n return true;\n }\n\n try {\n JSON.parse(val as string);\n\n return true;\n } catch {\n return false;\n }\n },\n};\n"],"names":["validators","required","yup","boolean","unique","minLength","number","integer","positive","maxLength","NAME_REGEX","COLLECTION_NAME_REGEX","CATEGORY_NAME_REGEX","ICON_REGEX","UID_REGEX","KEBAB_BASE_REGEX","isValidName","name","message","test","val","isValidIcon","isValidCategoryName","isValidCollectionName","isValidKey","key","isValidEnum","strings","startsWithANumber","areEnumValuesUnique","values","filtered","Set","length","isValidRegExpPattern","RegExp","isValidDefaultJSON","undefined","_","isNumber","isNull","isObject","isArray","JSON","parse"],"mappings":";;;MAKaA,UAAAA,GAAa;AACxBC,IAAAA,QAAAA,EAAUC,IAAIC,OAAO,EAAA;AACrBC,IAAAA,MAAAA,EAAQF,IAAIC,OAAO,EAAA;AACnBE,IAAAA,SAAAA,EAAWH,GAAAA,CAAII,MAAM,EAAA,CAAGC,OAAO,GAAGC,QAAQ,EAAA;AAC1CC,IAAAA,SAAAA,EAAWP,GAAAA,CAAII,MAAM,EAAA,CAAGC,OAAO,GAAGC,QAAQ;AAC5C;AAEO,MAAME,aAAa;AACnB,MAAMC,wBAAwB;AAC9B,MAAMC,sBAAsB;AAC5B,MAAMC,aAAa;AACnB,MAAMC,YAAY;AAClB,MAAMC,mBAAmB;
|
|
1
|
+
{"version":3,"file":"common.mjs","sources":["../../../../server/src/controllers/validation/common.ts"],"sourcesContent":["/* eslint-disable no-template-curly-in-string */\nimport { yup, strings } from '@strapi/utils';\nimport _ from 'lodash';\nimport { TestConfig } from 'yup';\n\nexport const validators = {\n required: yup.boolean(),\n unique: yup.boolean(),\n minLength: yup.number().integer().positive(),\n maxLength: yup.number().integer().positive(),\n};\n\nexport const NAME_REGEX = /^[A-Za-z][_0-9A-Za-z]*$/;\nexport const COLLECTION_NAME_REGEX = /^[A-Za-z][-_0-9A-Za-z]*$/;\nexport const CATEGORY_NAME_REGEX = /^[A-Za-z][-_0-9A-Za-z]*$/;\nexport const ICON_REGEX = /^[A-Za-z0-9][-A-Za-z0-9]*$/;\nexport const UID_REGEX = /^[A-Za-z0-9-_.~]*$/;\nexport const KEBAB_BASE_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n// Fully-qualified content-type uid: `api::a.a` / `plugin::p.p` / `strapi::x` / `admin::x`.\nexport const CONTENT_TYPE_UID_REGEX = /^((strapi|admin)::[\\w-]+|(api|plugin)::[\\w-]+\\.[\\w-]+)$/;\n\nexport type CommonTestConfig = TestConfig<unknown | undefined, Record<string, unknown>>;\n\nexport const isValidName: CommonTestConfig = {\n name: 'isValidName',\n message: `\\${path} must match the following regex: ${NAME_REGEX}`,\n test: (val: unknown) => val === '' || NAME_REGEX.test(val as string),\n};\n\nexport const isValidIcon: CommonTestConfig = {\n name: 'isValidIcon',\n message: `\\${path} is not a valid icon name. Make sure your icon name starts with an alphanumeric character and only includes alphanumeric characters or dashes.`,\n test: (val) => val === '' || ICON_REGEX.test(val as string),\n};\n\nexport const isValidUID: CommonTestConfig = {\n name: 'isValidUID',\n message: `\\${path} must match the following regex: ${UID_REGEX}`,\n test: (val) => val === '' || UID_REGEX.test(val as string),\n};\n\nexport const isValidCategoryName: CommonTestConfig = {\n name: 'isValidCategoryName',\n message: `\\${path} must start with a letter and only contain letters, numbers, dashes and underscores`,\n test: (val) => val === '' || CATEGORY_NAME_REGEX.test(val as string),\n};\n\nexport const isValidCollectionName: CommonTestConfig = {\n name: 'isValidCollectionName',\n message: `\\${path} must match the following regex: ${COLLECTION_NAME_REGEX}`,\n test: (val) => val === '' || COLLECTION_NAME_REGEX.test(val as string),\n};\n\nexport const isValidKey = (key: string): CommonTestConfig => ({\n name: 'isValidKey',\n message: `Attribute name '${key}' must match the following regex: ${NAME_REGEX}`,\n test: () => NAME_REGEX.test(key),\n});\n\nexport const isValidEnum: CommonTestConfig = {\n name: 'isValidEnum',\n message: '${path} should not start with number',\n test: (val) => val === '' || !strings.startsWithANumber(val as string),\n};\n\nexport const areEnumValuesUnique: CommonTestConfig = {\n name: 'areEnumValuesUnique',\n message: '${path} cannot contain duplicate values',\n test(values) {\n const filtered = [...new Set(values as string[])];\n\n return filtered.length === (values as string[]).length;\n },\n};\n\nexport const isValidRegExpPattern: CommonTestConfig = {\n name: 'isValidRegExpPattern',\n message: '${path} must be a valid RexExp pattern string',\n test: (val) => val === '' || !!new RegExp(val as string),\n};\n\nexport const isValidDefaultJSON: CommonTestConfig = {\n name: 'isValidDefaultJSON',\n message: '${path} is not a valid JSON',\n test(val) {\n if (val === undefined) {\n return true;\n }\n\n if (_.isNumber(val) || _.isNull(val) || _.isObject(val) || _.isArray(val)) {\n return true;\n }\n\n try {\n JSON.parse(val as string);\n\n return true;\n } catch {\n return false;\n }\n },\n};\n"],"names":["validators","required","yup","boolean","unique","minLength","number","integer","positive","maxLength","NAME_REGEX","COLLECTION_NAME_REGEX","CATEGORY_NAME_REGEX","ICON_REGEX","UID_REGEX","KEBAB_BASE_REGEX","CONTENT_TYPE_UID_REGEX","isValidName","name","message","test","val","isValidIcon","isValidCategoryName","isValidCollectionName","isValidKey","key","isValidEnum","strings","startsWithANumber","areEnumValuesUnique","values","filtered","Set","length","isValidRegExpPattern","RegExp","isValidDefaultJSON","undefined","_","isNumber","isNull","isObject","isArray","JSON","parse"],"mappings":"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"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var zod = require('zod');
|
|
4
|
+
var common = require('./common.js');
|
|
5
|
+
|
|
6
|
+
// eslint-disable-next-line no-control-regex
|
|
7
|
+
const CONTROL_CHARS_REGEX = /[\x00-\x1F\x7F-\x9F]/;
|
|
8
|
+
// eslint-disable-next-line no-control-regex
|
|
9
|
+
const ANSI_ESCAPE_REGEX = /\x1B\[[0-9;]*[A-Za-z]/;
|
|
10
|
+
const GROUP_NAME_MAX_LENGTH = 255;
|
|
11
|
+
const groupIdSchema = zod.z.string().min(1, 'Group id must not be empty');
|
|
12
|
+
const groupNameSchema = zod.z.string().min(1, 'Group name must not be empty').max(GROUP_NAME_MAX_LENGTH, `Group name must be at most ${GROUP_NAME_MAX_LENGTH} characters`).refine((value)=>value.trim().length > 0, 'Group name must not be empty').refine((value)=>value === value.trim(), 'Group name must not have leading or trailing whitespace').refine((value)=>!CONTROL_CHARS_REGEX.test(value), 'Group name must not contain control characters').refine((value)=>!ANSI_ESCAPE_REGEX.test(value), 'Group name must not contain ANSI escape characters');
|
|
13
|
+
const contentStructureChildSchema = zod.z.discriminatedUnion('type', [
|
|
14
|
+
zod.z.object({
|
|
15
|
+
uid: zod.z.string().regex(common.CONTENT_TYPE_UID_REGEX, 'Invalid content type uid'),
|
|
16
|
+
type: zod.z.literal('contentType')
|
|
17
|
+
}),
|
|
18
|
+
zod.z.object({
|
|
19
|
+
type: zod.z.literal('group'),
|
|
20
|
+
id: groupIdSchema
|
|
21
|
+
})
|
|
22
|
+
]);
|
|
23
|
+
/** Zod schema for a group record */ const contentStructureGroupSchema = zod.z.object({
|
|
24
|
+
children: zod.z.array(contentStructureChildSchema),
|
|
25
|
+
parent: groupIdSchema.nullable(),
|
|
26
|
+
name: groupNameSchema,
|
|
27
|
+
id: groupIdSchema
|
|
28
|
+
});
|
|
29
|
+
const contentStructureSectionSchema = zod.z.object({
|
|
30
|
+
groups: zod.z.array(contentStructureGroupSchema)
|
|
31
|
+
});
|
|
32
|
+
const contentStructureFileObjectSchema = zod.z.object({
|
|
33
|
+
version: zod.z.literal(1),
|
|
34
|
+
sections: zod.z.object({
|
|
35
|
+
collectionTypes: contentStructureSectionSchema,
|
|
36
|
+
singleTypes: contentStructureSectionSchema
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
const MAX_FOLDER_DEPTH = 3;
|
|
40
|
+
/**
|
|
41
|
+
* File-wide group-id uniqueness across singleTypes and collectionTypes
|
|
42
|
+
*/ const uniqueGroupIdsAcrossFile = (file, ctx)=>{
|
|
43
|
+
const seen = new Set();
|
|
44
|
+
for (const section of [
|
|
45
|
+
file.sections.collectionTypes,
|
|
46
|
+
file.sections.singleTypes
|
|
47
|
+
]){
|
|
48
|
+
for (const group of section.groups){
|
|
49
|
+
if (seen.has(group.id)) {
|
|
50
|
+
ctx.addIssue({
|
|
51
|
+
message: `Duplicate group id "${group.id}"`,
|
|
52
|
+
code: zod.z.ZodIssueCode.custom,
|
|
53
|
+
path: [
|
|
54
|
+
'sections'
|
|
55
|
+
]
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
seen.add(group.id);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* File-internal graph resolution/validation.
|
|
64
|
+
* This performs all context-UNAWARE validation of the structure. Context-aware validation is performed at the CTB service layer.
|
|
65
|
+
*/ const validateSectionGraph = (groups, sectionKey, ctx)=>{
|
|
66
|
+
const path = [
|
|
67
|
+
'sections',
|
|
68
|
+
sectionKey,
|
|
69
|
+
'groups'
|
|
70
|
+
];
|
|
71
|
+
const byId = new Map(groups.map((group)=>[
|
|
72
|
+
group.id,
|
|
73
|
+
group
|
|
74
|
+
]));
|
|
75
|
+
const report = (message)=>{
|
|
76
|
+
ctx.addIssue({
|
|
77
|
+
code: zod.z.ZodIssueCode.custom,
|
|
78
|
+
path,
|
|
79
|
+
message
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
// Sibling group names must be unique within the same parent (case-insensitive).
|
|
83
|
+
const siblingNames = new Map();
|
|
84
|
+
for (const group of groups){
|
|
85
|
+
const name = group.name.trim().toLowerCase();
|
|
86
|
+
const seen = siblingNames.get(group.parent) ?? new Set();
|
|
87
|
+
if (seen.has(name)) {
|
|
88
|
+
const where = group.parent ? `group "${group.parent}"` : 'the section root';
|
|
89
|
+
report(`Sibling groups under ${where} in section "${sectionKey}" share the name "${group.name.trim()}"`);
|
|
90
|
+
}
|
|
91
|
+
seen.add(name);
|
|
92
|
+
siblingNames.set(group.parent, seen);
|
|
93
|
+
}
|
|
94
|
+
// Parent references a group in the SAME section.
|
|
95
|
+
// No cycles
|
|
96
|
+
// Depth <= 3
|
|
97
|
+
for (const group of groups){
|
|
98
|
+
if (group.parent !== null && !byId.has(group.parent)) {
|
|
99
|
+
report(`Group "${group.id}" references parent "${group.parent}" which is not a group in section "${sectionKey}"`);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const chain = new Set([
|
|
103
|
+
group.id
|
|
104
|
+
]);
|
|
105
|
+
let current = group;
|
|
106
|
+
let depth = 1;
|
|
107
|
+
let broken = false;
|
|
108
|
+
while(current && current.parent !== null){
|
|
109
|
+
if (chain.has(current.parent)) {
|
|
110
|
+
report(`Group "${group.id}" is part of a parent cycle`);
|
|
111
|
+
broken = true;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
const parent = byId.get(current.parent);
|
|
115
|
+
if (!parent) {
|
|
116
|
+
broken = true;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
chain.add(current.parent);
|
|
120
|
+
current = parent;
|
|
121
|
+
depth += 1;
|
|
122
|
+
}
|
|
123
|
+
if (!broken && depth > MAX_FOLDER_DEPTH) {
|
|
124
|
+
report(`Group "${group.id}" exceeds the maximum nesting depth of ${MAX_FOLDER_DEPTH} in section "${sectionKey}"`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Group children reference an existing group in the same section whose parent points back at the containing group.
|
|
128
|
+
// Also, each content type appears in at most ONE group.
|
|
129
|
+
const groupChildCount = new Map();
|
|
130
|
+
const seenUids = new Set();
|
|
131
|
+
for (const group of groups){
|
|
132
|
+
for (const child of group.children){
|
|
133
|
+
if (child.type === 'group') {
|
|
134
|
+
const target = byId.get(child.id);
|
|
135
|
+
if (!target) {
|
|
136
|
+
report(`Group "${group.id}" has a group child "${child.id}" that does not exist in section "${sectionKey}"`);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (target.parent !== group.id) {
|
|
140
|
+
report(`Group child "${child.id}" of "${group.id}" does not list "${group.id}" as its parent`);
|
|
141
|
+
}
|
|
142
|
+
groupChildCount.set(child.id, (groupChildCount.get(child.id) ?? 0) + 1);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (seenUids.has(child.uid)) {
|
|
146
|
+
report(`Content type "${child.uid}" appears in more than one group in section "${sectionKey}"`);
|
|
147
|
+
} else {
|
|
148
|
+
seenUids.add(child.uid);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Every non-root group should appear exactly once as a group child.
|
|
153
|
+
for (const group of groups){
|
|
154
|
+
const count = groupChildCount.get(group.id) ?? 0;
|
|
155
|
+
if (group.parent === null) {
|
|
156
|
+
if (count > 0) {
|
|
157
|
+
report(`Root group "${group.id}" is listed as a group child of another group in section "${sectionKey}"`);
|
|
158
|
+
}
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (count === 0) {
|
|
162
|
+
report(`Group "${group.id}" is not listed in the children of its parent "${group.parent}"`);
|
|
163
|
+
} else if (count > 1) {
|
|
164
|
+
report(`Group "${group.id}" is listed ${count} times as a group child in section "${sectionKey}"`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
const validateGraphRules = (file, ctx)=>{
|
|
169
|
+
validateSectionGraph(file.sections.collectionTypes.groups, 'collectionTypes', ctx);
|
|
170
|
+
validateSectionGraph(file.sections.singleTypes.groups, 'singleTypes', ctx);
|
|
171
|
+
};
|
|
172
|
+
const contentStructureFileSchema = contentStructureFileObjectSchema.superRefine(uniqueGroupIdsAcrossFile).superRefine(validateGraphRules);
|
|
173
|
+
|
|
174
|
+
exports.contentStructureChildSchema = contentStructureChildSchema;
|
|
175
|
+
exports.contentStructureFileSchema = contentStructureFileSchema;
|
|
176
|
+
exports.contentStructureGroupSchema = contentStructureGroupSchema;
|
|
177
|
+
//# sourceMappingURL=content-structure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-structure.js","sources":["../../../../server/src/controllers/validation/content-structure.ts"],"sourcesContent":["import { z } from 'zod';\n\nimport { CONTENT_TYPE_UID_REGEX } from './common';\n\n// eslint-disable-next-line no-control-regex\nconst CONTROL_CHARS_REGEX = /[\\x00-\\x1F\\x7F-\\x9F]/;\n// eslint-disable-next-line no-control-regex\nconst ANSI_ESCAPE_REGEX = /\\x1B\\[[0-9;]*[A-Za-z]/;\n\nconst GROUP_NAME_MAX_LENGTH = 255;\n\nconst groupIdSchema = z.string().min(1, 'Group id must not be empty');\n\nconst groupNameSchema = z\n .string()\n .min(1, 'Group name must not be empty')\n .max(GROUP_NAME_MAX_LENGTH, `Group name must be at most ${GROUP_NAME_MAX_LENGTH} characters`)\n .refine((value) => value.trim().length > 0, 'Group name must not be empty')\n .refine(\n (value) => value === value.trim(),\n 'Group name must not have leading or trailing whitespace'\n )\n .refine(\n (value) => !CONTROL_CHARS_REGEX.test(value),\n 'Group name must not contain control characters'\n )\n .refine(\n (value) => !ANSI_ESCAPE_REGEX.test(value),\n 'Group name must not contain ANSI escape characters'\n );\n\nexport const contentStructureChildSchema = z.discriminatedUnion('type', [\n z.object({\n uid: z.string().regex(CONTENT_TYPE_UID_REGEX, 'Invalid content type uid'),\n type: z.literal('contentType'),\n }),\n z.object({\n type: z.literal('group'),\n id: groupIdSchema,\n }),\n]);\n\n/** Zod schema for a group record */\nexport const contentStructureGroupSchema = z.object({\n children: z.array(contentStructureChildSchema),\n parent: groupIdSchema.nullable(),\n name: groupNameSchema,\n id: groupIdSchema,\n});\n\nconst contentStructureSectionSchema = z.object({\n groups: z.array(contentStructureGroupSchema),\n});\n\nconst contentStructureFileObjectSchema = z.object({\n version: z.literal(1),\n sections: z.object({\n collectionTypes: contentStructureSectionSchema,\n singleTypes: contentStructureSectionSchema,\n }),\n});\n\ntype ContentStructureFileObject = z.infer<typeof contentStructureFileObjectSchema>;\ntype ContentStructureGroupInput = z.infer<typeof contentStructureGroupSchema>;\ntype SuperRefinement<T> = (value: T, ctx: z.RefinementCtx) => void | Promise<void>;\n\nconst MAX_FOLDER_DEPTH = 3;\n\n/**\n * File-wide group-id uniqueness across singleTypes and collectionTypes\n */\nconst uniqueGroupIdsAcrossFile: SuperRefinement<ContentStructureFileObject> = (file, ctx) => {\n const seen = new Set<string>();\n\n for (const section of [file.sections.collectionTypes, file.sections.singleTypes]) {\n for (const group of section.groups) {\n if (seen.has(group.id)) {\n ctx.addIssue({\n message: `Duplicate group id \"${group.id}\"`,\n code: z.ZodIssueCode.custom,\n path: ['sections'],\n });\n }\n\n seen.add(group.id);\n }\n }\n};\n\n/**\n * File-internal graph resolution/validation.\n * This performs all context-UNAWARE validation of the structure. Context-aware validation is performed at the CTB service layer.\n */\nconst validateSectionGraph = (\n groups: ContentStructureGroupInput[],\n sectionKey: 'collectionTypes' | 'singleTypes',\n ctx: z.RefinementCtx\n) => {\n const path: (string | number)[] = ['sections', sectionKey, 'groups'];\n const byId = new Map(groups.map((group) => [group.id, group]));\n\n const report = (message: string) => {\n ctx.addIssue({ code: z.ZodIssueCode.custom, path, message });\n };\n\n // Sibling group names must be unique within the same parent (case-insensitive).\n const siblingNames = new Map<string | null, Set<string>>();\n\n for (const group of groups) {\n const name = group.name.trim().toLowerCase();\n const seen = siblingNames.get(group.parent) ?? new Set<string>();\n\n if (seen.has(name)) {\n const where = group.parent ? `group \"${group.parent}\"` : 'the section root';\n report(\n `Sibling groups under ${where} in section \"${sectionKey}\" share the name \"${group.name.trim()}\"`\n );\n }\n\n seen.add(name);\n siblingNames.set(group.parent, seen);\n }\n\n // Parent references a group in the SAME section.\n // No cycles\n // Depth <= 3\n for (const group of groups) {\n if (group.parent !== null && !byId.has(group.parent)) {\n report(\n `Group \"${group.id}\" references parent \"${group.parent}\" which is not a group in section \"${sectionKey}\"`\n );\n continue;\n }\n\n const chain = new Set<string>([group.id]);\n\n let current: ContentStructureGroupInput | undefined = group;\n let depth = 1;\n let broken = false;\n\n while (current && current.parent !== null) {\n if (chain.has(current.parent)) {\n report(`Group \"${group.id}\" is part of a parent cycle`);\n broken = true;\n break;\n }\n\n const parent = byId.get(current.parent);\n\n if (!parent) {\n broken = true;\n break;\n }\n\n chain.add(current.parent);\n current = parent;\n depth += 1;\n }\n\n if (!broken && depth > MAX_FOLDER_DEPTH) {\n report(\n `Group \"${group.id}\" exceeds the maximum nesting depth of ${MAX_FOLDER_DEPTH} in section \"${sectionKey}\"`\n );\n }\n }\n\n // Group children reference an existing group in the same section whose parent points back at the containing group.\n // Also, each content type appears in at most ONE group.\n const groupChildCount = new Map<string, number>();\n const seenUids = new Set<string>();\n\n for (const group of groups) {\n for (const child of group.children) {\n if (child.type === 'group') {\n const target = byId.get(child.id);\n\n if (!target) {\n report(\n `Group \"${group.id}\" has a group child \"${child.id}\" that does not exist in section \"${sectionKey}\"`\n );\n continue;\n }\n\n if (target.parent !== group.id) {\n report(\n `Group child \"${child.id}\" of \"${group.id}\" does not list \"${group.id}\" as its parent`\n );\n }\n\n groupChildCount.set(child.id, (groupChildCount.get(child.id) ?? 0) + 1);\n continue;\n }\n\n if (seenUids.has(child.uid)) {\n report(\n `Content type \"${child.uid}\" appears in more than one group in section \"${sectionKey}\"`\n );\n } else {\n seenUids.add(child.uid);\n }\n }\n }\n\n // Every non-root group should appear exactly once as a group child.\n for (const group of groups) {\n const count = groupChildCount.get(group.id) ?? 0;\n\n if (group.parent === null) {\n if (count > 0) {\n report(\n `Root group \"${group.id}\" is listed as a group child of another group in section \"${sectionKey}\"`\n );\n }\n continue;\n }\n\n if (count === 0) {\n report(`Group \"${group.id}\" is not listed in the children of its parent \"${group.parent}\"`);\n } else if (count > 1) {\n report(\n `Group \"${group.id}\" is listed ${count} times as a group child in section \"${sectionKey}\"`\n );\n }\n }\n};\n\nconst validateGraphRules: SuperRefinement<ContentStructureFileObject> = (file, ctx) => {\n validateSectionGraph(file.sections.collectionTypes.groups, 'collectionTypes', ctx);\n validateSectionGraph(file.sections.singleTypes.groups, 'singleTypes', ctx);\n};\n\nexport const contentStructureFileSchema = contentStructureFileObjectSchema\n .superRefine(uniqueGroupIdsAcrossFile)\n .superRefine(validateGraphRules);\n\nexport type ContentStructureFileInput = z.infer<typeof contentStructureFileSchema>;\n"],"names":["CONTROL_CHARS_REGEX","ANSI_ESCAPE_REGEX","GROUP_NAME_MAX_LENGTH","groupIdSchema","z","string","min","groupNameSchema","max","refine","value","trim","length","test","contentStructureChildSchema","discriminatedUnion","object","uid","regex","CONTENT_TYPE_UID_REGEX","type","literal","id","contentStructureGroupSchema","children","array","parent","nullable","name","contentStructureSectionSchema","groups","contentStructureFileObjectSchema","version","sections","collectionTypes","singleTypes","MAX_FOLDER_DEPTH","uniqueGroupIdsAcrossFile","file","ctx","seen","Set","section","group","has","addIssue","message","code","ZodIssueCode","custom","path","add","validateSectionGraph","sectionKey","byId","Map","map","report","siblingNames","toLowerCase","get","where","set","chain","current","depth","broken","groupChildCount","seenUids","child","target","count","validateGraphRules","contentStructureFileSchema","superRefine"],"mappings":"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"}
|