Last active
June 18, 2019 18:59
-
-
Save brandonkal/a029f0f2dbc600d69d0ba6ffb83d5154 to your computer and use it in GitHub Desktop.
Typescript Return type from compiled string
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ts from 'typescript' | |
import fs from 'fs' | |
import path from 'path' | |
function transform( | |
contents: string, | |
libSource: string, | |
compilerOptions: ts.CompilerOptions = {} | |
) { | |
if (!compilerOptions.target) { | |
compilerOptions.target = ts.ScriptTarget.ES2015 | |
} | |
// Generated outputs | |
let outputs: any[] = [] | |
// Create a compilerHost object to allow the compiler to read and write files | |
let compilerHost = { | |
getSourceFile: function(filename: string, languageVersion: any) { | |
if (filename === 'file.ts') | |
return ts.createSourceFile( | |
filename, | |
contents, | |
compilerOptions.target!, | |
false | |
) | |
if (filename === 'lib.d.ts') | |
return ts.createSourceFile( | |
filename, | |
libSource, | |
compilerOptions.target!, | |
false | |
) | |
return undefined | |
}, | |
writeFile: function( | |
name: string, | |
text: string, | |
writeByteOrderMark: boolean | |
) { | |
outputs.push({ | |
name: name, | |
text: text, | |
writeByteOrderMark: writeByteOrderMark, | |
}) | |
}, | |
getDefaultLibFileName: function(options: ts.CompilerOptions) { | |
return 'lib.d.ts' | |
}, | |
getDefaultLibName: function(filename: string, languageVersion: any) { | |
return 'lib.d.ts' | |
}, | |
useCaseSensitiveFileNames: function() { | |
return false | |
}, | |
getCanonicalFileName: function(filename: string) { | |
return filename | |
}, | |
getCurrentDirectory: function() { | |
return '' | |
}, | |
getNewLine: function() { | |
return '\n' | |
}, | |
fileExists: function() { | |
return true | |
}, | |
readFile: function() { | |
return '' | |
}, | |
} | |
// Create a program from inputs | |
let program = ts.createProgram(['file.ts'], compilerOptions, compilerHost) | |
// Query for early errors | |
let errors = program.getGlobalDiagnostics() | |
let checker = program.getTypeChecker() | |
let files = program.getSourceFiles() | |
let theType: ts.Type | undefined = undefined | |
// Find type from export | |
files.forEach(file => { | |
if (file.fileName === 'file.ts') { | |
console.log(file) | |
file.forEachChild(node => { | |
if (theType) return | |
if ( | |
node.kind === ts.SyntaxKind.VariableStatement && | |
node.modifiers && | |
node.modifiers[0].kind === ts.SyntaxKind.ExportKeyword | |
) { | |
node.forEachChild(child => { | |
if (theType) return | |
console.log('children') | |
console.log(child) | |
if (child.kind === ts.SyntaxKind.VariableDeclarationList) { | |
child.forEachChild(decl => { | |
if (theType) return | |
theType = checker.getTypeAtLocation(decl) | |
}) | |
} | |
}) | |
} | |
}) | |
} | |
}) | |
let type: ts.Type | |
let returnInfo | |
interface TypeInfo { | |
value?: any | |
kind?: string | |
} | |
let typeArray: TypeInfo[] = [] | |
if (theType !== undefined) { | |
type = theType as ts.Type | |
let getKind = (flags: ts.TypeFlags) => { | |
return flags === ts.TypeFlags.Number | |
? 'number' | |
: flags === ts.TypeFlags.String | |
? 'string' | |
: flags === ts.TypeFlags.StringLiteral | |
? 'stringLiteral' | |
: flags === ts.TypeFlags.NumberLiteral | |
? 'numberLiteral' | |
: 'other' | |
} | |
if (type.isUnion()) { | |
type.types.forEach(current => { | |
if (current.isLiteral()) { | |
current.value | |
typeArray.push({ | |
value: current.value, | |
kind: getKind(current.flags), | |
}) | |
} else { | |
typeArray.push({ | |
kind: getKind(current.flags), | |
}) | |
} | |
}) | |
} | |
let value: boolean | string | ts.PseudoBigInt | number = false | |
if (type.isLiteral()) value = type.value | |
returnInfo = { | |
union: type.isUnion(), | |
kind: getKind(type.flags), | |
types: typeArray, | |
value: value, | |
} | |
} | |
return { | |
outputs: outputs, | |
type: returnInfo, | |
errors: errors, | |
} | |
} | |
// Calling our transform function and loading the default library: | |
let source = "export const x = (1 == 2 && 'awesome') || 'not cool'" | |
let libSource = fs | |
.readFileSync( | |
path.join(path.dirname(require.resolve('typescript')), 'lib.d.ts') | |
) | |
.toString() | |
let result = transform(source, libSource) | |
debugger | |
console.log(JSON.stringify(result)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment