From 87daee7c06766985df4d3e5f1548d1bccc319c65 Mon Sep 17 00:00:00 2001 From: garrettmills Date: Fri, 14 Jan 2022 01:03:50 -0600 Subject: [PATCH] WIP: create ts-patch tsc transformers for mapping interface -> zodified schemata --- package.json | 4 +- pnpm-lock.yaml | 111 ++++++++++++++- src/phases/CompilePhase.ts | 6 +- src/phases/PreparePhase.ts | 25 ++++ src/phases/ZodifyPhase.ts | 14 +- src/transformer.ts | 274 +++++++++++++++++++++++++++++++++++++ 6 files changed, 429 insertions(+), 5 deletions(-) create mode 100644 src/transformer.ts diff --git a/package.json b/package.json index 5ad05dd..3154f66 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "lib/**/*" ], "bin": { - "excc": "lib/excc.js" + "excc": "lib/excc.js" }, "prepare": "pnpm run build", "postversion": "git push && git push --tags", @@ -47,7 +47,9 @@ "mkdirp": "^1.0.4", "rfdc": "^1.3.0", "rimraf": "^3.0.2", + "ts-expose-internals": "^4.5.4", "ts-node": "^10.4.0", + "ts-patch": "^2.0.1", "ts-to-zod": "^1.8.0", "typescript": "^4.5.2", "uuid": "^8.3.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c640401..ac942f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,7 +17,9 @@ specifiers: mkdirp: ^1.0.4 rfdc: ^1.3.0 rimraf: ^3.0.2 + ts-expose-internals: ^4.5.4 ts-node: ^10.4.0 + ts-patch: ^2.0.1 ts-to-zod: ^1.8.0 typescript: ^4.5.2 uuid: ^8.3.2 @@ -36,7 +38,9 @@ dependencies: mkdirp: 1.0.4 rfdc: 1.3.0 rimraf: 3.0.2 + ts-expose-internals: 4.5.4 ts-node: 10.4.0_typescript@4.5.2 + ts-patch: 2.0.1_typescript@4.5.2 ts-to-zod: 1.8.0 typescript: 4.5.2 uuid: 8.3.2 @@ -945,6 +949,10 @@ packages: dev: false optional: true + /function-bind/1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + dev: false + /functional-red-black-tree/1.0.1: resolution: {integrity: sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=} dev: true @@ -972,6 +980,15 @@ packages: once: 1.4.0 path-is-absolute: 1.0.1 + /global-prefix/3.0.0: + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} + dependencies: + ini: 1.3.8 + kind-of: 6.0.3 + which: 1.3.1 + dev: false + /globals/13.12.0: resolution: {integrity: sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==} engines: {node: '>=8'} @@ -998,6 +1015,13 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + /has/1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + dev: false + /iconv-lite/0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -1045,6 +1069,10 @@ packages: /inherits/2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + /ini/1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: false + /inquirer/8.2.0: resolution: {integrity: sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==} engines: {node: '>=8.0.0'} @@ -1065,6 +1093,11 @@ packages: through: 2.3.8 dev: false + /interpret/1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + dev: false + /is-binary-path/2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -1072,6 +1105,12 @@ packages: binary-extensions: 2.2.0 dev: false + /is-core-module/2.8.1: + resolution: {integrity: sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==} + dependencies: + has: 1.0.3 + dev: false + /is-docker/2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -1125,7 +1164,6 @@ packages: /isexe/2.0.0: resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=} - dev: true /js-yaml/4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} @@ -1156,6 +1194,11 @@ packages: graceful-fs: 4.2.9 dev: false + /kind-of/6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + dev: false + /levn/0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -1235,6 +1278,10 @@ packages: dependencies: brace-expansion: 1.1.11 + /minimist/1.2.5: + resolution: {integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==} + dev: false + /mkdirp/1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} @@ -1329,6 +1376,10 @@ packages: engines: {node: '>=8'} dev: true + /path-parse/1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: false + /path-type/4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -1377,6 +1428,13 @@ packages: picomatch: 2.3.0 dev: false + /rechoir/0.6.2: + resolution: {integrity: sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=} + engines: {node: '>= 0.10'} + dependencies: + resolve: 1.21.0 + dev: false + /regexpp/3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} @@ -1387,6 +1445,15 @@ packages: engines: {node: '>=4'} dev: true + /resolve/1.21.0: + resolution: {integrity: sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==} + hasBin: true + dependencies: + is-core-module: 2.8.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: false + /restore-cursor/3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -1452,6 +1519,16 @@ packages: engines: {node: '>=8'} dev: true + /shelljs/0.8.5: + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + engines: {node: '>=4'} + hasBin: true + dependencies: + glob: 7.2.0 + interpret: 1.4.0 + rechoir: 0.6.2 + dev: false + /signal-exit/3.0.6: resolution: {integrity: sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==} dev: false @@ -1492,6 +1569,11 @@ packages: dependencies: has-flag: 4.0.0 + /supports-preserve-symlinks-flag/1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: false + /text-table/0.2.0: resolution: {integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=} dev: true @@ -1541,6 +1623,10 @@ packages: dependencies: is-number: 7.0.0 + /ts-expose-internals/4.5.4: + resolution: {integrity: sha512-HobejGI9ZnpRlyA0nlpIBpLG8A/gv+pDXP3L0OTRTqkJiInz3+yoMnRCaxw343pzQtxCYM0J/gpZ4IkLudrOWw==} + dev: false + /ts-node/10.4.0_typescript@4.5.2: resolution: {integrity: sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==} hasBin: true @@ -1570,6 +1656,22 @@ packages: yn: 3.1.1 dev: false + /ts-patch/2.0.1_typescript@4.5.2: + resolution: {integrity: sha512-mP7beU1QkmyDs1+SzXYVaSTD6Xo7ZCibOJ3sZkb/xsQjoAQXvn4oPjk0keC2LfCNAgilqtqgjiWp3pQri1uz4w==} + hasBin: true + peerDependencies: + typescript: '>=4.0.0' + dependencies: + chalk: 4.1.2 + glob: 7.2.0 + global-prefix: 3.0.0 + minimist: 1.2.5 + resolve: 1.21.0 + shelljs: 0.8.5 + strip-ansi: 6.0.1 + typescript: 4.5.2 + dev: false + /ts-to-zod/1.8.0: resolution: {integrity: sha512-kxduq1dp7qj9A+cY+yXb4ynJgpOt5TteeiKfp6is7WDVKLa7G/ofQI4myemTJ53TZCblOhQbCUr9nA/zXMORkg==} hasBin: true @@ -1680,6 +1782,13 @@ packages: defaults: 1.0.3 dev: false + /which/1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: false + /which/2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} diff --git a/src/phases/CompilePhase.ts b/src/phases/CompilePhase.ts index 9d1c21f..d0eba7d 100644 --- a/src/phases/CompilePhase.ts +++ b/src/phases/CompilePhase.ts @@ -15,9 +15,11 @@ export class CompilePhase extends Phase { } public run(): Promise { + const dir = this.config.compileDir || 'exbuild' + Logger.verb('tsc', 'transpile sources') - Logger.verb('++', `tsc -p ${path.resolve(this.tsconfigPath)}`) - const tsc = childProcess.spawn('tsc', ['-p', path.resolve(this.tsconfigPath)]) + Logger.verb('++', `tsc -p ${path.resolve(dir, this.tsconfigPath)}`) + const tsc = childProcess.spawn('./node_modules/.bin/tsc', ['-p', path.resolve(dir, this.tsconfigPath)]) tsc.stdout.on('data', (output: Buffer) => { Logger.info('tsc', output.toString('utf-8')) diff --git a/src/phases/PreparePhase.ts b/src/phases/PreparePhase.ts index b6071dd..5110a59 100644 --- a/src/phases/PreparePhase.ts +++ b/src/phases/PreparePhase.ts @@ -29,12 +29,37 @@ export class PreparePhase extends Phase { await fse.copy(src, path.join(dir, src)) } + const transformerPath = path.resolve(__dirname, '..', 'transformer.js') + Logger.verb('prepare', `copy ${transformerPath}`) + await fse.copy(transformerPath, path.join(dir, 'transformer.js')) + const tsconfig = rfdc()(this.tsconfig) const outDir = tsconfig?.compilerOptions?.outDir || './lib' if ( !tsconfig.compilerOptions ) { tsconfig.compilerOptions = {} } + if ( !tsconfig.compilerOptions.plugins ) { + tsconfig.compilerOptions.plugins = [] + } + + tsconfig.compilerOptions.plugins.push({ + transform: './transformer.js', + import: 'identifierProgram', + }) + + tsconfig.compilerOptions.plugins.push({ + transform: './transformer.js', + import: 'transformProgram', + transformProgram: true, + }) + + /* tsconfig.compilerOptions.plugins.push({ + transform: './transformer.js', + import: 'transformerProgram', + after: true, + })*/ + tsconfig.compilerOptions.outDir = path.join('..', outDir) fse.writeFileSync(path.join(dir, 'tsconfig.json'), JSON.stringify(tsconfig, undefined, 4)) diff --git a/src/phases/ZodifyPhase.ts b/src/phases/ZodifyPhase.ts index 6a68fd7..26d31fc 100644 --- a/src/phases/ZodifyPhase.ts +++ b/src/phases/ZodifyPhase.ts @@ -17,6 +17,8 @@ async function* walk(dir: string): any { } export class ZodifyPhase extends Phase { + private static zodId = 1 + constructor( config: ExtolloCompileConfig, tsconfig: any, @@ -68,11 +70,21 @@ export class ZodifyPhase extends Phase { lines.forEach((lineVal, idx) => { if ( idx === line ) { newlines.push('import { z } from "zod";') + newlines.push('import { registerZodifiedSchema } from "@extollo/lib";') } newlines.push(lineVal) }) - return [...newlines, ...zodSource.split('\n').slice(2)].join('\n') + const id = ZodifyPhase.zodId++ + const zodLines = [ + `/** @ex-zod-id ${id}@ */`, + ...zodSource.split('\n') + .filter(x => x.trim()) + .slice(2), + `registerZodifiedSchema(${id}, exZodifiedSchema);`, + ] + + return [...newlines, ...zodLines].join('\n') } } diff --git a/src/transformer.ts b/src/transformer.ts new file mode 100644 index 0000000..a8a8908 --- /dev/null +++ b/src/transformer.ts @@ -0,0 +1,274 @@ +import * as ts from 'typescript' +import {} from 'ts-expose-internals' + +const interfaceDeclarations = [] as ts.InterfaceDeclaration[] +const zodifiedIds = [] as string[] + +const identifierProgram = (program: ts.Program, options: any) => { + return (context: ts.TransformationContext) => { + const factory = context.factory + + return (sourceFile: ts.SourceFile) => { + console.log(`TT: ${sourceFile.fileName} : ${interfaceDeclarations.length}`) // eslint-disable-line no-console + const visitor = (node: ts.Node): ts.Node => { + if ( ts.isNewExpression(node) ) { + const exp = node as ts.NewExpression + console.log(`New Expression: ${exp.expression.getText()}`) // eslint-disable-line no-console + + const schema = [] as number[] + for ( const type of exp.typeArguments ?? [] ) { + console.log(`Type symbol: ${type.localSymbol?.name} : ${type.id} : ${type.getText()}`) // eslint-disable-line no-console + + for ( const decl of interfaceDeclarations ) { + if ( decl.name.symbol === (type as any).typeName.symbol ) { + console.log(`Match to interface: ${decl.name.text}`) // eslint-disable-line no-console + console.log(decl) // eslint-disable-line no-console + + const id = parseInt(zodifiedIds[interfaceDeclarations.indexOf(decl)], 10) + if ( !isNaN(id) ) { + schema.push(id) + } + } + } + } + + console.log(schema) // eslint-disable-line no-console + + const call = factory.createCallExpression( + factory.createParenthesizedExpression(factory.createArrowFunction( + undefined, + undefined, + [], + undefined, + factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + factory.createBlock( + [ + factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [factory.createVariableDeclaration( + factory.createIdentifier('vI'), + undefined, + undefined, + node, + )], + ts.NodeFlags.Const, + ), + ), + factory.createExpressionStatement(factory.createBinaryExpression( + factory.createPropertyAccessExpression( + factory.createParenthesizedExpression(factory.createAsExpression( + factory.createIdentifier('vI'), + factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + )), + factory.createIdentifier('__exZodifiedSchemata'), + ), + factory.createToken(ts.SyntaxKind.EqualsToken), + factory.createArrayLiteralExpression( + schema.map(x => factory.createNumericLiteral(x)), + false, + ), + )), + factory.createReturnStatement(factory.createIdentifier('vI')), + ], + true, + ), + )), + undefined, + [], + ) + + return call + } + + return ts.visitEachChild(node, visitor, context) + } + + return ts.visitEachChild(sourceFile, visitor, context) + } + } +} + +function transformAst(this: typeof ts, context: ts.TransformationContext) { + // eslint-disable-next-line @typescript-eslint/no-this-alias,no-invalid-this + const tsInstance = this + + return (sourceFile: ts.SourceFile) => { + if ( sourceFile.fileName.endsWith('.d.ts') ) { + return sourceFile + } + + console.log(`ID: ${sourceFile.fileName}`) // eslint-disable-line no-console + const visit = (node: ts.Node): ts.Node => { + if ( ts.isInterfaceDeclaration(node) ) { + console.log(`Interface Declaration: ${(node as ts.InterfaceDeclaration).name}`) // eslint-disable-line no-console + + if ( sourceFile.identifiers.has('exZodifiedSchema') ) { + const id = [...(sourceFile as any).statements].reverse()[0].expression.arguments[0].text + console.log('Zod-ID: ' + id) // eslint-disable-line no-console + + interfaceDeclarations.push(node) + zodifiedIds.push(id) + } + } + + return tsInstance.visitEachChild(node, visit, context) + } + + return tsInstance.visitEachChild(sourceFile, visit, context) + } +} + +/** + * Patches existing Compiler Host (or creates new one) to allow feeding updated file content from cache + */ +function getPatchedHost( + maybeHost: ts.CompilerHost | undefined, + tsInstance: typeof ts, + compilerOptions: ts.CompilerOptions, +): ts.CompilerHost & { fileCache: Map } { + const fileCache = new Map() + const compilerHost = maybeHost ?? tsInstance.createCompilerHost(compilerOptions, true) + const originalGetSourceFile = compilerHost.getSourceFile + + return Object.assign(compilerHost, { + getSourceFile(fileName: string, languageVersion: ts.ScriptTarget) { + fileName = tsInstance.normalizePath(fileName) + if (fileCache.has(fileName)) { + return fileCache.get(fileName) + } + + // eslint-disable-next-line prefer-spread,prefer-rest-params + const sourceFile = originalGetSourceFile.apply(void 0, Array.from(arguments) as any) + fileCache.set(fileName, sourceFile) + + return sourceFile + }, + fileCache, + }) +} + +const transformProgram = (program: ts.Program, host: ts.CompilerHost | undefined, options: any, { ts: tsInstance }: any) => { + const compilerOptions = program.getCompilerOptions() + const compilerHost = getPatchedHost(host, tsInstance, compilerOptions) + const rootFileNames = program.getRootFileNames().map(tsInstance.normalizePath) + + // transform ast + const transformedSource = tsInstance.transform( + [...program.getSourceFiles()], + [transformAst.bind(tsInstance)], + compilerOptions, + ).transformed + + return program + + /* /!* Render modified files and create new SourceFiles for them to use in host's cache *!/ + const { printFile } = tsInstance.createPrinter() + for (const sourceFile of transformedSource) { + const { fileName, languageVersion } = sourceFile + const updatedSourceFile = tsInstance.createSourceFile(fileName, printFile(sourceFile), languageVersion) + compilerHost.fileCache.set(fileName, updatedSourceFile) + } + + /!* Re-create Program instance *!/ + return tsInstance.createProgram(rootFileNames, compilerOptions, compilerHost)*/ +} + +const identifierProgramOld = (program: ts.Program) => { + const transformerFactory: ts.TransformerFactory = context => { + const factory = context.factory + return sourceFile => { + console.log(`ID Source: ${sourceFile.fileName}`) // eslint-disable-line no-console + const visitor = (node: ts.Node): ts.Node => { + if (ts.isInterfaceDeclaration(node)) { + console.log('Found Interface: ' + (node as ts.InterfaceDeclaration).name.text) // eslint-disable-line no-console + interfaceDeclarations.push(node) + } + + return ts.visitEachChild(node, visitor, context) + } + + return ts.visitNode(sourceFile, visitor) + } + } + + return transformerFactory +} + +/* const transformerProgram = (program: ts.Program) => { + // const typeChecker = program.getTypeChecker() + + // Create array of found symbols + // const foundSymbols = new Array() + const typeReferences = [] as ts.TypeReference[] + const newExpressions = [] as ts.NewExpression[] + + const transformerFactory: ts.TransformerFactory = context => { + const factory = context.factory + return sourceFile => { + console.log(`TT Source: ${sourceFile.fileName} : ${interfaceDeclarations.length}`) // eslint-disable-line no-console + const visitor = (node: ts.Node): ts.Node => { + if ( ts.isNewExpression(node) ) { + const exp = node as ts.NewExpression + console.log('New Expression: ' + exp.expression.getText() + ' w/ type args: ' + exp.typeArguments?.[0].getText()) // eslint-disable-line no-console + // newExpressions.push(node) + + const call = factory.createCallExpression( + factory.createParenthesizedExpression(factory.createArrowFunction( + undefined, + undefined, + [], + undefined, + factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + factory.createBlock( + [ + factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [factory.createVariableDeclaration( + factory.createIdentifier('vI'), + undefined, + undefined, + exp, + )], + ts.NodeFlags.Const, + ), + ), + factory.createExpressionStatement(factory.createBinaryExpression( + factory.createPropertyAccessExpression( + factory.createParenthesizedExpression(factory.createAsExpression( + factory.createIdentifier('vI'), + factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + )), + factory.createIdentifier('__exSchema'), + ), + factory.createToken(ts.SyntaxKind.EqualsToken), + factory.createObjectLiteralExpression( + [], + false, + ), + )), + factory.createReturnStatement(factory.createIdentifier('vI')), + ], + true, + ), + )), + undefined, + [], + ) + + console.log('returned call expression') // eslint-disable-line no-console + return call + } + + return ts.visitEachChild(node, visitor, context) + } + + return ts.visitNode(sourceFile, visitor) + } + } + + return transformerFactory +}*/ + +export {identifierProgram, transformProgram}