npm-groovy-lint 12.2.1-beta202311260926.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/analytics.js +3 -1
- package/lib/codenarc-caller.js +2 -14
- package/lib/codenarc-factory.js +69 -65
- package/lib/example/fake_node_modules/samplefolder/ToIgnore.groovy +1 -1
- package/lib/groovy-lint.js +25 -5
- package/lib/java/{CodeNarc-3.1.0.jar → CodeNarc-3.4.0-alpha+3346775f.jar} +0 -0
- package/lib/java/CodeNarcServer.jar +0 -0
- package/lib/utils.js +5 -1
- package/package.json +5 -2
package/lib/analytics.js
CHANGED
|
@@ -189,7 +189,9 @@ async function buildFileStatsEvents(linterEvent, data) {
|
|
|
189
189
|
|
|
190
190
|
async function getFileStats(file) {
|
|
191
191
|
const fileStatEventProps = {};
|
|
192
|
-
const source = await fse.readFile(file)
|
|
192
|
+
const source = await fse.readFile(file).catch(err => {
|
|
193
|
+
throw new Error(`Unable to read stats: ${err}`); // Ensure that we have a stack trace.
|
|
194
|
+
});
|
|
193
195
|
const sourceLines = await getSourceLines(source);
|
|
194
196
|
fileStatEventProps.fileId = crypto
|
|
195
197
|
.createHash("sha1")
|
package/lib/codenarc-caller.js
CHANGED
|
@@ -59,24 +59,12 @@ class CodeNarcCaller {
|
|
|
59
59
|
async callCodeNarcServer(startServerTried = false) {
|
|
60
60
|
// If use of --codenarcargs, get default values for CodeNarcServer host & port
|
|
61
61
|
const requestUri = this.getCodeNarcServerUri() + "/request";
|
|
62
|
-
// Remove "" around values because they won't get thru system command line parser
|
|
63
|
-
const codeNarcArgsForServer = this.codenarcArgs.map(codeNarcArg => {
|
|
64
|
-
if (codeNarcArg.includes('="') || codeNarcArg.includes(':"')) {
|
|
65
|
-
codeNarcArg = codeNarcArg
|
|
66
|
-
.replace('="', "=")
|
|
67
|
-
.replace(':"', ":")
|
|
68
|
-
.replace(/ /g, "%20");
|
|
69
|
-
codeNarcArg = codeNarcArg.substring(0, codeNarcArg.length - 1);
|
|
70
|
-
}
|
|
71
|
-
return codeNarcArg;
|
|
72
|
-
});
|
|
73
62
|
// Call CodeNarc server
|
|
74
|
-
const codeNarcArgsString = codeNarcArgsForServer.join(" ");
|
|
75
63
|
const axiosConfig = {
|
|
76
64
|
method: "post",
|
|
77
65
|
url: requestUri,
|
|
78
66
|
data: {
|
|
79
|
-
codeNarcArgs:
|
|
67
|
+
codeNarcArgs: this.codenarcArgs,
|
|
80
68
|
codeNarcBaseDir: this.execOpts.codeNarcBaseDir,
|
|
81
69
|
codeNarcIncludes: this.execOpts.codeNarcIncludes,
|
|
82
70
|
codeNarcExcludes: this.execOpts.codeNarcExcludes,
|
|
@@ -212,7 +200,7 @@ class CodeNarcCaller {
|
|
|
212
200
|
javaCallerOpts.javaExecutable = this.javaExecutable;
|
|
213
201
|
javaCallerOpts.additionalJavaArgs = this.additionalJavaArgs;
|
|
214
202
|
const javaCaller = new JavaCaller(javaCallerOpts);
|
|
215
|
-
const javaResult = await javaCaller.run(scriptArgs, { detached: false });
|
|
203
|
+
const javaResult = await javaCaller.run(scriptArgs, { detached: false, windowsVerbatimArguments: false });
|
|
216
204
|
|
|
217
205
|
clearInterval(this.barTimer);
|
|
218
206
|
this.bar.stop();
|
package/lib/codenarc-factory.js
CHANGED
|
@@ -26,42 +26,48 @@ const defaultFilesPattern = ["*.groovy", "*.gvy", "Jenkinsfile", "*.gradle", "*.
|
|
|
26
26
|
async function prepareCodeNarcCall(options) {
|
|
27
27
|
const result = { codenarcArgs: [] };
|
|
28
28
|
|
|
29
|
+
// Protect against regressions in argument parsing.
|
|
30
|
+
for (const [key, value] of Object.entries(options)) {
|
|
31
|
+
if (typeof value === "string" && value.match(/^['"]/)) {
|
|
32
|
+
throw new Error(`CodeNarc doesn't supported options found ${key} = ${value}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
29
36
|
let cnPath = options.path;
|
|
30
|
-
let cnFiles = options.
|
|
37
|
+
let cnFiles = options.file;
|
|
31
38
|
const positionalArgs = options._ || [];
|
|
32
39
|
|
|
33
40
|
// If source option, create a temporary Groovy file
|
|
34
41
|
if (options.source) {
|
|
35
42
|
cnPath = path.resolve(os.tmpdir() + "/npm-groovy-lint");
|
|
36
|
-
await fs.ensureDir(cnPath, { mode: "0777" });
|
|
43
|
+
await fs.ensureDir(cnPath, { mode: "0777" }); // await is needed, ignore editor warning.
|
|
37
44
|
// File path is sent (recommended): use it to create temp file name
|
|
38
45
|
if (options.sourcefilepath) {
|
|
39
46
|
const pathParse = path.parse(options.sourcefilepath);
|
|
40
47
|
cnPath = cnPath + "/codeNarcTmpDir_" + Math.random();
|
|
41
|
-
await fs.ensureDir(cnPath, { mode: "0777" });
|
|
48
|
+
await fs.ensureDir(cnPath, { mode: "0777" }); // await is needed, ignore editor warning.
|
|
42
49
|
const pathBase = pathParse.base.replace(/ /g, "_");
|
|
43
50
|
result.tmpGroovyFileName = path.resolve(cnPath + "/" + pathBase);
|
|
44
|
-
cnFiles = "**/" + pathBase;
|
|
51
|
+
cnFiles = ["**/" + pathBase];
|
|
45
52
|
}
|
|
46
53
|
// Use default random file name
|
|
47
54
|
else {
|
|
48
55
|
const tmpFileNm = CODENARC_TMP_FILENAME_BASE + Math.random() + ".groovy";
|
|
49
56
|
result.tmpGroovyFileName = path.resolve(cnPath + "/" + tmpFileNm);
|
|
50
|
-
cnFiles = "**/" + tmpFileNm;
|
|
57
|
+
cnFiles = ["**/" + tmpFileNm];
|
|
51
58
|
}
|
|
52
59
|
|
|
53
|
-
await fs.writeFile(result.tmpGroovyFileName, normalizeNewLines(options.source))
|
|
60
|
+
await fs.writeFile(result.tmpGroovyFileName, normalizeNewLines(options.source)).catch(err => {
|
|
61
|
+
throw new Error(`Unable to write temp file: ${err}`); // Ensure we have a stack trace.
|
|
62
|
+
});
|
|
63
|
+
|
|
54
64
|
debug(`CREATE GROOVY temp file ${result.tmpGroovyFileName} with input source, as CodeNarc requires physical files`);
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
// Define base directory
|
|
58
68
|
const baseBefore = (cnPath !== "." && cnPath.startsWith("/")) || cnPath.includes(":/") || cnPath.includes(":\\") ? "" : process.cwd() + "/";
|
|
59
69
|
const codeNarcBaseDir =
|
|
60
|
-
positionalArgs.length > 0
|
|
61
|
-
? await getCodeNarcBaseDirFromFiles(positionalArgs)
|
|
62
|
-
: cnPath !== "."
|
|
63
|
-
? baseBefore + cnPath.replace(/^"(.*)"$/, "$1")
|
|
64
|
-
: process.cwd();
|
|
70
|
+
positionalArgs.length > 0 ? await getCodeNarcBaseDirFromFiles(positionalArgs) : cnPath !== "." ? baseBefore + cnPath : process.cwd();
|
|
65
71
|
result.codeNarcBaseDir = path.resolve(codeNarcBaseDir);
|
|
66
72
|
result.codenarcArgs.push(`-basedir=${result.codeNarcBaseDir}`);
|
|
67
73
|
|
|
@@ -74,69 +80,66 @@ async function prepareCodeNarcCall(options) {
|
|
|
74
80
|
result.codenarcArgs.push(`-ruleset=${encodeURIComponent(options.rulesets)}`);
|
|
75
81
|
} else {
|
|
76
82
|
// File list format
|
|
77
|
-
const rulesetFileArgs = options.rulesets.startsWith("file:") ? options.rulesets : `file:${options.rulesets
|
|
83
|
+
const rulesetFileArgs = options.rulesets.startsWith("file:") ? options.rulesets : `file:${options.rulesets}`;
|
|
78
84
|
result.codenarcArgs.push(`-rulesetfiles=${rulesetFileArgs}`);
|
|
79
85
|
}
|
|
80
86
|
|
|
81
|
-
// Default file patterns
|
|
82
|
-
let filePatterns = defaultFilesPattern.map(filePattern => `**/${filePattern}`).join(",");
|
|
83
|
-
|
|
84
87
|
// Build codenarc arguments from eslint-like formatted positional arguments
|
|
85
88
|
if (positionalArgs.length > 0) {
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
const filePatterns =
|
|
90
|
+
options.ext && options.ext.length > 0
|
|
91
|
+
? // Convert extensions with or without leading slash into an ant pattern.
|
|
92
|
+
options.ext.map(ext => ext.replace(/^\.?/u, "*."))
|
|
93
|
+
: defaultFilesPattern;
|
|
94
|
+
const sourceFiles = [];
|
|
95
|
+
const includes = [];
|
|
96
|
+
positionalArgs.filter(Boolean).forEach(pathname => {
|
|
97
|
+
const absolutePath = path.resolve(".", pathname);
|
|
98
|
+
const relativePath = path.relative(codeNarcBaseDir, absolutePath);
|
|
99
|
+
if (directoryExists(absolutePath)) {
|
|
100
|
+
// Directory: convert into ant patterns.
|
|
101
|
+
const patternBase = antPath(relativePath) + "**/";
|
|
102
|
+
includes.push(...filePatterns.map(filePattern => patternBase + filePattern));
|
|
103
|
+
} else if (fs.existsSync(absolutePath)) {
|
|
104
|
+
// File: add to file / patterns list.
|
|
105
|
+
const file = antPath(relativePath);
|
|
106
|
+
includes.push(file);
|
|
107
|
+
sourceFiles.push(absolutePath);
|
|
108
|
+
} else {
|
|
109
|
+
// Ant pattern.
|
|
110
|
+
includes.push(antPath(path.normalize(pathname)));
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (includes.length > 0) {
|
|
115
|
+
result.codenarcArgs.push(`-includes=${includes.join(",")}`);
|
|
116
|
+
} else if (sourceFiles.length > 0) {
|
|
117
|
+
// Source files override patterns, so only use if we have no patterns.
|
|
118
|
+
result.codenarcArgs.push(`-sourcefiles=${sourceFiles.join(",")}`);
|
|
88
119
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
.map(pathname => {
|
|
93
|
-
let finalPattern = path.normalize(pathname).replace(/\\/gu, "/");
|
|
94
|
-
// Directory: convert into ant pattern
|
|
95
|
-
const resolvedPath = path.resolve(cnPath, pathname);
|
|
96
|
-
if (directoryExists(resolvedPath)) {
|
|
97
|
-
finalPattern = "**/" + path.normalize(pathname.replace(/[/\\]$/u, "")).replace(/\\/gu, "/") + filePatterns;
|
|
98
|
-
}
|
|
99
|
-
// Relative with codeNarcBaseDir
|
|
100
|
-
else if (fs.existsSync(path.join(result.codeNarcBaseDir, finalPattern))) {
|
|
101
|
-
const absolutePath = path.resolve(finalPattern).replace(/\\/gu, "/");
|
|
102
|
-
fileList.push(absolutePath);
|
|
103
|
-
const relativePath = finalPattern.replace(/\\/gu, "/");
|
|
104
|
-
finalPattern = "**/" + path.normalize(relativePath.replace(/[/\\]$/u, "")).replace(/\\/gu, "/");
|
|
105
|
-
}
|
|
106
|
-
// Absolute or cwd - relative path file
|
|
107
|
-
else if (fs.existsSync(finalPattern)) {
|
|
108
|
-
const absolutePath = path.resolve(finalPattern).replace(/\\/gu, "/");
|
|
109
|
-
fileList.push(absolutePath);
|
|
110
|
-
const relativePath = path.relative(result.codeNarcBaseDir, path.resolve(finalPattern)).replace(/\\/gu, "/");
|
|
111
|
-
finalPattern = "**/" + path.normalize(relativePath.replace(/[/\\]$/u, "")).replace(/\\/gu, "/");
|
|
112
|
-
}
|
|
113
|
-
// Directory or ant pattern
|
|
114
|
-
return finalPattern;
|
|
115
|
-
})
|
|
116
|
-
.join(",");
|
|
117
|
-
result.codenarcArgs.push(`-includes="${patternsFinal}"`);
|
|
118
|
-
result.codeNarcIncludes = patternsFinal;
|
|
119
|
-
result.inputFileList = fileList;
|
|
120
|
+
|
|
121
|
+
result.codeNarcIncludes = includes;
|
|
122
|
+
result.inputFileList = sourceFiles;
|
|
120
123
|
}
|
|
121
124
|
// Matching files pattern(s)
|
|
122
125
|
else if (cnFiles) {
|
|
123
|
-
|
|
124
|
-
result.
|
|
125
|
-
result.codeNarcIncludes = normalizedCnFiles;
|
|
126
|
+
result.codenarcArgs.push(`-includes=${cnFiles.join(",")}`);
|
|
127
|
+
result.codeNarcIncludes = cnFiles;
|
|
126
128
|
} else {
|
|
127
129
|
// If files not sent, use defaultFilesPattern, guessed from options.rulesets value
|
|
128
|
-
|
|
130
|
+
const filePatterns = defaultFilesPattern.map(filePattern => `**/${filePattern}`);
|
|
131
|
+
result.codenarcArgs.push(`-includes=${filePatterns.join(",")}`);
|
|
129
132
|
result.codeNarcIncludes = filePatterns;
|
|
130
133
|
}
|
|
131
134
|
|
|
132
135
|
// Ignore pattern
|
|
133
136
|
if (options.ignorepattern) {
|
|
134
|
-
result.codenarcArgs.push(`-excludes
|
|
135
|
-
result.codeNarcExcludes = options.ignorepattern;
|
|
137
|
+
result.codenarcArgs.push(`-excludes=${options.ignorepattern}`);
|
|
138
|
+
result.codeNarcExcludes = options.ignorepattern.split(",");
|
|
136
139
|
}
|
|
137
140
|
|
|
138
141
|
// Output
|
|
139
|
-
result.output = options.output
|
|
142
|
+
result.output = options.output;
|
|
140
143
|
if (
|
|
141
144
|
["txt", "json", "sarif", "none", "stdout"].includes(result.output) ||
|
|
142
145
|
result.output.endsWith(".txt") ||
|
|
@@ -181,6 +184,16 @@ async function prepareCodeNarcCall(options) {
|
|
|
181
184
|
return result;
|
|
182
185
|
}
|
|
183
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Converts a path with forward slashes to backslashes.
|
|
189
|
+
*
|
|
190
|
+
* @param {string} path The path to convert
|
|
191
|
+
* @returns The converted path
|
|
192
|
+
*/
|
|
193
|
+
function antPath(path) {
|
|
194
|
+
return path.replace(/\\/gu, "/");
|
|
195
|
+
}
|
|
196
|
+
|
|
184
197
|
// Calculate longest base dir by analyzing the list of files
|
|
185
198
|
async function getCodeNarcBaseDirFromFiles(positionalArgs) {
|
|
186
199
|
// All arguments are not files
|
|
@@ -504,15 +517,6 @@ function getCodeNarcPriorityCode(ruleFromConfig) {
|
|
|
504
517
|
return null;
|
|
505
518
|
}
|
|
506
519
|
|
|
507
|
-
async function manageDeleteTmpFiles(tmpGroovyFileName) {
|
|
508
|
-
// Remove temporary groovy file created for source argument if provided
|
|
509
|
-
if (tmpGroovyFileName) {
|
|
510
|
-
await fs.remove(tmpGroovyFileName);
|
|
511
|
-
debug(`Removed temp file ${tmpGroovyFileName} as it is not longer used`);
|
|
512
|
-
tmpGroovyFileName = null;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
520
|
function directoryExists(resolvedPath) {
|
|
517
521
|
try {
|
|
518
522
|
return fs.statSync(resolvedPath).isDirectory();
|
|
@@ -524,4 +528,4 @@ function directoryExists(resolvedPath) {
|
|
|
524
528
|
}
|
|
525
529
|
}
|
|
526
530
|
|
|
527
|
-
module.exports = { prepareCodeNarcCall, parseCodeNarcResult
|
|
531
|
+
module.exports = { prepareCodeNarcCall, parseCodeNarcResult };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
println 'This file should not be linted if --ignorepattern is **/
|
|
1
|
+
println 'This file should not be linted if --ignorepattern is **/fake_node_modules/**' ;
|
package/lib/groovy-lint.js
CHANGED
|
@@ -7,7 +7,7 @@ const performance = require("perf_hooks").performance;
|
|
|
7
7
|
|
|
8
8
|
const NpmGroovyLintFix = require("./groovy-lint-fix");
|
|
9
9
|
const CodeNarcCaller = require("./codenarc-caller");
|
|
10
|
-
const { prepareCodeNarcCall, parseCodeNarcResult
|
|
10
|
+
const { prepareCodeNarcCall, parseCodeNarcResult } = require("./codenarc-factory");
|
|
11
11
|
const { NPM_GROOVY_LINT_CONSTANTS, loadConfig, getConfigFileName } = require("./config.js");
|
|
12
12
|
const optionsDefinition = require("./options");
|
|
13
13
|
const { computeStats, processOutput } = require("./output.js");
|
|
@@ -98,7 +98,19 @@ class NpmGroovyLint {
|
|
|
98
98
|
this.lintResult = computeStats(this.lintResult);
|
|
99
99
|
this.outputString = await processOutput(this.outputType, this.output, this.lintResult, this.options, this.fixer);
|
|
100
100
|
// Delete Tmp file if existing
|
|
101
|
-
manageDeleteTmpFiles(
|
|
101
|
+
await this.manageDeleteTmpFiles();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Delete tmp file if needed.
|
|
105
|
+
async manageDeleteTmpFiles() {
|
|
106
|
+
if (!this.tmpGroovyFileName) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
await fs.remove(this.tmpGroovyFileName);
|
|
111
|
+
console.log(`GroovyLint: Removed temp file ${this.tmpGroovyFileName} as it is not longer used`);
|
|
112
|
+
debug(`Removed temp file ${this.tmpGroovyFileName} as it is not longer used`);
|
|
113
|
+
this.tmpGroovyFileName = null;
|
|
102
114
|
}
|
|
103
115
|
|
|
104
116
|
// Returns the full path of the configuration file
|
|
@@ -119,10 +131,12 @@ class NpmGroovyLint {
|
|
|
119
131
|
async preProcess() {
|
|
120
132
|
// Reset status so we don't get stale results.
|
|
121
133
|
this.status = 0;
|
|
122
|
-
|
|
123
134
|
// Manage when the user wants to use only codenarc args
|
|
124
135
|
if (Array.isArray(this.args) && this.args.includes("--codenarcargs")) {
|
|
125
|
-
this.codenarcArgs = this.args
|
|
136
|
+
this.codenarcArgs = this.args
|
|
137
|
+
.slice(2)
|
|
138
|
+
.filter(userArg => userArg !== "--codenarcargs") // Strip codenarcargs.
|
|
139
|
+
.map(userArg => userArg.replace(/^-(\w+)="(.*)"$/, "-$1=$2").replace(/^-(\w+)='(.*)'$/, "-$1=$2")); // Strip quotes around values which CodeNarc doesn't support.
|
|
126
140
|
this.onlyCodeNarc = true;
|
|
127
141
|
return true;
|
|
128
142
|
}
|
|
@@ -132,6 +146,12 @@ class NpmGroovyLint {
|
|
|
132
146
|
if (this.parseOptions) {
|
|
133
147
|
try {
|
|
134
148
|
this.options = optionsDefinition.parse(this.args);
|
|
149
|
+
// Strip quotes around values which CodeNarc doesn't support.
|
|
150
|
+
for (const [key, value] of Object.entries(this.options)) {
|
|
151
|
+
if (typeof value === "string") {
|
|
152
|
+
this.options[key] = value.replace(/^"(.*)"$/, "$1").replace(/^'(.*)'$/, "$1");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
135
155
|
const configProperties = await loadConfig(
|
|
136
156
|
this.options.config || this.options.path,
|
|
137
157
|
this.options.format ? "format" : "lint",
|
|
@@ -330,7 +350,7 @@ class NpmGroovyLint {
|
|
|
330
350
|
}
|
|
331
351
|
}
|
|
332
352
|
|
|
333
|
-
manageDeleteTmpFiles(
|
|
353
|
+
await this.manageDeleteTmpFiles();
|
|
334
354
|
|
|
335
355
|
// Manage return code in case failonerror, failonwarning or failoninfo is called
|
|
336
356
|
this.manageReturnCode();
|
|
Binary file
|
|
Binary file
|
package/lib/utils.js
CHANGED
|
@@ -255,7 +255,11 @@ function getOutOfBracesStrings(str, exclude = []) {
|
|
|
255
255
|
|
|
256
256
|
// Split source lines to analyse
|
|
257
257
|
async function getSourceLines(source, fileNm) {
|
|
258
|
-
let fileContent =
|
|
258
|
+
let fileContent =
|
|
259
|
+
source ||
|
|
260
|
+
(await fse.readFile(fileNm).catch(err => {
|
|
261
|
+
throw new Error(`Unable to read source lines: ${err}`); // Ensure that we have a stack trace.
|
|
262
|
+
}));
|
|
259
263
|
return normalizeNewLines(fileContent.toString()).split(os.EOL);
|
|
260
264
|
}
|
|
261
265
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "npm-groovy-lint",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.0.0",
|
|
4
4
|
"description": "Lint, format and auto-fix your Groovy / Jenkinsfile / Gradle files",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"amplitude": "^5.1.6",
|
|
50
50
|
"ansi-colors": "^4.1.1",
|
|
51
|
-
"axios": "^1.6.
|
|
51
|
+
"axios": "^1.6.2",
|
|
52
52
|
"chalk": "^4.1.2",
|
|
53
53
|
"cli-progress": "^3.12.0",
|
|
54
54
|
"commondir": "^1.0.1",
|
|
@@ -107,5 +107,8 @@
|
|
|
107
107
|
"html"
|
|
108
108
|
],
|
|
109
109
|
"all": true
|
|
110
|
+
},
|
|
111
|
+
"overrides": {
|
|
112
|
+
"axios": "^1.6.2"
|
|
110
113
|
}
|
|
111
114
|
}
|