npm-groovy-lint 9.4.1 → 10.0.1

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 (35) hide show
  1. package/CHANGELOG.md +39 -2
  2. package/README.md +54 -28
  3. package/lib/.groovylintrc-all.json +393 -394
  4. package/lib/.groovylintrc-format.json +2 -0
  5. package/lib/codenarc-caller.js +7 -3
  6. package/lib/codenarc-factory.js +77 -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 +5 -3
  13. package/lib/index.js +5 -1
  14. package/lib/java/CodeNarc-3.1.0.jar +0 -0
  15. package/lib/java/CodeNarcServer.jar +0 -0
  16. package/lib/java/GMetrics-2.1.0.jar +0 -0
  17. package/lib/java/{log4j-api-2.17.1.jar → log4j-api-2.18.0.jar} +0 -0
  18. package/lib/java/{log4j-core-2.17.1.jar → log4j-core-2.18.0.jar} +0 -0
  19. package/lib/java/{log4j-slf4j-impl-2.17.1.jar → log4j-slf4j-impl-2.18.0.jar} +0 -0
  20. package/lib/options.js +30 -15
  21. package/lib/output.js +1 -3
  22. package/lib/rules/DuplicateNumberLiteral.js +21 -0
  23. package/lib/rules/DuplicateStringLiteral.js +21 -0
  24. package/lib/rules/MethodParameterTypeRequired.js +21 -0
  25. package/lib/rules/MisorderedStaticImports.js +2 -2
  26. package/lib/rules/NoDef.js +14 -0
  27. package/lib/rules/SimpleDateFormatMissingLocale.js +14 -0
  28. package/lib/rules/SpaceAfterMethodCallName.js +30 -0
  29. package/lib/rules/SpaceInsideParentheses.js +73 -0
  30. package/lib/rules/UnnecessaryPublicModifier.js +13 -0
  31. package/lib/rules/VariableTypeRequired.js +36 -0
  32. package/lib/utils.js +2 -2
  33. package/package.json +4 -8
  34. package/lib/java/CodeNarc-2.2.0.jar +0 -0
  35. package/lib/java/gmetrics-1.1.jar +0 -0
@@ -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,76 @@ 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 absolutePath = path.resolve(finalPattern).replace(/\\/gu, "/");
96
+ const relativePath = path.relative(process.cwd(), path.resolve(finalPattern)).replace(/\\/gu, "/");
97
+ fileList.push(absolutePath);
98
+ finalPattern = "**/" + path.normalize(relativePath.replace(/[/\\]$/u, "")).replace(/\\/gu, "/");
99
+ }
100
+ // Relative with codeNardBaseDir
101
+ else if (fs.existsSync(path.join(result.codeNarcBaseDir, finalPattern))) {
102
+ const relativePath = path.relative(process.cwd(), path.join(result.codeNarcBaseDir, finalPattern)).replace(/\\/gu, "/");
103
+ fileList.push(relativePath);
104
+ finalPattern = "**/" + path.normalize(relativePath.replace(/[/\\]$/u, "")).replace(/\\/gu, "/");
105
+ }
106
+ // Directory or ant pattern
107
+ return finalPattern;
108
+ })
109
+ .join(",");
110
+ result.codenarcArgs.push(`-includes="${patternsFinal}"`);
111
+ result.codeNarcIncludes = patternsFinal;
112
+ result.inputFileList = fileList;
113
+ }
75
114
  // Matching files pattern(s)
76
- if (cnFiles) {
115
+ else if (cnFiles) {
77
116
  const normalizedCnFiles = cnFiles.replace(/^"(.*)"$/, "$1");
78
- result.codenarcArgs.push(`-includes=${normalizedCnFiles}`);
117
+ result.codenarcArgs.push(`-includes="${normalizedCnFiles}"`);
79
118
  result.codeNarcIncludes = normalizedCnFiles;
80
119
  } else {
81
120
  // If files not sent, use defaultFilesPattern, guessed from options.rulesets value
82
- result.codenarcArgs.push(`-includes=${defaultFilesPattern}`);
83
- result.codeNarcIncludes = defaultFilesPattern;
121
+ result.codenarcArgs.push(`-includes="${filePatterns}"`);
122
+ result.codeNarcIncludes = filePatterns;
84
123
  }
85
124
 
86
125
  // Ignore pattern
87
126
  if (options.ignorepattern) {
88
- result.codenarcArgs.push(`-excludes=${options.ignorepattern}`);
127
+ result.codenarcArgs.push(`-excludes="${options.ignorepattern}"`);
89
128
  result.codeNarcExcludes = options.ignorepattern;
90
129
  }
91
130
 
92
131
  // Output
93
132
  result.output = options.output.replace(/^"(.*)"$/, "$1");
94
- if (["txt", "json", "sarif", "none"].includes(result.output) ||
133
+ if (
134
+ ["txt", "json", "sarif", "none"].includes(result.output) ||
95
135
  result.output.endsWith(".txt") ||
96
136
  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"
137
+ result.output.endsWith(".json")
138
+ ) {
139
+ result.outputType = result.output.endsWith(".txt")
140
+ ? "txt"
141
+ : result.output.endsWith(".json")
142
+ ? "json"
143
+ : result.output.endsWith(".sarif")
144
+ ? "sarif"
101
145
  : result.output;
102
146
  result.codenarcArgs.push(`-report=json:stdout`);
103
147
  } else if (["html", "xml"].includes(result.output.split(".").pop())) {
@@ -253,7 +297,7 @@ async function parseCodeNarcResult(options, codeNarcBaseDir, codeNarcJsonResult,
253
297
  const evaluatedVars = evaluateVariables(errRule.variables, errItem.msg, { verbose: options.verbose });
254
298
  const errLine = allLines[errItem.line - 1];
255
299
  const range = evaluateRange(errItem, errRule, evaluatedVars, errLine, allLines, { verbose: options.verbose });
256
- if (range) {
300
+ if (range && range.start.character > -1) {
257
301
  errItem.range = range;
258
302
  }
259
303
  }
@@ -347,6 +391,10 @@ async function buildRuleSets(options) {
347
391
  ? ruleOptions
348
392
  : ruleFromConfig;
349
393
  const ruleDef = buildCodeNarcRule(ruleName, mergedRuleConfig);
394
+ // If rule has been sent as argument, enable it by default
395
+ if (ruleDef.enabled === false) {
396
+ ruleDef.enabled = true;
397
+ }
350
398
  return ruleDef;
351
399
  });
352
400
  }
@@ -385,6 +433,10 @@ async function buildRuleSets(options) {
385
433
  delete rule.ruleName;
386
434
  ruleSetJson[ruleName] = rule;
387
435
  }
436
+ // Remove UnnecessarySubstring as it is no longer in CodeNarc v3
437
+ if (ruleSetJson["UnnecessarySubstring"] != null) {
438
+ delete ruleSetJson["UnnecessarySubstring"];
439
+ }
388
440
  return JSON.stringify(ruleSetJson);
389
441
  }
390
442
 
@@ -428,4 +480,15 @@ async function manageDeleteTmpFiles(tmpGroovyFileName) {
428
480
  }
429
481
  }
430
482
 
483
+ function directoryExists(resolvedPath) {
484
+ try {
485
+ return fs.statSync(resolvedPath).isDirectory();
486
+ } catch (error) {
487
+ if (error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
488
+ return false;
489
+ }
490
+ throw error;
491
+ }
492
+ }
493
+
431
494
  module.exports = { prepareCodeNarcCall, parseCodeNarcResult, manageDeleteTmpFiles };