Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

npm-groovy-lint

Package Overview
Dependencies
Maintainers
1
Versions
204
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

npm-groovy-lint - npm Package Compare versions

Comparing version 3.0.0-beta.4 to 3.0.0-beta.5

jdeploy-bundle/rules/BracesForIfElse.js

10

CHANGELOG.md

@@ -8,3 +8,13 @@ # Changelog

- Local microservice "CodeNarcServer" called via Http by npm-groovy-lint, to avoid loading all groovy/java classes at each lint request. This microservice autokills itself after one hour idle.
- Test classes for rules fix (before / after fix defined in rule definitions)
- Add debug logs (use it by setting DEBUG env variable , ex: `DEBUG=npm-groovy-lint npm-groovy-lint args...`)
- Update lines and ranges of other errors after a fix updated the number of lines
## Changes
- Split rules definition into files instead of all in a huge single file
- New lib utils.js that can be used by rules definition
- Fix: Crash when there was no error found in a file
- Fix: Remove Promise error display in log after launching CodeNarcServer
## [2.2.0] 2020-02-28

@@ -11,0 +21,0 @@

98

jdeploy-bundle/groovy-lint-fix.js

@@ -46,3 +46,4 @@ #! /usr/bin/env node

// Fix errors using codenarc result and groovy lint rules
async run(errorIds = null) {
async run(optns = { errorIds: null, propagate: false }) {
debug(`<<<<<< NpmGroovyLintFix.run START >>>>>>`);
// Start progress bar

@@ -59,4 +60,4 @@ this.bar = new cliProgress.SingleBar(

// Parse fixes and process them
await this.parseFixableErrors(errorIds);
await this.fixErrors();
await this.parseFixableErrors(optns.errorIds);
await this.fixErrors(optns.propagate);

@@ -67,3 +68,3 @@ this.updateResultCounters();

this.bar.stop();
debug(`>>>>>> NpmGroovyLintFix.run END <<<<<<`);
return this;

@@ -118,2 +119,3 @@ }

}
debug(`Parsed fixable errors: ${JSON.stringify(this.fixableErrors)}`);
}

@@ -134,3 +136,3 @@

// Fix errors in files using fix rules
async fixErrors() {
async fixErrors(propagate) {
// Process files in parallel

@@ -151,9 +153,12 @@ await Promise.all(

if (fileFixableError.rule.scope === "file") {
const allLinesNew = this.tryApplyFixRule(allLines, lineNb, fileFixableError).slice(); // copy result lines
if (JSON.stringify(allLinesNew) !== JSON.stringify(allLines.toString)) {
allLines = allLinesNew;
const allLinesNew = this.tryApplyFixRule([...allLines], lineNb, fileFixableError).slice(); // copy result lines
if (JSON.stringify(allLinesNew) !== JSON.stringify(allLines)) {
fixedInFileNb = fixedInFileNb + 1;
this.fixedErrorsNumber = this.fixedErrorsNumber + 1;
this.fixedErrorsIds.push(fileFixableError.id);
this.updateLintResult(fileNm, fileFixableError.id, { fixed: true });
this.updateLintResult(fileNm, fileFixableError.id, { fixed: true }, propagate, {
beforeFix: allLines,
afterFix: allLinesNew
});
allLines = allLinesNew;
}

@@ -170,3 +175,3 @@ }

this.fixedErrorsIds.push(fileFixableError.id);
this.updateLintResult(fileNm, fileFixableError.id, { fixed: true });
this.updateLintResult(fileNm, fileFixableError.id, { fixed: true }, propagate);
}

@@ -240,23 +245,62 @@ }

// Update lint result of an identified error
updateLintResult(fileNm, errId, errDataToSet) {
updateLintResult(fileNm, errId, errDataToSet, propagate, compareInfo = {}) {
const errIndex = this.updatedLintResult.files[fileNm].errors.findIndex(error => error.id === errId);
if (errIndex < 0) {
// No error to update in case of fix from triggers of another rule
return;
// Update error in lint result {mostly fixed: true}
// It not in list of errors, it means it's from a triggered error
if (errIndex > -1) {
const error = this.updatedLintResult.files[fileNm].errors[errIndex];
Object.assign(error, errDataToSet);
this.updatedLintResult.files[fileNm].errors[errIndex] = error;
if (errDataToSet.fixed === true) {
switch (error.severity) {
case "error":
this.updatedLintResult.summary.totalFixedErrorNumber++;
break;
case "warning":
this.updatedLintResult.summary.totalFixedWarningNumber++;
break;
case "info":
this.updatedLintResult.summary.totalFixedInfoNumber++;
break;
}
}
}
const error = this.updatedLintResult.files[fileNm].errors[errIndex];
Object.assign(error, errDataToSet);
this.updatedLintResult.files[fileNm].errors[errIndex] = error;
if (errDataToSet.fixed === true) {
switch (error.severity) {
case "error":
this.updatedLintResult.summary.totalFixedErrorNumber++;
// If the number of lines has changes, update lines after
if (propagate && compareInfo && compareInfo.beforeFix && compareInfo.afterFix) {
// Propagate only if number of lines is different
if (compareInfo.beforeFix.length === compareInfo.afterFix.length) {
return;
}
let diffLinesNb = compareInfo.afterFix.length - compareInfo.beforeFix.length;
let firstAddedOrRemovedLineNb;
// Find first updated line number
for (let i = 0; i < compareInfo.beforeFix.length; i++) {
if (compareInfo.beforeFix[i] !== compareInfo.afterFix[i]) {
firstAddedOrRemovedLineNb = i;
break;
case "warning":
this.updatedLintResult.summary.totalFixedWarningNumber++;
break;
case "info":
this.updatedLintResult.summary.totalFixedInfoNumber++;
break;
}
}
// Recalculate line positions if line number has changed
if ((firstAddedOrRemovedLineNb || firstAddedOrRemovedLineNb === 0) & (diffLinesNb !== 0)) {
// Update lint results
this.updatedLintResult.files[fileNm].errors = this.updatedLintResult.files[fileNm].errors.map(err => {
if (err.range && err.range.start.line >= firstAddedOrRemovedLineNb) {
err.range.start.line = err.range.start.line + diffLinesNb;
err.range.end.line = err.range.end.line + diffLinesNb;
}
if (err.line && err.line >= firstAddedOrRemovedLineNb) {
err.line = err.line + diffLinesNb;
}
return err;
});
// Update fixable Errors
this.fixableErrors[fileNm] = this.fixableErrors[fileNm].map(fixableError => {
if ((fixableError.lineNb || fixableError.lineNb === 0) && fixableError.lineNb >= firstAddedOrRemovedLineNb) {
fixableError.lineNb = fixableError.lineNb + diffLinesNb;
}
return fixableError;
});
}
}

@@ -263,0 +307,0 @@ }

@@ -5,7 +5,13 @@ // Additional definition for codenarc rules ( get position & available fix)

/*
RuleName: {
const rule = {
// add scope = "file" if the fix impacts more than the identified line (If fix defined)
scope: "file",
// Define a priority at the top of groovy-lint-rules.js (If fix defined)
priority: getPriority("RuleName"),
scope: "file", // default: line
// add isCodeNarcRule: false if the rule is not part of CodeNarc list of supported rules ( but triggered by another rule with trigger property)
isCodeNarcRule: false, // default: true
// List of other rules fix that this rule fix must trigger (if fix defined)
triggers: ["SomeOtherRule","AnotherRule"],
// Extract variables from CodeNarc error message (optional)

@@ -25,2 +31,3 @@ variables: [

],
// Return range for UI . Input: errorLine, errorItem, evaluated variables

@@ -37,2 +44,3 @@ range: {

},
// Fix if scope = file

@@ -56,5 +64,20 @@ fix: {

}
}
},
},
// Definition for automated tests (mocha).
// If a fix is defined, define at least one test with sourceBefore and sourceAfter expected value
tests: [
{
sourceBefore: `
def str = "lelamanul"
`,
sourceAfter: `
str = "lelamanul"
`
}
]
}
module.exports = { rule }
*/

@@ -64,7 +87,4 @@

const decodeHtml = require("decode-html");
const fse = require("fs-extra");
// Default indent length
const indentLength = 4;
// If you add a new global rule, it's very important to think about their order.

@@ -87,3 +107,2 @@ // Rules modifiyng the number of lines must arrive last !

// Rule that can change the numbers of lines, so they must be processed after line scope rules
"IfStatementBraces",

@@ -98,733 +117,16 @@ "ElseBlocktBraces",

const npmGroovyLintRules = {
// Braces for if else
BracesForIfElse: {
range: {
type: "function",
func: (_errLine, errItem, _evaluatedVars, allLines) => {
return findRangeBetweenStrings(allLines, errItem, "if", "{");
}
}
},
const RULES_FOLDER = __dirname + "/rules";
// Exception type must not be used
CatchException: {
range: {
type: "function",
func: (errLine, errItem) => {
return getStringRange(errLine, "Exception", errItem);
}
}
},
// Closing brace not alone
ClosingBraceNotAlone: {
scope: "file",
priority: getPriority("ClosingBraceNotAlone"),
range: {
type: "function",
func: (errLine, errItem) => {
const closingBracePos = errLine.lastIndexOf("}");
return {
start: { line: errItem.line, character: closingBracePos },
end: { line: errItem.line, character: closingBracePos + 1 }
};
}
},
fix: {
type: "function",
func: allLines => {
const newFileLines = [];
let prevLine = "";
for (const line of allLines) {
const newLine = line.replace("{{{NEWLINECLOSINGBRACE}}}", "");
const prevLineIndent = prevLine.search(/\S/);
newFileLines.push(newLine);
if (newLine !== line) {
newFileLines.push(" ".repeat(prevLineIndent) + "}");
}
prevLine = newLine;
}
return newFileLines;
}
}
},
// Consecutive blank lines
ConsecutiveBlankLines: {
scope: "file",
priority: getPriority("ConsecutiveBlankLines"),
fix: {
label: "Remove consecutive blank lines",
type: "function",
func: allLines => {
const newFileLines = [];
let prevLine = "none";
for (const line of allLines) {
if (!(line.trim() === "" && prevLine.trim() === "")) {
// Check if previous line is empty: if not do not add line
newFileLines.push(line);
prevLine = line;
}
}
return newFileLines;
}
}
},
// Missing else braces
ElseBlockBraces: {
scope: "file",
unitary: true,
triggers: ["ClosingBraceNotAlone"],
priority: getPriority("ElseBlocktBraces"),
range: {
type: "function",
func: (errLine, errItem) => {
return getStringRangeMultiline(errLine, "else", errItem);
}
},
fix: {
label: "Add braces",
type: "function",
func: (allLines, variables) => {
const lineNumber = getVariable(variables, "lineNb", { mandatory: true });
// If next line is also a if/else, this rule can not autofix for now, it has to be done manually
if (allLines[lineNumber + 1] && lineNumber[lineNumber + 1].includes("else")) {
return allLines;
}
let line = allLines[lineNumber];
line = line.trimEnd() + " {";
allLines[lineNumber] = line;
// next line
let match = false;
let pos = 0;
let level = 0;
while (!match && pos < allLines.length) {
let nextLine = allLines[lineNumber + pos + 1];
if (isValidCodeLine(nextLine) && level === 0) {
if (!nextLine.trim().startsWith("if") && !nextLine.includes("{")) {
nextLine = nextLine + "{{{NEWLINECLOSINGBRACE}}}";
allLines[lineNumber + pos + 1] = nextLine;
match = true;
} else if (nextLine.includes("}") && !nextLine.includes("{")) {
level--;
} else {
level++;
}
}
pos++;
}
return allLines;
}
}
},
// File ends without new line
FileEndsWithoutNewline: {
scope: "file",
priority: getPriority("FileEndsWithoutNewline"),
fix: {
label: "Add new line at the end of file",
type: "function",
func: allLines => {
return (allLines.join("\r\n") + "\r\n").split("\r\n");
}
}
},
// nvuillam: Fix not working, especially when embedded missing If statements ...
// let's let people correct that manually for now :)
// Missing if braces
IfStatementBraces: {
scope: "file",
unitary: true,
triggers: ["ClosingBraceNotAlone"],
priority: getPriority("IfStatementBraces"),
range: {
type: "function",
func: (errLine, errItem) => {
return getStringRange(errLine, "if", errItem);
}
},
fix: {
label: "Add if statement braces",
type: "function",
func: (allLines, variables) => {
const lineNumber = getVariable(variables, "lineNb", { mandatory: true });
// If next line is also a if/else, this rule can not autofix for now, it has to be done manually
if (allLines[lineNumber + 1] && (allLines[lineNumber + 1].includes("if") || allLines[lineNumber + 1].includes("else"))) {
return allLines;
}
// If line
let line = allLines[lineNumber];
line = line.trimEnd() + " {";
allLines[lineNumber] = line;
// next line
let match = false;
let pos = 0;
let level = 0;
while (!match && pos < allLines.length) {
let nextLine = allLines[lineNumber + pos + 1];
if (isValidCodeLine(nextLine) && level === 0) {
if (!nextLine.trim().startsWith("if") && !nextLine.includes("{")) {
nextLine = nextLine + "{{{NEWLINECLOSINGBRACE}}}";
allLines[lineNumber + pos + 1] = nextLine;
match = true;
} else if (nextLine.includes("}") && !nextLine.includes("{")) {
level--;
} else {
level++;
}
}
pos++;
}
return allLines;
}
}
},
// Indentation
Indentation: {
triggers: ["IndentationClosingBraces", "IndentationComments"],
priority: getPriority("Indentation"),
variables: [
{
name: "EXPECTED",
regex: /The (.*) is at the incorrect indent level: Expected column (.*) but was (.*)/,
regexPos: 2,
type: "number"
},
{
name: "FOUND",
regex: /The (.*) is at the incorrect indent level: Expected column (.*) but was (.*)/,
regexPos: 3,
type: "number"
}
],
range: {
type: "function",
func: (errLine, errItem, evaluatedVars) => {
return {
start: { line: errItem.line, character: 0 },
end: { line: errItem.line, character: getVariable(evaluatedVars, "FOUND") - 1 }
};
}
},
fix: {
label: "Fix indentation",
type: "function",
func: (line, evaluatedVars) => {
const expectedCol = parseInt(getVariable(evaluatedVars, "EXPECTED", { mandatory: true, line: line }), 10);
// const foundIndent = parseInt(getVariable(evaluatedVars, "FOUND", { mandatory: true, line: line }));
/* if (line.trim() === "}") {
// Manage Wrong info from codeNarc :/ {
line = " ".repeat(expectedIndent + (indentLength * 2)) + line.trimStart();
} else { */
const startSpaces = expectedCol === 0 ? 0 : expectedCol - 1;
line = " ".repeat(startSpaces) + line.trimStart();
return line;
}
}
},
// Indentation comments
IndentationComments: {
scope: "file",
priority: getPriority("IndentationComments"),
fix: {
label: "Fix indentation",
type: "function",
func: allLines => {
const newFileLines = [];
for (let i = 0; i < allLines.length; i++) {
let line = allLines[i];
// Detect comment line
if (line.trimStart().startsWith("//")) {
// Find indentation of next line (which is not blank or a comment)
let j = 1;
let nextLineIndent = null;
while (allLines[i + j] && nextLineIndent == null) {
if (!/^\s*$/.test(allLines[i + j]) && !allLines[i + j].trimStart().startsWith("//")) {
nextLineIndent = allLines[i + j].search(/\S/); // find first non blank character
}
j++;
}
// Set new indentation it on this comment line
if (nextLineIndent) {
line = " ".repeat(nextLineIndent) + line.trimStart();
}
}
newFileLines.push(line);
}
return newFileLines;
}
}
},
// Indentation closing braces
IndentationClosingBraces: {
scope: "file",
priority: getPriority("IndentationClosingBraces"),
fix: {
label: "Fix indentation",
type: "function",
func: allLines => {
const newFileLines = [];
for (let i = 0; i < allLines.length; i++) {
let line = allLines[i] + "";
// Detect closing brace line
if (line.trim() === "}") {
// Find indentation of matching brace (CodeNarc Indentation rule does not always work well :/ )
let j = 1;
let matchingLineIndent = null;
let level = 1;
while ((allLines[i - j] || allLines[i - j] === "") && matchingLineIndent == null) {
const prevLine = allLines[i - j];
if (prevLine.includes("}") && !prevLine.includes("${")) {
level++;
}
if (prevLine.includes("{") && !prevLine.includes("${")) {
level--;
if (level === 0) {
matchingLineIndent = prevLine.search(/\S/);
}
}
j++;
}
// Set new indentation it on this comment line
if (matchingLineIndent) {
line = (" ".repeat(matchingLineIndent) + line.trimStart()).replace(/\t/g, "");
}
}
newFileLines.push(line);
}
return newFileLines;
}
}
},
// No use of Java.io classes
/* NV: TODO: finalise for when there is several occurences of the string in the same line
JavaIoPackageAccess: {
variables: [
{
name: "CLASSNAME",
regex: /The use of java.io.(.*) violates the Enterprise Java Bean specification/,
regexPos: 1
}
],
range: {
type: "function",
func: (errLine, errItem, evaluatedVars) => {
return getLastVariableRange(errLine, evaluatedVars, "CLASSNAME", errItem);
}
}
}, */
// Too many methods in a class
MethodCount: {
variables: [
{
name: "CLASSNAME",
regex: /Class (.*) has 52 methods/,
regexPos: 1
}
],
range: {
type: "function",
func: (errLine, errItem, evaluatedVars) => {
return getVariableRange(errLine, evaluatedVars, "CLASSNAME", errItem);
}
}
},
// No use of Java.util.date
NoJavaUtilDate: {
range: {
type: "function",
func: (errLine, errItem) => {
return getStringRange(errLine, "Date", errItem);
}
}
},
// No tab character
NoTabCharacter: {
scope: "file",
priority: getPriority("NoTabCharacter"),
fix: {
label: "Replace tabs by spaces in all file",
type: "function",
func: allLines => {
const newFileLines = [];
const replaceChars = " ".repeat(indentLength);
for (const line of allLines) {
newFileLines.push(line.replace(/\t/g, replaceChars));
}
return newFileLines;
}
}
},
// Space after catch
SpaceAfterCatch: {
range: {
type: "function",
func: (errLine, errItem) => {
return getStringRange(errLine, "){", errItem);
}
},
priority: getPriority("SpaceAfterCatch"),
fix: {
label: "Add space after catch",
type: "replaceString",
before: "){",
after: ") {"
}
},
// Space after opening brace
SpaceAfterOpeningBrace: {
priority: getPriority("SpaceAfterOpeningBrace"),
range: {
type: "function",
func: (errLine, errItem) => {
return getStringRange(errLine, "{", errItem);
}
},
fix: {
label: "Add space after opening brace",
type: "function",
func: line => {
const regexMatch = line.match(new RegExp(/{[^ ]/, "g"));
if (regexMatch && regexMatch[0]) {
line = line.replace(regexMatch[0], "{ " + regexMatch[0][1]);
}
return line;
}
}
},
// Space around operators
SpaceAroundOperator: {
priority: getPriority("SpaceAroundOperator"),
variables: [
{
name: "OPERATOR",
regex: /The operator "(.*)" within class (.*) is not (.*) by a space or whitespace/
}
],
range: {
type: "function",
func: (errLine, errItem, evaluatedVars) => {
return getVariableRange(errLine, evaluatedVars, "OPERATOR", errItem);
}
},
fix: {
label: "Add space around operator",
type: "function",
func: (line, evaluatedVars) => {
let operator = getVariable(evaluatedVars, "OPERATOR", { mandatory: true, htmlToString: true, line: line });
if (!line.includes("+=") && !line.includes("++") && !line.includes("--") && !line.includes("-=")) {
return addSpaceAroundChar(line, operator);
} else {
return line;
}
}
}
},
// Add space after a comma
SpaceAfterComma: {
priority: getPriority("SpaceAfterComma"),
range: {
type: "function",
func: (errLine, errItem) => {
return getStringRange(errLine, ",", errItem);
}
},
fix: {
label: "Add space after comma",
type: "function",
func: line => {
return addSpaceAroundChar(line, ",");
}
}
},
// Space before opening brace
SpaceBeforeOpeningBrace: {
priority: getPriority("SpaceBeforeOpeningBrace"),
range: {
type: "function",
func: (errLine, errItem) => {
return getStringRange(errLine, "{", errItem);
}
},
fix: {
label: "Add space before opening brace",
type: "function",
func: line => {
const regexMatch = line.match(new RegExp(/[^ ]{/, "g"));
if (regexMatch && regexMatch[0]) {
line = line.replace(regexMatch[0], regexMatch[0][0] + " {");
}
return line;
}
}
},
// System.exit forbidden
SystemExit: {
range: {
type: "function",
func: (errLine, errItem, evaluatedVars) => {
return getVariableRange(errLine, evaluatedVars, "System.exit", errItem);
}
}
},
// Trailing Whitespaces
TrailingWhitespace: {
priority: getPriority("TrailingWhitespace"),
range: {
type: "function",
func: (errLine, errItem) => {
const diff = errLine.length - errLine.trimEnd().length;
return {
start: { line: errItem.line, character: errLine.length - diff },
end: { line: errItem.line, character: errLine.length }
};
}
},
fix: {
label: "Remove trailing whitespace",
type: "function",
func: line => {
return line.trimEnd();
}
}
},
// Unnecessary def in field declaration (statif def)
UnnecessaryDefInFieldDeclaration: {
priority: getPriority("UnnecessaryDefInFieldDeclaration"),
range: {
type: "function",
func: (errLine, errItem) => {
return getStringRange(errLine, "def", errItem);
}
},
fix: {
label: "Remove def",
type: "replaceString",
before: "def ",
after: ""
}
},
// Unnecessary Groovy String
UnnecessaryGString: {
priority: getPriority("UnnecessaryGString"),
variables: [
{
name: "STRING",
regex: /The String '(.*)' can be wrapped in single quotes instead of double quotes/
}
],
range: {
type: "function",
func: (errLine, errItem, evaluatedVars) => {
return getVariableRange(errLine, evaluatedVars, "STRING", errItem);
}
},
fix: {
label: "Replace double quotes by single quotes",
type: "replaceString",
before: '"{{STRING}}"',
after: "'{{STRING}}'"
}
},
// Unnecessary semi colon at the end of a line
UnnecessarySemicolon: {
priority: getPriority("UnnecessarySemicolon"),
range: {
type: "function",
func: (errLine, errItem) => {
return getLastStringRange(errLine, ";", errItem);
}
},
fix: {
label: "Remove unnecessary semicolon",
type: "function",
func: line => {
if ((line.match(/;/g) || []).length === 1) {
line = line.split(";").join("");
}
return line;
}
}
},
// Unnecessary toString()
UnnecessaryToString: {
priority: getPriority("UnnecessaryToString"),
range: {
type: "function",
func: (errLine, errItem) => {
return getStringRange(errLine, ".toString()", errItem);
}
},
fix: {
label: "Remove unnecessary toString()",
type: "function",
func: line => {
return line.replace(".toString()");
}
}
},
// Unused method parameter
UnusedMethodParameter: {
variables: [
{
name: "PARAMNAME",
regex: /Violation in class (.*) Method parameter \[(.*)\] is never referenced in the method (.*) of class (.*)/,
regexPos: 2
}
],
range: {
type: "function",
func: (errLine, errItem, evaluatedVars) => {
return getVariableRange(errLine, evaluatedVars, "PARAMNAME", errItem);
}
}
},
// Unused variable
UnusedVariable: {
variables: [
{
name: "VARNAME",
regex: /The variable \[(.*)\] in (.*) is not used/
}
],
range: {
type: "function",
func: (errLine, errItem, evaluatedVars) => {
return getVariableRange(errLine, evaluatedVars, "VARNAME", errItem);
}
}
const ruleFiles = fse.readdirSync(RULES_FOLDER);
const npmGroovyLintRules = {};
for (const file of ruleFiles) {
const ruleName = file.replace(".js", "");
const { rule } = require(`${RULES_FOLDER}/${file}`);
if (rule.disabled) {
continue;
}
};
function getPriority(ruleName) {
return rulesFixPriorityOrder.indexOf(ruleName);
rule.priority = rulesFixPriorityOrder.indexOf(ruleName);
npmGroovyLintRules[ruleName] = rule;
}
function getVariable(evaluatedVars, name, optns = { mandatory: true, decodeHtml: false, line: "" }) {
const matchingVars = evaluatedVars.filter(evaluatedVar => evaluatedVar.name === name);
if (matchingVars && matchingVars.length > 0) {
return optns.decodeHtml ? decodeHtml(matchingVars[0].value) : matchingVars[0].value;
} else if (optns.mandatory) {
throw new Error("NGL fix: missing mandatory variable " + name + " in " + JSON.stringify(evaluatedVars)) + "for line :\n" + optns.line;
} else {
return null;
}
}
function getStringRange(errLine, str, errItem) {
const varStartPos = errLine.indexOf(str);
return {
start: { line: errItem.line, character: varStartPos },
end: { line: errItem.line, character: varStartPos + str.length }
};
}
function getStringRangeMultiline(allLines, str, errItem) {
let range = getDefaultRange(allLines, errItem);
let pos = errItem.line - 1;
let isFound = false;
while (isFound === false && pos < allLines.length) {
if (!isFound && allLines[pos].indexOf(str) > -1) {
const varStartPos = allLines[pos].indexOf(str);
range = {
start: { line: errItem.line, character: varStartPos },
end: { line: errItem.line, character: varStartPos + str.length }
};
isFound = true;
}
pos++;
}
return range;
}
function getLastStringRange(errLine, str, errItem) {
const varStartPos = errLine.lastIndexOf(str);
return {
start: { line: errItem.line, character: varStartPos },
end: { line: errItem.line, character: varStartPos + str.length }
};
}
function getVariableRange(errLine, evaluatedVars, variable, errItem) {
const varValue = getVariable(evaluatedVars, variable);
return getStringRange(errLine, varValue, errItem);
}
/*
function getLastVariableRange(errLine, evaluatedVars, variable, errItem) {
const varValue = getVariable(evaluatedVars, variable);
return getLastStringRange(errLine, varValue, errItem);
}
*/
function findRangeBetweenStrings(allLines, errItem, strStart, strEnd) {
let range = getDefaultRange(allLines, errItem);
let pos = errItem.line - 1;
let isStartFound = false;
let isEndFound = false;
while ((isStartFound === false || isEndFound === false) && pos < allLines.length) {
if (!isStartFound && allLines[pos].indexOf(strStart) > -1) {
range.start = { line: pos + 1, character: allLines[pos].indexOf(strStart) };
isStartFound = true;
}
if (!isEndFound && allLines[pos].indexOf(strEnd) > -1) {
range.end = { line: pos + 1, character: allLines[pos].indexOf(strEnd) };
isEndFound = true;
}
pos++;
}
return range;
}
function getDefaultRange(allLines, errItem) {
return {
start: { line: errItem.line, character: 0 },
end: { line: errItem.line, character: allLines[errItem.line - 1].length }
};
}
function isValidCodeLine(line) {
return line.trim() !== "" && line.trim().split("//")[0] !== "";
}
function addSpaceAroundChar(line, char) {
let pos = -1;
const splits = line.split(char);
const newArray = splits.map(str => {
pos++;
if (pos === 0) {
return str.trimEnd();
} else if (pos === splits.length - 1) {
return str.trimStart();
} else {
return str.trim();
}
});
return newArray.join(" " + char + " ").trimEnd();
}
module.exports = { npmGroovyLintRules };

@@ -70,2 +70,3 @@ #! /usr/bin/env node

async run() {
debug(`<<< NpmGroovyLint.run START >>>`);
const doProcess = await this.preProcess();

@@ -76,2 +77,3 @@ if (doProcess) {

}
debug(`>>> NpmGroovyLint.run END <<<`);
return this;

@@ -81,10 +83,11 @@ }

// Call an existing NpmGroovyLint instance to request fix of errors
async fixErrors(errorIds) {
async fixErrors(errorIds, optns = {}) {
debug(`Fix errors for ${JSON.stringify(errorIds)} on existing NpmGroovyLint instance`);
this.fixer = new NpmGroovyLintFix(this.lintResult, {
verbose: this.options.verbose,
fixrules: this.options.fixrules,
source: this.options.source,
verbose: optns.verbose || this.options.verbose,
fixrules: optns.fixrules || this.options.fixrules,
source: optns.source || this.options.source,
save: this.tmpGroovyFileName ? false : true
});
await this.fixer.run(errorIds);
await this.fixer.run({ errorIds: errorIds, propagate: true });
this.lintResult = this.fixer.updatedLintResult;

@@ -181,2 +184,3 @@ }

await fse.writeFile(this.tmpGroovyFileName, this.options.source);
debug(`Create temp file ${this.tmpGroovyFileName} with input source, as CodeNarc requires physical files`);
}

@@ -290,2 +294,3 @@

};
debug(`CALL CodeNarcServer with ${JSON.stringify(rqstOptions, null, 2)}`);
let parsedBody = null;

@@ -323,3 +328,3 @@ try {

// Start progress bar
debug("NGL: running CodeNarc using " + jDeployCommand);
debug(`CALL CodeNarcJava with ${jDeployCommand}`);
this.bar = new cliProgress.SingleBar(

@@ -374,5 +379,8 @@ {

let interval;
debug(`ATTEMPT to start CodeNarcServer with ${jDeployCommand}`);
try {
// Start server using java
exec(jDeployCommand, { timeout: this.execTimeout });
// Start server using java (we don't care the promise result, as the following promise will poll the server)
exec(jDeployCommand, { timeout: this.execTimeout })
.then(() => {})
.catch(() => {});
// Poll it until it is ready

@@ -387,2 +395,3 @@ const start = performance.now();

this.serverStatus = "running";
debug(`SUCCESS: CodeNarcServer is running`);
clearInterval(interval);

@@ -426,4 +435,6 @@ resolve();

}
console.log("NGL: Unable to start CodeNarc Server. Use --noserver if you do not even want to try");
const errMsg = "NGL: Unable to start CodeNarc Server. Use --noserver if you do not even want to try";
debug(errMsg);
debug(e.message);
console.log(errMsg);
}

@@ -445,3 +456,3 @@

}
// no --ngl* options
// only --codenarcargs arguments
else if (this.onlyCodeNarc) {

@@ -476,2 +487,4 @@ console.log("NGL: Successfully processed CodeNarc: \n" + this.codeNarcStdOut);

await fse.remove(this.tmpGroovyFileName);
debug(`Removed temp file ${this.tmpGroovyFileName} as it is not longer used`);
this.tmpXmlFileName = null;
}

@@ -504,2 +517,3 @@ }

if (!folderInfo.File) {
debug(`Warning: ${folderInfo} does not contain any File item`);
continue;

@@ -562,4 +576,4 @@ }

}
// Complete with files with no error
result.files = files;
await fse.remove(this.tmpXmlFileName); // Remove temporary file
return result;

@@ -572,2 +586,3 @@ }

const lintAgainOptions = JSON.parse(JSON.stringify(this.options));
debug(`Fix is done, lint again with options ${JSON.stringify(lintAgainOptions)}`);
if (this.options.source) {

@@ -609,3 +624,3 @@ lintAgainOptions.source = this.lintResult.files[0].updatedSource;

const initialResfileErrors = initialResults.files[fileNm].errors;
const afterFixResfileErrors = afterFixResults.files[fileNm].errors;
const afterFixResfileErrors = afterFixResults.files[fileNm] ? afterFixResults.files[fileNm].errors : [];
const fileDtl = {

@@ -626,3 +641,3 @@ errors: afterFixResfileErrors,

updatedResults.summary.fixedErrorsIds = fixedErrorsIds;
debug(`Merged results summary ${JSON.stringify(updatedResults.summary)}`);
return updatedResults;

@@ -629,0 +644,0 @@ }

@@ -17,2 +17,7 @@ // Shared functions

// Get indent length
function getIndentLength() {
return 4;
}
// Evaluate variables from messages

@@ -57,2 +62,118 @@ function evaluateVariables(variableDefs, msg) {

module.exports = { evaluateVariables, getSourceLines, evaluateRange };
function getVariable(evaluatedVars, name, optns = { mandatory: true, decodeHtml: false, line: "" }) {
const matchingVars = evaluatedVars.filter(evaluatedVar => evaluatedVar.name === name);
if (matchingVars && matchingVars.length > 0) {
return optns.decodeHtml ? decodeHtml(matchingVars[0].value) : matchingVars[0].value;
} else if (optns.mandatory) {
throw new Error("NGL fix: missing mandatory variable " + name + " in " + JSON.stringify(evaluatedVars)) + "for line :\n" + optns.line;
} else {
return null;
}
}
function getStringRange(errLine, str, errItem) {
const varStartPos = errLine.indexOf(str);
return {
start: { line: errItem.line, character: varStartPos },
end: { line: errItem.line, character: varStartPos + str.length }
};
}
function getStringRangeMultiline(allLines, str, errItem) {
let range = getDefaultRange(allLines, errItem);
let pos = errItem.line - 1;
let isFound = false;
while (isFound === false && pos < allLines.length) {
if (!isFound && allLines[pos].indexOf(str) > -1) {
const varStartPos = allLines[pos].indexOf(str);
range = {
start: { line: errItem.line, character: varStartPos },
end: { line: errItem.line, character: varStartPos + str.length }
};
isFound = true;
}
pos++;
}
return range;
}
function getLastStringRange(errLine, str, errItem) {
const varStartPos = errLine.lastIndexOf(str);
return {
start: { line: errItem.line, character: varStartPos },
end: { line: errItem.line, character: varStartPos + str.length }
};
}
function getVariableRange(errLine, evaluatedVars, variable, errItem) {
const varValue = getVariable(evaluatedVars, variable);
return getStringRange(errLine, varValue, errItem);
}
/*
function getLastVariableRange(errLine, evaluatedVars, variable, errItem) {
const varValue = getVariable(evaluatedVars, variable);
return getLastStringRange(errLine, varValue, errItem);
}
*/
function findRangeBetweenStrings(allLines, errItem, strStart, strEnd) {
let range = getDefaultRange(allLines, errItem);
let pos = errItem.line - 1;
let isStartFound = false;
let isEndFound = false;
while ((isStartFound === false || isEndFound === false) && pos < allLines.length) {
if (!isStartFound && allLines[pos].indexOf(strStart) > -1) {
range.start = { line: pos + 1, character: allLines[pos].indexOf(strStart) };
isStartFound = true;
}
if (!isEndFound && allLines[pos].indexOf(strEnd) > -1) {
range.end = { line: pos + 1, character: allLines[pos].indexOf(strEnd) };
isEndFound = true;
}
pos++;
}
return range;
}
function getDefaultRange(allLines, errItem) {
return {
start: { line: errItem.line, character: 0 },
end: { line: errItem.line, character: allLines[errItem.line - 1].length }
};
}
function isValidCodeLine(line) {
return line.trim() !== "" && line.trim().split("//")[0] !== "";
}
function addSpaceAroundChar(line, char) {
let pos = -1;
const splits = line.split(char);
const newArray = splits.map(str => {
pos++;
if (pos === 0) {
return str.trimEnd();
} else if (pos === splits.length - 1) {
return str.trimStart();
} else {
return str.trim();
}
});
return newArray.join(" " + char + " ").trimEnd();
}
module.exports = {
addSpaceAroundChar,
evaluateRange,
evaluateVariables,
findRangeBetweenStrings,
getIndentLength,
getLastStringRange,
getSourceLines,
getStringRange,
getStringRangeMultiline,
getVariable,
getVariableRange,
isValidCodeLine
};
{
"name": "npm-groovy-lint",
"version": "3.0.0-beta.4",
"version": "3.0.0-beta.5",
"description": "NPM CodeNarc wrapper to easily lint Groovy files",

@@ -60,2 +60,3 @@ "main": "index.js",

"babel-eslint": "^10.0.3",
"diff": "^4.0.2",
"eslint": "^6.8.0",

@@ -62,0 +63,0 @@ "eslint-config-standard": "^14.1.0",

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc