fix: incorrect lint error position (#16526)

* perform string search using original binding

* Add jest test

* Improve code for better readability
This commit is contained in:
Favour Ohanekwu 2022-09-14 01:35:29 -07:00 committed by GitHub
parent a706ad3160
commit 16b04f33a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 19 deletions

View File

@ -44,8 +44,8 @@ describe("getLintAnnotations()", () => {
const { LINT, PARSE } = PropertyEvaluationErrorType;
const { ERROR, WARNING } = Severity;
it("should return proper annotations", () => {
const value = `Hello {{ world == test }}`;
const errors: EvaluationError[] = [
const value1 = `Hello {{ world == test }}`;
const errors1: EvaluationError[] = [
{
errorType: LINT,
raw:
@ -87,8 +87,8 @@ describe("getLintAnnotations()", () => {
},
];
const res = getLintAnnotations(value, errors, {});
expect(res).toEqual([
const res1 = getLintAnnotations(value1, errors1, {});
expect(res1).toEqual([
{
from: {
line: 0,
@ -126,6 +126,40 @@ describe("getLintAnnotations()", () => {
severity: "warning",
},
]);
/// 2
const value2 = `hss{{hss}}`;
const errors2: EvaluationError[] = [
{
errorType: LINT,
raw:
"\n function closedFunction () {\n const result = hss\n return result;\n }\n closedFunction.call(THIS_CONTEXT)\n ",
severity: ERROR,
errorMessage: "'hss' is not defined.",
errorSegment: " const result = hss",
originalBinding: "{{hss}}",
variables: ["hss", null, null, null],
code: "W117",
line: 0,
ch: 1,
},
];
const res2 = getLintAnnotations(value2, errors2, {});
expect(res2).toEqual([
{
from: {
line: 0,
ch: 5,
},
to: {
line: 0,
ch: 8,
},
message: "'hss' is not defined.",
severity: "error",
},
]);
});
it("should return correct annotation with newline in original binding", () => {

View File

@ -2,6 +2,7 @@ import { last, isNumber, isEmpty } from "lodash";
import { Annotation, Position } from "codemirror";
import {
EvaluationError,
isDynamicValue,
PropertyEvaluationErrorType,
} from "utils/DynamicBindingUtils";
import { Severity } from "entities/AppsmithConsole";
@ -117,6 +118,11 @@ export const getLintAnnotations = (
const annotations: Annotation[] = [];
const lintErrors = filterLintErrors(errors, contextData);
const lines = value.split("\n");
// The binding position of every valid JS Object is constant, so we need not
// waste time checking for position of binding.
// For JS Objects not starting with the expected "export default" statement, we return early
// with a "invalid start statement" lint error
if (
isJSObject &&
!isEmpty(lines) &&
@ -167,8 +173,19 @@ export const getLintAnnotations = (
for (const bindingLocation of bindingPositions) {
const currentLine = bindingLocation.line + line;
const lineContent = lines[currentLine] || "";
const currentCh =
bindingLocation.line !== currentLine ? ch : bindingLocation.ch + ch;
let currentCh: number;
// for case where "{{" is in the same line as the lint error
if (bindingLocation.line === currentLine) {
currentCh =
bindingLocation.ch +
ch +
// Add 2 to account for "{{", if binding is a dynamicValue (NB: JS Objects are dynamicValues without "{{}}")
(isDynamicValue(originalBinding) ? 2 : 0);
} else {
currentCh = ch;
}
// Jshint counts \t as two characters and codemirror counts it as 1.
// So we need to subtract number of tabs to get accurate position
const tabs = lineContent.slice(0, currentCh).match(/\t/g)?.length || 0;

View File

@ -15,11 +15,7 @@ import {
removeLintErrorsFromEntityProperty,
} from "workers/evaluationUtils";
import {
getJSSnippetToLint,
getLintingErrors,
pathRequiresLinting,
} from "./utils";
import { getJSToLint, getLintingErrors, pathRequiresLinting } from "./utils";
interface LintTreeArgs {
unEvalTree: DataTree;
@ -136,19 +132,21 @@ const lintBindingPath = (
);
if (stringSegments) {
jsSnippets.map((jsSnippet) => {
const jsSnippetToLint = getJSSnippetToLint(
jsSnippets.map((jsSnippet, index) => {
if (jsSnippet) {
const jsSnippetToLint = getJSToLint(entity, jsSnippet, propertyPath);
// {{user's code}}
const originalBinding = getJSToLint(
entity,
jsSnippet,
stringSegments[index],
propertyPath,
);
if (jsSnippet) {
const scriptType = getScriptType(false, false);
const scriptToLint = getScriptToEval(jsSnippetToLint, scriptType);
lintErrors = getLintingErrors(
scriptToLint,
globalData,
jsSnippetToLint,
originalBinding,
scriptType,
);
}

View File

@ -55,7 +55,8 @@ export const pathRequiresLinting = (
return requiresLinting;
};
export const getJSSnippetToLint = (
// Removes "export default" statement from js Object
export const getJSToLint = (
entity: DataTreeEntity,
snippet: string,
propertyPath: string,
@ -97,6 +98,7 @@ function getEvaluationScriptPosition(scriptType: EvaluationScriptType) {
export const getLintingErrors = (
script: string,
data: Record<string, unknown>,
// {{user's code}}
originalBinding: string,
scriptType: EvaluationScriptType,
): EvaluationError[] => {