• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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';
27import type { LinterConfig } from '../lib/LinterConfig';
28
29export function run(): void {
30  const commandLineArgs = process.argv.slice(2);
31  if (commandLineArgs.length === 0) {
32    Logger.info('Command line error: no arguments');
33    process.exit(-1);
34  }
35
36  const cmdOptions = parseCommandLine(commandLineArgs);
37
38  TypeScriptLinter.initGlobals();
39
40  if (!cmdOptions.linterOptions.ideMode) {
41    const compileOptions = compileLintOptions(cmdOptions);
42    const result = lint(compileOptions, getEtsLoaderPath(compileOptions));
43    process.exit(result.errorNodes > 0 ? 1 : 0);
44  } else {
45    runIDEMode(cmdOptions);
46  }
47}
48
49function getTempFileName(): string {
50  return path.join(os.tmpdir(), Math.floor(Math.random() * 10000000).toString() + '_linter_tmp_file.ts');
51}
52
53function showJSONMessage(problems: ProblemInfo[][]): void {
54  const jsonMessage = problems[0].map((x) => {
55    return {
56      line: x.line,
57      column: x.column,
58      start: x.start,
59      end: x.end,
60      type: x.type,
61      suggest: x.suggest,
62      rule: x.rule,
63      severity: x.severity,
64      autofix: x.autofix
65    };
66  });
67  Logger.info(`{"linter messages":${JSON.stringify(jsonMessage)}}`);
68}
69
70function runIDEMode(cmdOptions: CommandLineOptions): void {
71  cmdOptions.linterOptions.ideMode = true;
72  const tmpFileName = getTempFileName();
73  // read data from stdin
74  const writeStream = fs.createWriteStream(tmpFileName, { flags: 'w' });
75  const rl = readline.createInterface({
76    input: process.stdin,
77    output: writeStream,
78    terminal: false
79  });
80
81  rl.on('line', (line: string) => {
82    fs.appendFileSync(tmpFileName, line + '\n');
83  });
84  rl.once('close', () => {
85    // end of input
86    writeStream.close();
87    cmdOptions.inputFiles = [tmpFileName];
88    if (cmdOptions.parsedConfigFile) {
89      cmdOptions.parsedConfigFile.fileNames.push(tmpFileName);
90    }
91    const compileOptions = compileLintOptions(cmdOptions);
92    const result = lint(compileOptions, getEtsLoaderPath(compileOptions));
93    const problems = Array.from(result.problemsInfos.values());
94    if (problems.length === 1) {
95      showJSONMessage(problems);
96    } else {
97      Logger.error('Unexpected error: could not lint file');
98    }
99    fs.unlinkSync(tmpFileName);
100  });
101}
102
103export function getEtsLoaderPath(linterConfig: LinterConfig): string | undefined {
104  const tsProgram = linterConfig.tscCompiledProgram.getProgram();
105  return tsProgram.getCompilerOptions().etsLoaderPath;
106}
107