From d50c1a9ccf006ed5227bc8c8046b0a924cb8c7cf Mon Sep 17 00:00:00 2001 From: Jos de Jong Date: Fri, 1 Sep 2023 18:36:50 +0200 Subject: [PATCH] some refinements in the plugin --- README.md | 2 +- src/{generic/infer.ts => core/typed.ts} | 7 +-- src/experiment/arithmeticInfer.ts | 2 +- src/plugins/typeInferPlugin.ts | 57 ++++++++++++------------- 4 files changed, 31 insertions(+), 37 deletions(-) rename src/{generic/infer.ts => core/typed.ts} (54%) diff --git a/README.md b/README.md index a7bf7e4..968cf51 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Have a look at the section under `/src/experiment` and `/src/plugins`: - `src/plugins/typeInferPlugin.ts` is the actual plugin - in `tsconfig.json` we configure TypeScript to run the plugin - `src/experiment/arithmeticInfer.ts` with an example where we define `__infer__` -- `build/experiment/arithmeticInfer.ts` where the `__infer__` string literal is replace with the actual types +- after running TypeScript: look at `build/experiment/arithmeticInfer.ts` where the `__infer__` string literal is replaced with the actual types ### The idea diff --git a/src/generic/infer.ts b/src/core/typed.ts similarity index 54% rename from src/generic/infer.ts rename to src/core/typed.ts index 4fa9279..f66a4ad 100644 --- a/src/generic/infer.ts +++ b/src/core/typed.ts @@ -1,14 +1,9 @@ -export function infer(arg: T) : T { - console.error('infer should be replaced with runtime type information by a magic TypeScript plugin') - return arg -} - export function typed(name: string, types: string, arg: T) : T { // TODO: implement typed-function for real if (types === '__infer__') { console.error('__infer__ should be replaced with runtime type information by the TypeScript plugin') } - console.log(`Creating typed-function "${name}" with types ${types}`) + console.log(`TYPED-FUNCTION: Creating function "${name}" with types ${types}`) return arg } diff --git a/src/experiment/arithmeticInfer.ts b/src/experiment/arithmeticInfer.ts index e17ac6b..be544a3 100644 --- a/src/experiment/arithmeticInfer.ts +++ b/src/experiment/arithmeticInfer.ts @@ -1,4 +1,4 @@ -import { typed } from '../generic/infer' +import { typed } from '../core/typed.js' export const square = typed('square', '__infer__', (dep: { multiply: (a: T, b: T) => T, diff --git a/src/plugins/typeInferPlugin.ts b/src/plugins/typeInferPlugin.ts index 0cf6d6f..4ca6c21 100644 --- a/src/plugins/typeInferPlugin.ts +++ b/src/plugins/typeInferPlugin.ts @@ -6,45 +6,44 @@ const transformer: ts.TransformerFactory = context => { const checker = program.getTypeChecker() return sourceFile => { - // For the experiment we only want to influence a single file - if (!sourceFile.fileName.endsWith('arithmeticInfer.ts')) { - return sourceFile - } - const visitor = (node: ts.Node): ts.Node => { // @ts-ignore if (ts.isStringLiteral(node) && node.text === '__infer__') { - console.log('FOUND AN OCCURRENCE OF __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 - // console.log('PARENT') - // console.log(parentNode) + if (ts.isCallExpression(parentNode) && ts.isIdentifier(parentNode.expression) && parentNode.expression.escapedText === 'typed') { + // console.log('PARENT') + // console.log(parentNode) - // TODO: validate that the parent is indeed a mathjs typed function with deps + // TODO: validate that argNode is an ArrowFunction + // @ts-ignore + const argNode = parentNode.arguments[2] + // @ts-ignore + const returnType = argNode.type.getText(sourceFile) + console.log('PLUGIN: RETURN TYPE') + console.log(returnType) + // (a: number) => number - // @ts-ignore - const argNode = parentNode.arguments[2] - const returnType = argNode.type.getText(sourceFile) - console.log('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 paramNode = argNode.parameters[0] - const paramTypeSrc = paramNode.type.getText(sourceFile) - console.log('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 type = checker.getTypeAtLocation(paramNode) - const paramType = checker.typeToString(type, paramNode, ts.TypeFormatFlags.InTypeAlias) - console.log('PARAM TYPE STRING', paramType) - // { multiply: (a: number, b: number) => number; unaryMinus: (x: number) => number; } + const depsAndReturnType = `{ deps: ${paramType}; return: ${returnType} }` - const depsAndReturnType = `{ deps: ${paramType}; return: ${returnType} }` - - return ts.factory.createStringLiteral(depsAndReturnType) + return ts.factory.createStringLiteral(depsAndReturnType) + } } return ts.visitEachChild(node, visitor, context)