From 561e8f076b2e77a02f170e48bdfb8482e7f02e7c Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Sat, 25 Nov 2023 15:04:31 -0700 Subject: [PATCH 1/9] fix: Improve fetching config --- .../src/worker/spellCheck.mts | 2 +- packages/cspell-lib/api/api.d.ts | 29 +++++- .../Controller/configLoader/configLoader.ts | 37 ++++++-- .../src/lib/__snapshots__/index.test.ts.snap | 1 + packages/cspell-lib/src/lib/index.ts | 2 + packages/cspell-lib/src/lib/perf/README.md | 5 ++ packages/cspell-lib/src/lib/perf/index.ts | 2 + packages/cspell-lib/src/lib/perf/perf.ts | 31 +++++++ .../cspell-lib/src/lib/perf/timer.test.ts | 30 +++++++ packages/cspell-lib/src/lib/perf/timer.ts | 57 ++++++++++++ packages/cspell-lib/src/lib/spellCheckFile.ts | 43 ++++++++- .../lib/textValidation/ValidateTextOptions.ts | 5 ++ .../src/lib/textValidation/docValidator.ts | 90 ++++++++++++++----- .../cspell-lib/src/lib/util/debugPerf.test.ts | 19 ---- packages/cspell-lib/src/lib/util/debugPerf.ts | 23 ----- .../cspell-lib/src/lib/util/timer.test.ts | 47 ---------- packages/cspell-lib/src/lib/util/timer.ts | 80 ----------------- .../src/app/__snapshots__/app.test.ts.snap | 4 +- packages/cspell/src/app/commandLint.ts | 37 ++++---- packages/cspell/src/app/lint/lint.ts | 30 +++++-- packages/cspell/src/app/options.ts | 4 + packages/cspell/src/app/util/fileHelper.ts | 4 + packages/cspell/src/app/util/timer.ts | 18 ++-- packages/cspell/tsconfig.esm.json | 2 + packages/cspell/tsconfig.json | 2 +- 25 files changed, 367 insertions(+), 237 deletions(-) create mode 100644 packages/cspell-lib/src/lib/perf/README.md create mode 100644 packages/cspell-lib/src/lib/perf/index.ts create mode 100644 packages/cspell-lib/src/lib/perf/perf.ts create mode 100644 packages/cspell-lib/src/lib/perf/timer.test.ts create mode 100644 packages/cspell-lib/src/lib/perf/timer.ts delete mode 100644 packages/cspell-lib/src/lib/util/debugPerf.test.ts delete mode 100644 packages/cspell-lib/src/lib/util/debugPerf.ts delete mode 100644 packages/cspell-lib/src/lib/util/timer.test.ts delete mode 100644 packages/cspell-lib/src/lib/util/timer.ts diff --git a/packages/cspell-eslint-plugin/src/worker/spellCheck.mts b/packages/cspell-eslint-plugin/src/worker/spellCheck.mts index 91c6a9e2db2..67af6f94e22 100644 --- a/packages/cspell-eslint-plugin/src/worker/spellCheck.mts +++ b/packages/cspell-eslint-plugin/src/worker/spellCheck.mts @@ -351,7 +351,7 @@ function getDocValidator(filename: string, text: string, options: WorkerOptions) const cachedValidator = docValCache.get(doc); if (cachedValidator && deepEqual(cachedValidator.settings, settings)) { refreshDictionaryCache(0); - cachedValidator.updateDocumentText(text); + cachedValidator.updateDocumentText(text).catch(() => undefined); return cachedValidator; } diff --git a/packages/cspell-lib/api/api.d.ts b/packages/cspell-lib/api/api.d.ts index 539adeeae58..115effc4411 100644 --- a/packages/cspell-lib/api/api.d.ts +++ b/packages/cspell-lib/api/api.d.ts @@ -636,6 +636,11 @@ interface ValidateTextOptions { * Verify that the in-document directives are correct. */ validateDirectives?: boolean; + /** + * Skips spell checking the document. Useful for testing and dry runs. + * It will read the configuration and parse the document. + */ + skipValidation?: boolean; } interface DocumentValidatorOptions extends ValidateTextOptions { @@ -654,6 +659,7 @@ interface DocumentValidatorOptions extends ValidateTextOptions { */ noConfigSearch?: boolean; } +type PerfTimings = Record; declare class DocumentValidator { readonly settings: CSpellUserSettings; private _document; @@ -664,6 +670,8 @@ declare class DocumentValidator { private _preparationTime; private _suggestions; readonly options: DocumentValidatorOptions; + readonly perfTiming: PerfTimings; + skipValidation: boolean; /** * @param doc - Document to validate * @param config - configuration to use (not finalized). @@ -717,6 +725,8 @@ declare class DocumentValidator { * Internal `cspell-lib` use. */ _getPreparations(): Preparations | undefined; + private static getGlobMatcher; + private static _getGlobMatcher; } interface Preparations { /** loaded config */ @@ -800,6 +810,12 @@ interface SpellCheckFileOptions extends ValidateTextOptions { */ noConfigSearch?: boolean; } +interface SpellCheckFilePerf extends Record { + loadTimeMs?: number; + prepareTimeMs?: number; + checkTimeMs?: number; + totalTimeMs?: number; +} interface SpellCheckFileResult { document: Document | DocumentWithText; settingsUsed: CSpellSettingsWithSourceTrace; @@ -808,6 +824,7 @@ interface SpellCheckFileResult { issues: ValidationIssue[]; checked: boolean; errors: Error[] | undefined; + perf?: SpellCheckFilePerf; } /** * Spell Check a file @@ -902,4 +919,14 @@ declare function clearCachedFiles(): Promise; */ declare function getDictionary(settings: CSpellUserSettings): Promise; -export { type CheckTextInfo, type ConfigurationDependencies, type CreateTextDocumentParams, type DetermineFinalDocumentSettingsResult, type Document, DocumentValidator, type DocumentValidatorOptions, ENV_CSPELL_GLOB_ROOT, type ExcludeFilesGlobMap, type ExclusionFunction, exclusionHelper_d as ExclusionHelper, type FeatureFlag, FeatureFlags, ImportError, type ImportFileRefWithError, IncludeExcludeFlag, type IncludeExcludeOptions, index_link_d as Link, type Logger, type SpellCheckFileOptions, type SpellCheckFileResult, SpellingDictionaryLoadError, type SuggestedWord, SuggestionError, type SuggestionOptions, type SuggestionsForWordResult, text_d as Text, type TextDocument, type TextDocumentLine, type TextDocumentRef, type TextInfoItem, type TraceOptions, type TraceResult, UnknownFeatureFlagError, type ValidationIssue, calcOverrideSettings, checkFilenameMatchesGlob, checkText, checkTextDocument, clearCachedFiles, clearCachedSettingsFiles, combineTextAndLanguageSettings, combineTextAndLanguageSettings as constructSettingsForText, createTextDocument, currentSettingsFileVersion, defaultConfigFilenames, defaultFileName, defaultFileName as defaultSettingsFilename, determineFinalDocumentSettings, extractDependencies, extractImportErrors, fileToDocument, fileToTextDocument, finalizeSettings, getCachedFileSize, getDefaultBundledSettingsAsync, getDefaultSettings, getDictionary, getGlobalSettings, getLanguagesForBasename as getLanguageIdsForBaseFilename, getLanguagesForExt, getLogger, getSources, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, loadConfig, loadPnP, loadPnPSync, mergeInDocSettings, mergeSettings, readRawSettings, readSettings, readSettingsFiles, refreshDictionaryCache, resolveFile, searchForConfig, sectionCSpell, setLogger, shouldCheckDocument, spellCheckDocument, spellCheckFile, suggestionsForWord, suggestionsForWords, traceWords, traceWordsAsync, updateTextDocument, validateText }; +interface PerfTimer { + readonly name: string; + readonly startTime: number; + readonly elapsed: number; + start(): void; + end(): void; +} +type TimeNowFn = () => number; +declare function createPerfTimer(name: string, onEnd?: (elapsed: number, name: string) => void, timeNowFn?: TimeNowFn): PerfTimer; + +export { type CheckTextInfo, type ConfigurationDependencies, type CreateTextDocumentParams, type DetermineFinalDocumentSettingsResult, type Document, DocumentValidator, type DocumentValidatorOptions, ENV_CSPELL_GLOB_ROOT, type ExcludeFilesGlobMap, type ExclusionFunction, exclusionHelper_d as ExclusionHelper, type FeatureFlag, FeatureFlags, ImportError, type ImportFileRefWithError, IncludeExcludeFlag, type IncludeExcludeOptions, index_link_d as Link, type Logger, type PerfTimer, type SpellCheckFileOptions, type SpellCheckFileResult, SpellingDictionaryLoadError, type SuggestedWord, SuggestionError, type SuggestionOptions, type SuggestionsForWordResult, text_d as Text, type TextDocument, type TextDocumentLine, type TextDocumentRef, type TextInfoItem, type TraceOptions, type TraceResult, UnknownFeatureFlagError, type ValidationIssue, calcOverrideSettings, checkFilenameMatchesGlob, checkText, checkTextDocument, clearCachedFiles, clearCachedSettingsFiles, combineTextAndLanguageSettings, combineTextAndLanguageSettings as constructSettingsForText, createPerfTimer, createTextDocument, currentSettingsFileVersion, defaultConfigFilenames, defaultFileName, defaultFileName as defaultSettingsFilename, determineFinalDocumentSettings, extractDependencies, extractImportErrors, fileToDocument, fileToTextDocument, finalizeSettings, getCachedFileSize, getDefaultBundledSettingsAsync, getDefaultSettings, getDictionary, getGlobalSettings, getLanguagesForBasename as getLanguageIdsForBaseFilename, getLanguagesForExt, getLogger, getSources, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, loadConfig, loadPnP, loadPnPSync, mergeInDocSettings, mergeSettings, readRawSettings, readSettings, readSettingsFiles, refreshDictionaryCache, resolveFile, searchForConfig, sectionCSpell, setLogger, shouldCheckDocument, spellCheckDocument, spellCheckFile, suggestionsForWord, suggestionsForWords, traceWords, traceWordsAsync, updateTextDocument, validateText }; diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts index 522640f3cca..10e20ccc458 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts @@ -40,6 +40,7 @@ import { import type { PnPSettingsOptional } from './PnPSettings.js'; import { defaultPnPSettings, normalizePnPSettings } from './PnPSettings.js'; import type { CSpellSettingsI, CSpellSettingsWST } from './types.js'; +import { c } from 'vitest/dist/reporters-5f784f42.js'; type CSpellSettingsVersion = Exclude; const supportedCSpellConfigVersions: CSpellSettingsVersion[] = [configSettingsFileVersion0_2]; @@ -70,6 +71,13 @@ interface ImportedConfigEntry { let defaultConfigLoader: ConfigLoaderInternal | undefined = undefined; +interface CacheMergeConfigFileWithImports { + // cfgFile: CSpellConfigFile; + pnpSettings: PnPSettingsOptional | undefined; + referencedBy: string[] | undefined; + result: Promise; +} + export class ConfigLoader { public onReady: Promise; @@ -88,6 +96,7 @@ export class ConfigLoader { protected cachedConfig = new Map(); protected cachedConfigFiles = new Map(); protected cachedPendingConfigFile = new AutoResolveCache>(); + protected cachedMergedConfig = new WeakMap(); protected globalSettings: CSpellSettingsI | undefined; protected cspellConfigFileReaderWriter: CSpellConfigFileReaderWriter; protected configSearch = new ConfigSearch(searchPlaces); @@ -163,7 +172,7 @@ export class ConfigLoader { public async getGlobalSettingsAsync(): Promise { if (!this.globalSettings) { const globalConfFile = await getGlobalConfig(); - const normalized = await this.mergeConfigFileWithImports(globalConfFile, {}); + const normalized = await this.mergeConfigFileWithImports(globalConfFile, undefined); normalized.id ??= 'global_config'; this.globalSettings = normalized; } @@ -177,11 +186,12 @@ export class ConfigLoader { this.configSearch.clearCache(); this.cachedPendingConfigFile.clear(); this.cspellConfigFileReaderWriter.clearCachedFiles(); + this.cachedMergedConfig = new WeakMap(); } protected importSettings( fileRef: ImportFileRef, - pnpSettings: PnPSettingsOptional, + pnpSettings: PnPSettingsOptional | undefined, backReferences: string[], ): ImportedConfigEntry { const url = this.cspellIO.toFileURL(fileRef.filename); @@ -264,7 +274,8 @@ export class ConfigLoader { } } - private async setupPnp(cfgFile: CSpellConfigFile, pnpSettings: PnPSettingsOptional) { + private async setupPnp(cfgFile: CSpellConfigFile, pnpSettings: PnPSettingsOptional | undefined) { + if (!pnpSettings?.usePnP || pnpSettings === defaultPnPSettings) return; if (cfgFile.url.protocol !== 'file:') return; // Try to load any .pnp files before reading dictionaries or other config files. @@ -274,9 +285,25 @@ export class ConfigLoader { loadPnPSync(pnpSettingsToUse, pathToSettingsDir); } - public async mergeConfigFileWithImports( + public mergeConfigFileWithImports( + cfgFile: CSpellConfigFile, + pnpSettings: PnPSettingsOptional | undefined, + referencedBy?: string[] | undefined, + ): Promise { + const cached = this.cachedMergedConfig.get(cfgFile); + if (cached && cached.pnpSettings === pnpSettings && cached.referencedBy === referencedBy) { + return cached.result; + } + // console.warn('missing cache %o', cfgFile.url.href); + + const result = this._mergeConfigFileWithImports(cfgFile, pnpSettings, referencedBy); + this.cachedMergedConfig.set(cfgFile, { pnpSettings, referencedBy, result }); + return result; + } + + private async _mergeConfigFileWithImports( cfgFile: CSpellConfigFile, - pnpSettings: PnPSettingsOptional, + pnpSettings: PnPSettingsOptional | undefined, referencedBy: string[] = [], ): Promise { await this.setupPnp(cfgFile, pnpSettings); diff --git a/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap b/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap index 292370beb21..70e49321685 100644 --- a/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap +++ b/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap @@ -151,6 +151,7 @@ exports[`Validate the cspell API > Verify API exports 1`] = ` "clearCachedSettingsFiles": [Function], "combineTextAndLanguageSettings": [Function], "constructSettingsForText": [Function], + "createPerfTimer": [Function], "createSpellingDictionary": [Function], "createSpellingDictionaryCollection": [Function], "createTextDocument": [Function], diff --git a/packages/cspell-lib/src/lib/index.ts b/packages/cspell-lib/src/lib/index.ts index e7574033b6d..db382e67518 100644 --- a/packages/cspell-lib/src/lib/index.ts +++ b/packages/cspell-lib/src/lib/index.ts @@ -100,3 +100,5 @@ export { Link, Text }; export { ExclusionHelper }; export { clearCachedFiles } from './clearCachedFiles.js'; export { getDictionary } from './getDictionary.js'; +export type { PerfTimer } from './perf/index.js'; +export { createPerfTimer } from './perf/index.js'; diff --git a/packages/cspell-lib/src/lib/perf/README.md b/packages/cspell-lib/src/lib/perf/README.md new file mode 100644 index 00000000000..6538cfc3f93 --- /dev/null +++ b/packages/cspell-lib/src/lib/perf/README.md @@ -0,0 +1,5 @@ +# CSpell Performance Measurement + +This is a library of methods used to measure performance within CSpell. + +It uses the standard [Performance API - Web APIs](https://developer.mozilla.org/en-US/docs/Web/API/Performance_API) diff --git a/packages/cspell-lib/src/lib/perf/index.ts b/packages/cspell-lib/src/lib/perf/index.ts new file mode 100644 index 00000000000..2264018ba1b --- /dev/null +++ b/packages/cspell-lib/src/lib/perf/index.ts @@ -0,0 +1,2 @@ +export type { PerfTimer } from './timer.js'; +export { createPerfTimer } from './timer.js'; diff --git a/packages/cspell-lib/src/lib/perf/perf.ts b/packages/cspell-lib/src/lib/perf/perf.ts new file mode 100644 index 00000000000..9b92ff8b027 --- /dev/null +++ b/packages/cspell-lib/src/lib/perf/perf.ts @@ -0,0 +1,31 @@ +class PerfMonitor { + private _enabled = false; + + constructor(private _performance: Performance = performance) {} + + mark(name: string) { + this._enabled && this._performance.mark(name); + } + + measure(name: string, startMark: string, endMark: string) { + this._enabled && this._performance.measure(name, startMark, endMark); + } + + clearMarks(name?: string) { + this._enabled && this._performance.clearMarks(name); + } + + clearMeasures(name?: string) { + this._enabled && this._performance.clearMeasures(name); + } + + get enabled() { + return this._enabled; + } + + set enabled(value: boolean) { + this._enabled = value; + } +} + +export const perf = new PerfMonitor(); diff --git a/packages/cspell-lib/src/lib/perf/timer.test.ts b/packages/cspell-lib/src/lib/perf/timer.test.ts new file mode 100644 index 00000000000..bd17f4ca5f7 --- /dev/null +++ b/packages/cspell-lib/src/lib/perf/timer.test.ts @@ -0,0 +1,30 @@ +import { promisify } from 'util'; +import { describe, expect, test, vi } from 'vitest'; + +import { createPerfTimer } from './timer.js'; + +const delay = promisify(setTimeout); + +describe('timer', () => { + test('createTimer', async () => { + const t = createPerfTimer('test'); + await delay(12); + expect(t.elapsed).toBeGreaterThan(10); + }); + + test('createTimer with onEnd', async () => { + const onEnd = vi.fn(); + const timer = createPerfTimer('test', onEnd); + const v0 = timer.elapsed; + await delay(12); + const v2 = timer.elapsed; + expect(v2).toBeGreaterThan(v0); + timer.end(); + const v3 = timer.elapsed; + expect(onEnd).toHaveBeenCalledOnce(); + timer.end(); + expect(onEnd).toHaveBeenCalledOnce(); + await delay(12); + expect(timer.elapsed).toBe(v3); + }); +}); diff --git a/packages/cspell-lib/src/lib/perf/timer.ts b/packages/cspell-lib/src/lib/perf/timer.ts new file mode 100644 index 00000000000..4cbb0f54d84 --- /dev/null +++ b/packages/cspell-lib/src/lib/perf/timer.ts @@ -0,0 +1,57 @@ +// Symbol.dispose ??= Symbol('Symbol.dispose'); +// Symbol.asyncDispose ??= Symbol('Symbol.asyncDispose'); + +export interface PerfTimer /* extends Disposable */ { + readonly name: string; + readonly startTime: number; + readonly elapsed: number; + start(): void; + end(): void; +} + +type TimeNowFn = () => number; + +export function createPerfTimer( + name: string, + onEnd?: (elapsed: number, name: string) => void, + timeNowFn?: TimeNowFn, +): PerfTimer { + return new SimpleTimer(name, onEnd, timeNowFn); +} + +class SimpleTimer implements PerfTimer { + private _start = performance.now(); + private _elapsed: number | undefined = undefined; + private _running = true; + + constructor( + readonly name: string, + readonly onEnd?: (elapsed: number, name: string) => void, + readonly timeNowFn = performance.now, + ) {} + + get startTime() { + return this._start; + } + + get elapsed() { + return this._elapsed ?? performance.now() - this._start; + } + + end() { + if (!this._running) return; + this._running = false; + const end = performance.now(); + this._elapsed = end - this._start; + this.onEnd?.(this._elapsed, this.name); + } + + start() { + this._start = performance.now(); + this._running = true; + } + + // [Symbol.dispose]() { + // this.end(); + // } +} diff --git a/packages/cspell-lib/src/lib/spellCheckFile.ts b/packages/cspell-lib/src/lib/spellCheckFile.ts index ae4853b2163..a1dad862932 100644 --- a/packages/cspell-lib/src/lib/spellCheckFile.ts +++ b/packages/cspell-lib/src/lib/spellCheckFile.ts @@ -4,6 +4,7 @@ import type { Document, DocumentWithText } from './Document/index.js'; import { isBinaryDoc } from './Document/isBinaryDoc.js'; import { documentToTextDocument, resolveDocument } from './Document/resolveDocument.js'; import { createTextDocument } from './Models/TextDocument.js'; +import { createPerfTimer } from './perf/index.js'; import { determineTextDocumentSettings } from './textValidation/determineTextDocumentSettings.js'; import type { DocumentValidatorOptions } from './textValidation/index.js'; import { DocumentValidator } from './textValidation/index.js'; @@ -34,6 +35,13 @@ export interface SpellCheckFileOptions extends ValidateTextOptions { noConfigSearch?: boolean; } +export interface SpellCheckFilePerf extends Record { + loadTimeMs?: number; + prepareTimeMs?: number; + checkTimeMs?: number; + totalTimeMs?: number; +} + export interface SpellCheckFileResult { document: Document | DocumentWithText; settingsUsed: CSpellSettingsWithSourceTrace; @@ -42,6 +50,7 @@ export interface SpellCheckFileResult { issues: ValidationIssue[]; checked: boolean; errors: Error[] | undefined; + perf?: SpellCheckFilePerf; } /** @@ -84,7 +93,13 @@ export async function spellCheckDocument( }; } try { - return spellCheckFullDocument(await resolveDocument(document), options, settings); + const timer = createPerfTimer('loadFile'); + const doc = await resolveDocument(document).finally(() => timer.end()); + const result = await spellCheckFullDocument(doc, options, settings); + const perf = result.perf || {}; + perf.loadTimeMs = timer.elapsed; + result.perf = perf; + return result; } catch (e) { const errors = isError(e) ? [e] : []; return { @@ -104,10 +119,28 @@ async function spellCheckFullDocument( options: SpellCheckFileOptions, settings: CSpellUserSettings, ): Promise { + // if (options.skipValidation) { + // return { + // document, + // options, + // settingsUsed: settings, + // localConfigFilepath: undefined, + // issues: [], + // checked: true, + // errors: undefined, + // }; + // } + + const perf: SpellCheckFilePerf = {}; + const timer = createPerfTimer('spellCheckFullDocument', (elapsed) => (perf.totalTimeMs = elapsed)); + const timerCheck = createPerfTimer('check', (elapsed) => (perf.checkTimeMs = elapsed)); + const timerPrepare = createPerfTimer('prepare', (elapsed) => (perf.prepareTimeMs = elapsed)); + const doc = documentToTextDocument(document); const docValOptions: DocumentValidatorOptions = options; const docValidator = new DocumentValidator(doc, docValOptions, settings); - await docValidator.prepare(); + await docValidator.prepare().finally(() => timerPrepare.end()); + Object.assign(perf, Object.fromEntries(Object.entries(docValidator.perfTiming).map(([k, v]) => ['_' + k, v]))); const prep = docValidator._getPreparations(); @@ -120,10 +153,13 @@ async function spellCheckFullDocument( issues: [], checked: false, errors: docValidator.errors, + perf, }; } + timerCheck.start(); const issues = docValidator.checkDocument(); + timerCheck.end(); const result: SpellCheckFileResult = { document, @@ -133,8 +169,9 @@ async function spellCheckFullDocument( issues, checked: docValidator.shouldCheckDocument(), errors: undefined, + perf, }; - + timer.end(); return result; } diff --git a/packages/cspell-lib/src/lib/textValidation/ValidateTextOptions.ts b/packages/cspell-lib/src/lib/textValidation/ValidateTextOptions.ts index 121b4424da8..a14c2cd6de6 100644 --- a/packages/cspell-lib/src/lib/textValidation/ValidateTextOptions.ts +++ b/packages/cspell-lib/src/lib/textValidation/ValidateTextOptions.ts @@ -13,4 +13,9 @@ export interface ValidateTextOptions { * Verify that the in-document directives are correct. */ validateDirectives?: boolean; + /** + * Skips spell checking the document. Useful for testing and dry runs. + * It will read the configuration and parse the document. + */ + skipValidation?: boolean; } diff --git a/packages/cspell-lib/src/lib/textValidation/docValidator.ts b/packages/cspell-lib/src/lib/textValidation/docValidator.ts index 2d519c49f1d..1217a5125c5 100644 --- a/packages/cspell-lib/src/lib/textValidation/docValidator.ts +++ b/packages/cspell-lib/src/lib/textValidation/docValidator.ts @@ -2,6 +2,7 @@ import { opConcatMap, opMap, pipeSync } from '@cspell/cspell-pipe/sync'; import type { CSpellSettingsWithSourceTrace, CSpellUserSettings, + Glob, MappedText, ParsedText, PnPSettings, @@ -16,6 +17,7 @@ import type { ExtendedSuggestion } from '../Models/Suggestion.js'; import type { TextDocument, TextDocumentLine, TextDocumentRef } from '../Models/TextDocument.js'; import { updateTextDocument } from '../Models/TextDocument.js'; import type { ValidationIssue } from '../Models/ValidationIssue.js'; +import { createPerfTimer } from '../perf/index.js'; import { finalizeSettings, loadConfig, mergeSettings, searchForConfig } from '../Settings/index.js'; import type { DirectiveIssue } from '../Settings/InDocSettings.js'; import { validateInDocumentSettings } from '../Settings/InDocSettings.js'; @@ -24,9 +26,9 @@ import { getDictionaryInternal, getDictionaryInternalSync } from '../SpellingDic import type { WordSuggestion } from '../suggestions.js'; import { calcSuggestionAdjustedToToMatchCase } from '../suggestions.js'; import { catchPromiseError, toError } from '../util/errors.js'; +import { memorizeLastCall } from '../util/memorizeLastCall.js'; import { AutoCache } from '../util/simpleCache.js'; import type { MatchRange } from '../util/TextRange.js'; -import { createTimer } from '../util/timer.js'; import { uriToFilePath } from '../util/Uri.js'; import { defaultMaxDuplicateProblems, defaultMaxNumberOfProblems } from './defaultConstants.js'; import { determineTextDocumentSettings } from './determineTextDocumentSettings.js'; @@ -58,7 +60,7 @@ export interface DocumentValidatorOptions extends ValidateTextOptions { const ERROR_NOT_PREPARED = 'Validator Must be prepared before calling this function.'; -const skipValidation = false; +type PerfTimings = Record; export class DocumentValidator { private _document: TextDocument; @@ -69,6 +71,8 @@ export class DocumentValidator { private _preparationTime = -1; private _suggestions = new AutoCache((text: string) => this.genSuggestions(text), 1000); readonly options: DocumentValidatorOptions; + readonly perfTiming: PerfTimings = {}; + public skipValidation: boolean; /** * @param doc - Document to validate @@ -85,6 +89,7 @@ export class DocumentValidator { if (numSuggestions !== undefined) { this.options.numSuggestions = numSuggestions; } + this.skipValidation = !!options.skipValidation; // console.error(`DocumentValidator: ${doc.uri}`); } @@ -92,8 +97,8 @@ export class DocumentValidator { return this._ready; } - async prepare(): Promise { - if (this._ready) return; + prepare(): Promise { + if (this._ready) return Promise.resolve(); if (this._prepared) return this._prepared; this._prepared = this._prepareAsync(); return this._prepared; @@ -102,7 +107,7 @@ export class DocumentValidator { private async _prepareAsync(): Promise { assert(!this._ready); - const timer = createTimer(); + const timer = createPerfTimer('_prepareAsync'); const { options, settings } = this; @@ -111,27 +116,45 @@ export class DocumentValidator { const pLocalConfig = options.configFile ? loadConfig(options.configFile, settings) : useSearchForConfig - ? searchForDocumentConfig(this._document, settings, settings) + ? timePromise( + this.perfTiming, + '__searchForDocumentConfig', + searchForDocumentConfig(this._document, settings, settings), + ) : undefined; + pLocalConfig && timePromise(this.perfTiming, '_loadConfig', pLocalConfig); const localConfig = (await catchPromiseError(pLocalConfig, (e) => this.addPossibleError(e))) || {}; this.addPossibleError(localConfig?.__importRef?.error); const config = mergeSettings(settings, localConfig); - const docSettings = await determineTextDocumentSettings(this._document, config); - const dict = await getDictionaryInternal(docSettings); + const docSettings = await timePromise( + this.perfTiming, + '_determineTextDocumentSettings', + determineTextDocumentSettings(this._document, config), + ); + const dict = await timePromise(this.perfTiming, '_getDictionaryInternal', getDictionaryInternal(docSettings)); - const matcher = new GlobMatcher(localConfig?.ignorePaths || [], { root: process.cwd(), dot: true }); + const recGlobMatcherTime = recordPerfTime(this.perfTiming, '_GlobMatcher'); + const matcher = DocumentValidator.getGlobMatcher(localConfig?.ignorePaths); const uri = this._document.uri; + recGlobMatcherTime(); + const recShouldCheckTime = recordPerfTime(this.perfTiming, '_shouldCheck'); const shouldCheck = !matcher.match(uriToFilePath(uri)) && (docSettings.enabled ?? true); + recShouldCheckTime(); + + const recFinalizeTime = recordPerfTime(this.perfTiming, '_finalizeSettings'); + const finalSettings = finalizeSettings(docSettings); const validateOptions = settingsToValidateOptions(finalSettings); const includeRanges = calcTextInclusionRanges(this._document.text, validateOptions); const segmenter = createMappedTextSegmenter(includeRanges); const textValidator = textValidatorFactory(dict, validateOptions); + recFinalizeTime(); + this._preparations = { config, dictionary: dict, @@ -147,12 +170,13 @@ export class DocumentValidator { }; this._ready = true; - this._preparationTime = timer.elapsed(); + this._preparationTime = timer.elapsed; + this.perfTiming.prepTime = this._preparationTime; } private async _updatePrep() { assert(this._preparations, ERROR_NOT_PREPARED); - const timer = createTimer(); + const timer = createPerfTimer('_updatePrep'); const prep = this._preparations; const docSettings = await determineTextDocumentSettings(this._document, prep.config); const dict = getDictionaryInternalSync(docSettings); @@ -173,7 +197,7 @@ export class DocumentValidator { segmenter, textValidator, }; - this._preparationTime = timer.elapsed(); + this._preparationTime = timer.elapsed; } /** @@ -251,16 +275,21 @@ export class DocumentValidator { * @returns the validation issues. */ public checkDocument(forceCheck = false): ValidationIssue[] { - if (skipValidation) return []; - assert(this._ready); - assert(this._preparations, ERROR_NOT_PREPARED); - - const spellingIssues = - forceCheck || this.shouldCheckDocument() ? [...this._checkParsedText(this._parse())] : []; - const directiveIssues = this.checkDocumentDirectives(); - // console.log('Stats: %o', this._preparations.textValidator.lineValidator.dict.stats()); - const allIssues = spellingIssues.concat(directiveIssues).sort((a, b) => a.offset - b.offset); - return allIssues; + const timerDone = recordPerfTime(this.perfTiming, 'checkDocument'); + try { + if (this.skipValidation) return []; + assert(this._ready); + assert(this._preparations, ERROR_NOT_PREPARED); + + const spellingIssues = + forceCheck || this.shouldCheckDocument() ? [...this._checkParsedText(this._parse())] : []; + const directiveIssues = this.checkDocumentDirectives(); + // console.log('Stats: %o', this._preparations.textValidator.lineValidator.dict.stats()); + const allIssues = spellingIssues.concat(directiveIssues).sort((a, b) => a.offset - b.offset); + return allIssues; + } finally { + timerDone(); + } } public checkDocumentDirectives(forceCheck = false): ValidationIssue[] { @@ -402,6 +431,12 @@ export class DocumentValidator { public _getPreparations(): Preparations | undefined { return this._preparations; } + + private static getGlobMatcher = memorizeLastCall(DocumentValidator._getGlobMatcher); + + private static _getGlobMatcher(ignorePaths: Glob[] | undefined): GlobMatcher { + return new GlobMatcher(ignorePaths || [], { root: process.cwd(), dot: true }); + } } function sanitizeSuggestion(sug: WordSuggestion): ExtendedSuggestion { @@ -435,7 +470,7 @@ async function searchForDocumentConfig( ): Promise { const { uri } = document; if (uri.scheme !== 'file') return Promise.resolve(defaultConfig); - return searchForConfig(path.dirname(uriToFilePath(uri)), pnpSettings).then((s) => s || defaultConfig); + return searchForConfig(uri.toString(), pnpSettings).then((s) => s || defaultConfig); } function mapSug(sug: ExtendedSuggestion | SuggestionResult): SuggestionResult { @@ -486,3 +521,12 @@ export async function shouldCheckDocument( export const __testing__ = { sanitizeSuggestion, }; + +function recordPerfTime(timings: PerfTimings, name: string): () => void { + const timer = createPerfTimer(name, (elapsed) => (timings[name] = elapsed)); + return () => timer.end(); +} + +function timePromise(timings: PerfTimings, name: string, p: Promise): Promise { + return p.finally(recordPerfTime(timings, name)); +} diff --git a/packages/cspell-lib/src/lib/util/debugPerf.test.ts b/packages/cspell-lib/src/lib/util/debugPerf.test.ts deleted file mode 100644 index 96af707d00c..00000000000 --- a/packages/cspell-lib/src/lib/util/debugPerf.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { describe, expect, test, vi } from 'vitest'; - -import { perfFn } from './debugPerf.js'; - -describe('debugPerf', () => { - test('perfFn with callback', () => { - const mock = vi.fn(); - const fn = perfFn(() => undefined, 'message', mock); - fn(); - expect(mock).toHaveBeenCalledWith(expect.stringContaining('message'), expect.any(Number)); - }); - - test('perfFn default callback', () => { - const mock = vi.spyOn(console, 'error').mockImplementation(() => undefined); - const fn = perfFn(() => undefined, 'message'); - fn(); - expect(mock).toHaveBeenCalledWith(expect.stringContaining('message')); - }); -}); diff --git a/packages/cspell-lib/src/lib/util/debugPerf.ts b/packages/cspell-lib/src/lib/util/debugPerf.ts deleted file mode 100644 index 74423c8ab2e..00000000000 --- a/packages/cspell-lib/src/lib/util/debugPerf.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { createTimer } from './timer.js'; - -/** - * Measure and log result. - * @param fn - function to measure. - * @param message - message to log - * @param callback - called when the function has finished. - * @returns a function - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function perfFn

( - fn: (...args: P) => R, - message: string, - callback: (m: string, elapsedMs: number) => void = (message, time) => - console.error(`${message}: ${time.toFixed(2)}ms`), -): (...args: P) => R { - return (...args: P) => { - const timer = createTimer(); - const r = fn(...args); - callback(message, timer.elapsed()); - return r; - }; -} diff --git a/packages/cspell-lib/src/lib/util/timer.test.ts b/packages/cspell-lib/src/lib/util/timer.test.ts deleted file mode 100644 index bbb8e237a00..00000000000 --- a/packages/cspell-lib/src/lib/util/timer.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { promisify } from 'util'; -import { describe, expect, test } from 'vitest'; - -import { createLapRecorder, createTimer, polyHrTime } from './timer.js'; - -const delay = promisify(setTimeout); - -describe('timer', () => { - test('createTimer', async () => { - const t = createTimer(); - await delay(12); - expect(t.elapsed()).toBeGreaterThan(10); - }); - - test('polyHrTime', async () => { - const a = createTimer(); - const b = createTimer(polyHrTime); - await delay(12); - const a1 = a.elapsed(); - const b1 = b.elapsed(); - expect(a1).toBeGreaterThanOrEqual(10); - expect(b1).toBeGreaterThanOrEqual(10); - expect(Math.abs(b1 - a1)).toBeLessThan(10); - }); - - test('lap', async () => { - const t = createTimer(); - const a = t.lap(); - await delay(12); - const b = t.lap(); - await delay(1); - expect(b).toBeLessThan(t.elapsed()); - expect(a).toBeLessThan(b); - }); -}); - -describe('LapRecorder', () => { - test('LapRecorder', () => { - const timer = createLapRecorder(); - timer.lap('a'); - timer.lap('b'); - expect(timer.times.length).toBe(2); - expect(timer.times[0][0]).toBe('a'); - expect(timer.times[0][1]).toBe(timer.times[0][2]); - expect(timer.report()).toHaveLength(2); - }); -}); diff --git a/packages/cspell-lib/src/lib/util/timer.ts b/packages/cspell-lib/src/lib/util/timer.ts deleted file mode 100644 index 2aaa9ccb90a..00000000000 --- a/packages/cspell-lib/src/lib/util/timer.ts +++ /dev/null @@ -1,80 +0,0 @@ -const _hrTime: HRTimeFn = process?.hrtime || polyHrTime; - -export interface Timer { - /** Start / restart the timer. */ - start(): void; - /** - * Calculate the amount of time in ms since the - * timer was created / started. - */ - elapsed(): number; - /** - * Calculate the amount of time in ms since the - * end of the last lap. - */ - lap(): number; -} - -export function createTimer(hrTimeFn = _hrTime): Timer { - let start: HRTime = hrTimeFn(); - let lastLap = 0; - function elapsed() { - return toMilliseconds(hrTimeFn(start)); - } - - return { - start() { - start = hrTimeFn(); - lastLap = 0; - }, - elapsed, - lap() { - const now = elapsed(); - const diff = now - lastLap; - lastLap = now; - return diff; - }, - }; -} - -export type HRTimeFn = (time?: HRTime) => HRTime; - -export type HRTime = [number, number]; - -export function toMilliseconds(t: HRTime): number { - return (t[0] + t[1] * 1e-9) * 1000; -} - -export function polyHrTime(time?: HRTime): HRTime { - const now = Date.now() - (time ? toMilliseconds(time) : 0); - const inSeconds = now * 1.0e-3; - const s = Math.floor(inSeconds); - const n = (inSeconds - s) * 1.0e9; - return [s, n]; -} - -export interface LapRecorder { - times: [name: string, lapTime: number, totalTime: number][]; - lap(name: string): void; - report(): string[]; -} - -export function createLapRecorder(): LapRecorder { - const timer = createTimer(); - const times: [string, number, number][] = []; - let lapTime = 0; - function lap(name: string) { - const now = timer.elapsed(); - const diff = now - lapTime; - times.push([name, diff, now]); - lapTime = diff; - } - function report() { - return times.map(([name, time]) => `${name}: ${time.toFixed(2)}`); - } - return { - times, - lap, - report, - }; -} diff --git a/packages/cspell/src/app/__snapshots__/app.test.ts.snap b/packages/cspell/src/app/__snapshots__/app.test.ts.snap index 34090c0d2af..64daad7661f 100644 --- a/packages/cspell/src/app/__snapshots__/app.test.ts.snap +++ b/packages/cspell/src/app/__snapshots__/app.test.ts.snap @@ -367,7 +367,7 @@ info Glob: .vscode/** from ./cspell.json info Glob: node_modules/** from command line info info Checking: ./src/app/app.test.ts, File type: auto, Language: default -info Checked: ./src/app/app.test.ts, File type: typescript, Language: en ... Issues: 0 0.00S +info Checked: ./src/app/app.test.ts, File type: typescript, Language: en ... Issues: 0 0.00ms info Config file Used: ./cspell.json info Dictionaries Used: companies, filetypes, public-licenses, softwareTerms, computing-acronyms, web-services, workspace, aws, cryptocurrencies, en_us, en-common-misspellings, fullstack, node, npm, svelte, typescript error 0.00ms @@ -434,7 +434,7 @@ info Exclusion Globs: info Glob: node_modules/** from command line info info Checking: ./fixtures/issue-2998/fix-words.txt, File type: fix, Language: default -info Checked: ./fixtures/issue-2998/fix-words.txt, File type: fix, Language: en ... Issues: 0 0.00S +info Checked: ./fixtures/issue-2998/fix-words.txt, File type: fix, Language: en ... Issues: 0 0.00ms info Config file Used: ./fixtures/issue-2998/cspell.json info Dictionaries Used: companies, filetypes, public-licenses, softwareTerms, computing-acronyms, web-services, aws, cryptocurrencies, en_us, en-common-misspellings, fixture error 0.00ms diff --git a/packages/cspell/src/app/commandLint.ts b/packages/cspell/src/app/commandLint.ts index 0e6e6afba44..bef26d0edd9 100644 --- a/packages/cspell/src/app/commandLint.ts +++ b/packages/cspell/src/app/commandLint.ts @@ -159,27 +159,34 @@ export function commandLint(prog: Command): Command { ) .option('--debug', 'Output information useful for debugging cspell.json files.') .option('--reporter ', 'Specify one or more reporters to use.', collect) + .addOption( + new CommanderOption('--skip-validation', 'Collect and process documents, but do not spell check.') + .implies({ cache: false }) + .hideHelp(), + ) .usage(usage) .addHelpText('after', advanced) .arguments('[globs...]') - .action((fileGlobs: string[], options: LinterCliOptions) => { + .action(async (fileGlobs: string[], options: LinterCliOptions) => { const useExitCode = options.exitCode ?? true; + if (options.skipValidation) { + options.cache = false; + } App.parseApplicationFeatureFlags(options.flag); const { mustFindFiles, fileList } = options; - return App.lint(fileGlobs, options).then((result) => { - if (!fileGlobs.length && !result.files && !result.errors && !fileList) { - spellCheckCommand.outputHelp(); - throw new CheckFailed('outputHelp', 1); - } - if (result.errors || (mustFindFiles && !result.files)) { - throw new CheckFailed('check failed', 1); - } - if (result.issues) { - const exitCode = useExitCode ? 1 : 0; - throw new CheckFailed('check failed', exitCode); - } - return; - }); + const result = await App.lint(fileGlobs, options); + if (!fileGlobs.length && !result.files && !result.errors && !fileList) { + spellCheckCommand.outputHelp(); + throw new CheckFailed('outputHelp', 1); + } + if (result.errors || (mustFindFiles && !result.files)) { + throw new CheckFailed('check failed', 1); + } + if (result.issues) { + const exitCode = useExitCode ? 1 : 0; + throw new CheckFailed('check failed', exitCode); + } + return; }); return spellCheckCommand; diff --git a/packages/cspell/src/app/lint/lint.ts b/packages/cspell/src/app/lint/lint.ts index 7ae2b9bd325..19dc1721545 100644 --- a/packages/cspell/src/app/lint/lint.ts +++ b/packages/cspell/src/app/lint/lint.ts @@ -178,12 +178,19 @@ export async function runLint(cfg: LintRequest): Promise { MessageTypes.Info, ); try { - const { showSuggestions: generateSuggestions, validateDirectives } = cfg.options; + const { showSuggestions: generateSuggestions, validateDirectives, skipValidation } = cfg.options; const numSuggestions = configInfo.config.numSuggestions ?? 5; - const validateOptions = util.clean({ generateSuggestions, numSuggestions, validateDirectives }); + const validateOptions = util.clean({ + generateSuggestions, + numSuggestions, + validateDirectives, + skipValidation, + }); const r = await spellCheckDocument(doc, validateOptions, configInfo.config); + // console.warn('filename: %o %o', path.relative(process.cwd(), filename), r.perf); spellResult = r; result.processed = r.checked; + result.perf = r.perf ? { ...r.perf } : undefined; result.issues = cspellText.calculateTextDocumentOffsets(doc.uri, text, r.issues).map(mapIssue); } catch (e) { reporter.error(`Failed to process "${filename}"`, toError(e)); @@ -195,10 +202,12 @@ export async function runLint(cfg: LintRequest): Promise { result.configErrors += await reportConfigurationErrors(config); - const elapsed = result.elapsedTimeMs / 1000.0; + const elapsed = result.elapsedTimeMs; const dictionaries = config.dictionaries || []; reporter.info( - `Checked: ${filename}, File type: ${config.languageId}, Language: ${config.language} ... Issues: ${result.issues.length} ${elapsed}S`, + `Checked: ${filename}, File type: ${config.languageId}, Language: ${config.language} ... Issues: ${ + result.issues.length + } ${elapsed.toFixed(2)}ms`, MessageTypes.Info, ); reporter.info(`Config file Used: ${spellResult.localConfigFilepath || configInfo.source}`, MessageTypes.Info); @@ -313,8 +322,19 @@ export async function runLint(cfg: LintRequest): Promise { } else { for (const pf of prefetchFiles(files)) { await pf.result; - yield await processPrefetchFileResult(pf, ++i); + yield processPrefetchFileResult(pf, ++i); } + // const iter = prefetchIterable( + // pipe( + // prefetchFiles(files), + // opMap(async (pf) => { + // return processPrefetchFileResult(pf, ++i); + // }), + // ), + // BATCH_SIZE, + // ); + + // yield* iter; } } diff --git a/packages/cspell/src/app/options.ts b/packages/cspell/src/app/options.ts index 00de4932ec7..6e311a04177 100644 --- a/packages/cspell/src/app/options.ts +++ b/packages/cspell/src/app/options.ts @@ -73,6 +73,10 @@ export interface LinterOptions extends BaseOptions, Omit; + export interface FileResult { fileInfo: FileInfo; processed: boolean; @@ -52,6 +55,7 @@ export interface FileResult { errors: number; configErrors: number; elapsedTimeMs: number | undefined; + perf?: Perf | undefined; cached?: boolean; } diff --git a/packages/cspell/src/app/util/timer.ts b/packages/cspell/src/app/util/timer.ts index 32deb10efc2..72e88cfa011 100644 --- a/packages/cspell/src/app/util/timer.ts +++ b/packages/cspell/src/app/util/timer.ts @@ -1,17 +1,11 @@ -export interface MeasurePromiseResult { - elapsedTimeMs: number; - success: boolean; -} +import type { PerfTimer } from 'cspell-lib'; +import { createPerfTimer } from 'cspell-lib'; export function getTimeMeasurer(): () => number { - const start = process.hrtime(); - return () => hrTimeToMs(process.hrtime(start)); -} - -export function elapsedTimeMsFrom(relativeTo: [number, number]): number { - return hrTimeToMs(process.hrtime(relativeTo)); + const timer = createPerfTimer('timer'); + return () => timer.elapsed; } -export function hrTimeToMs(hrTime: [number, number]): number { - return hrTime[0] * 1.0e3 + hrTime[1] * 1.0e-6; +export function getTimer(name: string, onEnd?: (elapsed: number, name: string) => void): PerfTimer { + return createPerfTimer(name, onEnd); } diff --git a/packages/cspell/tsconfig.esm.json b/packages/cspell/tsconfig.esm.json index 895acb2dde0..95a3d642689 100644 --- a/packages/cspell/tsconfig.esm.json +++ b/packages/cspell/tsconfig.esm.json @@ -5,6 +5,8 @@ "tsBuildInfoFile": "temp/compile.esm.tsbuildInfo", "rootDir": "src/app", "outDir": "dist/esm", + "target": "es2022", + "lib": ["es2023"], "types": ["node"] }, "include": ["src/app"], diff --git a/packages/cspell/tsconfig.json b/packages/cspell/tsconfig.json index 290b677dc75..ecbd69ab9c2 100644 --- a/packages/cspell/tsconfig.json +++ b/packages/cspell/tsconfig.json @@ -1,4 +1,4 @@ { "files": [], - "references": [{ "path": "./tsconfig.esm.json" }, { "path": "./src/lib" }] + "references": [{ "path": "./tsconfig.esm.json" }, { "path": "./src/lib/tsconfig.json" }] } From af912b02bb73917e3ec585583e3466ac2bf74eec Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Sat, 25 Nov 2023 17:34:23 -0700 Subject: [PATCH 2/9] Add ClearCacheEvent --- packages/cspell-lib/api/api.d.ts | 21 +++++++- .../configLoader/configLoader.test.ts | 6 ++- .../Controller/configLoader/configLoader.ts | 19 ++++++- .../configLoader/defaultConfigLoader.ts | 12 +++++ .../Settings/Controller/configLoader/index.ts | 1 + packages/cspell-lib/src/lib/Settings/index.ts | 1 + .../src/lib/__snapshots__/index.test.ts.snap | 2 +- .../src/lib/clearCachedFiles.test.ts | 14 +++++- .../cspell-lib/src/lib/clearCachedFiles.ts | 34 +++++++++++-- .../cspell-lib/src/lib/events/events.test.ts | 50 +++++++++++++++++++ packages/cspell-lib/src/lib/events/events.ts | 41 +++++++++++++++ packages/cspell-lib/src/lib/events/index.ts | 2 + packages/cspell-lib/src/lib/index.ts | 4 +- packages/cspell-lib/src/lib/suggestions.ts | 6 +-- packages/cspell/src/app/application.ts | 6 ++- 15 files changed, 203 insertions(+), 16 deletions(-) create mode 100644 packages/cspell-lib/src/lib/events/events.test.ts create mode 100644 packages/cspell-lib/src/lib/events/events.ts create mode 100644 packages/cspell-lib/src/lib/events/index.ts diff --git a/packages/cspell-lib/api/api.d.ts b/packages/cspell-lib/api/api.d.ts index 115effc4411..7e73c4df911 100644 --- a/packages/cspell-lib/api/api.d.ts +++ b/packages/cspell-lib/api/api.d.ts @@ -388,9 +388,12 @@ declare function searchForConfig(searchFrom: URL | string | undefined, pnpSettin * @returns normalized CSpellSettings */ declare function loadConfig(file: string, pnpSettings?: PnPSettingsOptional): Promise; +/** + * Might throw if the settings have not yet been loaded. + * @deprecated use `getGlobalSettingsAsync` instead. + */ declare function getGlobalSettings(): CSpellSettingsI$1; declare function getCachedFileSize(): number; -declare function clearCachedSettingsFiles(): void; declare function readRawSettings(filename: string | URL, relativeTo?: string | URL): Promise; declare function extractImportErrors(settings: CSpellSettingsWST$1): ImportFileRefWithError$1[]; @@ -910,7 +913,21 @@ interface ResolveFileResult { */ declare function resolveFile(filename: string, relativeTo: string | URL): ResolveFileResult; +/** + * Clear the cached files and other cached data. + * Calling this function will cause the next spell check to take longer because it will need to reload configuration files and dictionaries. + * Call this function if configuration files have changed. + * + * It is safe to replace {@link clearCachedFiles} with {@link clearCaches} + */ declare function clearCachedFiles(): Promise; +/** + * Sends and event to clear the caches. + * It resets the configuration files and dictionaries. + * + * It is safe to replace {@link clearCaches} with {@link clearCachedFiles} + */ +declare function clearCaches(): void; /** * Load a dictionary collection defined by the settings. @@ -929,4 +946,4 @@ interface PerfTimer { type TimeNowFn = () => number; declare function createPerfTimer(name: string, onEnd?: (elapsed: number, name: string) => void, timeNowFn?: TimeNowFn): PerfTimer; -export { type CheckTextInfo, type ConfigurationDependencies, type CreateTextDocumentParams, type DetermineFinalDocumentSettingsResult, type Document, DocumentValidator, type DocumentValidatorOptions, ENV_CSPELL_GLOB_ROOT, type ExcludeFilesGlobMap, type ExclusionFunction, exclusionHelper_d as ExclusionHelper, type FeatureFlag, FeatureFlags, ImportError, type ImportFileRefWithError, IncludeExcludeFlag, type IncludeExcludeOptions, index_link_d as Link, type Logger, type PerfTimer, type SpellCheckFileOptions, type SpellCheckFileResult, SpellingDictionaryLoadError, type SuggestedWord, SuggestionError, type SuggestionOptions, type SuggestionsForWordResult, text_d as Text, type TextDocument, type TextDocumentLine, type TextDocumentRef, type TextInfoItem, type TraceOptions, type TraceResult, UnknownFeatureFlagError, type ValidationIssue, calcOverrideSettings, checkFilenameMatchesGlob, checkText, checkTextDocument, clearCachedFiles, clearCachedSettingsFiles, combineTextAndLanguageSettings, combineTextAndLanguageSettings as constructSettingsForText, createPerfTimer, createTextDocument, currentSettingsFileVersion, defaultConfigFilenames, defaultFileName, defaultFileName as defaultSettingsFilename, determineFinalDocumentSettings, extractDependencies, extractImportErrors, fileToDocument, fileToTextDocument, finalizeSettings, getCachedFileSize, getDefaultBundledSettingsAsync, getDefaultSettings, getDictionary, getGlobalSettings, getLanguagesForBasename as getLanguageIdsForBaseFilename, getLanguagesForExt, getLogger, getSources, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, loadConfig, loadPnP, loadPnPSync, mergeInDocSettings, mergeSettings, readRawSettings, readSettings, readSettingsFiles, refreshDictionaryCache, resolveFile, searchForConfig, sectionCSpell, setLogger, shouldCheckDocument, spellCheckDocument, spellCheckFile, suggestionsForWord, suggestionsForWords, traceWords, traceWordsAsync, updateTextDocument, validateText }; +export { type CheckTextInfo, type ConfigurationDependencies, type CreateTextDocumentParams, type DetermineFinalDocumentSettingsResult, type Document, DocumentValidator, type DocumentValidatorOptions, ENV_CSPELL_GLOB_ROOT, type ExcludeFilesGlobMap, type ExclusionFunction, exclusionHelper_d as ExclusionHelper, type FeatureFlag, FeatureFlags, ImportError, type ImportFileRefWithError, IncludeExcludeFlag, type IncludeExcludeOptions, index_link_d as Link, type Logger, type PerfTimer, type SpellCheckFileOptions, type SpellCheckFileResult, SpellingDictionaryLoadError, type SuggestedWord, SuggestionError, type SuggestionOptions, type SuggestionsForWordResult, text_d as Text, type TextDocument, type TextDocumentLine, type TextDocumentRef, type TextInfoItem, type TraceOptions, type TraceResult, UnknownFeatureFlagError, type ValidationIssue, calcOverrideSettings, checkFilenameMatchesGlob, checkText, checkTextDocument, clearCachedFiles, clearCaches, combineTextAndLanguageSettings, combineTextAndLanguageSettings as constructSettingsForText, createPerfTimer, createTextDocument, currentSettingsFileVersion, defaultConfigFilenames, defaultFileName, defaultFileName as defaultSettingsFilename, determineFinalDocumentSettings, extractDependencies, extractImportErrors, fileToDocument, fileToTextDocument, finalizeSettings, getCachedFileSize, getDefaultBundledSettingsAsync, getDefaultSettings, getDictionary, getGlobalSettings, getLanguagesForBasename as getLanguageIdsForBaseFilename, getLanguagesForExt, getLogger, getSources, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, loadConfig, loadPnP, loadPnPSync, mergeInDocSettings, mergeSettings, readRawSettings, readSettings, readSettingsFiles, refreshDictionaryCache, resolveFile, searchForConfig, sectionCSpell, setLogger, shouldCheckDocument, spellCheckDocument, spellCheckFile, suggestionsForWord, suggestionsForWords, traceWords, traceWordsAsync, updateTextDocument, validateText }; diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.test.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.test.ts index 81300270589..b5bfc6473a7 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.test.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.test.ts @@ -23,6 +23,7 @@ import { getCachedFileSize, getDefaultConfigLoader, getGlobalSettings, + getGlobalSettingsAsync, loadConfig, readConfigFile, readRawSettings, @@ -109,13 +110,14 @@ describe('Validate CSpellSettingsServer', () => { test('makes sure global settings is an object', async () => { const settings = getGlobalSettings(); + expect(await getGlobalSettingsAsync()).toBe(settings); expect(Object.keys(settings)).not.toHaveLength(0); - const merged = mergeSettings(await getDefaultBundledSettingsAsync(), await getGlobalSettings()); + const merged = mergeSettings(await getDefaultBundledSettingsAsync(), await getGlobalSettingsAsync()); expect(Object.keys(merged)).not.toHaveLength(0); }); test('verify clearing the file cache works', async () => { - mergeSettings(await getDefaultBundledSettingsAsync(), await getGlobalSettings()); + mergeSettings(await getDefaultBundledSettingsAsync(), await getGlobalSettingsAsync()); expect(getCachedFileSize()).toBeGreaterThan(0); clearCachedSettingsFiles(); expect(getCachedFileSize()).toBe(0); diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts index 10e20ccc458..5f99fc509e0 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts @@ -7,6 +7,7 @@ import { getDefaultCSpellIO } from 'cspell-io'; import * as path from 'path'; import { fileURLToPath } from 'url'; +import { onClearCache } from '../../../events/index.js'; import { createCSpellSettingsInternal as csi } from '../../../Models/CSpellSettingsInternalDef.js'; import { AutoResolveCache } from '../../../util/AutoResolve.js'; import { logError, logWarning } from '../../../util/logger.js'; @@ -40,7 +41,6 @@ import { import type { PnPSettingsOptional } from './PnPSettings.js'; import { defaultPnPSettings, normalizePnPSettings } from './PnPSettings.js'; import type { CSpellSettingsI, CSpellSettingsWST } from './types.js'; -import { c } from 'vitest/dist/reporters-5f784f42.js'; type CSpellSettingsVersion = Exclude; const supportedCSpellConfigVersions: CSpellSettingsVersion[] = [configSettingsFileVersion0_2]; @@ -91,6 +91,11 @@ export class ConfigLoader { () => undefined, (e) => logError(e), ); + this.subscribeToEvents(); + } + + private subscribeToEvents() { + this.toDispose.push(onClearCache(() => this.clearCachedSettingsFiles())); } protected cachedConfig = new Map(); @@ -101,6 +106,8 @@ export class ConfigLoader { protected cspellConfigFileReaderWriter: CSpellConfigFileReaderWriter; protected configSearch = new ConfigSearch(searchPlaces); + protected toDispose: { dispose: () => void }[] = []; + public async readSettingsAsync( filename: string | URL, relativeTo?: string | URL, @@ -389,6 +396,16 @@ export class ConfigLoader { createCSpellConfigFile(filename: URL | string, settings: CSpellUserSettings): CSpellConfigFile { return new CSpellConfigFileInMemory(this.cspellIO.toFileURL(filename), settings); } + + dispose() { + while (this.toDispose.length) { + try { + this.toDispose.pop()?.dispose(); + } catch (e) { + logError(e); + } + } + } } class ConfigLoaderInternal extends ConfigLoader { diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/defaultConfigLoader.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/defaultConfigLoader.ts index 8219f87717c..21ed573b93a 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/defaultConfigLoader.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/defaultConfigLoader.ts @@ -42,10 +42,22 @@ export async function readConfigFile(filename: string | URL, relativeTo?: string return result; } +/** + * Might throw if the settings have not yet been loaded. + * @deprecated use {@link getGlobalSettingsAsync} instead. + */ export function getGlobalSettings(): CSpellSettingsI { return gcl().getGlobalSettings(); } +/** + * Loads and caches the global settings. + * @returns - global settings + */ +export function getGlobalSettingsAsync(): Promise { + return gcl().getGlobalSettingsAsync(); +} + export function getCachedFileSize(): number { return cachedFiles().size; } diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/index.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/index.ts index d43da348c7f..4de9ec303eb 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/index.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/index.ts @@ -12,6 +12,7 @@ export { clearCachedSettingsFiles, getCachedFileSize, getGlobalSettings, + getGlobalSettingsAsync, loadConfig, readRawSettings, searchForConfig, diff --git a/packages/cspell-lib/src/lib/Settings/index.ts b/packages/cspell-lib/src/lib/Settings/index.ts index 538ce513b62..e31cf1b5413 100644 --- a/packages/cspell-lib/src/lib/Settings/index.ts +++ b/packages/cspell-lib/src/lib/Settings/index.ts @@ -6,6 +6,7 @@ export { extractImportErrors, getCachedFileSize, getGlobalSettings, + getGlobalSettingsAsync, loadConfig, loadPnP, loadPnPSync, diff --git a/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap b/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap index 70e49321685..342fe99b56d 100644 --- a/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap +++ b/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap @@ -148,7 +148,7 @@ exports[`Validate the cspell API > Verify API exports 1`] = ` "checkText": [Function], "checkTextDocument": [Function], "clearCachedFiles": [Function], - "clearCachedSettingsFiles": [Function], + "clearCaches": [Function], "combineTextAndLanguageSettings": [Function], "constructSettingsForText": [Function], "createPerfTimer": [Function], diff --git a/packages/cspell-lib/src/lib/clearCachedFiles.test.ts b/packages/cspell-lib/src/lib/clearCachedFiles.test.ts index 5c961f0d2cc..bc742c3ff95 100644 --- a/packages/cspell-lib/src/lib/clearCachedFiles.test.ts +++ b/packages/cspell-lib/src/lib/clearCachedFiles.test.ts @@ -1,9 +1,21 @@ -import { describe, expect, test } from 'vitest'; +import { describe, expect, test, vi } from 'vitest'; import * as clearCachedFiles from './clearCachedFiles.js'; +import { onClearCache } from './events/events.js'; describe('clearCachedFiles', () => { test('clearCachedFiles', async () => { await expect(clearCachedFiles.clearCachedFiles()).resolves.not.toThrow(); }); + + test('clearCaches', () => { + const listener = vi.fn(); + const dispose = onClearCache(listener); + expect(() => clearCachedFiles.clearCaches()).not.toThrow(); + expect(listener).toHaveBeenCalledTimes(1); + dispose.dispose(); + listener.mockClear(); + expect(() => clearCachedFiles.clearCaches()).not.toThrow(); + expect(listener).not.toHaveBeenCalled(); + }); }); diff --git a/packages/cspell-lib/src/lib/clearCachedFiles.ts b/packages/cspell-lib/src/lib/clearCachedFiles.ts index b1b545343a3..a13f955f530 100644 --- a/packages/cspell-lib/src/lib/clearCachedFiles.ts +++ b/packages/cspell-lib/src/lib/clearCachedFiles.ts @@ -1,6 +1,34 @@ -import { clearCachedSettingsFiles } from './Settings/index.js'; +import { dispatchClearCache } from './events/index.js'; import { refreshDictionaryCache } from './SpellingDictionary/index.js'; -export async function clearCachedFiles(): Promise { - await Promise.all([clearCachedSettingsFiles(), refreshDictionaryCache(0)]); +/** + * Clear the cached files and other cached data. + * Calling this function will cause the next spell check to take longer because it will need to reload configuration files and dictionaries. + * Call this function if configuration files have changed. + * + * It is safe to replace {@link clearCachedFiles} with {@link clearCaches} + */ +export function clearCachedFiles(): Promise { + return _clearCachedFiles(); +} + +/** + * Clear the cached files and other cached data. + * Calling this function will cause the next spell check to take longer because it will need to reload configuration files and dictionaries. + * Call this function if configuration files have changed. + */ +function _clearCachedFiles(): Promise { + // We want to dispatch immediately. + dispatchClearCache(); + return Promise.all([refreshDictionaryCache(0)]).then(() => undefined); +} + +/** + * Sends and event to clear the caches. + * It resets the configuration files and dictionaries. + * + * It is safe to replace {@link clearCaches} with {@link clearCachedFiles} + */ +export function clearCaches(): void { + clearCachedFiles().catch(() => {}); } diff --git a/packages/cspell-lib/src/lib/events/events.test.ts b/packages/cspell-lib/src/lib/events/events.test.ts new file mode 100644 index 00000000000..a2fefb4b267 --- /dev/null +++ b/packages/cspell-lib/src/lib/events/events.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, test, vi } from 'vitest'; + +import { addEventListener, ClearCacheEvent, dispatchClearCache, dispatchEvent, onClearCache } from './events.js'; + +describe('events', () => { + describe('addEventListener', () => { + test('should add an event listener for ClearCacheEvent', () => { + const listener = vi.fn(); + const disposableListener = addEventListener('clear-cache', listener); + + expect(disposableListener).toBeDefined(); + + const event = new ClearCacheEvent(); + dispatchEvent(event); + + expect(listener).toHaveBeenCalledWith(event); + expect(listener).toHaveBeenCalledTimes(1); + + disposableListener.dispose(); + + const event2 = new ClearCacheEvent(); + dispatchEvent(event2); + expect(listener).toHaveBeenCalledTimes(1); + }); + }); + + describe('ClearCacheEvent', () => { + test('should have the correct event name', () => { + expect(ClearCacheEvent.eventName).toBe('clear-cache'); + }); + + test('onClearCache should add an event listener for ClearCacheEvent', () => { + const listener = vi.fn(); + + const disposableListener = onClearCache(listener); + + expect(disposableListener).toBeDefined(); + + dispatchClearCache(); + expect(listener).toHaveBeenCalledTimes(1); + + dispatchClearCache(); + expect(listener).toHaveBeenCalledTimes(2); + + disposableListener.dispose(); + dispatchClearCache(); + expect(listener).toHaveBeenCalledTimes(2); + }); + }); +}); diff --git a/packages/cspell-lib/src/lib/events/events.ts b/packages/cspell-lib/src/lib/events/events.ts new file mode 100644 index 00000000000..ebcdc7ec546 --- /dev/null +++ b/packages/cspell-lib/src/lib/events/events.ts @@ -0,0 +1,41 @@ +/** + * Event indicating that the cache should be cleared. + */ +export class ClearCacheEvent extends Event { + constructor() { + super(ClearCacheEvent.eventName); + } + static eventName = 'clear-cache' as const; +} + +export type EventNames = typeof ClearCacheEvent.eventName; + +export type EventTypes = ClearCacheEvent; + +const eventEmitter = new EventTarget(); + +export interface DisposableListener { + dispose(): void; +} + +export function addEventListener(event: EventNames, listener: (event: ClearCacheEvent) => void): DisposableListener; +export function addEventListener(event: string, listener: (event: Event) => void): DisposableListener { + eventEmitter.addEventListener(event, listener); + return { + dispose() { + eventEmitter.removeEventListener(event, listener); + }, + }; +} + +export function dispatchEvent(event: EventTypes): void { + eventEmitter.dispatchEvent(event); +} + +export function onClearCache(listener: () => void): DisposableListener { + return addEventListener(ClearCacheEvent.eventName, listener); +} + +export function dispatchClearCache(): void { + dispatchEvent(new ClearCacheEvent()); +} diff --git a/packages/cspell-lib/src/lib/events/index.ts b/packages/cspell-lib/src/lib/events/index.ts new file mode 100644 index 00000000000..ab9d4ea0865 --- /dev/null +++ b/packages/cspell-lib/src/lib/events/index.ts @@ -0,0 +1,2 @@ +export type { DisposableListener, EventNames, EventTypes } from './events.js'; +export { addEventListener, ClearCacheEvent, dispatchClearCache, dispatchEvent, onClearCache } from './events.js'; diff --git a/packages/cspell-lib/src/lib/index.ts b/packages/cspell-lib/src/lib/index.ts index db382e67518..1d6ae872d73 100644 --- a/packages/cspell-lib/src/lib/index.ts +++ b/packages/cspell-lib/src/lib/index.ts @@ -17,7 +17,6 @@ export { createTextDocument, updateTextDocument } from './Models/TextDocument.js export { calcOverrideSettings, checkFilenameMatchesGlob, - clearCachedSettingsFiles, type ConfigurationDependencies, currentSettingsFileVersion, defaultConfigFilenames, @@ -30,6 +29,7 @@ export { getDefaultBundledSettingsAsync, getDefaultSettings, getGlobalSettings, + getGlobalSettingsAsync, getSources, ImportError, type ImportFileRefWithError, @@ -98,7 +98,7 @@ export { } from 'cspell-io'; export { Link, Text }; export { ExclusionHelper }; -export { clearCachedFiles } from './clearCachedFiles.js'; +export { clearCachedFiles, clearCaches } from './clearCachedFiles.js'; export { getDictionary } from './getDictionary.js'; export type { PerfTimer } from './perf/index.js'; export { createPerfTimer } from './perf/index.js'; diff --git a/packages/cspell-lib/src/lib/suggestions.ts b/packages/cspell-lib/src/lib/suggestions.ts index feb7fdb8ce6..4fd1d905b33 100644 --- a/packages/cspell-lib/src/lib/suggestions.ts +++ b/packages/cspell-lib/src/lib/suggestions.ts @@ -2,7 +2,7 @@ import type { CSpellSettings, LocaleId } from '@cspell/cspell-types'; import assert from 'assert'; import type { LanguageId } from './LanguageIds.js'; -import { finalizeSettings, getDefaultSettings, getGlobalSettings, mergeSettings } from './Settings/index.js'; +import { finalizeSettings, getDefaultSettings, getGlobalSettingsAsync, mergeSettings } from './Settings/index.js'; import { calcSettingsForLanguageId, isValidLocaleIntlFormat, @@ -160,7 +160,7 @@ async function _suggestionsForWord( const config = includeDefaultConfig ? mergeSettings( await getDefaultSettings(settings.loadDefaultConfiguration ?? true), - await getGlobalSettings(), + await getGlobalSettingsAsync(), settings, ) : settings; @@ -190,7 +190,7 @@ async function _suggestionsForWordAsync( const config = includeDefaultConfig ? mergeSettings( await getDefaultSettings(settings.loadDefaultConfiguration ?? true), - await getGlobalSettings(), + await getGlobalSettingsAsync(), settings, ) : settings; diff --git a/packages/cspell/src/app/application.ts b/packages/cspell/src/app/application.ts index 7aae72fc690..7cf3f3b6181 100644 --- a/packages/cspell/src/app/application.ts +++ b/packages/cspell/src/app/application.ts @@ -45,7 +45,11 @@ export async function* trace(words: string[], options: TraceOptions): AsyncItera const configFile = await readConfig(options.config, undefined); const loadDefault = options.defaultConfiguration ?? configFile.config.loadDefaultConfiguration ?? true; - const config = mergeSettings(await getDefaultSettings(loadDefault), getGlobalSettings(), configFile.config); + const config = mergeSettings( + await getDefaultSettings(loadDefault), + await getGlobalSettingsAsync(), + configFile.config, + ); yield* traceWordsAsync(iWords, config, util.clean({ languageId, locale, ignoreCase, allowCompoundWords })); } From 0988e2f0d036a7611ab9011184366a006304bb5d Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Sat, 25 Nov 2023 17:36:49 -0700 Subject: [PATCH 3/9] Update index.test.ts.snap --- packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap b/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap index 342fe99b56d..6eeda39bfa4 100644 --- a/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap +++ b/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap @@ -221,6 +221,7 @@ exports[`Validate the cspell API > Verify API exports 1`] = ` "getDefaultSettings": [Function], "getDictionary": [Function], "getGlobalSettings": [Function], + "getGlobalSettingsAsync": [Function], "getLanguageIdsForBaseFilename": [Function], "getLanguagesForExt": [Function], "getLogger": [Function], From 9f92ace14abe380aef1931491181110fbe0f56fd Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Sat, 25 Nov 2023 17:39:13 -0700 Subject: [PATCH 4/9] fix api --- packages/cspell-lib/api/api.d.ts | 9 +++++++-- packages/cspell/src/app/application.ts | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/cspell-lib/api/api.d.ts b/packages/cspell-lib/api/api.d.ts index 7e73c4df911..4635124a7c0 100644 --- a/packages/cspell-lib/api/api.d.ts +++ b/packages/cspell-lib/api/api.d.ts @@ -390,9 +390,14 @@ declare function searchForConfig(searchFrom: URL | string | undefined, pnpSettin declare function loadConfig(file: string, pnpSettings?: PnPSettingsOptional): Promise; /** * Might throw if the settings have not yet been loaded. - * @deprecated use `getGlobalSettingsAsync` instead. + * @deprecated use {@link getGlobalSettingsAsync} instead. */ declare function getGlobalSettings(): CSpellSettingsI$1; +/** + * Loads and caches the global settings. + * @returns - global settings + */ +declare function getGlobalSettingsAsync(): Promise; declare function getCachedFileSize(): number; declare function readRawSettings(filename: string | URL, relativeTo?: string | URL): Promise; @@ -946,4 +951,4 @@ interface PerfTimer { type TimeNowFn = () => number; declare function createPerfTimer(name: string, onEnd?: (elapsed: number, name: string) => void, timeNowFn?: TimeNowFn): PerfTimer; -export { type CheckTextInfo, type ConfigurationDependencies, type CreateTextDocumentParams, type DetermineFinalDocumentSettingsResult, type Document, DocumentValidator, type DocumentValidatorOptions, ENV_CSPELL_GLOB_ROOT, type ExcludeFilesGlobMap, type ExclusionFunction, exclusionHelper_d as ExclusionHelper, type FeatureFlag, FeatureFlags, ImportError, type ImportFileRefWithError, IncludeExcludeFlag, type IncludeExcludeOptions, index_link_d as Link, type Logger, type PerfTimer, type SpellCheckFileOptions, type SpellCheckFileResult, SpellingDictionaryLoadError, type SuggestedWord, SuggestionError, type SuggestionOptions, type SuggestionsForWordResult, text_d as Text, type TextDocument, type TextDocumentLine, type TextDocumentRef, type TextInfoItem, type TraceOptions, type TraceResult, UnknownFeatureFlagError, type ValidationIssue, calcOverrideSettings, checkFilenameMatchesGlob, checkText, checkTextDocument, clearCachedFiles, clearCaches, combineTextAndLanguageSettings, combineTextAndLanguageSettings as constructSettingsForText, createPerfTimer, createTextDocument, currentSettingsFileVersion, defaultConfigFilenames, defaultFileName, defaultFileName as defaultSettingsFilename, determineFinalDocumentSettings, extractDependencies, extractImportErrors, fileToDocument, fileToTextDocument, finalizeSettings, getCachedFileSize, getDefaultBundledSettingsAsync, getDefaultSettings, getDictionary, getGlobalSettings, getLanguagesForBasename as getLanguageIdsForBaseFilename, getLanguagesForExt, getLogger, getSources, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, loadConfig, loadPnP, loadPnPSync, mergeInDocSettings, mergeSettings, readRawSettings, readSettings, readSettingsFiles, refreshDictionaryCache, resolveFile, searchForConfig, sectionCSpell, setLogger, shouldCheckDocument, spellCheckDocument, spellCheckFile, suggestionsForWord, suggestionsForWords, traceWords, traceWordsAsync, updateTextDocument, validateText }; +export { type CheckTextInfo, type ConfigurationDependencies, type CreateTextDocumentParams, type DetermineFinalDocumentSettingsResult, type Document, DocumentValidator, type DocumentValidatorOptions, ENV_CSPELL_GLOB_ROOT, type ExcludeFilesGlobMap, type ExclusionFunction, exclusionHelper_d as ExclusionHelper, type FeatureFlag, FeatureFlags, ImportError, type ImportFileRefWithError, IncludeExcludeFlag, type IncludeExcludeOptions, index_link_d as Link, type Logger, type PerfTimer, type SpellCheckFileOptions, type SpellCheckFileResult, SpellingDictionaryLoadError, type SuggestedWord, SuggestionError, type SuggestionOptions, type SuggestionsForWordResult, text_d as Text, type TextDocument, type TextDocumentLine, type TextDocumentRef, type TextInfoItem, type TraceOptions, type TraceResult, UnknownFeatureFlagError, type ValidationIssue, calcOverrideSettings, checkFilenameMatchesGlob, checkText, checkTextDocument, clearCachedFiles, clearCaches, combineTextAndLanguageSettings, combineTextAndLanguageSettings as constructSettingsForText, createPerfTimer, createTextDocument, currentSettingsFileVersion, defaultConfigFilenames, defaultFileName, defaultFileName as defaultSettingsFilename, determineFinalDocumentSettings, extractDependencies, extractImportErrors, fileToDocument, fileToTextDocument, finalizeSettings, getCachedFileSize, getDefaultBundledSettingsAsync, getDefaultSettings, getDictionary, getGlobalSettings, getGlobalSettingsAsync, getLanguagesForBasename as getLanguageIdsForBaseFilename, getLanguagesForExt, getLogger, getSources, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, loadConfig, loadPnP, loadPnPSync, mergeInDocSettings, mergeSettings, readRawSettings, readSettings, readSettingsFiles, refreshDictionaryCache, resolveFile, searchForConfig, sectionCSpell, setLogger, shouldCheckDocument, spellCheckDocument, spellCheckFile, suggestionsForWord, suggestionsForWords, traceWords, traceWordsAsync, updateTextDocument, validateText }; diff --git a/packages/cspell/src/app/application.ts b/packages/cspell/src/app/application.ts index 7cf3f3b6181..a9988dfc3c5 100644 --- a/packages/cspell/src/app/application.ts +++ b/packages/cspell/src/app/application.ts @@ -4,7 +4,7 @@ import type { CheckTextInfo, FeatureFlags, SuggestionsForWordResult, TraceResult import { checkTextDocument, getDefaultSettings, - getGlobalSettings, + getGlobalSettingsAsync, mergeSettings, SuggestionError, suggestionsForWords, From e6aebdf24d26bda550468b628895eb574dad9e77 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Sat, 25 Nov 2023 17:45:44 -0700 Subject: [PATCH 5/9] fix lint issues --- .../src/lib/Settings/Controller/configLoader/configLoader.ts | 4 ---- .../Settings/Controller/configLoader/configToRawSettings.ts | 5 ++++- packages/cspell-lib/src/lib/textValidation/docValidator.ts | 1 - 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts index 5f99fc509e0..f4c5619e43c 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts @@ -522,10 +522,6 @@ function createIO(cspellIO: CSpellIO): IO { }; } -export function urlToSimpleId(url: URL): string { - return url.pathname.split('/').slice(-2).join('/'); -} - export const __testing__ = { getDefaultConfigLoaderInternal, normalizeCacheSettings, diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configToRawSettings.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configToRawSettings.ts index 6eb55e27d38..a19cba5b448 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configToRawSettings.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configToRawSettings.ts @@ -2,7 +2,6 @@ import type { ImportFileRef, Source } from '@cspell/cspell-types'; import type { CSpellConfigFile } from 'cspell-config-lib'; import { toFilePathOrHref } from '../../../util/url.js'; -import { urlToSimpleId } from './configLoader.js'; import { normalizeImport, normalizeRawConfig } from './normalizeRawSettings.js'; import type { CSpellSettingsWST } from './types.js'; @@ -41,3 +40,7 @@ export function configToRawSettings(cfgFile: CSpellConfigFile | undefined): CSpe return rawSettings; } + +function urlToSimpleId(url: URL): string { + return url.pathname.split('/').slice(-2).join('/'); +} diff --git a/packages/cspell-lib/src/lib/textValidation/docValidator.ts b/packages/cspell-lib/src/lib/textValidation/docValidator.ts index 1217a5125c5..dcd3abbd57d 100644 --- a/packages/cspell-lib/src/lib/textValidation/docValidator.ts +++ b/packages/cspell-lib/src/lib/textValidation/docValidator.ts @@ -10,7 +10,6 @@ import type { import { IssueType } from '@cspell/cspell-types'; import assert from 'assert'; import { GlobMatcher } from 'cspell-glob'; -import path from 'path'; import type { CSpellSettingsInternal, CSpellSettingsInternalFinalized } from '../Models/CSpellSettingsInternalDef.js'; import type { ExtendedSuggestion } from '../Models/Suggestion.js'; From b1d0c0abab28c747c4249515eb8a5dd45684b5bf Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Sun, 26 Nov 2023 09:23:18 -0700 Subject: [PATCH 6/9] fix loader --- .../Controller/configLoader/configSearch.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configSearch.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configSearch.ts index 518964fdc87..26bb2a3bf3e 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configSearch.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configSearch.ts @@ -112,15 +112,23 @@ export class ConfigSearch { const found = await hasFile(file); if (found) { if (path.basename(file) !== 'package.json') return file; - const content = await readFile(file, 'utf8'); - const pkg = JSON.parse(content); - if (typeof pkg.cspell === 'object') return file; + if (await checkPackageJson(file)) return file; } } return undefined; } } +async function checkPackageJson(filename: string): Promise { + try { + const content = await readFile(filename, 'utf8'); + const pkg = JSON.parse(content); + return typeof pkg.cspell === 'object'; + } catch (e) { + return false; + } +} + async function isDirectory(path: string | URL): Promise { try { return (await stat(path)).isDirectory(); From 9a697d508ea23df87c2946b1606054b2da2442c3 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Sun, 26 Nov 2023 09:26:10 -0700 Subject: [PATCH 7/9] fix snapshot --- integration-tests/snapshots/eslint/eslint/report.yaml | 4 ++-- integration-tests/snapshots/eslint/eslint/snapshot.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/integration-tests/snapshots/eslint/eslint/report.yaml b/integration-tests/snapshots/eslint/eslint/report.yaml index 708218edf13..d7e5771f83c 100644 --- a/integration-tests/snapshots/eslint/eslint/report.yaml +++ b/integration-tests/snapshots/eslint/eslint/report.yaml @@ -4,8 +4,8 @@ Url: https://github.com/eslint/eslint Args: '["**","--exclude=bin/**","--exclude=CHANGELOG.md","--exclude=_data","--exclude=tests/bench/large.js","--exclude=docs/src/_includes","--exclude=docs/src/assets/{fonts,s?css,images}"]' Summary: files: 1898 - filesWithIssues: 1257 - issues: 5490 + filesWithIssues: 1258 + issues: 5491 errors: 0 Errors: [] diff --git a/integration-tests/snapshots/eslint/eslint/snapshot.txt b/integration-tests/snapshots/eslint/eslint/snapshot.txt index 4d17c7dc4d2..a99e5e0f077 100644 --- a/integration-tests/snapshots/eslint/eslint/snapshot.txt +++ b/integration-tests/snapshots/eslint/eslint/snapshot.txt @@ -3,7 +3,7 @@ Repository: eslint/eslint Url: "https://github.com/eslint/eslint" Args: ["**","--exclude=bin/**","--exclude=CHANGELOG.md","--exclude=_data","--exclude=tests/bench/large.js","--exclude=docs/src/_includes","--exclude=docs/src/assets/{fonts,s?css,images}"] Lines: - CSpell: Files checked: 1898, Issues found: 5490 in 1257 files + CSpell: Files checked: 1898, Issues found: 5491 in 1258 files exit code: 1 ./Makefile.js:144:88 - Unknown word (ined) -- followed by the string "ined". ./Makefile.js:150:48 - Unknown word (blogpost) -- render(cat("./templates/blogpost.md.ejs"), renderContext From 627c5911db7e134a0ca3ca388adff1d78e879730 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Sun, 26 Nov 2023 11:50:36 -0700 Subject: [PATCH 8/9] Update integration test --- integration-tests/config/config.json | 4 +- .../config/eslint/cspell.config.yaml | 78 ++ .../snapshots/eslint/eslint/report.yaml | 758 +++++++++++++++--- .../snapshots/eslint/eslint/snapshot.txt | 100 +-- integration-tests/src/reporter/index.ts | 49 +- .../src/reporter/reportGenerator.ts | 11 + integration-tests/src/reporter/stringify.ts | 14 +- packages/cspell/src/app/application.ts | 2 +- packages/cspell/src/app/cli-reporter.ts | 11 +- packages/cspell/src/app/commandLint.ts | 1 + packages/cspell/src/app/lint/LintRequest.ts | 3 +- packages/cspell/src/app/options.ts | 5 + 12 files changed, 827 insertions(+), 209 deletions(-) create mode 100644 integration-tests/repositories/config/eslint/cspell.config.yaml diff --git a/integration-tests/config/config.json b/integration-tests/config/config.json index 8552e0692a2..b49ebb85dbd 100644 --- a/integration-tests/config/config.json +++ b/integration-tests/config/config.json @@ -323,7 +323,9 @@ "path": "eslint/eslint", "url": "https://github.com/eslint/eslint", "args": [ - "**", + ".", + "--config=../../../config/eslint/cspell.config.yaml", + "--issues-summary-report", "--exclude=bin/**", "--exclude=CHANGELOG.md", "--exclude=_data", diff --git a/integration-tests/repositories/config/eslint/cspell.config.yaml b/integration-tests/repositories/config/eslint/cspell.config.yaml new file mode 100644 index 00000000000..e7098cc2d7a --- /dev/null +++ b/integration-tests/repositories/config/eslint/cspell.config.yaml @@ -0,0 +1,78 @@ +import: + - ../../cspell.yaml +words: + - autofix + - autofixes + - autofixer + - autofixed + - autofixable + - autofixing + - backreferences + - backreference + - builtins + - camelcase + - camelcased + - checkstyle + - classname + - codebase + - codebases + - codeframe + - dosomething + - doublecircle + - doublequote + - eqeqeq + - eslintconfig + - eslintplugin + - eslintignore + - espree + - escope + - esquery + - eslintrc + - eslintrcjson + - eslintrcyaml + - eslintrcjs + - eslintrcjson + - eslintrcyaml + - eslintrcjs + - fileoverview + - fillcolor + - fixedsize + - fixedmode + - gitignores + - globalstrict + - hashbang + - hashbangs + - iife + - iifes + - imurmurhash + - instanceof + - linebreak + - linebreaks + - autocrlf + - concat + - hiddenfolder + - hola + - lookaround + - lookbehinds + - multipass + - parenthesised + - pluggable + - postprocess + - postprocessed + - preprocess + - redeclaration + - redeclarations + - redeclared + - regexpp + - rulesdir + - rulesdirs + - singlequote + - testcase + - testcases + - testsuite + - testsuites + - typedefs + - unignore + - unignored + - unignores + - unparenthesized diff --git a/integration-tests/snapshots/eslint/eslint/report.yaml b/integration-tests/snapshots/eslint/eslint/report.yaml index d7e5771f83c..1280ad775fd 100644 --- a/integration-tests/snapshots/eslint/eslint/report.yaml +++ b/integration-tests/snapshots/eslint/eslint/report.yaml @@ -1,30 +1,26 @@ --- Repository: eslint/eslint Url: https://github.com/eslint/eslint -Args: '["**","--exclude=bin/**","--exclude=CHANGELOG.md","--exclude=_data","--exclude=tests/bench/large.js","--exclude=docs/src/_includes","--exclude=docs/src/assets/{fonts,s?css,images}"]' +Args: '[".","--config=../../../config/eslint/cspell.config.yaml","--issues-summary-report","--exclude=bin/**","--exclude=CHANGELOG.md","--exclude=_data","--exclude=tests/bench/large.js","--exclude=docs/src/_includes","--exclude=docs/src/assets/{fonts,s?css,images}"]' Summary: files: 1898 - filesWithIssues: 1258 - issues: 5491 + filesWithIssues: 401 + issues: 2191 errors: 0 Errors: [] issues: - - "conf/config-schema.js:8:63 nzakas U file, please contact @nzakas first." - - "conf/config-schema.js:14:5 fileoverview U * @fileoverview Defines a schema for" + - "conf/config-schema.js:8:63 nzakas U file, please contact @nzakas first." - "conf/replacements.json:12:36 parens U wrap-func\": [\"no-extra-parens\"]," - "conf/replacements.json:13:62 paren U space-before-function-paren\"]," - - "docs/_examples/custom-rule-tutorial-code/package.json:8:6 eslintplugin U \"eslintplugin\"," - "docs/package.json:30:32 syntaxhighlight U 1ty/eleventy-plugin-syntaxhighlight\": \"^5.0.0\"," - "docs/package.json:31:11 munter U \"@munter/tap-render\": \"^0.2." - "docs/package.json:33:10 algoliasearch U \"algoliasearch\": \"^4.12.1\"," - "docs/package.json:46:10 luxon U \"luxon\": \"^2.4.0\"," - "docs/package.json:54:10 prismjs U \"prismjs\": \"^1.29.0\"," - - "docs/README.md:37:4 autofix U To autofix JS files, run this from" - "docs/README.md:45:51 openjsf U ESLint contributors, [www.openjsf.org](https://www.openjsf" - "docs/src/_plugins/md-syntax-highlighter.js:4:29 Yuxi U Copyright (c) 2019-present, Yuxi (Evan) You" - - "docs/src/about/index.md:6:87 Zakas U created by Nicholas C. Zakas in June 2013. Code" - - "docs/src/about/index.md:10:146 pluggable U all rules completely pluggable. The default rules are" + - "docs/src/about/index.md:6:87 Zakas U created by Nicholas C. Zakas in June 2013. Code" - "docs/src/assets/js/components-index.js:17:14 toggleindex U function toggleindex(e) {" - "docs/src/assets/js/css-vars-ponyfill@2.js:2:13 ponyfill U * css-vars-ponyfill" - "docs/src/assets/js/css-vars-ponyfill@2.js:5:23 Hildenbiddle U (c) 2018-2019 John Hildenbiddle {" - "docs/src/rules/arrow-parens.md:15:79 arity U parameters regardless of arity. For example:" - "docs/src/rules/brace-style.md:25:54 Stroustrup U brace style is called Stroustrup, in which the `else" - "docs/src/rules/brace-style.md:36:26 Allman U Another style is called [Allman](https://en.wikipedia" - "docs/src/rules/brace-style.md:60:5 stroustrup U * `\"stroustrup\"` enforces Stroustrup" - "docs/src/rules/brace-style.md:61:5 allman U * `\"allman\"` enforces Allman style" - - "docs/src/rules/callback-return.md:152:163 IIFE U function expression (IIFE)." - - "docs/src/rules/camelcase.md:36:13 camelcased U import { no_camelcased } from \"external-module" - - "docs/src/rules/camelcase.md:52:18 Camelcased U function bar({ isCamelcased: no_camelcased }) {" - "docs/src/rules/capitalized-comments.md:272:84 blockignore U { \"ignorePattern\": \"blockignore\" } }] */" - "docs/src/rules/comma-dangle.md:13:11 quux U qux: \"quux\"," - "docs/src/rules/complexity.md:21:1 Cyclomatic U Cyclomatic complexity measures" - "docs/src/rules/complexity.md:21:133 cyclomatic U rule allows setting a cyclomatic complexity threshold" - - "docs/src/rules/consistent-return.md:76:16 instanceof U if (!(this instanceof Foo)) {" - - "docs/src/rules/eqeqeq.md:2:8 eqeqeq U title: eqeqeq" - "docs/src/rules/eqeqeq.md:39:150 typeof U of the operands is a `typeof` expression, or if both" - "docs/src/rules/function-paren-newline.md:338:5 barbaz U var barbaz = function(" - "docs/src/rules/generator-star-spacing.md:85:40 configurability U rule allows further configurability via overrides per function" - - "docs/src/rules/guard-for-in.md:6:16 builtins U - no-prototype-builtins" - - "docs/src/rules/guard-for-in.md:21:5 codebases U For codebases that do not support" - "docs/src/rules/id-denylist.md:7:102 Karlton U naming things.\" — Phil Karlton" - "docs/src/rules/id-length.md:93:10 foobaz U function foobaz({ a: prop }) { }" - "docs/src/rules/indent-legacy.md:28:16 Crockford U * Four spaces: Crockford" - "docs/src/rules/indent-legacy.md:91:76 declarators U indentation level for `var` declarators; can also take an object" - - "docs/src/rules/indent-legacy.md:92:76 IIFEs U level for file-level IIFEs." - "docs/src/rules/indent-legacy.md:405:8 boop U qux, boop) {" - "docs/src/rules/key-spacing.md:194:5 bcde U bcde: 42," - "docs/src/rules/key-spacing.md:216:5 ijkl U ijkl: 'Non-consecutive lines" - - "docs/src/rules/lines-around-comment.md:36:10 Hashbang U * `\"afterHashbangComment\": true` requires" - - "docs/src/rules/lines-around-comment.md:36:63 hashbang U an empty line after hashbang comments" - "docs/src/rules/max-lines-per-function.md:31:45 dbname U return m(\"tr\", {key: db.dbname}, [" - "docs/src/rules/no-buffer-constructor.md:13:407 alloc U Buffer.from`, `Buffer.alloc`, and `Buffer.allocUnsafe" - "docs/src/rules/no-cond-assign.md:2:11 cond U title: no-cond-assign" @@ -148,10 +113,7 @@ issues: - "docs/src/rules/no-empty-character-class.md:40:13 abcefg U regex.test(\"abcefg\"); // false, the nested" - "docs/src/rules/no-eq-null.md:61:41 eqnull U rule corresponds to `eqnull` rule of JSHint." - "docs/src/rules/no-extend-native.md:74:34 muhahaha U prototype.forEach = 'muhahaha'\");" - - "docs/src/rules/no-extra-parens.md:21:172 iife U conflicts with the [wrap-iife](wrap-iife) rule" - "docs/src/rules/no-fallthrough.md:59:12 fallsthrough U // fallsthrough" - - "docs/src/rules/no-implicit-globals.md:24:3 Redeclarations U * Redeclarations of read-only global" - - "docs/src/rules/no-implicit-globals.md:119:26 redeclarations U rule also disallows redeclarations of read-only global" - "docs/src/rules/no-irregular-whitespace.md:45:2 ufeff U \\ufeff - Zero Width No-Break" - "docs/src/rules/no-irregular-whitespace.md:57:30 ZWSP U Zero Width Space - " - "docs/src/rules/no-loop-func.md:11:5 funcs U funcs[i] = function() {" @@ -162,8 +124,7 @@ issues: - "docs/src/rules/no-plusplus.md:2:11 plusplus U title: no-plusplus" - "docs/src/rules/no-proto.md:2:11 proto U title: no-proto" - "docs/src/rules/no-prototype-builtins.md:10:216 webserver U would be unsafe for a webserver to parse JSON input" - - "docs/src/rules/no-redeclare.md:5:68 redeclares U TypeScript will catch `let` redeclares and `const` redeclares" - - "docs/src/rules/no-redeclare.md:72:41 redeclaration U this rule also checks redeclaration of built-in globals" + - "docs/src/rules/no-redeclare.md:5:68 redeclares U TypeScript will catch `let` redeclares and `const` redeclares" - "docs/src/rules/no-restricted-globals.md:28:54 fdescribe U [\"error\", \"event\", \"fdescribe\"]" - "docs/src/rules/no-restricted-imports.md:125:64 dgram U \"cluster\",\"crypto\",\"dgram\",\"dns\",\"domain\",\"events" - "docs/src/rules/no-restricted-imports.md:125:96 freelist U ,\"domain\",\"events\",\"freelist\",\"fs\",\"http\",\"https" @@ -176,14 +137,9 @@ issues: - "docs/src/rules/no-script-url.md:29:41 scripturl U rule corresponds to `scripturl` rule of JSHint." - "docs/src/rules/no-unexpected-multiline.md:14:78 Schlueter U once described by Isaac Schlueter, a newline character" - "docs/src/rules/no-unsafe-finally.md:44:69 rethrown U block is caught and rethrown" - - "docs/src/rules/no-unsafe-finally.md:119:22 hola U console.log(\"hola!\");" - "docs/src/rules/no-unused-vars.md:55:31 destructures U function definition destructures an array, unused entries" - "docs/src/rules/no-unused-vars.md:160:67 gnored U varsIgnorePattern\": \"[iI]gnored\" }` option:" - "docs/src/rules/no-use-before-define.md:160:21 nofunc U This rule accepts `\"nofunc\"` string as an option" - - "docs/src/rules/no-useless-backreference.md:14:337 lookaround U is inside a negative lookaround. However, by the specificatio" - - "docs/src/rules/no-useless-backreference.md:16:1 Backreferences U Backreferences that always successfully" - - "docs/src/rules/no-useless-backreference.md:36:53 backreferences U disallow the following backreferences in regular expression" - - "docs/src/rules/no-useless-backreference.md:39:178 lookbehinds U forward references. Inside lookbehinds, which match backward" - "docs/src/rules/nonblock-statement-body-position.md:2:8 nonblock U title: nonblock-statement-body-position" - "docs/src/rules/object-property-newline.md:74:12 bazz U + bar: \"bazz\"," - "docs/src/rules/object-property-newline.md:124:24 colocation U The rule prohibits the colocation on any line of at least" @@ -204,7 +160,6 @@ issues: - "docs/src/rules/one-var.md:428:9 fooqux U let fooqux, foonorf;" - "docs/src/rules/one-var.md:428:17 foonorf U let fooqux, foonorf;" - "docs/src/rules/one-var.md:725:38 onevar U This rule maps to the `onevar` JSHint rule, but allows" - - "docs/src/rules/padding-line-between-statements.md:37:24 LINEBREAK U { \"blankLine\": LINEBREAK_TYPE, \"prev\": STATEMENT" - "docs/src/rules/padding-line-between-statements.md:81:9 singleline U * `\"singleline-const\"` is single-line" - "docs/src/rules/prefer-named-capture-group.md:21:19 cauli U const regex = /(?:cauli|sun)flower/;" - "docs/src/rules/radix.md:10:305 autodetected U , `parseInt()` also autodetected octal literals, which" @@ -226,9 +181,6 @@ issues: - "docs/src/use/command-line-interface.md:277:68 levn U configuration specified with [levn](https://github.com" - "docs/src/use/command-line-interface.md:428:5 myfile U cat myfile.js | npx eslint --stdin" - "docs/src/use/command-line-interface.md:520:17 customformat U npx eslint -f ./customformat.js file.js" - - "docs/src/use/command-line-interface.md:605:1 Autofixed U Autofixed files are not placed" - - "docs/src/use/configure/configuration-files-new.md:181:14 unignore U You can also unignore files and directories" - - "docs/src/use/configure/configuration-files-new.md:181:112 unignores U example, this config unignores `node_modules/mylibrary" - "docs/src/use/configure/configuration-files-new.md:181:136 mylibrary U unignores `node_modules/mylibrary`:" - "docs/src/use/configure/configuration-files-new.md:268:564 runtimes U example, some older runtimes might only allow ECMAScript" - "docs/src/use/configure/configuration-files.md:45:25 myfiletotest U eslint -c myconfig.json myfiletotest.js" @@ -253,12 +205,6 @@ issues: - "docs/src/use/configure/migration-guide.md:550:42 dotfile U config, dotfiles (e.g. `.dotfile.js`) are no longer ignored" - "docs/src/use/configure/plugins.md:44:152 pluginname U require('eslint-plugin-pluginname')` in the config file" - "docs/src/use/configure/rules.md:25:294 buildtime U other than a potential buildtime or runtime error (such" - - "docs/src/use/formatters/index.md:17:4 checkstyle U * [checkstyle](#checkstyle)" - - "docs/src/use/formatters/index.md:70:25 Checkstyle U Outputs results to the [Checkstyle](https://checkstyle" - - "docs/src/use/formatters/index.md:893:2 testsuites U " - - "docs/src/use/formatters/index.md:894:2 testsuite U The `CLIEngine" - "docs/src/use/migrating-from-jscs.md:12:111 jscsrs U .jscsrc.yaml`, or `.jscsrs.js`. In ESLint, the" - "docs/src/use/migrating-from-jscs.md:15:38 Polyjuice U Configuration Files Using Polyjuice" @@ -278,12 +223,10 @@ issues: - "docs/src/use/migrating-to-2.0.0.md:347:45 FEFF U parse(text.replace(/^\\uFEFF/, \"\"), options);" - "docs/src/use/migrating-to-3.0.0.md:47:229 lifed U Explorer 8 was end-of-lifed](https://www.microsoft" - "docs/src/use/migrating-to-5.0.0.md:114:68 lintable U line does not match any lintable files" - - "lib/cli-engine/cli-engine.js:47:4 Typedefs U // Typedefs" - "lib/cli-engine/formatters/html.js:46:48 Neue U family: Arial, \"Helvetica Neue\", Helvetica, sans-serif" - "lib/cli-engine/formatters/html.js:247:66 noopener U target=\"_blank\" rel=\"noopener noreferrer\">${ruleId" - "lib/cli-engine/formatters/html.js:247:75 noreferrer U blank\" rel=\"noopener noreferrer\">${ruleId ? ruleId" - "lib/cli-engine/formatters/html.js:303:9 colspan U " - - "lib/cli-engine/hash.js:12:25 imurmurhash U const murmur = require(\"imurmurhash\");" - "lib/cli-engine/lint-result-cache.js:14:58 jsonify U stable-stringify-without-jsonify\");" - "lib/cli-engine/xml-escape.js:29:26 apos U return \"'\";" - "lib/cli.js:27:38 humanwhocodes U ModuleImporter } = require(\"@humanwhocodes/module-importer\");" @@ -297,14 +240,10 @@ issues: - "lib/linter/code-path-analysis/code-path-state.js:774:31 unflattened U {CodePathSegment[]} unflattenedFromSegments Segments" - "lib/linter/code-path-analysis/code-path-state.js:1256:46 circuting U path due to the short-circuting, so we are just seeding" - "lib/linter/code-path-analysis/code-path-state.js:1730:23 Segs U const prevSegsOfLeavingSegment = [headOfLeav" - - "lib/linter/code-path-analysis/debug-helpers.js:95:44 Graphvis U can be visualized with Graphvis." - - "lib/linter/code-path-analysis/debug-helpers.js:105:54 fillcolor U style=\\\"rounded,filled\\\",fillcolor=white];\\n\" +" - - "lib/linter/code-path-analysis/debug-helpers.js:109:45 doublecircle U final[label=\\\"\\\",shape=doublecircle,style=filled,fillcolor" - - "lib/linter/code-path-analysis/debug-helpers.js:112:75 fixedsize U width=0.3,height=0.3,fixedsize=true];\\n\";" + - "lib/linter/code-path-analysis/debug-helpers.js:95:44 Graphvis U can be visualized with Graphvis." - "lib/linter/config-comment-parser.js:82:22 commaless U // Also, commaless notations have invalid" - "lib/linter/config-comment-parser.js:93:20 Levn U debug(\"Levn parsing failed; falling" - "lib/linter/config-comment-parser.js:99:12 Optionator U * Optionator cannot parse commaless" - - "lib/linter/linter.js:48:11 AUTOFIX U const MAX_AUTOFIX_PASSES = 10;" - "lib/linter/linter.js:113:52 postprocessor U postprocess} [postprocess] postprocessor for report" - "lib/linter/linter.js:918:18 SOURCECODE U const DEPRECATED_SOURCECODE_PASSTHROUGHS = {" - "lib/linter/linter.js:918:29 PASSTHROUGHS U DEPRECATED_SOURCECODE_PASSTHROUGHS = {" @@ -312,10 +251,6 @@ issues: - "lib/rule-tester/flat-rule-tester.js:236:42 errorize U ast The root node to errorize `start`/`end` properties" - "lib/rule-tester/flat-rule-tester.js:791:27 Didnt (Didn't) U function assertASTDidntChange(beforeAST, afterAST" - "lib/rule-tester/rule-tester.js:10:52 unittests U mocha to allow for DRY unittests for eslint" - - "lib/rules/array-bracket-newline.js:54:30 Linebreak U unexpectedOpeningLinebreak: \"There should be no" - - "lib/rules/array-bracket-newline.js:207:24 Linebreaks U const needsLinebreaks = (" - - "lib/rules/array-callback-return.js:163:21 Parenthesised U !astUtils.isParenthesised(sourceCode, node);" - - "lib/rules/arrow-body-style.js:230:33 parenthesised U let parenthesisedObjectLiteral = null" - "lib/rules/dot-notation.js:138:63 quasis U node, node.property.quasis[0].value.cooked);" - "lib/rules/for-direction.js:73:65 nochange U if sub return -1, if nochange, return 0" - "lib/rules/func-name-matching.js:13:7 esutils U const esutils = require(\"esutils\"" @@ -324,7 +259,6 @@ issues: - "lib/rules/indent-legacy.js:573:43 IIEF U that the node is an IIEF" - "lib/rules/indent-legacy.js:918:66 blockless U for indentation for blockless nodes" - "lib/rules/indent.js:902:21 Blockless U function addBlocklessNodeIndent(node) {" - - "lib/rules/jsx-quotes.js:22:23 singlequote U description: \"singlequote\"," - "lib/rules/keyword-spacing.js:151:18 unexpect U function unexpectSpaceBefore(token, pattern" - "lib/rules/lines-around-comment.js:23:22 Nums U function getEmptyLineNums(lines) {" - "lib/rules/logical-assignment-operators.js:115:4 falsiness U * falsiness checks: !value, !Boolean" @@ -332,7 +266,6 @@ issues: - "lib/rules/no-caller.js:38:106 calle U propertyName.match(/^calle[er]$/u)) {" - "lib/rules/no-constant-binary-expression.js:35:59 nullishness U statically knowable constant nullishness. Meaning," - "lib/rules/no-constant-binary-expression.js:44:21 Nullishness U function hasConstantNullishness(scope, node, nonNullish" - - "lib/rules/no-control-regex.js:8:52 regexpp U require(\"@eslint-community/regexpp\").RegExpValidator;" - "lib/rules/no-else-return.js:80:16 Redeclaring U * Redeclaring any of these would cause" - "lib/rules/no-else-return.js:315:50 codepath U node returns in every codepath." - "lib/rules/no-else-return.js:351:19 consequents U const consequents = [];" @@ -342,7 +275,6 @@ issues: - "lib/rules/no-extra-parens.js:260:52 newed U constructor function is newed-up with parens" - "lib/rules/no-extra-parens.js:559:28 logicals U * Evaluate binary logicals" - "lib/rules/no-extra-parens.js:565:19 prec U const prec = precedence(node);" - - "lib/rules/no-extra-parens.js:806:81 unparenthesized U left-hand side is an *unparenthesized*" - "lib/rules/no-implicit-coercion.js:14:39 ndex U PATTERN = /^(?:i|lastI)ndexOf$/u;" - "lib/rules/no-inline-comments.js:61:17 postamble U postamble = endLine.slice(node" - "lib/rules/no-inline-comments.js:63:19 Postamble U isPostambleEmpty = !postamble;" @@ -351,30 +283,22 @@ issues: - "lib/rules/no-mixed-requires.js:182:62 Declarators U The list of VariableDeclarators." - "lib/rules/no-new-native-nonconstructor.js:32:18 Nonconstructor U noNewNonconstructor: \"`{{name}}` cannot" - "lib/rules/no-trailing-spaces.js:60:13 NONBLANK U NONBLANK = `${BLANK_CLASS}+$" - - "lib/rules/no-useless-backreference.js:43:12 Lookaround U function isLookaround(node) {" - - "lib/rules/no-useless-backreference.js:75:40 bref U \"Backreference '{{ bref }}' will be ignored" - - "lib/rules/no-useless-backreference.js:114:37 bref's U // group is bref's ancestor => bref is" + - "lib/rules/no-useless-backreference.js:75:40 bref U \"Backreference '{{ bref }}' will be ignored" + - "lib/rules/no-useless-backreference.js:114:37 bref's U // group is bref's ancestor => bref is" - "lib/rules/no-useless-escape.js:32:47 nrvtbfux U ESCAPES = union(new Set(\"\\\\nrvtbfux\"), astUtils.LINEBREAKS" - - "lib/rules/no-useless-escape.js:32:68 LINEBREAKS U nrvtbfux\"), astUtils.LINEBREAKS);" - "lib/rules/no-useless-escape.js:33:45 Dfnp U ESCAPES = new Set(\"\\\\bcdDfnpPrsStvwWxu0123456789" - "lib/rules/no-useless-escape.js:33:52 Stvw U new Set(\"\\\\bcdDfnpPrsStvwWxu0123456789]\");" - "lib/rules/no-useless-escape.js:34:17 CHARCLASS U const REGEX_NON_CHARCLASS_ESCAPES = union(REGEX" - "lib/rules/no-useless-escape.js:40:13 CLASSSET U const REGEX_CLASSSET_CHARACTER_ESCAPES =" - - "lib/rules/no-var.js:102:12 Redeclared U function isRedeclared(variable) {" - "lib/rules/object-shorthand.js:102:34 Longform U expectedLiteralMethodLongform: \"Expected longform" - "lib/rules/object-shorthand.js:102:54 longform U eralMethodLongform: \"Expected longform method syntax for string" - "lib/rules/prefer-object-spread.js:61:42 sourcecode U sourceCode in context sourcecode object" - - "lib/rules/prefer-object-spread.js:173:4 Autofixes U * Autofixes the Object.assign call" - - "lib/rules/prefer-object-spread.js:176:24 autofixer U @returns {Function} autofixer - replaces the Object" - - "lib/rules/prefer-regex-literals.js:16:9 REGEXPP U const { REGEXPP_LATEST_ECMA_VERSION" - - "lib/rules/prefer-regex-literals.js:246:21 Regexpp U function getRegexppEcmaVersion(ecmaVersion" - "lib/rules/quotes.js:42:17 unescaping U * escaping and unescaping as necessary." - "lib/rules/sort-vars.js:53:23 unfixable U const unfixable = idDeclarations.some" - "lib/rules/space-unary-ops.js:133:28 Doesnt (Doesn't) U function verifyWordDoesntHaveSpaces(node, firstToken" - "lib/rules/space-unary-ops.js:246:32 Dont U function verifyNonWordsDontHaveSpaces(node, firstToken" - - "lib/rules/utils/ast-utils.js:396:40 samely U a.b` and `a?.b` are samely." - - "lib/rules/utils/ast-utils.js:1041:89 braket U opening parenthesis or braket." - - "lib/rules/utils/ast-utils.js:2136:80 hashbangs U ESLint itself handles hashbangs." + - "lib/rules/utils/ast-utils.js:396:40 samely U a.b` and `a?.b` are samely." + - "lib/rules/utils/ast-utils.js:1041:89 braket U opening parenthesis or braket." - "lib/rules/utils/patterns/letters.js:12:24 Dulin U Copyright 2013-2016 Dulin Marat and other contributors" - "lib/shared/config-validator.js:286:55 ECMAFEATURES U source, \"ESLINT_LEGACY_ECMAFEATURES\");" - "lib/shared/string-utils.js:12:7 Graphemer U const Graphemer = require(\"graphemer" @@ -426,12 +350,7 @@ issues: - "tests/fixtures/rules/indent-legacy/indent-invalid-fixture-1.js:440:40 youll U terribly long description youll ' +" - "tests/lib/cli-engine/cli-engine.js:410:37 layou U fixTypes: [\"layou\"]" - "tests/lib/cli-engine/cli-engine.js:621:44 foothis U output: \"var bar = foothis is a syntax error.\"" - - "tests/lib/cli-engine/cli-engine.js:1072:60 hiddenfolder U executeOnFiles([\"hidden/.hiddenfolder/*.js\"]);" - - "tests/lib/cli-engine/cli-engine.js:1174:52 unignored U hidden files if they are unignored with an --ignore-pattern" - - "tests/lib/cli-engine/cli-engine.js:1648:60 rulesdirs U etFixturePath(\"rules\", \"multi-rulesdirs.json\")" - - "tests/lib/cli-engine/cli-engine.js:1813:51 autocrlf U workaround for git's autocrlf option on Windows." - "tests/lib/cli-engine/cli-engine.js:1836:95 fixmode U fixtureDir, `${fixtureDir}/fixmode`)]);" - - "tests/lib/cli-engine/cli-engine.js:4415:115 Unignored U , \".eslintignoreWithUnignoredDefaults\") });" - "tests/lib/cli-engine/cli-engine.js:4500:53 sampleignorepattern U eslintignore` includes `sampleignorepattern`." - "tests/lib/cli-engine/cli-engine.js:4847:51 somenamespace U engine.getFormatter(\"@somenamespace/foo\");" - "tests/lib/cli-engine/cli-engine.js:4863:63 doesntexist U getFixturePath(\"formatters\", \"doesntexist.js\")," @@ -450,15 +369,12 @@ issues: - "tests/lib/eslint/flat-eslint.js:1687:30 reignoring U it(\"should allow reignoring of previously ignored" - "tests/lib/eslint/flat-eslint.js:5316:31 reignore U cwd: `${root}-reignore`," - "tests/lib/eslint/flat-eslint.js:5356:31 dignore U cwd: `${root}-dignore`," - - "tests/lib/linter/code-path-analysis/code-path-analyzer.js:30:16 ESQUERY U const STANDARD_ESQUERY_OPTION = { visitorKeys" - "tests/lib/linter/config-comment-parser.js:165:41 ELEVENTEEN U code = \"a: seventy, b:ELEVENTEEN\";" - "tests/lib/linter/linter.js:3550:1 consolexlog U consolexlog(\"test2\");" - "tests/lib/linter/linter.js:3696:84 rulename U this is 2, since the rulename is very likely to be" - "tests/lib/linter/linter.js:5692:31 suppresed U it(\"should report one suppresed problem when noInlineConfig" - "tests/lib/linter/linter.js:7851:19 postprocessors U describe(\"postprocessors\", () => {" - - "tests/lib/linter/linter.js:7904:28 postprocessed U it(\"should use postprocessed problem ranges when" - "tests/lib/linter/linter.js:17912:52 intentionaly U // intentionaly mutates objects and" - - "tests/lib/linter/node-event-generator.js:25:7 ESPREE U const ESPREE_CONFIG = {" - "tests/lib/linter/node-event-generator.js:298:68 pseudoclasses U // 0 identifiers, 0 pseudoclasses" - "tests/lib/linter/node-event-generator.js:304:66 pseudoclass U ].expression], // 1 pseudoclass, 0 identifiers" - "tests/lib/linter/report-translator.js:337:32 fooo U text: \"fooo\\nbar\"" @@ -473,16 +389,14 @@ issues: - "tests/lib/rule-tester/flat-rule-tester.js:1104:36 somefile U filename: \"somefile.js\"" - "tests/lib/rule-tester/flat-rule-tester.js:2309:33 outpt U outpt: \"var baz;\"" - "tests/lib/rule-tester/flat-rule-tester.js:2744:15 Subclassing U describe(\"Subclassing\", () => {" - - "tests/lib/rules/array-bracket-newline.js:57:50 ndosomething U [\\nfunction foo() {\\ndosomething();\\n}\\n];\"," - "tests/lib/rules/array-bracket-spacing.js:51:47 n'qux U [{\\n'bar': 'baz', \\n'qux': [{ 'bar': 'baz' }" - "tests/lib/rules/array-bracket-spacing.js:51:76 n'quxx U { 'bar': 'baz' }], \\n'quxx': 1 \\n}]\", options:" - "tests/lib/rules/array-element-newline.js:45:78 nosomething U ,\\nfunction bar() {\\nosomething();\\n}\\n];\"," - "tests/lib/rules/arrow-body-style.js:27:38 nretv U = (retv, name) => {\\nretv[name] = true;\\nreturn" - "tests/lib/rules/brace-style.js:32:44 Varint U glyph.id = pbf.readVarint();\\nelse if (tag ==" - "tests/lib/rules/brace-style.js:103:35 fontstack U code: \"if (tag === 1) fontstack.name = pbf.readString" - - "tests/lib/rules/capitalized-comments.js:164:29 Fileoverview U code: \"/**\\n * @Fileoverview This is a file */\"," - - "tests/lib/rules/capitalized-comments.js:344:22 über U code: \"//über\"," - - "tests/lib/rules/capitalized-comments.js:345:24 Über U output: \"//Über\"," + - "tests/lib/rules/capitalized-comments.js:344:22 über U code: \"//über\"," + - "tests/lib/rules/capitalized-comments.js:345:24 Über U output: \"//Über\"," - "tests/lib/rules/comma-spacing.js:22:10 myfunc U \"myfunc(404, true/* bla bla" - "tests/lib/rules/comma-style.js:69:36 nsnd U code: \"var ar ={fst:1,\\nsnd: [1,\\n2]};\"," - "tests/lib/rules/comma-style.js:268:38 fifi U \"const arr = [\\n ,'fifi' \\n]\"," @@ -519,7 +433,6 @@ issues: - "tests/lib/rules/no-duplicate-imports.js:94:32 modns U code: \"import * as modns from \\\"lodash-es\\\";" - "tests/lib/rules/no-eval.js:41:29 noneval U { code: \"globalThis.noneval('foo')\", env: { es2" - "tests/lib/rules/no-extra-parens.js:781:32 ipaddr U code: \"const net = ipaddr.parseCIDR(/** @type" - - "tests/lib/rules/no-implicit-globals.js:26:15 Redeclaration U const readonlyRedeclarationMessage = \"Unexpected" - "tests/lib/rules/no-inline-comments.js:127:37 otherthing U ignorePattern: \"otherthing\"" - "tests/lib/rules/no-invalid-regexp.js:70:35 Nandinagari U RegExp('\\\\\\\\p{Script=Nandinagari}', 'u');\"," - "tests/lib/rules/no-invalid-regexp.js:74:35 Cpmn U RegExp('\\\\\\\\p{Script=Cpmn}', 'u')\"," @@ -532,14 +445,12 @@ issues: - "tests/lib/rules/no-invalid-regexp.js:82:35 Vithkuqi U RegExp('\\\\\\\\p{Script=Vithkuqi}', 'u')\"," - "tests/lib/rules/no-prototype-builtins.js:44:35 Enumerabl U code: \"foo?.['propertyIsEnumerabl']('bar')\", parserOptions" - "tests/lib/rules/no-prototype-builtins.js:233:52 Expresion U OwnProperty is part of a ChainExpresion" - - "tests/lib/rules/no-restricted-imports.js:50:31 Gitignores U code: \"import withGitignores from \\\"foo/bar\\\";\"," - "tests/lib/rules/no-restricted-imports.js:359:84 subimports U message: \"some foo subimports are restricted\" }]" - "tests/lib/rules/no-script-url.js:25:21 xjavascript U \"var url = 'xjavascript:'\"," - "tests/lib/rules/no-tabs.js:24:17 sdfdsf U \" // sdfdsf \\n\" +" - "tests/lib/rules/no-tabs.js:60:19 tsdfdsf U \" //\\tsdfdsf \\n\" +" - "tests/lib/rules/no-undefined.js:38:10 ndefined U \"ndefined\"," - "tests/lib/rules/no-unexpected-multiline.js:307:22 gimuygimuygimuy U /bar/gimuygimuygimuy.test(baz)" - - "tests/lib/rules/no-unsafe-finally.js:42:123 Hola U static ehm() { return 'Hola!'; } } } };\"," - "tests/lib/rules/no-unused-vars.js:957:32 fooz U code: \"/* global a$fooz,$foo */\\na$fooz;\"," - "tests/lib/rules/no-use-before-define.js:1129:17 mdjermanovic U * TODO(mdjermanovic): Add the following" - "tests/lib/rules/no-warning-comments.js:37:92 aeiou U options: [{ terms: [\"[aeiou]\"], location: \"anywhere" @@ -604,7 +515,6 @@ issues: - "tests/performance/jshint.js:1078:26 Kovalyov U Copyright 2012 Anton Kovalyov (http://jshint.com)" - "tests/performance/jshint.js:1125:6 anonname U var anonname, // The guessed name" - "tests/performance/jshint.js:1166:4 funcscope U funcscope : true, // if only" - - "tests/performance/jshint.js:1168:4 globalstrict U globalstrict: true, // if global" - "tests/performance/jshint.js:1169:4 immed U immed : true, // if" - "tests/performance/jshint.js:1172:4 lastsemic U lastsemic : true, // if semicolons" - "tests/performance/jshint.js:1174:4 laxbreak U laxbreak : true, // if line" @@ -738,3 +648,643 @@ issues: - "wdio.conf.js:224:76 initialise U spawned and can be used to initialise specific service" - "wdio.conf.js:248:34 initialising U executed just before initialising the webdriver session" - "wdio.conf.js:318:39 informations U Object} result.retries informations to spec related retries" + +issuesSummary: + - "text: abce, count: 1, files: 1," + - "text: abcefg, count: 2, files: 1," + - "text: abnf, count: 1, files: 1," + - "text: ABNF, count: 1, files: 1," + - "text: accululated, count: 1, files: 1," + - "text: accum, count: 3, files: 1," + - "text: addlabel, count: 5, files: 1," + - "text: aeiou, count: 1, files: 1," + - "text: afoob, count: 5, files: 1," + - "text: algoliasearch, count: 4, files: 2," + - "text: allman, count: 13, files: 3," + - "text: Allman, count: 2, files: 1," + - "text: alloc, count: 5, files: 1," + - "text: Amaresh, count: 1, files: 1," + - "text: amet, count: 2, files: 1," + - "text: anchorjs, count: 1, files: 1," + - "text: anonname, count: 5, files: 1," + - "text: antidisestablishmentarianistically, count: 1, files: 1," + - "text: apos, count: 5, files: 4," + - "text: appium, count: 1, files: 1," + - "text: applescript, count: 1, files: 1," + - "text: arity, count: 1, files: 1," + - "text: Ashkenas, count: 1, files: 1," + - "text: assignadd, count: 1, files: 1," + - "text: assignbitand, count: 1, files: 1," + - "text: assignbitor, count: 1, files: 1," + - "text: assignbitxor, count: 1, files: 1," + - "text: assigndiv, count: 1, files: 1," + - "text: assignmod, count: 1, files: 1," + - "text: assignmult, count: 1, files: 1," + - "text: assignop, count: 5, files: 1," + - "text: assignshiftleft, count: 1, files: 1," + - "text: assignshiftright, count: 1, files: 1," + - "text: assignshiftrightunsigned, count: 1, files: 1," + - "text: assignsub, count: 1, files: 1," + - "text: astexplorer, count: 7, files: 7," + - "text: astnode, count: 5, files: 1," + - "text: Astnode, count: 5, files: 1," + - "text: atomtest, count: 1, files: 1," + - "text: atrule, count: 1, files: 1," + - "text: Autocompleter, count: 1, files: 1," + - "text: autodetected, count: 1, files: 1," + - "text: autodetects, count: 1, files: 1," + - "text: avalue, count: 1, files: 1," + - "text: barbaz, count: 5, files: 4," + - "text: barfoo, count: 5, files: 3," + - "text: barqux, count: 2, files: 2," + - "text: barrito, count: 2, files: 1," + - "text: basictkn, count: 1, files: 1," + - "text: bazfoo, count: 1, files: 1," + - "text: bazqux, count: 2, files: 2," + - "text: bazz, count: 15, files: 4," + - "text: bcde, count: 2, files: 1," + - "text: bikeshedding, count: 1, files: 1," + - "text: bingg, count: 10, files: 2," + - "text: binop, count: 9, files: 9," + - "text: bitand, count: 1, files: 1," + - "text: bitor, count: 1, files: 1," + - "text: bitwiseassignop, count: 5, files: 1," + - "text: bitxor, count: 1, files: 1," + - "text: bkufyydt, count: 1, files: 1," + - "text: blahblah, count: 4, files: 1," + - "text: blockignore, count: 4, files: 1," + - "text: blockless, count: 3, files: 2," + - "text: Blockless, count: 5, files: 1," + - "text: blockscope, count: 5, files: 1," + - "text: blockstmt, count: 5, files: 1," + - "text: blocktype, count: 3, files: 1," + - "text: blogpost, count: 2, files: 1," + - "text: boop, count: 24, files: 9," + - "text: booya, count: 2, files: 1," + - "text: braceless, count: 1, files: 1," + - "text: braket, count: 1, files: 1," + - "text: bref, count: 10, files: 2," + - "text: bref's, count: 3, files: 1," + - "text: browserstack, count: 1, files: 1," + - "text: buildtime, count: 1, files: 1," + - "text: butwhy, count: 2, files: 1," + - "text: calle, count: 1, files: 1," + - "text: carbonads, count: 5, files: 1," + - "text: carrays, count: 5, files: 1," + - "text: cauli, count: 1, files: 1," + - "text: changefreq, count: 2, files: 1," + - "text: CHARCLASS, count: 2, files: 1," + - "text: circuting, count: 1, files: 1," + - "text: classdef, count: 3, files: 1," + - "text: CLASSSET, count: 2, files: 1," + - "text: classtail, count: 2, files: 1," + - "text: cliengine, count: 2, files: 2," + - "text: codepath, count: 2, files: 1," + - "text: colocation, count: 2, files: 2," + - "text: colspan, count: 1, files: 1," + - "text: commaless, count: 2, files: 1," + - "text: committership, count: 2, files: 1," + - "text: comparray, count: 5, files: 1," + - "text: compat, count: 2, files: 1," + - "text: Compat, count: 5, files: 1," + - "text: complexdomain, count: 1, files: 1," + - "text: cond, count: 9, files: 4," + - "text: configurability, count: 1, files: 1," + - "text: consequents, count: 3, files: 1," + - "text: consolexlog, count: 2, files: 1," + - "text: conststatement, count: 2, files: 1," + - "text: corge, count: 1, files: 1," + - "text: Cpath, count: 2, files: 1," + - "text: Cpmn, count: 1, files: 1," + - "text: Crect, count: 2, files: 1," + - "text: crockford, count: 1, files: 1," + - "text: Crockford, count: 2, files: 2," + - "text: cssvars, count: 5, files: 1," + - "text: CSSVARSPONYFILL, count: 3, files: 1," + - "text: Csvg, count: 3, files: 2," + - "text: curlies, count: 2, files: 1," + - "text: curlybracket, count: 1, files: 1," + - "text: customformat, count: 1, files: 1," + - "text: cyclomatic, count: 9, files: 4," + - "text: Cyclomatic, count: 1, files: 1," + - "text: Cypro, count: 1, files: 1," + - "text: datetime, count: 2, files: 1," + - "text: dbname, count: 3, files: 1," + - "text: declarators, count: 4, files: 3," + - "text: Declarators, count: 3, files: 2," + - "text: decrementcurrent, count: 2, files: 1," + - "text: destructures, count: 1, files: 1," + - "text: devel, count: 4, files: 1," + - "text: Dfnp, count: 1, files: 1," + - "text: dgimsuvy, count: 1, files: 1," + - "text: dgram, count: 2, files: 2," + - "text: Didnt, count: 6, files: 2," + - "text: dignore, count: 1, files: 1," + - "text: dijit, count: 1, files: 1," + - "text: Djermanovic, count: 1, files: 1," + - "text: docsearch, count: 1, files: 1," + - "text: doesexist, count: 1, files: 1," + - "text: doesnotexist, count: 5, files: 1," + - "text: doesnt, count: 3, files: 1," + - "text: Doesnt, count: 3, files: 1," + - "text: doesntexist, count: 3, files: 3," + - "text: dojox, count: 1, files: 1," + - "text: dont, count: 11, files: 4," + - "text: Dont, count: 3, files: 1," + - "text: dotfile, count: 2, files: 2," + - "text: doxygen, count: 1, files: 1," + - "text: Draggables, count: 1, files: 1," + - "text: Droppables, count: 1, files: 1," + - "text: Dulin, count: 1, files: 1," + - "text: ECMAFEATURES, count: 2, files: 2," + - "text: egal, count: 2, files: 1," + - "text: elapseds, count: 1, files: 1," + - "text: ELEVENTEEN, count: 2, files: 1," + - "text: eleventy, count: 4, files: 4," + - "text: embertest, count: 1, files: 1," + - "text: endfor, count: 6, files: 3," + - "text: endraw, count: 8, files: 4," + - "text: endregion, count: 5, files: 1," + - "text: endregionfoo, count: 1, files: 1," + - "text: endset, count: 1, files: 1," + - "text: Enumerabl, count: 1, files: 1," + - "text: eqnull, count: 6, files: 2," + - "text: errorize, count: 3, files: 3," + - "text: eslintbot, count: 1, files: 1," + - "text: eslintformatter, count: 1, files: 1," + - "text: eslump, count: 5, files: 2," + - "text: estraverse, count: 1, files: 1," + - "text: esutils, count: 8, files: 3," + - "text: Europese, count: 1, files: 1," + - "text: exportee, count: 1, files: 1," + - "text: expresion, count: 1, files: 1," + - "text: Expresion, count: 2, files: 1," + - "text: Expressio, count: 1, files: 1," + - "text: extendees, count: 4, files: 2," + - "text: fakeformatter, count: 1, files: 1," + - "text: fallsthrough, count: 1, files: 1," + - "text: falsiness, count: 1, files: 1," + - "text: Fastpath, count: 1, files: 1," + - "text: fatarrowparams, count: 3, files: 1," + - "text: fdescribe, count: 5, files: 1," + - "text: FEFF, count: 1, files: 1," + - "text: fifi, count: 1, files: 1," + - "text: fileexts, count: 1, files: 1," + - "text: firstname, count: 2, files: 1," + - "text: fixability, count: 1, files: 1," + - "text: fixmode, count: 15, files: 3," + - "text: fizzbuzz, count: 2, files: 1," + - "text: flexer, count: 2, files: 1," + - "text: Flycheck, count: 1, files: 1," + - "text: fnparam, count: 5, files: 1," + - "text: foldl, count: 2, files: 1," + - "text: foldr, count: 2, files: 1," + - "text: fontstack, count: 5, files: 1," + - "text: fooa, count: 1, files: 1," + - "text: foobaz, count: 5, files: 4," + - "text: foonorf, count: 1, files: 1," + - "text: fooo, count: 13, files: 3," + - "text: foop, count: 1, files: 1," + - "text: fooqux, count: 1, files: 1," + - "text: foos, count: 4, files: 1," + - "text: foothis, count: 9, files: 3," + - "text: foox, count: 8, files: 2," + - "text: fooz, count: 4, files: 1," + - "text: foreachtok, count: 4, files: 1," + - "text: Fpath, count: 2, files: 1," + - "text: Francesco, count: 1, files: 1," + - "text: freelist, count: 2, files: 2," + - "text: frist, count: 2, files: 1," + - "text: fswalk, count: 3, files: 1," + - "text: fucntion, count: 1, files: 1," + - "text: fuga, count: 13, files: 6," + - "text: funcs, count: 2, files: 1," + - "text: funcscope, count: 3, files: 1," + - "text: funct, count: 5, files: 1," + - "text: functionicity, count: 5, files: 1," + - "text: functionparams, count: 2, files: 1," + - "text: Fvar, count: 2, files: 2," + - "text: gensite, count: 4, files: 2," + - "text: getfoo, count: 1, files: 1," + - "text: getlabel, count: 4, files: 1," + - "text: gimu, count: 3, files: 1," + - "text: gimuy, count: 4, files: 1," + - "text: gimuygimuygimuy, count: 1, files: 1," + - "text: gimv, count: 1, files: 1," + - "text: gimvy, count: 4, files: 1," + - "text: gimy, count: 4, files: 1," + - "text: gimyu, count: 4, files: 1," + - "text: globbed, count: 1, files: 1," + - "text: globbing, count: 1, files: 1," + - "text: gnored, count: 7, files: 2," + - "text: graphemer, count: 2, files: 2," + - "text: Graphemer, count: 3, files: 1," + - "text: Graphvis, count: 2, files: 1," + - "text: greasemonkey, count: 1, files: 1," + - "text: Gruntfile, count: 1, files: 1," + - "text: Guake, count: 1, files: 1," + - "text: hasher, count: 4, files: 1," + - "text: Hildenbiddle, count: 1, files: 1," + - "text: hoge, count: 18, files: 7," + - "text: humanwhocodes, count: 5, files: 4," + - "text: iframe, count: 2, files: 1," + - "text: iframes, count: 1, files: 1," + - "text: IIEF, count: 2, files: 1," + - "text: ijkl, count: 1, files: 1," + - "text: immed, count: 5, files: 1," + - "text: implieds, count: 5, files: 1," + - "text: inblock, count: 5, files: 1," + - "text: incompat, count: 1, files: 1," + - "text: incrementcurrent, count: 2, files: 1," + - "text: ined, count: 1, files: 1," + - "text: informations, count: 1, files: 1," + - "text: initialise, count: 1, files: 1," + - "text: initialising, count: 1, files: 1," + - "text: inof, count: 3, files: 1," + - "text: inspectable, count: 1, files: 1," + - "text: Intelli, count: 1, files: 1," + - "text: intenationally, count: 6, files: 2," + - "text: intentionaly, count: 1, files: 1," + - "text: invalidtoken, count: 2, files: 1," + - "text: iojs, count: 1, files: 1," + - "text: ipaddr, count: 5, files: 1," + - "text: isclassdef, count: 5, files: 1," + - "text: isfatarrow, count: 2, files: 1," + - "text: isfunc, count: 5, files: 1," + - "text: isnan, count: 12, files: 4," + - "text: isundef, count: 5, files: 1," + - "text: jscodeshift, count: 2, files: 1," + - "text: jscript, count: 2, files: 1," + - "text: jscsrs, count: 1, files: 1," + - "text: jshintignore, count: 2, files: 1," + - "text: jsonify, count: 3, files: 3," + - "text: Kanti, count: 1, files: 1," + - "text: Karlton, count: 2, files: 2," + - "text: Kovalyov, count: 1, files: 1," + - "text: Kumar, count: 1, files: 1," + - "text: kumiko, count: 5, files: 1," + - "text: Kumiko, count: 1, files: 1," + - "text: labelledby, count: 2, files: 2," + - "text: lalala, count: 3, files: 2," + - "text: Larcher, count: 2, files: 1," + - "text: lastcharacter, count: 4, files: 1," + - "text: lastmod, count: 2, files: 1," + - "text: lastsemic, count: 3, files: 1," + - "text: latedef, count: 5, files: 1," + - "text: laxbreak, count: 3, files: 1," + - "text: laxcomma, count: 3, files: 1," + - "text: layou, count: 3, files: 3," + - "text: leftpad, count: 6, files: 3," + - "text: letblock, count: 3, files: 1," + - "text: letscope, count: 4, files: 1," + - "text: letstatement, count: 2, files: 1," + - "text: levn, count: 5, files: 3," + - "text: Levn, count: 1, files: 1," + - "text: lifed, count: 1, files: 1," + - "text: linkify, count: 2, files: 1," + - "text: lintable, count: 1, files: 1," + - "text: litera, count: 4, files: 1," + - "text: livescript, count: 2, files: 1," + - "text: lmnn, count: 1, files: 1," + - "text: logicals, count: 1, files: 1," + - "text: longform, count: 5, files: 1," + - "text: Longform, count: 8, files: 2," + - "text: LONGFORM, count: 5, files: 1," + - "text: longlonglong, count: 5, files: 1," + - "text: loopage, count: 5, files: 1," + - "text: loopfunc, count: 4, files: 1," + - "text: luxon, count: 1, files: 1," + - "text: markdownlintignore, count: 1, files: 1," + - "text: Matthieu, count: 5, files: 1," + - "text: maxcomplexity, count: 3, files: 1," + - "text: maxerr, count: 5, files: 1," + - "text: maxlen, count: 5, files: 1," + - "text: maxparams, count: 4, files: 1," + - "text: maxstatements, count: 4, files: 1," + - "text: mdcs, count: 2, files: 1," + - "text: mdjermanovic, count: 1, files: 1," + - "text: Meep, count: 2, files: 1," + - "text: memfs, count: 2, files: 2," + - "text: mergeable, count: 1, files: 1," + - "text: metascraper, count: 10, files: 2," + - "text: michaelficarra, count: 1, files: 1," + - "text: microtask, count: 2, files: 1," + - "text: Mishkin, count: 1, files: 1," + - "text: modns, count: 3, files: 1," + - "text: mootools, count: 4, files: 1," + - "text: morerules, count: 2, files: 1," + - "text: muhahaha, count: 1, files: 1," + - "text: mult, count: 1, files: 1," + - "text: Multifiles, count: 2, files: 1," + - "text: MULTIFILES, count: 5, files: 1," + - "text: multistr, count: 5, files: 1," + - "text: munter, count: 2, files: 2," + - "text: myarray, count: 4, files: 2," + - "text: myconf, count: 15, files: 3," + - "text: myconfig, count: 10, files: 3," + - "text: myconsole, count: 1, files: 1," + - "text: mydate, count: 4, files: 2," + - "text: myfile, count: 3, files: 1," + - "text: myfiletotest, count: 1, files: 1," + - "text: myfunc, count: 5, files: 1," + - "text: mylib, count: 7, files: 2," + - "text: mylibrary, count: 3, files: 1," + - "text: mypackage, count: 7, files: 6," + - "text: myparser, count: 2, files: 1," + - "text: myplugin, count: 7, files: 2," + - "text: mysafereg, count: 1, files: 1," + - "text: mytest, count: 5, files: 1," + - "text: n'qux, count: 3, files: 1," + - "text: n'quxx, count: 3, files: 1," + - "text: Nandinagari, count: 1, files: 1," + - "text: nashorn, count: 4, files: 3," + - "text: Nashorn, count: 2, files: 2," + - "text: nccc, count: 2, files: 1," + - "text: ncdar, count: 1, files: 1," + - "text: ncde, count: 1, files: 1," + - "text: ndefined, count: 1, files: 1," + - "text: ndex, count: 1, files: 1," + - "text: Neue, count: 1, files: 1," + - "text: newcap, count: 5, files: 1," + - "text: Newcap, count: 3, files: 1," + - "text: newed, count: 1, files: 1," + - "text: nextop, count: 5, files: 1," + - "text: Nitin, count: 1, files: 1," + - "text: noarg, count: 2, files: 1," + - "text: nobreak, count: 4, files: 1," + - "text: nobreakcomma, count: 3, files: 1," + - "text: nobreaknonadjacent, count: 5, files: 1," + - "text: nochange, count: 2, files: 1," + - "text: nodeca, count: 1, files: 1," + - "text: nodelib, count: 2, files: 2," + - "text: noempty, count: 2, files: 1," + - "text: noeval, count: 7, files: 3," + - "text: nofix, count: 5, files: 1," + - "text: nofunc, count: 12, files: 5," + - "text: noindent, count: 2, files: 1," + - "text: nolet, count: 4, files: 1," + - "text: nolinebreak, count: 5, files: 1," + - "text: NONBLANK, count: 2, files: 1," + - "text: nonblock, count: 10, files: 4," + - "text: nonconstructor, count: 10, files: 5," + - "text: Nonconstructor, count: 2, files: 1," + - "text: noneval, count: 1, files: 1," + - "text: nonew, count: 2, files: 1," + - "text: noniterable, count: 1, files: 1," + - "text: nonoctal, count: 12, files: 7," + - "text: nonwords, count: 17, files: 7," + - "text: noopener, count: 1, files: 1," + - "text: noreach, count: 4, files: 1," + - "text: noreferrer, count: 1, files: 1," + - "text: norf, count: 5, files: 1," + - "text: nosomething, count: 1, files: 1," + - "text: NOTMATCHED, count: 1, files: 1," + - "text: notoctal, count: 2, files: 1," + - "text: notregbutstring, count: 5, files: 1," + - "text: npmjs, count: 1, files: 1," + - "text: nretv, count: 3, files: 1," + - "text: nrvtbfux, count: 1, files: 1," + - "text: nsnd, count: 5, files: 1," + - "text: nullishness, count: 5, files: 2," + - "text: Nullishness, count: 5, files: 1," + - "text: nums, count: 1, files: 1," + - "text: Nums, count: 4, files: 1," + - "text: numvals, count: 2, files: 1," + - "text: nunber, count: 1, files: 1," + - "text: nzakas, count: 5, files: 5," + - "text: occured, count: 4, files: 2," + - "text: octals, count: 1, files: 1," + - "text: Officiële, count: 1, files: 1," + - "text: omittable, count: 1, files: 1," + - "text: onecase, count: 1, files: 1," + - "text: onevar, count: 6, files: 2," + - "text: openjsf, count: 3, files: 3," + - "text: optionalidentifier, count: 4, files: 1," + - "text: optionator, count: 6, files: 2," + - "text: Optionator, count: 2, files: 2," + - "text: otherdata, count: 2, files: 2," + - "text: otherthing, count: 1, files: 1," + - "text: Ougr, count: 1, files: 1," + - "text: Oumae, count: 1, files: 1," + - "text: outpt, count: 4, files: 2," + - "text: overcommit, count: 1, files: 1," + - "text: packagejson, count: 12, files: 3," + - "text: paren, count: 32, files: 13," + - "text: parens, count: 58, files: 23," + - "text: Parens, count: 11, files: 3," + - "text: parenthesising, count: 2, files: 2," + - "text: passfail, count: 2, files: 1," + - "text: PASSTHROUGHS, count: 6, files: 2," + - "text: pluginname, count: 1, files: 1," + - "text: plusplus, count: 16, files: 6," + - "text: polyjuice, count: 3, files: 1," + - "text: Polyjuice, count: 5, files: 1," + - "text: ponyfill, count: 1, files: 1," + - "text: popd, count: 1, files: 1," + - "text: postamble, count: 3, files: 1," + - "text: Postamble, count: 3, files: 1," + - "text: postdec, count: 1, files: 1," + - "text: postinc, count: 1, files: 1," + - "text: postpack, count: 1, files: 1," + - "text: postprepare, count: 1, files: 1," + - "text: postprocessor, count: 6, files: 2," + - "text: postprocessors, count: 2, files: 1," + - "text: poweredby, count: 2, files: 1," + - "text: prec, count: 5, files: 1," + - "text: Precendence, count: 3, files: 1," + - "text: Precommit, count: 1, files: 1," + - "text: precompilation, count: 1, files: 1," + - "text: predec, count: 1, files: 1," + - "text: predef, count: 5, files: 1," + - "text: preferrable, count: 2, files: 1," + - "text: preinc, count: 1, files: 1," + - "text: preinstall, count: 1, files: 1," + - "text: Premajor, count: 1, files: 1," + - "text: preminor, count: 1, files: 1," + - "text: Preminor, count: 1, files: 1," + - "text: prepatch, count: 2, files: 1," + - "text: prepopulated, count: 1, files: 1," + - "text: preprepare, count: 1, files: 1," + - "text: prereg, count: 5, files: 1," + - "text: Prereleases, count: 1, files: 1," + - "text: previos, count: 2, files: 2," + - "text: prismjs, count: 3, files: 2," + - "text: Propert, count: 2, files: 2," + - "text: proto, count: 12, files: 5," + - "text: prototypejs, count: 5, files: 2," + - "text: pseudoclass, count: 3, files: 1," + - "text: pseudoclasses, count: 5, files: 1," + - "text: punycode, count: 2, files: 2," + - "text: pushd, count: 1, files: 1," + - "text: quasis, count: 29, files: 16," + - "text: querystring, count: 2, files: 2," + - "text: qunit, count: 1, files: 1," + - "text: quotmark, count: 5, files: 1," + - "text: quuux, count: 13, files: 7," + - "text: quux, count: 44, files: 21," + - "text: Quux, count: 1, files: 1," + - "text: quxx, count: 22, files: 8," + - "text: readline, count: 2, files: 2," + - "text: redeclares, count: 3, files: 1," + - "text: Redeclaring, count: 3, files: 1," + - "text: regexdash, count: 1, files: 1," + - "text: reignore, count: 1, files: 1," + - "text: reignoring, count: 1, files: 1," + - "text: reinclude, count: 1, files: 1," + - "text: removeend, count: 1, files: 1," + - "text: removemiddle, count: 5, files: 1," + - "text: removestart, count: 1, files: 1," + - "text: reservevar, count: 5, files: 1," + - "text: Resig's, count: 1, files: 1," + - "text: rethrown, count: 1, files: 1," + - "text: retv, count: 58, files: 16," + - "text: rewritable, count: 1, files: 1," + - "text: righthand, count: 1, files: 1," + - "text: rror, count: 1, files: 1," + - "text: rulename, count: 1, files: 1," + - "text: runtimes, count: 5, files: 4," + - "text: samely, count: 1, files: 1," + - "text: sampleignorepattern, count: 10, files: 2," + - "text: Schlueter, count: 2, files: 2," + - "text: Scriptaculous, count: 2, files: 1," + - "text: scripturl, count: 4, files: 2," + - "text: sdfdsf, count: 2, files: 1," + - "text: Segs, count: 4, files: 1," + - "text: semistandard, count: 5, files: 1," + - "text: serviceworker, count: 1, files: 1," + - "text: setupindex, count: 4, files: 1," + - "text: shiftleft, count: 1, files: 1," + - "text: shiftright, count: 1, files: 1," + - "text: shiftrightunsigned, count: 1, files: 1," + - "text: shortcode, count: 6, files: 4," + - "text: shortcodes, count: 2, files: 1," + - "text: shortcutted, count: 2, files: 1," + - "text: shtylman, count: 1, files: 1," + - "text: simpledomain, count: 1, files: 1," + - "text: singleline, count: 3, files: 1," + - "text: smalloc, count: 3, files: 3," + - "text: smarttabs, count: 4, files: 1," + - "text: somefile, count: 6, files: 2," + - "text: somenamespace, count: 6, files: 3," + - "text: someplugin, count: 5, files: 1," + - "text: someregular, count: 2, files: 1," + - "text: somethingelse, count: 4, files: 1," + - "text: sourcecode, count: 2, files: 1," + - "text: SOURCECODE, count: 6, files: 2," + - "text: specfile, count: 1, files: 1," + - "text: specfiles, count: 1, files: 1," + - "text: sponsorsend, count: 3, files: 2," + - "text: sponsorsstart, count: 3, files: 2," + - "text: squarebracket, count: 1, files: 1," + - "text: Stackaid, count: 1, files: 1," + - "text: Strek, count: 1, files: 1," + - "text: strnig, count: 7, files: 2," + - "text: stroustrup, count: 11, files: 3," + - "text: Stroustrup, count: 2, files: 1," + - "text: Stvw, count: 1, files: 1," + - "text: subbroken, count: 9, files: 3," + - "text: Subclassing, count: 2, files: 2," + - "text: subconditions, count: 1, files: 1," + - "text: subdir, count: 28, files: 12," + - "text: subexpressions, count: 2, files: 2," + - "text: subimports, count: 2, files: 1," + - "text: substr, count: 2, files: 1," + - "text: subsubbroken, count: 3, files: 3," + - "text: subsubdir, count: 21, files: 7," + - "text: subsubsubdir, count: 4, files: 4," + - "text: sumologic, count: 1, files: 1," + - "text: supernew, count: 3, files: 1," + - "text: suppresed, count: 2, files: 1," + - "text: SVGCSS, count: 1, files: 1," + - "text: SVGH, count: 1, files: 1," + - "text: SVGICC, count: 1, files: 1," + - "text: SVGM, count: 1, files: 1," + - "text: SVGV, count: 1, files: 1," + - "text: Swiff, count: 1, files: 1," + - "text: Syntastic, count: 1, files: 1," + - "text: syntaxhighlight, count: 1, files: 1," + - "text: tablist, count: 6, files: 2," + - "text: tabpanel, count: 8, files: 2," + - "text: Tabpanel, count: 2, files: 1," + - "text: tabpanels, count: 5, files: 1," + - "text: Tangsa, count: 1, files: 1," + - "text: Tanuj, count: 1, files: 1," + - "text: teamend, count: 3, files: 2," + - "text: teamstart, count: 3, files: 2," + - "text: tempdir, count: 1, files: 1," + - "text: templating, count: 2, files: 1," + - "text: thepanel, count: 3, files: 1," + - "text: Titlecase, count: 1, files: 1," + - "text: tmbundle, count: 2, files: 1," + - "text: Tnsa, count: 1, files: 1," + - "text: toggleindex, count: 4, files: 2," + - "text: togglenav, count: 2, files: 1," + - "text: toint, count: 1, files: 1," + - "text: Traceur, count: 1, files: 1," + - "text: Transloadit, count: 1, files: 1," + - "text: triaging, count: 3, files: 2," + - "text: Triaging, count: 5, files: 1," + - "text: Trotta, count: 1, files: 1," + - "text: truex, count: 1, files: 1," + - "text: tsdfdsf, count: 2, files: 1," + - "text: Tweetdeck, count: 1, files: 1," + - "text: Twemoji, count: 1, files: 1," + - "text: typeof, count: 40, files: 14," + - "text: über, count: 3, files: 1," + - "text: Über, count: 3, files: 1," + - "text: ufeff, count: 1, files: 1," + - "text: umdefined, count: 5, files: 1," + - "text: unactivate, count: 1, files: 1," + - "text: unbegun, count: 1, files: 1," + - "text: Unbegun, count: 1, files: 1," + - "text: undefimed, count: 1, files: 1," + - "text: undefs, count: 4, files: 1," + - "text: unescapes, count: 4, files: 1," + - "text: unescaping, count: 2, files: 2," + - "text: unexpect, count: 5, files: 1," + - "text: unfixable, count: 2, files: 1," + - "text: unflattened, count: 5, files: 1," + - "text: ungap, count: 2, files: 2," + - "text: Unie, count: 1, files: 1," + - "text: unindented, count: 5, files: 1," + - "text: unittests, count: 1, files: 1," + - "text: unuseds, count: 5, files: 1," + - "text: uppercases, count: 1, files: 1," + - "text: urlset, count: 2, files: 1," + - "text: Uyghur, count: 1, files: 1," + - "text: validthis, count: 5, files: 1," + - "text: valign, count: 1, files: 1," + - "text: Vals, count: 5, files: 1," + - "text: Varint, count: 1, files: 1," + - "text: varstatement, count: 2, files: 1," + - "text: verif, count: 3, files: 1," + - "text: verifsint, count: 4, files: 1," + - "text: verifuint, count: 4, files: 1," + - "text: Vith, count: 1, files: 1," + - "text: Vithkuqi, count: 1, files: 1," + - "text: vsdoc, count: 1, files: 1," + - "text: waitfor, count: 1, files: 1," + - "text: warnable, count: 3, files: 1," + - "text: wdio, count: 14, files: 3," + - "text: webdriverio, count: 2, files: 2," + - "text: webextensions, count: 4, files: 3," + - "text: webserver, count: 1, files: 1," + - "text: Whoh, count: 1, files: 1," + - "text: withstmt, count: 2, files: 1," + - "text: writability, count: 2, files: 2," + - "text: wuint, count: 2, files: 1," + - "text: xdescribe, count: 2, files: 1," + - "text: xfilter, count: 2, files: 2," + - "text: xjavascript, count: 2, files: 1," + - "text: xmldoc, count: 2, files: 1," + - "text: Yosuke, count: 1, files: 1," + - "text: youll, count: 4, files: 4," + - "text: yourfile, count: 3, files: 2," + - "text: yugoslavyalılaştırabildiklerimizdenmişsiniz, count: 1, files: 1," + - "text: Yuxi, count: 1, files: 1," + - "text: Zakas, count: 4, files: 4," + - "text: ZWSP, count: 2, files: 1," + - "text: Европейския, count: 1, files: 1," + - "text: Официален, count: 1, files: 1," + - "text: съюз, count: 1, files: 1," + - "text: уебсайт, count: 1, files: 1," diff --git a/integration-tests/snapshots/eslint/eslint/snapshot.txt b/integration-tests/snapshots/eslint/eslint/snapshot.txt index a99e5e0f077..950620c60b0 100644 --- a/integration-tests/snapshots/eslint/eslint/snapshot.txt +++ b/integration-tests/snapshots/eslint/eslint/snapshot.txt @@ -1,9 +1,9 @@ Repository: eslint/eslint Url: "https://github.com/eslint/eslint" -Args: ["**","--exclude=bin/**","--exclude=CHANGELOG.md","--exclude=_data","--exclude=tests/bench/large.js","--exclude=docs/src/_includes","--exclude=docs/src/assets/{fonts,s?css,images}"] +Args: [".","--config=../../../config/eslint/cspell.config.yaml","--issues-summary-report","--exclude=bin/**","--exclude=CHANGELOG.md","--exclude=_data","--exclude=tests/bench/large.js","--exclude=docs/src/_includes","--exclude=docs/src/assets/{fonts,s?css,images}"] Lines: - CSpell: Files checked: 1898, Issues found: 5491 in 1258 files + CSpell: Files checked: 1898, Issues found: 2191 in 401 files exit code: 1 ./Makefile.js:144:88 - Unknown word (ined) -- followed by the string "ined". ./Makefile.js:150:48 - Unknown word (blogpost) -- render(cat("./templates/blogpost.md.ejs"), renderContext @@ -32,20 +32,16 @@ Lines: ./README.md:292:5 - Unknown word (sponsorsstart) -- ./README.md:297:679 - Unknown word (Transloadit) -- com/u/125754?v=4" alt="Transloadit" height="32"> -./conf/config-schema.js:14:5 - Unknown word (fileoverview) -- * @fileoverview Defines a schema for ./conf/config-schema.js:8:63 - Unknown word (nzakas) -- file, please contact @nzakas first. ./conf/replacements.json:12:36 - Unknown word (parens) -- wrap-func": ["no-extra-parens"], ./conf/replacements.json:13:62 - Unknown word (paren) -- space-before-function-paren"], -./docs/README.md:37:4 - Unknown word (autofix) -- To autofix JS files, run this from ./docs/README.md:45:51 - Unknown word (openjsf) -- ESLint contributors, [www.openjsf.org](https://www.openjsf -./docs/_examples/custom-rule-tutorial-code/package.json:8:6 - Unknown word (eslintplugin) -- "eslintplugin", ./docs/package.json:30:32 - Unknown word (syntaxhighlight) -- 1ty/eleventy-plugin-syntaxhighlight": "^5.0.0", ./docs/package.json:31:11 - Unknown word (munter) -- "@munter/tap-render": "^0.2. ./docs/package.json:33:10 - Unknown word (algoliasearch) -- "algoliasearch": "^4.12.1", ./docs/package.json:46:10 - Unknown word (luxon) -- "luxon": "^2.4.0", ./docs/package.json:54:10 - Unknown word (prismjs) -- "prismjs": "^1.29.0", ./docs/src/_plugins/md-syntax-highlighter.js:4:29 - Unknown word (Yuxi) -- Copyright (c) 2019-present, Yuxi (Evan) You -./docs/src/about/index.md:10:146 - Unknown word (pluggable) -- all rules completely pluggable. The default rules are ./docs/src/about/index.md:6:87 - Unknown word (Zakas) -- created by Nicholas C. Zakas in June 2013. Code ./docs/src/assets/js/components-index.js:17:14 - Unknown word (toggleindex) -- function toggleindex(e) { ./docs/src/assets/js/css-vars-ponyfill@2.js:2:13 - Unknown word (ponyfill) -- * css-vars-ponyfill @@ -76,7 +72,6 @@ Lines: ./docs/src/assets/scss/syntax-highlighter.scss:118:39 - Unknown word (nums) -- variant-numeric: tabular-nums; ./docs/src/assets/scss/syntax-highlighter.scss:83:8 - Unknown word (atrule) -- .token.atrule, ./docs/src/assets/scss/tokens/typography.scss:63:10 - Unknown word (Twemoji) -- "Twemoji Country Flags", -./docs/src/contribute/architecture/index.md:66:264 - Unknown word (espree) -- the given text with `espree` (or whatever the configured ./docs/src/contribute/architecture/index.md:68:29 - Unknown word (estraverse) -- the AST is available, `estraverse` is used to traverse ./docs/src/contribute/governance.md:150:64 - Unknown word (Tweetdeck) -- ESLint Twitter Account on Tweetdeck ./docs/src/contribute/governance.md:73:35 - Unknown word (committership) -- important to recognize that committership is a privilege, not @@ -90,36 +85,19 @@ Lines: ./docs/src/contribute/work-on-issue.md:16:588 - Unknown word (bikeshedding) -- evaluating`, and/or `needs bikeshedding`, and issues that cannot ./docs/src/extend/code-path-analysis.md:542:5 - Unknown word (hoge) -- hoge(); ./docs/src/extend/code-path-analysis.md:591:9 - Unknown word (fuga) -- fuga(); -./docs/src/extend/custom-formatters.md:201:14 - Unknown word (concat) -- .concat(warnings) ./docs/src/extend/custom-formatters.md:251:61 - Unknown word (Guake) -- www.iterm2.com/) or [Guake](http://guake-project ./docs/src/extend/custom-formatters.md:273:9 - Unknown word (eslintformatter) -- * `"eslintformatter"` ./docs/src/extend/custom-formatters.md:80:29 - Unknown word (Gruntfile) -- filePath: "/path/to/Gruntfile.js", ./docs/src/extend/custom-parsers.md:121:27 - Unknown word (myparser) -- install eslint-parser-myparser --save-dev ./docs/src/extend/custom-parsers.md:80:44 - Unknown word (rewritable) -- of all nodes must be rewritable. Before any rules have -./docs/src/extend/custom-processors.md:109:37 - Unknown word (autofixes) -- ESLint does not perform autofixes when a custom processor -./docs/src/extend/custom-processors.md:111:107 - Unknown word (autofixable) -- reported problems. All autofixable problems have a `fix -./docs/src/extend/custom-processors.md:26:13 - Unknown word (preprocess) -- preprocess: function(text, filename -./docs/src/extend/custom-processors.md:37:13 - Unknown word (postprocess) -- postprocess: function(messages, -./docs/src/extend/custom-processors.md:46:21 - Unknown word (Autofix) -- supportsAutofix: true // (optional, ./docs/src/extend/custom-rule-tutorial.md:171:4 - Unknown word (endraw) -- {% endraw %} ./docs/src/extend/custom-rule-tutorial.md:87:127 - Unknown word (fixability) -- documentation, and fixability. In this case, the rule -./docs/src/extend/custom-rules-deprecated.md:442:36 - Unknown word (doublequote) -- ["Strings must use doublequote."] -./docs/src/extend/custom-rules-deprecated.md:533:1 - Unknown word (camelcase) -- camelcase | -./docs/src/extend/custom-rules-deprecated.md:580:81 - Unknown word (rulesdir) -- interface) using the `--rulesdir` option to specify the -./docs/src/extend/custom-rules.md:398:78 - Unknown word (multipass) -- without triggering multipass fixes. Each suggestion ./docs/src/extend/plugin-migration-flat-config.md:217:17 - Unknown word (xdescribe) -- xdescribe: true ./docs/src/extend/plugins.md:37:162 - Unknown word (myplugin) -- named `eslint-plugin-myplugin`, then in your configuration -./docs/src/extend/scope-manager-interface.md:218:100 - Unknown word (redeclared) -- If this variable is redeclared, this array includes -./docs/src/extend/scope-manager-interface.md:6:125 - Unknown word (escope) -- eslint-scope), a fork of [escope](https://github.com ./docs/src/extend/selectors.md:140:405 - Unknown word (Fpath) -- so: `[value=/some\u002Fpath/]`. -./docs/src/extend/selectors.md:54:58 - Unknown word (esquery) -- were adapted from the [esquery](https://github.com ./docs/src/extend/shareable-configs.md:21:55 - Unknown word (myconfig) -- such as `eslint-config-myconfig`. -./docs/src/extend/shareable-configs.md:45:192 - Unknown word (eslintconfig) -- using the `eslint` and `eslintconfig` [keywords](https:/ -./docs/src/extend/ways-to-extend.md:54:49 - Unknown word (Espree) -- in JavaScript parser (Espree), but custom parsers ./docs/src/integrate/nodejs-api.md:211:35 - Unknown word (omittable) -- parameter `options` is omittable. ./docs/src/integrate/nodejs-api.md:478:35 - Unknown word (Fvar) -- new SourceCode("\uFEFFvar foo = bar;", ast); -./docs/src/integrate/nodejs-api.md:641:161 - Unknown word (autofixed) -- object will contain the autofixed code, along with any -./docs/src/integrate/nodejs-api.md:641:59 - Unknown word (autofixing) -- except that it also runs autofixing logic, similar to the ./docs/src/library/alert.md:9:12 - Unknown word (shortcode) -- There is a shortcode for each type of alert ./docs/src/maintain/manage-issues.md:32:4 - Unknown word (Triaging) -- ## Triaging Process ./docs/src/maintain/manage-releases.md:14:3 - Unknown word (Prereleases) -- * Prereleases that are not considered @@ -127,39 +105,26 @@ Lines: ./docs/src/pages/component-library.html:7:45 - Unknown word (shortcodes) -- on the left includes shortcodes, macros and partials ./docs/src/pages/rules.md:51:9 - Unknown word (endfor) -- {%- endfor -%} ./docs/src/rules/accessor-pairs.md:267:7 - Unknown word (Quux) -- const Quux = class { -./docs/src/rules/array-bracket-newline.md:22:138 - Unknown word (linebreak) -- bracket in the pair has a linebreak inside it and the other -./docs/src/rules/array-bracket-newline.md:22:47 - Unknown word (linebreaks) -- consistent usage of linebreaks for each pair of brackets -./docs/src/rules/array-bracket-newline.md:44:5 - Unknown word (dosomething) -- dosomething(); ./docs/src/rules/arrow-body-style.md:52:12 - Unknown word (retv) -- let bar = (retv, name) => { ./docs/src/rules/arrow-parens.md:15:79 - Unknown word (arity) -- parameters regardless of arity. For example: ./docs/src/rules/brace-style.md:25:54 - Unknown word (Stroustrup) -- brace style is called Stroustrup, in which the `else ./docs/src/rules/brace-style.md:36:26 - Unknown word (Allman) -- Another style is called [Allman](https://en.wikipedia ./docs/src/rules/brace-style.md:60:5 - Unknown word (stroustrup) -- * `"stroustrup"` enforces Stroustrup ./docs/src/rules/brace-style.md:61:5 - Unknown word (allman) -- * `"allman"` enforces Allman style -./docs/src/rules/callback-return.md:152:163 - Unknown word (IIFE) -- function expression (IIFE). -./docs/src/rules/camelcase.md:36:13 - Unknown word (camelcased) -- import { no_camelcased } from "external-module -./docs/src/rules/camelcase.md:52:18 - Unknown word (Camelcased) -- function bar({ isCamelcased: no_camelcased }) { ./docs/src/rules/capitalized-comments.md:272:84 - Unknown word (blockignore) -- { "ignorePattern": "blockignore" } }] */ ./docs/src/rules/comma-dangle.md:13:11 - Unknown word (quux) -- qux: "quux", ./docs/src/rules/complexity.md:21:1 - Unknown word (Cyclomatic) -- Cyclomatic complexity measures ./docs/src/rules/complexity.md:21:133 - Unknown word (cyclomatic) -- rule allows setting a cyclomatic complexity threshold -./docs/src/rules/consistent-return.md:76:16 - Unknown word (instanceof) -- if (!(this instanceof Foo)) { -./docs/src/rules/eqeqeq.md:2:8 - Unknown word (eqeqeq) -- title: eqeqeq ./docs/src/rules/eqeqeq.md:39:150 - Unknown word (typeof) -- of the operands is a `typeof` expression, or if both ./docs/src/rules/function-paren-newline.md:338:5 - Unknown word (barbaz) -- var barbaz = function( ./docs/src/rules/generator-star-spacing.md:85:40 - Unknown word (configurability) -- rule allows further configurability via overrides per function -./docs/src/rules/guard-for-in.md:21:5 - Unknown word (codebases) -- For codebases that do not support -./docs/src/rules/guard-for-in.md:6:16 - Unknown word (builtins) -- - no-prototype-builtins ./docs/src/rules/id-denylist.md:7:102 - Unknown word (Karlton) -- naming things." — Phil Karlton ./docs/src/rules/id-length.md:93:10 - Unknown word (foobaz) -- function foobaz({ a: prop }) { } ./docs/src/rules/indent-legacy.md:28:16 - Unknown word (Crockford) -- * Four spaces: Crockford ./docs/src/rules/indent-legacy.md:405:8 - Unknown word (boop) -- qux, boop) { ./docs/src/rules/indent-legacy.md:91:76 - Unknown word (declarators) -- indentation level for `var` declarators; can also take an object -./docs/src/rules/indent-legacy.md:92:76 - Unknown word (IIFEs) -- level for file-level IIFEs. ./docs/src/rules/key-spacing.md:194:5 - Unknown word (bcde) -- bcde: 42, ./docs/src/rules/key-spacing.md:216:5 - Unknown word (ijkl) -- ijkl: 'Non-consecutive lines -./docs/src/rules/lines-around-comment.md:36:10 - Unknown word (Hashbang) -- * `"afterHashbangComment": true` requires -./docs/src/rules/lines-around-comment.md:36:63 - Unknown word (hashbang) -- an empty line after hashbang comments ./docs/src/rules/max-lines-per-function.md:31:45 - Unknown word (dbname) -- return m("tr", {key: db.dbname}, [ ./docs/src/rules/no-buffer-constructor.md:13:407 - Unknown word (alloc) -- Buffer.from`, `Buffer.alloc`, and `Buffer.allocUnsafe ./docs/src/rules/no-cond-assign.md:2:11 - Unknown word (cond) -- title: no-cond-assign @@ -170,10 +135,7 @@ Lines: ./docs/src/rules/no-empty-character-class.md:40:13 - Unknown word (abcefg) -- regex.test("abcefg"); // false, the nested ./docs/src/rules/no-eq-null.md:61:41 - Unknown word (eqnull) -- rule corresponds to `eqnull` rule of JSHint. ./docs/src/rules/no-extend-native.md:74:34 - Unknown word (muhahaha) -- prototype.forEach = 'muhahaha'"); -./docs/src/rules/no-extra-parens.md:21:172 - Unknown word (iife) -- conflicts with the [wrap-iife](wrap-iife) rule ./docs/src/rules/no-fallthrough.md:59:12 - Unknown word (fallsthrough) -- // fallsthrough -./docs/src/rules/no-implicit-globals.md:119:26 - Unknown word (redeclarations) -- rule also disallows redeclarations of read-only global -./docs/src/rules/no-implicit-globals.md:24:3 - Unknown word (Redeclarations) -- * Redeclarations of read-only global ./docs/src/rules/no-irregular-whitespace.md:45:2 - Unknown word (ufeff) -- \ufeff - Zero Width No-Break ./docs/src/rules/no-irregular-whitespace.md:57:30 - Unknown word (ZWSP) -- Zero Width Space - ./docs/src/rules/no-loop-func.md:11:5 - Unknown word (funcs) -- funcs[i] = function() { @@ -185,7 +147,6 @@ Lines: ./docs/src/rules/no-proto.md:2:11 - Unknown word (proto) -- title: no-proto ./docs/src/rules/no-prototype-builtins.md:10:216 - Unknown word (webserver) -- would be unsafe for a webserver to parse JSON input ./docs/src/rules/no-redeclare.md:5:68 - Unknown word (redeclares) -- TypeScript will catch `let` redeclares and `const` redeclares -./docs/src/rules/no-redeclare.md:72:41 - Unknown word (redeclaration) -- this rule also checks redeclaration of built-in globals ./docs/src/rules/no-restricted-globals.md:28:54 - Unknown word (fdescribe) -- ["error", "event", "fdescribe"] ./docs/src/rules/no-restricted-imports.md:125:154 - Unknown word (punycode) -- ,"net","os","path","punycode","querystring","readline ./docs/src/rules/no-restricted-imports.md:125:165 - Unknown word (querystring) -- ,"path","punycode","querystring","readline","repl", @@ -197,15 +158,10 @@ Lines: ./docs/src/rules/no-return-await.md:12:172 - Unknown word (microtask) -- the cost of an extra microtask before resolving the ./docs/src/rules/no-script-url.md:29:41 - Unknown word (scripturl) -- rule corresponds to `scripturl` rule of JSHint. ./docs/src/rules/no-unexpected-multiline.md:14:78 - Unknown word (Schlueter) -- once described by Isaac Schlueter, a newline character -./docs/src/rules/no-unsafe-finally.md:119:22 - Unknown word (hola) -- console.log("hola!"); ./docs/src/rules/no-unsafe-finally.md:44:69 - Unknown word (rethrown) -- block is caught and rethrown ./docs/src/rules/no-unused-vars.md:160:67 - Unknown word (gnored) -- varsIgnorePattern": "[iI]gnored" }` option: ./docs/src/rules/no-unused-vars.md:55:31 - Unknown word (destructures) -- function definition destructures an array, unused entries ./docs/src/rules/no-use-before-define.md:160:21 - Unknown word (nofunc) -- This rule accepts `"nofunc"` string as an option -./docs/src/rules/no-useless-backreference.md:14:337 - Unknown word (lookaround) -- is inside a negative lookaround. However, by the specificatio -./docs/src/rules/no-useless-backreference.md:16:1 - Unknown word (Backreferences) -- Backreferences that always successfully -./docs/src/rules/no-useless-backreference.md:36:53 - Unknown word (backreferences) -- disallow the following backreferences in regular expression -./docs/src/rules/no-useless-backreference.md:39:178 - Unknown word (lookbehinds) -- forward references. Inside lookbehinds, which match backward ./docs/src/rules/nonblock-statement-body-position.md:2:8 - Unknown word (nonblock) -- title: nonblock-statement-body-position ./docs/src/rules/object-property-newline.md:124:24 - Unknown word (colocation) -- The rule prohibits the colocation on any line of at least ./docs/src/rules/object-property-newline.md:128:31 - Unknown word (Europese) -- Officiële website van de Europese Unie', @@ -226,7 +182,6 @@ Lines: ./docs/src/rules/one-var.md:428:9 - Unknown word (fooqux) -- let fooqux, foonorf; ./docs/src/rules/one-var.md:725:38 - Unknown word (onevar) -- This rule maps to the `onevar` JSHint rule, but allows ./docs/src/rules/one-var.md:81:9 - Unknown word (norf) -- let norf; -./docs/src/rules/padding-line-between-statements.md:37:24 - Unknown word (LINEBREAK) -- { "blankLine": LINEBREAK_TYPE, "prev": STATEMENT ./docs/src/rules/padding-line-between-statements.md:81:9 - Unknown word (singleline) -- * `"singleline-const"` is single-line ./docs/src/rules/prefer-named-capture-group.md:21:19 - Unknown word (cauli) -- const regex = /(?:cauli|sun)flower/; ./docs/src/rules/radix.md:10:305 - Unknown word (autodetected) -- , `parseInt()` also autodetected octal literals, which @@ -248,10 +203,7 @@ Lines: ./docs/src/use/command-line-interface.md:277:68 - Unknown word (levn) -- configuration specified with [levn](https://github.com ./docs/src/use/command-line-interface.md:428:5 - Unknown word (myfile) -- cat myfile.js | npx eslint --stdin ./docs/src/use/command-line-interface.md:520:17 - Unknown word (customformat) -- npx eslint -f ./customformat.js file.js -./docs/src/use/command-line-interface.md:605:1 - Unknown word (Autofixed) -- Autofixed files are not placed -./docs/src/use/configure/configuration-files-new.md:181:112 - Unknown word (unignores) -- example, this config unignores `node_modules/mylibrary ./docs/src/use/configure/configuration-files-new.md:181:136 - Unknown word (mylibrary) -- unignores `node_modules/mylibrary`: -./docs/src/use/configure/configuration-files-new.md:181:14 - Unknown word (unignore) -- You can also unignore files and directories ./docs/src/use/configure/configuration-files-new.md:268:564 - Unknown word (runtimes) -- example, some older runtimes might only allow ECMAScript ./docs/src/use/configure/configuration-files.md:45:25 - Unknown word (myfiletotest) -- eslint -c myconfig.json myfiletotest.js ./docs/src/use/configure/ignore.md:102:200 - Unknown word (jshintignore) -- example, you can use `.jshintignore` file because it has @@ -275,12 +227,6 @@ Lines: ./docs/src/use/configure/migration-guide.md:550:42 - Unknown word (dotfile) -- config, dotfiles (e.g. `.dotfile.js`) are no longer ignored ./docs/src/use/configure/plugins.md:44:152 - Unknown word (pluginname) -- require('eslint-plugin-pluginname')` in the config file ./docs/src/use/configure/rules.md:25:294 - Unknown word (buildtime) -- other than a potential buildtime or runtime error (such -./docs/src/use/formatters/index.md:17:4 - Unknown word (checkstyle) -- * [checkstyle](#checkstyle) -./docs/src/use/formatters/index.md:70:25 - Unknown word (Checkstyle) -- Outputs results to the [Checkstyle](https://checkstyle -./docs/src/use/formatters/index.md:893:2 - Unknown word (testsuites) -- -./docs/src/use/formatters/index.md:894:2 - Unknown word (testsuite) -- The `CLIEngine ./docs/src/use/migrating-from-jscs.md:12:111 - Unknown word (jscsrs) -- .jscsrc.yaml`, or `.jscsrs.js`. In ESLint, the ./docs/src/use/migrating-from-jscs.md:15:38 - Unknown word (Polyjuice) -- Configuration Files Using Polyjuice @@ -300,12 +245,10 @@ Lines: ./docs/src/use/migrating-to-2.0.0.md:347:45 - Unknown word (FEFF) -- parse(text.replace(/^\uFEFF/, ""), options); ./docs/src/use/migrating-to-3.0.0.md:47:229 - Unknown word (lifed) -- Explorer 8 was end-of-lifed](https://www.microsoft ./docs/src/use/migrating-to-5.0.0.md:114:68 - Unknown word (lintable) -- line does not match any lintable files -./lib/cli-engine/cli-engine.js:47:4 - Unknown word (Typedefs) -- // Typedefs ./lib/cli-engine/formatters/html.js:247:66 - Unknown word (noopener) -- target="_blank" rel="noopener noreferrer">${ruleId ./lib/cli-engine/formatters/html.js:247:75 - Unknown word (noreferrer) -- blank" rel="noopener noreferrer">${ruleId ? ruleId ./lib/cli-engine/formatters/html.js:303:9 - Unknown word (colspan) -- ./lib/cli-engine/formatters/html.js:46:48 - Unknown word (Neue) -- family: Arial, "Helvetica Neue", Helvetica, sans-serif -./lib/cli-engine/hash.js:12:25 - Unknown word (imurmurhash) -- const murmur = require("imurmurhash"); ./lib/cli-engine/lint-result-cache.js:14:58 - Unknown word (jsonify) -- stable-stringify-without-jsonify"); ./lib/cli-engine/xml-escape.js:29:26 - Unknown word (apos) -- return "'"; ./lib/cli.js:27:38 - Unknown word (humanwhocodes) -- ModuleImporter } = require("@humanwhocodes/module-importer"); @@ -319,25 +262,17 @@ Lines: ./lib/linter/code-path-analysis/code-path-state.js:1730:23 - Unknown word (Segs) -- const prevSegsOfLeavingSegment = [headOfLeav ./lib/linter/code-path-analysis/code-path-state.js:351:34 - Unknown word (expresion) -- The end of the update expresion. This may change during ./lib/linter/code-path-analysis/code-path-state.js:774:31 - Unknown word (unflattened) -- {CodePathSegment[]} unflattenedFromSegments Segments -./lib/linter/code-path-analysis/debug-helpers.js:105:54 - Unknown word (fillcolor) -- style=\"rounded,filled\",fillcolor=white];\n" + -./lib/linter/code-path-analysis/debug-helpers.js:109:45 - Unknown word (doublecircle) -- final[label=\"\",shape=doublecircle,style=filled,fillcolor -./lib/linter/code-path-analysis/debug-helpers.js:112:75 - Unknown word (fixedsize) -- width=0.3,height=0.3,fixedsize=true];\n"; ./lib/linter/code-path-analysis/debug-helpers.js:95:44 - Unknown word (Graphvis) -- can be visualized with Graphvis. ./lib/linter/config-comment-parser.js:82:22 - Unknown word (commaless) -- // Also, commaless notations have invalid ./lib/linter/config-comment-parser.js:93:20 - Unknown word (Levn) -- debug("Levn parsing failed; falling ./lib/linter/config-comment-parser.js:99:12 - Unknown word (Optionator) -- * Optionator cannot parse commaless ./lib/linter/linter.js:113:52 - Unknown word (postprocessor) -- postprocess} [postprocess] postprocessor for report -./lib/linter/linter.js:48:11 - Unknown word (AUTOFIX) -- const MAX_AUTOFIX_PASSES = 10; ./lib/linter/linter.js:918:18 - Unknown word (SOURCECODE) -- const DEPRECATED_SOURCECODE_PASSTHROUGHS = { ./lib/linter/linter.js:918:29 - Unknown word (PASSTHROUGHS) -- DEPRECATED_SOURCECODE_PASSTHROUGHS = { ./lib/options.js:2:44 - Unknown word (optionator) -- Options configuration for optionator. ./lib/rule-tester/flat-rule-tester.js:236:42 - Unknown word (errorize) -- ast The root node to errorize `start`/`end` properties ./lib/rule-tester/flat-rule-tester.js:791:27 - Unknown word (Didnt) -- function assertASTDidntChange(beforeAST, afterAST ./lib/rule-tester/rule-tester.js:10:52 - Unknown word (unittests) -- mocha to allow for DRY unittests for eslint -./lib/rules/array-bracket-newline.js:207:24 - Unknown word (Linebreaks) -- const needsLinebreaks = ( -./lib/rules/array-bracket-newline.js:54:30 - Unknown word (Linebreak) -- unexpectedOpeningLinebreak: "There should be no -./lib/rules/array-callback-return.js:163:21 - Unknown word (Parenthesised) -- !astUtils.isParenthesised(sourceCode, node); -./lib/rules/arrow-body-style.js:230:33 - Unknown word (parenthesised) -- let parenthesisedObjectLiteral = null ./lib/rules/dot-notation.js:138:63 - Unknown word (quasis) -- node, node.property.quasis[0].value.cooked); ./lib/rules/for-direction.js:73:65 - Unknown word (nochange) -- if sub return -1, if nochange, return 0 ./lib/rules/func-name-matching.js:13:7 - Unknown word (esutils) -- const esutils = require("esutils" @@ -346,7 +281,6 @@ Lines: ./lib/rules/indent-legacy.js:573:43 - Unknown word (IIEF) -- that the node is an IIEF ./lib/rules/indent-legacy.js:918:66 - Unknown word (blockless) -- for indentation for blockless nodes ./lib/rules/indent.js:902:21 - Unknown word (Blockless) -- function addBlocklessNodeIndent(node) { -./lib/rules/jsx-quotes.js:22:23 - Unknown word (singlequote) -- description: "singlequote", ./lib/rules/keyword-spacing.js:151:18 - Unknown word (unexpect) -- function unexpectSpaceBefore(token, pattern ./lib/rules/lines-around-comment.js:23:22 - Unknown word (Nums) -- function getEmptyLineNums(lines) { ./lib/rules/logical-assignment-operators.js:115:4 - Unknown word (falsiness) -- * falsiness checks: !value, !Boolean @@ -354,7 +288,6 @@ Lines: ./lib/rules/no-caller.js:38:106 - Unknown word (calle) -- propertyName.match(/^calle[er]$/u)) { ./lib/rules/no-constant-binary-expression.js:35:59 - Unknown word (nullishness) -- statically knowable constant nullishness. Meaning, ./lib/rules/no-constant-binary-expression.js:44:21 - Unknown word (Nullishness) -- function hasConstantNullishness(scope, node, nonNullish -./lib/rules/no-control-regex.js:8:52 - Unknown word (regexpp) -- require("@eslint-community/regexpp").RegExpValidator; ./lib/rules/no-else-return.js:315:50 - Unknown word (codepath) -- node returns in every codepath. ./lib/rules/no-else-return.js:351:19 - Unknown word (consequents) -- const consequents = []; ./lib/rules/no-else-return.js:80:16 - Unknown word (Redeclaring) -- * Redeclaring any of these would cause @@ -364,7 +297,6 @@ Lines: ./lib/rules/no-extra-parens.js:2:60 - Unknown word (subexpressions) -- enthesising higher precedence subexpressions. ./lib/rules/no-extra-parens.js:559:28 - Unknown word (logicals) -- * Evaluate binary logicals ./lib/rules/no-extra-parens.js:565:19 - Unknown word (prec) -- const prec = precedence(node); -./lib/rules/no-extra-parens.js:806:81 - Unknown word (unparenthesized) -- left-hand side is an *unparenthesized* ./lib/rules/no-implicit-coercion.js:14:39 - Unknown word (ndex) -- PATTERN = /^(?:i|lastI)ndexOf$/u; ./lib/rules/no-inline-comments.js:61:17 - Unknown word (postamble) -- postamble = endLine.slice(node ./lib/rules/no-inline-comments.js:63:19 - Unknown word (Postamble) -- isPostambleEmpty = !postamble; @@ -374,28 +306,20 @@ Lines: ./lib/rules/no-new-native-nonconstructor.js:32:18 - Unknown word (Nonconstructor) -- noNewNonconstructor: "`{{name}}` cannot ./lib/rules/no-trailing-spaces.js:60:13 - Unknown word (NONBLANK) -- NONBLANK = `${BLANK_CLASS}+$ ./lib/rules/no-useless-backreference.js:114:37 - Unknown word (bref's) -- // group is bref's ancestor => bref is -./lib/rules/no-useless-backreference.js:43:12 - Unknown word (Lookaround) -- function isLookaround(node) { ./lib/rules/no-useless-backreference.js:75:40 - Unknown word (bref) -- "Backreference '{{ bref }}' will be ignored ./lib/rules/no-useless-escape.js:32:47 - Unknown word (nrvtbfux) -- ESCAPES = union(new Set("\\nrvtbfux"), astUtils.LINEBREAKS -./lib/rules/no-useless-escape.js:32:68 - Unknown word (LINEBREAKS) -- nrvtbfux"), astUtils.LINEBREAKS); ./lib/rules/no-useless-escape.js:33:45 - Unknown word (Dfnp) -- ESCAPES = new Set("\\bcdDfnpPrsStvwWxu0123456789 ./lib/rules/no-useless-escape.js:33:52 - Unknown word (Stvw) -- new Set("\\bcdDfnpPrsStvwWxu0123456789]"); ./lib/rules/no-useless-escape.js:34:17 - Unknown word (CHARCLASS) -- const REGEX_NON_CHARCLASS_ESCAPES = union(REGEX ./lib/rules/no-useless-escape.js:40:13 - Unknown word (CLASSSET) -- const REGEX_CLASSSET_CHARACTER_ESCAPES = -./lib/rules/no-var.js:102:12 - Unknown word (Redeclared) -- function isRedeclared(variable) { ./lib/rules/object-shorthand.js:102:34 - Unknown word (Longform) -- expectedLiteralMethodLongform: "Expected longform ./lib/rules/object-shorthand.js:102:54 - Unknown word (longform) -- eralMethodLongform: "Expected longform method syntax for string -./lib/rules/prefer-object-spread.js:173:4 - Unknown word (Autofixes) -- * Autofixes the Object.assign call -./lib/rules/prefer-object-spread.js:176:24 - Unknown word (autofixer) -- @returns {Function} autofixer - replaces the Object ./lib/rules/prefer-object-spread.js:61:42 - Unknown word (sourcecode) -- sourceCode in context sourcecode object -./lib/rules/prefer-regex-literals.js:16:9 - Unknown word (REGEXPP) -- const { REGEXPP_LATEST_ECMA_VERSION -./lib/rules/prefer-regex-literals.js:246:21 - Unknown word (Regexpp) -- function getRegexppEcmaVersion(ecmaVersion ./lib/rules/quotes.js:42:17 - Unknown word (unescaping) -- * escaping and unescaping as necessary. ./lib/rules/sort-vars.js:53:23 - Unknown word (unfixable) -- const unfixable = idDeclarations.some ./lib/rules/space-unary-ops.js:133:28 - Unknown word (Doesnt) -- function verifyWordDoesntHaveSpaces(node, firstToken ./lib/rules/space-unary-ops.js:246:32 - Unknown word (Dont) -- function verifyNonWordsDontHaveSpaces(node, firstToken ./lib/rules/utils/ast-utils.js:1041:89 - Unknown word (braket) -- opening parenthesis or braket. -./lib/rules/utils/ast-utils.js:2136:80 - Unknown word (hashbangs) -- ESLint itself handles hashbangs. ./lib/rules/utils/ast-utils.js:396:40 - Unknown word (samely) -- a.b` and `a?.b` are samely. ./lib/rules/utils/patterns/letters.js:12:24 - Unknown word (Dulin) -- Copyright 2013-2016 Dulin Marat and other contributors ./lib/shared/config-validator.js:286:55 - Unknown word (ECMAFEATURES) -- source, "ESLINT_LEGACY_ECMAFEATURES"); @@ -419,13 +343,8 @@ Lines: ./tests/fixtures/parsers/arrow-parens/identifier-type.js:323:17 - Unknown word (binop) -- binop: null, ./tests/fixtures/parsers/typescript-parsers/declare-class.js:4:14 - Unknown word (astexplorer) -- * Parsed on astexplorer.net using @typescript ./tests/fixtures/rules/indent-legacy/indent-invalid-fixture-1.js:440:40 - Unknown word (youll) -- terribly long description youll ' + -./tests/lib/cli-engine/cli-engine.js:1072:60 - Unknown word (hiddenfolder) -- executeOnFiles(["hidden/.hiddenfolder/*.js"]); -./tests/lib/cli-engine/cli-engine.js:1174:52 - Unknown word (unignored) -- hidden files if they are unignored with an --ignore-pattern -./tests/lib/cli-engine/cli-engine.js:1648:60 - Unknown word (rulesdirs) -- etFixturePath("rules", "multi-rulesdirs.json") -./tests/lib/cli-engine/cli-engine.js:1813:51 - Unknown word (autocrlf) -- workaround for git's autocrlf option on Windows. -./tests/lib/cli-engine/cli-engine.js:1836:95 - Unknown word (fixmode) -- fixtureDir, `${fixtureDir}/fixmode`)]); +./tests/lib/cli-engine/cli-engine.js:1836:95 - Unknown word (fixmode) -- fixtureDir, `${fixtureDir}/fixmode`)]); ./tests/lib/cli-engine/cli-engine.js:410:37 - Unknown word (layou) -- fixTypes: ["layou"] -./tests/lib/cli-engine/cli-engine.js:4415:115 - Unknown word (Unignored) -- , ".eslintignoreWithUnignoredDefaults") }); ./tests/lib/cli-engine/cli-engine.js:4500:53 - Unknown word (sampleignorepattern) -- eslintignore` includes `sampleignorepattern`. ./tests/lib/cli-engine/cli-engine.js:4847:51 - Unknown word (somenamespace) -- engine.getFormatter("@somenamespace/foo"); ./tests/lib/cli-engine/cli-engine.js:4863:63 - Unknown word (doesntexist) -- getFixturePath("formatters", "doesntexist.js"), @@ -445,15 +364,12 @@ Lines: ./tests/lib/eslint/flat-eslint.js:1687:30 - Unknown word (reignoring) -- it("should allow reignoring of previously ignored ./tests/lib/eslint/flat-eslint.js:5316:31 - Unknown word (reignore) -- cwd: `${root}-reignore`, ./tests/lib/eslint/flat-eslint.js:5356:31 - Unknown word (dignore) -- cwd: `${root}-dignore`, -./tests/lib/linter/code-path-analysis/code-path-analyzer.js:30:16 - Unknown word (ESQUERY) -- const STANDARD_ESQUERY_OPTION = { visitorKeys ./tests/lib/linter/config-comment-parser.js:165:41 - Unknown word (ELEVENTEEN) -- code = "a: seventy, b:ELEVENTEEN"; ./tests/lib/linter/linter.js:17912:52 - Unknown word (intentionaly) -- // intentionaly mutates objects and ./tests/lib/linter/linter.js:3550:1 - Unknown word (consolexlog) -- consolexlog("test2"); ./tests/lib/linter/linter.js:3696:84 - Unknown word (rulename) -- this is 2, since the rulename is very likely to be ./tests/lib/linter/linter.js:5692:31 - Unknown word (suppresed) -- it("should report one suppresed problem when noInlineConfig ./tests/lib/linter/linter.js:7851:19 - Unknown word (postprocessors) -- describe("postprocessors", () => { -./tests/lib/linter/linter.js:7904:28 - Unknown word (postprocessed) -- it("should use postprocessed problem ranges when -./tests/lib/linter/node-event-generator.js:25:7 - Unknown word (ESPREE) -- const ESPREE_CONFIG = { ./tests/lib/linter/node-event-generator.js:298:68 - Unknown word (pseudoclasses) -- // 0 identifiers, 0 pseudoclasses ./tests/lib/linter/node-event-generator.js:304:66 - Unknown word (pseudoclass) -- ].expression], // 1 pseudoclass, 0 identifiers ./tests/lib/linter/report-translator.js:337:32 - Unknown word (fooo) -- text: "fooo\nbar" @@ -468,16 +384,14 @@ Lines: ./tests/lib/rule-tester/flat-rule-tester.js:2309:33 - Unknown word (outpt) -- outpt: "var baz;" ./tests/lib/rule-tester/flat-rule-tester.js:2744:15 - Unknown word (Subclassing) -- describe("Subclassing", () => { ./tests/lib/rule-tester/flat-rule-tester.js:989:22 - Unknown word (noeval) -- "noeval('foo')" -./tests/lib/rules/array-bracket-newline.js:57:50 - Unknown word (ndosomething) -- [\nfunction foo() {\ndosomething();\n}\n];", ./tests/lib/rules/array-bracket-spacing.js:51:47 - Unknown word (n'qux) -- [{\n'bar': 'baz', \n'qux': [{ 'bar': 'baz' } ./tests/lib/rules/array-bracket-spacing.js:51:76 - Unknown word (n'quxx) -- { 'bar': 'baz' }], \n'quxx': 1 \n}]", options: ./tests/lib/rules/array-element-newline.js:45:78 - Unknown word (nosomething) -- ,\nfunction bar() {\nosomething();\n}\n];", ./tests/lib/rules/arrow-body-style.js:27:38 - Unknown word (nretv) -- = (retv, name) => {\nretv[name] = true;\nreturn ./tests/lib/rules/brace-style.js:103:35 - Unknown word (fontstack) -- code: "if (tag === 1) fontstack.name = pbf.readString ./tests/lib/rules/brace-style.js:32:44 - Unknown word (Varint) -- glyph.id = pbf.readVarint();\nelse if (tag == -./tests/lib/rules/capitalized-comments.js:164:29 - Unknown word (Fileoverview) -- code: "/**\n * @Fileoverview This is a file */", -./tests/lib/rules/capitalized-comments.js:344:22 - Unknown word (über) -- code: "//über", -./tests/lib/rules/capitalized-comments.js:345:24 - Unknown word (Über) -- output: "//Über", +./tests/lib/rules/capitalized-comments.js:344:22 - Unknown word (über) -- code: "//über", +./tests/lib/rules/capitalized-comments.js:345:24 - Unknown word (Über) -- output: "//Über", ./tests/lib/rules/comma-spacing.js:22:10 - Unknown word (myfunc) -- "myfunc(404, true/* bla bla ./tests/lib/rules/comma-style.js:268:38 - Unknown word (fifi) -- "const arr = [\n ,'fifi' \n]", ./tests/lib/rules/comma-style.js:69:36 - Unknown word (nsnd) -- code: "var ar ={fst:1,\nsnd: [1,\n2]};", @@ -514,7 +428,6 @@ Lines: ./tests/lib/rules/no-duplicate-imports.js:94:32 - Unknown word (modns) -- code: "import * as modns from \"lodash-es\"; ./tests/lib/rules/no-eval.js:41:29 - Unknown word (noneval) -- { code: "globalThis.noneval('foo')", env: { es2 ./tests/lib/rules/no-extra-parens.js:781:32 - Unknown word (ipaddr) -- code: "const net = ipaddr.parseCIDR(/** @type -./tests/lib/rules/no-implicit-globals.js:26:15 - Unknown word (Redeclaration) -- const readonlyRedeclarationMessage = "Unexpected ./tests/lib/rules/no-inline-comments.js:127:37 - Unknown word (otherthing) -- ignorePattern: "otherthing" ./tests/lib/rules/no-invalid-regexp.js:70:35 - Unknown word (Nandinagari) -- RegExp('\\\\p{Script=Nandinagari}', 'u');", ./tests/lib/rules/no-invalid-regexp.js:74:35 - Unknown word (Cpmn) -- RegExp('\\\\p{Script=Cpmn}', 'u')", @@ -528,13 +441,11 @@ Lines: ./tests/lib/rules/no-prototype-builtins.js:233:52 - Unknown word (Expresion) -- OwnProperty is part of a ChainExpresion ./tests/lib/rules/no-prototype-builtins.js:44:35 - Unknown word (Enumerabl) -- code: "foo?.['propertyIsEnumerabl']('bar')", parserOptions ./tests/lib/rules/no-restricted-imports.js:359:84 - Unknown word (subimports) -- message: "some foo subimports are restricted" }] -./tests/lib/rules/no-restricted-imports.js:50:31 - Unknown word (Gitignores) -- code: "import withGitignores from \"foo/bar\";", ./tests/lib/rules/no-script-url.js:25:21 - Unknown word (xjavascript) -- "var url = 'xjavascript:'", ./tests/lib/rules/no-tabs.js:24:17 - Unknown word (sdfdsf) -- " // sdfdsf \n" + ./tests/lib/rules/no-tabs.js:60:19 - Unknown word (tsdfdsf) -- " //\tsdfdsf \n" + ./tests/lib/rules/no-undefined.js:38:10 - Unknown word (ndefined) -- "ndefined", ./tests/lib/rules/no-unexpected-multiline.js:307:22 - Unknown word (gimuygimuygimuy) -- /bar/gimuygimuygimuy.test(baz) -./tests/lib/rules/no-unsafe-finally.js:42:123 - Unknown word (Hola) -- static ehm() { return 'Hola!'; } } } };", ./tests/lib/rules/no-unused-vars.js:957:32 - Unknown word (fooz) -- code: "/* global a$fooz,$foo */\na$fooz;", ./tests/lib/rules/no-use-before-define.js:1129:17 - Unknown word (mdjermanovic) -- * TODO(mdjermanovic): Add the following ./tests/lib/rules/no-warning-comments.js:153:30 - Unknown word (litera) -- code: "// regex [litera|$]", @@ -582,7 +493,6 @@ Lines: ./tests/performance/jshint.js:11020:10 - Unknown word (verif) -- function verifIEEE754(value, max, min ./tests/performance/jshint.js:1125:6 - Unknown word (anonname) -- var anonname, // The guessed name ./tests/performance/jshint.js:1166:4 - Unknown word (funcscope) -- funcscope : true, // if only -./tests/performance/jshint.js:1168:4 - Unknown word (globalstrict) -- globalstrict: true, // if global ./tests/performance/jshint.js:1169:4 - Unknown word (immed) -- immed : true, // if ./tests/performance/jshint.js:1172:4 - Unknown word (lastsemic) -- lastsemic : true, // if semicolons ./tests/performance/jshint.js:1174:4 - Unknown word (laxbreak) -- laxbreak : true, // if line diff --git a/integration-tests/src/reporter/index.ts b/integration-tests/src/reporter/index.ts index 69674ffbabb..f495ea0fc94 100644 --- a/integration-tests/src/reporter/index.ts +++ b/integration-tests/src/reporter/index.ts @@ -1,9 +1,10 @@ -import type { CSpellReporter, Issue, RunResult } from '@cspell/cspell-types'; +import type { CSpellReporter, Issue, ReporterConfiguration, RunResult } from '@cspell/cspell-types'; import * as vscodeUri from 'vscode-uri'; import { readConfig } from '../config'; import type { Repository } from '../configDef'; import { writeSnapshotRaw } from '../snapshots'; +import type { IssueSummary } from './reportGenerator'; import { generateReport } from './reportGenerator'; import { stringify } from './stringify'; @@ -13,10 +14,18 @@ const noopReporter = () => { return; }; -export function getReporter(): CSpellReporter { +interface Config extends ReporterConfiguration { + issuesSummaryReport?: boolean; +} + +export function getReporter(_settings: unknown, config?: Config): CSpellReporter { + const issueFilter = config?.unique ? uniqueFilter((i: Issue) => i.text) : () => true; const issues: Issue[] = []; const errors: string[] = []; const files: string[] = []; + const issuesSummaryReport = !!config?.issuesSummaryReport; + const issuesSummary = new Map(); + const summaryAccumulator = createIssuesSummaryAccumulator(issuesSummary); async function processResult(result: RunResult): Promise { const root = URI.file(process.cwd()); @@ -27,6 +36,7 @@ export function getReporter(): CSpellReporter { runResult: result, root, repository: fetchRepositoryInfo(root), + issuesSummary: issuesSummaryReport && issuesSummary.size ? [...issuesSummary.values()] : undefined, }); const repPath = extractRepositoryPath(root); writeSnapshotRaw(repPath, 'report.yaml', stringify(report)); @@ -34,7 +44,10 @@ export function getReporter(): CSpellReporter { const reporter: CSpellReporter = { issue: (issue) => { - issues.push(issue); + summaryAccumulator(issue); + if (issueFilter(issue)) { + issues.push(issue); + } }, info: noopReporter, debug: noopReporter, @@ -60,3 +73,33 @@ function fetchRepositoryInfo(root: vscodeUri.URI): Repository | undefined { const path = extractRepositoryPath(root); return reps.get(path); } + +function uniqueFilter(keyFn: (v: T) => K): (v: T) => boolean { + const seen = new Set(); + return (v) => { + const k = keyFn(v); + if (seen.has(k)) return false; + seen.add(k); + return true; + }; +} + +function createIssuesSummaryAccumulator(issuesSummary: Map): (issue: Issue) => void { + function uniqueKey(issue: Issue): string { + return [issue.text, issue.uri || ''].join('::'); + } + + const isUnique = uniqueFilter(uniqueKey); + + return (issue: Issue) => { + const { text } = issue; + const summary = issuesSummary.get(text) || { text, count: 0, files: 0 }; + const unique = isUnique(issue); + summary.count += 1; + summary.files += unique ? 1 : 0; + if (issue.isFlagged) { + summary.isFlagged = true; + } + issuesSummary.set(text, summary); + }; +} diff --git a/integration-tests/src/reporter/reportGenerator.ts b/integration-tests/src/reporter/reportGenerator.ts index 2487211f21e..be77f50e0ff 100644 --- a/integration-tests/src/reporter/reportGenerator.ts +++ b/integration-tests/src/reporter/reportGenerator.ts @@ -8,6 +8,7 @@ export type Report = { errors: string[]; summary: Summary; repository: Repository | undefined; + issuesSummary: IssueSummary[]; }; export interface Summary { @@ -17,6 +18,13 @@ export interface Summary { errors: number; } +export interface IssueSummary { + text: string; + isFlagged?: boolean | undefined; + count: number; + files: number; +} + type SortedFileIssues = FileIssue[]; type FileIssue = string; @@ -27,6 +35,7 @@ export interface ReportData { root: Uri; runResult: RunResult; repository: Repository | undefined; + issuesSummary?: IssueSummary[] | undefined; } const compare = new Intl.Collator().compare; @@ -61,6 +70,7 @@ export function generateReport(data: ReportData): Report { const base: SortedFileIssues = []; const fileIssues: SortedFileIssues = base.concat(...issuesByFile); + const issuesSummary = [...(data.issuesSummary || [])].sort((a, b) => compare(a.text, b.text)); return { fileIssues, @@ -72,6 +82,7 @@ export function generateReport(data: ReportData): Report { errors: runResult.errors, }, repository: data.repository, + issuesSummary, }; } diff --git a/integration-tests/src/reporter/stringify.ts b/integration-tests/src/reporter/stringify.ts index 581dd809854..0c45de216c0 100644 --- a/integration-tests/src/reporter/stringify.ts +++ b/integration-tests/src/reporter/stringify.ts @@ -29,5 +29,17 @@ export function stringify(report: Report): string { defaultKeyType: 'PLAIN', doubleQuotedAsJSON: true, }); - return [header, issues].join('\n'); + + const issuesSummary = report.issuesSummary?.length + ? stringifyYaml( + { + issuesSummary: report.issuesSummary.map((issue) => + stringifyYaml(issue).replace(/\n/g, ', ').replace(/\s+/g, ' ').trim(), + ), + }, + { lineWidth: 200 }, + ) + : ''; + + return [header, issues, issuesSummary].filter((a) => !!a).join('\n'); } diff --git a/packages/cspell/src/app/application.ts b/packages/cspell/src/app/application.ts index a9988dfc3c5..28df54612f0 100644 --- a/packages/cspell/src/app/application.ts +++ b/packages/cspell/src/app/application.ts @@ -33,7 +33,7 @@ export function lint(fileGlobs: string[], options: LinterCliOptions, reporter?: const cfg = new LintRequest( fileGlobs, options, - finalizeReporter(reporter) ?? getReporter({ ...options, fileGlobs }), + finalizeReporter(reporter) ?? getReporter({ ...options, fileGlobs }, options), ); return runLint(cfg); } diff --git a/packages/cspell/src/app/cli-reporter.ts b/packages/cspell/src/app/cli-reporter.ts index 3ca1fb8be47..8165a3f632e 100644 --- a/packages/cspell/src/app/cli-reporter.ts +++ b/packages/cspell/src/app/cli-reporter.ts @@ -4,6 +4,7 @@ import type { ProgressFileBegin, ProgressFileComplete, ProgressItem, + ReporterConfiguration, RunResult, } from '@cspell/cspell-types'; import chalk from 'chalk'; @@ -15,6 +16,7 @@ import { URI } from 'vscode-uri'; import type { LinterCliOptions } from './options.js'; import type { FinalizedReporter } from './util/reporters.js'; +import { uniqueFilterFnGenerator } from './util/util.js'; const templateIssue = `{green $filename}:{yellow $row:$col} - $message ({red $text}) $quickFix`; const templateIssueNoFix = `{green $filename}:{yellow $row:$col} - $message ({red $text})`; @@ -29,12 +31,14 @@ interface ReporterIssue extends Issue { filename: string; } -function genIssueEmitter(template: string) { +function genIssueEmitter(template: string, uniqueIssues: boolean) { + const uniqueFilter = uniqueIssues ? uniqueFilterFnGenerator((issue: Issue) => issue.text) : () => true; const defaultWidth = 10; let maxWidth = defaultWidth; let uri: string | undefined; return function issueEmitter(issue: ReporterIssue) { + if (!uniqueFilter(issue)) return; if (uri !== issue.uri) { maxWidth = defaultWidth; uri = issue.uri; @@ -120,7 +124,8 @@ export interface ReporterOptions fileGlobs: string[]; } -export function getReporter(options: ReporterOptions): FinalizedReporter { +export function getReporter(options: ReporterOptions, config?: ReporterConfiguration): FinalizedReporter { + const uniqueIssues = config?.unique || false; const issueTemplate = options.wordsOnly ? templateIssueWordsOnly : options.legacy @@ -183,7 +188,7 @@ export function getReporter(options: ReporterOptions): FinalizedReporter { }; return { - issue: relativeIssue(silent || !issues ? nullEmitter : genIssueEmitter(issueTemplate)), + issue: relativeIssue(silent || !issues ? nullEmitter : genIssueEmitter(issueTemplate, uniqueIssues)), error: silent ? nullEmitter : errorEmitter, info: infoEmitter, debug: emitters.Debug, diff --git a/packages/cspell/src/app/commandLint.ts b/packages/cspell/src/app/commandLint.ts index bef26d0edd9..fd55c2b08e0 100644 --- a/packages/cspell/src/app/commandLint.ts +++ b/packages/cspell/src/app/commandLint.ts @@ -164,6 +164,7 @@ export function commandLint(prog: Command): Command { .implies({ cache: false }) .hideHelp(), ) + .addOption(new CommanderOption('--issues-summary-report', 'Output a summary of issues found.').hideHelp()) .usage(usage) .addHelpText('after', advanced) .arguments('[globs...]') diff --git a/packages/cspell/src/app/lint/LintRequest.ts b/packages/cspell/src/app/lint/LintRequest.ts index e0c94bee891..328e3093e09 100644 --- a/packages/cspell/src/app/lint/LintRequest.ts +++ b/packages/cspell/src/app/lint/LintRequest.ts @@ -34,7 +34,8 @@ export class LintRequest { this.excludes = calcExcludeGlobInfo(this.root, options.exclude); this.locale = options.locale || ''; this.enableGlobDot = options.dot; - this.uniqueFilter = options.unique ? util.uniqueFilterFnGenerator((issue: Issue) => issue.text) : () => true; + // this.uniqueFilter = options.unique ? util.uniqueFilterFnGenerator((issue: Issue) => issue.text) : () => true; + this.uniqueFilter = () => true; this.showContext = options.showContext === true ? defaultContextRange : options.showContext ? options.showContext : 0; this.fileLists = (options.fileList ?? options.fileLists) || []; diff --git a/packages/cspell/src/app/options.ts b/packages/cspell/src/app/options.ts index 6e311a04177..65e4a6131f4 100644 --- a/packages/cspell/src/app/options.ts +++ b/packages/cspell/src/app/options.ts @@ -203,6 +203,11 @@ export interface LinterCliOptions extends LinterOptions { * Files must be found or cli will exit with an error. */ mustFindFiles?: boolean; + + /** + * Generate a summary report of issues. + */ + issuesSummaryReport?: boolean; } export function fixLegacy(opts: T & LegacyOptions): Omit { From c6c2fd13717308ee625ca754f336557eb1dcbd48 Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Sun, 26 Nov 2023 13:04:52 -0700 Subject: [PATCH 9/9] Update LintRequest.ts --- packages/cspell/src/app/lint/LintRequest.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/cspell/src/app/lint/LintRequest.ts b/packages/cspell/src/app/lint/LintRequest.ts index 328e3093e09..b08699458d1 100644 --- a/packages/cspell/src/app/lint/LintRequest.ts +++ b/packages/cspell/src/app/lint/LintRequest.ts @@ -5,7 +5,6 @@ import type { LinterOptions } from '../options.js'; import type { GlobSrcInfo } from '../util/glob.js'; import { calcExcludeGlobInfo } from '../util/glob.js'; import type { FinalizedReporter } from '../util/reporters.js'; -import * as util from '../util/util.js'; const defaultContextRange = 20;