1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 | 1×
1×
1×
1×
1×
1×
1×
1×
1×
1×
1×
1×
1×
| import Validators from './index'
import { prepareMsg, prepare, memoize, isNumber, TO_STRING } from './helpers'
// TODO doc: accept attribute on file input
const TYPE_REG = {
image: /^image\//,
video: /^video\//,
audio: /^audio\//
}
const TYPES = Object.keys(TYPE_REG)
const ERRORS = TYPES.concat(["mimeType", "extension", "tooSmall", "tooBig"])
let file = memoize(function ({
message, msg,
image, video, audio,
mimeType,
ext,
minSize,
maxSize,
'if': ifCond,
unless,
allowBlank
}={}) {
msg = msg || message
let checkTypes = { image, video, audio }
if (mimeType) {
mimeType = mimeType.split ? mimeType.split(',') : [].concat(mimeType)
}
if (ext) {
ext = ext.split ? ext.split(',') : [].concat(ext)
}
let min = null != minSize ? sizeToInt(minSize) : null
let max = null != maxSize ? sizeToInt(maxSize) : null
return prepare(ifCond, unless, false, function (value) {
let isAFileList = isFileList(value)
// special blank check
if ((null != allowBlank ? allowBlank : Validators.defaultOptions.allowBlank) && isAFileList && 0 === value.length) {
return
}
if (!isAFileList) {
return Validators.formatMessage(prepareMsg(msg, 'file'))
}
let errors = ERRORS.reduce(function(h, err) { h[err] = []; return h }, {})
for (let i = 0, len = value.length, val, ftype, fext; i < len; ++i) {
val = value[i]
ftype = val.type
TYPES.forEach(function(type) {
if (true === checkTypes[type] && !TYPE_REG[type].test(ftype)) {
errors[type].push(val)
}
});
if (mimeType && mimeType.some(function(t) { return 'string' === typeof t ? t !== ftype : !t.exec(ftype) })) {
errors.mimeType.push(val)
}
if (ext) {
fext = extension(val.name)
if (ext.some(function(e) { return 'string' === typeof e ? e !== fext : !e.exec(fext) })) {
errors.extension.push(val)
}
}
if (null != min && val.size < min) {
errors.tooSmall.push(val)
}
if (null != max && val.size > max) {
errors.tooBig.push(val)
}
}
for (let i = 0, len = ERRORS.length, err, arr, opts; i < len; ++i) {
err = ERRORS[i]
arr = errors[err]
if (arr.length) {
opts = { files: arr, count: arr.length }
if (err === 'tooSmall') {
opts.size = Validators.formatSize(parse(minSize))
}
if (err === 'tooBig') {
opts.size = Validators.formatSize(parse(maxSize))
}
return Validators.formatMessage(prepareMsg(msg, err, opts))
}
}
})
})
export default file
export function isFileList (value) {
return '[object FileList]' === TO_STRING.call(value) || '[object File]' === TO_STRING.call(value[0])
}
export function formatSize (pair) {
return pair[1] + ' ' + pair[2]
}
// private
const SIZE_REG = /^([\d\.]+)\s*([KMGTPE]?B)?$/
const SIZE_UNITS = {
B: 1,
KB: 1024,
MB: 1048576,
GB: 1073741824,
TB: 1099511627776,
PB: 1125899906842624,
EB: 1152921504606847000
}
function parse (size) {
return SIZE_REG.exec(('' + size).trim())
}
function sizeToInt (size) {
let pair = parse(size)
return pair ? pair[1] * (SIZE_UNITS[pair[2]] || 1) : null
}
function extension (filename) {
return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2)
} |