<commit_before>/*
 * Copyright (c) 2015-2016 PointSource, LLC.
 * MIT Licensed
 */

var path = require('path');
var fs = require('fs');
var debug = require('debug')('swagger');
var async = require('async');
var parser = require('swagger-parser');
var swaggerUtil = require('../lib/swaggerUtil');
var tv4 = require('tv4');
var _ = require('lodash');

var specs = {
    dereferenced: {},
    bundled: {}
};

var httpMethods = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch'];

var responseModelValidationLevel;
var polymorphicValidation;

exports.init = function (logger, config, callback) {
    var cfg = config.get('swagger');

    // default responseModelValidationLevel to level zero, i.e. off
    responseModelValidationLevel = /warn|error|fail/.test(cfg.validateResponseModels) ?
        cfg.validateResponseModels : 0;
    if (responseModelValidationLevel) {
        logger.info('Response model validation is on and set to level "%s"', responseModelValidationLevel);
    }

    // default polymorphicValidation to 'on'; allow both 'off' and false to turn it off
    polymorphicValidation = /on|warn|off/.test(cfg.polymorphicValidation) ?
        cfg.polymorphicValidation : ((cfg.polymorphicValidation === false) ? 'off' : 'on');
    if (polymorphicValidation !== 'on') {
        logger.info('Polymorphic validation is disabled (%s)', polymorphicValidation);
    }

    var swaggerDir = null;
    if (isBlueoakProject()) {
        swaggerDir = path.resolve(global.__appDir, '../common/swagger');
    } else {
        swaggerDir = path.resolve(global.__appDir, 'swagger');
    }


    debug('Loading swagger files from %s', swaggerDir);

    var files = [];

    try {
        fs.readdirSync(swaggerDir).forEach(function (fileName) {
            //look for json and yaml
            if (path.extname(fileName) === '.json') {
                files.push(path.resolve(swaggerDir, fileName));
            } else if (path.extname(fileName) === '.yaml') {
                files.push(path.resolve(swaggerDir, fileName));
            }
        });
    } catch (err) {
        //swagger dir probably doesn't exist
        return callback();
    }



    //Loop through all our swagger models
    //For each model, parse it, and automatically hook up the routes to the appropriate handler
    async.eachSeries(files, function parseSwagger(file, swagCallback) {
        var handlerName = path.basename(file); //use the swagger filename as our handler module id
        handlerName = handlerName.substring(0, handlerName.lastIndexOf('.')); //strip extensions

        var derefPromise = parser.validate(file);
        parser.bundle(file)
            .then(function (bundledApi) {
                specs.bundled[handlerName] = bundledApi;
                return derefPromise;
            })
            .then(function (dereferencedApi) {
                specs.dereferenced[handlerName] = dereferencedApi;
                if (polymorphicValidation !== 'off') {
                    getDiscriminatorObjectsForSchemas(dereferencedApi.paths, responseModelValidationLevel);
                }
                flattenModelDefinitions(dereferencedApi.definitions);
                return swagCallback();
            })
            .catch(function (error) {
                // don't generate an error if it was a non-Swagger Spec JSON file
                var swagErr = error;
                if (path.extname(file) !== '.yaml') {
                    try {
                        var json = JSON.parse(fs.readFileSync(file, {
                            encoding: 'utf8'
                        }));
                        if (!isSwaggerFile(json)) {
                            logger.info('Skipping non-Swagger JSON file %s', file);
                            swagErr = null;
                        }
                    } catch (err) {
                        logger.error('%s is not valid JSON', file);
                    }
                }
                return swagCallback(swagErr);
            });
    }, function (err) {
        callback(err);
    });

};

exports.getResponseModelValidationLevel = function () {
    return responseModelValidationLevel;
};

exports.isPolymorphicValidationEnabled = function () {
    return polymorphicValidation;
};

exports.getValidHttpMethods = function () {
    return httpMethods;
};

exports.getSimpleSpecs = function () {
    return specs.dereferenced;
};

exports.getPrettySpecs = function () {
    return specs.bundled;
};

exports.addFormat = function (format, validationFunction) {
    tv4.addFormat(format, validationFunction);
};

function flattenModelDefinitions(definitions) {
    Object.keys(definitions).forEach(function (defn) {
        var flattenedDefn = {};
        if (definitions[defn].hasOwnProperty('allOf')) {
            for (var i = 0; i < definitions[defn].allOf.length; i++) {
                //have to clone so that inherited definitions are not affected
                definitions[defn].allOf[i] = _.cloneDeep(definitions[defn].allOf[i]);
                flattenModel(definitions[defn].allOf[i], flattenedDefn);
            }
            flattenedDefn.required = Object.keys(flattenedDefn.required);
            definitions[defn] = flattenedDefn;
            delete definitions[defn].allOf;
        }
    });
}

