X Tutup
#!/usr/bin/env node import * as ts from "typescript"; import * as tstl from "."; import * as cliDiagnostics from "./cli/diagnostics"; import { getHelpString, versionString } from "./cli/information"; import { parseCommandLine } from "./cli/parse"; import { createDiagnosticReporter } from "./cli/report"; import { createConfigFileUpdater, locateConfigFile, parseConfigFileWithSystem } from "./cli/tsconfig"; import { isBundleEnabled } from "./CompilerOptions"; import * as performance from "./measure-performance"; const shouldBePretty = ({ pretty }: ts.CompilerOptions = {}) => pretty !== undefined ? (pretty as boolean) : ts.sys.writeOutputIsTTY?.() ?? false; let reportDiagnostic = createDiagnosticReporter(false); function updateReportDiagnostic(options?: ts.CompilerOptions): void { reportDiagnostic = createDiagnosticReporter(shouldBePretty(options)); } function createWatchStatusReporter(options?: ts.CompilerOptions): ts.WatchStatusReporter { return ts.createWatchStatusReporter(ts.sys, shouldBePretty(options)); } function executeCommandLine(args: string[]): void { if (args.length > 0 && args[0].startsWith("-")) { const firstOption = args[0].slice(args[0].startsWith("--") ? 2 : 1).toLowerCase(); if (firstOption === "build" || firstOption === "b") { return performBuild(args.slice(1)); } } const commandLine = parseCommandLine(args); if (commandLine.options.build) { reportDiagnostic(cliDiagnostics.optionBuildMustBeFirstCommandLineArgument()); return ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); } // TODO: ParsedCommandLine.errors isn't meant to contain warnings. Once root-level options // support would be dropped it should be changed to `commandLine.errors.length > 0`. if (commandLine.errors.some(e => e.category === ts.DiagnosticCategory.Error)) { commandLine.errors.forEach(reportDiagnostic); return ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); } if (commandLine.options.version) { console.log(versionString); return ts.sys.exit(ts.ExitStatus.Success); } if (commandLine.options.help) { console.log(versionString); console.log(getHelpString()); return ts.sys.exit(ts.ExitStatus.Success); } const configFileName = locateConfigFile(commandLine); if (typeof configFileName === "object") { reportDiagnostic(configFileName); return ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); } const commandLineOptions = commandLine.options; if (configFileName) { const configParseResult = parseConfigFileWithSystem(configFileName, commandLineOptions); updateReportDiagnostic(configParseResult.options); if (configParseResult.options.watch) { createWatchOfConfigFile(configFileName, commandLineOptions); } else { performCompilation( configParseResult.fileNames, configParseResult.projectReferences, configParseResult.options, ts.getConfigFileParsingDiagnostics(configParseResult) ); } } else { updateReportDiagnostic(commandLineOptions); if (commandLineOptions.watch) { createWatchOfFilesAndCompilerOptions(commandLine.fileNames, commandLineOptions); } else { performCompilation(commandLine.fileNames, commandLine.projectReferences, commandLineOptions); } } } function performBuild(_args: string[]): void { console.log("Option '--build' is not supported."); return ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsSkipped); } function performCompilation( rootNames: string[], projectReferences: readonly ts.ProjectReference[] | undefined, options: tstl.CompilerOptions, configFileParsingDiagnostics?: readonly ts.Diagnostic[] ): void { if (options.measurePerformance) performance.enableMeasurement(); performance.startSection("createProgram"); const program = ts.createProgram({ rootNames, options, projectReferences, configFileParsingDiagnostics, }); const preEmitDiagnostics = ts.getPreEmitDiagnostics(program); performance.endSection("createProgram"); const { diagnostics: transpileDiagnostics, emitSkipped } = new tstl.Transpiler().emit({ program }); const diagnostics = ts.sortAndDeduplicateDiagnostics([...preEmitDiagnostics, ...transpileDiagnostics]); diagnostics.forEach(reportDiagnostic); if (options.measurePerformance) reportPerformance(); const exitCode = diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error).length === 0 ? ts.ExitStatus.Success : emitSkipped ? ts.ExitStatus.DiagnosticsPresent_OutputsSkipped : ts.ExitStatus.DiagnosticsPresent_OutputsGenerated; return ts.sys.exit(exitCode); } function createWatchOfConfigFile(configFileName: string, optionsToExtend: tstl.CompilerOptions): void { const watchCompilerHost = ts.createWatchCompilerHost( configFileName, optionsToExtend, ts.sys, ts.createSemanticDiagnosticsBuilderProgram, undefined, createWatchStatusReporter(optionsToExtend) ); updateWatchCompilationHost(watchCompilerHost, optionsToExtend); ts.createWatchProgram(watchCompilerHost); } function createWatchOfFilesAndCompilerOptions(rootFiles: string[], options: tstl.CompilerOptions): void { const watchCompilerHost = ts.createWatchCompilerHost( rootFiles, options, ts.sys, ts.createSemanticDiagnosticsBuilderProgram, undefined, createWatchStatusReporter(options) ); updateWatchCompilationHost(watchCompilerHost, options); ts.createWatchProgram(watchCompilerHost); } function updateWatchCompilationHost( host: ts.WatchCompilerHost, optionsToExtend: tstl.CompilerOptions ): void { let hadErrorLastTime = true; const updateConfigFile = createConfigFileUpdater(optionsToExtend); const transpiler = new tstl.Transpiler(); host.afterProgramCreate = builderProgram => { const program = builderProgram.getProgram(); const options = builderProgram.getCompilerOptions() as tstl.CompilerOptions; if (options.measurePerformance) performance.enableMeasurement(); const configFileParsingDiagnostics: ts.Diagnostic[] = updateConfigFile(options); let sourceFiles: ts.SourceFile[] | undefined; if (!isBundleEnabled(options) && !hadErrorLastTime) { sourceFiles = []; while (true) { const currentFile = builderProgram.getSemanticDiagnosticsOfNextAffectedFile(); if (!currentFile) break; if ("fileName" in currentFile.affected) { sourceFiles.push(currentFile.affected); } else { sourceFiles.push(...currentFile.affected.getSourceFiles()); } } } const { diagnostics: emitDiagnostics } = transpiler.emit({ program, sourceFiles }); const diagnostics = ts.sortAndDeduplicateDiagnostics([ ...configFileParsingDiagnostics, ...program.getOptionsDiagnostics(), ...program.getSyntacticDiagnostics(), ...program.getGlobalDiagnostics(), ...program.getSemanticDiagnostics(), ...emitDiagnostics, ]); diagnostics.forEach(reportDiagnostic); if (options.measurePerformance) reportPerformance(); const errors = diagnostics.filter(d => d.category === ts.DiagnosticCategory.Error); hadErrorLastTime = errors.length > 0; host.onWatchStatusChange!(cliDiagnostics.watchErrorSummary(errors.length), host.getNewLine(), options); }; } function reportPerformance() { if (performance.isMeasurementEnabled()) { console.log("Performance measurements: "); performance.forEachMeasure((name, duration) => { console.log(` ${name}: ${duration.toFixed(2)}ms`); }); console.log(`Total: ${performance.getTotalDuration().toFixed(2)}ms`); performance.disableMeasurement(); } } function checkNodeVersion(): void { const [major, minor] = process.version.slice(1).split(".").map(Number); const isValid = major > 12 || (major === 12 && minor >= 13); if (!isValid) { console.error(`TypeScriptToLua requires Node.js >=12.13.0, the current version is ${process.version}`); process.exit(1); } } checkNodeVersion(); if (ts.sys.setBlocking) { ts.sys.setBlocking(); } executeCommandLine(ts.sys.args);
X Tutup