Skip to content
This repository has been archived by the owner on Aug 7, 2023. It is now read-only.

Commit

Permalink
Merge pull request #396 from AtomLinter/config-extends
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya committed Apr 5, 2021
2 parents 9fe2347 + c2189f7 commit a22d785
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 23 deletions.
12 changes: 7 additions & 5 deletions lib/compat-shim.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import type * as Tslint from "tslint";

type LinterTslintV3 = (filePath: string, text: string, configuration: Tslint.ILinterOptions) => { lint: () => Tslint.LintResult[] }

/**
* Shim for TSLint v3 interoperability
* @param {Function} Linter TSLint v3 linter
* @return {Function} TSLint v4-compatible linter
*/
export function shim(Linter: Function): typeof Tslint.Linter {
function LinterShim(options) {
export function shim(Linter: LinterTslintV3): typeof Tslint.Linter {
function LinterShim(options: Tslint.ILinterOptions) {
this.options = options;
this.results = {};
}
Expand All @@ -17,9 +19,9 @@ export function shim(Linter: Function): typeof Tslint.Linter {
// Assign instance methods
LinterShim.prototype = {
...Linter.prototype,
lint(filePath, text, configuration) {
const options = { ...this.options, configuration };
const linter = new Linter(filePath, text, options);
lint(filePath: string, text: string, configuration: Tslint.ILinterOptions) {
const options : Tslint.ILinterOptions = { ...this.options, configuration };
const linter = new Linter(filePath, text, options) as ReturnType<LinterTslintV3>;
this.results = linter.lint();
},
getResult() {
Expand Down
77 changes: 60 additions & 17 deletions lib/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { emit } from 'node:cluster';
import type * as Tslint from "tslint";
import type * as Ts from "typescript";
import type { JobMessage, ConfigMessage } from "./workerHelper"
import { RuleFailure } from 'tslint';

process.title = 'linter-tslint worker';

Expand All @@ -24,7 +25,7 @@ let fallbackLinter: typeof Tslint.Linter;
let requireResolve: typeof import("resolve");


function resolveAndCacheLinter(fileDir: string, moduleDir?: string): Promise<typeof Tslint.Linter> {
function resolveAndCacheLinter(fileDir: string, moduleDir?: string): Promise<typeof Tslint.Linter | undefined> {
const basedir = moduleDir || fileDir;
return new Promise((resolve) => {
if (!requireResolve) {
Expand All @@ -34,16 +35,16 @@ function resolveAndCacheLinter(fileDir: string, moduleDir?: string): Promise<typ
tslintModuleName,
{ basedir },
(err, linterPath, pkg) => {
let linter: typeof Tslint.Linter;
if (!err && pkg && /^3|4|5|6\./.test(pkg.version)) {
let linter: typeof Tslint.Linter | undefined = undefined;
if (!err && linterPath !== undefined && pkg && /^3|4|5|6\./.test(pkg.version)) {
if (pkg.version.startsWith('3')) {
// eslint-disable-next-line import/no-dynamic-require
linter = shim(require('loophole').allowUnsafeNewFunction(() => require(linterPath) as typeof import("tslint")));
} else {
// eslint-disable-next-line import/no-dynamic-require
linter = require('loophole').allowUnsafeNewFunction(() => (require(linterPath) as typeof import("tslint")).Linter);
}
tslintCache.set(fileDir, linter);
tslintCache.set(fileDir, linter!);
}
resolve(linter);
},
Expand All @@ -68,7 +69,7 @@ function getNodePrefixPath(): Promise<string> {
});
}

async function getLinter(filePath: string): Promise<typeof Tslint.Linter> {
async function getLinter(filePath: string): Promise<typeof Tslint.Linter | undefined> {
const basedir = path.dirname(filePath);
if (tslintCache.has(basedir)) {
return tslintCache.get(basedir);
Expand All @@ -95,7 +96,7 @@ async function getLinter(filePath: string): Promise<typeof Tslint.Linter> {
}
}

let prefix: string;
let prefix: string | undefined = undefined;
try {
prefix = await getNodePrefixPath();
} catch (err) {
Expand All @@ -120,8 +121,8 @@ async function getLinter(filePath: string): Promise<typeof Tslint.Linter> {
return fallbackLinter;
}

async function getProgram(Linter: typeof Tslint.Linter, configurationPath: string): Promise<Ts.Program> {
let program: Ts.Program;
async function getProgram(Linter: typeof Tslint.Linter, configurationPath: string): Promise<Ts.Program | undefined> {
let program: Ts.Program | undefined = undefined;
const configurationDir = path.dirname(configurationPath);
const tsconfigPath = path.resolve(configurationDir, 'tsconfig.json');
try {
Expand All @@ -135,30 +136,72 @@ async function getProgram(Linter: typeof Tslint.Linter, configurationPath: strin
return program;
}

function getSeverity(failure) {
const severity = failure.ruleSeverity.toLowerCase();
function getSeverity(failure: RuleFailure) {
const severity = failure["ruleSeverity"].toLowerCase();
return ['info', 'warning', 'error'].includes(severity) ? severity : 'warning';
}

let tslint: undefined | typeof import("tslint")

function loadTslintConfig(Linter: typeof Tslint.Linter, filePath: string) {
let configurationPath: string | undefined
let configuration: Tslint.Configuration.IConfigurationFile | undefined
if (typeof Linter.findConfiguration === "function") {
const { path, results } = Linter.findConfiguration(null, filePath)
configurationPath = path
configuration = results
} else {
configurationPath = Linter.findConfigurationPath(null, filePath);
configuration = Linter.loadConfigurationFromPath(configurationPath);
}
// Load extends using `require` - this is a bug in Tslint
let configExtends = configuration?.extends ?? []
if (configurationPath !== undefined && configExtends !== undefined && configExtends.length === 0) {
try {
if (!tslint) {
tslint = require("tslint") as typeof import("tslint")
}
const configurationJson = tslint.Configuration.readConfigurationFile?.(configurationPath)
const extendsJson = configurationJson.extends
if (typeof extendsJson === "string") {
configExtends = [...configExtends, extendsJson]
} else if (extendsJson !== undefined) {
configExtends = [...configExtends, ...extendsJson]
}
} catch { /* ignore error */ }
}
return {
configurationPath,
configuration: configuration !== undefined
? {
...configuration,
extends: configExtends
}
: configuration
}
}

/**
* Lint the provided TypeScript content
* @param content {string} The content of the TypeScript file
* @param filePath {string} File path of the TypeScript filePath
* @param options {Object} Linter options
* @return Array of lint results
*/
async function lint(content: string, filePath: string, options: Tslint.ILinterOptions) {
async function lint(content: string, filePath: string | undefined, options: Tslint.ILinterOptions) {
if (filePath === null || filePath === undefined) {
return null;
}

let lintResult: Tslint.LintResult;
try {
const Linter = await getLinter(filePath);
const configurationPath = Linter.findConfigurationPath(null, filePath);
const configuration = Linter.loadConfigurationFromPath(configurationPath);
if (!Linter) {
throw new Error(`tslint was not found for ${filePath}`)
}
const { configurationPath, configuration } = loadTslintConfig(Linter, filePath)

let { rulesDirectory } = configuration;
let rulesDirectory = configuration?.rulesDirectory;
if (rulesDirectory && configurationPath) {
const configurationDir = path.dirname(configurationPath);
if (!Array.isArray(rulesDirectory)) {
Expand All @@ -176,7 +219,7 @@ async function lint(content: string, filePath: string, options: Tslint.ILinterOp
}
}

let program: Ts.Program;
let program: Ts.Program | undefined = undefined;
if (config.enableSemanticRules && configurationPath) {
program = await getProgram(Linter, configurationPath);
}
Expand All @@ -196,11 +239,11 @@ async function lint(content: string, filePath: string, options: Tslint.ILinterOp

if (
// tslint@<5
!lintResult.failureCount
!(lintResult as any).failureCount
// tslint@>=5
&& !lintResult.errorCount
&& !lintResult.warningCount
&& !lintResult.infoCount
&& !(lintResult as any).infoCount // TODO is this still supported?
) {
return [];
}
Expand Down
2 changes: 1 addition & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const CommonConfig = {
sourcemap: true,
},
],
external: ["atom"],
external: ["atom", "tslint"],
plugins,
}

Expand Down

0 comments on commit a22d785

Please sign in to comment.