Skip to content

Commit

Permalink
feat: Support --file-list cli option
Browse files Browse the repository at this point in the history
Related to #1850
  • Loading branch information
Jason3S committed Dec 26, 2021
1 parent 52d3765 commit 99abcc2
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 39 deletions.
7 changes: 7 additions & 0 deletions cspell.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,12 @@
"cSpell.customDictionaries": {
"workspace": true
}
},
"extensions": {
"recommendations": [
"streetsidesoftware.code-spell-checker",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
}
12 changes: 7 additions & 5 deletions packages/cspell/src/__snapshots__/app.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Array [
" -h, --help display help for command",
"",
"Commands:",
" lint [options] [files...] Check spelling",
" lint [options] [globs...] Check spelling",
" trace [options] <words...> Trace words",
" Search for words in the configuration and dictionaries.",
" check [options] <files...> Spell check file(s) and display the result. The",
Expand Down Expand Up @@ -289,7 +289,7 @@ exports[`Validate cli app must find with error Expect Error: [Function CheckFail
exports[`Validate cli app no-args Expect Error: outputHelp 1`] = `
Array [
"Usage: cspell lint [options] [files...]",
"Usage: cspell lint [options] [globs...]",
"",
"Check spelling",
"",
Expand All @@ -306,11 +306,12 @@ Array [
" dictionaries.",
" -u, --unique Only output the first instance of a word not",
" found in the dictionaries.",
" --debug Output information useful for debugging",
" cspell.json files.",
" -e, --exclude <glob> Exclude files matching the glob pattern. This",
" option can be used multiple times to add",
" multiple globs.",
" --file-list <path or stdin> Specify a list of files to be spell checked. The",
" list is filtered against the glob file patterns.",
" Note: the format is 1 file path per line.",
" --no-issues Do not show the spelling errors.",
" --no-progress Turn off progress messages",
" --no-summary Turn off summary message in console",
Expand All @@ -320,7 +321,6 @@ Array [
" --show-context Show the surrounding text around an issue.",
" --show-suggestions Show spelling suggestions.",
" --no-must-find-files Do not error if no files are found",
" --legacy Legacy output",
" --cache Only check changed files (default: false)",
" --cache-strategy <strategy> Strategy to use for detecting changed files",
" (choices: \\"metadata\\", \\"content\\")",
Expand All @@ -335,6 +335,8 @@ Array [
" root.",
" --no-color Turn off color.",
" --color Force color",
" --debug Output information useful for debugging",
" cspell.json files.",
" -h, --help display help for command",
"",
"",
Expand Down
2 changes: 1 addition & 1 deletion packages/cspell/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ApplicationError } from './util/errors';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const npmPackage = require(path.join(__dirname, '..', 'package.json'));

export { LinterCliOptions as Options } from './commandLint';
export { LinterCliOptions as Options } from './options';
export { CheckFailed } from './util/errors';

export async function run(program?: commander.Command, argv?: string[]): Promise<void> {
Expand Down
4 changes: 2 additions & 2 deletions packages/cspell/src/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export type { TraceResult } from 'cspell-lib';

export type AppError = NodeJS.ErrnoException;

export function lint(files: string[], options: LinterOptions, emitters: CSpellReporter): Promise<RunResult> {
const cfg = new LintRequest(files, options, emitters);
export function lint(fileGlobs: string[], options: LinterOptions, emitters: CSpellReporter): Promise<RunResult> {
const cfg = new LintRequest(fileGlobs, options, emitters);
return runLint(cfg);
}

Expand Down
27 changes: 23 additions & 4 deletions packages/cspell/src/cli-reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import chalk = require('chalk');
import type { CSpellReporter, Issue, MessageType, ProgressItem, RunResult } from '@cspell/cspell-types';
import { ImportError, isSpellingDictionaryLoadError, SpellingDictionaryLoadError } from 'cspell-lib';
import * as path from 'path';
import { Options } from './app';
import { URI } from 'vscode-uri';
import { LinterCliOptions } from './options';

const templateIssue = `{green $filename}:{yellow $row:$col} - $message ({red $text})`;
const templateIssueWithSuggestions = `{green $filename}:{yellow $row:$col} - $message ({red $text}) Suggestions: {yellow [$suggestions]}`;
Expand Down Expand Up @@ -79,7 +79,26 @@ function reportTime(elapsedTimeMs: number | undefined, cached: boolean): string
return color(elapsedTimeMs.toFixed(2) + 'ms');
}

export function getReporter(options: Options): CSpellReporter {
export interface ReporterOptions
extends Pick<
LinterCliOptions,
| 'debug'
| 'issues'
| 'legacy'
| 'progress'
| 'relative'
| 'root'
| 'showContext'
| 'showSuggestions'
| 'silent'
| 'summary'
| 'verbose'
| 'wordsOnly'
> {
fileGlobs: string[];
}

export function getReporter(options: ReporterOptions): CSpellReporter {
const issueTemplate = options.wordsOnly
? templateIssueWordsOnly
: options.legacy
Expand All @@ -91,7 +110,7 @@ export function getReporter(options: Options): CSpellReporter {
: options.showSuggestions
? templateIssueWithSuggestions
: templateIssue;
const { files, silent, summary, issues, progress, verbose, debug } = options;
const { fileGlobs, silent, summary, issues, progress, verbose, debug } = options;

const emitters: InfoEmitter = {
Debug: !silent && debug ? (s) => console.info(chalk.cyan(s)) : nullEmitter,
Expand All @@ -117,7 +136,7 @@ export function getReporter(options: Options): CSpellReporter {
}

const resultEmitter = (result: RunResult) => {
if (!files.length && !result.files) {
if (!fileGlobs.length && !result.files) {
return;
}
console.error(
Expand Down
40 changes: 17 additions & 23 deletions packages/cspell/src/commandLint.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
import { Command, Option as CommanderOption } from 'commander';
import * as App from './application';
import { getReporter } from './cli-reporter';
import { LinterOptions } from './options';
import { LinterCliOptions, LinterOptions } from './options';
import { DEFAULT_CACHE_LOCATION } from './util/cache';
import { CheckFailed } from './util/errors';

export interface LinterCliOptions extends LinterOptions {
files: string[];
legacy?: boolean;
summary: boolean;
issues: boolean;
silent: boolean;
mustFindFiles: boolean;
progress?: boolean;
/**
* issues are shown with a relative path to the root or `cwd`
*/
relative?: boolean;
}
// interface InitOptions extends Options {}

const usage = `
Expand Down Expand Up @@ -63,12 +50,18 @@ export function commandLint(prog: Command): Command {
new CommanderOption('--wordsOnly', 'Only output the words not found in the dictionaries.').hideHelp()
)
.option('-u, --unique', 'Only output the first instance of a word not found in the dictionaries.')
.option('--debug', 'Output information useful for debugging cspell.json files.')
.option(
'-e, --exclude <glob>',
'Exclude files matching the glob pattern. This option can be used multiple times to add multiple globs. ',
collect
)
.option(
'--file-list <path or stdin>',
'Specify a list of files to be spell checked.' +
' The list is filtered against the glob file patterns.' +
' Note: the format is 1 file path per line.',
collect
)
.option('--no-issues', 'Do not show the spelling errors.')
.option('--no-progress', 'Turn off progress messages')
.option('--no-summary', 'Turn off summary message in console')
Expand All @@ -82,7 +75,7 @@ export function commandLint(prog: Command): Command {
// The following options are planned features
// .option('-w, --watch', 'Watch for any changes to the matching files and report any errors')
// .option('--force', 'Force the exit value to always be 0')
.option('--legacy', 'Legacy output')
.addOption(new CommanderOption('--legacy', 'Legacy output').hideHelp())
.addOption(new CommanderOption('--local <local>', 'Deprecated -- Use: --locale').hideHelp())
.option('--cache', 'Only check changed files', false)
.addOption(
Expand All @@ -98,14 +91,15 @@ export function commandLint(prog: Command): Command {
.option('--gitignore-root <path>', 'Prevent searching for .gitignore files past root.', collect)
.option('--no-color', 'Turn off color.')
.option('--color', 'Force color')
.option('--debug', 'Output information useful for debugging cspell.json files.')
.addHelpText('after', usage)
.arguments('[files...]')
.action((files: string[], options: LinterCliOptions) => {
options.files = files;
const { mustFindFiles } = options;
const cliReporter = getReporter(options);
return App.lint(files, options, cliReporter).then((result) => {
if (!files.length && !result.files) {
.arguments('[globs...]')
.action((fileGlobs: string[], options: LinterCliOptions) => {
const { mustFindFiles, fileList } = options;
const cliReporter = getReporter({ ...options, fileGlobs });
const lintOptions: LinterOptions = { ...options, fileLists: fileList };
return App.lint(fileGlobs, lintOptions, cliReporter).then((result) => {
if (!fileGlobs.length && !result.files) {
spellCheckCommand.outputHelp();
throw new CheckFailed('outputHelp', 1);
}
Expand Down
4 changes: 3 additions & 1 deletion packages/cspell/src/lint/LintRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ export class LintRequest {
readonly root: string;
readonly showContext: number;
readonly enableGlobDot: boolean | undefined;
readonly fileLists: string[];

constructor(readonly files: string[], readonly options: LinterOptions, readonly reporter: CSpellReporter) {
constructor(readonly fileGlobs: string[], readonly options: LinterOptions, readonly reporter: CSpellReporter) {
this.root = path.resolve(options.root || process.cwd());
this.configFile = options.config;
this.excludes = calcExcludeGlobInfo(this.root, options.exclude);
Expand All @@ -25,5 +26,6 @@ export class LintRequest {
this.uniqueFilter = options.unique ? util.uniqueFilterFnGenerator((issue: Issue) => issue.text) : () => true;
this.showContext =
options.showContext === true ? defaultContextRange : options.showContext ? options.showContext : 0;
this.fileLists = options.fileLists || [];
}
}
5 changes: 3 additions & 2 deletions packages/cspell/src/lint/lint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { LintRequest } from './LintRequest';

export async function runLint(cfg: LintRequest): Promise<RunResult> {
let { reporter } = cfg;
const { fileLists } = cfg;
cspell.setLogger(getLoggerFromReporter(reporter));
const configErrors = new Set<string>();

Expand Down Expand Up @@ -189,15 +190,15 @@ export async function runLint(cfg: LintRequest): Promise<RunResult> {
const gitignoreRoots = cfg.options.gitignoreRoot ?? configInfo.config.gitignoreRoot;
const gitIgnore = useGitignore ? await generateGitIgnore(gitignoreRoots) : undefined;

const cliGlobs: Glob[] = cfg.files;
const cliGlobs: Glob[] = cfg.fileGlobs;
const allGlobs: Glob[] = cliGlobs.length ? cliGlobs : configInfo.config.files || [];
const combinedGlobs = normalizeGlobsToRoot(allGlobs, cfg.root, false);
const cliExcludeGlobs = extractPatterns(cfg.excludes).map((p) => p.glob);
const normalizedExcludes = normalizeGlobsToRoot(cliExcludeGlobs, cfg.root, true);
const includeGlobs = combinedGlobs.filter((g) => !g.startsWith('!'));
const excludeGlobs = combinedGlobs.filter((g) => g.startsWith('!')).concat(normalizedExcludes);
const fileGlobs: string[] = includeGlobs;
if (!fileGlobs.length) {
if (!fileGlobs.length && !fileLists.length) {
// Nothing to do.
return runResult();
}
Expand Down
23 changes: 23 additions & 0 deletions packages/cspell/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ export interface LinterOptions extends BaseOptions, CacheOptions {
* Stop searching for a `.gitignore`s when a root is reached.
*/
gitignoreRoot?: string | string[];
/**
* List of files that contains the paths to files to be spell checked.
* The files in the lists will be filtered against the glob patterns.
* - an entry of `stdin` means to read the file list from **`stdin`**
*/
fileLists?: string[] | undefined;
}

export interface TraceOptions extends BaseOptions {
Expand All @@ -64,3 +70,20 @@ export interface BaseOptions {
locale?: string;
local?: string; // deprecated
}

export interface LinterCliOptions extends Omit<LinterOptions, 'fileLists'> {
legacy?: boolean;
summary: boolean;
issues: boolean;
silent: boolean;
mustFindFiles: boolean;
progress?: boolean;
/**
* issues are shown with a relative path to the root or `cwd`
*/
relative?: boolean;
/**
* List of file paths to files that contains a list of files to be spell checked.
*/
fileList?: string[];
}
2 changes: 1 addition & 1 deletion packages/cspell/src/util/glob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export function extractGlobExcludesFromConfig(root: string, source: string, conf

/**
* Build GlobMatcher from command line or config file globs.
* @param globs Glob patterns.
* @param globs Glob patterns or file paths
* @param root - directory to use as the root
*/
export function buildGlobMatcher(globs: Glob[], root: string, isExclude: boolean): GlobMatcher {
Expand Down

0 comments on commit 99abcc2

Please sign in to comment.