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

source-academy / js-slang / 11296882442

11 Oct 2024 05:41PM UTC coverage: 81.253% (-0.4%) from 81.61%
11296882442

Pull #1725

github

web-flow
Merge cabdfe168 into 883ffe766
Pull Request #1725: Remove Non-Det Interpreter

3379 of 4524 branches covered (74.69%)

Branch coverage included in aggregate %.

22 of 32 new or added lines in 7 files covered. (68.75%)

7 existing lines in 4 files now uncovered.

10664 of 12759 relevant lines covered (83.58%)

142972.81 hits per line

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

47.84
/src/parser/source/typed/typeParser.ts
1
// Code taken from https://github.com/patternfly/patternfly-org/blob/main/packages/ast-helpers/acorn-typescript.js
2
// Some cases such as arrow function expressions are not properly handled
3
import { getLineInfo, Parser, tokTypes } from 'acorn'
73✔
4

5
// Taken from https://github.com/acornjs/acorn/blob/6770c2ecbf8e01470f6c9a2f59c786f014045baf/acorn/src/whitespace.js#L4C1-L5C1
6
const lineBreak = /\r\n?|\n|\u2028|\u2029/
73✔
7

8
class DestructuringErrors {
9
  shorthandAssign: number
10
  trailingComma: number
11
  parenthesizedAssign: number
12
  parenthesizedBind: number
13
  doubleProto: number
14
  constructor() {
15
    this.shorthandAssign =
56✔
16
      this.trailingComma =
17
      this.parenthesizedAssign =
18
      this.parenthesizedBind =
19
      this.doubleProto =
20
        -1
21
  }
22
}
23

24
const tsPredefinedType = {
73✔
25
  any: 'TSAnyKeyword',
26
  bigint: 'TSBigIntKeyword',
27
  boolean: 'TSBooleanKeyword',
28
  never: 'TSNeverKeyword',
29
  null: 'TSNullKeyword',
30
  number: 'TSNumberKeyword',
31
  object: 'TSObjectKeyword',
32
  string: 'TSStringKeyword',
33
  symbol: 'TSSymbolKeyword',
34
  undefined: 'TSUndefinedKeyword',
35
  unknown: 'TSUnknownKeyword',
36
  void: 'TSVoidKeyword'
37
}
38

39
const tsDeclaration = {
73✔
40
  interface: 1,
41
  type: 2,
42
  enum: 4,
43
  declare: 8
44
}
45

46
const tsTypeOperator = {
73✔
47
  typeof: 1,
48
  keyof: 2,
49
  infer: 4
50
}
51

52
const tsExprMarkup = {
73✔
53
  as: 1,
54
  '!': 2
55
}
56

