From 27b0fa875b860af82037a49dcd53789cbfe18a27 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Wed, 30 Nov 2022 11:31:21 -0700 Subject: [PATCH] feat: Support preferred suggestions (#3885) To support AutoFix, it is necessary to distinguish which suggestions are preferred. Preferred suggestions are AutoFix candidates. --- packages/cspell-lib/api/api.d.ts | 32 +++++++----- packages/cspell-lib/src/Models/Suggestion.ts | 4 ++ .../cspell-lib/src/Models/ValidationIssue.ts | 7 +++ .../cspell-lib/src/Models/ValidationResult.ts | 7 +++ .../cspell-lib/src/Settings/InDocSettings.ts | 32 ++++++++++-- .../src/textValidation/ValidationTypes.ts | 9 +--- .../__snapshots__/validator.test.ts.snap | 51 +++++++++++++++++++ .../src/textValidation/checkText.ts | 3 +- .../src/textValidation/docValidator.test.ts | 2 +- .../src/textValidation/docValidator.ts | 23 +++++---- .../cspell-lib/src/textValidation/index.ts | 6 ++- .../textValidation/lineValidatorFactory.ts | 2 +- .../src/textValidation/parsedText.ts | 6 +-- .../src/textValidation/textValidator.ts | 11 ++-- .../src/textValidation/validator.test.ts | 13 +++-- .../src/textValidation/validator.ts | 25 +++++---- 16 files changed, 165 insertions(+), 68 deletions(-) create mode 100644 packages/cspell-lib/src/Models/Suggestion.ts create mode 100644 packages/cspell-lib/src/Models/ValidationIssue.ts create mode 100644 packages/cspell-lib/src/Models/ValidationResult.ts diff --git a/packages/cspell-lib/api/api.d.ts b/packages/cspell-lib/api/api.d.ts index 07a81f954d6..8a7d9479f3d 100644 --- a/packages/cspell-lib/api/api.d.ts +++ b/packages/cspell-lib/api/api.d.ts @@ -477,6 +477,22 @@ declare class ImportError extends Error { declare function combineTextAndLanguageSettings(settings: CSpellUserSettings, text: string, languageId: string | string[]): CSpellSettingsInternal; +interface ExtendedSuggestion { + word: string; + isPreferred?: boolean; +} + +interface ValidationResult extends TextOffset, Pick { + line: TextOffset; + isFlagged?: boolean | undefined; + isFound?: boolean | undefined; +} + +interface ValidationIssue extends ValidationResult { + suggestions?: string[]; + suggestionsEx?: ExtendedSuggestion[]; +} + interface MatchRange { startPos: number; endPos: number; @@ -496,11 +512,6 @@ interface IncludeExcludeOptions { ignoreRegExpList?: RegExp[]; includeRegExpList?: RegExp[]; } -interface ValidationResult extends TextOffset, Pick { - line: TextOffset; - isFlagged?: boolean | undefined; - isFound?: boolean | undefined; -} type LineValidatorFn = (line: LineSegment) => Iterable; interface LineSegment { line: TextOffsetRO; @@ -521,9 +532,9 @@ interface TextValidator { lineValidator: LineValidator; } -interface ValidationIssue extends ValidationResult { - suggestions?: string[]; -} +type Offset = number; +type SimpleRange = readonly [Offset, Offset]; + interface ValidateTextOptions { /** * Generate suggestions where there are spelling issues. @@ -544,9 +555,6 @@ interface ValidateTextOptions { */ declare function validateText(text: string, settings: CSpellUserSettings, options?: ValidateTextOptions): Promise; -type Offset = number; -type SimpleRange = readonly [Offset, Offset]; - interface DocumentValidatorOptions extends ValidateTextOptions { /** * Optional path to a configuration file. @@ -613,7 +621,7 @@ declare class DocumentValidator { private catchError; private errorCatcherWrapper; private _parse; - private suggest; + private getSuggestions; private genSuggestions; getFinalizedDocSettings(): CSpellSettingsInternal; /** diff --git a/packages/cspell-lib/src/Models/Suggestion.ts b/packages/cspell-lib/src/Models/Suggestion.ts new file mode 100644 index 00000000000..5aac46e164a --- /dev/null +++ b/packages/cspell-lib/src/Models/Suggestion.ts @@ -0,0 +1,4 @@ +export interface ExtendedSuggestion { + word: string; + isPreferred?: boolean; +} diff --git a/packages/cspell-lib/src/Models/ValidationIssue.ts b/packages/cspell-lib/src/Models/ValidationIssue.ts new file mode 100644 index 00000000000..c9882959c81 --- /dev/null +++ b/packages/cspell-lib/src/Models/ValidationIssue.ts @@ -0,0 +1,7 @@ +import type { ExtendedSuggestion } from './Suggestion'; +import type { ValidationResult } from './ValidationResult'; + +export interface ValidationIssue extends ValidationResult { + suggestions?: string[]; + suggestionsEx?: ExtendedSuggestion[]; +} diff --git a/packages/cspell-lib/src/Models/ValidationResult.ts b/packages/cspell-lib/src/Models/ValidationResult.ts new file mode 100644 index 00000000000..56801e4fc75 --- /dev/null +++ b/packages/cspell-lib/src/Models/ValidationResult.ts @@ -0,0 +1,7 @@ +import { TextOffset as TextOffsetRW, Issue } from '@cspell/cspell-types'; + +export interface ValidationResult extends TextOffsetRW, Pick { + line: TextOffsetRW; + isFlagged?: boolean | undefined; + isFound?: boolean | undefined; +} diff --git a/packages/cspell-lib/src/Settings/InDocSettings.ts b/packages/cspell-lib/src/Settings/InDocSettings.ts index 1422f55df5b..b31a3dfac05 100644 --- a/packages/cspell-lib/src/Settings/InDocSettings.ts +++ b/packages/cspell-lib/src/Settings/InDocSettings.ts @@ -1,6 +1,7 @@ import { opAppend, opFilter, opMap, pipeSync } from '@cspell/cspell-pipe/sync'; import type { CSpellUserSettings } from '@cspell/cspell-types'; import { genSequence, Sequence } from 'gensequence'; +import { ExtendedSuggestion } from '../Models/Suggestion'; import { getSpellDictInterface } from '../SpellingDictionary'; import * as Text from '../util/text'; import { clean, isDefined } from '../util/util'; @@ -66,6 +67,12 @@ const preferredDirectives = [ ]; const allDirectives = new Set(preferredDirectives.concat(officialDirectives)); +const allDirectiveSuggestions: ExtendedSuggestion[] = [ + ...pipeSync( + allDirectives, + opMap((word) => ({ word })) + ), +]; const dictInDocSettings = getSpellDictInterface().createSpellingDictionary( allDirectives, @@ -90,6 +97,7 @@ export interface DirectiveIssue { text: string; message: string; suggestions: string[]; + suggestionsEx: ExtendedSuggestion[]; } export function getInDocumentSettings(text: string): CSpellUserSettings { @@ -156,21 +164,37 @@ function parseSettingMatchValidation(matchArray: RegExpMatchArray): DirectiveIss // No matches were found, let make some suggestions. const dictSugs = dictInDocSettings .suggest(text, { ignoreCase: false }) - .map((sug) => sug.word) - .filter((a) => !noSuggestDirectives.has(a)); - const sugs = new Set(pipeSync(dictSugs, opAppend(allDirectives))); - const suggestions = [...sugs].slice(0, 8); + .map(({ word, isPreferred }) => (isPreferred ? { word, isPreferred } : { word })) + .filter((a) => !noSuggestDirectives.has(a.word)); + const sugs = pipeSync(dictSugs, opAppend(allDirectiveSuggestions), filterUniqueSuggestions); + const suggestionsEx = [...sugs].slice(0, 8); + const suggestions = suggestionsEx.map((s) => s.word); const issue: DirectiveIssue = { range: [start, end], text, message: issueMessages.unknownDirective, suggestions, + suggestionsEx, }; return issue; } +function* filterUniqueSuggestions(sugs: Iterable): Iterable { + const map = new Map(); + + for (const sug of sugs) { + const existing = map.get(sug.word); + if (existing) { + if (sug.isPreferred) { + existing.isPreferred = true; + } + } + yield sug; + } +} + function parseSettingMatch(matchArray: RegExpMatchArray): CSpellUserSettings[] { const [, match = ''] = matchArray; const possibleSetting = match.trim(); diff --git a/packages/cspell-lib/src/textValidation/ValidationTypes.ts b/packages/cspell-lib/src/textValidation/ValidationTypes.ts index 3ef63406c79..197847c56d8 100644 --- a/packages/cspell-lib/src/textValidation/ValidationTypes.ts +++ b/packages/cspell-lib/src/textValidation/ValidationTypes.ts @@ -1,4 +1,5 @@ -import { MappedText, TextOffset as TextOffsetRW, Issue } from '@cspell/cspell-types'; +import type { MappedText, TextOffset as TextOffsetRW } from '@cspell/cspell-types'; +import type { ValidationResult } from '../Models/ValidationResult'; export type TextOffsetRO = Readonly; @@ -29,12 +30,6 @@ export interface WordRangeAcc { rangePos: number; } -export interface ValidationResult extends TextOffsetRW, Pick { - line: TextOffsetRW; - isFlagged?: boolean | undefined; - isFound?: boolean | undefined; -} - export type ValidationResultRO = Readonly; export type LineValidatorFn = (line: LineSegment) => Iterable; diff --git a/packages/cspell-lib/src/textValidation/__snapshots__/validator.test.ts.snap b/packages/cspell-lib/src/textValidation/__snapshots__/validator.test.ts.snap index e70d4dda3da..478cc1a957f 100644 --- a/packages/cspell-lib/src/textValidation/__snapshots__/validator.test.ts.snap +++ b/packages/cspell-lib/src/textValidation/__snapshots__/validator.test.ts.snap @@ -18,6 +18,23 @@ exports[`Validator validateText with suggestions 1`] = ` "with", "Witt", ], + "suggestionsEx": [ + { + "word": "witty", + }, + { + "word": "witt", + }, + { + "word": "witch", + }, + { + "word": "with", + }, + { + "word": "Witt", + }, + ], "text": "witth", }, { @@ -36,6 +53,23 @@ exports[`Validator validateText with suggestions 1`] = ` "fe's", "feal", ], + "suggestionsEx": [ + { + "word": "few", + }, + { + "word": "fewer", + }, + { + "word": "few's", + }, + { + "word": "fe's", + }, + { + "word": "feal", + }, + ], "text": "feww", }, { @@ -54,6 +88,23 @@ exports[`Validator validateText with suggestions 1`] = ` "mistaker", "mistake's", ], + "suggestionsEx": [ + { + "word": "mistake", + }, + { + "word": "mistakes", + }, + { + "word": "mistaken", + }, + { + "word": "mistaker", + }, + { + "word": "mistake's", + }, + ], "text": "mistaks", }, ] diff --git a/packages/cspell-lib/src/textValidation/checkText.ts b/packages/cspell-lib/src/textValidation/checkText.ts index 9b1c06ad0e3..ca9fe82e260 100644 --- a/packages/cspell-lib/src/textValidation/checkText.ts +++ b/packages/cspell-lib/src/textValidation/checkText.ts @@ -1,13 +1,14 @@ import { CSpellUserSettings } from '@cspell/cspell-types'; import assert from 'assert'; import { isTextDocument, TextDocument } from '../Models/TextDocument'; +import type { ValidationIssue } from '../Models/ValidationIssue'; import * as Settings from '../Settings'; import { Document, resolveDocumentToTextDocument } from '../spellCheckFile'; import { MatchRange } from '../util/TextRange'; import { clean } from '../util/util'; import { DocumentValidator, DocumentValidatorOptions } from './docValidator'; import { calcTextInclusionRanges } from './textValidator'; -import { validateText, ValidationIssue } from './validator'; +import { validateText } from './validator'; /** * Annotate text with issues and include / exclude zones. diff --git a/packages/cspell-lib/src/textValidation/docValidator.test.ts b/packages/cspell-lib/src/textValidation/docValidator.test.ts index b2df05b84dd..949cd05a1cc 100644 --- a/packages/cspell-lib/src/textValidation/docValidator.test.ts +++ b/packages/cspell-lib/src/textValidation/docValidator.test.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import { createTextDocument, TextDocument } from '../Models/TextDocument'; import { AutoCache } from '../util/simpleCache'; import { DocumentValidator } from './docValidator'; -import { ValidationIssue } from './validator'; +import { ValidationIssue } from '../Models/ValidationIssue'; const docCache = new AutoCache(_loadDoc, 100); const fixturesDir = path.join(__dirname, '../../fixtures'); diff --git a/packages/cspell-lib/src/textValidation/docValidator.ts b/packages/cspell-lib/src/textValidation/docValidator.ts index f80c738cd91..bf1afc74d3c 100644 --- a/packages/cspell-lib/src/textValidation/docValidator.ts +++ b/packages/cspell-lib/src/textValidation/docValidator.ts @@ -10,13 +10,14 @@ import { import assert from 'assert'; import { GlobMatcher } from 'cspell-glob'; import { CSpellSettingsInternal, CSpellSettingsInternalFinalized } from '../Models/CSpellSettingsInternalDef'; +import { ExtendedSuggestion } from '../Models/Suggestion'; import { TextDocument, TextDocumentLine, updateTextDocument } from '../Models/TextDocument'; +import { ValidationIssue } from '../Models/ValidationIssue'; import { finalizeSettings, loadConfig, mergeSettings, searchForConfig } from '../Settings'; import { loadConfigSync, searchForConfigSync } from '../Settings/Controller/configLoader'; import { DirectiveIssue, validateInDocumentSettings } from '../Settings/InDocSettings'; import { getDictionaryInternal, getDictionaryInternalSync, SpellingDictionaryCollection } from '../SpellingDictionary'; import { toError } from '../util/errors'; -import { callOnce } from '../util/Memorizer'; import { AutoCache } from '../util/simpleCache'; import { MatchRange } from '../util/TextRange'; import { createTimer } from '../util/timer'; @@ -27,7 +28,7 @@ import { createMappedTextSegmenter, SimpleRange } from './parsedText'; import { calcTextInclusionRanges, defaultMaxDuplicateProblems, defaultMaxNumberOfProblems } from './textValidator'; import type { MappedTextValidationResult } from './ValidationTypes'; import { ValidationOptions } from './ValidationTypes'; -import { settingsToValidateOptions, ValidateTextOptions, ValidationIssue } from './validator'; +import { settingsToValidateOptions, ValidateTextOptions } from './validator'; export interface DocumentValidatorOptions extends ValidateTextOptions { /** @@ -252,8 +253,10 @@ export class DocumentValidator { const withSugs = issues.map((t) => { // lazy suggestion calculation. const text = t.text; - const suggestions = callOnce(() => this.suggest(text)); - return Object.defineProperty({ ...t }, 'suggestions', { enumerable: true, get: suggestions }); + const suggestionsEx = this.getSuggestions(text); + t.suggestionsEx = suggestionsEx; + t.suggestions = suggestionsEx.map((s) => s.word); + return t; }); return withSugs; @@ -299,11 +302,11 @@ export class DocumentValidator { const issueType = IssueType.directive; function toValidationIssue(dirIssue: DirectiveIssue): ValidationIssue { - const { text, range, suggestions, message } = dirIssue; + const { text, range, suggestions, suggestionsEx, message } = dirIssue; const offset = range[0]; const pos = document.positionAt(offset); const line = document.getLine(pos.line); - const issue: ValidationIssue = { text, offset, line, suggestions, message, issueType }; + const issue: ValidationIssue = { text, offset, line, suggestions, suggestionsEx, message, issueType }; return issue; } @@ -377,11 +380,11 @@ export class DocumentValidator { return parser.parse(this.document.text, this.document.uri.path).parsedTexts; } - private suggest(text: string) { + private getSuggestions(text: string): ExtendedSuggestion[] { return this._suggestions.get(text); } - private genSuggestions(text: string): string[] { + private genSuggestions(text: string): ExtendedSuggestion[] { assert(this._preparations, ERROR_NOT_PREPARED); const settings = this._preparations.docSettings; const dict = this._preparations.dictionary; @@ -393,7 +396,9 @@ export class DocumentValidator { timeout: settings.suggestionsTimeout, numChanges: settings.suggestionNumChanges, }); - return dict.suggest(text, sugOptions).map((r) => r.word); + return dict + .suggest(text, sugOptions) + .map(({ word, isPreferred }) => (isPreferred ? { word, isPreferred } : { word })); } public getFinalizedDocSettings(): CSpellSettingsInternal { diff --git a/packages/cspell-lib/src/textValidation/index.ts b/packages/cspell-lib/src/textValidation/index.ts index 0248c780286..042a2b68eeb 100644 --- a/packages/cspell-lib/src/textValidation/index.ts +++ b/packages/cspell-lib/src/textValidation/index.ts @@ -1,9 +1,11 @@ +export type { ValidationIssue } from '../Models/ValidationIssue'; +export type { ValidationResult } from '../Models/ValidationResult'; export { checkText, checkTextDocument, IncludeExcludeFlag } from './checkText'; export type { CheckTextInfo, TextInfoItem } from './checkText'; export { DocumentValidator } from './docValidator'; export type { DocumentValidatorOptions } from './docValidator'; export type { Offset, SimpleRange } from './parsedText'; export { calcTextInclusionRanges } from './textValidator'; -export type { CheckOptions, IncludeExcludeOptions, ValidationOptions, ValidationResult } from './ValidationTypes'; +export type { CheckOptions, IncludeExcludeOptions, ValidationOptions } from './ValidationTypes'; export { validateText } from './validator'; -export type { ValidateTextOptions, ValidationIssue } from './validator'; +export type { ValidateTextOptions } from './validator'; diff --git a/packages/cspell-lib/src/textValidation/lineValidatorFactory.ts b/packages/cspell-lib/src/textValidation/lineValidatorFactory.ts index 6f6922035d6..07955c492cc 100644 --- a/packages/cspell-lib/src/textValidation/lineValidatorFactory.ts +++ b/packages/cspell-lib/src/textValidation/lineValidatorFactory.ts @@ -2,6 +2,7 @@ import { opConcatMap, opFilter, opMap, pipe, toArray } from '@cspell/cspell-pipe import { ParsedText } from '@cspell/cspell-types'; import { CachingDictionary, createCachingDictionary, SearchOptions, SpellingDictionary } from 'cspell-dictionary'; import { genSequence, Sequence } from 'gensequence'; +import type { ValidationResult } from '../Models/ValidationResult'; import * as RxPat from '../Settings/RegExpPatterns'; import * as Text from '../util/text'; import { clean } from '../util/util'; @@ -16,7 +17,6 @@ import type { TextOffsetRO, TextValidatorFn, ValidationOptions, - ValidationResult, ValidationResultRO, } from './ValidationTypes'; diff --git a/packages/cspell-lib/src/textValidation/parsedText.ts b/packages/cspell-lib/src/textValidation/parsedText.ts index 3dc10a8e689..e575a5ab8b9 100644 --- a/packages/cspell-lib/src/textValidation/parsedText.ts +++ b/packages/cspell-lib/src/textValidation/parsedText.ts @@ -1,7 +1,7 @@ -import { TextOffset, MappedText } from '@cspell/cspell-types'; -import { ValidationIssue } from './validator'; -import * as TextRange from '../util/TextRange'; +import { MappedText, TextOffset } from '@cspell/cspell-types'; +import type { ValidationIssue } from '../Models/ValidationIssue'; import { extractTextMapRangeOrigin } from '../util/TextMap'; +import * as TextRange from '../util/TextRange'; export type Offset = number; diff --git a/packages/cspell-lib/src/textValidation/textValidator.ts b/packages/cspell-lib/src/textValidation/textValidator.ts index 21adb386268..c77755bb610 100644 --- a/packages/cspell-lib/src/textValidation/textValidator.ts +++ b/packages/cspell-lib/src/textValidation/textValidator.ts @@ -1,16 +1,11 @@ import { opConcatMap, opFilter, opTake, pipe } from '@cspell/cspell-pipe/sync'; -import { genSequence, Sequence } from 'gensequence'; import { SpellingDictionary } from 'cspell-dictionary'; +import { genSequence, Sequence } from 'gensequence'; +import type { ValidationResult } from '../Models/ValidationResult'; import * as Text from '../util/text'; import * as TextRange from '../util/TextRange'; import { lineValidatorFactory } from './lineValidatorFactory'; -import { - IncludeExcludeOptions, - LineSegment, - TextOffsetRO, - ValidationOptions, - ValidationResult, -} from './ValidationTypes'; +import type { IncludeExcludeOptions, LineSegment, TextOffsetRO, ValidationOptions } from './ValidationTypes'; export const defaultMaxNumberOfProblems = 200; export const defaultMaxDuplicateProblems = 5; diff --git a/packages/cspell-lib/src/textValidation/validator.test.ts b/packages/cspell-lib/src/textValidation/validator.test.ts index ed35a0c4904..d0e5bc0d8bd 100644 --- a/packages/cspell-lib/src/textValidation/validator.test.ts +++ b/packages/cspell-lib/src/textValidation/validator.test.ts @@ -1,5 +1,6 @@ import type { CSpellSettings } from '@cspell/cspell-types'; import { loremIpsum } from 'lorem-ipsum'; +import type { ValidationIssue } from '.'; import { mergeSettings } from '../Settings'; import { getDefaultSettings } from '../Settings/DefaultSettings'; import * as tds from '../Settings/TextDocumentSettings'; @@ -10,6 +11,8 @@ import * as Validator from './validator'; const ac = expect.arrayContaining; const notAc = expect.not.arrayContaining; +const oc = expect.objectContaining; + describe('Validator', () => { test('validates the validator', async () => { const text = 'The quick brouwn fox jumpped over the lazzy dog.'; @@ -228,14 +231,14 @@ const defaultSettings: CSpellSettings = { enabledLanguageIds: ['plaintext', 'javascript'], }; -function mValIssue(text: string, ...parts: Partial[]): Validator.ValidationIssue { - const issue: Partial = { +function mValIssue(text: string, ...parts: Partial[]): ValidationIssue { + const issue: Partial = { text, }; for (const p of parts) { Object.assign(issue, p); } - return oc(issue); + return oc(issue); } function sampleSettings() { @@ -245,7 +248,3 @@ function sampleSettings() { function getSettings(text: string, languageId: string) { return tds.combineTextAndLanguageSettings(defaultSettings, text, languageId); } - -function oc(t: Partial): T { - return expect.objectContaining(t); -} diff --git a/packages/cspell-lib/src/textValidation/validator.ts b/packages/cspell-lib/src/textValidation/validator.ts index 20d0a493c30..011d10ab38d 100644 --- a/packages/cspell-lib/src/textValidation/validator.ts +++ b/packages/cspell-lib/src/textValidation/validator.ts @@ -1,20 +1,16 @@ import { CSpellUserSettings, IssueType } from '@cspell/cspell-types'; import { CSpellSettingsInternalFinalized } from '../Models/CSpellSettingsInternalDef'; import { createTextDocument } from '../Models/TextDocument'; +import type { ValidationIssue } from '../Models/ValidationIssue'; import * as Settings from '../Settings'; import { DirectiveIssue, validateInDocumentSettings } from '../Settings/InDocSettings'; import { CompoundWordsMethod, getDictionaryInternal } from '../SpellingDictionary'; -import { callOnce } from '../util/Memorizer'; import { clean } from '../util/util'; import { validateText as validateFullText } from './textValidator'; -import type { ValidationOptions, ValidationResult } from './ValidationTypes'; +import type { ValidationOptions } from './ValidationTypes'; export const diagSource = 'cSpell Checker'; -export interface ValidationIssue extends ValidationResult { - suggestions?: string[]; -} - export interface ValidateTextOptions { /** * Generate suggestions where there are spelling issues. @@ -47,7 +43,7 @@ export async function validateText( options.validateDirectives || finalSettings.validateDirectives ? validateInDocumentSettings(text, settings) : []; - const issues = spellingIssues.concat(mapValidationIssues(text, validationIssues)); + const issues: ValidationIssue[] = spellingIssues.concat(mapValidationIssues(text, validationIssues)); if (!options.generateSuggestions) { return issues; } @@ -61,15 +57,18 @@ export async function validateText( }); const withSugs = issues.map((t) => { const text = t.text; - // lazy suggestion calculation. - const suggestions = callOnce(() => dict.suggest(text, sugOptions).map((r) => r.word)); - return Object.defineProperty({ ...t }, 'suggestions', { enumerable: true, get: suggestions }); + const suggestionsEx = dict + .suggest(text, sugOptions) + .map(({ word, isPreferred }) => (isPreferred ? { word, isPreferred } : { word })); + t.suggestions = suggestionsEx.map((s) => s.word); + t.suggestionsEx = suggestionsEx; + return t; }); return withSugs; } -function mapValidationIssues(text: string, valIssues: Iterable): ValidationResult[] { +function mapValidationIssues(text: string, valIssues: Iterable): ValidationIssue[] { const issues = [...valIssues]; if (!issues.length) return []; @@ -77,11 +76,11 @@ function mapValidationIssues(text: string, valIssues: Iterable): const issueType = IssueType.directive; function toValidationIssue(dirIssue: DirectiveIssue): ValidationIssue { - const { text, range, suggestions, message } = dirIssue; + const { text, range, suggestions, suggestionsEx, message } = dirIssue; const offset = range[0]; const pos = document.positionAt(offset); const line = document.getLine(pos.line); - const issue: ValidationIssue = { text, offset, line, suggestions, message, issueType }; + const issue: ValidationIssue = { text, offset, line, suggestions, suggestionsEx, message, issueType }; return issue; }