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 => { // we're looking for a function call like $reflect(deps => ...) // @ts-ignore if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.escapedText === '$reflect') { console.log('PLUGIN: FOUND AN OCCURRENCE OF $reflect') // console.log('PARENT') // console.log(node) // TODO: validate that argNode is an ArrowFunction // @ts-ignore const argNode = node.arguments[0] // @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 // } // WIP // @ts-ignore const type = checker.getTypeAtLocation(paramNode) const paramType = checker.typeToString(type, paramNode, ts.TypeFormatFlags.InTypeAlias) // const paramType = checker.typeToString(type) // TDOO: get checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration) console.log('PLUGIN: PARAM TYPE STRING', paramType) // { multiply: (a: number, b: number) => number; unaryMinus: (x: number) => number; } // WIP // For a function definition // const signature = checker.getResolvedSignature(node); // if (signature != null) { // // outputs -- (Ctor: Ctor): void // console.log(signature) // console.log('TEST 1', checker.signatureToString(signature)); // // @ts-ignore // // console.log('TEST 2', checker.getResolvedSignatureForStringLiteralCompletions(node)); // const params = signature.getParameters(); // for (const param of params) { // const type = checker.getTypeOfSymbolAtLocation(param, node); // // outputs -- Ctor // console.log('TEST 3', checker.typeToString(type)); // } // } // WIP const type0 = resolveTypeArgumentOfCall(checker, node, 0) // @ts-ignore const typeStr = checker.typeToString(type0); console.log('PLUGIN: RESOLVED TYPE ARGUMENT', typeStr) const depsAndReturnType = `{ deps: ${paramType}; return: ${returnType} }` // Now we insert a second argument to the $reflect function call: a string with the types // @ts-ignore node.arguments.push(ts.factory.createStringLiteral(depsAndReturnType)) return node } return ts.visitEachChild(node, visitor, context) } return ts.visitNode(sourceFile, visitor) } } // WIP function resolveTypeArgumentOfCall(checker: ts.TypeChecker, macroCall: ts.CallExpression, typeIndex: number) : ts.Type | undefined { // @ts-ignore console.log( 'TEST D', macroCall.arguments[0].typeParameters) if (!macroCall.typeArguments || !macroCall.typeArguments[typeIndex]) return; const type = checker.getTypeAtLocation(macroCall.typeArguments[typeIndex]); console.log( 'TEST A', type, macroCall.typeArguments ) return type // const lastMacroCall = this.getLastMacro(); // if (!lastMacroCall) return type; // if (type.isTypeParameter()) { // const resolvedTypeParameterIndex = lastMacroCall.macro.typeParams.findIndex(arg => this.checker.getTypeAtLocation(arg) === type); // if (resolvedTypeParameterIndex === -1) return; // if (lastMacroCall.call && ts.isCallExpression(lastMacroCall.call)) { // const resolvedTypeParam = lastMacroCall.call.typeArguments?.[resolvedTypeParameterIndex]; // if (!resolvedTypeParam) return resolveTypeArguments(this.checker, lastMacroCall.call)[resolvedTypeParameterIndex]; // return this.checker.getTypeAtLocation(resolvedTypeParam); // } else return; // } else { // const allParams = lastMacroCall.macro.typeParams.map(p => this.checker.getTypeAtLocation(p)); // const replacementTypes = resolveTypeArguments(this.checker, lastMacroCall.call as ts.CallExpression); // return resolveTypeWithTypeParams(type, allParams, replacementTypes); // } } export default transformer