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

jsdoc-type-pratt-parser / jsdoc-type-pratt-parser / 17509961174

06 Sep 2025 04:26AM UTC coverage: 98.559% (-0.08%) from 98.639%
17509961174

push

github

brettz9
feat(typescript): allow missing return type; fixes #81

778 of 789 branches covered (98.61%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

7 existing lines in 2 files now uncovered.

3599 of 3652 relevant lines covered (98.55%)

1636.51 hits per line

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

98.36
/src/transforms/stringify.ts
1
import { transform, type TransformRules } from './transform'
1✔
2
import type { NonRootResult } from '../result/NonRootResult'
1✔
3
import type { RootResult } from '../result/RootResult'
1✔
4

1✔
5
function applyPosition (position: 'prefix' | 'suffix', target: string, value: string): string {
74✔
6
  return position === 'prefix' ? value + target : target + value
74✔
7
}
74✔
8

1✔
9
export function quote (value: string, quote: 'single' | 'double' | undefined): string {
1✔
10
  switch (quote) {
255✔
11
    case 'double':
255✔
12
      return `"${value}"`
25✔
13
    case 'single':
255✔
14
      return `'${value}'`
15✔
15
    case undefined:
255✔
16
      return value
215✔
17
  }
255✔
18
}
255✔
19

1✔
20
export function stringifyRules (): TransformRules<string> {
1✔
21
  return {
1✔
22
    JsdocTypeParenthesis: (result, transform) => `(${result.element !== undefined ? transform(result.element) : ''})`,
1✔
23

1✔
24
    JsdocTypeKeyof: (result, transform) => `keyof ${transform(result.element)}`,
1✔
25

1✔
26
    JsdocTypeFunction: (result, transform) => {
1✔
27
      if (!result.arrow) {
69✔
28
        let stringified = result.constructor ? 'new' : 'function'
49✔
29
        if (!result.parenthesis) {
49✔
30
          return stringified
1✔
31
        }
1✔
32
        stringified += `(${result.parameters.map(transform).join(', ')})`
48✔
33
        if (result.returnType !== undefined) {
49✔
34
          stringified += `: ${transform(result.returnType)}`
29✔
35
        }
29✔
36
        return stringified
48✔
37
      } else {
69✔
38
        if (result.returnType === undefined) {
20✔
39
          throw new Error('Arrow function needs a return type.')
1✔
40
        }
1✔
41
        let stringified = `${
19✔
42
          result.typeParameters !== undefined
19✔
43
            ? `<${result.typeParameters.map(transform).join(', ') ?? ''}>`
20!
44
            : ''
20✔
45
        }(${result.parameters.map(transform).join(', ')}) => ${transform(result.returnType)}`
20✔
46
        if (result.constructor) {
20✔
47
          stringified = 'new ' + stringified
1✔
48
        }
1✔
49
        return stringified
19✔
50
      }
19✔
51
    },
1✔
52

1✔
53
    JsdocTypeName: result => result.value,
1✔
54

1✔
55
    JsdocTypeTuple: (result, transform) => `[${(result.elements as NonRootResult[]).map(transform).join(', ')}]`,
1✔
56

1✔
57
    JsdocTypeVariadic: (result, transform) => result.meta.position === undefined
1✔
58
      ? '...'
35✔
59
      : applyPosition(result.meta.position, transform(result.element as NonRootResult), '...'),
1✔
60

1✔
61
    JsdocTypeNamePath: (result, transform) => {
1✔
62
      const left = transform(result.left)
56✔
63
      const right = transform(result.right)
56✔
64
      switch (result.pathType) {
56✔
65
        case 'inner':
56✔
66
          return `${left}~${right}`
5✔
67
        case 'instance':
56✔
68
          return `${left}#${right}`
4✔
69
        case 'property':
56✔
70
          return `${left}.${right}`
43✔
71
        case 'property-brackets':
56✔
72
          return `${left}[${right}]`
4✔
73
      }
56✔
74
    },
1✔
75

1✔
76
    JsdocTypeStringValue: result => quote(result.value, result.meta.quote),
1✔
77

1✔
78
    JsdocTypeAny: () => '*',
1✔
79

1✔
80
    JsdocTypeGeneric: (result, transform) => {
1✔
81
      if (result.meta.brackets === 'square') {
43✔
82
        const element = result.elements[0]
15✔
83
        const transformed = transform(element)
15✔
84
        if (element.type === 'JsdocTypeUnion' || element.type === 'JsdocTypeIntersection') {
15✔
85
          return `(${transformed})[]`
1✔
86
        } else {
15✔
87
          return `${transformed}[]`
14✔
88
        }
14✔
89
      } else {
43✔
90
        return `${transform(result.left)}${result.meta.dot ? '.' : ''}<${result.infer === true ? 'infer ' : ''}${result.elements.map(transform).join(', ')}>`
28✔
91
      }
28✔
92
    },
1✔
93

1✔
94
    JsdocTypeImport: (result, transform) => `import(${transform(result.element)})`,
1✔
95

1✔
96
    JsdocTypeObjectField: (result, transform) => {
1✔
97
      let text = ''
42✔
98
      if (result.readonly) {
42✔
99
        text += 'readonly '
3✔
100
      }
3✔
101
      if (typeof result.key === 'string') {
42✔
102
        text += quote(result.key, result.meta.quote)
37✔
103
      } else {
42✔
104
        text += transform(result.key)
5✔
105
      }
5✔
106

42✔
107
      if (result.optional) {
42✔
108
        text += '?'
1✔
109
      }
1✔
110

42✔
111
      if (result.right === undefined) {
42✔
112
        return text
5✔
113
      } else {
42✔
114
        return text + `: ${transform(result.right)}`
37✔
115
      }
37✔
116
    },
1✔
117

1✔
118
    JsdocTypeJsdocObjectField: (result, transform) => `${transform(result.left)}: ${transform(result.right)}`,
1✔
119

1✔
120
    JsdocTypeKeyValue: (result, transform) => {
1✔
121
      let text = result.key
32✔
122
      if (result.optional) {
32✔
123
        text += '?'
1✔
124
      }
1✔
125
      if (result.variadic) {
32✔
126
        text = '...' + text
1✔
127
      }
1✔
128

32✔
129
      if (result.right === undefined) {
32!
UNCOV
130
        return text
×
131
      } else {
32✔
132
        return text + `: ${transform(result.right)}`
32✔
133
      }
32✔
134
    },
1✔
135

1✔
136
    JsdocTypeSpecialNamePath: result => `${result.specialType}:${quote(result.value, result.meta.quote)}`,
1✔
137

1✔
138
    JsdocTypeNotNullable: (result, transform) => applyPosition(result.meta.position, transform(result.element), '!'),
1✔
139

1✔
140
    JsdocTypeNull: () => 'null',
1✔
141

1✔
142
    JsdocTypeNullable: (result, transform) => applyPosition(result.meta.position, transform(result.element), '?'),
1✔
143

1✔
144
    JsdocTypeNumber: result => result.value.toString(),
1✔
145

1✔
146
    JsdocTypeObject: (result, transform) => `{${
1✔
147
      (result.meta.separator === 'linebreak' && result.elements.length > 1
41✔
148
       ? '\n' + (result.meta.propertyIndent ?? '')
41!
149
       : '') +
41✔
150
      result.elements.map(transform).join(
41✔
151
        (result.meta.separator === 'comma' ? ', ' : result.meta.separator === 'linebreak' ? '\n' + (result.meta.propertyIndent ?? '') : '; ')
41!
152
      ) +
41✔
153
      (result.meta.separator === 'linebreak' && result.elements.length > 1
41✔
154
       ? '\n'
41✔
155
       : '')
41✔
156
    }}`,
41✔
157

1✔
158
    JsdocTypeOptional: (result, transform) => applyPosition(result.meta.position, transform(result.element), '='),
1✔
159

1✔
160
    JsdocTypeSymbol: (result, transform) => `${result.value}(${result.element !== undefined ? transform(result.element) : ''})`,
1✔
161

1✔
162
    JsdocTypeTypeof: (result, transform) => `typeof ${transform(result.element)}`,
1✔
163

1✔
164
    JsdocTypeUndefined: () => 'undefined',
1✔
165

1✔
166
    JsdocTypeUnion: (result, transform) => result.elements.map(transform).join(' | '),
1✔
167

1✔
168
    JsdocTypeUnknown: () => '?',
1✔
169

1✔
170
    JsdocTypeIntersection: (result, transform) => result.elements.map(transform).join(' & '),
1✔
171

1✔
172
    JsdocTypeProperty: result => quote(result.value, result.meta.quote),
1✔
173

1✔
174
    JsdocTypePredicate: (result, transform) => `${transform(result.left)} is ${transform(result.right)}`,
1✔
175

1✔
176
    JsdocTypeIndexSignature: (result, transform) => `[${result.key}: ${transform(result.right)}]`,
1✔
177

1✔
178
    JsdocTypeMappedType: (result, transform) => `[${result.key} in ${transform(result.right)}]`,
1✔
179

1✔
180
    JsdocTypeAsserts: (result, transform) => `asserts ${transform(result.left)} is ${transform(result.right)}`,
1✔
181

1✔
182
    JsdocTypeReadonlyArray: (result, transform) => `readonly ${transform(result.element)}`,
1✔
183

1✔
184
    JsdocTypeAssertsPlain: (result, transform) => `asserts ${transform(result.element)}`,
1✔
185

1✔
186
    JsdocTypeConditional: (result, transform) => `${transform(result.checksType)} extends ${transform(result.extendsType)} ? ${transform(result.trueType)} : ${transform(result.falseType)}`,
1✔
187

1✔
188
    JsdocTypeTypeParameter: (result, transform) => `${
1✔
189
      transform(result.name)}${
3✔
190
        result.constraint !== undefined ? ` extends ${transform(result.constraint)}` : ''
3✔
191
      }${
3✔
192
        result.defaultValue !== undefined ? ` = ${transform(result.defaultValue)}` : ''
3✔
193
      }`
3✔
194
  }
1✔
195
}
1✔
196

1✔
197
const storedStringifyRules = stringifyRules()
1✔
198

1✔
199
export function stringify (result: RootResult): string {
1✔
200
  return transform(storedStringifyRules, result)
248✔
201
}
248✔
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