Skip to content

Commit 43fe48d

Browse files
authored
[BUG] TsConfig file resolution ignores include if there is also a file node present #272 (#273)
[BUG] TsConfig file resolution ignores include if there is also a file node present #272 - Merged files and include - More debug logging [BUG] eslint ignoreFailures is not ignoring all failures #271 - Add more logging - Add `fileNoFiles` (defaults to true)
1 parent 93a82c8 commit 43fe48d

8 files changed

Lines changed: 162 additions & 33 deletions

File tree

eslint-ts-plugin/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,10 @@ module.exports = function(grunt) {
102102
"lint": {
103103
options: {
104104
format: "codeframe",
105-
suppressWarnings: false
105+
suppressWarnings: false,
106+
debug: true,
107+
logOutput: true,
108+
failNoFiles: false // Defaults to `true` linting will fail if no files are configured
106109
},
107110
"shared": {
108111
tsconfig: "./shared/tsconfig.json",

eslint-ts-plugin/src/eslint-ts-plugin.ts

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,32 @@ function _registerTask(inst: IGrunt, taskName: string) {
2121
let done: grunt.task.AsyncResultCatcher = null;
2222
let gwInst = new GruntWrapper(inst, { debug: false });
2323

24+
let taskOptions: IEslintTsPluginTaskOptions = null;
25+
let loggerOptions: IGruntWrapperOptions = null;
26+
let grunt: GruntWrapper = null;
2427
try {
2528
const options = this.options<IEslintTsPluginTaskOptions>({
2629
});
2730

28-
const taskOptions = getGruntMultiTaskOptions<IEslintTsPluginTaskOptions>(gwInst, this);
29-
const loggerOptions: IGruntWrapperOptions = {
31+
taskOptions = getGruntMultiTaskOptions<IEslintTsPluginTaskOptions>(gwInst, this);
32+
loggerOptions = {
3033
debug: resolveValue(taskOptions.debug, options.debug, false)
3134
}
3235

33-
let grunt = new GruntWrapper(inst, loggerOptions);
36+
grunt = new GruntWrapper(inst, loggerOptions);
3437
if (grunt.isDebug) {
38+
grunt.logVerbose((" Pwd : " + process.cwd()).cyan);
3539
grunt.logVerbose((" Options: [" + dumpObj(options) + "]").cyan);
3640
grunt.logVerbose((" Config : [" + dumpObj(this.data) + "]").cyan);
41+
grunt.logVerbose((" Task : [" + dumpObj(taskOptions) + "]").cyan);
3742
}
3843

3944
done = this.async();
4045
(async function runEslint() {
4146
let tsDefs: Array<string | ITsOption> = [];
4247
let tsconfig = await resolveValueAsync(taskOptions.tsconfig, options.tsconfig);
4348

44-
if (!tsconfig) {
49+
if (tsconfig) {
4550
if (isString(tsconfig)) {
4651
tsDefs.push(tsconfig);
4752
} else if (Array.isArray(tsconfig)) {
@@ -51,26 +56,39 @@ function _registerTask(inst: IGrunt, taskName: string) {
5156
tsDefs.push(value);
5257
});
5358
} else {
54-
grunt.logError("The TSConfig project file [" + tsconfig + "] does not exist");
59+
grunt.logError("The TSConfig project file [" + dumpObj(tsconfig) + "] is unsupported!");
5560
return false;
5661
}
62+
} else {
63+
grunt.logError("Missing TSConfig project file... - " + dumpObj(tsconfig));
64+
return false;
5765
}
5866

5967
for (let lp = 0; lp < tsDefs.length; lp++) {
6068
// eslint-disable-next-line security/detect-non-literal-fs-filename, security/detect-object-injection
6169
let tsDef = tsDefs[lp];
6270

6371
if (isString(tsDef)) {
72+
if (grunt.isDebug) {
73+
grunt.logVerbose("TSConfig: " + tsDef);
74+
}
6475
if (!grunt.file.exists(tsDef)) {
6576
// eslint-disable-next-line security/detect-object-injection
6677
grunt.logError("The TSConfig project file [" + tsDefs[lp] + "] does not exist");
6778
return false;
6879
}
6980
} else if (tsDef.name) {
81+
if (grunt.isDebug) {
82+
grunt.logVerbose("TSConfig: " + tsDef);
83+
}
84+
7085
if (!grunt.file.exists(tsDef.name)) {
7186
grunt.logError("The TSConfig project file [" + tsDef.name + "] does not exist");
7287
return false;
7388
}
89+
} else {
90+
grunt.logError("The TSConfig project file [" + tsDef + "] does not exist");
91+
return false;
7492
}
7593
}
7694

@@ -96,8 +114,6 @@ function _registerTask(inst: IGrunt, taskName: string) {
96114
});
97115

98116
let results: IESLintRunnerResponse = null;
99-
100-
101117

102118
const eslint = new ESLintRunner(grunt, eslintOptions);
103119

@@ -139,8 +155,28 @@ function _registerTask(inst: IGrunt, taskName: string) {
139155
linterConfig.parserOptions.project = theTsConfig;
140156
}
141157

158+
let theFiles = tsDetail.getFiles();
159+
if (theFiles.length === 0 && taskOptions.failNoFiles !== false) {
160+
if (!taskOptions.ignoreFailures) {
161+
grunt.logError("No files found to lint! (disable this error with failNoFiles: false)");
162+
done(true);
163+
return -1;
164+
} else {
165+
grunt.logError("[!] Ignoring Failures: No files found to lint... (disable this error with failNoFiles: false)")
166+
}
167+
}
168+
142169
results = await eslint.lint(linterConfig, tsDetail.getFiles());
143-
170+
} catch (e) {
171+
if (grunt.isDebug) {
172+
grunt.logError("EsLint error: " + e);
173+
}
174+
175+
if (taskOptions.ignoreFailures) {
176+
grunt.logError("[!] Ignoring Failures: The Task failed but continuing... - " + e)
177+
done(true);
178+
return -1;
179+
}
144180
} finally {
145181
tsDetail.cleanupTemp();
146182
}
@@ -160,22 +196,42 @@ function _registerTask(inst: IGrunt, taskName: string) {
160196
}
161197
}),
162198
(response) => {
199+
let theResult = !response.rejected && isSuccess;
163200
if (grunt.isDebug) {
164-
grunt.logVerbose("EsLint response:" + dumpObj(response));
201+
grunt.logVerbose("EsLint response :" + theResult + " - " + dumpObj(response));
202+
}
203+
204+
if (taskOptions.ignoreFailures) {
205+
grunt.logError("[!] Ignoring Failures: The Task failed but continuing... - " + dumpObj(response))
206+
theResult = true;
165207
}
166-
done(!response.rejected && isSuccess);
208+
209+
done(theResult);
167210
});
168211
})().catch((error) => {
212+
let theResult = false;
169213
grunt.logError("EsLint error: " + error);
170-
done(false);
214+
if (taskOptions.ignoreFailures) {
215+
grunt.logError("[!] Ignoring Failures: The Task failed but continuing...")
216+
theResult = true;
217+
}
218+
219+
done(theResult);
171220
});
172221

173222
} catch (e) {
223+
let theResult = false;
174224
inst.log.error("EsLint catch:: " + e + "\n" + dumpObj(e));
225+
226+
if (taskOptions && taskOptions.ignoreFailures) {
227+
inst.log.error("[!] Ignoring Failures: The Task failed but continuing...")
228+
theResult = true;
229+
}
230+
175231
if (done) {
176-
done(false);
232+
done(theResult);
177233
}
178-
return false;
234+
return theResult;
179235
} finally {
180236
if (tempIgnoreFile) {
181237
// cleanup temp file

eslint-ts-plugin/src/interfaces/IEslintTsPluginOptions.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,9 @@ export interface IEslintTsPluginTaskOptions extends IEsLintOptions {
131131
* Ignore failures and continue
132132
*/
133133
ignoreFailures?: boolean;
134+
135+
/**
136+
* Fail the task if no files are found to process (default is true)
137+
*/
138+
failNoFiles?: boolean;
134139
}

gruntfile.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ module.exports = function (grunt) {
9191
ignoreFailures: true
9292
},
9393
"shared-test-fix": {
94+
tsconfig: "./shared/test/tsconfig.test.json",
9495
options: {
95-
tsconfig: "./shared/test/tsconfig.test.json",
9696
fix: true
9797
}
9898
},
@@ -105,23 +105,23 @@ module.exports = function (grunt) {
105105
ignoreFailures: true
106106
},
107107
"shared-fix": {
108+
tsconfig: "./shared/tsconfig.json",
108109
options: {
109-
tsconfig: "./shared/tsconfig.json",
110110
fix: true,
111111
src: [
112112
"./shared/src/**/*.ts"
113113
]
114114
}
115115
},
116116
"ts_plugin-fix": {
117+
tsconfig: "./ts-plugin/tsconfig.json",
117118
options: {
118-
tsconfig: "./ts-plugin/tsconfig.json",
119119
fix: true
120120
}
121121
},
122122
"eslint_ts-fix": {
123+
tsconfig: "./eslint-ts-plugin/tsconfig.json",
123124
options: {
124-
tsconfig: "./eslint-ts-plugin/tsconfig.json",
125125
fix: true,
126126
}
127127
}

shared/src/fileHelpers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export function findCommonPath(paths: string[], seperator?: string) {
100100

101101
export function normalizePath(thePath: string) {
102102
if (thePath) {
103-
return thePath.replace(/\\/g, "/");
103+
return thePath.replace(/\\/g, "/").replace(/\/\.\//g, "/");
104104
}
105105

106106
return thePath;
@@ -111,7 +111,7 @@ export function makeRelative(thePath: string) {
111111
}
112112

113113
export function makeRelativeTo(rootPath: string, thePath: string) {
114-
return normalizePath(path.relative(rootPath, path.resolve(thePath)));
114+
return normalizePath(path.relative(rootPath, path.resolve(normalizePath(thePath))));
115115
}
116116

117117
function _findPath(rootPath: string, moduleFolder: string, logDebug?: (message: string) => void) {

shared/src/tsConfigDetails.ts

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ function _resolveTsConfigFiles(tsConfigPath: string, files: string[]): string[]
8989
if (location) {
9090
const destFiles: string[] = [];
9191
if (files && files.length > 0) {
92-
files.forEach((theFile) => {
93-
destFiles.push(location + theFile);
92+
arrForEach(files, (theFile) => {
93+
destFiles.push(normalizePath(location + theFile));
9494
});
9595
}
9696

@@ -100,6 +100,27 @@ function _resolveTsConfigFiles(tsConfigPath: string, files: string[]): string[]
100100
return files;
101101
}
102102

103+
/**
104+
* Merge the files from the merge array into the target array but only add unique values
105+
*
106+
* @param target - The target array to merge into
107+
* @param merge - The array to merge into the target
108+
* @returns - The target array
109+
*/
110+
function _mergeFiles(target: string[], merge: string[]): string[] {
111+
if (isNullOrUndefined(target) || target.length === 0) {
112+
return merge;
113+
}
114+
115+
arrForEach(merge, (val) => {
116+
if (target.indexOf(val) === -1) {
117+
target.push(val);
118+
}
119+
});
120+
121+
return target;
122+
}
123+
103124
function _mergeConfigs(target: any, merge: any): any {
104125
if (isNullOrUndefined(target)) {
105126
return merge;
@@ -174,7 +195,7 @@ function _createTsConfigDetails(grunt: IGruntWrapper, tsConfigOrOption: string |
174195
let compilerOptions = tsConfig.compilerOptions = tsConfig.compilerOptions || {};
175196

176197
if (compilerOptions.rootDir) {
177-
projectRootDir = path.resolve(findCommonPath([details.name || "."]), compilerOptions.rootDir);
198+
projectRootDir = normalizePath(path.resolve(findCommonPath([details.name || "."]), compilerOptions.rootDir));
178199

179200
// eslint-disable-next-line security/detect-non-literal-fs-filename
180201
if (!fs.existsSync(path.resolve(projectRootDir))) {
@@ -230,7 +251,7 @@ function _createTsConfigDetails(grunt: IGruntWrapper, tsConfigOrOption: string |
230251
grunt.logDebug("-----------------------------------------------------------------------------------------------------");
231252
}
232253

233-
tsFiles.forEach((theFile) => {
254+
arrForEach(tsFiles, (theFile) => {
234255
let excludePath = false;
235256

236257
if (theFile.startsWith("!")) {
@@ -270,8 +291,16 @@ function _createTsConfigDetails(grunt: IGruntWrapper, tsConfigOrOption: string |
270291
if (excludePath) {
271292
destContainer = tsConfig.exclude = tsConfig.exclude || [];
272293
} else if (!tsConfig.exclude && theResolvedFile.indexOf("*") === -1) {
294+
if (grunt.isDebug) {
295+
grunt.logDebug("Using files as the container");
296+
}
297+
273298
destContainer = tsConfig.files = tsConfig.files || [];
274299
} else {
300+
if (grunt.isDebug) {
301+
grunt.logDebug("Using include as the container");
302+
}
303+
275304
destContainer = tsConfig.include = tsConfig.include || [];
276305
}
277306

@@ -282,16 +311,28 @@ function _createTsConfigDetails(grunt: IGruntWrapper, tsConfigOrOption: string |
282311
grunt.logDebug("-----------------------------------------------------------------------------------------------------");
283312

284313
if (tsConfig.files && tsConfig.files.length === 0) {
314+
if (grunt.isDebug) {
315+
grunt.logDebug("Removing empty files");
316+
}
317+
285318
details.modified = true;
286319
delete tsConfig.files;
287320
}
288321

289322
if (tsConfig.include && tsConfig.include.length === 0) {
323+
if (grunt.isDebug) {
324+
grunt.logDebug("Removing empty include");
325+
}
326+
290327
details.modified = true;
291328
delete tsConfig.include;
292329
}
293330

294331
if (tsConfig.exclude && tsConfig.exclude.length === 0) {
332+
if (grunt.isDebug) {
333+
grunt.logDebug("Removing empty exclude");
334+
}
335+
295336
details.modified = true;
296337
delete tsConfig.exclude;
297338
}
@@ -307,16 +348,30 @@ function _createTsConfigDetails(grunt: IGruntWrapper, tsConfigOrOption: string |
307348
let tsConfig = details.tsConfig;
308349
//grunt.log.writeln("Using tsconfig: " + tsProject);
309350
if (tsConfig.files) {
310-
tsConfigFiles = _resolveTsConfigFiles(details.name, tsConfig.files);
311-
} else if (tsConfig.include) {
312-
tsConfigFiles = _resolveTsConfigFiles(details.name, tsConfig.include);
351+
if (grunt.isDebug) {
352+
grunt.logDebug("Adding Files: " + JSON.stringify(tsConfig.files));
353+
}
354+
355+
tsConfigFiles = _mergeFiles(tsConfigFiles, _resolveTsConfigFiles(details.name, tsConfig.files));
356+
}
357+
358+
if (tsConfig.include) {
359+
if (grunt.isDebug) {
360+
grunt.logDebug("Adding Include: " + JSON.stringify(tsConfig.include));
361+
}
362+
363+
tsConfigFiles = _mergeFiles(tsConfigFiles, _resolveTsConfigFiles(details.name, tsConfig.include));
313364
}
314365

315366
// if (tsConfig.exclude) {
316367
// exclude = _resolveTsConfigFiles(details.name, tsConfig.exclude);
317368
// //grunt.log.writeln("Excluding: " + JSON.stringify(exclude));
318369
// }
319370
}
371+
372+
if (grunt.isDebug) {
373+
grunt.logDebug("getFiles (" + details.name + "): " + JSON.stringify(tsConfigFiles));
374+
}
320375

321376
return tsConfigFiles;
322377
}

0 commit comments

Comments
 (0)