| 'use strict' |
| |
| const fs = require('graceful-fs') |
| const path = require('path') |
| const _ = require('lodash') |
| const useragent = require('useragent') |
| const Promise = require('bluebird') |
| const mm = require('minimatch') |
| |
| exports.browserFullNameToShort = (fullName) => { |
| const agent = useragent.parse(fullName) |
| const isUnknown = agent.family === 'Other' || agent.os.family === 'Other' |
| return isUnknown ? fullName : `${agent.toAgent()} (${agent.os})` |
| } |
| |
| exports.isDefined = (value) => { |
| return !_.isUndefined(value) |
| } |
| |
| const parser = (pattern, out) => { |
| if (pattern.length === 0) return out |
| const p = /^(\[[^\]]*\]|[*+@?]\((.+?)\))/g |
| const matches = p.exec(pattern) |
| if (!matches) { |
| const c = pattern[0] |
| let t = 'word' |
| if (c === '*') { |
| t = 'star' |
| } else if (c === '?') { |
| t = 'optional' |
| } |
| out[t]++ |
| return parser(pattern.substring(1), out) |
| } |
| if (matches[2] !== undefined) { |
| out.ext_glob++ |
| parser(matches[2], out) |
| return parser(pattern.substring(matches[0].length), out) |
| } |
| out.range++ |
| return parser(pattern.substring(matches[0].length), out) |
| } |
| |
| const gsParser = (pattern, out) => { |
| if (pattern === '**') { |
| out.glob_star++ |
| return out |
| } |
| return parser(pattern, out) |
| } |
| |
| const compareWeightObject = (w1, w2) => { |
| return exports.mmComparePatternWeights( |
| [w1.glob_star, w1.star, w1.ext_glob, w1.range, w1.optional], |
| [w2.glob_star, w2.star, w2.ext_glob, w2.range, w2.optional] |
| ) |
| } |
| |
| exports.mmPatternWeight = (pattern) => { |
| const m = new mm.Minimatch(pattern) |
| if (!m.globParts) return [0, 0, 0, 0, 0, 0] |
| const result = m.globParts.reduce((prev, p) => { |
| const r = p.reduce((prev, p) => { |
| return gsParser(p, prev) |
| }, { glob_star: 0, ext_glob: 0, word: 0, star: 0, optional: 0, range: 0 }) |
| if (prev === undefined) return r |
| return compareWeightObject(r, prev) > 0 ? r : prev |
| }, undefined) |
| result.glob_sets = m.set.length |
| return [result.glob_sets, result.glob_star, result.star, result.ext_glob, result.range, result.optional] |
| } |
| |
| exports.mmComparePatternWeights = (weight1, weight2) => { |
| let n1, n2, diff |
| n1 = weight1[0] |
| n2 = weight2[0] |
| diff = n1 - n2 |
| if (diff !== 0) return diff / Math.abs(diff) |
| return weight1.length > 1 ? exports.mmComparePatternWeights(weight1.slice(1), weight2.slice(1)) : 0 |
| } |
| |
| exports.isFunction = _.isFunction |
| exports.isString = _.isString |
| exports.isObject = _.isObject |
| exports.isArray = _.isArray |
| exports.isNumber = _.isNumber |
| |
| const ABS_URL = /^https?:\/\// |
| exports.isUrlAbsolute = (url) => { |
| return ABS_URL.test(url) |
| } |
| |
| exports.camelToSnake = (camelCase) => { |
| return camelCase.replace(/[A-Z]/g, (match, pos) => { |
| return (pos > 0 ? '_' : '') + match.toLowerCase() |
| }) |
| } |
| |
| exports.ucFirst = (word) => { |
| return word.charAt(0).toUpperCase() + word.substr(1) |
| } |
| |
| exports.dashToCamel = (dash) => { |
| const words = dash.split('-') |
| return words.shift() + words.map(exports.ucFirst).join('') |
| } |
| |
| exports.arrayRemove = (collection, item) => { |
| const idx = collection.indexOf(item) |
| |
| if (idx !== -1) { |
| collection.splice(idx, 1) |
| return true |
| } |
| |
| return false |
| } |
| |
| exports.merge = function () { |
| const args = Array.prototype.slice.call(arguments, 0) |
| args.unshift({}) |
| return _.merge.apply({}, args) |
| } |
| |
| exports.formatTimeInterval = (time) => { |
| const mins = Math.floor(time / 60000) |
| const secs = (time - mins * 60000) / 1000 |
| let str = secs + (secs === 1 ? ' sec' : ' secs') |
| |
| if (mins) { |
| str = mins + (mins === 1 ? ' min ' : ' mins ') + str |
| } |
| |
| return str |
| } |
| |
| const replaceWinPath = (path) => { |
| return _.isString(path) ? path.replace(/\\/g, '/') : path |
| } |
| |
| exports.normalizeWinPath = process.platform === 'win32' ? replaceWinPath : _.identity |
| |
| exports.mkdirIfNotExists = (directory, done) => { |
| // TODO(vojta): handle if it's a file |
| /* eslint-disable handle-callback-err */ |
| fs.stat(directory, (err, stat) => { |
| if (stat && stat.isDirectory()) { |
| done() |
| } else { |
| exports.mkdirIfNotExists(path.dirname(directory), () => { |
| fs.mkdir(directory, done) |
| }) |
| } |
| }) |
| /* eslint-enable handle-callback-err */ |
| } |
| |
| exports.defer = () => { |
| let res |
| let rej |
| const promise = new Promise((resolve, reject) => { |
| res = resolve |
| rej = reject |
| }) |
| |
| return { |
| resolve: res, |
| reject: rej, |
| promise: promise |
| } |
| } |
| |
| exports.saveOriginalArgs = (config) => { |
| if (config && config.client && config.client.args) { |
| config.client.originalArgs = _.cloneDeep(config.client.args) |
| } |
| } |
| |
| exports.restoreOriginalArgs = (config) => { |
| if (config && config.client && config.client.originalArgs) { |
| config.client.args = _.cloneDeep(config.client.originalArgs) |
| } |
| } |