1/* 2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import * as fs from 'node:fs'; 17import * as os from 'node:os'; 18import * as path from 'node:path'; 19import * as readline from 'node:readline'; 20import type { CommandLineOptions } from '../lib/CommandLineOptions'; 21import { lint } from '../lib/LinterRunner'; 22import { Logger } from '../lib/Logger'; 23import type { ProblemInfo } from '../lib/ProblemInfo'; 24import { TypeScriptLinter } from '../lib/TypeScriptLinter'; 25import { parseCommandLine } from './CommandLineParser'; 26import { compileLintOptions } from './Compiler'; 27 28export function run(): void { 29 const commandLineArgs = process.argv.slice(2); 30 if (commandLineArgs.length === 0) { 31 Logger.info('Command line error: no arguments'); 32 process.exit(-1); 33 } 34 35 const cmdOptions = parseCommandLine(commandLineArgs); 36 37 if (cmdOptions.testMode) { 38 TypeScriptLinter.testMode = true; 39 } 40 41 TypeScriptLinter.initGlobals(); 42 43 if (!cmdOptions.ideMode) { 44 const result = lint(compileLintOptions(cmdOptions)); 45 process.exit(result.errorNodes > 0 ? 1 : 0); 46 } else { 47 runIDEMode(cmdOptions); 48 } 49} 50 51function getTempFileName(): string { 52 return path.join(os.tmpdir(), Math.floor(Math.random() * 10000000).toString() + '_linter_tmp_file.ts'); 53} 54 55function showJSONMessage(problems: ProblemInfo[][]): void { 56 const jsonMessage = problems[0].map((x) => { 57 return { 58 line: x.line, 59 column: x.column, 60 start: x.start, 61 end: x.end, 62 type: x.type, 63 suggest: x.suggest, 64 rule: x.rule, 65 severity: x.severity, 66 autofix: x.autofix 67 }; 68 }); 69 Logger.info(`{"linter messages":${JSON.stringify(jsonMessage)}}`); 70} 71 72function runIDEMode(cmdOptions: CommandLineOptions): void { 73 TypeScriptLinter.ideMode = true; 74 const tmpFileName = getTempFileName(); 75 // read data from stdin 76 const writeStream = fs.createWriteStream(tmpFileName, { flags: 'w' }); 77 const rl = readline.createInterface({ 78 input: process.stdin, 79 output: writeStream, 80 terminal: false 81 }); 82 83 rl.on('line', (line: string) => { 84 fs.appendFileSync(tmpFileName, line + '\n'); 85 }); 86 rl.once('close', () => { 87 // end of input 88 writeStream.close(); 89 cmdOptions.inputFiles = [tmpFileName]; 90 if (cmdOptions.parsedConfigFile) { 91 cmdOptions.parsedConfigFile.fileNames.push(tmpFileName); 92 } 93 const result = lint(compileLintOptions(cmdOptions)); 94 const problems = Array.from(result.problemsInfos.values()); 95 if (problems.length === 1) { 96 showJSONMessage(problems); 97 } else { 98 Logger.error('Unexpected error: could not lint file'); 99 } 100 fs.unlinkSync(tmpFileName); 101 }); 102} 103