1 | 'use strict'
|
2 |
|
3 | const fs = require('graceful-fs')
|
4 | const path = require('path')
|
5 | const _ = require('lodash')
|
6 | const useragent = require('ua-parser-js')
|
7 | const mm = require('minimatch')
|
8 |
|
9 | exports.browserFullNameToShort = (fullName) => {
|
10 | const ua = useragent(fullName)
|
11 | if (!ua.browser.name && !ua.browser.version && !ua.os.name && !ua.os.version) {
|
12 | return fullName
|
13 | }
|
14 | return `${ua.browser.name} ${ua.browser.version || '0.0.0'} (${ua.os.name} ${ua.os.version || '0.0.0'})`
|
15 | }
|
16 |
|
17 | exports.isDefined = (value) => {
|
18 | return !_.isUndefined(value)
|
19 | }
|
20 |
|
21 | const parser = (pattern, out) => {
|
22 | if (pattern.length === 0) return out
|
23 | const p = /^(\[[^\]]*\]|[*+@?]\((.+?)\))/g
|
24 | const matches = p.exec(pattern)
|
25 | if (!matches) {
|
26 | const c = pattern[0]
|
27 | let t = 'word'
|
28 | if (c === '*') {
|
29 | t = 'star'
|
30 | } else if (c === '?') {
|
31 | t = 'optional'
|
32 | }
|
33 | out[t]++
|
34 | return parser(pattern.substring(1), out)
|
35 | }
|
36 | if (matches[2] !== undefined) {
|
37 | out.ext_glob++
|
38 | parser(matches[2], out)
|
39 | return parser(pattern.substring(matches[0].length), out)
|
40 | }
|
41 | out.range++
|
42 | return parser(pattern.substring(matches[0].length), out)
|
43 | }
|
44 |
|
45 | const gsParser = (pattern, out) => {
|
46 | if (pattern === '**') {
|
47 | out.glob_star++
|
48 | return out
|
49 | }
|
50 | return parser(pattern, out)
|
51 | }
|
52 |
|
53 | const compareWeightObject = (w1, w2) => {
|
54 | return exports.mmComparePatternWeights(
|
55 | [w1.glob_star, w1.star, w1.ext_glob, w1.range, w1.optional],
|
56 | [w2.glob_star, w2.star, w2.ext_glob, w2.range, w2.optional]
|
57 | )
|
58 | }
|
59 |
|
60 | exports.mmPatternWeight = (pattern) => {
|
61 | const m = new mm.Minimatch(pattern)
|
62 | if (!m.globParts) return [0, 0, 0, 0, 0, 0]
|
63 | const result = m.globParts.reduce((prev, p) => {
|
64 | const r = p.reduce((prev, p) => {
|
65 | return gsParser(p, prev)
|
66 | }, { glob_star: 0, ext_glob: 0, word: 0, star: 0, optional: 0, range: 0 })
|
67 | if (prev === undefined) return r
|
68 | return compareWeightObject(r, prev) > 0 ? r : prev
|
69 | }, undefined)
|
70 | result.glob_sets = m.set.length
|
71 | return [result.glob_sets, result.glob_star, result.star, result.ext_glob, result.range, result.optional]
|
72 | }
|
73 |
|
74 | exports.mmComparePatternWeights = (weight1, weight2) => {
|
75 | let n1, n2, diff
|
76 | n1 = weight1[0]
|
77 | n2 = weight2[0]
|
78 | diff = n1 - n2
|
79 | if (diff !== 0) return diff / Math.abs(diff)
|
80 | return weight1.length > 1 ? exports.mmComparePatternWeights(weight1.slice(1), weight2.slice(1)) : 0
|
81 | }
|
82 |
|
83 | exports.isFunction = _.isFunction
|
84 | exports.isString = _.isString
|
85 | exports.isObject = _.isObject
|
86 | exports.isArray = _.isArray
|
87 | exports.isNumber = _.isNumber
|
88 |
|
89 | const ABS_URL = /^https?:\/\//
|
90 | exports.isUrlAbsolute = (url) => {
|
91 | return ABS_URL.test(url)
|
92 | }
|
93 |
|
94 | exports.camelToSnake = (camelCase) => {
|
95 | return camelCase.replace(/[A-Z]/g, (match, pos) => {
|
96 | return (pos > 0 ? '_' : '') + match.toLowerCase()
|
97 | })
|
98 | }
|
99 |
|
100 | exports.ucFirst = (word) => {
|
101 | return word.charAt(0).toUpperCase() + word.substr(1)
|
102 | }
|
103 |
|
104 | exports.dashToCamel = (dash) => {
|
105 | const words = dash.split('-')
|
106 | return words.shift() + words.map(exports.ucFirst).join('')
|
107 | }
|
108 |
|
109 | exports.arrayRemove = (collection, item) => {
|
110 | const idx = collection.indexOf(item)
|
111 |
|
112 | if (idx !== -1) {
|
113 | collection.splice(idx, 1)
|
114 | return true
|
115 | }
|
116 |
|
117 | return false
|
118 | }
|
119 |
|
120 | exports.merge = function () {
|
121 | const args = Array.prototype.slice.call(arguments, 0)
|
122 | args.unshift({})
|
123 | return _.merge.apply({}, args)
|
124 | }
|
125 |
|
126 | exports.formatTimeInterval = (time) => {
|
127 | const mins = Math.floor(time / 60000)
|
128 | const secs = (time - mins * 60000) / 1000
|
129 | let str = secs + (secs === 1 ? ' sec' : ' secs')
|
130 |
|
131 | if (mins) {
|
132 | str = mins + (mins === 1 ? ' min ' : ' mins ') + str
|
133 | }
|
134 |
|
135 | return str
|
136 | }
|
137 |
|
138 | const replaceWinPath = (path) => {
|
139 | return _.isString(path) ? path.replace(/\\/g, '/') : path
|
140 | }
|
141 |
|
142 | exports.normalizeWinPath = process.platform === 'win32' ? replaceWinPath : _.identity
|
143 |
|
144 | exports.mkdirIfNotExists = (directory, done) => {
|
145 |
|
146 |
|
147 | fs.stat(directory, (err, stat) => {
|
148 | if (stat && stat.isDirectory()) {
|
149 | done()
|
150 | } else {
|
151 | exports.mkdirIfNotExists(path.dirname(directory), () => {
|
152 | fs.mkdir(directory, done)
|
153 | })
|
154 | }
|
155 | })
|
156 |
|
157 | }
|
158 |
|
159 | exports.defer = () => {
|
160 | let res
|
161 | let rej
|
162 | const promise = new Promise((resolve, reject) => {
|
163 | res = resolve
|
164 | rej = reject
|
165 | })
|
166 |
|
167 | return {
|
168 | resolve: res,
|
169 | reject: rej,
|
170 | promise: promise
|
171 | }
|
172 | }
|
173 |
|
174 | exports.saveOriginalArgs = (config) => {
|
175 | if (config && config.client && config.client.args) {
|
176 | config.client.originalArgs = _.cloneDeep(config.client.args)
|
177 | }
|
178 | }
|
179 |
|
180 | exports.restoreOriginalArgs = (config) => {
|
181 | if (config && config.client && config.client.originalArgs) {
|
182 | config.client.args = _.cloneDeep(config.client.originalArgs)
|
183 | }
|
184 | }
|