• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict'
2
3// hoisted due to circular dependency on command.
4module.exports = argsert
5const command = require('./command')()
6const YError = require('./yerror')
7
8const positionName = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']
9function argsert (expected, callerArguments, length) {
10  // TODO: should this eventually raise an exception.
11  try {
12    // preface the argument description with "cmd", so
13    // that we can run it through yargs' command parser.
14    let position = 0
15    let parsed = { demanded: [], optional: [] }
16    if (typeof expected === 'object') {
17      length = callerArguments
18      callerArguments = expected
19    } else {
20      parsed = command.parseCommand(`cmd ${expected}`)
21    }
22    const args = [].slice.call(callerArguments)
23
24    while (args.length && args[args.length - 1] === undefined) args.pop()
25    length = length || args.length
26
27    if (length < parsed.demanded.length) {
28      throw new YError(`Not enough arguments provided. Expected ${parsed.demanded.length} but received ${args.length}.`)
29    }
30
31    const totalCommands = parsed.demanded.length + parsed.optional.length
32    if (length > totalCommands) {
33      throw new YError(`Too many arguments provided. Expected max ${totalCommands} but received ${length}.`)
34    }
35
36    parsed.demanded.forEach((demanded) => {
37      const arg = args.shift()
38      const observedType = guessType(arg)
39      const matchingTypes = demanded.cmd.filter(type => type === observedType || type === '*')
40      if (matchingTypes.length === 0) argumentTypeError(observedType, demanded.cmd, position, false)
41      position += 1
42    })
43
44    parsed.optional.forEach((optional) => {
45      if (args.length === 0) return
46      const arg = args.shift()
47      const observedType = guessType(arg)
48      const matchingTypes = optional.cmd.filter(type => type === observedType || type === '*')
49      if (matchingTypes.length === 0) argumentTypeError(observedType, optional.cmd, position, true)
50      position += 1
51    })
52  } catch (err) {
53    console.warn(err.stack)
54  }
55}
56
57function guessType (arg) {
58  if (Array.isArray(arg)) {
59    return 'array'
60  } else if (arg === null) {
61    return 'null'
62  }
63  return typeof arg
64}
65
66function argumentTypeError (observedType, allowedTypes, position, optional) {
67  throw new YError(`Invalid ${positionName[position] || 'manyith'} argument. Expected ${allowedTypes.join(' or ')} but received ${observedType}.`)
68}
69