npm-groovy-lint 9.5.0 → 10.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +31 -2
  2. package/README.md +29 -3
  3. package/lib/.groovylintrc-all.json +0 -1
  4. package/lib/.groovylintrc-format.json +2 -0
  5. package/lib/codenarc-caller.js +7 -3
  6. package/lib/codenarc-factory.js +76 -14
  7. package/lib/example/RuleSet-All.groovy +413 -417
  8. package/lib/example/SampleFileSmall.groovy +3 -3
  9. package/lib/example/SampleFileSmallFixed.txt +4 -4
  10. package/lib/example/SampleFileSmallFormatted.txt +4 -4
  11. package/lib/groovy-lint-rules.js +2 -0
  12. package/lib/groovy-lint.js +3 -1
  13. package/lib/java/CodeNarc-3.1.0.jar +0 -0
  14. package/lib/java/CodeNarcServer.jar +0 -0
  15. package/lib/java/GMetrics-2.1.0.jar +0 -0
  16. package/lib/java/{log4j-api-2.17.1.jar → log4j-api-2.18.0.jar} +0 -0
  17. package/lib/java/{log4j-core-2.17.1.jar → log4j-core-2.18.0.jar} +0 -0
  18. package/lib/java/{log4j-slf4j-impl-2.17.1.jar → log4j-slf4j-impl-2.18.0.jar} +0 -0
  19. package/lib/options.js +28 -14
  20. package/lib/output.js +1 -3
  21. package/lib/rules/DuplicateNumberLiteral.js +21 -0
  22. package/lib/rules/DuplicateStringLiteral.js +21 -0
  23. package/lib/rules/MethodParameterTypeRequired.js +21 -0
  24. package/lib/rules/MisorderedStaticImports.js +2 -2
  25. package/lib/rules/NoDef.js +14 -0
  26. package/lib/rules/SimpleDateFormatMissingLocale.js +14 -0
  27. package/lib/rules/SpaceAfterMethodCallName.js +30 -0
  28. package/lib/rules/SpaceInsideParentheses.js +73 -0
  29. package/lib/rules/UnnecessaryPublicModifier.js +13 -0
  30. package/lib/rules/VariableTypeRequired.js +36 -0
  31. package/lib/utils.js +2 -2
  32. package/package.json +4 -8
  33. package/lib/java/CodeNarc-2.2.0.jar +0 -0
  34. package/lib/java/gmetrics-1.1.jar +0 -0
package/CHANGELOG.md CHANGED
@@ -2,13 +2,42 @@
2
2
 
3
3
  ## UNRELEASED
4
4
 
5
- - Add your updates here :)
5
+ ## [10.0.0] 2022-08-13
6
+
7
+ - Core
8
+ - Upgrade to [CodeNarc v3.1.0](https://github.com/CodeNarc/CodeNarc/blob/master/CHANGELOG.md#version-310----jun-2022)
9
+ - Accept list of directories / files as arguments (`--path` and `--files` become deprecated but are still usable)
10
+ - Examples
11
+ - Multiple files: `npm-groovy-lint path/to/file1.groovy path/to/file2.groovy`
12
+ - Directory: `npm groovy-lint path/to`
13
+ - Single file: `npm-groovy-lint Jenkinsfile`
14
+ - Ant pattern(s): `npm-groovy-lint path/to/**/*.groovy`
15
+ - Upgrade npm dependencies
16
+ - CI: Upgrade [MegaLinter](https://oxsecurity.github.io/megalinter/latest/) to v6
17
+ - Test classes for collecting error ranges
18
+
19
+ - New error ranges rules
20
+ - DuplicateNumberLiteral
21
+ - DuplicateStringLiteral
22
+ - MethodParameterTypeRequired
23
+ - NoDef
24
+ - SimpleDateFormatMissingLocale
25
+ - SpaceInsideParenthesis
26
+ - UnnecessaryPublicModifier
27
+ - VariableTypeRequired
28
+
29
+ - New fix rules
30
+ - SpaceAfterMethodCallName
31
+ - SpaceInsideParentheses
32
+
33
+ - Bug Fixes
34
+ - Wrongly calculated ranges are no more returned
6
35
 
7
36
  ## [9.5.0] 2022-04-12
8
37
 
9
38
  - Disable Amplitude anonymous stats by default (use `--insight` to enable them)
10
39
 
11
- ## [9.4.1] 2022-01-22
40
+ ## [9.4.1] 2022-01-12
12
41
 
13
42
  - Upgrade node-sarif-builder to 2.0.1 and send npm-groovy-lint version in SARIF logs
14
43
  - New range detection for rules:
package/README.md CHANGED
@@ -40,13 +40,13 @@ Any **question**, **problem** or **enhancement request** ? Ask [**here**](https:
40
40
  ## Usage
41
41
 
42
42
  ```shell
43
- npm-groovy-lint OPTIONS
43
+ npm-groovy-lint [OPTIONS] [FILES|PATH|PATTERN]
44
44
  ```
45
45
 
46
+ See [examples](#example-calls)
47
+
46
48
  | Parameter | Type | Description |
47
49
  |-------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
48
- | -p<br/> --path | String | Directory containing the files to lint<br/> Example: `./path/to/my/groovy/files` |
49
- | -f<br/> --files | String | Comma-separated list of Ant-style file patterns specifying files that must be included.<br/> Default: `"**/*.groovy,**/Jenkinsfile,**/*.gradle"`<br/>Examples:<br/> - `"**/Jenkinsfile"`<br/> - `"**/*.groovy"`<br/> - `"**/*.gradle"`<br/> - `"**/mySingleFile.groovy"` |
50
50
  | -o<br/> --output | String | Output format (txt,json,sarif,html,xml), or path to a file with one of these extensions<br/> Default: `txt`<br/> Examples:<br/> - `"txt"`<br/> - `"json"`<br/> - `"./logs/myLintResults.txt"`<br/> - `"./logs/myLintResults.sarif"`<br/> - `"./logs/myLintResults.html"`<br/> - `"./logs/myLintResults.xml"` |
51
51
  | -l<br/> --loglevel | String | Log level (error,warning or info)<br/>Default: info |
52
52
  | --failon | String | Defines the error level where CLI will fail (return code = 1). error,warning,info or none. Each failure level includes the more critical ones. |
@@ -69,6 +69,8 @@ Any **question**, **problem** or **enhancement request** ? Ask [**here**](https:
69
69
  | --codenarcargs | String | Use core CodeNarc arguments (all npm-groovy-lint arguments will be ignored)<br/> Doc: <http://codenarc.github.io/CodeNarc/codenarc-command-line.html><br/> Example: `npm-groovy-lint --codenarcargs -basedir="lib/example" -rulesetfiles="file:lib/example/RuleSet-Groovy.groovy" -maxPriority1Violations=0 -report="xml:ReportTestCodenarc.xml` |
70
70
  | -h<br/> --help | Boolean | Show help (npm-groovy-lint -h OPTIONNAME to see option detail with examples) |
71
71
  | -v<br/> --version | Boolean | Show npm-groovy-lint version (with CodeNarc version) |
72
+ | -p<br/> --path | String | (DEPRECATED) Directory containing the files to lint<br/> Example: `./path/to/my/groovy/files` |
73
+ | -f<br/> --files | String | (DEPRECATED) Comma-separated list of Ant-style file patterns specifying files that must be included.<br/> Default: `"**/*.groovy,**/Jenkinsfile,**/*.gradle"`<br/>Examples:<br/> - `"**/Jenkinsfile"`<br/> - `"**/*.groovy"`<br/> - `"**/*.gradle"`<br/> - `"**/mySingleFile.groovy"` |
72
74
 
73
75
  ## Installation
74
76
 
@@ -145,6 +147,30 @@ OR
145
147
 
146
148
  ## Example calls
147
149
 
150
+ - Lint a file
151
+
152
+ ```shell
153
+ npm-groovy-lint path/to/my/groovy/file.groovy
154
+ ```
155
+
156
+ - Lint multiple files
157
+
158
+ ```shell
159
+ npm-groovy-lint path/to/my/groovy/file.groovy path/to/my/groovy/file2.groovy path/to/my/groovy/file3.groovy
160
+ ```
161
+
162
+ - Lint directory
163
+
164
+ ```shell
165
+ npm-groovy-lint path/to/my/groovy
166
+ ```
167
+
168
+ - Lint pattern
169
+
170
+ ```shell
171
+ npm-groovy-lint path/to/my/groovy/*.groovy
172
+ ```
173
+
148
174
  - Lint groovy with JSON output
149
175
 
150
176
  ```shell
@@ -380,7 +380,6 @@
380
380
  "unnecessary.UnnecessarySemicolon": {},
381
381
  "unnecessary.UnnecessarySetter": {},
382
382
  "unnecessary.UnnecessaryStringInstantiation": {},
383
- "unnecessary.UnnecessarySubstring": {},
384
383
  "unnecessary.UnnecessaryTernaryExpression": {},
385
384
  "unnecessary.UnnecessaryToString": {},
386
385
  "unnecessary.UnnecessaryTransientModifier": {},
@@ -29,6 +29,7 @@
29
29
  "formatting.SpaceAfterComma": {},
30
30
  "formatting.SpaceAfterFor": {},
31
31
  "formatting.SpaceAfterIf": {},
32
+ "formatting.SpaceAfterMethodCallName": {},
32
33
  "formatting.SpaceAfterOpeningBrace": {},
33
34
  "formatting.SpaceAfterSemicolon": {},
34
35
  "formatting.SpaceAfterSwitch": {},
@@ -38,6 +39,7 @@
38
39
  "formatting.SpaceAroundOperator": {},
39
40
  "formatting.SpaceBeforeClosingBrace": {},
40
41
  "formatting.SpaceBeforeOpeningBrace": {},
42
+ "formatting.SpaceInsideParentheses": {},
41
43
  "formatting.TrailingWhitespace": {},
42
44
  "unnecessary.UnnecessaryGString": {},
43
45
  "unnecessary.UnnecessarySemicolon": {}
@@ -39,7 +39,7 @@ class CodeNarcCaller {
39
39
  rootPath: __dirname,
40
40
  mainClass: "org.codenarc.CodeNarc",
41
41
  classPath:
42
- "java/CodeNarc-2.2.0.jar:java/groovy/lib/groovy-3.0.9.jar:java/groovy/lib/groovy-templates-3.0.9.jar:java/groovy/lib/groovy-xml-3.0.9.jar:java/groovy/lib/groovy-json-3.0.9.jar:java/groovy/lib/groovy-ant-3.0.9.jar:java/groovy/lib/ant-1.10.11.jar:java/groovy/lib/ant-launcher-1.10.11.jar:java/slf4j-api-1.7.9.jar:java/log4j-slf4j-impl-2.17.1.jar:java/log4j-api-2.17.1.jar:java/log4j-core-2.17.1.jar:java/gmetrics-1.1.jar:java/*"
42
+ "java/CodeNarc-3.1.0.jar:java/groovy/lib/groovy-3.0.9.jar:java/groovy/lib/groovy-templates-3.0.9.jar:java/groovy/lib/groovy-xml-3.0.9.jar:java/groovy/lib/groovy-json-3.0.9.jar:java/groovy/lib/groovy-ant-3.0.9.jar:java/groovy/lib/ant-1.10.11.jar:java/groovy/lib/ant-launcher-1.10.11.jar:java/slf4j-api-1.7.9.jar:java/log4j-slf4j-impl-2.18.0.jar:java/log4j-api-2.18.0.jar:java/log4j-core-2.18.0.jar:java/GMetrics-2.1.0.jar:java/*"
43
43
  }
44
44
  };
45
45
 
@@ -60,7 +60,10 @@ class CodeNarcCaller {
60
60
  // Remove "" around values because they won't get thru system command line parser
61
61
  const codeNarcArgsForServer = this.codenarcArgs.map(codeNarcArg => {
62
62
  if (codeNarcArg.includes('="') || codeNarcArg.includes(':"')) {
63
- codeNarcArg = codeNarcArg.replace('="', "=").replace(':"', ":");
63
+ codeNarcArg = codeNarcArg
64
+ .replace('="', "=")
65
+ .replace(':"', ":")
66
+ .replace(/ /g, "%20");
64
67
  codeNarcArg = codeNarcArg.substring(0, codeNarcArg.length - 1);
65
68
  }
66
69
  return codeNarcArg;
@@ -76,7 +79,8 @@ class CodeNarcCaller {
76
79
  codeNarcIncludes: this.execOpts.codeNarcIncludes,
77
80
  codeNarcExcludes: this.execOpts.codeNarcExcludes,
78
81
  parse: this.options.parse !== false && this.execOpts.onlyCodeNarc === false ? true : false,
79
- file: this.execOpts.groovyFileName ? this.execOpts.groovyFileName : null,
82
+ file: this.execOpts.groovyFileName || null,
83
+ fileList: this.execOpts.inputFileList || null,
80
84
  requestKey: this.execOpts.requestKey || null
81
85
  },
82
86
  timeout: 600000
@@ -18,6 +18,8 @@ const npmGroovyLintRules = getNpmGroovyLintRules();
18
18
  const CODENARC_TMP_FILENAME_BASE = "codeNarcTmpDir_";
19
19
  const CODENARC_WWW_BASE = "https://codenarc.github.io/CodeNarc";
20
20
 
21
+ const defaultFilesPattern = ["*.groovy", "*.gvy", "Jenkinsfile", "*.gradle", "*.nf"];
22
+
21
23
  // Convert NPM-groovy-lint into codeNarc arguments
22
24
  // Create temporary files if necessary
23
25
  async function prepareCodeNarcCall(options) {
@@ -25,6 +27,7 @@ async function prepareCodeNarcCall(options) {
25
27
 
26
28
  let cnPath = options.path;
27
29
  let cnFiles = options.files;
30
+ const positionalArgs = options._ || [];
28
31
 
29
32
  // If source option, create a temporary Groovy file
30
33
  if (options.source) {
@@ -59,9 +62,6 @@ async function prepareCodeNarcCall(options) {
59
62
  // Create ruleSet groovy file if necessary
60
63
  options.rulesets = await buildRuleSets(options);
61
64
 
62
- // Build ruleSet & file CodeNarc arguments
63
- let defaultFilesPattern = "**/*.groovy,**/*.gvy,**/Jenkinsfile,**/*.gradle,**/*.nf";
64
-
65
65
  // RuleSets codeNarc args
66
66
  if (options.rulesets && options.rulesets.startsWith("{")) {
67
67
  // JSON format
@@ -72,32 +72,75 @@ async function prepareCodeNarcCall(options) {
72
72
  result.codenarcArgs.push(`-rulesetfiles=${rulesetFileArgs}`);
73
73
  }
74
74
 
75
+ // Default file patterns
76
+ let filePatterns = defaultFilesPattern.map(filePattern => `**/${filePattern}`).join(",");
77
+
78
+ // Build codenarc arguments from eslint-like formatted positional arguments
79
+ if (positionalArgs.length > 0) {
80
+ if (options.ext && options.ext.length > 0) {
81
+ filePatterns = `/**/*.{` + options.extensions.map(ext => ext.replace(/^\./u, "")) + "}";
82
+ }
83
+ const fileList = [];
84
+ const patternsFinal = positionalArgs
85
+ .filter(Boolean)
86
+ .map(pathname => {
87
+ let finalPattern = path.normalize(pathname).replace(/\\/gu, "/");
88
+ // Directory: convert into ant pattern
89
+ const resolvedPath = path.resolve(cnPath, pathname);
90
+ if (directoryExists(resolvedPath)) {
91
+ finalPattern = "**/" + path.normalize(pathname.replace(/[/\\]$/u, "")).replace(/\\/gu, "/") + filePatterns;
92
+ }
93
+ // Absolute or cwd - relative path file
94
+ if (fs.existsSync(finalPattern)) {
95
+ const relativePath = path.relative(process.cwd(), finalPattern).replace(/\\/gu, "/");
96
+ fileList.push(relativePath);
97
+ finalPattern = "**/" + path.normalize(relativePath.replace(/[/\\]$/u, "")).replace(/\\/gu, "/");
98
+ }
99
+ // Relative with codeNardBaseDir
100
+ else if (fs.existsSync(path.join(result.codeNarcBaseDir, finalPattern))) {
101
+ const relativePath = path.relative(process.cwd(), path.join(result.codeNarcBaseDir, finalPattern)).replace(/\\/gu, "/");
102
+ fileList.push(relativePath);
103
+ finalPattern = "**/" + path.normalize(relativePath.replace(/[/\\]$/u, "")).replace(/\\/gu, "/");
104
+ }
105
+ // Directory or ant pattern
106
+ return finalPattern;
107
+ })
108
+ .join(",");
109
+ result.codenarcArgs.push(`-includes="${patternsFinal}"`);
110
+ result.codeNarcIncludes = patternsFinal;
111
+ result.inputFileList = fileList;
112
+ }
75
113
  // Matching files pattern(s)
76
- if (cnFiles) {
114
+ else if (cnFiles) {
77
115
  const normalizedCnFiles = cnFiles.replace(/^"(.*)"$/, "$1");
78
- result.codenarcArgs.push(`-includes=${normalizedCnFiles}`);
116
+ result.codenarcArgs.push(`-includes="${normalizedCnFiles}"`);
79
117
  result.codeNarcIncludes = normalizedCnFiles;
80
118
  } else {
81
119
  // If files not sent, use defaultFilesPattern, guessed from options.rulesets value
82
- result.codenarcArgs.push(`-includes=${defaultFilesPattern}`);
83
- result.codeNarcIncludes = defaultFilesPattern;
120
+ result.codenarcArgs.push(`-includes="${filePatterns}"`);
121
+ result.codeNarcIncludes = filePatterns;
84
122
  }
85
123
 
86
124
  // Ignore pattern
87
125
  if (options.ignorepattern) {
88
- result.codenarcArgs.push(`-excludes=${options.ignorepattern}`);
126
+ result.codenarcArgs.push(`-excludes="${options.ignorepattern}"`);
89
127
  result.codeNarcExcludes = options.ignorepattern;
90
128
  }
91
129
 
92
130
  // Output
93
131
  result.output = options.output.replace(/^"(.*)"$/, "$1");
94
- if (["txt", "json", "sarif", "none"].includes(result.output) ||
132
+ if (
133
+ ["txt", "json", "sarif", "none"].includes(result.output) ||
95
134
  result.output.endsWith(".txt") ||
96
135
  result.output.endsWith(".sarif") ||
97
- result.output.endsWith(".json")) {
98
- result.outputType = result.output.endsWith(".txt") ? "txt"
99
- : result.output.endsWith(".json") ? "json"
100
- : result.output.endsWith(".sarif") ? "sarif"
136
+ result.output.endsWith(".json")
137
+ ) {
138
+ result.outputType = result.output.endsWith(".txt")
139
+ ? "txt"
140
+ : result.output.endsWith(".json")
141
+ ? "json"
142
+ : result.output.endsWith(".sarif")
143
+ ? "sarif"
101
144
  : result.output;
102
145
  result.codenarcArgs.push(`-report=json:stdout`);
103
146
  } else if (["html", "xml"].includes(result.output.split(".").pop())) {
@@ -253,7 +296,7 @@ async function parseCodeNarcResult(options, codeNarcBaseDir, codeNarcJsonResult,
253
296
  const evaluatedVars = evaluateVariables(errRule.variables, errItem.msg, { verbose: options.verbose });
254
297
  const errLine = allLines[errItem.line - 1];
255
298
  const range = evaluateRange(errItem, errRule, evaluatedVars, errLine, allLines, { verbose: options.verbose });
256
- if (range) {
299
+ if (range && range.start.character > -1) {
257
300
  errItem.range = range;
258
301
  }
259
302
  }
@@ -347,6 +390,10 @@ async function buildRuleSets(options) {
347
390
  ? ruleOptions
348
391
  : ruleFromConfig;
349
392
  const ruleDef = buildCodeNarcRule(ruleName, mergedRuleConfig);
393
+ // If rule has been sent as argument, enable it by default
394
+ if (ruleDef.enabled === false) {
395
+ ruleDef.enabled = true;
396
+ }
350
397
  return ruleDef;
351
398
  });
352
399
  }
@@ -385,6 +432,10 @@ async function buildRuleSets(options) {
385
432
  delete rule.ruleName;
386
433
  ruleSetJson[ruleName] = rule;
387
434
  }
435
+ // Remove UnnecessarySubstring as it is no longer in CodeNarc v3
436
+ if (ruleSetJson["UnnecessarySubstring"] != null) {
437
+ delete ruleSetJson["UnnecessarySubstring"];
438
+ }
388
439
  return JSON.stringify(ruleSetJson);
389
440
  }
390
441
 
@@ -428,4 +479,15 @@ async function manageDeleteTmpFiles(tmpGroovyFileName) {
428
479
  }
429
480
  }
430
481
 
482
+ function directoryExists(resolvedPath) {
483
+ try {
484
+ return fs.statSync(resolvedPath).isDirectory();
485
+ } catch (error) {
486
+ if (error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
487
+ return false;
488
+ }
489
+ throw error;
490
+ }
491
+ }
492
+
431
493
  module.exports = { prepareCodeNarcCall, parseCodeNarcResult, manageDeleteTmpFiles };