Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions packages/input_schema/src/input_schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,24 @@ const validateField = <T extends Record<string, any>> (validator: Ajv, fieldSche
};

/**
* This function validates given input schema first just for basic structure then each field one by one and
* finally fully against the whole schema.
* Validates that all required fields are present in properties list
*/
export function validateExistenceOfRequiredFields<T extends Record<string, any>>(inputSchema: T) {
// If the input schema does not have any required fields, we do not need to validate them
if (!inputSchema?.required?.length) return;

Object.values(inputSchema?.required).forEach((fieldKey) => {
// If the required field is present in the list of properties, we can check the next one
if (inputSchema?.properties[fieldKey as string]) return;

// The required field is not defined in list of properties. Which means the schema is not valid.
throw new Error(m('inputSchema.validation.missingRequiredField', { fieldKey }));
});
}

/**
* This function validates given input schema first just for basic structure then each field one by one,
* then checks that all required fields are present and finally checks fully against the whole schema.
*
* This way we get the most accurate error message for user.
*/
Expand All @@ -129,6 +145,9 @@ export function validateInputSchema<T extends Record<string, any>>(validator: Aj
// Then validate each field separately.
Object.entries<any>(inputSchema.properties).forEach(([fieldKey, fieldSchema]) => validateField(validator, fieldSchema, fieldKey));

// Next validate if required fields are actually present in the schema
validateExistenceOfRequiredFields(inputSchema);

// Finally just to be sure run validation against the whole shema.
validateAgainstSchemaOrThrow(validator, inputSchema, schema, 'schema');
}
2 changes: 2 additions & 0 deletions packages/input_schema/src/intl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ const intlStrings = {
'Currently you do not have access to any proxy group usable in automatic mode.',
'inputSchema.validation.noMatchingDefinition':
'Field schema.properties.{fieldKey} is not matching any input schema type definition. Please make sure that it\'s type is valid.',
'inputSchema.validation.missingRequiredField':
'Field schema.properties.{fieldKey} does not exist, but it is specified in schema.required. Either define the field or remove it from schema.required.',
};
/* eslint-enable max-len,quotes,quote-props */

Expand Down
6 changes: 3 additions & 3 deletions packages/input_schema/src/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"title": { "type": "string" },
"description": { "type": "string" },
"nullable": { "type": "boolean" },
"editor": { "enum": ["javascript", "python", "textfield", "textarea", "hidden"] },
"editor": { "enum": ["javascript", "python", "textfield", "textarea", "datepicker", "hidden"] },
"isSecret": { "type": "boolean" }
},
"required": ["type", "title", "description", "editor"],
Expand All @@ -111,7 +111,7 @@
"nullable": { "type": "boolean" },
"minLength": { "type": "integer" },
"maxLength": { "type": "integer" },
"editor": { "enum": ["javascript", "python", "textfield", "textarea", "hidden"] },
"editor": { "enum": ["javascript", "python", "textfield", "textarea", "datepicker", "hidden"] },
"isSecret": { "type": "boolean" },
"sectionCaption": { "type": "string" },
"sectionDescription": { "type": "string" }
Expand Down Expand Up @@ -152,7 +152,7 @@
"maxItems": { "type": "integer" },
"uniqueItems": { "type": "boolean" },

"editor": { "enum": ["json", "requestListSources", "pseudoUrls", "keyValue", "stringList", "hidden"] },
"editor": { "enum": ["json", "requestListSources", "pseudoUrls", "globs", "keyValue", "stringList", "hidden"] },
"sectionCaption": { "type": "string" },
"sectionDescription": { "type": "string" }
},
Expand Down
17 changes: 16 additions & 1 deletion test/input_schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ describe('input_schema.json', () => {

expect(() => validateInputSchema(validator, schema)).toThrow(
'Input schema is not valid (Field schema.properties.myField.editor must be equal to one of the allowed values: '
+ '"javascript", "python", "textfield", "textarea", "hidden")',
+ '"javascript", "python", "textfield", "textarea", "datepicker", "hidden")',
);
});

Expand Down Expand Up @@ -207,5 +207,20 @@ describe('input_schema.json', () => {
'Input schema is not valid (Field schema.properties.myField.enum.0 must be string)',
);
});

it('should throw error when required field is not defined', () => {
const schema = {
title: 'Test input schema',
type: 'object',
schemaVersion: 1,
properties: {},
required: ['something'],
};

expect(() => validateInputSchema(validator, schema)).toThrow(
// eslint-disable-next-line
'Field schema.properties.something does not exist, but it is specified in schema.required. Either define the field or remove it from schema.required.',
);
});
});
});