Skip to content

Commit f98f7ab

Browse files
authored
Use jsdoc-type-pratt-parser instead of jsdoctypeparser (#651)
1 parent a6fda59 commit f98f7ab

File tree

7 files changed

+189
-200
lines changed

7 files changed

+189
-200
lines changed

.changeset/twenty-coats-melt.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-regexp": major
3+
---
4+
5+
Use jsdoc-type-pratt-parser instead of jsdoctypeparser

lib/utils/type-tracker/index.ts

Lines changed: 103 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ import {
2727
hasType,
2828
} from "./type-data"
2929
import { getJSDoc, parseTypeText } from "./jsdoc"
30-
import type { JSDocTypeNode } from "./jsdoc/jsdoctypeparser-ast"
30+
import type {
31+
RootResult as JSDocTypeRootResult,
32+
KeyValueResult,
33+
} from "jsdoc-type-pratt-parser"
3134
import { TypeIterable, UNKNOWN_ITERABLE } from "./type-data/iterable"
3235
import { getParent } from "../ast-utils"
3336
import {
@@ -46,6 +49,7 @@ import {
4649
isUnionOrIntersection,
4750
isUnknown,
4851
} from "../ts-utils"
52+
import { assertNever } from "../util"
4953

5054
const ts = getTypeScript()!
5155

@@ -596,94 +600,152 @@ function typeTextToTypeInfo(typeText?: string): TypeInfo | null {
596600
return jsDocTypeNodeToTypeInfo(parseTypeText(typeText))
597601
}
598602

599-
/** Get type from JSDocTypeNode */
600-
function jsDocTypeNodeToTypeInfo(node: JSDocTypeNode | null): TypeInfo | null {
603+
/** Get type from jsdoc-type-pratt-parser's RootResult */
604+
function jsDocTypeNodeToTypeInfo(
605+
node: JSDocTypeRootResult | null,
606+
): TypeInfo | null {
601607
if (node == null) {
602608
return null
603609
}
604-
if (node.type === "NAME") {
605-
return typeNameToTypeInfo(node.name)
610+
if (node.type === "JsdocTypeName") {
611+
return typeNameToTypeInfo(node.value)
606612
}
607-
if (node.type === "STRING_VALUE") {
613+
if (node.type === "JsdocTypeStringValue") {
608614
return STRING
609615
}
610-
if (node.type === "NUMBER_VALUE") {
616+
if (node.type === "JsdocTypeNumber") {
611617
return NUMBER
612618
}
613619
if (
614-
node.type === "OPTIONAL" ||
615-
node.type === "NULLABLE" ||
616-
node.type === "NOT_NULLABLE" ||
617-
node.type === "PARENTHESIS"
620+
node.type === "JsdocTypeOptional" ||
621+
node.type === "JsdocTypeNullable" ||
622+
node.type === "JsdocTypeNotNullable" ||
623+
node.type === "JsdocTypeParenthesis"
618624
) {
619-
return jsDocTypeNodeToTypeInfo(node.value)
625+
return jsDocTypeNodeToTypeInfo(node.element)
620626
}
621-
if (node.type === "VARIADIC") {
627+
if (node.type === "JsdocTypeVariadic") {
622628
return new TypeArray(function* () {
623-
if (node.value) {
624-
yield jsDocTypeNodeToTypeInfo(node.value)
629+
if (node.element) {
630+
yield jsDocTypeNodeToTypeInfo(node.element)
625631
} else {
626632
yield null
627633
}
628634
})
629635
}
630-
if (node.type === "UNION" || node.type === "INTERSECTION") {
636+
if (
637+
node.type === "JsdocTypeUnion" ||
638+
node.type === "JsdocTypeIntersection"
639+
) {
631640
return TypeUnionOrIntersection.buildType(function* () {
632-
const left = jsDocTypeNodeToTypeInfo(node.left)
633-
if (left) {
634-
yield left
635-
}
636-
const right = jsDocTypeNodeToTypeInfo(node.right)
637-
if (right) {
638-
yield right
641+
for (const e of node.elements) {
642+
yield jsDocTypeNodeToTypeInfo(e)
639643
}
640644
})
641645
}
642-
if (node.type === "GENERIC") {
643-
const subject = jsDocTypeNodeToTypeInfo(node.subject)
646+
if (node.type === "JsdocTypeGeneric") {
647+
const subject = jsDocTypeNodeToTypeInfo(node.left)
644648
if (hasType(subject, "Array")) {
645649
return new TypeArray(function* () {
646-
yield jsDocTypeNodeToTypeInfo(node.objects[0])
650+
yield jsDocTypeNodeToTypeInfo(node.elements[0])
647651
})
648652
}
649653
if (hasType(subject, "Map")) {
650654
return new TypeMap(
651-
() => jsDocTypeNodeToTypeInfo(node.objects[0]),
652-
() => jsDocTypeNodeToTypeInfo(node.objects[1]),
655+
() => jsDocTypeNodeToTypeInfo(node.elements[0]),
656+
() => jsDocTypeNodeToTypeInfo(node.elements[1]),
653657
)
654658
}
655659
if (hasType(subject, "Set")) {
656-
return new TypeSet(() => jsDocTypeNodeToTypeInfo(node.objects[0]))
660+
return new TypeSet(() => jsDocTypeNodeToTypeInfo(node.elements[0]))
657661
}
658662
if (subject === UNKNOWN_ITERABLE) {
659663
return new TypeIterable(() =>
660-
jsDocTypeNodeToTypeInfo(node.objects[0]),
664+
jsDocTypeNodeToTypeInfo(node.elements[0]),
661665
)
662666
}
663667
return subject
664668
}
665-
if (node.type === "RECORD") {
669+
if (node.type === "JsdocTypeObject") {
666670
return new TypeObject(function* () {
667-
for (const entry of node.entries) {
668-
yield [entry.key, () => jsDocTypeNodeToTypeInfo(entry.value)]
671+
for (const element of node.elements) {
672+
if (element.type === "JsdocTypeObjectField") {
673+
if (typeof element.key !== "string") {
674+
// unknown key
675+
continue
676+
}
677+
yield [
678+
element.key,
679+
() =>
680+
element.right
681+
? jsDocTypeNodeToTypeInfo(element.right)
682+
: null,
683+
]
684+
} else if (element.type === "JsdocTypeJsdocObjectField") {
685+
if (
686+
element.left.type === "JsdocTypeNullable" &&
687+
element.left.element.type === "JsdocTypeName"
688+
) {
689+
yield [
690+
element.left.element.value,
691+
() =>
692+
element.right
693+
? jsDocTypeNodeToTypeInfo(element.right)
694+
: null,
695+
]
696+
}
697+
}
698+
}
699+
})
700+
}
701+
if (node.type === "JsdocTypeTuple") {
702+
if (node.elements[0].type === "JsdocTypeKeyValue") {
703+
const elements = node.elements as KeyValueResult[]
704+
return new TypeArray(function* () {
705+
for (const element of elements) {
706+
if (element.right) {
707+
yield jsDocTypeNodeToTypeInfo(element.right)
708+
}
709+
}
710+
})
711+
}
712+
const elements = node.elements as JSDocTypeRootResult[]
713+
return new TypeArray(function* () {
714+
for (const element of elements) {
715+
yield jsDocTypeNodeToTypeInfo(element)
669716
}
670717
})
671718
}
672-
if (node.type === "ANY" || node.type === "UNKNOWN") {
719+
if (node.type === "JsdocTypeFunction") {
720+
if (node.returnType) {
721+
const returnType = node.returnType
722+
return new TypeFunction(() => jsDocTypeNodeToTypeInfo(returnType))
723+
}
724+
return UNKNOWN_FUNCTION
725+
}
726+
if (node.type === "JsdocTypeTypeof") {
727+
return new TypeFunction(() => jsDocTypeNodeToTypeInfo(node.element))
728+
}
729+
if (
730+
node.type === "JsdocTypeAny" ||
731+
node.type === "JsdocTypeUnknown" ||
732+
node.type === "JsdocTypeNull" ||
733+
node.type === "JsdocTypeUndefined"
734+
) {
673735
return null
674736
}
675737
if (
676-
node.type === "MEMBER" ||
677-
node.type === "INNER_MEMBER" ||
678-
node.type === "INSTANCE_MEMBER" ||
679-
node.type === "EXTERNAL" ||
680-
node.type === "FILE_PATH" ||
681-
node.type === "MODULE"
738+
node.type === "JsdocTypeImport" ||
739+
node.type === "JsdocTypeKeyof" ||
740+
node.type === "JsdocTypeNamePath" ||
741+
node.type === "JsdocTypePredicate" ||
742+
node.type === "JsdocTypeSpecialNamePath" ||
743+
node.type === "JsdocTypeSymbol"
682744
) {
683745
return null
684746
}
685747

686-
return null
748+
throw assertNever(node)
687749
}
688750

689751
/** Get type from type name */

lib/utils/type-tracker/jsdoc/index.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ import type * as ES from "estree"
33
import { isCommentToken } from "@eslint-community/eslint-utils"
44
import * as commentParser from "comment-parser"
55
import type { Spec } from "comment-parser"
6-
// @ts-expect-error -- no type
7-
import * as jsdocTypeParser from "jsdoctypeparser"
8-
import type { JSDocTypeNode } from "./jsdoctypeparser-ast"
6+
import * as jsdocTypeParser from "jsdoc-type-pratt-parser"
7+
import type { RootResult } from "jsdoc-type-pratt-parser"
98

109
type ParsedComment = ReturnType<typeof commentParser.parse>[number]
1110

@@ -182,10 +181,10 @@ function findJSDocComment(node: ES.Node, sourceCode: SourceCode) {
182181
/**
183182
* Parse JSDoc type text
184183
*/
185-
export function parseTypeText(text: string): JSDocTypeNode | null {
184+
export function parseTypeText(text: string): RootResult | null {
186185
try {
187-
const ast: JSDocTypeNode = jsdocTypeParser.parse(text)
188-
return ast
186+
const result = jsdocTypeParser.tryParse(text)
187+
return result
189188
} catch {
190189
return null
191190
}

lib/utils/type-tracker/jsdoc/jsdoctypeparser-ast.ts

Lines changed: 0 additions & 148 deletions
This file was deleted.

0 commit comments

Comments
 (0)