13af6ab5fSopenharmony_ci/*
23af6ab5fSopenharmony_ci * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ciimport * as fs from 'node:fs';
173af6ab5fSopenharmony_ciimport * as os from 'node:os';
183af6ab5fSopenharmony_ciimport * as path from 'node:path';
193af6ab5fSopenharmony_ciimport * as readline from 'node:readline';
203af6ab5fSopenharmony_ciimport type { CommandLineOptions } from '../lib/CommandLineOptions';
213af6ab5fSopenharmony_ciimport { lint } from '../lib/LinterRunner';
223af6ab5fSopenharmony_ciimport { Logger } from '../lib/Logger';
233af6ab5fSopenharmony_ciimport type { ProblemInfo } from '../lib/ProblemInfo';
243af6ab5fSopenharmony_ciimport { TypeScriptLinter } from '../lib/TypeScriptLinter';
253af6ab5fSopenharmony_ciimport { parseCommandLine } from './CommandLineParser';
263af6ab5fSopenharmony_ciimport { compileLintOptions } from './Compiler';
273af6ab5fSopenharmony_ciimport type { LintOptions } from '../lib/LintOptions';
283af6ab5fSopenharmony_ci
293af6ab5fSopenharmony_ciexport function run(): void {
303af6ab5fSopenharmony_ci  const commandLineArgs = process.argv.slice(2);
313af6ab5fSopenharmony_ci  if (commandLineArgs.length === 0) {
323af6ab5fSopenharmony_ci    Logger.info('Command line error: no arguments');
333af6ab5fSopenharmony_ci    process.exit(-1);
343af6ab5fSopenharmony_ci  }
353af6ab5fSopenharmony_ci
363af6ab5fSopenharmony_ci  const cmdOptions = parseCommandLine(commandLineArgs);
373af6ab5fSopenharmony_ci
383af6ab5fSopenharmony_ci  if (cmdOptions.testMode) {
393af6ab5fSopenharmony_ci    TypeScriptLinter.testMode = true;
403af6ab5fSopenharmony_ci  }
413af6ab5fSopenharmony_ci
423af6ab5fSopenharmony_ci  TypeScriptLinter.initGlobals();
433af6ab5fSopenharmony_ci
443af6ab5fSopenharmony_ci  if (!cmdOptions.ideMode) {
453af6ab5fSopenharmony_ci    const compileOptions = compileLintOptions(cmdOptions);
463af6ab5fSopenharmony_ci    const result = lint(compileOptions, getEtsLoaderPath(compileOptions));
473af6ab5fSopenharmony_ci    process.exit(result.errorNodes > 0 ? 1 : 0);
483af6ab5fSopenharmony_ci  } else {
493af6ab5fSopenharmony_ci    runIDEMode(cmdOptions);
503af6ab5fSopenharmony_ci  }
513af6ab5fSopenharmony_ci}
523af6ab5fSopenharmony_ci
533af6ab5fSopenharmony_cifunction getTempFileName(): string {
543af6ab5fSopenharmony_ci  return path.join(os.tmpdir(), Math.floor(Math.random() * 10000000).toString() + '_linter_tmp_file.ts');
553af6ab5fSopenharmony_ci}
563af6ab5fSopenharmony_ci
573af6ab5fSopenharmony_cifunction showJSONMessage(problems: ProblemInfo[][]): void {
583af6ab5fSopenharmony_ci  const jsonMessage = problems[0].map((x) => {
593af6ab5fSopenharmony_ci    return {
603af6ab5fSopenharmony_ci      line: x.line,
613af6ab5fSopenharmony_ci      column: x.column,
623af6ab5fSopenharmony_ci      start: x.start,
633af6ab5fSopenharmony_ci      end: x.end,
643af6ab5fSopenharmony_ci      type: x.type,
653af6ab5fSopenharmony_ci      suggest: x.suggest,
663af6ab5fSopenharmony_ci      rule: x.rule,
673af6ab5fSopenharmony_ci      severity: x.severity,
683af6ab5fSopenharmony_ci      autofix: x.autofix
693af6ab5fSopenharmony_ci    };
703af6ab5fSopenharmony_ci  });
713af6ab5fSopenharmony_ci  Logger.info(`{"linter messages":${JSON.stringify(jsonMessage)}}`);
723af6ab5fSopenharmony_ci}
733af6ab5fSopenharmony_ci
743af6ab5fSopenharmony_cifunction runIDEMode(cmdOptions: CommandLineOptions): void {
753af6ab5fSopenharmony_ci  TypeScriptLinter.ideMode = true;
763af6ab5fSopenharmony_ci  const tmpFileName = getTempFileName();
773af6ab5fSopenharmony_ci  // read data from stdin
783af6ab5fSopenharmony_ci  const writeStream = fs.createWriteStream(tmpFileName, { flags: 'w' });
793af6ab5fSopenharmony_ci  const rl = readline.createInterface({
803af6ab5fSopenharmony_ci    input: process.stdin,
813af6ab5fSopenharmony_ci    output: writeStream,
823af6ab5fSopenharmony_ci    terminal: false
833af6ab5fSopenharmony_ci  });
843af6ab5fSopenharmony_ci
853af6ab5fSopenharmony_ci  rl.on('line', (line: string) => {
863af6ab5fSopenharmony_ci    fs.appendFileSync(tmpFileName, line + '\n');
873af6ab5fSopenharmony_ci  });
883af6ab5fSopenharmony_ci  rl.once('close', () => {
893af6ab5fSopenharmony_ci    // end of input
903af6ab5fSopenharmony_ci    writeStream.close();
913af6ab5fSopenharmony_ci    cmdOptions.inputFiles = [tmpFileName];
923af6ab5fSopenharmony_ci    if (cmdOptions.parsedConfigFile) {
933af6ab5fSopenharmony_ci      cmdOptions.parsedConfigFile.fileNames.push(tmpFileName);
943af6ab5fSopenharmony_ci    }
953af6ab5fSopenharmony_ci    const compileOptions = compileLintOptions(cmdOptions);
963af6ab5fSopenharmony_ci    const result = lint(compileOptions, getEtsLoaderPath(compileOptions));
973af6ab5fSopenharmony_ci    const problems = Array.from(result.problemsInfos.values());
983af6ab5fSopenharmony_ci    if (problems.length === 1) {
993af6ab5fSopenharmony_ci      showJSONMessage(problems);
1003af6ab5fSopenharmony_ci    } else {
1013af6ab5fSopenharmony_ci      Logger.error('Unexpected error: could not lint file');
1023af6ab5fSopenharmony_ci    }
1033af6ab5fSopenharmony_ci    fs.unlinkSync(tmpFileName);
1043af6ab5fSopenharmony_ci  });
1053af6ab5fSopenharmony_ci}
1063af6ab5fSopenharmony_ci
1073af6ab5fSopenharmony_ciexport function getEtsLoaderPath(compileOptions: LintOptions): string | undefined {
1083af6ab5fSopenharmony_ci  const tsProgram = compileOptions.tscCompiledProgram.getProgram();
1093af6ab5fSopenharmony_ci  return tsProgram.getCompilerOptions().etsLoaderPath;
1103af6ab5fSopenharmony_ci}
111