<commit_before>'use strict';

const fs = require('fs');

const Promise = require('bluebird');
const semver = require('semver');
const david = require('david');
const checkstyleFormatter = require('checkstyle-formatter');

const pkg = require('./package.json');
const pkgLines = fs.readFileSync('./package.json').toString().split(/\n/);

const errorOpts = {
    E404: true,
    ESCM: true
};

/**
 * @param {string} name
 * @param {string} version
 * @return {?{ source: string, line: number, column: number }}
 */
function getSourceLine(name, version) {
    const matches = pkgLines
        .map((source, index) => ({ source, line: index + 1 }))
        .filter(entry => entry.source.indexOf(`"${name}": "${version}"`) !== -1)
        .map(entry => Object.assign(entry, { column: entry.source.indexOf(version)}));

    return matches.length === 1 ? matches[0] : null;
}

/**
 * @param {{ stable: string, required: string, latest: string }} dependencies
 * @return {Array.<Object>}
 */
function check(dependencies) {
    const messages = [];

    Object.keys(dependencies).forEach(function (name) {
        const vStable = dependencies[name].stable;
        const vRequired = dependencies[name].required;
        const source = getSourceLine(name, vRequired) || { line: 0, column: 0 };

        if (!semver.valid(vRequired)) {
            // David has incomplete support for alternative syntaxes, e.g. "<EMAIL>:...", see
            // https://github.com/alanshaw/david/issues/92
            return messages.push({
                line: source.line,
                column: source.column,
                severity: 'warning',
                message: `Unparsable semver string for module "${name}": "${vRequired}"`
            });
        }

        const stable = { major: semver.major(vStable), minor: semver.minor(vStable) };
        const required = { major: semver.major(vRequired), minor: semver.minor(vRequired) };

        if (stable.major > required.major) {
            messages.push({
                line: source.line,
                column: source.column,
                severity: 'error',
                message: `New major version available for module "${name}" (${vStable})`
            });
        } else if (stable.minor > required.minor) {
            messages.push({
                line: source.line,
                column: source.column,
                severity: 'warning',
                message: `New minor version available for module "${name}" (${vStable})`
            });
        }
    });

    return messages;
}

Promise
    .join(
        Promise.fromCallback(cb => david.getUpdatedDependencies(pkg, { stable: true, error: errorOpts }, cb)),
        Promise.fromCallback(cb => david.getUpdatedDependencies(pkg, { dev: true, stable: true, error: errorOpts }, cb))
    )
    .map(check)
    .spread((deps, devDeps) => deps.concat(devDeps))
    .tap(messages => console.log(checkstyleFormatter([{ filename: 'package.json', messages }])))
    .then(function (messages) {
        if (messages.some(message => message.severity === 'error')) {
            process.exit(1);
        }
    })
    .catch(function (error) {
        console.error(error.message);
        console.dir(error.stack.split(/\n/));
        process.exit(2);
    });<commit_msg>read package.json location from argv<commit_after>'use strict';

const fs = require('fs');

const Promise = require('bluebird');
const semver = require('semver');
const david = require('david');
const checkstyleFormatter = require('checkstyle-formatter');

const packageFile = process.argv[2];

const errorOpts = {
    E404: true,
    ESCM: true
};

let pkg, pkgLines;

/**
 * @param {string} name
 * @param {string} version
 * @return {?{ source: string, line: number, column: number }}
 */
function findLineInSource(name, version) {
    const matches = pkgLines
        .map((source, index) => ({ source, line: index + 1 }))
        .filter(entry => entry.source.indexOf(`"${name}": "${version}"`) !== -1)
        .map(entry => Object.assign(entry, { column: entry.source.indexOf(version)}));

    return matches.length === 1 ? matches[0] : null;
}

/**
 * @param {{ stable: string, required: string, latest: string }} dependencies
 * @return {Array.<Object>}
 */
function check(dependencies) {
    const messages = [];

    Object.keys(dependencies).forEach(function (name) {
        const vStable = dependencies[name].stable;
        const vRequired = dependencies[name].required;
        const source = findLineInSource(name, vRequired) || { line: 0, column: 0 };

        if (!semver.valid(vRequired)) {
            // David has incomplete support for alternative syntaxes, e.g. "git<EMAIL>:...", see
            // https://github.com/alanshaw/david/issues/92
            return messages.push({
                line: source.line,
                column: source.column,
                severity: 'warning',
                message: `Unparsable semver string for module "${name}": "${vRequired}"`
            });
        }

        const stable = { major: semver.major(vStable), minor: semver.minor(vStable) };
        const required = { major: semver.major(vRequired), minor: semver.minor(vRequired) };

        if (stable.major > required.major) {
            messages.push({
                line: source.line,
                column: source.column,
                severity: 'error',
                message: `New major version available for module "${name}" (${vStable})`
            });
        } else if (stable.minor > required.minor) {
            messages.push({
                line: source.line,
                column: source.column,
                severity: 'warning',
                message: `New minor version available for module "${name}" (${vStable})`
            });
        }
    });

    return messages;
}

Promise
    .fromCallback(cb => fs.access(packageFile, fs.R_OK, cb))
    .then(function () {
        pkg = require(packageFile);
        pkgLines = fs.readFileSync(packageFile).toString().split(/\n/);
    })
    .then(() => [
        Promise.fromCallback(cb => david.getUpdatedDependencies(pkg, { stable: true, error: errorOpts }, cb)),
        Promise.fromCallback(cb => david.getUpdatedDependencies(pkg, { dev: true, stable: true, error: errorOpts }, cb))
    ])
    .map(check)
    .spread((deps, devDeps) => deps.concat(devDeps))
    .tap(messages => console.log(checkstyleFormatter([{ filename: 'package.json', messages }])))
    .then(function (messages) {
        if (messages.some(message => message.severity === 'error')) {
            process.exit(1);
        }
    })
    .catch(function (error) {
        console.error(error.message);
        console.dir(error.stack.split(/\n/));
        process.exit(2);
    });
{'fraction_non_alphanumeric': 0.15704319430013358, 'fraction_numerical': 0.004007718569096037, 'mean_word_length': 2.4839710444674252, 'pattern_counts': {'":': 4, '<': 7, '<?xml version=': 0, '>': 29, 'https://': 2, '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': '4563199', 'n_tokens_mistral': 1984, 'n_tokens_neox': 1901, 'n_words': 449}