Skip to content

Commit 0d477e9

Browse files
feat: add ChildTypes helper
1 parent 4558c48 commit 0d477e9

3 files changed

Lines changed: 24 additions & 10 deletions

File tree

crates/napi/__test__/type.spec.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ test('test no type annotation', t => {
1717
t.assert(childKind !== ',')
1818
// test parent method
1919
const parent = child!.parent()
20-
t.assert(parent === root)
20+
t.assert(parent!.kind() === root.kind())
2121
// test find
2222
const sum = root.find({
2323
rule: {
@@ -65,7 +65,7 @@ test('test type assertion', t => {
6565
t.assert(childKind !== ',')
6666
// test parent method
6767
const parent = child!.parent()
68-
t.assert(parent === root)
68+
t.assert(parent?.kind() === root.kind())
6969
// test find
7070
const sum = root.find({
7171
rule: {
@@ -114,13 +114,15 @@ test('test type argument style', t => {
114114
t.assert(childKind !== ',')
115115
// test parent method
116116
const parent = child!.parent<'program'>()
117-
t.assert(parent === root)
117+
t.assert(parent!.kind() === root.kind())
118118
// @ts-expect-error should reject wrong kind
119119
const parent2 = child!.parent<'eskdf'>()
120-
t.assert(parent2 === root)
120+
t.assert(parent2!.kind() === root.kind())
121121
const parent3 = child!.parent<'expression_statement'>()
122122
// @ts-expect-error parent3 should take new kind
123-
t.assert(parent3 === root)
123+
t.assert(parent3!.kind() === root.kind())
124+
// @ts-expect-error should report invalid child type
125+
root.child<'binary_expression'>
124126
// test find
125127
const sum = root.find<'binary_expression'>({
126128
rule: {

crates/napi/types/sgnode.d.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import type {
77
NodeFieldInfo,
88
RootKind,
99
NamedKinds,
10+
ChildKinds,
11+
NamedChildKinds,
1012
} from './staticTypes'
1113
import type { NapiConfig } from './config'
1214

@@ -71,7 +73,8 @@ export declare class SgNode<
7173
name: F,
7274
): Exclude<FieldNode<M, T, F>, null>[]
7375
parent: NodeMethod<M>
74-
child<K extends Kinds<M>>(nth: number): RefineNode<M, K> | null
76+
child(nth: number): SgNode<M, ChildKinds<M, T>> | null
77+
child<K extends NamedChildKinds<M, T>>(nth: number): RefineNode<M, K> | null
7578
ancestors(): Array<SgNode<M>>
7679
next: NodeMethod<M>
7780
nextAll(): Array<SgNode<M>>
@@ -91,9 +94,9 @@ export declare class SgRoot<M extends TypesMap = TypesMap> {
9194
filename(): string
9295
}
9396

94-
interface NodeMethod<M extends TypesMap, Args extends unknown[] = [], T = NamedKinds<M>> {
97+
interface NodeMethod<M extends TypesMap, Args extends unknown[] = []> {
9598
(...args: Args): SgNode<M> | null
96-
<K extends T>(...args: Args): RefineNode<M, K> | null
99+
<K extends NamedKinds<M>>(...args: Args): RefineNode<M, K> | null
97100
}
98101

99102
/**

crates/napi/types/staticTypes.d.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,21 @@ export type ExtractField<
4848
: NodeFieldInfo
4949

5050
// in case of empty types array, return string as fallback
51-
type NoNever<T, Fallback = string> = [T] extends [never] ? Fallback : T
51+
type NoNever<T, Fallback> = [T] extends [never] ? Fallback : T
5252

5353
export type TypesInField<M extends TypesMap, I extends NodeFieldInfo> = NoNever<
54-
ResolveType<M, I['types'][number]['type']>
54+
ResolveType<M, I['types'][number]['type']>,
55+
Kinds<M>
5556
>
5657

58+
export type NamedChildKinds<M extends TypesMap, T extends Kinds<M>> =
59+
M[T] extends { children: infer C extends NodeFieldInfo }
60+
? TypesInField<M, C>
61+
: NamedKinds<M>
62+
export type ChildKinds<M extends TypesMap, T extends Kinds<M>> =
63+
| NamedChildKinds<M, T>
64+
| LowPriorityKey
65+
5766
/**
5867
* resolve subtypes alias. see tree-sitter's reference
5968
* e.g. like `expression` => `binary_expression` | `unary_expression` | ...

0 commit comments

Comments
 (0)