@travetto/transformer
Version:
Functionality for AST transformations, with transformer registration, and general utils
253 lines (221 loc) • 10.2 kB
text/typescript
import ts from 'typescript';
import { DecoratorMeta, NodeTransformer, State, TransformPhase, TransformerType, Transformer, ModuleNameSymbol } from './types/visitor.ts';
const HandlersSymbol = Symbol();
type TransformerWithHandlers = Transformer & { [HandlersSymbol]?: NodeTransformer[] };
function isTransformer(x: unknown): x is Transformer {
return x !== null && x !== undefined && typeof x === 'function';
}
/**
* Get all transformers
* @param obj Object to search for transformers
*/
export function getAllTransformers(obj: Record<string, { [HandlersSymbol]?: NodeTransformer[] }>, module: string): NodeTransformer[] {
return Object.values(obj)
.flatMap(x => {
if (isTransformer(x)) {
x[ModuleNameSymbol] = module;
}
return (x[HandlersSymbol] ?? []);
})
.map(handler => ({
...handler,
key: `${module}:${handler.key}`,
target: handler.target?.map(t => `${module}:${t}`)
}));
}
// Store handlers in class
function storeHandler(cls: TransformerWithHandlers, fn: Function, phase: TransformPhase, type: TransformerType, target?: string[]): void {
(cls[HandlersSymbol] ??= []).push({ key: fn.name, [phase]: fn.bind(cls), type, target });
}
/**
* Wraps entire file before transforming
*/
export function OnFile(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.SourceFile) => R>
): void => storeHandler(inst, d.value!, 'before', 'file', target);
}
/**
* Wraps entire file after transforming
*/
export function AfterFile(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.SourceFile) => R>
): void => storeHandler(inst, d.value!, 'before', 'file', target);
}
/**
* Listens for a `ts.CallExpression`, on descent
*/
export function OnCall(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.CallExpression) => R>
): void => storeHandler(inst, d.value!, 'before', 'call', target);
}
/**
* Listens for a `ts.FunctionDeclaration`, on descent
*/
export function OnFunction(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.FunctionDeclaration | ts.FunctionExpression) => R>
): void => storeHandler(inst, d.value!, 'before', 'function', target);
}
/**
* Listens for a `ts.ParameterDeclaration`, on descent
*/
export function OnParameter(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.ParameterDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'before', 'parameter', target);
}
/**
* Listens for a `ts.PropertyDeclaration`, on descent
*/
export function OnProperty(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.PropertyDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'before', 'property', target);
}
/**
* Listens for a `ts.GetAccessorDeclaration`, on descent
*/
export function OnGetter(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.GetAccessorDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'before', 'getter', target);
}
/**
* Listens for a `ts.SetAccessorDeclaration`, on descent
*/
export function OnSetter(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.SetAccessorDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'before', 'setter', target);
}
/**
* Listens for a `ts.MethodDeclaration`, on descent
*/
export function OnMethod(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.MethodDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'before', 'method', target);
}
/**
* Listens for a static `ts.MethodDeclaration`, on descent
*/
export function OnStaticMethod(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.MethodDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'before', 'static-method', target);
}
/**
* Listens for a `ts.ClassDeclaration`, on descent
*/
export function OnClass(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.ClassDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'before', 'class', target);
}
/**
* Listens for a `ts.TypeAliasDeclaration` on descent
*/
export function OnTypeAlias(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.TypeAliasDeclaration) => R>
): void => storeHandler(inst, d.value!, 'before', 'type', target);
}
/**
* Listens for a `ts.InterfaceDeclaration` on descent
*/
export function OnInterface(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.InterfaceDeclaration) => R>
): void => storeHandler(inst, d.value!, 'before', 'interface', target);
}
/**
* Listens for a `ts.CallExpression`, on ascent
*/
export function AfterCall(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.CallExpression, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'after', 'call', target);
}
/**
* Listens for a `ts.FunctionDeclaration`, on descent
*/
export function AfterFunction(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.FunctionDeclaration | ts.FunctionExpression) => R>
): void => storeHandler(inst, d.value!, 'after', 'function', target);
}
/**
* Listens for a `ts.ParameterDeclaration`, on ascent
*/
export function AfterParameter(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.ParameterDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'after', 'parameter', target);
}
/**
* Listens for a `ts.PropertyDeclaration`, on ascent
*/
export function AfterProperty(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.PropertyDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'after', 'property', target);
}
/**
* Listens for a `ts.GetAccessorDeclaration`, on ascent
*/
export function AfterGetter(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.GetAccessorDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'after', 'getter', target);
}
/**
* Listens for a `ts.SetAccessorDeclaration`, on ascent
*/
export function AfterSetter(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.SetAccessorDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'after', 'setter', target);
}
/**
* Listens for a `ts.MethodDeclaration`, on ascent
*/
export function AfterMethod(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.MethodDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'after', 'method', target);
}
/**
* Listens for a static `ts.MethodDeclaration`, on ascent
*/
export function AfterStaticMethod(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.MethodDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'after', 'static-method', target);
}
/**
* Listens for a `ts.ClassDeclaration`, on ascent
*/
export function AfterClass(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.ClassDeclaration, dm?: DecoratorMeta) => R>
): void => storeHandler(inst, d.value!, 'after', 'class', target);
}
/**
* Listens for a `ts.TypeAliasDeclaration` on ascent
*/
export function AfterTypeAlias(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.TypeAliasDeclaration) => R>
): void => storeHandler(inst, d.value!, 'after', 'type', target);
}
/**
* Listens for a `ts.InterfaceDeclaration` on ascent
*/
export function AfterInterface(...target: string[]) {
return <S extends State = State, R extends ts.Node = ts.Node>(
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.InterfaceDeclaration) => R>
): void => storeHandler(inst, d.value!, 'after', 'interface', target);
}