function flattenModel(item, props) {
    //have to convert 'required' array to object for merging purposes
    if (item.required && Array.isArray(item.required)) {
        var requiredObj = {};
        item.required.reduce(function (prevVal, currentVal, idx) {
            prevVal[currentVal] = idx;
            return prevVal;
        }, requiredObj);
        item.required = requiredObj;
    }
    _.merge(props, item);
    if (item.hasOwnProperty('allOf')) {
        item.allOf.forEach(function (subItem) {
            flattenModel(subItem, props);
        });<commit_msg>follow lodash merge paradigm with merge to flat model implementation<commit_after>/*
 * Copyright (c) 2015-2016 PointSource, LLC.
 * MIT Licensed
 */

var path = require('path');
var fs = require('fs');
var debug = require('debug')('swagger');
var async = require('async');
var parser = require('swagger-parser');
var swaggerUtil = require('../lib/swaggerUtil');
var tv4 = require('tv4');
var _ = require('lodash');

var specs = {
    dereferenced: {},
    bundled: {}
};

var httpMethods = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch'];

var responseModelValidationLevel;
var polymorphicValidation;

exports.init = function (logger, config, callback) {
    var cfg = config.get('swagger');

    // default responseModelValidationLevel to level zero, i.e. off
    responseModelValidationLevel = /warn|error|fail/.test(cfg.validateResponseModels) ?
        cfg.validateResponseModels : 0;
    if (responseModelValidationLevel) {
        logger.info('Response model validation is on and set to level "%s"', responseModelValidationLevel);
    }

    // default polymorphicValidation to 'on'; allow both 'off' and false to turn it off
    polymorphicValidation = /on|warn|off/.test(cfg.polymorphicValidation) ?
        cfg.polymorphicValidation : ((cfg.polymorphicValidation === false) ? 'off' : 'on');
    if (polymorphicValidation !== 'on') {
        logger.info('Polymorphic validation is disabled (%s)', polymorphicValidation);
    }

    var swaggerDir = null;
    if (isBlueoakProject()) {
        swaggerDir = path.resolve(global.__appDir, '../common/swagger');
    } else {
        swaggerDir = path.resolve(global.__appDir, 'swagger');
    }


    debug('Loading swagger files from %s', swaggerDir);

    var files = [];

    try {
        fs.readdirSync(swaggerDir).forEach(function (fileName) {
            //look for json and yaml
            if (path.extname(fileName) === '.json') {
                files.push(path.resolve(swaggerDir, fileName));
            } else if (path.extname(fileName) === '.yaml') {
                files.push(path.resolve(swaggerDir, fileName));
            }
        });
    } catch (err) {
        //swagger dir probably doesn't exist
        return callback();
    }



    //Loop through all our swagger models
    //For each model, parse it, and automatically hook up the routes to the appropriate handler
    async.eachSeries(files, function parseSwagger(file, swagCallback) {
        var handlerName = path.basename(file); //use the swagger filename as our handler module id
        handlerName = handlerName.substring(0, handlerName.lastIndexOf('.')); //strip extensions

        var derefPromise = parser.validate(file);
        parser.bundle(file)
            .then(function (bundledApi) {
                specs.bundled[handlerName] = bundledApi;
                return derefPromise;
            })
            .then(function (dereferencedApi) {
                specs.dereferenced[handlerName] = dereferencedApi;
                if (polymorphicValidation !== 'off') {
                    getDiscriminatorObjectsForSchemas(dereferencedApi.paths, responseModelValidationLevel);
                }
                flattenModelDefinitions(dereferencedApi.definitions);
                return swagCallback();
            })
            .catch(function (error) {
                // don't generate an error if it was a non-Swagger Spec JSON file
                var swagErr = error;
                if (path.extname(file) !== '.yaml') {
                    try {
                        var json = JSON.parse(fs.readFileSync(file, {
                            encoding: 'utf8'
                        }));
                        if (!isSwaggerFile(json)) {
                            logger.info('Skipping non-Swagger JSON file %s', file);
                            swagErr = null;
                        }
                    } catch (err) {
                        logger.error('%s is not valid JSON', file);
                    }
                }
                return swagCallback(swagErr);
            });
    }, function (err) {
        callback(err);
    });

};

exports.getResponseModelValidationLevel = function () {
    return responseModelValidationLevel;
};

exports.isPolymorphicValidationEnabled = function () {
    return polymorphicValidation;
};

exports.getValidHttpMethods = function () {
    return httpMethods;
};

exports.getSimpleSpecs = function () {
    return specs.dereferenced;
};

exports.getPrettySpecs = function () {
    return specs.bundled;
};

exports.addFormat = function (format, validationFunction) {
    tv4.addFormat(format, validationFunction);
};

function flattenModelDefinitions(definitions) {
    Object.keys(definitions).forEach(function (defn) {
        if (definitions[defn].hasOwnProperty('allOf')) {
            var flattenedDefn = {};
            for (var i = 0; i < definitions[defn].allOf.length; i++) {
                //have to clone so that inherited definitions are not affected
                definitions[defn].allOf[i] = _.cloneDeep(definitions[defn].allOf[i]);
                mergeToFlatModel(flattenedDefn, definitions[defn].allOf[i]);
            }
            flattenedDefn.required = Object.keys(flattenedDefn.required);
            definitions[defn] = flattenedDefn;
            delete definitions[defn].allOf;
        }
    });
}

function mergeToFlatModel(flatModel, model) {
    //have to convert 'required' array to object for merging purposes
    if (model.required && Array.isArray(model.required)) {
        var requiredAsObj = {};
        model.required.reduce(function (reqsAsObj, reqdPropName, arrayIndex) {
            reqsAsObj[reqdPropName] = arrayIndex;
            return reqsAsObj;
        }, requiredAsObj);
        model.required = requiredAsObj;
    }
    _.merge(flatModel, model);
    if (model.hasOwnProperty('allOf')) {
        model.allOf.forEach(function (subModel) {
            mergeToFlatModel(flatModel, subModel);
        });
{'fraction_non_alphanumeric': 0.11869987336428874, 'fraction_numerical': 0.002532714225411566, 'mean_word_length': 2.3256597417181357, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, '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': '1159851', 'n_tokens_mistral': 3314, 'n_tokens_neox': 3145, 'n_words': 745}