• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jeffijoe / awilix / 11006888653

24 Sep 2024 04:16AM UTC coverage: 100.0%. Remained the same
11006888653

Pull #370

github

web-flow
Merge f72908f4f into 7acf6578d
Pull Request #370: build(deps-dev): bump rollup from 4.21.0 to 4.22.4

258 of 258 branches covered (100.0%)

513 of 513 relevant lines covered (100.0%)

287.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/param-parser.ts
1
import { createTokenizer, Token, TokenizerFlags } from './function-tokenizer'
20✔
2

3
/**
4
 * A parameter for a function.
5
 */
6
export interface Parameter {
7
  /**
8
   * Parameter name.
9
   */
10
  name: string
11
  /**
12
   * True if the parameter is optional.
13
   */
14
  optional: boolean
15
}
16

17
/*
18
 * Parses the parameter list of a function string, including ES6 class constructors.
19
 *
20
 * @param {string} source
21
 * The source of a function to extract the parameter list from
22
 *
23
 * @return {Array<Parameter> | null}
24
 * Returns an array of parameters, or `null` if no
25
 * constructor was found for a class.
26
 */
27
export function parseParameterList(source: string): Array<Parameter> | null {
20✔
28
  const { next: _next, done } = createTokenizer(source)
370✔
29
  const params: Array<Parameter> = []
370✔
30

31
  let t: Token = null!
370✔
32
  nextToken()
370✔
33
  while (!done()) {
370✔
34
    switch (t.type) {
838✔
35
      case 'class':
36
        skipUntilConstructor()
126✔
37
        // If we didn't find a constructor token, then we know that there
38
        // are no dependencies in the defined class.
39
        if (!isConstructorToken()) {
126✔
40
          return null
56✔
41
        }
42
        // Next token is the constructor identifier.
43
        nextToken()
70✔
44
        break
70✔
45
      case 'function': {
46
        const next = nextToken()
82✔
47
        if (next.type === 'ident' || next.type === '*') {
82✔
48
          // This is the function name or a generator star. Skip it.
49
          nextToken()
20✔
50
        }
51
        break
82✔
52
      }
53
      case '(':
54
        // Start parsing parameter names.
55
        parseParams()
308✔
56
        break
308✔
57
      case ')':
58
        // We're now out of the parameter list.
59
        return params
308✔
60
      case 'ident': {
61
        // Likely a paren-less arrow function
62
        // which can have no default args.
63
        const param = { name: t.value!, optional: false }
14✔
64
        if (t.value === 'async') {
14✔
65
          // Given it's the very first token, we can assume it's an async function,
66
          // so skip the async keyword if the next token is not an equals sign, in which
67
          // case it is a single-arg arrow func.
68
          const next = nextToken()
12✔
69
          if (next && next.type !== '=') {
12✔
70
            break
10✔
71
          }
72
        }
73
        params.push(param)
4✔
74
        return params
4✔
75
      }
76
      /* istanbul ignore next */
77
      default:
78
        throw unexpected()
79
    }
80
  }
81

82
  return params
2✔
83

84
  /**
85
   * After having been placed within the parameter list of
86
   * a function, parses the parameters.
87
   */
88
  function parseParams() {
89
    // Current token is a left-paren
90
    let param: Parameter = { name: '', optional: false }
308✔
91
    while (!done()) {
308✔
92
      nextToken()
664✔
93
      switch (t.type) {
664✔
94
        case 'ident':
95
          param.name = t.value!
274✔
96
          break
274✔
97
        case '=':
98
          param.optional = true
20✔
99
          break
20✔
100
        case ',':
101
          params.push(param)
62✔
102
          param = { name: '', optional: false }
62✔
103
          break
62✔
104
        case ')':
105
          if (param.name) {
308✔
106
            params.push(param)
210✔
107
          }
108
          return
308✔
109
        /* istanbul ignore next */
110
        default:
111
          throw unexpected()
112
      }
113
    }
114
  }
115

116
  /**
117
   * Skips until we reach the constructor identifier.
118
   */
119
  function skipUntilConstructor() {
120
    while (!isConstructorToken() && !done()) {
126✔
121
      nextToken(TokenizerFlags.Dumb)
496✔
122
    }
123
  }
124

125
  /**
126
   * Determines if the current token represents a constructor, and the next token after it is a paren
127
   * @return {boolean}
128
   */
129
  function isConstructorToken(): boolean {
130
    return t.type === 'ident' && t.value === 'constructor'
748✔
131
  }
132

133
  /**
134
   * Advances the tokenizer and stores the previous token in history
135
   */
136
  function nextToken(flags = TokenizerFlags.None) {
609✔
137
    t = _next(flags)
1,714✔
138
    return t
1,714✔
139
  }
140

141
  /**
142
   * Returns an error describing an unexpected token.
143
   */
144
  /* istanbul ignore next */
145
  function unexpected() {
146
    return new SyntaxError(
147
      `Parsing parameter list, did not expect ${t.type} token${
148
        t.value ? ` (${t.value})` : ''
149
      }`,
150
    )
151
  }
152
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc