1 |
|
2 |
|
3 | export const emptyObject = Object.freeze({})
|
4 |
|
5 |
|
6 |
|
7 | export function isUndef (v: any): boolean %checks {
|
8 | return v === undefined || v === null
|
9 | }
|
10 |
|
11 | export function isDef (v: any): boolean %checks {
|
12 | return v !== undefined && v !== null
|
13 | }
|
14 |
|
15 | export function isTrue (v: any): boolean %checks {
|
16 | return v === true
|
17 | }
|
18 |
|
19 | export function isFalse (v: any): boolean %checks {
|
20 | return v === false
|
21 | }
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | export function isPrimitive (value: any): boolean %checks {
|
27 | return (
|
28 | typeof value === 'string' ||
|
29 | typeof value === 'number' ||
|
30 |
|
31 | typeof value === 'symbol' ||
|
32 | typeof value === 'boolean'
|
33 | )
|
34 | }
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | export function isObject (obj: mixed): boolean %checks {
|
42 | return obj !== null && typeof obj === 'object'
|
43 | }
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | const _toString = Object.prototype.toString
|
49 |
|
50 | export function toRawType (value: any): string {
|
51 | return _toString.call(value).slice(8, -1)
|
52 | }
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | export function isPlainObject (obj: any): boolean {
|
59 | return _toString.call(obj) === '[object Object]'
|
60 | }
|
61 |
|
62 | export function isRegExp (v: any): boolean {
|
63 | return _toString.call(v) === '[object RegExp]'
|
64 | }
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | export function isValidArrayIndex (val: any): boolean {
|
70 | const n = parseFloat(String(val))
|
71 | return n >= 0 && Math.floor(n) === n && isFinite(val)
|
72 | }
|
73 |
|
74 | export function isPromise (val: any): boolean {
|
75 | return (
|
76 | isDef(val) &&
|
77 | typeof val.then === 'function' &&
|
78 | typeof val.catch === 'function'
|
79 | )
|
80 | }
|
81 |
|
82 |
|
83 |
|
84 |
|
85 | export function toString (val: any): string {
|
86 | return val == null
|
87 | ? ''
|
88 | : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
|
89 | ? JSON.stringify(val, null, 2)
|
90 | : String(val)
|
91 | }
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | export function toNumber (val: string): number | string {
|
98 | const n = parseFloat(val)
|
99 | return isNaN(n) ? val : n
|
100 | }
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 | export function makeMap (
|
107 | str: string,
|
108 | expectsLowerCase?: boolean
|
109 | ): (key: string) => true | void {
|
110 | const map = Object.create(null)
|
111 | const list: Array<string> = str.split(',')
|
112 | for (let i = 0; i < list.length; i++) {
|
113 | map[list[i]] = true
|
114 | }
|
115 | return expectsLowerCase
|
116 | ? val => map[val.toLowerCase()]
|
117 | : val => map[val]
|
118 | }
|
119 |
|
120 |
|
121 |
|
122 |
|
123 | export const isBuiltInTag = makeMap('slot,component', true)
|
124 |
|
125 |
|
126 |
|
127 |
|
128 | export const isReservedAttribute = makeMap('key,ref,slot,slot-scope,is')
|
129 |
|
130 |
|
131 |
|
132 |
|
133 | export function remove (arr: Array<any>, item: any): Array<any> | void {
|
134 | if (arr.length) {
|
135 | const index = arr.indexOf(item)
|
136 | if (index > -1) {
|
137 | return arr.splice(index, 1)
|
138 | }
|
139 | }
|
140 | }
|
141 |
|
142 |
|
143 |
|
144 |
|
145 | const hasOwnProperty = Object.prototype.hasOwnProperty
|
146 | export function hasOwn (obj: Object | Array<*>, key: string): boolean {
|
147 | return hasOwnProperty.call(obj, key)
|
148 | }
|
149 |
|
150 |
|
151 |
|
152 |
|
153 | export function cached<F: Function> (fn: F): F {
|
154 | const cache = Object.create(null)
|
155 | return (function cachedFn (str: string) {
|
156 | const hit = cache[str]
|
157 | return hit || (cache[str] = fn(str))
|
158 | }: any)
|
159 | }
|
160 |
|
161 |
|
162 |
|
163 |
|
164 | const camelizeRE = /-(\w)/g
|
165 | export const camelize = cached((str: string): string => {
|
166 | return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
|
167 | })
|
168 |
|
169 |
|
170 |
|
171 |
|
172 | export const capitalize = cached((str: string): string => {
|
173 | return str.charAt(0).toUpperCase() + str.slice(1)
|
174 | })
|
175 |
|
176 |
|
177 |
|
178 |
|
179 | const hyphenateRE = /\B([A-Z])/g
|
180 | export const hyphenate = cached((str: string): string => {
|
181 | return str.replace(hyphenateRE, '-$1').toLowerCase()
|
182 | })
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 | function polyfillBind (fn: Function, ctx: Object): Function {
|
194 | function boundFn (a) {
|
195 | const l = arguments.length
|
196 | return l
|
197 | ? l > 1
|
198 | ? fn.apply(ctx, arguments)
|
199 | : fn.call(ctx, a)
|
200 | : fn.call(ctx)
|
201 | }
|
202 |
|
203 | boundFn._length = fn.length
|
204 | return boundFn
|
205 | }
|
206 |
|
207 | function nativeBind (fn: Function, ctx: Object): Function {
|
208 | return fn.bind(ctx)
|
209 | }
|
210 |
|
211 | export const bind = Function.prototype.bind
|
212 | ? nativeBind
|
213 | : polyfillBind
|
214 |
|
215 |
|
216 |
|
217 |
|
218 | export function toArray (list: any, start?: number): Array<any> {
|
219 | start = start || 0
|
220 | let i = list.length - start
|
221 | const ret: Array<any> = new Array(i)
|
222 | while (i--) {
|
223 | ret[i] = list[i + start]
|
224 | }
|
225 | return ret
|
226 | }
|
227 |
|
228 |
|
229 |
|
230 |
|
231 | export function extend (to: Object, _from: ?Object): Object {
|
232 | for (const key in _from) {
|
233 | to[key] = _from[key]
|
234 | }
|
235 | return to
|
236 | }
|
237 |
|
238 |
|
239 |
|
240 |
|
241 | export function toObject (arr: Array<any>): Object {
|
242 | const res = {}
|
243 | for (let i = 0; i < arr.length; i++) {
|
244 | if (arr[i]) {
|
245 | extend(res, arr[i])
|
246 | }
|
247 | }
|
248 | return res
|
249 | }
|
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 | export function noop (a?: any, b?: any, c?: any) {}
|
259 |
|
260 |
|
261 |
|
262 |
|
263 | export const no = (a?: any, b?: any, c?: any) => false
|
264 |
|
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 | export const identity = (_: any) => _
|
271 |
|
272 |
|
273 |
|
274 |
|
275 | export function genStaticKeys (modules: Array<ModuleOptions>): string {
|
276 | return modules.reduce((keys, m) => {
|
277 | return keys.concat(m.staticKeys || [])
|
278 | }, []).join(',')
|
279 | }
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 | export function looseEqual (a: any, b: any): boolean {
|
286 | if (a === b) return true
|
287 | const isObjectA = isObject(a)
|
288 | const isObjectB = isObject(b)
|
289 | if (isObjectA && isObjectB) {
|
290 | try {
|
291 | const isArrayA = Array.isArray(a)
|
292 | const isArrayB = Array.isArray(b)
|
293 | if (isArrayA && isArrayB) {
|
294 | return a.length === b.length && a.every((e, i) => {
|
295 | return looseEqual(e, b[i])
|
296 | })
|
297 | } else if (a instanceof Date && b instanceof Date) {
|
298 | return a.getTime() === b.getTime()
|
299 | } else if (!isArrayA && !isArrayB) {
|
300 | const keysA = Object.keys(a)
|
301 | const keysB = Object.keys(b)
|
302 | return keysA.length === keysB.length && keysA.every(key => {
|
303 | return looseEqual(a[key], b[key])
|
304 | })
|
305 | } else {
|
306 |
|
307 | return false
|
308 | }
|
309 | } catch (e) {
|
310 |
|
311 | return false
|
312 | }
|
313 | } else if (!isObjectA && !isObjectB) {
|
314 | return String(a) === String(b)
|
315 | } else {
|
316 | return false
|
317 | }
|
318 | }
|
319 |
|
320 |
|
321 |
|
322 |
|
323 |
|
324 |
|
325 | export function looseIndexOf (arr: Array<mixed>, val: mixed): number {
|
326 | for (let i = 0; i < arr.length; i++) {
|
327 | if (looseEqual(arr[i], val)) return i
|
328 | }
|
329 | return -1
|
330 | }
|
331 |
|
332 |
|
333 |
|
334 |
|
335 | export function once (fn: Function): Function {
|
336 | let called = false
|
337 | return function () {
|
338 | if (!called) {
|
339 | called = true
|
340 | fn.apply(this, arguments)
|
341 | }
|
342 | }
|
343 | }
|