diff --git a/packages/cspell-lib/src/Settings/InDocSettings.test.ts b/packages/cspell-lib/src/Settings/InDocSettings.test.ts index 0f23e7df14eb..51f88f05ae8e 100644 --- a/packages/cspell-lib/src/Settings/InDocSettings.test.ts +++ b/packages/cspell-lib/src/Settings/InDocSettings.test.ts @@ -2,6 +2,65 @@ import * as Text from '../util/text'; import * as TextRange from '../util/TextRange'; import * as InDoc from './InDocSettings'; +const oc = expect.objectContaining; + +// cSpell:ignore faullts straange +// cSpell:ignoreRegExp \w+s{4}\w+ +// cSpell:ignoreRegExp /\/\/\/.*/ +// cSpell:ignoreRegExp weird +const sampleCode = ` + // cSpell:enableCompoundWords + // cSpell:disableCompoundWords + // cSpell: enableCOMPOUNDWords + // cSpell:words whiteberry, redberry, lightbrown + // cSpell: ignoreRegExp /\\/\\/\\/.*/ + // cSpell:ignoreRegexp w\\w+berry + // cSpell::ignoreRegExp / + /* cSpell:ignoreRegExp \\w+s{4}\\w+ */ + /* cSpell:ignoreRegExp /faullts[/]?/ */ + const berries = ['whiteberry', 'redberry', 'blueberry']; + + /* cSpell:ignore tripe, comment */ + // cSpell:: ignoreWords tooo faullts + /// ignore triple comment, with misssspellings and faullts + /// mooree prooobleems onn thisss line tooo with wordberry + // misssspellings faullts + + // weirdberry can be straange. + // cSpell:language en-US + // cspell:local + // cspell:locale es-ES + // cspell:local en, nl + + // cspell:dictionaries lorem-ipsum + // LocalWords: one two three + // LocalWords:four five six + // localwords: seven eight nine +`; + +// cspell:ignore againxx +const sampleText = ` +# cSpell:disableCompoundWords +# cSpell:enableCOMPOUNDWords +# happydays arehere againxx +`; + +// cspell:ignore popoutlist +const sampleTextWithIncompleteInDocSetting = ` +// spell:dictionaries php +// spell:words const +// cspell: +// cspell:ignore popoutlist +const x = imp.popoutlist; +// cspell:ignore again +`; + +// cspell:disable +const sampleTextWithBadRegexp = ` +# cspell\x3AignoreRegExp "(foobar|foo_baz)"'); +`; +// cspell:enable + describe('Validate InDocSettings', () => { test('tests matching settings', () => { const matches = InDoc.internal @@ -11,48 +70,52 @@ describe('Validate InDocSettings', () => { expect(matches.map((a) => a[0])).toEqual([ 'enableCompoundWords', 'disableCompoundWords', - 'enableCOMPOUNDWords', + ' enableCOMPOUNDWords', 'words whiteberry, redberry, lightbrown', - 'ignoreRegExp /\\/\\/\\/.*/', + ' ignoreRegExp /\\/\\/\\/.*/', 'ignoreRegexp w\\w+berry', 'ignoreRegExp /', 'ignoreRegExp \\w+s{4}\\w+ */', 'ignoreRegExp /faullts[/]?/ */', 'ignore tripe, comment */', - 'ignoreWords tooo faullts', + ' ignoreWords tooo faullts', 'language en-US', 'local', 'locale es-ES', 'local en, nl', 'dictionaries lorem-ipsum', 'LocalWords: one two three', + 'LocalWords:four five six', ]); }); - test('tests extracting in file settings for compound words', () => { - expect(InDoc.getInDocumentSettings('')).toEqual({ id: 'in-doc-settings' }); - // 'cSpell:enableCompoundWords' - expect(InDoc.getInDocumentSettings('cSpell:enableCompoundWords').allowCompoundWords).toBe(true); - // 'cSpell:ENABLECompoundWords' - expect(InDoc.getInDocumentSettings('cSpell:ENABLECompoundWords').allowCompoundWords).toBe(true); - // 'cSpell:disableCompoundWords' - expect(InDoc.getInDocumentSettings('cSpell:disableCompoundWords').allowCompoundWords).toBe(false); - // 'cSpell:disableCompoundWORDS' - expect(InDoc.getInDocumentSettings('cSpell:disableCompoundWORDS').allowCompoundWords).toBe(false); - expect( - InDoc.getInDocumentSettings('cSpell:ENABLECompoundWords\ncSpell:disableCompoundWords').allowCompoundWords - ).toBe(false); - expect( - InDoc.getInDocumentSettings('cSpell:disableCompoundWords\ncSpell:enableCompoundWords').allowCompoundWords - ).toBe(true); - expect(InDoc.getInDocumentSettings(sampleText).allowCompoundWords).toBe(true); - expect(InDoc.getInDocumentSettings(sampleCode).allowCompoundWords).toBe(true); + test.each` + test | text | expected + ${'Empty Doc'} | ${''} | ${{ id: 'in-doc-settings' }} + ${'cSpell:enableCompoundWords'} | ${'cSpell:enableCompoundWords'} | ${oc({ allowCompoundWords: true })} + ${'cSpell:ENABLECompoundWords'} | ${'cSpell:ENABLECompoundWords'} | ${oc({ allowCompoundWords: true })} + ${'cSpell:disableCompoundWords'} | ${'cSpell:disableCompoundWords'} | ${oc({ allowCompoundWords: false })} + ${'cSpell:disableCompoundWORDS'} | ${'cSpell:disableCompoundWORDS'} | ${oc({ allowCompoundWords: false })} + ${'cSpell:ENABLECompoundWords\ncSpell:disableCompoundWords'} | ${'cSpell:ENABLECompoundWords\ncSpell:disableCompoundWords'} | ${oc({ allowCompoundWords: false })} + ${'cSpell:disableCompoundWords\ncSpell:enableCompoundWords'} | ${'cSpell:disableCompoundWords\ncSpell:enableCompoundWords'} | ${oc({ allowCompoundWords: true })} + ${'sampleText'} | ${sampleText} | ${oc({ allowCompoundWords: true })} + ${'sampleCode'} | ${sampleCode} | ${oc({ allowCompoundWords: true })} + `('detect compound words setting: $test', ({ text, expected }) => { + expect(InDoc.getInDocumentSettings(text)).toEqual(expected); + }); + + test.each` + test | text | expected + ${'Empty Doc'} | ${''} | ${{ id: 'in-doc-settings' }} + ${'sampleTextWithIncompleteInDocSetting'} | ${sampleTextWithIncompleteInDocSetting} | ${oc({ words: ['const'], ignoreWords: ['popoutlist', 'again'], dictionaries: ['php'] })} + `('extract setting: $test', ({ text, expected }) => { + expect(InDoc.getInDocumentSettings(text)).toEqual(expected); }); test('tests finding words to add to dictionary', () => { const words = InDoc.internal.getWordsFromDocument(sampleCode); // we match to the end of the line, so the */ is included. - expect(words).toEqual(['whiteberry', 'redberry', 'lightbrown', 'one', 'two', 'three']); + expect(words).toEqual(['whiteberry', 'redberry', 'lightbrown', 'one', 'two', 'three', 'four', 'five', 'six']); expect(InDoc.getIgnoreWordsFromDocument('Hello')).toEqual([]); }); @@ -74,7 +137,7 @@ describe('Validate InDocSettings', () => { test('fetching the local for the text', () => { const settings = InDoc.getInDocumentSettings(sampleCode); - expect(settings.language).toBe('en, nl'); + expect(settings.language).toBe('en,nl'); }); test('setting dictionaries for file', () => { @@ -91,52 +154,6 @@ describe('Validate InDocSettings', () => { ); }); }); -// cSpell:ignore faullts straange -// cSpell:ignoreRegExp \w+s{4}\w+ -// cSpell:ignoreRegExp /\/\/\/.*/ -// cSpell:ignoreRegExp weird -const sampleCode = ` - // cSpell:enableCompoundWords - // cSpell:disableCompoundWords - // cSpell: enableCOMPOUNDWords - // cSpell:words whiteberry, redberry, lightbrown - // cSpell: ignoreRegExp /\\/\\/\\/.*/ - // cSpell:ignoreRegexp w\\w+berry - // cSpell::ignoreRegExp / - /* cSpell:ignoreRegExp \\w+s{4}\\w+ */ - /* cSpell:ignoreRegExp /faullts[/]?/ */ - const berries = ['whiteberry', 'redberry', 'blueberry']; - - /* cSpell:ignore tripe, comment */ - // cSpell:: ignoreWords tooo faullts - /// ignore triple comment, with misssspellings and faullts - /// mooree prooobleems onn thisss line tooo with wordberry - // misssspellings faullts - - // weirdberry can be straange. - // cSpell:language en-US - // cspell:local - // cspell:locale es-ES - // cspell:local en, nl - - // cspell:dictionaries lorem-ipsum - // LocalWords: one two three - // LocalWords:four five six - // localwords: seven eight nine -`; - -// cspell:ignore againxx -const sampleText = ` -# cSpell:disableCompoundWords -# cSpell:enableCOMPOUNDWords -# happydays arehere againxx -`; - -// cspell:disable -const sampleTextWithBadRegexp = ` -# cspell\x3AignoreRegExp "(foobar|foo_baz)"'); -`; -// cspell:enable // cspell:disableCompoundWords // cspell:ignore localwords happydays arehere diff --git a/packages/cspell-lib/src/Settings/InDocSettings.ts b/packages/cspell-lib/src/Settings/InDocSettings.ts index 9c07099b6b87..7f435a84a168 100644 --- a/packages/cspell-lib/src/Settings/InDocSettings.ts +++ b/packages/cspell-lib/src/Settings/InDocSettings.ts @@ -5,7 +5,7 @@ import { mergeInDocSettings } from './CSpellSettingsServer'; // cspell:ignore gimuy const regExMatchRegEx = /\/.*\/[gimuy]*/; -const regExInFileSettings = [/(?:spell-?checker|cSpell)::?\s*(.*)/gi, /(LocalWords:?\s+.*)/g]; +const regExInFileSettings = [/(?:spell-?checker|c?spell)::?(.*)/gi, /(LocalWords:?.*)/g]; export type CSpellUserSettingsKeys = keyof CSpellUserSettings; @@ -22,17 +22,18 @@ export function getInDocumentSettings(text: string): CSpellUserSettings { } function parseSettingMatch(matchArray: RegExpMatchArray): CSpellUserSettings[] { - const [, possibleSetting = ''] = matchArray; + const [, match = ''] = matchArray; + const possibleSetting = match.trim(); const settingParsers: [RegExp, (m: string) => CSpellUserSettings][] = [ [/^(?:enable|disable)(?:allow)?CompoundWords/i, parseCompoundWords], [/^words?\s/i, parseWords], [/^ignore(?:words?)?\s/i, parseIgnoreWords], [/^ignore_?Reg_?Exp\s+.+$/i, parseIgnoreRegExp], [/^include_?Reg_?Exp\s+.+$/i, parseIncludeRegExp], - [/^locale?\s/i, parseLocal], - [/^language\s/i, parseLocal], + [/^locale?\s/i, parseLocale], + [/^language\s/i, parseLocale], [/^dictionaries\s/i, parseDictionaries], - [/^LocalWords:/, parseWords], + [/^LocalWords:/, (w) => parseWords(w.replace(/LocalWords:?/gi, ' '))], ]; return settingParsers @@ -51,9 +52,9 @@ function parseWords(match: string): CSpellUserSettings { return { id: 'in-doc-words', words }; } -function parseLocal(match: string): CSpellUserSettings { - const parts = match.trim().split(/\s+/); - const language = parts.slice(1).join(' '); +function parseLocale(match: string): CSpellUserSettings { + const parts = match.trim().split(/[\s,]+/); + const language = parts.slice(1).join(','); return language ? { id: 'in-doc-local', language } : {}; } diff --git a/packages/cspell-lib/src/Settings/LanguageSettings.test.ts b/packages/cspell-lib/src/Settings/LanguageSettings.test.ts index 2acc255330e0..dd88fb2cc49b 100644 --- a/packages/cspell-lib/src/Settings/LanguageSettings.test.ts +++ b/packages/cspell-lib/src/Settings/LanguageSettings.test.ts @@ -114,8 +114,19 @@ describe('Validate LanguageSettings', () => { expect(langSet).toContain('literate haskell'); }); - test('tests locale matching', () => { - const localeSet = LS.normalizeLocale('en, en-GB, fr-fr, nl_NL'); + // cspell:ignore engb frfr nlnl + test.each` + locales | expected + ${''} | ${[]} + ${'en, en-GB, fr-fr, nl_NL'} | ${['en', 'engb', 'frfr', 'nlnl']} + ${['en, en-GB', 'fr-fr, nl_NL']} | ${['en', 'engb', 'frfr', 'nlnl']} + `('normalizeLocale $locales', ({ locales, expected }) => { + const localeSet = LS.normalizeLocale(locales); + expect([...localeSet]).toEqual(expected); + }); + + test('normalizeLocale $locales', () => { + const localeSet = LS.normalizeLocale('en, en-GB, fr-fr,nl_NL'); expect(localeSet.has('en')).toBe(true); expect(LS.isLocaleInSet('nl-nl', localeSet)).toBe(true); expect(LS.isLocaleInSet('nl_nl', localeSet)).toBe(true); diff --git a/packages/cspell-lib/src/Settings/LanguageSettings.ts b/packages/cspell-lib/src/Settings/LanguageSettings.ts index 1de3bcbd57a2..156062f77a37 100644 --- a/packages/cspell-lib/src/Settings/LanguageSettings.ts +++ b/packages/cspell-lib/src/Settings/LanguageSettings.ts @@ -13,13 +13,20 @@ export function getDefaultLanguageSettings(): LanguageSettings { return defaultLanguageSettings; } +function localesToList(locales: string | string[]): string[] { + locales = typeof locales !== 'string' ? locales.join(',') : locales; + return stringToList(locales.replace(/\s+/g, ',')); +} + function stringToList(sList: string | string[]): string[] { - if (typeof sList === 'string') { - sList = sList - .replace(/[|;]/g, ',') - .split(',') - .map((s) => s.trim()); + if (typeof sList !== 'string') { + sList = sList.join(','); } + sList = sList + .replace(/[|;]/g, ',') + .split(',') + .map((s) => s.trim()) + .filter((s) => !!s); return sList; } @@ -33,7 +40,7 @@ function normalizeLanguageIdToString(langId: LanguageId | LanguageId[]): string } export function normalizeLocale(locale: LocaleId | LocaleId[]): Set { - locale = stringToList(locale); + locale = localesToList(locale); return new Set(locale.map((locale) => locale.toLowerCase().replace(/[^a-z]/g, ''))); }