@boltic/cli 1.0.6 → 1.0.7
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/helper/validation.js +70 -22
- package/package.json +1 -1
- package/templates/component-schemas.js +17 -1
package/helper/validation.js
CHANGED
|
@@ -142,14 +142,17 @@ const validateSchemaKeys = (
|
|
|
142
142
|
schemaName,
|
|
143
143
|
displayType,
|
|
144
144
|
errors,
|
|
145
|
-
prefix = ""
|
|
145
|
+
prefix = "",
|
|
146
|
+
filename = ""
|
|
146
147
|
) => {
|
|
148
|
+
const fileLabel = filename ? ` in "${filename}"` : "";
|
|
149
|
+
|
|
147
150
|
Object.keys(schemaObj).forEach((key) => {
|
|
148
151
|
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
149
152
|
|
|
150
153
|
if (!allowedKeys.has(fullKey)) {
|
|
151
154
|
errors.add(
|
|
152
|
-
`"${schemaName}" has an invalid key "${fullKey}" for displayType "${displayType}".`
|
|
155
|
+
`"${schemaName}" has an invalid key "${fullKey}" for displayType "${displayType}"${fileLabel}.`
|
|
153
156
|
);
|
|
154
157
|
}
|
|
155
158
|
|
|
@@ -164,7 +167,8 @@ const validateSchemaKeys = (
|
|
|
164
167
|
schemaName,
|
|
165
168
|
displayType,
|
|
166
169
|
errors,
|
|
167
|
-
fullKey
|
|
170
|
+
fullKey,
|
|
171
|
+
filename
|
|
168
172
|
);
|
|
169
173
|
}
|
|
170
174
|
});
|
|
@@ -175,21 +179,29 @@ const validateSchemaKeys = (
|
|
|
175
179
|
* @param {Object} schema - The schema to validate
|
|
176
180
|
* @param {string} displayType - The display type to validate against
|
|
177
181
|
* @param {Set} errors - Error collection
|
|
182
|
+
* @param {string} filename - The filename for error messages
|
|
178
183
|
*/
|
|
179
|
-
const validateComponentByType = (
|
|
184
|
+
const validateComponentByType = (
|
|
185
|
+
schema,
|
|
186
|
+
displayType,
|
|
187
|
+
errors,
|
|
188
|
+
filename = ""
|
|
189
|
+
) => {
|
|
190
|
+
const fileLabel = filename ? ` in "${filename}"` : "";
|
|
191
|
+
|
|
180
192
|
// Get the component schema definition for this display type
|
|
181
193
|
const componentSchema = componentSchemas[displayType];
|
|
182
194
|
|
|
183
195
|
if (!componentSchema) {
|
|
184
196
|
errors.add(
|
|
185
|
-
`"${schema.name}" has an unsupported displayType "${displayType}".`
|
|
197
|
+
`"${schema.name}" has an unsupported displayType "${displayType}"${fileLabel}.`
|
|
186
198
|
);
|
|
187
199
|
return;
|
|
188
200
|
}
|
|
189
201
|
|
|
190
202
|
if (!componentSchema.meta) {
|
|
191
203
|
errors.add(
|
|
192
|
-
`Component schema for "${displayType}" is missing meta definition.`
|
|
204
|
+
`Component schema for "${displayType}" is missing meta definition${fileLabel}.`
|
|
193
205
|
);
|
|
194
206
|
return;
|
|
195
207
|
}
|
|
@@ -204,29 +216,39 @@ const validateComponentByType = (schema, displayType, errors) => {
|
|
|
204
216
|
allowedKeys,
|
|
205
217
|
schema.name,
|
|
206
218
|
currentDisplayType,
|
|
207
|
-
errors
|
|
219
|
+
errors,
|
|
220
|
+
"",
|
|
221
|
+
filename
|
|
208
222
|
);
|
|
209
223
|
};
|
|
210
224
|
|
|
211
|
-
const validateComponentSchemas = (schemas, errors) => {
|
|
225
|
+
const validateComponentSchemas = (schemas, errors, filename = "") => {
|
|
226
|
+
const fileLabel = filename ? ` in "${filename}"` : "";
|
|
227
|
+
|
|
212
228
|
schemas.forEach((schema) => {
|
|
213
229
|
// Basic required field validation
|
|
214
230
|
if (!schema.name) {
|
|
215
|
-
errors.add(`Schema is missing a name.`);
|
|
231
|
+
errors.add(`Schema is missing a name${fileLabel}.`);
|
|
216
232
|
return; // Can't continue without a name
|
|
217
233
|
}
|
|
218
234
|
if (!schema.meta) {
|
|
219
|
-
errors.add(
|
|
235
|
+
errors.add(
|
|
236
|
+
`"${schema.name}" is missing a meta object${fileLabel}.`
|
|
237
|
+
);
|
|
220
238
|
return; // Can't continue without meta
|
|
221
239
|
}
|
|
222
240
|
if (!schema.meta.displayType) {
|
|
223
|
-
errors.add(
|
|
241
|
+
errors.add(
|
|
242
|
+
`"${schema.name}" is missing a displayType${fileLabel}.`
|
|
243
|
+
);
|
|
224
244
|
return; // Can't continue without displayType
|
|
225
245
|
}
|
|
226
246
|
|
|
227
247
|
// Optional field validation (these are warnings, not blocking)
|
|
228
248
|
if (!schema.meta.displayName) {
|
|
229
|
-
errors.add(
|
|
249
|
+
errors.add(
|
|
250
|
+
`"${schema.name}" is missing a displayName${fileLabel}.`
|
|
251
|
+
);
|
|
230
252
|
}
|
|
231
253
|
|
|
232
254
|
// Only require placeholder if the component schema defines it
|
|
@@ -237,7 +259,9 @@ const validateComponentSchemas = (schemas, errors) => {
|
|
|
237
259
|
"placeholder" in componentSchema.meta &&
|
|
238
260
|
!schema.meta.placeholder
|
|
239
261
|
) {
|
|
240
|
-
errors.add(
|
|
262
|
+
errors.add(
|
|
263
|
+
`"${schema.name}" is missing a placeholder${fileLabel}.`
|
|
264
|
+
);
|
|
241
265
|
}
|
|
242
266
|
|
|
243
267
|
// Only require description if the component schema defines it
|
|
@@ -247,7 +271,9 @@ const validateComponentSchemas = (schemas, errors) => {
|
|
|
247
271
|
"description" in componentSchema.meta &&
|
|
248
272
|
!schema.meta.description
|
|
249
273
|
) {
|
|
250
|
-
errors.add(
|
|
274
|
+
errors.add(
|
|
275
|
+
`"${schema.name}" is missing a description${fileLabel}.`
|
|
276
|
+
);
|
|
251
277
|
}
|
|
252
278
|
|
|
253
279
|
// 🚨 Validate for duplicate options with same label and value
|
|
@@ -258,7 +284,7 @@ const validateComponentSchemas = (schemas, errors) => {
|
|
|
258
284
|
const key = `${option.label}::${option.value}`;
|
|
259
285
|
if (seen.has(key)) {
|
|
260
286
|
errors.add(
|
|
261
|
-
`"${schema.name}" contains duplicate option at index ${index} with label "${option.label}" and value "${option.value}".`
|
|
287
|
+
`"${schema.name}" contains duplicate option at index ${index} with label "${option.label}" and value "${option.value}"${fileLabel}.`
|
|
262
288
|
);
|
|
263
289
|
} else {
|
|
264
290
|
seen.add(key);
|
|
@@ -268,7 +294,12 @@ const validateComponentSchemas = (schemas, errors) => {
|
|
|
268
294
|
}
|
|
269
295
|
|
|
270
296
|
// Validate against the specific component type schema
|
|
271
|
-
validateComponentByType(
|
|
297
|
+
validateComponentByType(
|
|
298
|
+
schema,
|
|
299
|
+
schema.meta.displayType,
|
|
300
|
+
errors,
|
|
301
|
+
filename
|
|
302
|
+
);
|
|
272
303
|
});
|
|
273
304
|
};
|
|
274
305
|
|
|
@@ -314,7 +345,11 @@ const validateWebhook = (webhookPath, spec, errors) => {
|
|
|
314
345
|
errors
|
|
315
346
|
);
|
|
316
347
|
if (webhookSchema && Array.isArray(webhookSchema.parameters)) {
|
|
317
|
-
validateComponentSchemas(
|
|
348
|
+
validateComponentSchemas(
|
|
349
|
+
webhookSchema.parameters,
|
|
350
|
+
errors,
|
|
351
|
+
"webhook.json"
|
|
352
|
+
);
|
|
318
353
|
}
|
|
319
354
|
}
|
|
320
355
|
};
|
|
@@ -329,7 +364,7 @@ const validateBaseSchema = (baseSchemaPath, errors) => {
|
|
|
329
364
|
|
|
330
365
|
// Validate base schema parameters
|
|
331
366
|
if (baseSchema && Array.isArray(baseSchema.parameters)) {
|
|
332
|
-
validateComponentSchemas(baseSchema.parameters, errors);
|
|
367
|
+
validateComponentSchemas(baseSchema.parameters, errors, "base.json");
|
|
333
368
|
}
|
|
334
369
|
|
|
335
370
|
return baseSchema;
|
|
@@ -346,7 +381,11 @@ const validateAuthentication = (authPath, errors) => {
|
|
|
346
381
|
|
|
347
382
|
// Validate authentication schema parameters
|
|
348
383
|
if (authSchema && Array.isArray(authSchema.parameters)) {
|
|
349
|
-
validateComponentSchemas(
|
|
384
|
+
validateComponentSchemas(
|
|
385
|
+
authSchema.parameters,
|
|
386
|
+
errors,
|
|
387
|
+
"authentication.json"
|
|
388
|
+
);
|
|
350
389
|
}
|
|
351
390
|
|
|
352
391
|
// Validate authentication type-specific parameters (like api_key, oauth, etc.)
|
|
@@ -360,7 +399,8 @@ const validateAuthentication = (authPath, errors) => {
|
|
|
360
399
|
if (Array.isArray(authSchema[key].parameters)) {
|
|
361
400
|
validateComponentSchemas(
|
|
362
401
|
authSchema[key].parameters,
|
|
363
|
-
errors
|
|
402
|
+
errors,
|
|
403
|
+
"authentication.json"
|
|
364
404
|
);
|
|
365
405
|
}
|
|
366
406
|
}
|
|
@@ -399,7 +439,11 @@ const validateResources = (resourcesDir, resourceFields, errors) => {
|
|
|
399
439
|
|
|
400
440
|
// Validate resource file parameters
|
|
401
441
|
if (Array.isArray(schema.parameters)) {
|
|
402
|
-
validateComponentSchemas(
|
|
442
|
+
validateComponentSchemas(
|
|
443
|
+
schema.parameters,
|
|
444
|
+
errors,
|
|
445
|
+
`${resourceFile}.json`
|
|
446
|
+
);
|
|
403
447
|
}
|
|
404
448
|
|
|
405
449
|
const operationFields = findOperationFieldsWithOptions(
|
|
@@ -433,7 +477,11 @@ const validateResources = (resourcesDir, resourceFields, errors) => {
|
|
|
433
477
|
} else {
|
|
434
478
|
// Validate operation parameters using component schemas
|
|
435
479
|
if (Array.isArray(methodDef.parameters)) {
|
|
436
|
-
validateComponentSchemas(
|
|
480
|
+
validateComponentSchemas(
|
|
481
|
+
methodDef.parameters,
|
|
482
|
+
errors,
|
|
483
|
+
`${resourceFile}.json`
|
|
484
|
+
);
|
|
437
485
|
}
|
|
438
486
|
}
|
|
439
487
|
if (!methodDef.definition) {
|
package/package.json
CHANGED
|
@@ -110,7 +110,12 @@ const select = {
|
|
|
110
110
|
url: "/api/options",
|
|
111
111
|
labelKey: "label",
|
|
112
112
|
valueKey: "value",
|
|
113
|
-
body: {
|
|
113
|
+
body: {
|
|
114
|
+
secret: "secret",
|
|
115
|
+
loadOptionsMethod: "get",
|
|
116
|
+
resource: "resource",
|
|
117
|
+
operation: "operation",
|
|
118
|
+
},
|
|
114
119
|
},
|
|
115
120
|
displayProps: { loading: false },
|
|
116
121
|
validation: {
|
|
@@ -118,6 +123,17 @@ const select = {
|
|
|
118
123
|
requiredDetail: {
|
|
119
124
|
errorMsg: "Selection is required",
|
|
120
125
|
},
|
|
126
|
+
max: 10,
|
|
127
|
+
maxDetail: {
|
|
128
|
+
errorMsg: "Too many options",
|
|
129
|
+
},
|
|
130
|
+
min: 1,
|
|
131
|
+
minDetail: {
|
|
132
|
+
errorMsg: "At least one option is required",
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
htmlProps: {
|
|
136
|
+
allowDynamic: false,
|
|
121
137
|
},
|
|
122
138
|
dependencies: {
|
|
123
139
|
logic: "AND",
|