index.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. /* globals window, HTMLElement */
  2. 'use strict';
  3. /**!
  4. * is
  5. * the definitive JavaScript type testing library
  6. *
  7. * @copyright 2013-2014 Enrico Marino / Jordan Harband
  8. * @license MIT
  9. */
  10. var objProto = Object.prototype;
  11. var owns = objProto.hasOwnProperty;
  12. var toStr = objProto.toString;
  13. var symbolValueOf;
  14. if (typeof Symbol === 'function') {
  15. symbolValueOf = Symbol.prototype.valueOf;
  16. }
  17. var isActualNaN = function (value) {
  18. return value !== value;
  19. };
  20. var NON_HOST_TYPES = {
  21. 'boolean': 1,
  22. number: 1,
  23. string: 1,
  24. undefined: 1
  25. };
  26. var base64Regex = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$/;
  27. var hexRegex = /^[A-Fa-f0-9]+$/;
  28. /**
  29. * Expose `is`
  30. */
  31. var is = {};
  32. /**
  33. * Test general.
  34. */
  35. /**
  36. * is.type
  37. * Test if `value` is a type of `type`.
  38. *
  39. * @param {Mixed} value value to test
  40. * @param {String} type type
  41. * @return {Boolean} true if `value` is a type of `type`, false otherwise
  42. * @api public
  43. */
  44. is.a = is.type = function (value, type) {
  45. return typeof value === type;
  46. };
  47. /**
  48. * is.defined
  49. * Test if `value` is defined.
  50. *
  51. * @param {Mixed} value value to test
  52. * @return {Boolean} true if 'value' is defined, false otherwise
  53. * @api public
  54. */
  55. is.defined = function (value) {
  56. return typeof value !== 'undefined';
  57. };
  58. /**
  59. * is.empty
  60. * Test if `value` is empty.
  61. *
  62. * @param {Mixed} value value to test
  63. * @return {Boolean} true if `value` is empty, false otherwise
  64. * @api public
  65. */
  66. is.empty = function (value) {
  67. var type = toStr.call(value);
  68. var key;
  69. if (type === '[object Array]' || type === '[object Arguments]' || type === '[object String]') {
  70. return value.length === 0;
  71. }
  72. if (type === '[object Object]') {
  73. for (key in value) {
  74. if (owns.call(value, key)) {
  75. return false;
  76. }
  77. }
  78. return true;
  79. }
  80. return !value;
  81. };
  82. /**
  83. * is.equal
  84. * Test if `value` is equal to `other`.
  85. *
  86. * @param {Mixed} value value to test
  87. * @param {Mixed} other value to compare with
  88. * @return {Boolean} true if `value` is equal to `other`, false otherwise
  89. */
  90. is.equal = function equal(value, other) {
  91. if (value === other) {
  92. return true;
  93. }
  94. var type = toStr.call(value);
  95. var key;
  96. if (type !== toStr.call(other)) {
  97. return false;
  98. }
  99. if (type === '[object Object]') {
  100. for (key in value) {
  101. if (!is.equal(value[key], other[key]) || !(key in other)) {
  102. return false;
  103. }
  104. }
  105. for (key in other) {
  106. if (!is.equal(value[key], other[key]) || !(key in value)) {
  107. return false;
  108. }
  109. }
  110. return true;
  111. }
  112. if (type === '[object Array]') {
  113. key = value.length;
  114. if (key !== other.length) {
  115. return false;
  116. }
  117. while (key--) {
  118. if (!is.equal(value[key], other[key])) {
  119. return false;
  120. }
  121. }
  122. return true;
  123. }
  124. if (type === '[object Function]') {
  125. return value.prototype === other.prototype;
  126. }
  127. if (type === '[object Date]') {
  128. return value.getTime() === other.getTime();
  129. }
  130. return false;
  131. };
  132. /**
  133. * is.hosted
  134. * Test if `value` is hosted by `host`.
  135. *
  136. * @param {Mixed} value to test
  137. * @param {Mixed} host host to test with
  138. * @return {Boolean} true if `value` is hosted by `host`, false otherwise
  139. * @api public
  140. */
  141. is.hosted = function (value, host) {
  142. var type = typeof host[value];
  143. return type === 'object' ? !!host[value] : !NON_HOST_TYPES[type];
  144. };
  145. /**
  146. * is.instance
  147. * Test if `value` is an instance of `constructor`.
  148. *
  149. * @param {Mixed} value value to test
  150. * @return {Boolean} true if `value` is an instance of `constructor`
  151. * @api public
  152. */
  153. is.instance = is['instanceof'] = function (value, constructor) {
  154. return value instanceof constructor;
  155. };
  156. /**
  157. * is.nil / is.null
  158. * Test if `value` is null.
  159. *
  160. * @param {Mixed} value value to test
  161. * @return {Boolean} true if `value` is null, false otherwise
  162. * @api public
  163. */
  164. is.nil = is['null'] = function (value) {
  165. return value === null;
  166. };
  167. /**
  168. * is.undef / is.undefined
  169. * Test if `value` is undefined.
  170. *
  171. * @param {Mixed} value value to test
  172. * @return {Boolean} true if `value` is undefined, false otherwise
  173. * @api public
  174. */
  175. is.undef = is.undefined = function (value) {
  176. return typeof value === 'undefined';
  177. };
  178. /**
  179. * Test arguments.
  180. */
  181. /**
  182. * is.args
  183. * Test if `value` is an arguments object.
  184. *
  185. * @param {Mixed} value value to test
  186. * @return {Boolean} true if `value` is an arguments object, false otherwise
  187. * @api public
  188. */
  189. is.args = is.arguments = function (value) {
  190. var isStandardArguments = toStr.call(value) === '[object Arguments]';
  191. var isOldArguments = !is.array(value) && is.arraylike(value) && is.object(value) && is.fn(value.callee);
  192. return isStandardArguments || isOldArguments;
  193. };
  194. /**
  195. * Test array.
  196. */
  197. /**
  198. * is.array
  199. * Test if 'value' is an array.
  200. *
  201. * @param {Mixed} value value to test
  202. * @return {Boolean} true if `value` is an array, false otherwise
  203. * @api public
  204. */
  205. is.array = Array.isArray || function (value) {
  206. return toStr.call(value) === '[object Array]';
  207. };
  208. /**
  209. * is.arguments.empty
  210. * Test if `value` is an empty arguments object.
  211. *
  212. * @param {Mixed} value value to test
  213. * @return {Boolean} true if `value` is an empty arguments object, false otherwise
  214. * @api public
  215. */
  216. is.args.empty = function (value) {
  217. return is.args(value) && value.length === 0;
  218. };
  219. /**
  220. * is.array.empty
  221. * Test if `value` is an empty array.
  222. *
  223. * @param {Mixed} value value to test
  224. * @return {Boolean} true if `value` is an empty array, false otherwise
  225. * @api public
  226. */
  227. is.array.empty = function (value) {
  228. return is.array(value) && value.length === 0;
  229. };
  230. /**
  231. * is.arraylike
  232. * Test if `value` is an arraylike object.
  233. *
  234. * @param {Mixed} value value to test
  235. * @return {Boolean} true if `value` is an arguments object, false otherwise
  236. * @api public
  237. */
  238. is.arraylike = function (value) {
  239. return !!value && !is.bool(value)
  240. && owns.call(value, 'length')
  241. && isFinite(value.length)
  242. && is.number(value.length)
  243. && value.length >= 0;
  244. };
  245. /**
  246. * Test boolean.
  247. */
  248. /**
  249. * is.bool
  250. * Test if `value` is a boolean.
  251. *
  252. * @param {Mixed} value value to test
  253. * @return {Boolean} true if `value` is a boolean, false otherwise
  254. * @api public
  255. */
  256. is.bool = is['boolean'] = function (value) {
  257. return toStr.call(value) === '[object Boolean]';
  258. };
  259. /**
  260. * is.false
  261. * Test if `value` is false.
  262. *
  263. * @param {Mixed} value value to test
  264. * @return {Boolean} true if `value` is false, false otherwise
  265. * @api public
  266. */
  267. is['false'] = function (value) {
  268. return is.bool(value) && Boolean(Number(value)) === false;
  269. };
  270. /**
  271. * is.true
  272. * Test if `value` is true.
  273. *
  274. * @param {Mixed} value value to test
  275. * @return {Boolean} true if `value` is true, false otherwise
  276. * @api public
  277. */
  278. is['true'] = function (value) {
  279. return is.bool(value) && Boolean(Number(value)) === true;
  280. };
  281. /**
  282. * Test date.
  283. */
  284. /**
  285. * is.date
  286. * Test if `value` is a date.
  287. *
  288. * @param {Mixed} value value to test
  289. * @return {Boolean} true if `value` is a date, false otherwise
  290. * @api public
  291. */
  292. is.date = function (value) {
  293. return toStr.call(value) === '[object Date]';
  294. };
  295. /**
  296. * is.date.valid
  297. * Test if `value` is a valid date.
  298. *
  299. * @param {Mixed} value value to test
  300. * @returns {Boolean} true if `value` is a valid date, false otherwise
  301. */
  302. is.date.valid = function (value) {
  303. return is.date(value) && !isNaN(Number(value));
  304. };
  305. /**
  306. * Test element.
  307. */
  308. /**
  309. * is.element
  310. * Test if `value` is an html element.
  311. *
  312. * @param {Mixed} value value to test
  313. * @return {Boolean} true if `value` is an HTML Element, false otherwise
  314. * @api public
  315. */
  316. is.element = function (value) {
  317. return value !== undefined
  318. && typeof HTMLElement !== 'undefined'
  319. && value instanceof HTMLElement
  320. && value.nodeType === 1;
  321. };
  322. /**
  323. * Test error.
  324. */
  325. /**
  326. * is.error
  327. * Test if `value` is an error object.
  328. *
  329. * @param {Mixed} value value to test
  330. * @return {Boolean} true if `value` is an error object, false otherwise
  331. * @api public
  332. */
  333. is.error = function (value) {
  334. return toStr.call(value) === '[object Error]';
  335. };
  336. /**
  337. * Test function.
  338. */
  339. /**
  340. * is.fn / is.function (deprecated)
  341. * Test if `value` is a function.
  342. *
  343. * @param {Mixed} value value to test
  344. * @return {Boolean} true if `value` is a function, false otherwise
  345. * @api public
  346. */
  347. is.fn = is['function'] = function (value) {
  348. var isAlert = typeof window !== 'undefined' && value === window.alert;
  349. if (isAlert) {
  350. return true;
  351. }
  352. var str = toStr.call(value);
  353. return str === '[object Function]' || str === '[object GeneratorFunction]' || str === '[object AsyncFunction]';
  354. };
  355. /**
  356. * Test number.
  357. */
  358. /**
  359. * is.number
  360. * Test if `value` is a number.
  361. *
  362. * @param {Mixed} value value to test
  363. * @return {Boolean} true if `value` is a number, false otherwise
  364. * @api public
  365. */
  366. is.number = function (value) {
  367. return toStr.call(value) === '[object Number]';
  368. };
  369. /**
  370. * is.infinite
  371. * Test if `value` is positive or negative infinity.
  372. *
  373. * @param {Mixed} value value to test
  374. * @return {Boolean} true if `value` is positive or negative Infinity, false otherwise
  375. * @api public
  376. */
  377. is.infinite = function (value) {
  378. return value === Infinity || value === -Infinity;
  379. };
  380. /**
  381. * is.decimal
  382. * Test if `value` is a decimal number.
  383. *
  384. * @param {Mixed} value value to test
  385. * @return {Boolean} true if `value` is a decimal number, false otherwise
  386. * @api public
  387. */
  388. is.decimal = function (value) {
  389. return is.number(value) && !isActualNaN(value) && !is.infinite(value) && value % 1 !== 0;
  390. };
  391. /**
  392. * is.divisibleBy
  393. * Test if `value` is divisible by `n`.
  394. *
  395. * @param {Number} value value to test
  396. * @param {Number} n dividend
  397. * @return {Boolean} true if `value` is divisible by `n`, false otherwise
  398. * @api public
  399. */
  400. is.divisibleBy = function (value, n) {
  401. var isDividendInfinite = is.infinite(value);
  402. var isDivisorInfinite = is.infinite(n);
  403. var isNonZeroNumber = is.number(value) && !isActualNaN(value) && is.number(n) && !isActualNaN(n) && n !== 0;
  404. return isDividendInfinite || isDivisorInfinite || (isNonZeroNumber && value % n === 0);
  405. };
  406. /**
  407. * is.integer
  408. * Test if `value` is an integer.
  409. *
  410. * @param value to test
  411. * @return {Boolean} true if `value` is an integer, false otherwise
  412. * @api public
  413. */
  414. is.integer = is['int'] = function (value) {
  415. return is.number(value) && !isActualNaN(value) && value % 1 === 0;
  416. };
  417. /**
  418. * is.maximum
  419. * Test if `value` is greater than 'others' values.
  420. *
  421. * @param {Number} value value to test
  422. * @param {Array} others values to compare with
  423. * @return {Boolean} true if `value` is greater than `others` values
  424. * @api public
  425. */
  426. is.maximum = function (value, others) {
  427. if (isActualNaN(value)) {
  428. throw new TypeError('NaN is not a valid value');
  429. } else if (!is.arraylike(others)) {
  430. throw new TypeError('second argument must be array-like');
  431. }
  432. var len = others.length;
  433. while (--len >= 0) {
  434. if (value < others[len]) {
  435. return false;
  436. }
  437. }
  438. return true;
  439. };
  440. /**
  441. * is.minimum
  442. * Test if `value` is less than `others` values.
  443. *
  444. * @param {Number} value value to test
  445. * @param {Array} others values to compare with
  446. * @return {Boolean} true if `value` is less than `others` values
  447. * @api public
  448. */
  449. is.minimum = function (value, others) {
  450. if (isActualNaN(value)) {
  451. throw new TypeError('NaN is not a valid value');
  452. } else if (!is.arraylike(others)) {
  453. throw new TypeError('second argument must be array-like');
  454. }
  455. var len = others.length;
  456. while (--len >= 0) {
  457. if (value > others[len]) {
  458. return false;
  459. }
  460. }
  461. return true;
  462. };
  463. /**
  464. * is.nan
  465. * Test if `value` is not a number.
  466. *
  467. * @param {Mixed} value value to test
  468. * @return {Boolean} true if `value` is not a number, false otherwise
  469. * @api public
  470. */
  471. is.nan = function (value) {
  472. return !is.number(value) || value !== value;
  473. };
  474. /**
  475. * is.even
  476. * Test if `value` is an even number.
  477. *
  478. * @param {Number} value value to test
  479. * @return {Boolean} true if `value` is an even number, false otherwise
  480. * @api public
  481. */
  482. is.even = function (value) {
  483. return is.infinite(value) || (is.number(value) && value === value && value % 2 === 0);
  484. };
  485. /**
  486. * is.odd
  487. * Test if `value` is an odd number.
  488. *
  489. * @param {Number} value value to test
  490. * @return {Boolean} true if `value` is an odd number, false otherwise
  491. * @api public
  492. */
  493. is.odd = function (value) {
  494. return is.infinite(value) || (is.number(value) && value === value && value % 2 !== 0);
  495. };
  496. /**
  497. * is.ge
  498. * Test if `value` is greater than or equal to `other`.
  499. *
  500. * @param {Number} value value to test
  501. * @param {Number} other value to compare with
  502. * @return {Boolean}
  503. * @api public
  504. */
  505. is.ge = function (value, other) {
  506. if (isActualNaN(value) || isActualNaN(other)) {
  507. throw new TypeError('NaN is not a valid value');
  508. }
  509. return !is.infinite(value) && !is.infinite(other) && value >= other;
  510. };
  511. /**
  512. * is.gt
  513. * Test if `value` is greater than `other`.
  514. *
  515. * @param {Number} value value to test
  516. * @param {Number} other value to compare with
  517. * @return {Boolean}
  518. * @api public
  519. */
  520. is.gt = function (value, other) {
  521. if (isActualNaN(value) || isActualNaN(other)) {
  522. throw new TypeError('NaN is not a valid value');
  523. }
  524. return !is.infinite(value) && !is.infinite(other) && value > other;
  525. };
  526. /**
  527. * is.le
  528. * Test if `value` is less than or equal to `other`.
  529. *
  530. * @param {Number} value value to test
  531. * @param {Number} other value to compare with
  532. * @return {Boolean} if 'value' is less than or equal to 'other'
  533. * @api public
  534. */
  535. is.le = function (value, other) {
  536. if (isActualNaN(value) || isActualNaN(other)) {
  537. throw new TypeError('NaN is not a valid value');
  538. }
  539. return !is.infinite(value) && !is.infinite(other) && value <= other;
  540. };
  541. /**
  542. * is.lt
  543. * Test if `value` is less than `other`.
  544. *
  545. * @param {Number} value value to test
  546. * @param {Number} other value to compare with
  547. * @return {Boolean} if `value` is less than `other`
  548. * @api public
  549. */
  550. is.lt = function (value, other) {
  551. if (isActualNaN(value) || isActualNaN(other)) {
  552. throw new TypeError('NaN is not a valid value');
  553. }
  554. return !is.infinite(value) && !is.infinite(other) && value < other;
  555. };
  556. /**
  557. * is.within
  558. * Test if `value` is within `start` and `finish`.
  559. *
  560. * @param {Number} value value to test
  561. * @param {Number} start lower bound
  562. * @param {Number} finish upper bound
  563. * @return {Boolean} true if 'value' is is within 'start' and 'finish'
  564. * @api public
  565. */
  566. is.within = function (value, start, finish) {
  567. if (isActualNaN(value) || isActualNaN(start) || isActualNaN(finish)) {
  568. throw new TypeError('NaN is not a valid value');
  569. } else if (!is.number(value) || !is.number(start) || !is.number(finish)) {
  570. throw new TypeError('all arguments must be numbers');
  571. }
  572. var isAnyInfinite = is.infinite(value) || is.infinite(start) || is.infinite(finish);
  573. return isAnyInfinite || (value >= start && value <= finish);
  574. };
  575. /**
  576. * Test object.
  577. */
  578. /**
  579. * is.object
  580. * Test if `value` is an object.
  581. *
  582. * @param {Mixed} value value to test
  583. * @return {Boolean} true if `value` is an object, false otherwise
  584. * @api public
  585. */
  586. is.object = function (value) {
  587. return toStr.call(value) === '[object Object]';
  588. };
  589. /**
  590. * is.primitive
  591. * Test if `value` is a primitive.
  592. *
  593. * @param {Mixed} value value to test
  594. * @return {Boolean} true if `value` is a primitive, false otherwise
  595. * @api public
  596. */
  597. is.primitive = function isPrimitive(value) {
  598. if (!value) {
  599. return true;
  600. }
  601. if (typeof value === 'object' || is.object(value) || is.fn(value) || is.array(value)) {
  602. return false;
  603. }
  604. return true;
  605. };
  606. /**
  607. * is.hash
  608. * Test if `value` is a hash - a plain object literal.
  609. *
  610. * @param {Mixed} value value to test
  611. * @return {Boolean} true if `value` is a hash, false otherwise
  612. * @api public
  613. */
  614. is.hash = function (value) {
  615. return is.object(value) && value.constructor === Object && !value.nodeType && !value.setInterval;
  616. };
  617. /**
  618. * Test regexp.
  619. */
  620. /**
  621. * is.regexp
  622. * Test if `value` is a regular expression.
  623. *
  624. * @param {Mixed} value value to test
  625. * @return {Boolean} true if `value` is a regexp, false otherwise
  626. * @api public
  627. */
  628. is.regexp = function (value) {
  629. return toStr.call(value) === '[object RegExp]';
  630. };
  631. /**
  632. * Test string.
  633. */
  634. /**
  635. * is.string
  636. * Test if `value` is a string.
  637. *
  638. * @param {Mixed} value value to test
  639. * @return {Boolean} true if 'value' is a string, false otherwise
  640. * @api public
  641. */
  642. is.string = function (value) {
  643. return toStr.call(value) === '[object String]';
  644. };
  645. /**
  646. * Test base64 string.
  647. */
  648. /**
  649. * is.base64
  650. * Test if `value` is a valid base64 encoded string.
  651. *
  652. * @param {Mixed} value value to test
  653. * @return {Boolean} true if 'value' is a base64 encoded string, false otherwise
  654. * @api public
  655. */
  656. is.base64 = function (value) {
  657. return is.string(value) && (!value.length || base64Regex.test(value));
  658. };
  659. /**
  660. * Test base64 string.
  661. */
  662. /**
  663. * is.hex
  664. * Test if `value` is a valid hex encoded string.
  665. *
  666. * @param {Mixed} value value to test
  667. * @return {Boolean} true if 'value' is a hex encoded string, false otherwise
  668. * @api public
  669. */
  670. is.hex = function (value) {
  671. return is.string(value) && (!value.length || hexRegex.test(value));
  672. };
  673. /**
  674. * is.symbol
  675. * Test if `value` is an ES6 Symbol
  676. *
  677. * @param {Mixed} value value to test
  678. * @return {Boolean} true if `value` is a Symbol, false otherise
  679. * @api public
  680. */
  681. is.symbol = function (value) {
  682. return typeof Symbol === 'function' && toStr.call(value) === '[object Symbol]' && typeof symbolValueOf.call(value) === 'symbol';
  683. };
  684. module.exports = is;