<commit_before>"use strict"

require 'colors'
{path, Promise: global.Promise} = fs = require 'nofs'
global._ = require 'underscore'
semver = require 'semver'

npm = require './npm'
util = require './util'
checkVer = require './checkVersion'
packageMgr = require './package'

option = {}
globalPackage = {}

parseOpts = (opts = {}) ->
    _.defaults opts,
        include: "", exclude: [] # array
        writeBack: no
        install: no
        lock: no
        all: no # w + i + l
        devDep: yes, dep: yes, optional: yes
        silent: no
        lockAll: false
        cache: true
        logLevel: 'error'
        cwd: process.cwd()
        warning: true
        mirror: ''

    opts.mirror = util.getRegistry opts.mirror

    opts.all and
        _.assign opts,
            writeBack: yes
            install: yes
            lock: yes

    opts.exclude = _.compact opts.exclude
    opts.include and opts.include = _.compact opts.include
    opts.silent and console.log = -> return

    opts

parsePackage = (name, ver, type) ->
    if Array.isArray(option.include) and not (name in option.include)
        return null

    if name in option.exclude
        return null

    if type is 'g'
        declareVer = installedVer = ver
    else
        # version in package.json
        declareVer = if semver.validRange ver then ver.trim() else null
        declareVer is '' and declareVer = '*'
        return null unless declareVer

        # version installed
        installedVer = packageMgr.getPackageVersion name

    {
        packageName: name
        declareVer
        installedVer
        baseVer: installedVer
        newVer: ''
        type
        needUpdate: no
        warnMsg: ''
    }

formatPackages = (obj, type) ->
    _.map obj, (version, name) ->
        pack = parsePackage name, version, type

prepare = ->
    try
        globalPackage = packageMgr.readPackageFile()
    catch e
        throw new Error (
            if e instanceof SyntaxError
                'unvalid package.json!'
            else
                'package.json Not Found!'
        )

    deps = []
    if option.dep
        deps = deps.concat formatPackages globalPackage.dependencies, 'S'
    if option.devDep
        deps = deps.concat formatPackages globalPackage.devDependencies, 'D'
    if option.optional
        deps = deps.concat formatPackages globalPackage.optionalDependencies, 'O'

    deps = _.compact deps

getToWrite = ({declareVer, newVer}, {lock, lockAll}) ->
    if declareVer in ['*', '']
        return if lockAll then newVer else '*'

    prefix =
        if lock or semver.valid declareVer
            ''
        else if m = declareVer.match /^([><=\s]+)[\d\w.-\s]*$/
            m[1]
        else '^'

    prefix + newVer

npmUp = ->
    process.chdir option.cwd

    try
        deps = prepare()
    catch e
        console.error (util.errorSign + " #{e}").red
        return Promise.reject()

    util.logInfo 'Checking packages\' version...'
    checkVer deps, option.cache, option.mirror
    .then (newDeps) ->
        deps = newDeps
        util.print deps, option.warning

        toUpdate = deps.filter (dep) -> dep.needUpdate and dep.installedVer
                        .map (dep) -> "#{dep.packageName}@#{dep.newVer}"

        chain = Promise.resolve()

        if toUpdate.length is 0
            util.logSucc "Everything is new!"

        if option.writeBack
            packageFile = util.cwdFilePath 'package.json'
            packageBakFile = util.cwdFilePath 'package.bak.json'

            chain = chain.then ->
                deps.forEach (dep) ->
                    toWrite = getToWrite dep, option

                    switch dep.type
                        when 'S' then globalPackage.dependencies[dep.packageName] = toWrite
                        when 'D' then globalPackage.devDependencies[dep.packageName] = toWrite
                        when 'O' then globalPackage.optionalDependencies[dep.packageName] = toWrite
            .then ->
                ['dependencies', 'devDependencies', 'optionalDependencies'].forEach (k) ->
                    delete globalPackage[k] if _.isEmpty globalPackage[k]
                fs.outputJSON packageFile, globalPackage, space: 2
            .then ->
                util.logSucc "package.json has been updated!"

        if option.install
            install = require './install'
            chain = chain.then ->
                install toUpdate, option.cwd

        chain

npmUpSubDir = ->
    process.chdir option.cwd

    dirs = []

    fs.eachDir '*',
        iter: (info) ->
            if info.isDir
                dirs.push info.path
    .then ->
        cwd = process.cwd()
        chain = Promise.resolve()

        dirs.forEach (odir) ->
            dir = path.join cwd, odir
            dirPack = path.join dir, 'package.json'
            if fs.fileExistsSync dirPack
                chain = chain.then ->
                    console.log '\n', odir
                    option.cwd = dir
                    npmUp()
                .catch -> return
        chain
    .then ->
        console.log 'FINISH'.green


npmUpGlobal = ->
    if option.install and not util.checkPrivilege()
        console.error (util.errorSign + " Permission Denied").red
        console.error "Please try running this command again as root/Administrator".yellow
        process.exit 1

    util.logInfo 'Searching global packages...'

    # In npm@3, global modules is not flatten.
    util.allPackagesIn npm.globalDir
    .then (packages) ->
        globalDep = packages.reduce (obj, pack) ->
            obj[pack.name] = pack.version
            obj
        , {}
        console.log (Object.keys(globalDep).join ' ').cyan

        deps = _.map globalDep, (val, key) ->
            parsePackage key, val, 'g'
        util.logInfo 'Checking packages\' version...'

        checkVer _.compact(deps), option.cache, option.mirror
    .then (newDeps) ->
        deps = newDeps<commit_msg>opt npm-up -A<commit_after>"use strict"

