Last active
February 3, 2023 22:33
-
-
Save rnag/0d8fe2e72dc7b48743c13f9ca8837a4c to your computer and use it in GitHub Desktop.
TypeScript Compiler API - Example
This file contains 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
// TypeScript code to programatically run the equivalent of `tsc` | |
// | |
// With Slight modifications, such as *Colorized* output being displayed. | |
// | |
// However, the nice one-line Error Summary that `tsc` gives you (e.g. Errors in X files) is currently missing. | |
// | |
// Refs: | |
// - https://github.com/microsoft/TypeScript-wiki/blob/main/Using-the-Compiler-API.md | |
// - https://github.com/Microsoft/TypeScript/issues/6387#issuecomment-169739615 | |
import { readFileSync } from 'node:fs'; | |
import { dirname } from 'node:path'; | |
import { exit } from 'process'; | |
import ts from 'typescript'; | |
// TODO | |
const rootDir = '.'; | |
const { | |
useCaseSensitiveFileNames, | |
// getCurrentDirectory, | |
newLine, | |
} = ts.sys; | |
const getCanonicalPath: (path: string) => string = | |
useCaseSensitiveFileNames ? (v) => v : (v) => v.toLowerCase(); | |
function getNewLine(): string { | |
return newLine; | |
} | |
function reportDiagnostics( | |
diagnostics: ts.Diagnostic[], | |
curDir = rootDir | |
) { | |
if (diagnostics.length == 0) return; | |
const formatDiagnosticsHost: ts.FormatDiagnosticsHost = { | |
getCurrentDirectory: () => curDir, | |
getCanonicalFileName: getCanonicalPath, | |
getNewLine: getNewLine, | |
}; | |
// De-duplicate diagnostics, as mentioned here: | |
// https://github.com/microsoft/TypeScript/issues/20876 | |
const allDiagnostics = | |
ts.sortAndDeduplicateDiagnostics(diagnostics); | |
console.log( | |
ts.formatDiagnosticsWithColorAndContext( | |
allDiagnostics, | |
formatDiagnosticsHost | |
) | |
); | |
// allDiagnostics.forEach((diagnostic) => { | |
// if (diagnostic.file) { | |
// const { line, character } = | |
// diagnostic.file.getLineAndCharacterOfPosition( | |
// diagnostic.start! | |
// ); | |
// const message = ts.flattenDiagnosticMessageText( | |
// diagnostic.messageText, | |
// '\n' | |
// ); | |
// console.log( | |
// `${diagnostic.file.fileName} (${line + 1},${ | |
// character + 1 | |
// }): ${message}` | |
// ); | |
// } else { | |
// console.log( | |
// ts.flattenDiagnosticMessageText( | |
// diagnostic.messageText, | |
// '\n' | |
// ) | |
// ); | |
// } | |
// }); | |
} | |
function readConfigFile(configFileName: string) { | |
// Read config file | |
const configFileText = readFileSync(configFileName).toString(); | |
// Parse JSON, after removing comments. Just fancier JSON.parse | |
const result = ts.parseConfigFileTextToJson( | |
configFileName, | |
configFileText | |
); | |
const configObject = result.config; | |
if (!configObject) { | |
reportDiagnostics([result.error!]); | |
exit(1); | |
} | |
// Extract config infromation | |
const configParseResult = ts.parseJsonConfigFileContent( | |
configObject, | |
ts.sys, | |
dirname(configFileName) | |
); | |
if (configParseResult.errors.length > 0) { | |
reportDiagnostics(configParseResult.errors); | |
exit(1); | |
} | |
return configParseResult; | |
} | |
const compile = (configFileName: string) => { | |
// Extract configuration from config file | |
const config = readConfigFile(configFileName); | |
// Compile | |
const program = ts.createProgram( | |
config.fileNames, | |
config.options | |
); | |
const emitResult = program.emit(); | |
const allDiagnostics = ts | |
.getPreEmitDiagnostics(program) | |
.concat(emitResult.diagnostics); | |
// Report errors | |
reportDiagnostics(allDiagnostics); | |
// Check return code | |
if (emitResult.emitSkipped) { | |
const exitCode = 1; | |
console.log(`Process exiting with code '${exitCode}'.`); | |
exit(exitCode); | |
} | |
}; | |
// TODO | |
compile(process.argv[2]); | |
// run with: | |
// npx ts-node ts-compile.ts tsconfig.json |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment