npm-groovy-lint
Advanced tools
Comparing version 2.2.0-beta.5 to 2.2.0-beta.6
# Changelog | ||
## [2.2.0] - 2020-02-25 | ||
## [2.2.0] BETA - 2020-02-26 | ||
@@ -9,3 +9,5 @@ ### Added | ||
- New option "source", allowing to call NpmGroovyLint with the groovy code as a string , not only path & files pattern | ||
- Run lint again after fix to get updated error log | ||
- Run lint again after fix all errors, to get updated lintResult | ||
- Add gitattributes to normalized line-endings (thanks [docwhat](https://github.com/docwhat)) | ||
- API: fix only some errors after an initial lint (better perfs) | ||
@@ -12,0 +14,0 @@ ## [2.0.1] - 2020-02-21 |
@@ -6,4 +6,4 @@ #! /usr/bin/env node | ||
const cliProgress = require("cli-progress"); | ||
const decodeHtml = require("decode-html"); | ||
const { npmGroovyLintRules } = require("./groovy-lint-rules.js"); | ||
const { evaluateVariables, getSourceLines } = require("./utils.js"); | ||
@@ -20,2 +20,3 @@ class NpmGroovyLintFix { | ||
fixedErrorsNumber = 0; | ||
fixedErrorsIds = []; | ||
@@ -35,10 +36,11 @@ bar; | ||
} | ||
// Initialize fix counters | ||
this.updatedLintResult.summary.totalFixedErrorNumber = 0; | ||
this.updatedLintResult.summary.totalFixedWarningNumber = 0; | ||
this.updatedLintResult.summary.totalFixedInfoNumber = 0; | ||
this.updatedLintResult.summary.totalFixedErrorNumber = this.updatedLintResult.summary.totalFixedErrorNumber || 0; | ||
this.updatedLintResult.summary.totalFixedWarningNumber = this.updatedLintResult.summary.totalFixedWarningNumber || 0; | ||
this.updatedLintResult.summary.totalFixedInfoNumber || this.updatedLintResult.summary.totalFixedInfoNumber || 0; | ||
} | ||
// Fix errors using codenarc result and groovy lint rules | ||
async run() { | ||
async run(errorIds = null) { | ||
// Start progress bar | ||
@@ -55,3 +57,3 @@ this.bar = new cliProgress.SingleBar( | ||
// Parse fixes and process them | ||
await this.parseFixableErrors(); | ||
await this.parseFixableErrors(errorIds); | ||
await this.fixErrors(); | ||
@@ -68,3 +70,3 @@ | ||
// Extract fixable errors from definition file | ||
async parseFixableErrors() { | ||
async parseFixableErrors(errorIds) { | ||
for (const fileNm of Object.keys(this.updatedLintResult.files)) { | ||
@@ -79,2 +81,3 @@ // Progress bar | ||
if ( | ||
(errorIds == null || errorIds.includes(err.id)) && | ||
this.npmGroovyLintRules[err.rule] != null && | ||
@@ -134,7 +137,3 @@ this.npmGroovyLintRules[err.rule].fix != null && | ||
// Read file | ||
let fileContent = this.options.source || (await fse.readFile(fileNm)); | ||
let fileLines = fileContent | ||
.toString() | ||
.replace(/\r?\n/g, "\r\n") | ||
.split("\r\n"); | ||
let allLines = await getSourceLines(this.options.source, fileNm); | ||
@@ -150,7 +149,8 @@ // Process fixes | ||
if (fileFixableError.rule.scope === "file") { | ||
const fileLinesNew = this.tryApplyFixRule(fileLines, lineNb, fileFixableError).slice(); // copy result lines | ||
if (JSON.stringify(fileLinesNew) !== JSON.stringify(fileLines.toString)) { | ||
fileLines = fileLinesNew; | ||
const allLinesNew = this.tryApplyFixRule(allLines, lineNb, fileFixableError).slice(); // copy result lines | ||
if (JSON.stringify(allLinesNew) !== JSON.stringify(allLines.toString)) { | ||
allLines = allLinesNew; | ||
fixedInFileNb = fixedInFileNb + 1; | ||
this.fixedErrorsNumber = this.fixedErrorsNumber + 1; | ||
this.fixedErrorsIds.push(fileFixableError.id); | ||
this.updateLintResult(fileNm, fileFixableError.id, { fixed: true }); | ||
@@ -161,8 +161,9 @@ } | ||
else { | ||
const line = fileLines[lineNb]; | ||
const line = allLines[lineNb]; | ||
const fixedLine = this.tryApplyFixRule(line, lineNb, fileFixableError); | ||
if (fixedLine !== line) { | ||
fileLines[lineNb] = fixedLine; | ||
allLines[lineNb] = fixedLine; | ||
fixedInFileNb = fixedInFileNb + 1; | ||
this.fixedErrorsNumber = this.fixedErrorsNumber + 1; | ||
this.fixedErrorsIds.push(fileFixableError.id); | ||
this.updateLintResult(fileNm, fileFixableError.id, { fixed: true }); | ||
@@ -172,3 +173,3 @@ } | ||
} | ||
const newSources = fileLines.join("\r\n") + "\r\n"; | ||
const newSources = allLines.join("\r\n") + "\r\n"; | ||
// Write new file content if it has been updated | ||
@@ -199,17 +200,3 @@ if (this.options.save && fixedInFileNb > 0) { | ||
// Evaluate variables from message | ||
const evaluatedVars = []; | ||
for (const varDef of fixableError.rule.variables || []) { | ||
// regex | ||
if (varDef.regex) { | ||
const regexRes = fixableError.msg.match(varDef.regex); | ||
if (regexRes && regexRes.length > 1) { | ||
const regexPos = varDef.regexPos || 1; | ||
evaluatedVars.push({ name: varDef.name, value: decodeHtml(regexRes[regexPos]) }); | ||
} else if (this.verbose) { | ||
console.error("NGL: Unable to match " + varDef.regex + " in " + fixableError.msg); | ||
} | ||
} else if (varDef.value) { | ||
evaluatedVars.push({ name: varDef.name, value: varDef.value }); | ||
} | ||
} | ||
const evaluatedVars = evaluateVariables(fixableError.rule.variables, fixableError.msg, { verbose: this.verbose }); | ||
evaluatedVars.push({ name: "lineNb", value: lineNb }); | ||
@@ -288,2 +275,6 @@ | ||
this.updatedLintResult.summary.totalInfoNumber - this.updatedLintResult.summary.totalFixedInfoNumber; | ||
// Return list of fixed error ids | ||
this.updatedLintResult.summary.fixedErrorsNumber = this.fixedErrorsNumber; | ||
this.updatedLintResult.summary.fixedErrorsIds = [...new Set(this.fixedErrorsIds)]; | ||
} | ||
@@ -290,0 +281,0 @@ } |
@@ -1,2 +0,2 @@ | ||
// List fixable CodeNarc rules | ||
// Additional definition for codenarc rules ( get position & available fix) | ||
"use strict"; | ||
@@ -41,2 +41,12 @@ | ||
priority: getPriority("ClosingBraceNotAlone"), | ||
range: { | ||
type: "function", | ||
func: (errLine, errItem) => { | ||
const closingBracePos = errLine.lastIndexOf("}"); | ||
return { | ||
from: { line: errItem.line, char: closingBracePos }, | ||
to: { line: errItem.line, char: closingBracePos + 1 } | ||
}; | ||
} | ||
}, | ||
fix: { | ||
@@ -187,3 +197,4 @@ type: "function", | ||
regex: /The (.*) is at the incorrect indent level: Expected column (.*) but was (.*)/, | ||
regexPos: 2 | ||
regexPos: 2, | ||
type: "number" | ||
}, | ||
@@ -193,5 +204,15 @@ { | ||
regex: /The (.*) is at the incorrect indent level: Expected column (.*) but was (.*)/, | ||
regexPos: 3 | ||
regexPos: 3, | ||
type: "number" | ||
} | ||
], | ||
range: { | ||
type: "function", | ||
func: (errLine, errItem, evaluatedVars) => { | ||
return { | ||
from: { line: errItem.line, char: getVariable(evaluatedVars, "EXPECTED") }, | ||
to: { line: errItem.line, char: getVariable(evaluatedVars, "FOUND") } | ||
}; | ||
} | ||
}, | ||
fix: { | ||
@@ -377,2 +398,13 @@ type: "function", | ||
// Trailing Whitespaces | ||
TrailingWhitespace: { | ||
priority: getPriority("TrailingWhitespace"), | ||
fix: { | ||
type: "function", | ||
func: line => { | ||
return line.trimEnd(); | ||
} | ||
} | ||
}, | ||
// Unnecessary def in field declaration (statif def) | ||
@@ -415,9 +447,20 @@ UnnecessaryDefInFieldDeclaration: { | ||
// Trailing Whitespaces | ||
TrailingWhitespace: { | ||
priority: getPriority("TrailingWhitespace"), | ||
fix: { | ||
// Unused variable | ||
UnusedVariable: { | ||
priority: getPriority("UnusedVariable"), | ||
variables: [ | ||
{ | ||
name: "VARNAME", | ||
regex: /The variable \[(.*)\] in (.*) is not used/ | ||
} | ||
], | ||
range: { | ||
type: "function", | ||
func: line => { | ||
return line.trimEnd(); | ||
func: (errLine, errItem, evaluatedVars) => { | ||
const varName = getVariable(evaluatedVars, "VARNAME"); | ||
const varStartPos = errLine.indexOf(varName); | ||
return { | ||
from: { line: errItem.line, char: varStartPos }, | ||
to: { line: errItem.line, char: varStartPos + varName.length } | ||
}; | ||
} | ||
@@ -432,3 +475,3 @@ } | ||
function getVariable(evaluatedVars, name, optns = { mandatory: false, decodeHtml: false, line: "" }) { | ||
function getVariable(evaluatedVars, name, optns = { mandatory: true, decodeHtml: false, line: "" }) { | ||
const matchingVars = evaluatedVars.filter(evaluatedVar => evaluatedVar.name === name); | ||
@@ -435,0 +478,0 @@ if (matchingVars && matchingVars.length > 0) { |
@@ -12,4 +12,5 @@ #! /usr/bin/env node | ||
const NpmGroovyLintFix = require("./groovy-lint-fix.js"); | ||
const { npmGroovyLintRules } = require("./groovy-lint-rules.js"); | ||
const optionsDefinition = require("./options"); | ||
const { evaluateRange, evaluateVariables, getSourceLines } = require("./utils.js"); | ||
class NpmGroovyLint { | ||
@@ -66,2 +67,14 @@ "use strict"; | ||
// Call an existing NpmGroovyLint instance to request fix of errors | ||
async fixErrors(errorIds) { | ||
this.fixer = new NpmGroovyLintFix(this.lintResult, { | ||
verbose: this.options.verbose, | ||
fixrules: this.options.fixrules, | ||
source: this.options.source, | ||
save: this.tmpGroovyFileName ? false : true | ||
}); | ||
await this.fixer.run(errorIds); | ||
this.lintResult = this.mergeResults(this.lintResult, this.fixer.updatedLintResult); | ||
} | ||
// Actions before call to CodeNarc | ||
@@ -301,2 +314,3 @@ async preProcess() { | ||
for (const fileInfo of folderInfo.File) { | ||
// Build file name, or use '0' if source has been sent as input parameter | ||
const fileNm = this.options.source | ||
@@ -308,4 +322,7 @@ ? 0 | ||
} | ||
// Get source code from file or input parameter | ||
let allLines = await getSourceLines(this.options.source, fileNm); | ||
for (const violation of fileInfo.Violation) { | ||
const err = { | ||
const errItem = { | ||
id: errId, | ||
@@ -324,9 +341,23 @@ line: violation["$"].lineNumber ? parseInt(violation["$"].lineNumber, 10) : 0, | ||
}; | ||
// Add error only if severity is matching logLevel | ||
// Find range & add error only if severity is matching logLevel | ||
if ( | ||
err.severity === "error" || | ||
errItem.severity === "error" || | ||
this.options.loglevel === "info" || | ||
(this.options.loglevel === "warning" && ["error", "warning"].includes(err.severity)) | ||
(this.options.loglevel === "warning" && ["error", "warning"].includes(errItem.severity)) | ||
) { | ||
files[fileNm].errors.push(err); | ||
// Get fixable info & range if they have been defined on the rule | ||
const errRule = npmGroovyLintRules[errItem.rule]; | ||
if (errRule) { | ||
errItem.fixable = errRule.fix ? true : false; | ||
if (errRule.range) { | ||
const evaluatedVars = evaluateVariables(errRule.variables, errItem.msg, { verbose: this.verbose }); | ||
const errLine = allLines[errItem.line - 1]; | ||
const range = evaluateRange(errItem, errRule, evaluatedVars, errLine, allLines, { verbose: this.verbose }); | ||
if (range) { | ||
errItem.range = range; | ||
} | ||
} | ||
} | ||
// Add in file errors | ||
files[fileNm].errors.push(errItem); | ||
errId++; | ||
@@ -372,7 +403,11 @@ } | ||
updatedResults.summary.totalInfoNumber = afterFixResults.summary.totalInfoNumber; | ||
updatedResults.summary.totalFixedErrorNumber = initialResults.summary.totalFixedErrorNumber; | ||
updatedResults.summary.totalFixedWarningNumber = initialResults.summary.totalFixedWarningNumber; | ||
updatedResults.summary.totalFixedInfoNumber = initialResults.summary.totalFixedInfoNumber; | ||
updatedResults.summary.totalFixedErrorNumber = afterFixResults.summary.totalFixedErrorNumber; | ||
updatedResults.summary.totalFixedWarningNumber = afterFixResults.summary.totalFixedWarningNumber; | ||
updatedResults.summary.totalFixedInfoNumber = afterFixResults.summary.totalFixedInfoNumber; | ||
updatedResults.summary.fixedErrorsNumber = afterFixResults.summary.fixedErrorsNumber; | ||
updatedResults.summary.fixedErrorsIds = afterFixResults.summary.fixedErrorsIds; | ||
// Remove not fixed errors from initial result and add remaining errors of afterfixResults | ||
// Pipes because variable content depends that if we run linter after fix or not | ||
for (const fileNm of Object.keys(initialResults.files)) { | ||
@@ -383,3 +418,3 @@ const initialResfileErrors = initialResults.files[fileNm].errors; | ||
errors: afterFixResfileErrors, | ||
updatedSource: initialResults.files[fileNm].updatedSource | ||
updatedSource: afterFixResults.files[fileNm].updatedSource || initialResults.files[fileNm].updatedSource | ||
}; | ||
@@ -386,0 +421,0 @@ for (const initialFileError of initialResfileErrors) { |
@@ -0,0 +0,0 @@ ANTLR 2 License |
@@ -0,0 +0,0 @@ ANTLR 4 License |
@@ -0,0 +0,0 @@ ASM License |
@@ -0,0 +0,0 @@ BSD License |
@@ -0,0 +0,0 @@ Copyright (c) 2002-2012, the original author or authors. |
@@ -0,0 +0,0 @@ The person or persons who have associated work with this document (the |
@@ -0,0 +0,0 @@ Copyright (c) 2006, Sun Microsystems, Inc. |
@@ -0,0 +0,0 @@ Eclipse Public License - v 1.0 |
@@ -0,0 +0,0 @@ Eclipse Public License - v 2.0 |
@@ -0,0 +0,0 @@ Copyright (c) 2003-2006, Joe Walnes |
{ | ||
"name": "npm-groovy-lint", | ||
"version": "2.2.0-beta.5", | ||
"version": "2.2.0-beta.6", | ||
"description": "NPM CodeNarc wrapper to easily lint Groovy files", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15911237
38
1544
7