[ES|QL] Improve warning handling for messages without positioning (#169066)

## Summary

This PR improves the warning unmarshalling for ES|QL providing support
for messages without positioning (`Line x:xx: ...`).

<img width="438" alt="Screenshot 2023-10-17 at 10 11 12"
src="4c9f2621-e4f8-4ea1-946a-0b6869946858">

### Checklist

Delete any items that are not applicable to this PR.

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
This commit is contained in:
Marco Liberati 2023-10-17 13:33:56 +02:00 committed by GitHub
parent 24c008b4c5
commit d7b9a2ab71
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 119 additions and 33 deletions

View file

@ -114,6 +114,73 @@ describe('helpers', function () {
}, },
]); ]);
}); });
it('should return the correct array of warnings if multiple warnins are detected without line indicators', function () {
const warning =
'299 Elasticsearch-8.10.0-SNAPSHOT-adb9fce96079b421c2575f0d2d445f492eb5f075 "Field [geo.coordinates] cannot be retrieved, it is unsupported or not indexed; returning null.", 299 Elasticsearch-8.10.0-SNAPSHOT-adb9fce96079b421c2575f0d2d445f492eb5f075 "Field [ip_range] cannot be retrieved, it is unsupported or not indexed; returning null.", 299 Elasticsearch-8.10.0-SNAPSHOT-adb9fce96079b421c2575f0d2d445f492eb5f075 "Field [timestamp_range] cannot be retrieved, it is unsupported or not indexed; returning null."';
expect(parseWarning(warning)).toEqual([
{
endColumn: 10,
endLineNumber: 1,
message:
'Field [geo.coordinates] cannot be retrieved, it is unsupported or not indexed; returning null.',
severity: 8,
startColumn: 1,
startLineNumber: 1,
},
{
endColumn: 10,
endLineNumber: 1,
message:
'Field [ip_range] cannot be retrieved, it is unsupported or not indexed; returning null.',
severity: 8,
startColumn: 1,
startLineNumber: 1,
},
{
endColumn: 10,
endLineNumber: 1,
message:
'Field [timestamp_range] cannot be retrieved, it is unsupported or not indexed; returning null.',
severity: 8,
startColumn: 1,
startLineNumber: 1,
},
]);
});
it('should return the correct array of warnings if multiple warnins of different types', function () {
const warning =
'299 Elasticsearch-8.10.0-SNAPSHOT-adb9fce96079b421c2575f0d2d445f492eb5f075 "Field [geo.coordinates] cannot be retrieved, it is unsupported or not indexed; returning null.", 299 Elasticsearch-8.10.0-SNAPSHOT-adb9fce96079b421c2575f0d2d445f492eb5f075 "Field [ip_range] cannot be retrieved, it is unsupported or not indexed; returning null.", 299 Elasticsearch-8.10.0-SNAPSHOT-adb9fce96079b421c2575f0d2d445f492eb5f075 "Line 1:52: evaluation of [date_parse(geo.dest)] failed, treating result as null. Only first 20 failures recorded."';
expect(parseWarning(warning)).toEqual([
{
endColumn: 10,
endLineNumber: 1,
message:
'Field [geo.coordinates] cannot be retrieved, it is unsupported or not indexed; returning null.',
severity: 8,
startColumn: 1,
startLineNumber: 1,
},
{
endColumn: 10,
endLineNumber: 1,
message:
'Field [ip_range] cannot be retrieved, it is unsupported or not indexed; returning null.',
severity: 8,
startColumn: 1,
startLineNumber: 1,
},
{
endColumn: 138,
endLineNumber: 1,
message:
'evaluation of [date_parse(geo.dest)] failed, treating result as null. Only first 20 failures recorded.',
severity: 8,
startColumn: 52,
startLineNumber: 1,
},
]);
});
}); });
describe('getInlineEditorText', function () { describe('getInlineEditorText', function () {

View file

@ -43,41 +43,60 @@ export const useDebounceWithOptions = (
); );
}; };
const quotedWarningMessageRegexp = /"(.*?)"/g;
export const parseWarning = (warning: string): MonacoError[] => { export const parseWarning = (warning: string): MonacoError[] => {
if (warning.includes('Line')) { if (quotedWarningMessageRegexp.test(warning)) {
const splitByLine = warning.split('Line'); const matches = warning.match(quotedWarningMessageRegexp);
splitByLine.shift(); if (matches) {
return splitByLine.map((item) => { return matches.map((message) => {
const [lineNumber, startPosition, warningMessage] = item.split(':'); // start extracting the quoted message and with few default positioning
const [trimmedMessage] = warningMessage.split('"'); let warningMessage = message.replace(/"/g, '');
// initialize the length to 10 in case no error word found let startColumn = 1;
let errorLength = 10; let startLineNumber = 1;
const [_, wordWithError] = trimmedMessage.split('['); // initialize the length to 10 in case no error word found
if (wordWithError) { let errorLength = 10;
errorLength = wordWithError.length - 1; // if there's line number encoded in the message use it as new positioning
} // and replace the actual message without it
return { if (/Line (\d+):(\d+):/.test(warningMessage)) {
message: trimmedMessage.trimStart(), const [encodedLine, encodedColumn, innerMessage] = warningMessage.split(':');
startColumn: Number(startPosition), warningMessage = innerMessage;
startLineNumber: Number(lineNumber), if (!Number.isNaN(Number(encodedColumn))) {
endColumn: Number(startPosition) + errorLength, startColumn = Number(encodedColumn);
endLineNumber: Number(lineNumber), startLineNumber = Number(encodedLine.replace('Line ', ''));
severity: monaco.MarkerSeverity.Error, }
}; // extract the length of the "expression" within the message
}); // and try to guess the correct size for the editor marker to highlight
} else { if (/\[.*\]/.test(warningMessage)) {
// unknown warning message const [_, wordWithError] = warningMessage.split('[');
return [ if (wordWithError) {
{ errorLength = wordWithError.length;
message: warning, }
startColumn: 1, }
startLineNumber: 1, }
endColumn: 10,
endLineNumber: 1, return {
severity: monaco.MarkerSeverity.Error, message: warningMessage.trimStart(),
}, startColumn,
]; startLineNumber,
endColumn: startColumn + errorLength - 1,
endLineNumber: startLineNumber,
severity: monaco.MarkerSeverity.Error,
};
});
}
} }
// unknown warning message
return [
{
message: warning,
startColumn: 1,
startLineNumber: 1,
endColumn: 10,
endLineNumber: 1,
severity: monaco.MarkerSeverity.Error,
},
];
}; };
export const parseErrors = (errors: Error[], code: string): MonacoError[] => { export const parseErrors = (errors: Error[], code: string): MonacoError[] => {