57
const tsPlugin = (BaseParser: any) => {
73✔
58
  return class extends BaseParser {
73✔
59
    constructor(...args: any) {
60
      super(...args)
179✔
61
      // Allow 'interface'
62
      this.reservedWords = /^(?:enum)$/
179✔
63
      this.reservedWordsStrict = this.reservedWords
179✔
64
    }
65

66
    finishNode(node: any, type: string) {
67
      if (type.startsWith('TS')) {
4,638✔
68
        // Hack to not need acorn-walk to detect TS
69
        this.options.sourceType = 'ts'
1,505✔
70
      }
71
      return this.finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc)
4,638✔
72
    }
73

74
    computeLocByOffset(offset: any) {
75
      // If `locations` option is off, do nothing for saving performance.
76
      if (this.options.locations) {
102✔
77
        return getLineInfo(this.input, offset)
100✔
78
      } else {
79
        return
2✔
80
      }
81
    }
82

83
    startNodeAtNode(node: { start: any }) {
84
      return this.startNodeAt(node.start, this.computeLocByOffset(node.start))
102✔
85
    }
86

87
    tsPreparePreview() {
88
      const {
89
        pos,
90
        curLine,
91
        type,
92
        value,
93
        end,
94
        start,
95
        endLoc,
96
        startLoc,
97
        scopeStack,
98
        lastTokStartLoc,
99
        lastTokEndLoc,
100
        lastTokEnd,
101
        lastTokStart,
102
        context
103
      } = this
30✔
104
      return () => {
30✔
105
        this.pos = pos
30✔
106
        this.curLine = curLine
30✔
107
        this.type = type
30✔
108
        this.value = value
30✔
109
        this.end = end
30✔
110
        this.start = start
30✔
111
        this.endLoc = endLoc
30✔
112
        this.startLoc = startLoc
30✔
113
        this.scopeStack = scopeStack
30✔
114
        this.lastTokStartLoc = lastTokStartLoc
30✔
115
        this.lastTokEndLoc = lastTokEndLoc
30✔
116
        this.lastTokEnd = lastTokEnd
30✔
117
        this.lastTokStart = lastTokStart
30✔
118
        this.context = context
30✔
119
      }
120
    }
121

122
    _isStartOfTypeParameters() {
123
      return this.value && this.value.charCodeAt(0) === 60 // <
1,456✔
124
    }
125

126
    _isEndOfTypeParameters() {
127
      return this.value && this.value.charCodeAt(0) === 62 // >
194✔
128
    }
129

130
    _hasPrecedingLineBreak() {
131
      return lineBreak.test(this.input.slice(this.lastTokEnd, this.start))
×
132
    }
133

134
    // Studied from Babel
135
    parseExpressionStatement(node: any, expr: any) {
136
      return expr.type === 'Identifier'
115✔
137
        ? this._parseTSDeclaration(node, expr)
138
        : super.parseExpressionStatement(node, expr)
139
    }
140

141
    parseBindingAtom() {
142
      const node = super.parseBindingAtom()
413✔
143
      if (this.eat(tokTypes.colon)) {
413✔
144
        node.typeAnnotation = this.parseTSTypeAnnotation(false)
388✔
145
        node.end = node.typeAnnotation.end
388✔
146
        if (this.options.locations) {
388✔
147
          node.loc.end = node.typeAnnotation.loc.end
384✔
148
        }
149
      }
150
      return node
413✔
151
    }
152

153
    parseMaybeDefault(
154
      startPos: any,
155
      startLoc: any,
156
      left: {
157
        optional: boolean
158
        typeAnnotation: { end: any; loc: { end: any } }
159
        end: any
160
        loc: { end: any }
161
      }
162
    ) {
163
      if (!left) {
54✔
164
        left = this.parseBindingAtom()
54✔
165
        if (this.eat(tokTypes.question)) {
54!
166
          left.optional = true
×
167
        }
168
        // `parseBindingAtom` is executed,
169
        // so we need to check type annotation again.
170
        if (this.eat(tokTypes.colon)) {
54!
171
          left.typeAnnotation = this.parseTSTypeAnnotation(false)
×
172
          left.end = left.typeAnnotation.end
×
173
          if (this.options.locations) {
×
174
            left.loc.end = left.typeAnnotation.loc.end
×
175
          }
176
        }
177
      }
178
      return super.parseMaybeDefault(startPos, startLoc, left)
54✔
179
    }
180

181
    parseMaybeAssign(
182
      noIn: boolean,
183
      refDestructuringErrors: any,
184
      afterLeftParse: (item: any) => any
185
    ) {
186
      let node = super.parseMaybeAssign(noIn, refDestructuringErrors, afterLeftParse)
1,020✔
187
      node = this._parseMaybeTSExpression(node)
1,020✔
188
      return node
1,020✔
189
    }
190

191
    parseFunctionParams(node: { typeParameters: any }) {
192
      node.typeParameters = this.parseMaybeTSTypeParameterDeclaration()
62✔
193
      return super.parseFunctionParams(node)
62✔
194
    }
195

196
    parseFunctionBody(node: { returnType: any }, isArrowFunction: any) {
197
      // I know, return type doesn't belong to function body,
198
      // but this will be less hacky.
199
      if (this.eat(tokTypes.colon)) {
82✔
200
        node.returnType = this.parseTSTypeAnnotation(false)
34✔
201
      }
202
      super.parseFunctionBody(node, isArrowFunction)
82✔
203
    }
204

205
    parseParenAndDistinguishExpression(canBeArrow: any) {
206
      const startPos = this.start
56✔
207
      const startLoc = this.startLoc
56✔
208
      const allowTrailingComma = this.options.ecmaVersion >= 8
56✔
209
      let val
210
      if (this.options.ecmaVersion >= 6) {
56!
211
        this.next()
56✔
212

213
        const innerStartPos = this.start,
56✔
214
          innerStartLoc = this.startLoc
56✔
215
        const exprList = []
56✔
216
        let first = true,
56✔
217
          lastIsComma = false
56✔
218
        const refDestructuringErrors = new DestructuringErrors(),
56✔
219
          oldYieldPos = this.yieldPos,
56✔
220
          oldAwaitPos = this.awaitPos
56✔
221
        let spreadStart
222
        this.yieldPos = 0
56✔
223
        this.awaitPos = 0
56✔
224
        // Do not save awaitIdentPos to allow checking awaits nested in parameters
225
        while (this.type !== tokTypes.parenR) {
56✔
226
          if (first) {
78✔
227
            first = false
52✔
228
          } else {
229
            this.expect(tokTypes.comma)
26✔
230
          }
231
          if (allowTrailingComma && this.afterTrailingComma(tokTypes.parenR, true)) {
78!
232
            lastIsComma = true
×
233
            break
×
234
          } else if (this.type === tokTypes.ellipsis) {
78!
235
            spreadStart = this.start
×
236
            exprList.push(this.parseParenItem(this.parseRestBinding()))
×
237
            if (this.type === tokTypes.comma)
×
238
              this.raise(this.start, 'Comma is not permitted after the rest element')
×
239
            break
×
240
          } else {
241
            exprList.push(this.parseMaybeAssign(false, refDestructuringErrors, this.parseParenItem))
78✔
242
          }
243
          if (this.type === tokTypes.colon) {
78✔
244
            this.parseTSTypeAnnotation() // Part I added
45✔
245
          }
246
        }
247
        const innerEndPos = this.start
56✔
248
        const innerEndLoc = this.startLoc
56✔
249
        this.expect(tokTypes.parenR)
56✔
250

251
        if (canBeArrow && !this.canInsertSemicolon()) {
56✔
252
          const branch = this._branch()
56✔
253
          try {
56✔
254
            if (branch.parseTSTypeAnnotation() && branch.eat(tokTypes.arrow)) {
56✔
255
              this.parseTSTypeAnnotation() // throw away type
26✔
256
            }
257
          } catch {}
258
          if (this.eat(tokTypes.arrow)) {
56✔
259
            this.checkPatternErrors(refDestructuringErrors, false)
42✔
260
            this.checkYieldAwaitInDefaultParams()
42✔
261
            this.yieldPos = oldYieldPos
42✔
262
            this.awaitPos = oldAwaitPos
42✔
263
            return this.parseParenArrowList(startPos, startLoc, exprList)
42✔
264
          }
265
        }
266

267
        if (!exprList.length || lastIsComma) this.unexpected(this.lastTokStart)
14!
268
        if (spreadStart) this.unexpected(spreadStart)
14!
269
        this.checkExpressionErrors(refDestructuringErrors, true)
14✔
270
        this.yieldPos = oldYieldPos || this.yieldPos
14✔
271
        this.awaitPos = oldAwaitPos || this.awaitPos
14✔
272

273
        if (exprList.length > 1) {
14!
274
          val = this.startNodeAt(innerStartPos, innerStartLoc)
×
275
          val.expressions = exprList
×
276
          this.finishNodeAt(val, 'SequenceExpression', innerEndPos, innerEndLoc)
×
277
        } else {
278
          val = exprList[0]
14✔
279
        }
280
      } else {
281
        val = this.parseParenExpression()
×
282
      }
283

284
      if (this.options.preserveParens) {
14!
285
        const par = this.startNodeAt(startPos, startLoc)
×
286
        par.expression = val
×
287
        return this.finishNode(par, 'ParenthesizedExpression')
×
288
      } else {
289
        return val
14✔
290
      }
291
    }
292

293
    // Fix ambiguity between BinaryExpressions and TSCallExpressions
294
    parseSubscript(base: { typeParameters: any }) {
295
      const branch = this._branch()
1,264✔
296
      if (this._isStartOfTypeParameters()) {
1,264✔
297
        // <
298
        try {
6✔
299
          // will throw if no matching >
300
          const typeParameters = branch.parseTSTypeParameterInstantiation()
6✔
301
          if (typeParameters && branch.eat(tokTypes.parenL)) {
4!
302
            // Update parser to match branch
303
            base.typeParameters = this.parseTSTypeParameterInstantiation()
×
304
          }
305
        } catch {}
306
      }
307

308
      return super.parseSubscript.apply(this, arguments)
1,264✔
309
    }
310

311
    parseExpression() {
312
      const parenthesized = this.type === tokTypes.parenL,
203✔
313
        parenStart = parenthesized ? this.start : -1
203✔
314
      let expr = super.parseExpression()
203✔
315

316
      if (parenthesized) {
203✔
317
        expr.extra = { parenthesized, parenStart }
15✔
318
        return expr
15✔
319
      }
320

321
      expr = this._parseMaybeTSExpression(expr)
188✔
322
      return expr
188✔
323
    }
324

325
    parseParenItem(item: any) {
326
      item = super.parseParenItem(item)
78✔
327
      item = this._parseMaybeTSExpression(item)
78✔
328
      return item
78✔
329
    }
330

331
    parseTSTypeAnnotation(eatColon = true) {
127✔
332
      if (eatColon) {
577✔
333
        this.expect(tokTypes.colon)
127✔
334
      }
335
      const node = this.startNodeAt(this.lastTokStart, this.lastTokStartLoc)
547✔
336
      this._parseTSTypeAnnotation(node)
547✔
337
      return this.finishNode(node, 'TSTypeAnnotation')
547✔
338
    }
339

340
    _parseTSType() {
341
      const node = this._parseNonConditionalType()
668✔
342
      if (this.type === tokTypes._extends && !this._hasPrecedingLineBreak()) {
668!
343
        return this.parseTSConditionalType(node)
×
344
      }
345
      return node
668✔
346
    }
347

348
    _parseTSTypeAnnotation(node: { typeAnnotation: any }) {
349
      node.typeAnnotation = this._parseTSType()
583✔
350
    }
351

352
    _parsePrimaryType() {
353
      let node
354
      switch (this.type) {
725!
355
        case tokTypes.name:
356
          node =
678✔
357
            this.value in tsPredefinedType
678✔
358
              ? this.parseTSPredefinedType()
359
              : this.parseTSTypeReference()
360
          break
678✔
361
        case tokTypes.braceL:
362
          node = this.parseTSTypeLiteral()
×
363
          break
×
364
        case tokTypes._void:
365
        case tokTypes._null:
366
          node = this.parseTSPredefinedType()
17✔
367
          break
17✔
368
        case tokTypes.parenL:
369
          node = this.parseTSParenthesizedType()
×
370
          break
×
371
        case tokTypes.bracketL:
372
          node = this.parseTSTupleType()
×
373
          break
×
374
        case tokTypes.num:
375
        case tokTypes.string:
376
        case tokTypes._true:
377
        case tokTypes._false:
378
          node = this.parseTSLiteralType(this.type)
30✔
379
          break
30✔
380
        case tokTypes._import:
381
          node = this.parseTSImportType(false)
×
382
          break
×
383
        default:
384
          return
×
385
      }
386

387
      while (this.type === tokTypes.bracketL) {
725✔
388
        node = this._parseMaybeTSArrayType(node)
19✔
389
      }
390

391
      return node
725✔
392
    }
393

394
    _parseNonConditionalType() {
395
      let node
396
      switch (this.type) {
668!
397
        case tokTypes.name:
398
          switch (tsTypeOperator[this.value]) {
604!
399
            case tsTypeOperator.infer:
400
              node = this.parseTSInferType()
×
401
              break
×
402
            case tsTypeOperator.keyof:
403
              node = this.parseTSKeyofType()
×
404
              break
×
405
            default:
406
              node = this._parseTSUnionTypeOrIntersectionType()
604✔
407
          }
408
          break
604✔
409
        case tokTypes._new:
410
          node = this.parseTSConstructorType()
×
411
          break
×
412
        case tokTypes.parenL:
413
          const recover = this.tsPreparePreview()
30✔
414
          const isStartOfTSFunctionType = this._isStartOfTSFunctionType()
30✔
415
          recover()
30✔
416
          node = isStartOfTSFunctionType
30✔
417
            ? this.parseTSFunctionType()
418
            : this.parseTSParenthesizedType()
419
          break
30✔
420
        case tokTypes.relational:
421
          node = this._isStartOfTypeParameters() ? this.parseTSFunctionType() : this.unexpected()
×
422
          break
×
423
        case tokTypes._typeof:
424
          node = this.parseTSTypeofType()
×
425
          break
×
426
        default:
427
          node = this._parseTSUnionTypeOrIntersectionType()
34✔
428
          break
34✔
429
      }
430
      return node || this.unexpected()
668!
431
    }
432

433
    _parseTSDeclaration(node: any, expr: { name: string | number }) {
434
      const val = tsDeclaration[expr.name]
30✔
435
      switch (val) {
30!
436
        case tsDeclaration.interface:
437
          if (this.type === tokTypes.name) {
×
438
            return this.parseTSInterfaceDeclaration()
×
439
          }
440
          break
×
441
        case tsDeclaration.type:
442
          if (this.type === tokTypes.name) {
25✔
443
            return this.parseTSTypeAliasDeclaration()
25✔
444
          }
445
          break
×
446
        default:
447
          break
5✔
448
      }
449
      return super.parseExpressionStatement(node, expr)
5✔
450
    }
451

452
    parseTSTypeReference() {
453
      const node = this.startNode()
77✔
454
      let typeName = this.parseIdent()
77✔
455
      if (this.type === tokTypes.dot) {
77!
456
        typeName = this.parseTSQualifiedName(typeName)
×
457
      }
458
      node.typeName = typeName
77✔
459
      if (this._isStartOfTypeParameters()) {
77✔
460
        node.typeParameters = this.parseTSTypeParameterInstantiation()
58✔
461
      }
462
      this.finishNode(node, 'TSTypeReference')
77✔
463
      return node
77✔
464
    }
465

466
    parseTSPredefinedType() {
467
      const node = this.startNode()
618✔
468
      const keyword = this.value
618✔
469
      this.next()
618✔
470
      this.finishNode(node, tsPredefinedType[keyword])
618✔
471
      return node
618✔
472
    }
473

474
    parseTSLiteralType(tokType: any) {
475
      const node = this.startNode()
30✔
476
      const literal = this.parseLiteral(this.value)
30✔
477
      if (tokType === tokTypes._true || tokType === tokTypes._false) {
30✔
478
        literal.value = tokType === tokTypes._true
6✔
479
      }
480
      node.literal = literal
30✔
481
      return this.finishNode(node, 'TSLiteralType')
30✔
482
    }
483

484
    parseTSTupleType() {
485
      const node = this.startNode()
×
486
      const elementTypes = []
×
487
      this.eat(tokTypes.bracketL)
×
488
      let first = true
×
489
      while (!this.eat(tokTypes.bracketR)) {
×
NEW
490
        if (first) {
×
NEW
491
          first = false
×
492
        } else {
NEW
493
          this.expect(tokTypes.comma)
×
494
        }
UNCOV
495
        switch (this.type) {
×
496
          case tokTypes.name:
497
            const elem = this.parseTSTypeReference()
×
498
            if (this.type === tokTypes.question) {
×
499
              elementTypes.push(this.parseTSOptionalType(elem))
×
500
            } else {
501
              elementTypes.push(elem)
×
502
            }
503
            break
×
504
          case tokTypes.ellipsis:
505
            elementTypes.push(this.parseTSRestType())
×
506
            break
×
507
          case tokTypes.bracketR:
508
            break
×
509
          default:
510
            this.unexpected()
×
511
        }
512
      }
513
      node.elementTypes = elementTypes
×
514
      return this.finishNode(node, 'TSTupleType')
×
515
    }
516

517
    parseTSOptionalType(typeRef: any) {
518
      const node = this.startNodeAt(this.lastTokStart, this.lastTokStartLoc)
×
519
      this.expect(tokTypes.question)
×
520
      node.typeAnnotation = typeRef
×
521
      return this.finishNode(node, 'TSOptionalType')
×
522
    }
523

524
    parseTSRestType() {
525
      const node = this.startNode()
×
526
      this.expect(tokTypes.ellipsis)
×
527
      this._parseTSTypeAnnotation(node)
×
528
      return this.finishNode(node, 'TSRestType')
×
529
    }
530

531
    _parseMaybeTSArrayType(prev: any): any {
532
      const node = this.startNodeAtNode(prev)
19✔
533
      this.expect(tokTypes.bracketL)
19✔
534
      if (this.eat(tokTypes.bracketR)) {
19✔
535
        return this.parseTSArrayType(node, prev)
19✔
536
      }
537
      return this.parseTSIndexedAccessType(node, prev)
×
538
    }
539

540
    parseTSArrayType(node: { elementType: any }, elementType: any) {
541
      node.elementType = elementType
19✔
542
      return this.finishNode(node, 'TSArrayType')
19✔
543
    }
544

545
    parseTSIndexedAccessType(node: { objectType: any; indexType: any }, objectType: any) {
546
      node.objectType = objectType
×
547
      node.indexType = this._parseTSType()
×
548
      this.expect(tokTypes.bracketR)
×
549
      if (this.type === tokTypes.bracketL) {
×
550
        return this._parseMaybeTSArrayType(node)
×
551
      }
552
      return this.finishNode(node, 'TSIndexedAccessType')
×
553
    }
554

555
    _isStartOfTSFunctionType() {
556
      this.nextToken()
30✔
557
      switch (this.type) {
30!
558
        case tokTypes.parenR:
559
        case tokTypes.ellipsis:
560
          return true
2✔
561
        case tokTypes.name:
562
        case tokTypes._this:
563
          this.nextToken()
28✔
564
          switch (this.type) {
28!
565
            case tokTypes.colon:
566
            case tokTypes.comma:
567
            case tokTypes.question:
568
              return true
26✔
569
            case tokTypes.parenR:
570
              this.nextToken()
×
571
              return this.type === tokTypes.arrow
×
572
            default:
573
              return false
2✔
574
          }
575
        case tokTypes.braceL:
576
        case tokTypes.bracketL: {
NEW
577
          if (this.type === tokTypes.braceL) {
×
NEW
578
            this.parseObj(/* isPattern */ true)
×
579
          } else {
NEW
580
            this.parseBindingAtom()
×
581
          }
582

UNCOV
583
          switch (this.type) {
×
584
            case tokTypes.colon:
585
            case tokTypes.comma:
586
            case tokTypes.question:
587
              return true
×
588
            case tokTypes.parenR:
589
              this.nextToken()
×
590
              return this.type === tokTypes.arrow
×
591
            default:
592
              return false
×
593
          }
594
        }
595
        default:
596
          return false
×
597
      }
598
    }
599

600
    parseTSFunctionType() {
601
      const node = this.startNode()
28✔
602
      const temp = Object.create(null)
28✔
603
      node.typeParameters = this.parseMaybeTSTypeParameterDeclaration()
28✔
604
      this.parseFunctionParams(temp)
28✔
605
      node.parameters = temp.params
28✔
606
      this.expect(tokTypes.arrow)
28✔
607
      node.typeAnnotation = this.parseTSTypeAnnotation(false)
28✔
608
      return this.finishNode(node, 'TSFunctionType')
28✔
609
    }
610

611
    parseTSParenthesizedType() {
612
      const node = this.startNode()
2✔
613
      this.expect(tokTypes.parenL)
2✔
614
      this._parseTSTypeAnnotation(node)
2✔
615
      this.expect(tokTypes.parenR)
2✔
616
      while (this.eat(tokTypes.bracketL)) {
2✔
617
        this.expect(tokTypes.bracketR)
3✔
618
      }
619
      return this.finishNode(node, 'TSParenthesizedType')
2✔
620
    }
621

622
    parseTSUnionType(first: any) {
623
      const node = first ? this.startNodeAtNode(first) : this.startNode()
74!
624
      const types = []
74✔
625
      if (first) types.push(first)
74✔
626
      while (this.eat(tokTypes.bitwiseOR)) {
74✔
627
        types.push(this._parseTSIntersectionTypeOrPrimaryType())
87✔
628
      }
629
      if (types.length === 1) {
74!
630
        return first
×
631
      }
632
      node.types = types
74✔
633
      return this.finishNode(node, 'TSUnionType')
74✔
634
    }
635

636
    parseTSIntersectionType(first: any) {
637
      const node = first ? this.startNodeAtNode(first) : this.startNode()
×
638
      const types = []
×
NEW
639
      if (first) types.push(first)
×
640
      while (this.eat(tokTypes.bitwiseAND)) {
×
641
        types.push(this._parsePrimaryType())
×
642
      }
643
      if (types.length === 1) {
×
644
        return first
×
645
      }
646
      node.types = types
×
647
      return this.finishNode(node, 'TSIntersectionType')
×
648
    }
649

650
    _parseTSIntersectionTypeOrPrimaryType() {
651
      this.eat(tokTypes.bitwiseAND)
725✔
652
      const node = this._parsePrimaryType()
725✔
653
      if (this.type === tokTypes.bitwiseAND) {
725!
654
        return this.parseTSIntersectionType(node)
×
655
      }
656
      return node
725✔
657
    }
658

659
    _parseTSUnionTypeOrIntersectionType() {
660
      this.eat(tokTypes.bitwiseOR)
638✔
661
      const node = this._parseTSIntersectionTypeOrPrimaryType()
638✔
662
      if (this.type === tokTypes.bitwiseOR) {
638✔
663
        return this.parseTSUnionType(node)
74✔
664
      }
665
      return node
564✔
666
    }
667

668
    parseTSConditionalType(checkType: any) {
669
      const node = this.startNodeAtNode(checkType)
×
670
      node.checkType = checkType
×
671
      this.expect(tokTypes._extends)
×
672
      node.extendsType = this._parseNonConditionalType()
×
673
      this.expect(tokTypes.question)
×
674
      node.trueType = this._parseNonConditionalType()
×
675
      this.expect(tokTypes.colon)
×
676
      node.falseType = this._parseNonConditionalType()
×
677
      return this.finishNode(node, 'TSConditionalType')
×
678
    }
679

680
    parseTSInferType() {
681
      const node = this.startNode()
×
682
      this.next()
×
683
      node.typeParameter = this.parseTSTypeParameter()
×
684
      return this.finishNode(node, 'TSInferType')
×
685
    }
686

687
    parseTSKeyofType() {
688
      const node = this.startNode()
×
689
      this.next()
×
690
      node.typeAnnotation = this.parseTSTypeAnnotation(false)
×
691
      return this.finishNode(node, 'TSTypeOperator')
×
692
    }
693

694
    parseTSTypeQuery() {
695
      const node = this.startNode()
×
696
      this.next()
×
697
      node.exprName = this.parseIdent()
×
698
      return this.finishNode(node, 'TSTypeQuery')
×
699
    }
700

701
    parseTSTypeofType() {
702
      const typeQuery = this.parseTSTypeQuery()
×
703
      if (this.eat(tokTypes.bracketL)) {
×
704
        const node = this.startNode()
×
705
        return this.parseTSIndexedAccessType(node, typeQuery)
×
706
      }
707
      return typeQuery
×
708
    }
709

710
    parseTSImportType(isTypeOf: boolean) {
711
      const node = this.startNode()
×
712
      node.isTypeOf = isTypeOf
×
713
      this.expect(tokTypes._import)
×
714
      this.expect(tokTypes.parenL)
×
715
      node.parameter = this.parseTSLiteralType(this.type)
×
716
      this.expect(tokTypes.parenR)
×
717
      if (this.eat(tokTypes.dot)) {
×
718
        let qualifier = this.parseIdent()
×
719
        if (this.type === tokTypes.dot) {
×
720
          qualifier = this.parseTSQualifiedName(qualifier)
×
721
        }
722
        node.qualifier = qualifier
×
723
      }
724
      return this.finishNode(node, 'TSImportType')
×
725
    }
726

727
    parseTSQualifiedName(left: any) {
728
      let node = this.startNodeAtNode(left)
×
729
      node.left = left
×
730
      this.expect(tokTypes.dot)
×
731
      node.right = this.parseIdent()
×
732
      node = this.finishNode(node, 'TSQualifiedName')
×
733
      if (this.type === tokTypes.dot) {
×
734
        node = this.parseTSQualifiedName(node)
×
735
      }
736
      return node
×
737
    }
738

739
    parseTSConstructorType() {
740
      const node = this.startNode()
×
741
      this.expect(tokTypes._new)
×
742
      node.typeParameters = this.parseMaybeTSTypeParameterDeclaration()
×
743
      this.expect(tokTypes.parenL)
×
744
      node.parameters = this.parseBindingList(tokTypes.parenR, false, this.options.ecmaVersion >= 8)
×
745
      this.expect(tokTypes.arrow)
×
746
      node.typeAnnotation = this.parseTSTypeAnnotation(false)
×
747
      return this.finishNode(node, 'TSConstructorType')
×
748
    }
749

750
    parseTSConstructSignatureDeclaration() {
751
      const node = this.startNode()
×
752
      this.expect(tokTypes._new)
×
753
      node.typeParameters = this.parseMaybeTSTypeParameterDeclaration()
×
754
      this.expect(tokTypes.parenL)
×
755
      node.parameters = this.parseBindingList(tokTypes.parenR, false, this.options.ecmaVersion >= 8)
×
756
      if (this.eat(tokTypes.colon)) {
×
757
        node.typeAnnotation = this.parseTSTypeAnnotation(false)
×
758
      }
759
      return this.finishNode(node, 'TSConstructSignatureDeclaration')
×
760
    }
761

762
    parseTSTypeLiteral() {
763
      return this._parseObjectLikeType('TSTypeLiteral', 'members')
×
764
    }
765

766
    parseTSTypeAliasDeclaration() {
767
      const node = this.startNodeAt(this.lastTokStart, this.lastTokStartLoc)
25✔
768
      node.id = this.parseIdent()
25✔
769
      node.typeParameters = this.parseMaybeTSTypeParameterDeclaration()
25✔
770
      this.expect(tokTypes.eq)
25✔
771
      this._parseTSTypeAnnotation(node)
25✔
772
      this.semicolon()
25✔
773
      return this.finishNode(node, 'TSTypeAliasDeclaration')
25✔
774
    }
775

776
    parseTSInterfaceDeclaration() {
777
      const node = this.startNodeAt(this.lastTokStart, this.lastTokStartLoc)
×
778
      node.id = this.parseIdent()
×
779
      node.typeParameters = this.parseMaybeTSTypeParameterDeclaration()
×
780
      if (this.eat(tokTypes._extends)) {
×
781
        const heritage = []
×
782
        do {
×
783
          heritage.push(this.parseTSExpressionWithTypeArguments())
×
784
        } while (this.eat(tokTypes.comma))
785
        node.heritage = heritage
×
786
      }
787
      node.body = this._parseObjectLikeType('TSInterfaceBody', 'body')
×
788
      this.semicolon()
×
789
      return this.finishNode(node, 'TSInterfaceDeclaration')
×
790
    }
791

792
    parseTSExpressionWithTypeArguments() {
793
      const node = this.startNode()
×
794
      let expr = this.parseIdent()
×
795
      if (this.eat(tokTypes.dot)) {
×
796
        expr = this.parseTSQualifiedName(expr)
×
797
      }
798
      node.expr = expr
×
799
      if (this._isStartOfTypeParameters()) {
×
800
        const typeParameters = this.parseTSTypeParameterInstantiation()
×
801
        node.typeParameters = typeParameters
×
802
        node.end = typeParameters.end
×
803
        if (this.options.locations) {
×
804
          node.loc.end = typeParameters.loc.end
×
805
        }
806
      }
807
      return this.finishNode(node, 'TSExpressionWithTypeArguments')
×
808
    }
809

810
    parseTSTypeParameter() {
811
      const node = this.startNode()
10✔
812
      if (this.type === tokTypes.name) {
10!
813
        node.name = this.value
10✔
814
        this.next()
10✔
815
      } else {
816
        this.unexpected()
×
817
      }
818
      if (this.eat(tokTypes._extends)) {
10!
819
        node.constraint = this._parseTSType()
×
820
      }
821
      if (this.eat(tokTypes.eq)) {
10!
822
        node.default = this._parseTSType()
×
823
      }
824
      return this.finishNode(node, 'TSTypeParameter')
10✔
825
    }
826

827
    parseMaybeTSTypeParameterDeclaration() {
828
      if (this._isStartOfTypeParameters()) {
115✔
829
        const node = this.startNode()
4✔
830
        const params = []
4✔
831
        let first = true
4✔
832
        this.next()
4✔
833
        while (!this.eat(tokTypes.relational)) {
4✔
834
          if (first) {
10✔
835
            first = false
4✔
836
          } else {
837
            this.expect(tokTypes.comma)
6✔
838
          }
839
          if (this._isEndOfTypeParameters()) {
10!
840
            break
×
841
          }
842
          params.push(this.parseTSTypeParameter())
10✔
843
        }
844
        node.params = params
4✔
845
        return this.finishNode(node, 'TSTypeParameterDeclaration')
4✔
846
      }
847
    }
848

849
    parseTSTypeParameterInstantiation() {
850
      const node = this.startNode()
64✔
851
      const params = []
64✔
852
      this.next() // <
64✔
853
      let first = true
64✔
854
      while ((this.value && !this._isEndOfTypeParameters()) || this.type === tokTypes.comma) {
64✔
855
        if (first) {
85✔
856
          first = false
62✔
857
        } else {
858
          this.expect(tokTypes.comma)
23✔
859
        }
860

861
        params.push(this._parseTSType())
85✔
862
      }
863
      if (this._isEndOfTypeParameters()) {
62✔
864
        if (this.value.length > 1) {
58✔
865
          this.value = this.value.slice(1) // Fix to allow chaining of type parameters
1✔
866
        } else {
867
          this.next() // >
57✔
868
        }
869
      }
870
      node.params = params
62✔
871
      return this.finishNode(node, 'TSTypeParameterInstantiation')
62✔
872
    }
873

874
    parseMaybeTSTypeParameterInstantiation() {
875
      if (this._isStartOfTypeParameters()) {
×
876
        return this.parseTSTypeParameterInstantiation()
×
877
      }
878
    }
879

880
    _parseObjectLikeType(kind: string, prop: string) {
881
      const node = this.startNode()
×
882
      this.expect(tokTypes.braceL)
×
883
      const list = []
×
884
      while (!this.eat(tokTypes.braceR)) {
×
885
        switch (this.type) {
×
886
          case tokTypes.name:
887
            const key = this.parseIdent()
×
888
            switch (this.type) {
×
889
              case tokTypes.parenL:
890
              case tokTypes.relational:
891
                list.push(this.parseTSMethodSignature(key))
×
892
                break
×
893
              case tokTypes.colon:
894
              case tokTypes.semi:
895
              case tokTypes.comma:
896
              case tokTypes.braceR:
897
              case tokTypes.question:
898
                list.push(this.parseTSPropertySignature(key))
×
899
                break
×
900
              default:
901
                if (this._hasPrecedingLineBreak()) {
×
902
                  list.push(this.parseTSPropertySignature(key))
×
903
                  continue
×
904
                }
905
                this.unexpected()
×
906
            }
907
            break
×
908
          case tokTypes.bracketL:
909
            const recover = this.tsPreparePreview()
×
910
            this.nextToken()
×
911
            if (this.type === tokTypes.name) {
×
912
              this.nextToken()
×
913
              switch (this.type) {
×
914
                case tokTypes.colon:
915
                  recover()
×
916
                  list.push(this.parseTSIndexSignature())
×
917
                  break
×
918
                case tokTypes._in:
919
                  if (list.length === 0) {
×
920
                    recover()
×
921
                    return this.parseTSMappedType()
×
922
                  } else {
923
                    recover()
×
924
                    list.push(this.parseTSPropertySignature(null, true))
×
925
                  }
926
                  break
×
927
                default:
928
                  recover()
×
929
                  list.push(this.parseTSPropertySignature(null, true))
×
930
              }
931
            } else {
932
              recover()
×
933
              list.push(this.parseTSPropertySignature(null, true))
×
934
            }
935
            break
×
936
          case tokTypes._new:
937
            list.push(this.parseTSConstructSignatureDeclaration())
×
938
            break
×
939
          default:
940
            this.unexpected()
×
941
        }
942
      }
943
      node[prop] = list
×
944
      return this.finishNode(node, kind)
×
945
    }
946

947
    parseTSMethodSignature(key: any) {
948
      const node = this.startNodeAtNode(key)
×
949
      node.key = key
×
950
      if (this.eat(tokTypes.question)) {
×
951
        node.optional = true
×
952
      }
953
      node.typeParameters = this.parseMaybeTSTypeParameterDeclaration()
×
954
      this.expect(tokTypes.parenL)
×
955
      node.parameters = this.parseBindingList(tokTypes.parenR, false, this.options.ecmaVersion >= 8)
×
956
      if (this.type === tokTypes.colon) {
×
957
        node.typeAnnotation = this.parseTSTypeAnnotation(true)
×
958
      }
NEW
959
      if (!this.eat(tokTypes.comma)) this.eat(tokTypes.semi)
×
960
      return this.finishNode(node, 'TSMethodSignature')
×
961
    }
962

963
    parseTSPropertySignature(key: any, computed = false) {
×
964
      let node
965
      if (computed) {
×
966
        node = this.startNode()
×
967
        this.expect(tokTypes.bracketL)
×
968
        node.key = this.parseExpression()
×
969
        this.expect(tokTypes.bracketR)
×
970
      } else {
971
        node = this.startNodeAtNode(key)
×
972
        node.key = key
×
973
      }
974
      node.computed = computed
×
975
      if (this.eat(tokTypes.question)) {
×
976
        node.optional = true
×
977
      }
978
      if (this.type === tokTypes.colon) {
×
979
        node.typeAnnotation = this.parseTSTypeAnnotation(true)
×
980
      }
NEW
981
      if (!this.eat(tokTypes.comma)) this.eat(tokTypes.semi)
×
982
      return this.finishNode(node, 'TSPropertySignature')
×
983
    }
984

985
    parseTSIndexSignature() {
986
      const node = this.startNode()
×
987
      this.expect(tokTypes.bracketL)
×
988
      const index = this.parseIdent()
×
989
      index.typeAnnotation = this.parseTSTypeAnnotation(true)
×
990
      index.end = index.typeAnnotation.end
×
991
      if (this.options.locations) {
×
992
        index.loc.end = index.typeAnnotation.loc.end
×
993
      }
994
      node.index = index
×
995
      this.expect(tokTypes.bracketR)
×
996
      node.typeAnnotation = this.parseTSTypeAnnotation(true)
×
NEW
997
      if (!this.eat(tokTypes.comma)) this.eat(tokTypes.semi)
×
998
      return this.finishNode(node, 'TSIndexSignature')
×
999
    }
1000

1001
    parseTSMappedType() {
1002
      const node = this.startNodeAt(this.lastTokStart, this.lastTokStartLoc)
×
1003
      this.expect(tokTypes.bracketL)
×
1004
      node.typeParameter = this._parseTSTypeParameterInTSMappedType()
×
1005
      this.expect(tokTypes.bracketR)
×
1006
      if (this.eat(tokTypes.question)) {
×
1007
        node.optional = true
×
1008
      }
1009
      if (this.type === tokTypes.colon) {
×
1010
        node.typeAnnotation = this.parseTSTypeAnnotation(true)
×
1011
      }
1012
      this.semicolon()
×
1013
      this.expect(tokTypes.braceR)
×
1014
      return this.finishNode(node, 'TSMappedType')
×
1015
    }
1016

1017
    _parseTSTypeParameterInTSMappedType() {
1018
      const node = this.startNode()
×
1019
      if (this.type === tokTypes.name) {
×
1020
        node.name = this.value
×
1021
        this.next()
×
1022
      } else {
1023
        this.unexpected()
×
1024
      }
1025
      this.expect(tokTypes._in)
×
1026
      node.constraint = this._parseNonConditionalType()
×
1027
      return this.finishNode(node, 'TSTypeParameter')
×
1028
    }
1029

1030
    _parseMaybeTSExpression(node: any) {
1031
      if (this.type === tokTypes.prefix && tsExprMarkup[this.value] === tsExprMarkup['!']) {
1,286!
1032
        node = this.parseTSNonNullExpression(node)
×
1033
      }
1034
      if (this.type === tokTypes.name && tsExprMarkup[this.value] === tsExprMarkup.as) {
1,286✔
1035
        node = this.parseTSAsExpression(node)
9✔
1036
      }
1037
      return node
1,286✔
1038
    }
1039

1040
    parseTSAsExpression(expression: any) {
1041
      let node = expression
9✔
1042
      while (this.type === tokTypes.name && tsExprMarkup[this.value] === tsExprMarkup.as) {
9✔
1043
        const _node = this.startNodeAtNode(node)
9✔
1044
        this.next()
9✔
1045
        _node.expression = node
9✔
1046
        this._parseTSTypeAnnotation(_node)
9✔
1047
        node = this.finishNode(_node, 'TSAsExpression')
9✔
1048
      }
1049
      return expression
9✔
1050
    }
1051

1052
    parseTSNonNullExpression(expression: any) {
1053
      let node = expression
×
1054
      while (this.type === tokTypes.prefix && tsExprMarkup[this.value] === tsExprMarkup['!']) {
×
1055
        const _node = this.startNodeAtNode(node)
×
1056
        _node.expression = node
×
1057
        this.next()
×
1058
        node = this.finishNode(_node, 'TSNonNullExpression')
×
1059
      }
1060
      return node
×
1061
    }
1062
  }
1063
}
1064

1065
// acorn-class-fields plugin is needed, else parsing of some function types will not work
1066
// eslint-disable-next-line @typescript-eslint/no-require-imports
1067
const TypeParser = Parser.extend(tsPlugin as any, require('acorn-class-fields'))
73✔
1068

1069
export default TypeParser
73✔
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

© 2025 Coveralls, Inc