validation.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // validation-type-stuff, missing params,
  2. // bad implications, custom checks.
  3. module.exports = function (yargs, usage) {
  4. var self = {}
  5. // validate appropriate # of non-option
  6. // arguments were provided, i.e., '_'.
  7. self.nonOptionCount = function (argv) {
  8. var demanded = yargs.getDemanded()
  9. if (demanded._ && argv._.length < demanded._.count) {
  10. if (demanded._.msg !== undefined) {
  11. usage.fail(demanded._.msg)
  12. } else {
  13. usage.fail('Not enough non-option arguments: got '
  14. + argv._.length + ', need at least ' + demanded._.count
  15. )
  16. }
  17. }
  18. }
  19. // make sure that any args that require an
  20. // value (--foo=bar), have a value.
  21. self.missingArgumentValue = function (argv) {
  22. var options = yargs.getOptions(),
  23. defaultValues = [true, false, '']
  24. if (options.requiresArg.length > 0) {
  25. var missingRequiredArgs = []
  26. options.requiresArg.forEach(function (key) {
  27. var value = argv[key]
  28. // if a value is explicitly requested,
  29. // flag argument as missing if it does not
  30. // look like foo=bar was entered.
  31. if (~defaultValues.indexOf(value)
  32. || (Array.isArray(value) && !value.length)) {
  33. missingRequiredArgs.push(key)
  34. }
  35. })
  36. if (missingRequiredArgs.length === 1) {
  37. usage.fail('Missing argument value: ' + missingRequiredArgs[0])
  38. } else if (missingRequiredArgs.length > 1) {
  39. var message = 'Missing argument values: ' + missingRequiredArgs.join(', ')
  40. usage.fail(message)
  41. }
  42. }
  43. }
  44. // make sure all the required arguments are present.
  45. self.requiredArguments = function (argv) {
  46. var demanded = yargs.getDemanded(),
  47. missing = null
  48. Object.keys(demanded).forEach(function (key) {
  49. if (!argv.hasOwnProperty(key)) {
  50. missing = missing || {}
  51. missing[key] = demanded[key]
  52. }
  53. })
  54. if (missing) {
  55. var customMsgs = []
  56. Object.keys(missing).forEach(function (key) {
  57. var msg = missing[key].msg
  58. if (msg && customMsgs.indexOf(msg) < 0) {
  59. customMsgs.push(msg)
  60. }
  61. })
  62. var customMsg = customMsgs.length ? '\n' + customMsgs.join('\n') : ''
  63. usage.fail('Missing required arguments: ' + Object.keys(missing).join(', ') + customMsg)
  64. }
  65. }
  66. // check for unknown arguments (strict-mode).
  67. self.unknownArguments = function (argv, aliases) {
  68. var descriptions = usage.getDescriptions(),
  69. demanded = yargs.getDemanded(),
  70. unknown = [],
  71. aliasLookup = {}
  72. Object.keys(aliases).forEach(function (key) {
  73. aliases[key].forEach(function (alias) {
  74. aliasLookup[alias] = key
  75. })
  76. })
  77. Object.keys(argv).forEach(function (key) {
  78. if (key !== '$0' && key !== '_' &&
  79. !descriptions.hasOwnProperty(key) &&
  80. !demanded.hasOwnProperty(key) &&
  81. !aliasLookup.hasOwnProperty(key)) {
  82. unknown.push(key)
  83. }
  84. })
  85. if (unknown.length === 1) {
  86. usage.fail('Unknown argument: ' + unknown[0])
  87. } else if (unknown.length > 1) {
  88. usage.fail('Unknown arguments: ' + unknown.join(', '))
  89. }
  90. }
  91. // custom checks, added using the `check` option on yargs.
  92. var checks = []
  93. self.check = function (f) {
  94. checks.push(f)
  95. }
  96. self.customChecks = function (argv, aliases) {
  97. checks.forEach(function (f) {
  98. try {
  99. var result = f(argv, aliases)
  100. if (!result) {
  101. usage.fail('Argument check failed: ' + f.toString())
  102. } else if (typeof result === 'string') {
  103. usage.fail(result)
  104. }
  105. } catch (err) {
  106. usage.fail(err.message ? err.message : err)
  107. }
  108. })
  109. }
  110. // check implications, argument foo implies => argument bar.
  111. var implied = {}
  112. self.implies = function (key, value) {
  113. if (typeof key === 'object') {
  114. Object.keys(key).forEach(function (k) {
  115. self.implies(k, key[k])
  116. })
  117. } else {
  118. implied[key] = value
  119. }
  120. }
  121. self.getImplied = function () {
  122. return implied
  123. }
  124. self.implications = function (argv) {
  125. var implyFail = []
  126. Object.keys(implied).forEach(function (key) {
  127. var num,
  128. origKey = key,
  129. value = implied[key]
  130. // convert string '1' to number 1
  131. num = Number(key)
  132. key = isNaN(num) ? key : num
  133. if (typeof key === 'number') {
  134. // check length of argv._
  135. key = argv._.length >= key
  136. } else if (key.match(/^--no-.+/)) {
  137. // check if key doesn't exist
  138. key = key.match(/^--no-(.+)/)[1]
  139. key = !argv[key]
  140. } else {
  141. // check if key exists
  142. key = argv[key]
  143. }
  144. num = Number(value)
  145. value = isNaN(num) ? value : num
  146. if (typeof value === 'number') {
  147. value = argv._.length >= value
  148. } else if (value.match(/^--no-.+/)) {
  149. value = value.match(/^--no-(.+)/)[1]
  150. value = !argv[value]
  151. } else {
  152. value = argv[value]
  153. }
  154. if (key && !value) {
  155. implyFail.push(origKey)
  156. }
  157. })
  158. if (implyFail.length) {
  159. var msg = 'Implications failed:\n'
  160. implyFail.forEach(function (key) {
  161. msg += (' ' + key + ' -> ' + implied[key])
  162. })
  163. usage.fail(msg)
  164. }
  165. }
  166. return self
  167. }