import ts from 'typescript' const transformer: ts.TransformerFactory = context => { // TODO: get a reference to the program instance that the plugin is running in instead of creating a new program? const program = ts.createProgram([], {}) const checker = program.getTypeChecker() return sourceFile => { const visitor = (node: ts.Node): ts.Node => { // @ts-ignore if (ts.isStringLiteral(node) && node.text === '__infer__') { console.log('PLUGIN: FOUND AN OCCURRENCE OF __infer__') // we're looking for a function call like typed('name', '__infer__', deps => ...) const parentNode = node.parent if (ts.isCallExpression(parentNode) && ts.isIdentifier(parentNode.expression) && parentNode.expression.escapedText === '$reflect') { // console.log('PARENT') // console.log(parentNode) // TODO: validate that argNode is an ArrowFunction // @ts-ignore const argNode = parentNode.arguments[1] // @ts-ignore const returnType = argNode.type.getText(sourceFile) console.log('PLUGIN: RETURN TYPE') console.log(returnType) // (a: number) => number // @ts-ignore const paramNode = argNode.parameters[0] const paramTypeSrc = paramNode.type.getText(sourceFile) console.log('PLUGIN: PARAM TYPE SRC', paramTypeSrc) // { // multiply: (a: number, b: number) => number, // unaryMinus: (x: number) => number, // just for the experiment // } const type = checker.getTypeAtLocation(paramNode) const paramType = checker.typeToString(type, paramNode, ts.TypeFormatFlags.InTypeAlias) console.log('PLUGIN: PARAM TYPE STRING', paramType) // { multiply: (a: number, b: number) => number; unaryMinus: (x: number) => number; } const depsAndReturnType = `{ deps: ${paramType}; return: ${returnType} }` return ts.factory.createStringLiteral(depsAndReturnType) } } return ts.visitEachChild(node, visitor, context) } return ts.visitNode(sourceFile, visitor) } } export default transformer