assert.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // Copyright (c) 2012, Mark Cavage. All rights reserved.
  2. var assert = require('assert');
  3. var Stream = require('stream').Stream;
  4. var util = require('util');
  5. ///--- Globals
  6. var NDEBUG = process.env.NODE_NDEBUG || false;
  7. var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
  8. ///--- Messages
  9. var ARRAY_TYPE_REQUIRED = '%s ([%s]) required';
  10. var TYPE_REQUIRED = '%s (%s) is required';
  11. ///--- Internal
  12. function capitalize(str) {
  13. return (str.charAt(0).toUpperCase() + str.slice(1));
  14. }
  15. function uncapitalize(str) {
  16. return (str.charAt(0).toLowerCase() + str.slice(1));
  17. }
  18. function _() {
  19. return (util.format.apply(util, arguments));
  20. }
  21. function _assert(arg, type, name, stackFunc) {
  22. if (!NDEBUG) {
  23. name = name || type;
  24. stackFunc = stackFunc || _assert.caller;
  25. var t = typeof (arg);
  26. if (t !== type) {
  27. throw new assert.AssertionError({
  28. message: _(TYPE_REQUIRED, name, type),
  29. actual: t,
  30. expected: type,
  31. operator: '===',
  32. stackStartFunction: stackFunc
  33. });
  34. }
  35. }
  36. }
  37. function _instanceof(arg, type, name, stackFunc) {
  38. if (!NDEBUG) {
  39. name = name || type;
  40. stackFunc = stackFunc || _instanceof.caller;
  41. if (!(arg instanceof type)) {
  42. throw new assert.AssertionError({
  43. message: _(TYPE_REQUIRED, name, type.name),
  44. actual: _getClass(arg),
  45. expected: type.name,
  46. operator: 'instanceof',
  47. stackStartFunction: stackFunc
  48. });
  49. }
  50. }
  51. }
  52. function _getClass(object) {
  53. return (Object.prototype.toString.call(object).slice(8, -1));
  54. };
  55. ///--- API
  56. function array(arr, type, name) {
  57. if (!NDEBUG) {
  58. name = name || type;
  59. if (!Array.isArray(arr)) {
  60. throw new assert.AssertionError({
  61. message: _(ARRAY_TYPE_REQUIRED, name, type),
  62. actual: typeof (arr),
  63. expected: 'array',
  64. operator: 'Array.isArray',
  65. stackStartFunction: array.caller
  66. });
  67. }
  68. for (var i = 0; i < arr.length; i++) {
  69. _assert(arr[i], type, name, array);
  70. }
  71. }
  72. }
  73. function bool(arg, name) {
  74. _assert(arg, 'boolean', name, bool);
  75. }
  76. function buffer(arg, name) {
  77. if (!Buffer.isBuffer(arg)) {
  78. throw new assert.AssertionError({
  79. message: _(TYPE_REQUIRED, name || '', 'Buffer'),
  80. actual: typeof (arg),
  81. expected: 'buffer',
  82. operator: 'Buffer.isBuffer',
  83. stackStartFunction: buffer
  84. });
  85. }
  86. }
  87. function func(arg, name) {
  88. _assert(arg, 'function', name);
  89. }
  90. function number(arg, name) {
  91. _assert(arg, 'number', name);
  92. if (!NDEBUG && (isNaN(arg) || !isFinite(arg))) {
  93. throw new assert.AssertionError({
  94. message: _(TYPE_REQUIRED, name, 'number'),
  95. actual: arg,
  96. expected: 'number',
  97. operator: 'isNaN',
  98. stackStartFunction: number
  99. });
  100. }
  101. }
  102. function object(arg, name) {
  103. _assert(arg, 'object', name);
  104. }
  105. function stream(arg, name) {
  106. _instanceof(arg, Stream, name);
  107. }
  108. function date(arg, name) {
  109. _instanceof(arg, Date, name);
  110. }
  111. function regexp(arg, name) {
  112. _instanceof(arg, RegExp, name);
  113. }
  114. function string(arg, name) {
  115. _assert(arg, 'string', name);
  116. }
  117. function uuid(arg, name) {
  118. string(arg, name);
  119. if (!NDEBUG && !UUID_REGEXP.test(arg)) {
  120. throw new assert.AssertionError({
  121. message: _(TYPE_REQUIRED, name, 'uuid'),
  122. actual: 'string',
  123. expected: 'uuid',
  124. operator: 'test',
  125. stackStartFunction: uuid
  126. });
  127. }
  128. }
  129. ///--- Exports
  130. module.exports = {
  131. bool: bool,
  132. buffer: buffer,
  133. date: date,
  134. func: func,
  135. number: number,
  136. object: object,
  137. regexp: regexp,
  138. stream: stream,
  139. string: string,
  140. uuid: uuid
  141. };
  142. Object.keys(module.exports).forEach(function (k) {
  143. if (k === 'buffer')
  144. return;
  145. var name = 'arrayOf' + capitalize(k);
  146. if (k === 'bool')
  147. k = 'boolean';
  148. if (k === 'func')
  149. k = 'function';
  150. module.exports[name] = function (arg, name) {
  151. array(arg, k, name);
  152. };
  153. });
  154. Object.keys(module.exports).forEach(function (k) {
  155. var _name = 'optional' + capitalize(k);
  156. var s = uncapitalize(k.replace('arrayOf', ''));
  157. if (s === 'bool')
  158. s = 'boolean';
  159. if (s === 'func')
  160. s = 'function';
  161. if (k.indexOf('arrayOf') !== -1) {
  162. module.exports[_name] = function (arg, name) {
  163. if (!NDEBUG && arg !== undefined) {
  164. array(arg, s, name);
  165. }
  166. };
  167. } else {
  168. module.exports[_name] = function (arg, name) {
  169. if (!NDEBUG && arg !== undefined) {
  170. _assert(arg, s, name);
  171. }
  172. };
  173. }
  174. });
  175. // Reexport built-in assertions
  176. Object.keys(assert).forEach(function (k) {
  177. if (k === 'AssertionError') {
  178. module.exports[k] = assert[k];
  179. return;
  180. }
  181. module.exports[k] = function () {
  182. if (!NDEBUG) {
  183. assert[k].apply(assert[k], arguments);
  184. }
  185. };
  186. });