@firecms/collection_editor 3.0.1 → 3.1.0-canary.02232f4
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/ConfigControllerProvider.d.ts +6 -0
- package/dist/api/generateCollectionApi.d.ts +71 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.es.js +15260 -8173
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +15257 -8170
- package/dist/index.umd.js.map +1 -1
- package/dist/locales/de.d.ts +120 -0
- package/dist/locales/en.d.ts +120 -0
- package/dist/locales/es.d.ts +120 -0
- package/dist/locales/fr.d.ts +120 -0
- package/dist/locales/hi.d.ts +120 -0
- package/dist/locales/it.d.ts +120 -0
- package/dist/locales/pt.d.ts +120 -0
- package/dist/types/collection_editor_controller.d.ts +14 -0
- package/dist/types/collection_inference.d.ts +8 -2
- package/dist/types/config_controller.d.ts +23 -2
- package/dist/ui/AddKanbanColumnAction.d.ts +11 -0
- package/dist/ui/KanbanSetupAction.d.ts +10 -0
- package/dist/ui/collection_editor/AICollectionGeneratorPopover.d.ts +37 -0
- package/dist/ui/collection_editor/AIModifiedPathsContext.d.ts +20 -0
- package/dist/ui/collection_editor/CollectionDetailsForm.d.ts +2 -3
- package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +24 -0
- package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +4 -1
- package/dist/ui/collection_editor/CollectionJsonImportDialog.d.ts +7 -0
- package/dist/ui/collection_editor/CollectionYupValidation.d.ts +9 -13
- package/dist/ui/collection_editor/DisplaySettingsForm.d.ts +3 -0
- package/dist/ui/collection_editor/EntityActionsEditTab.d.ts +2 -1
- package/dist/ui/collection_editor/ExtendSettingsForm.d.ts +14 -0
- package/dist/ui/collection_editor/GeneralSettingsForm.d.ts +7 -0
- package/dist/ui/collection_editor/KanbanConfigSection.d.ts +4 -0
- package/dist/ui/collection_editor/PropertyEditView.d.ts +6 -1
- package/dist/ui/collection_editor/PropertyTree.d.ts +2 -1
- package/dist/ui/collection_editor/SubcollectionsEditTab.d.ts +2 -1
- package/dist/ui/collection_editor/ViewModeSwitch.d.ts +6 -0
- package/dist/ui/collection_editor/properties/EnumPropertyField.d.ts +2 -1
- package/dist/ui/collection_editor/properties/conditions/ConditionsEditor.d.ts +10 -0
- package/dist/ui/collection_editor/properties/conditions/ConditionsPanel.d.ts +2 -0
- package/dist/ui/collection_editor/properties/conditions/EnumConditionsEditor.d.ts +6 -0
- package/dist/ui/collection_editor/properties/conditions/index.d.ts +6 -0
- package/dist/ui/collection_editor/properties/conditions/property_paths.d.ts +19 -0
- package/dist/useCollectionEditorPlugin.d.ts +7 -1
- package/dist/utils/validateCollectionJson.d.ts +22 -0
- package/package.json +15 -15
- package/src/ConfigControllerProvider.tsx +82 -47
- package/src/api/generateCollectionApi.ts +119 -0
- package/src/api/index.ts +1 -0
- package/src/index.ts +28 -1
- package/src/locales/de.ts +125 -0
- package/src/locales/en.ts +145 -0
- package/src/locales/es.ts +125 -0
- package/src/locales/fr.ts +125 -0
- package/src/locales/hi.ts +125 -0
- package/src/locales/it.ts +125 -0
- package/src/locales/pt.ts +125 -0
- package/src/types/collection_editor_controller.tsx +16 -3
- package/src/types/collection_inference.ts +15 -2
- package/src/types/config_controller.tsx +27 -2
- package/src/ui/AddKanbanColumnAction.tsx +203 -0
- package/src/ui/EditorCollectionAction.tsx +3 -3
- package/src/ui/EditorCollectionActionStart.tsx +1 -2
- package/src/ui/EditorEntityAction.tsx +3 -2
- package/src/ui/HomePageEditorCollectionAction.tsx +41 -13
- package/src/ui/KanbanSetupAction.tsx +38 -0
- package/src/ui/MissingReferenceWidget.tsx +1 -1
- package/src/ui/NewCollectionButton.tsx +4 -2
- package/src/ui/NewCollectionCard.tsx +7 -4
- package/src/ui/PropertyAddColumnComponent.tsx +4 -3
- package/src/ui/collection_editor/AICollectionGeneratorPopover.tsx +243 -0
- package/src/ui/collection_editor/AIModifiedPathsContext.tsx +88 -0
- package/src/ui/collection_editor/CollectionDetailsForm.tsx +222 -267
- package/src/ui/collection_editor/CollectionEditorDialog.tsx +270 -198
- package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +138 -71
- package/src/ui/collection_editor/CollectionJsonImportDialog.tsx +171 -0
- package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +202 -101
- package/src/ui/collection_editor/DisplaySettingsForm.tsx +335 -0
- package/src/ui/collection_editor/EntityActionsEditTab.tsx +106 -97
- package/src/ui/collection_editor/EntityActionsSelectDialog.tsx +8 -10
- package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +5 -7
- package/src/ui/collection_editor/EnumForm.tsx +153 -102
- package/src/ui/collection_editor/ExtendSettingsForm.tsx +94 -0
- package/src/ui/collection_editor/GeneralSettingsForm.tsx +335 -0
- package/src/ui/collection_editor/GetCodeDialog.tsx +63 -41
- package/src/ui/collection_editor/KanbanConfigSection.tsx +209 -0
- package/src/ui/collection_editor/LayoutModeSwitch.tsx +27 -43
- package/src/ui/collection_editor/PropertyEditView.tsx +272 -199
- package/src/ui/collection_editor/PropertyFieldPreview.tsx +1 -1
- package/src/ui/collection_editor/PropertyTree.tsx +130 -58
- package/src/ui/collection_editor/SubcollectionsEditTab.tsx +169 -163
- package/src/ui/collection_editor/UnsavedChangesDialog.tsx +0 -2
- package/src/ui/collection_editor/ViewModeSwitch.tsx +43 -0
- package/src/ui/collection_editor/import/CollectionEditorImportDataPreview.tsx +6 -3
- package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +5 -2
- package/src/ui/collection_editor/properties/BlockPropertyField.tsx +0 -2
- package/src/ui/collection_editor/properties/BooleanPropertyField.tsx +4 -1
- package/src/ui/collection_editor/properties/CommonPropertyFields.tsx +6 -4
- package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +126 -42
- package/src/ui/collection_editor/properties/EnumPropertyField.tsx +32 -24
- package/src/ui/collection_editor/properties/MapPropertyField.tsx +8 -9
- package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +128 -53
- package/src/ui/collection_editor/properties/NumberPropertyField.tsx +3 -1
- package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +5 -4
- package/src/ui/collection_editor/properties/StoragePropertyField.tsx +47 -52
- package/src/ui/collection_editor/properties/StringPropertyField.tsx +3 -1
- package/src/ui/collection_editor/properties/UrlPropertyField.tsx +12 -10
- package/src/ui/collection_editor/properties/advanced/AdvancedPropertyValidation.tsx +23 -4
- package/src/ui/collection_editor/properties/conditions/ConditionsEditor.tsx +866 -0
- package/src/ui/collection_editor/properties/conditions/ConditionsPanel.tsx +28 -0
- package/src/ui/collection_editor/properties/conditions/EnumConditionsEditor.tsx +599 -0
- package/src/ui/collection_editor/properties/conditions/index.ts +6 -0
- package/src/ui/collection_editor/properties/conditions/property_paths.ts +92 -0
- package/src/ui/collection_editor/properties/validation/ArrayPropertyValidation.tsx +5 -2
- package/src/ui/collection_editor/properties/validation/GeneralPropertyValidation.tsx +7 -5
- package/src/ui/collection_editor/properties/validation/NumberPropertyValidation.tsx +10 -7
- package/src/ui/collection_editor/properties/validation/StringPropertyValidation.tsx +11 -9
- package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +5 -2
- package/src/useCollectionEditorPlugin.tsx +53 -22
- package/src/utils/validateCollectionJson.ts +380 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import { EntityCollection } from "@firecms/core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Valid dataType values for properties
|
|
5
|
+
*/
|
|
6
|
+
const VALID_DATA_TYPES = [
|
|
7
|
+
"string",
|
|
8
|
+
"number",
|
|
9
|
+
"boolean",
|
|
10
|
+
"date",
|
|
11
|
+
"geopoint",
|
|
12
|
+
"reference",
|
|
13
|
+
"array",
|
|
14
|
+
"map"
|
|
15
|
+
] as const;
|
|
16
|
+
|
|
17
|
+
type DataType = typeof VALID_DATA_TYPES[number];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validation error with path and message
|
|
21
|
+
*/
|
|
22
|
+
export interface CollectionValidationError {
|
|
23
|
+
path: string;
|
|
24
|
+
message: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Result of collection JSON validation
|
|
29
|
+
*/
|
|
30
|
+
export interface CollectionValidationResult {
|
|
31
|
+
valid: boolean;
|
|
32
|
+
errors: CollectionValidationError[];
|
|
33
|
+
collection?: EntityCollection;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Validates a property object recursively
|
|
38
|
+
*/
|
|
39
|
+
function validateProperty(
|
|
40
|
+
property: any,
|
|
41
|
+
path: string,
|
|
42
|
+
errors: CollectionValidationError[]
|
|
43
|
+
): void {
|
|
44
|
+
if (typeof property !== "object" || property === null) {
|
|
45
|
+
errors.push({
|
|
46
|
+
path,
|
|
47
|
+
message: "Property must be an object"
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check dataType
|
|
53
|
+
if (!property.dataType) {
|
|
54
|
+
errors.push({
|
|
55
|
+
path: `${path}.dataType`,
|
|
56
|
+
message: "Required field is missing"
|
|
57
|
+
});
|
|
58
|
+
} else if (!VALID_DATA_TYPES.includes(property.dataType)) {
|
|
59
|
+
errors.push({
|
|
60
|
+
path: `${path}.dataType`,
|
|
61
|
+
message: `Invalid value "${property.dataType}", expected one of: ${VALID_DATA_TYPES.join(", ")}`
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Validate name if present
|
|
66
|
+
if (property.name !== undefined && typeof property.name !== "string") {
|
|
67
|
+
errors.push({
|
|
68
|
+
path: `${path}.name`,
|
|
69
|
+
message: "Must be a string"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Validate array "of" property
|
|
74
|
+
if (property.dataType === "array") {
|
|
75
|
+
if (property.of) {
|
|
76
|
+
if (Array.isArray(property.of)) {
|
|
77
|
+
property.of.forEach((ofProp: any, index: number) => {
|
|
78
|
+
validateProperty(ofProp, `${path}.of[${index}]`, errors);
|
|
79
|
+
});
|
|
80
|
+
} else {
|
|
81
|
+
validateProperty(property.of, `${path}.of`, errors);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// oneOf validation
|
|
85
|
+
if (property.oneOf) {
|
|
86
|
+
if (typeof property.oneOf !== "object") {
|
|
87
|
+
errors.push({
|
|
88
|
+
path: `${path}.oneOf`,
|
|
89
|
+
message: "Must be an object"
|
|
90
|
+
});
|
|
91
|
+
} else if (property.oneOf.properties) {
|
|
92
|
+
validateProperties(property.oneOf.properties, `${path}.oneOf.properties`, errors);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Validate map properties
|
|
98
|
+
if (property.dataType === "map" && property.properties) {
|
|
99
|
+
validateProperties(property.properties, `${path}.properties`, errors);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Validate reference path
|
|
103
|
+
if (property.dataType === "reference") {
|
|
104
|
+
if (property.path !== undefined && typeof property.path !== "string") {
|
|
105
|
+
errors.push({
|
|
106
|
+
path: `${path}.path`,
|
|
107
|
+
message: "Must be a string"
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Validate storage config for string
|
|
113
|
+
if (property.dataType === "string" && property.storage) {
|
|
114
|
+
if (typeof property.storage !== "object") {
|
|
115
|
+
errors.push({
|
|
116
|
+
path: `${path}.storage`,
|
|
117
|
+
message: "Must be an object"
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Validate enumValues if present
|
|
123
|
+
if (property.enumValues !== undefined) {
|
|
124
|
+
if (!Array.isArray(property.enumValues) && typeof property.enumValues !== "object") {
|
|
125
|
+
errors.push({
|
|
126
|
+
path: `${path}.enumValues`,
|
|
127
|
+
message: "Must be an array or object"
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Validates a properties object (collection of property definitions)
|
|
135
|
+
*/
|
|
136
|
+
function validateProperties(
|
|
137
|
+
properties: any,
|
|
138
|
+
path: string,
|
|
139
|
+
errors: CollectionValidationError[]
|
|
140
|
+
): void {
|
|
141
|
+
if (typeof properties !== "object" || properties === null) {
|
|
142
|
+
errors.push({
|
|
143
|
+
path,
|
|
144
|
+
message: "Must be an object"
|
|
145
|
+
});
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
for (const [key, property] of Object.entries(properties)) {
|
|
150
|
+
validateProperty(property, `${path}.${key}`, errors);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Validates optional collection fields
|
|
156
|
+
*/
|
|
157
|
+
function validateOptionalFields(
|
|
158
|
+
collection: any,
|
|
159
|
+
errors: CollectionValidationError[]
|
|
160
|
+
): void {
|
|
161
|
+
// String fields
|
|
162
|
+
const stringFields = [
|
|
163
|
+
"singularName",
|
|
164
|
+
"description",
|
|
165
|
+
"group",
|
|
166
|
+
"databaseId"
|
|
167
|
+
];
|
|
168
|
+
for (const field of stringFields) {
|
|
169
|
+
if (collection[field] !== undefined && typeof collection[field] !== "string") {
|
|
170
|
+
errors.push({
|
|
171
|
+
path: field,
|
|
172
|
+
message: "Must be a string"
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Boolean fields
|
|
178
|
+
const booleanFields = [
|
|
179
|
+
"collectionGroup",
|
|
180
|
+
"textSearchEnabled",
|
|
181
|
+
"selectionEnabled",
|
|
182
|
+
"inlineEditing",
|
|
183
|
+
"hideFromNavigation",
|
|
184
|
+
"hideIdFromForm",
|
|
185
|
+
"hideIdFromCollection",
|
|
186
|
+
"formAutoSave",
|
|
187
|
+
"editable",
|
|
188
|
+
"alwaysApplyDefaultValues",
|
|
189
|
+
"includeJsonView",
|
|
190
|
+
"history"
|
|
191
|
+
];
|
|
192
|
+
for (const field of booleanFields) {
|
|
193
|
+
if (collection[field] !== undefined && typeof collection[field] !== "boolean") {
|
|
194
|
+
errors.push({
|
|
195
|
+
path: field,
|
|
196
|
+
message: "Must be a boolean"
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Icon can be string or object (React node)
|
|
202
|
+
if (collection.icon !== undefined &&
|
|
203
|
+
typeof collection.icon !== "string" &&
|
|
204
|
+
typeof collection.icon !== "object") {
|
|
205
|
+
errors.push({
|
|
206
|
+
path: "icon",
|
|
207
|
+
message: "Must be a string (icon key) or object"
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// propertiesOrder must be array of strings
|
|
212
|
+
if (collection.propertiesOrder !== undefined) {
|
|
213
|
+
if (!Array.isArray(collection.propertiesOrder)) {
|
|
214
|
+
errors.push({
|
|
215
|
+
path: "propertiesOrder",
|
|
216
|
+
message: "Must be an array of strings"
|
|
217
|
+
});
|
|
218
|
+
} else if (!collection.propertiesOrder.every((item: any) => typeof item === "string")) {
|
|
219
|
+
errors.push({
|
|
220
|
+
path: "propertiesOrder",
|
|
221
|
+
message: "All items must be strings"
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// subcollections must be array
|
|
227
|
+
if (collection.subcollections !== undefined) {
|
|
228
|
+
if (!Array.isArray(collection.subcollections)) {
|
|
229
|
+
errors.push({
|
|
230
|
+
path: "subcollections",
|
|
231
|
+
message: "Must be an array"
|
|
232
|
+
});
|
|
233
|
+
} else {
|
|
234
|
+
collection.subcollections.forEach((sub: any, index: number) => {
|
|
235
|
+
const subErrors: CollectionValidationError[] = [];
|
|
236
|
+
validateCollectionObject(sub, subErrors);
|
|
237
|
+
subErrors.forEach(err => {
|
|
238
|
+
errors.push({
|
|
239
|
+
path: `subcollections[${index}].${err.path}`,
|
|
240
|
+
message: err.message
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// defaultViewMode validation
|
|
248
|
+
const validViewModes = ["table", "cards", "kanban"];
|
|
249
|
+
if (collection.defaultViewMode !== undefined) {
|
|
250
|
+
if (!validViewModes.includes(collection.defaultViewMode)) {
|
|
251
|
+
errors.push({
|
|
252
|
+
path: "defaultViewMode",
|
|
253
|
+
message: `Invalid value, expected one of: ${validViewModes.join(", ")}`
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// kanban config validation
|
|
259
|
+
if (collection.kanban !== undefined) {
|
|
260
|
+
if (typeof collection.kanban !== "object" || collection.kanban === null) {
|
|
261
|
+
errors.push({
|
|
262
|
+
path: "kanban",
|
|
263
|
+
message: "Must be an object"
|
|
264
|
+
});
|
|
265
|
+
} else if (collection.kanban.columnProperty !== undefined &&
|
|
266
|
+
typeof collection.kanban.columnProperty !== "string") {
|
|
267
|
+
errors.push({
|
|
268
|
+
path: "kanban.columnProperty",
|
|
269
|
+
message: "Must be a string"
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Validates a collection object
|
|
277
|
+
*/
|
|
278
|
+
function validateCollectionObject(
|
|
279
|
+
collection: any,
|
|
280
|
+
errors: CollectionValidationError[]
|
|
281
|
+
): void {
|
|
282
|
+
// Required fields
|
|
283
|
+
if (!collection.id) {
|
|
284
|
+
errors.push({
|
|
285
|
+
path: "id",
|
|
286
|
+
message: "Required field is missing"
|
|
287
|
+
});
|
|
288
|
+
} else if (typeof collection.id !== "string") {
|
|
289
|
+
errors.push({
|
|
290
|
+
path: "id",
|
|
291
|
+
message: "Must be a string"
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (!collection.name) {
|
|
296
|
+
errors.push({
|
|
297
|
+
path: "name",
|
|
298
|
+
message: "Required field is missing"
|
|
299
|
+
});
|
|
300
|
+
} else if (typeof collection.name !== "string") {
|
|
301
|
+
errors.push({
|
|
302
|
+
path: "name",
|
|
303
|
+
message: "Must be a string"
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (!collection.path) {
|
|
308
|
+
errors.push({
|
|
309
|
+
path: "path",
|
|
310
|
+
message: "Required field is missing"
|
|
311
|
+
});
|
|
312
|
+
} else if (typeof collection.path !== "string") {
|
|
313
|
+
errors.push({
|
|
314
|
+
path: "path",
|
|
315
|
+
message: "Must be a string"
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Properties validation
|
|
320
|
+
if (collection.properties !== undefined) {
|
|
321
|
+
validateProperties(collection.properties, "properties", errors);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Optional fields
|
|
325
|
+
validateOptionalFields(collection, errors);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Validates a JSON string representing a collection configuration.
|
|
330
|
+
* Returns detailed validation errors if the JSON is invalid or doesn't match
|
|
331
|
+
* the expected collection schema.
|
|
332
|
+
*/
|
|
333
|
+
export function validateCollectionJson(jsonString: string): CollectionValidationResult {
|
|
334
|
+
const errors: CollectionValidationError[] = [];
|
|
335
|
+
|
|
336
|
+
// Try to parse JSON
|
|
337
|
+
let parsed: any;
|
|
338
|
+
try {
|
|
339
|
+
parsed = JSON.parse(jsonString);
|
|
340
|
+
} catch (e: any) {
|
|
341
|
+
// Try to extract line/column info from the error
|
|
342
|
+
const match = e.message.match(/position (\d+)/);
|
|
343
|
+
let message = "Invalid JSON syntax";
|
|
344
|
+
if (match) {
|
|
345
|
+
const position = parseInt(match[1], 10);
|
|
346
|
+
const lines = jsonString.substring(0, position).split("\n");
|
|
347
|
+
const line = lines.length;
|
|
348
|
+
const column = lines[lines.length - 1].length + 1;
|
|
349
|
+
message = `Invalid JSON syntax at line ${line}, column ${column}: ${e.message}`;
|
|
350
|
+
} else {
|
|
351
|
+
message = `Invalid JSON syntax: ${e.message}`;
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
valid: false,
|
|
355
|
+
errors: [{
|
|
356
|
+
path: "",
|
|
357
|
+
message
|
|
358
|
+
}]
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Validate collection structure
|
|
363
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
364
|
+
return {
|
|
365
|
+
valid: false,
|
|
366
|
+
errors: [{
|
|
367
|
+
path: "",
|
|
368
|
+
message: "Collection must be an object"
|
|
369
|
+
}]
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
validateCollectionObject(parsed, errors);
|
|
374
|
+
|
|
375
|
+
return {
|
|
376
|
+
valid: errors.length === 0,
|
|
377
|
+
errors,
|
|
378
|
+
collection: errors.length === 0 ? parsed as EntityCollection : undefined
|
|
379
|
+
};
|
|
380
|
+
}
|