<commit_before>import { addPipelineOptionMetadata } from '../Abstract'

/**
 * Class or method decorator used to declare an action option, along with its JSONSchema definition.
 * 
 * @param option Name of the option
 * @param schema JSONSchema definition. Can be an object or a function returning an object
 * @param required true or false
 * @param description Description of the option
 */
export function option(option: string, schema: Object | (() => Object), required: boolean = true, description: string = null) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        // extract schemaObject
        let schemaObject
        if (typeof schema === "function") {
            schemaObject = schema()
        } else {
            schemaObject = schema
        }

        // add option metadata to the pipeline
        addPipelineOptionMetadata(target, propertyKey, option, schemaObject, description, required)

        // add validation code to the method
        // TODO add option validation here. @validate only validates schemas related to the model. When an option is passed it always needs to be validated
    }
}<commit_msg>Add validation to option decorator<commit_after>import { type } from 'os';
import { addPipelineOptionMetadata } from '../Abstract'
import * as Ajv from 'ajv'
import { PipelineAbstract } from '../Abstract'

/**
 * Class or method decorator used to declare an action option, along with its JSONSchema definition.
 * 
 * @param option Name of the option
 * @param schema JSONSchema definition. Can be an object or a function returning an object
 * @param required true or false
 * @param description Description of the option
 * @param validation Flag indicating if this option should be validated automatically. Default value : 'true'
 */
export function option(option: string, schema: Object | (() => Object), required: boolean = true, description: string = null, validation = true) {
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        // extract schemaObject
        let schemaObject
        if (typeof schema === "function") {
            schemaObject = schema()
        } else {
            schemaObject = schema
        }

        // add option metadata to the pipeline
        addPipelineOptionMetadata(target, propertyKey, option, schemaObject, description, required)

        // add validation code to the method
        if (validation && typeof descriptor.value == 'function' && PipelineAbstract.getCRUDMethods().find((key) => propertyKey == key)) {
            let func: Function = descriptor.value;

            // validate function to check this option alone
            var ajv = new Ajv();
            ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'));
            let validate = ajv.compile({
                type: 'object',
                properties: {
                    [option]: schemaObject
                },
                required: required ? [option] : []
            });
            // index of the option parameter based on the method name
            var optPosition = propertyKey === "create" || propertyKey === "read" || propertyKey === "delete" ? 1 : 2;

            // wrap the method to add validation
            descriptor.value = function (...params) {
                try {
                    // get options from params
                    let options = params.length > optPosition ? params[optPosition] : null;
                    // run validation
                    let valid = validate(options || {});
                    if (!valid) {
                        throw new Error(ajv.errorsText(validate.errors))
                    }
                    // call the real implementation
                    return func.apply(this, params);
                } catch (e) {
                    let callError = new Error("Validation error in " + Object.getPrototypeOf(this).constructor.name + "." + propertyKey + " : " + e);
                    console.log("Validation error in " + Object.getPrototypeOf(this).constructor.name + "." + propertyKey + " : " + e);
                    return Promise.reject(e);
                }
            };
        }
    }
}
{'fraction_non_alphanumeric': 0.09496810772501772, 'fraction_numerical': 0.0009449562957713206, 'mean_word_length': 2.18106686701728, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3819603', 'n_tokens_mistral': 985, 'n_tokens_neox': 947, 'n_words': 372}