|
| 1 | +import * as fs from "fs"; |
| 2 | +import * as path from "path"; |
| 3 | +import * as ts from "typescript"; |
| 4 | +import { parseConfigFileContent } from "./CommandLineParser"; |
| 5 | +import { CompilerOptions } from "./CompilerOptions"; |
| 6 | +import { getTranspileOutput, TranspiledFile, TranspilationResult } from "./Transpile"; |
| 7 | + |
| 8 | +export function transpileFiles( |
| 9 | + rootNames: string[], |
| 10 | + options: CompilerOptions = {} |
| 11 | +): TranspilationResult { |
| 12 | + const program = ts.createProgram(rootNames, options); |
| 13 | + const { diagnostics, transpiledFiles } = getTranspileOutput({ program, options }); |
| 14 | + |
| 15 | + const allDiagnostics = ts.sortAndDeduplicateDiagnostics([ |
| 16 | + ...ts.getPreEmitDiagnostics(program), |
| 17 | + ...diagnostics, |
| 18 | + ]); |
| 19 | + |
| 20 | + return { transpiledFiles, diagnostics: [...allDiagnostics] }; |
| 21 | +} |
| 22 | + |
| 23 | +export function transpileProject( |
| 24 | + fileName: string, |
| 25 | + options?: CompilerOptions |
| 26 | +): TranspilationResult { |
| 27 | + const parseResult = parseConfigFileContent( |
| 28 | + fs.readFileSync(fileName, "utf8"), |
| 29 | + fileName, |
| 30 | + options |
| 31 | + ); |
| 32 | + if (parseResult.isValid === false) { |
| 33 | + // TODO: Return diagnostics |
| 34 | + throw new Error(parseResult.errorMessage); |
| 35 | + } |
| 36 | + |
| 37 | + return transpileFiles(parseResult.result.fileNames, parseResult.result.options); |
| 38 | +} |
| 39 | + |
| 40 | +const libCache: { [key: string]: ts.SourceFile } = {}; |
| 41 | +export function createVirtualProgram( |
| 42 | + input: Record<string, string>, |
| 43 | + options?: CompilerOptions |
| 44 | +): ts.Program { |
| 45 | + const compilerHost: ts.CompilerHost = { |
| 46 | + fileExists: () => true, |
| 47 | + getCanonicalFileName: fileName => fileName, |
| 48 | + getCurrentDirectory: () => "", |
| 49 | + getDefaultLibFileName: ts.getDefaultLibFileName, |
| 50 | + readFile: () => "", |
| 51 | + getNewLine: () => "\n", |
| 52 | + useCaseSensitiveFileNames: () => false, |
| 53 | + writeFile: () => {}, |
| 54 | + |
| 55 | + getSourceFile: filename => { |
| 56 | + if (filename in input) { |
| 57 | + return ts.createSourceFile( |
| 58 | + filename, |
| 59 | + input[filename], |
| 60 | + ts.ScriptTarget.Latest, |
| 61 | + false |
| 62 | + ); |
| 63 | + } |
| 64 | + |
| 65 | + if (filename.startsWith("lib.")) { |
| 66 | + if (libCache[filename]) return libCache[filename]; |
| 67 | + const typeScriptDir = path.dirname(require.resolve("typescript")); |
| 68 | + const filePath = path.join(typeScriptDir, filename); |
| 69 | + const content = fs.readFileSync(filePath, "utf8"); |
| 70 | + |
| 71 | + libCache[filename] = ts.createSourceFile( |
| 72 | + filename, |
| 73 | + content, |
| 74 | + ts.ScriptTarget.Latest, |
| 75 | + false |
| 76 | + ); |
| 77 | + |
| 78 | + return libCache[filename]; |
| 79 | + } |
| 80 | + }, |
| 81 | + }; |
| 82 | + |
| 83 | + return ts.createProgram(Object.keys(input), options, compilerHost); |
| 84 | +} |
| 85 | + |
| 86 | +export interface TranspileStringResult { |
| 87 | + file: TranspiledFile; |
| 88 | + diagnostics: ts.Diagnostic[]; |
| 89 | +} |
| 90 | + |
| 91 | +export function transpileString( |
| 92 | + input: string | Record<string, string>, |
| 93 | + options: CompilerOptions = {} |
| 94 | +): TranspileStringResult { |
| 95 | + const programFiles = typeof input === "object" ? input : { "main.ts": input }; |
| 96 | + const mainFileName = |
| 97 | + typeof input === "string" |
| 98 | + ? "main.ts" |
| 99 | + : Object.keys(input).find(x => /\bmain\.[a-z]+$/.test(x)); |
| 100 | + if (mainFileName === undefined) throw new Error('Input should have a file named "main"'); |
| 101 | + |
| 102 | + const program = createVirtualProgram(programFiles, options); |
| 103 | + const { diagnostics, transpiledFiles } = getTranspileOutput({ program, options }); |
| 104 | + |
| 105 | + const allDiagnostics = ts.sortAndDeduplicateDiagnostics([ |
| 106 | + ...ts.getPreEmitDiagnostics(program), |
| 107 | + ...diagnostics, |
| 108 | + ]); |
| 109 | + |
| 110 | + return { file: transpiledFiles.get(mainFileName), diagnostics: [...allDiagnostics] }; |
| 111 | +} |
0 commit comments