<commit_before>"use strict";
/**
 * @module opcua.miscellaneous
 */



const _ = require("underscore");
const assert = require("node-opcua-assert").assert;

const _defaultTypeMap = require("./factories_builtin_types")._defaultTypeMap;
const TypeSchema = require("./factories_builtin_types").TypeSchema;

const _enumerations = require("./factories_enumerations")._private._enumerations;
const getFactory = require("./factories_factories").getFactory;

const debugLog = require("node-opcua-debug").make_debugLog(__filename);
exports.doDebug = !!process.env.DEBUG_CLASS;

const display_trace_from_this_projet_only = require("node-opcua-utils").display_trace_from_this_projet_only;


/**
 * ensure correctness of a schema object.
 *
 * @method check_schema_correctness
 * @param schema
 *
 */
function check_schema_correctness(schema) {
    assert(schema.name, " expecting schema to have a name");
    assert(schema.fields, " expecting schema to provide a set of fields " + schema.name);
    assert(schema.baseType === undefined || (typeof schema.baseType === "string"));
}
exports.check_schema_correctness = check_schema_correctness;

/**
 *
 * @method get_base_schema
 * @param schema
 * @return {*}
 *
 */
function get_base_schema(schema) {

    let base_schema = schema._base_schema;
    if (base_schema) {
        return base_schema;
    }

    if (schema.baseType && schema.baseType !== "BaseUAObject") {
        const baseType = getFactory(schema.baseType);

        // istanbul ignore next
        if (!baseType) {
            throw new Error(" cannot find factory for " + schema.baseType);
        }
        if (baseType.prototype._schema) {
            base_schema = baseType.prototype._schema;
        }
    }
    // put in  cache for speedup
    schema._base_schema = base_schema;

    return base_schema;
}
exports.get_base_schema = get_base_schema;

/**
 * extract a list of all possible fields for a schema
 * (by walking up the inheritance chain)
 * @method extract_all_fields
 *
 */
function extract_all_fields(schema) {

    // returns cached result if any
    // istanbul ignore next
    if (schema._possible_fields) {
        return schema._possible_fields;
    }
    // extract the possible fields from the schema.
    let possible_fields = schema.fields.map(function (field) {
        return field.name;
    });

    const base_schema = get_base_schema(schema);

    // istanbul ignore next
    if (base_schema) {
        const fields = extract_all_fields(base_schema);
        possible_fields = fields.concat(possible_fields);
    }

    // put in cache to speed up
    schema._possible_fields = possible_fields;

    return possible_fields;
}
exports.extract_all_fields = extract_all_fields;

/**
 * check correctness of option fields against scheme
 *
 * @method  check_options_correctness_against_schema
 *
 */
function check_options_correctness_against_schema(obj, schema, options) {

    if (!exports.doDebug) {
        return ; // ignoring set
    }

    // istanbul ignore next
    if (!_.isObject(options)) {
        let message = " Invalid options specified while trying to construct a ".red.bold + " " + schema.name.yellow;
        message += " expecting a ".red.bold + " Object ".yellow;
        message += " and got a ".red.bold + (typeof options).yellow + " instead ".red.bold;
        console.log(" Schema  = ", schema);
        console.log(" options = ", options);
        throw new Error(message);
    }

    // istanbul ignore next
    if (options instanceof obj.constructor) {
        return true;
    }

    // extract the possible fields from the schema.
    const possible_fields = obj.constructor.possibleFields;

    // extracts the fields exposed by the option object
    const current_fields = Object.keys(options);


    // get a list of field that are in the 'options' object but not in schema
    const invalid_options_fields = _.difference(current_fields, possible_fields);

    /* istanbul ignore next */
    if (invalid_options_fields.length > 0) {
        console.log("expected schema", schema.name);
        console.log("schema", schema);
        console.log("possible_fields", possible_fields);
        display_trace_from_this_projet_only();
        console.log("invalid_options_fields= ", invalid_options_fields);
    }
    if (invalid_options_fields.length !== 0) {
        throw new Error(" invalid field found in option :" + JSON.stringify(invalid_options_fields));
    }<commit_msg>add extra check in check_schema_correctness to verify array fields<commit_after>"use strict";
/**
 * @module opcua.miscellaneous
 */



const _ = require("underscore");
const assert = require("node-opcua-assert").assert;

const _defaultTypeMap = require("./factories_builtin_types")._defaultTypeMap;
const TypeSchema = require("./factories_builtin_types").TypeSchema;

const _enumerations = require("./factories_enumerations")._private._enumerations;
const getFactory = require("./factories_factories").getFactory;

const debugLog = require("node-opcua-debug").make_debugLog(__filename);
exports.doDebug = !!process.env.DEBUG_CLASS;

const display_trace_from_this_projet_only = require("node-opcua-utils").display_trace_from_this_projet_only;


/**
 * ensure correctness of a schema object.
 *
 * @method check_schema_correctness
 * @param schema
 *
 */
function check_schema_correctness(schema) {
    assert(schema.name, " expecting schema to have a name");
    assert(schema.fields, " expecting schema to provide a set of fields " + schema.name);
    assert(schema.baseType === undefined || (typeof schema.baseType === "string"));
}
exports.check_schema_correctness = check_schema_correctness;

/**
 *
 * @method get_base_schema
 * @param schema
 * @return {*}
 *
 */
function get_base_schema(schema) {

    let base_schema = schema._base_schema;
    if (base_schema) {
        return base_schema;
    }

    if (schema.baseType && schema.baseType !== "BaseUAObject") {
        const baseType = getFactory(schema.baseType);

        // istanbul ignore next
        if (!baseType) {
            throw new Error(" cannot find factory for " + schema.baseType);
        }
        if (baseType.prototype._schema) {
            base_schema = baseType.prototype._schema;
        }
    }
    // put in  cache for speedup
    schema._base_schema = base_schema;

    return base_schema;
}
exports.get_base_schema = get_base_schema;

/**
 * extract a list of all possible fields for a schema
 * (by walking up the inheritance chain)
 * @method extract_all_fields
 *
 */
function extract_all_fields(schema) {

    // returns cached result if any
    // istanbul ignore next
    if (schema._possible_fields) {
        return schema._possible_fields;
    }
    // extract the possible fields from the schema.
    let possible_fields = schema.fields.map(function (field) {
        return field.name;
    });

    const base_schema = get_base_schema(schema);

    // istanbul ignore next
    if (base_schema) {
        const fields = extract_all_fields(base_schema);
        possible_fields = fields.concat(possible_fields);
    }

    // put in cache to speed up
    schema._possible_fields = possible_fields;

    return possible_fields;
}
exports.extract_all_fields = extract_all_fields;

/**
 * check correctness of option fields against scheme
 *
 * @method  check_options_correctness_against_schema
 *
 */
function check_options_correctness_against_schema(obj, schema, options) {

    if (!exports.doDebug) {
        return ; // ignoring set
    }

    // istanbul ignore next
    if (!_.isObject(options)) {
        let message = " Invalid options specified while trying to construct a ".red.bold + " " + schema.name.yellow;
        message += " expecting a ".red.bold + " Object ".yellow;
        message += " and got a ".red.bold + (typeof options).yellow + " instead ".red.bold;
        console.log(" Schema  = ", schema);
        console.log(" options = ", options);
        throw new Error(message);
    }

    // istanbul ignore next
    if (options instanceof obj.constructor) {
        return true;
    }

    // extract the possible fields from the schema.
    const possible_fields = obj.constructor.possibleFields;

    // extracts the fields exposed by the option object
    const current_fields = Object.keys(options);


    // get a list of field that are in the 'options' object but not in schema
    const invalid_options_fields = _.difference(current_fields, possible_fields);

    /* istanbul ignore next */
    if (invalid_options_fields.length > 0)   {
        console.log("expected schema", schema.name);
        console.log("schema", schema);
        console.log("possible_fields", possible_fields);
        console.log("invalid_options_fields= ", invalid_options_fields);
        display_trace_from_this_projet_only();
    }
    if (invalid_options_fields.length !== 0) {
        throw new Error(" invalid field found in option :" + JSON.stringify(invalid_options_fields));
    }

    // check that fields that are supposed to be array are either null or array
    for(const field of schema.fields) {
        if (field.isArray) {
            const a = options[field.name];
            if (a === undefined ||a === null ) {
                continue;
            }
            if(!(a instanceof Array)) {
                console.log("expected schema", schema.name);
                console.log("schema", schema);
                console.log("field ", field.name, " is supposed to be an array");
                throw new Error(" Invalid array in field " + field.name);
            }

        }
    }


{'fraction_non_alphanumeric': 0.10780824785430186, 'fraction_numerical': 0.0004186728072011723, 'mean_word_length': 3.1008583690987126, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '415053', 'n_tokens_mistral': 2727, 'n_tokens_neox': 2652, 'n_words': 703}