require 'colors'
{path, Promise: global.Promise} = fs = require 'nofs'
global._ = require 'underscore'
semver = require 'semver'

npm = require './npm'
util = require './util'
checkVer = require './checkVersion'
packageMgr = require './package'

option = {}
globalPackage = {}

parseOpts = (opts = {}) ->
    _.defaults opts,
        include: "", exclude: [] # array
        writeBack: no
        install: no
        lock: no
        all: no # w + i + l
        devDep: yes, dep: yes, optional: yes
        silent: no
        lockAll: false
        cache: true
        logLevel: 'error'
        cwd: process.cwd()
        warning: true
        mirror: ''

    opts.mirror = util.getRegistry opts.mirror

    opts.all and
        _.assign opts,
            writeBack: yes
            install: yes
            lock: yes

    opts.exclude = _.compact opts.exclude
    opts.include and opts.include = _.compact opts.include
    opts.silent and console.log = -> return

    opts

parsePackage = (name, ver, type) ->
    if Array.isArray(option.include) and not (name in option.include)
        return null

    if name in option.exclude
        return null

    if type is 'g'
        declareVer = installedVer = ver
    else
        # version in package.json
        declareVer = if semver.validRange ver then ver.trim() else null
        declareVer is '' and declareVer = '*'
        return null unless declareVer

        # version installed
        installedVer = packageMgr.getPackageVersion name

    {
        packageName: name
        declareVer
        installedVer
        baseVer: installedVer
        newVer: ''
        type
        needUpdate: no
        warnMsg: ''
    }

formatPackages = (obj, type) ->
    _.map obj, (version, name) ->
        pack = parsePackage name, version, type

prepare = ->
    try
        globalPackage = packageMgr.readPackageFile()
    catch e
        throw new Error (
            if e instanceof SyntaxError
                'unvalid package.json!'
            else
                'package.json Not Found!'
        )

    deps = []
    if option.dep
        deps = deps.concat formatPackages globalPackage.dependencies, 'S'
    if option.devDep
        deps = deps.concat formatPackages globalPackage.devDependencies, 'D'
    if option.optional
        deps = deps.concat formatPackages globalPackage.optionalDependencies, 'O'

    deps = _.compact deps

getToWrite = ({declareVer, newVer}, {lock, lockAll}) ->
    if declareVer in ['*', '']
        return if lockAll then newVer else '*'

    prefix =
        if lock or semver.valid declareVer
            ''
        else if m = declareVer.match /^([><=\s]+)[\d\w.-\s]*$/
            m[1]
        else '^'

    prefix + newVer

npmUp = ->
    process.chdir option.cwd

    try
        deps = prepare()
    catch e
        console.error (util.errorSign + " #{e}").red
        return Promise.reject()

    util.logInfo 'Checking packages\' version...'
    checkVer deps, option.cache, option.mirror
    .then (newDeps) ->
        deps = newDeps
        util.print deps, option.warning

        toUpdate = deps.filter (dep) -> dep.needUpdate and dep.installedVer
                        .map (dep) -> "#{dep.packageName}@#{dep.newVer}"

        chain = Promise.resolve()

        if toUpdate.length is 0
            util.logSucc "Everything is new!"

        if option.writeBack
            packageFile = util.cwdFilePath 'package.json'
            packageBakFile = util.cwdFilePath 'package.bak.json'

            chain = chain.then ->
                deps.forEach (dep) ->
                    toWrite = getToWrite dep, option

                    switch dep.type
                        when 'S' then globalPackage.dependencies[dep.packageName] = toWrite
                        when 'D' then globalPackage.devDependencies[dep.packageName] = toWrite
                        when 'O' then globalPackage.optionalDependencies[dep.packageName] = toWrite
            .then ->
                ['dependencies', 'devDependencies', 'optionalDependencies'].forEach (k) ->
                    delete globalPackage[k] if _.isEmpty globalPackage[k]
                fs.outputJSON packageFile, globalPackage, space: 2
            .then ->
                util.logSucc "package.json has been updated!"

        if option.install
            install = require './install'
            chain = chain.then ->
                install toUpdate, option.cwd

        chain

npmUpSubDir = ->
    process.chdir option.cwd

    fs.glob '*/package.json'
    .then (packs) ->
        packs.reduce (prev, cur) ->
            cwd = process.cwd()
            dir = path.dirname cur
            prev.then ->
                console.log '\n', path.basename dir
                option.cwd = path.join cwd, dir
                npmUp()
            .catch -> return
        , Promise.resolve()
    .then ->
        console.log 'FINISH'.green


npmUpGlobal = ->
    if option.install and not util.checkPrivilege()
        console.error (util.errorSign + " Permission Denied").red
        console.error "Please try running this command again as root/Administrator".yellow
        process.exit 1

    util.logInfo 'Searching global packages...'

    # In npm@3, global modules is not flatten.
    util.allPackagesIn npm.globalDir
    .then (packages) ->
        globalDep = packages.reduce (obj, pack) ->
            obj[pack.name] = pack.version
            obj
        , {}
        console.log (Object.keys(globalDep).join ' ').cyan

        deps = _.map globalDep, (val, key) ->
            parsePackage key, val, 'g'
        util.logInfo 'Checking packages\' version...'

        checkVer _.compact(deps), option.cache, option.mirror
    .then (newDeps) ->
        deps = newDeps
{'fraction_non_alphanumeric': 0.10329558034573788, 'fraction_numerical': 0.0008515711487694797, 'mean_word_length': 1.7606958157028678, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 62, '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': '6841491', 'n_tokens_mistral': 3375, 'n_tokens_neox': 3221, 'n_words': 913}