diff --git a/README.md b/README.md index 44b4a46..49e5266 100644 --- a/README.md +++ b/README.md @@ -8,53 +8,3 @@ To build and run the prototype, run: pnpm install pnpm build-and-run ``` - -## experiment - -See: the section under `/src/experiment` and `/src/plugins`. - -### The idea - -Create a TypeScript plugin which can replace structures like: - - infer(factoryFunction) - -where `factoryFunction` is a mathjs factory function in TypeScript, with something like: - - infer({ signature: factoryFunction }) - -where `signature` is a string containing the type of the factory function and its dependencies. - -Relevant methods of the TypeScript compiler are: - -```ts -const program = ts.createProgram(fileNames, options) -const typeChecker = program.getTypeChecker() - -// relevant methods: -// -// typeChecker.getSymbolAtLocation -// typeChecker.getTypeOfSymbolAtLocation -// typeChecker.getResolvedSignature -// typeChecker.getSignaturesOfType -``` - -### Status - -None of the experiments (`infer1` and `infer2`) are outputting something useful yet. - - -### How to run - - pnpm experiment:infer1 - pnpm experiment:infer1-direct - pnpm experiment:infer2 - -### Read more - -- https://github.com/microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin -- https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API -- https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#using-the-type-checker -- https://github.com/Microsoft/TypeScript/wiki/Using-the-Language-Service-API -- https://stackoverflow.com/questions/63944135/typescript-compiler-api-how-to-get-type-with-resolved-type-arguments -- https://stackoverflow.com/questions/48886508/typechecker-api-how-do-i-find-inferred-type-arguments-to-a-function \ No newline at end of file diff --git a/package.json5 b/package.json5 index a140cb8..959a089 100644 --- a/package.json5 +++ b/package.json5 @@ -5,9 +5,6 @@ main: 'index.ts', scripts: { 'build-and-run': 'ttsc -b && node build', - 'experiment:infer1': 'ttsc -b && node build/plugins/infer.js ./src/generic/arithmetic.ts', - 'experiment:infer1-direct': 'ttsc -b && node build/plugins/infer.js ./src/experiment/arithmeticInfer1.ts', - 'experiment:infer2': 'ttsc -b && node build/plugins/infer2.js ./src/experiment/arithmeticInfer2.ts', test: 'echo "Error: no test specified" && exit 1', }, keywords: [ diff --git a/src/experiment/arithmeticInfer1.ts b/src/experiment/arithmeticInfer1.ts deleted file mode 100644 index 92aeffd..0000000 --- a/src/experiment/arithmeticInfer1.ts +++ /dev/null @@ -1,8 +0,0 @@ -import {infer} from '../generic/infer' - -export const square = infer((dep: { - multiply: (a: number, b: number) => number, - unaryMinus: (x: number) => number, // just for the experiment -}): (a: number) => number => - z => dep.multiply(z, z) -) diff --git a/src/experiment/arithmeticInfer2.ts b/src/experiment/arithmeticInfer2.ts deleted file mode 100644 index ab4eebf..0000000 --- a/src/experiment/arithmeticInfer2.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { infer } from '../generic/infer' -import { Dependencies, Signature } from '../interfaces/type' - -export type multiplyDep = Dependencies<'multiply', T> - -export const square1 = - (dep: Dependencies<'multiply', T>): Signature<'square', T> => - z => dep.multiply(z, z) - -export const square2 = infer((dep: { - multiply: (a: number, b: number) => number, - unaryMinus: (x: number) => number, // just for the experiment -}): (a: number) => number => - z => dep.multiply(z, z) -) diff --git a/src/generic/infer.ts b/src/generic/infer.ts deleted file mode 100644 index 6e654cb..0000000 --- a/src/generic/infer.ts +++ /dev/null @@ -1,4 +0,0 @@ -export function infer(arg: T) : T { - console.error('infer should be replace with runtime type information by a magic TypeScript plugin') - return arg -} diff --git a/src/plugins/infer1.ts b/src/plugins/infer1.ts deleted file mode 100644 index 81fa0a6..0000000 --- a/src/plugins/infer1.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { readFileSync } from "fs"; -import * as ts from "typescript"; -import { inspect } from 'util' - -export function infer(sourceFile: ts.SourceFile) { - recurse(sourceFile); - - function getType(kind: number) { - switch(kind) { - case ts.SyntaxKind.NumberKeyword: return 'number' - case ts.SyntaxKind.StringKeyword: return 'string' - case ts.SyntaxKind.BooleanKeyword: return 'boolean' - default: return String(ts.SyntaxKind[kind]) // TODO: work out all types - } - } - - function recurse(node: ts.Node) { - if (node.kind === ts.SyntaxKind.Identifier) { - console.log('Identifier', node['escapedText'], ts.SyntaxKind[node.kind]) - } - - // recognize a structure like: - // - // export const square = infer((dep: { - // multiply: (a: number, b: number) => number - // }): (a: number) => number => - // z => dep.multiply(z, z) - // ) - if (node?.['name']?.kind === ts.SyntaxKind.Identifier && node?.['name']['escapedText'] === 'dep') { - console.log('dep', getType(node['type'].kind), node) - - node['type']?.members?.forEach(member => { - console.log('member', { - name: member.name.escapedText, - parameters: member.type.parameters.map(parameter => { - return parameter.name.escapedText + ': ' + getType(parameter.type.kind) - }), - returns: getType(member.type.type.kind) - }) - }) - } - - // recognize a structure like: - // - // export const square = - // (dep: Dependencies<'multiply' | 'unaryMinus', T>): Signature<'square', T> => - // z => dep.multiply(z, z) - if (node?.['name']?.kind === ts.SyntaxKind.Identifier && node?.['name']['escapedText'] === 'dep') { - // TODO - } - - ts.forEachChild(node, recurse); - } -} - -const fileNames = process.argv.slice(2); -console.log('infer files', fileNames) -fileNames.forEach(fileName => { - // Parse a file - const sourceFile = ts.createSourceFile( - fileName, - readFileSync(fileName).toString(), - ts.ScriptTarget.ES2022, - /*setParentNodes */ true - ); - - console.log('AST', fileName, inspect(sourceFile, { depth: null, colors: true })) - - console.log(sourceFile.text) - console.log() - - infer(sourceFile); -}); diff --git a/src/plugins/infer2.ts b/src/plugins/infer2.ts deleted file mode 100644 index 43fc64b..0000000 --- a/src/plugins/infer2.ts +++ /dev/null @@ -1,74 +0,0 @@ -import * as ts from "typescript" - -// based on: https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#using-the-type-checker - -infer2(process.argv.slice(2), { - target: ts.ScriptTarget.ES5, - module: ts.ModuleKind.CommonJS -}) - -function infer2( - fileNames: string[], - options: ts.CompilerOptions -): void { - const program = ts.createProgram(fileNames, options) - const typeChecker = program.getTypeChecker() - - for (const sourceFile of program.getSourceFiles()) { - if (!sourceFile.isDeclarationFile) { - ts.forEachChild(sourceFile, visit) - } - } - - return - - function visit(node: ts.Node) { - // // Only consider exported nodes - // if (!isNodeExported(node)) { - // return; - // } - - // console.log('Node', node.kind, node?.['name']?.escapedText) - - if (ts.isModuleDeclaration(node)) { - // This is a namespace, visit its children - console.log('check') - ts.forEachChild(node, visit); - } else if (ts.isTypeAliasDeclaration(node)) { - console.log('isTypeAliasDeclaration', node.name.escapedText) - - let symbol = typeChecker.getSymbolAtLocation(node.name); - if (symbol) { - const symbolType = typeChecker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration) - const symbolSignature = typeChecker.getSignaturesOfType(symbolType, ts.SignatureKind.Call) - - // checker.getResolvedSignature(symbol) - console.log('symbol', symbol.getName(), symbolSignature) - - // getTypeOfSymbolAtLocation - // getResolvedSignature - } - } else if (ts.isCallExpression(node)) { - console.log('isCallExpression', node.expression) - } else if (ts.isFunctionDeclaration(node)) { - console.log('isFunctionDeclaration', node.name.escapedText, { typeParameter0: node.typeParameters[0] }) - - if (node.name.escapedText === 'infer') { - const param0 = node.typeParameters[0] - if (ts.isPropertyDeclaration(param0)) { - const symbol = typeChecker.getSymbolAtLocation(param0) - - // TODO: get resolving - - // console.log('getResolvedSignature', typeChecker.getResolvedSignature(node) ) - - // const symbolType = typeChecker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration) - // const symbolSignature = typeChecker.getSignaturesOfType(symbolType, ts.SignatureKind.Call) - // console.log('symbol', symbol.getName(), symbolSignature) - - // console.log('getSignaturesOfType', typeChecker.getSignaturesOfType(param0) - } - } - } - } -}