@ast-grep/napi
Version:
Search and Rewrite code at large scale using precise AST pattern
103 lines (88 loc) • 2.88 kB
TypeScript
/**
* Reference
* https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types
* Rust CLI Impl
* https://github.com/tree-sitter/tree-sitter/blob/f279d10aa2aca37c0004d84b2261685739f3cab8/cli/generate/src/node_types.rs#L35-L47
*/
export interface NodeBasicInfo {
type: string
named: boolean
}
export interface NodeFieldInfo {
multiple: boolean
required: boolean
types: NodeBasicInfo[]
}
export interface NodeType extends NodeBasicInfo {
root?: boolean
fields?: {
[fieldName: string]: NodeFieldInfo
}
children?: NodeFieldInfo
subtypes?: NodeBasicInfo[]
}
/**
* A map of key to NodeType.
* Note, the key is not necessary node's kind.
* it can be a rule representing a category of syntax nodes
* (e.g. “expression”, “type”, “declaration”).
* See reference above for more details.
*/
export interface TypesMap {
[key: string]: NodeType
}
export type FieldNames<N extends NodeType> = N extends { fields: infer F } ? keyof F
: string
export type ExtractField<
N extends NodeType,
F extends FieldNames<N>,
> = N['fields'] extends Record<F, NodeFieldInfo> ? N['fields'][F]
: NodeFieldInfo
// in case of empty types array, return string as fallback
type NoNever<T, Fallback> = [T] extends [never] ? Fallback : T
export type TypesInField<M extends TypesMap, I extends NodeFieldInfo> = NoNever<
ResolveType<M, I['types'][number]['type']>,
Kinds<M>
>
export type NamedChildKinds<
M extends TypesMap,
T extends Kinds<M>,
> = M[T] extends { children: infer C extends NodeFieldInfo } ? TypesInField<M, C>
: NamedKinds<M>
export type ChildKinds<M extends TypesMap, T extends Kinds<M>> =
| NamedChildKinds<M, T>
| LowPriorityKey
/**
* resolve subtypes alias. see tree-sitter's reference
* e.g. like `expression` => `binary_expression` | `unary_expression` | ...
*/
type ResolveType<M extends TypesMap, K> = K extends keyof M
? M[K] extends { subtypes: infer S extends NodeBasicInfo[] } ? ResolveType<M, S[number]['type']>
: K
: K
/**
* All named nodes' kinds that are usable in ast-grep rule
* NOTE: SgNode can return kind not in this list
*/
export type NamedKinds<M extends TypesMap> = ResolveType<M, keyof M>
/**
* See open-ended unions / string literal completion in TypeScript
* https://github.com/microsoft/TypeScript/issues/26277
* https://github.com/microsoft/TypeScript/issues/33471
*/
type LowPriorityKey = string & {}
/**
* A union of all named node kinds and a low priority key
* tree-sitter Kinds also include unnamed nodes which is not usable in rule
* NOTE: SgNode can return a string type if it is not a named node
*/
export type Kinds<M extends TypesMap = TypesMap> =
| NamedKinds<M>
| LowPriorityKey
/**
* The root node kind of the tree.
*/
export type RootKind<M extends TypesMap> = NoNever<
Extract<M[keyof M], { root: true }>['type'],
Kinds<M>
>