Skip to content

Commit bb1ac5c

Browse files
authored
feat(fmt): add --no-error-on-unmatched-pattern (#178)
1 parent 4626c4f commit bb1ac5c

6 files changed

Lines changed: 91 additions & 25 deletions

File tree

packages/rstack/src/fmt/cli.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface ParsedFmtCLIArgs {
1212
mode: FmtMode;
1313
patterns: string[];
1414
ignorePaths: string[];
15+
noErrorOnUnmatchedPattern: boolean;
1516
maxWorkers?: number;
1617
help: boolean;
1718
/** Path the stdin content is formatted as; it need not exist on disk. */
@@ -26,13 +27,14 @@ ${color.yellow(' $ rs fmt [options] [files/globs...]')}
2627
Format files with Prettier.
2728
2829
${color.cyan('Options')}:
29-
--write Write formatted files in place (default)
30-
--check Check whether files are formatted
31-
--list-different Print paths of unformatted files
32-
--ignore-path <path> Path to an additional ignore file (repeatable)
33-
--parallel-workers <count> Number of parallel workers
34-
--stdin-filepath <path> Format stdin as if it were saved at <path>
35-
-h, --help Display this help message`;
30+
--write Write formatted files in place (default)
31+
--check Check whether files are formatted
32+
--list-different Print paths of unformatted files
33+
--ignore-path <path> Path to an additional ignore file (repeatable)
34+
--no-error-on-unmatched-pattern Do not error when no files match
35+
--parallel-workers <count> Number of parallel workers
36+
--stdin-filepath <path> Format stdin as if it were saved at <path>
37+
-h, --help Display this help message`;
3638

3739
const parseMaxWorkers = (
3840
kebabValue: string | undefined,
@@ -60,6 +62,8 @@ const parseFmtCLIArgs = (args: string[]): ParsedFmtCLIArgs => {
6062
'list-different': { type: 'boolean' },
6163
listDifferent: { type: 'boolean' },
6264
'ignore-path': { type: 'string', multiple: true },
65+
'no-error-on-unmatched-pattern': { type: 'boolean' },
66+
noErrorOnUnmatchedPattern: { type: 'boolean' },
6367
'parallel-workers': { type: 'string' },
6468
parallelWorkers: { type: 'string' },
6569
'stdin-filepath': { type: 'string' },
@@ -77,6 +81,8 @@ const parseFmtCLIArgs = (args: string[]): ParsedFmtCLIArgs => {
7781
}
7882

7983
const mode = values.check ? 'check' : listDifferent ? 'list-different' : 'write';
84+
const noErrorOnUnmatchedPattern =
85+
values['no-error-on-unmatched-pattern'] ?? values.noErrorOnUnmatchedPattern ?? false;
8086
const maxWorkers = parseMaxWorkers(values['parallel-workers'], values.parallelWorkers);
8187
const stdinFilepath = values['stdin-filepath'] ?? values.stdinFilepath;
8288

@@ -96,6 +102,7 @@ const parseFmtCLIArgs = (args: string[]): ParsedFmtCLIArgs => {
96102
mode,
97103
patterns: positionals,
98104
ignorePaths: values['ignore-path'] ?? [],
105+
noErrorOnUnmatchedPattern,
99106
maxWorkers,
100107
help: values.help ?? false,
101108
stdinFilepath,
@@ -214,7 +221,15 @@ const runFmtCLI = async (args: string[]): Promise<void> => {
214221
// Argument errors are reported like every other failure so that a single
215222
// exit code identifies "rs fmt refused to run".
216223
try {
217-
const { help, ignorePaths, maxWorkers, mode, patterns, stdinFilepath } = parseFmtCLIArgs(args);
224+
const {
225+
help,
226+
ignorePaths,
227+
maxWorkers,
228+
mode,
229+
noErrorOnUnmatchedPattern,
230+
patterns,
231+
stdinFilepath,
232+
} = parseFmtCLIArgs(args);
218233
if (help) {
219234
logger.log(fmtHelpMessage);
220235
return;
@@ -243,6 +258,9 @@ const runFmtCLI = async (args: string[]): Promise<void> => {
243258
});
244259

245260
if (files.length === 0) {
261+
if (noErrorOnUnmatchedPattern) {
262+
return;
263+
}
246264
const targets = (patterns.length ? patterns : ['.'])
247265
.map((pattern) => color.cyan(JSON.stringify(pattern)))
248266
.join(', ');

packages/rstack/tests/cli/fmt/index.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,3 +597,16 @@ test('returns exit code 2 when no files match', () => {
597597
expect(result.stderr).not.toContain('\n at ');
598598
}
599599
});
600+
601+
test.each(['--no-error-on-unmatched-pattern', '--noErrorOnUnmatchedPattern'])(
602+
'allows no files to match with %s',
603+
(option) => {
604+
for (const modeArgs of [[], ['--check'], ['--list-different']]) {
605+
const result = runFmt([...modeArgs, option, 'missing/**/*.ts']);
606+
607+
expect(result.status).toBe(0);
608+
expect(result.stdout).toBe('');
609+
expect(result.stderr).toBe('');
610+
}
611+
},
612+
);

packages/rstack/tests/fmt/__snapshots__/cli.test.ts.snap

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ exports[`provides command help 1`] = `
77
Format files with Prettier.
88
99
Options:
10-
--write Write formatted files in place (default)
11-
--check Check whether files are formatted
12-
--list-different Print paths of unformatted files
13-
--ignore-path <path> Path to an additional ignore file (repeatable)
14-
--parallel-workers <count> Number of parallel workers
15-
--stdin-filepath <path> Format stdin as if it were saved at <path>
16-
-h, --help Display this help message"
10+
--write Write formatted files in place (default)
11+
--check Check whether files are formatted
12+
--list-different Print paths of unformatted files
13+
--ignore-path <path> Path to an additional ignore file (repeatable)
14+
--no-error-on-unmatched-pattern Do not error when no files match
15+
--parallel-workers <count> Number of parallel workers
16+
--stdin-filepath <path> Format stdin as if it were saved at <path>
17+
-h, --help Display this help message"
1718
`;

packages/rstack/tests/fmt/cli.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ test('uses write mode by default', () => {
2222
mode: 'write',
2323
patterns: [],
2424
ignorePaths: [],
25+
noErrorOnUnmatchedPattern: false,
2526
maxWorkers: undefined,
2627
help: false,
2728
});
@@ -37,6 +38,7 @@ test.each([
3738
mode,
3839
patterns: [],
3940
ignorePaths: [],
41+
noErrorOnUnmatchedPattern: false,
4042
maxWorkers: undefined,
4143
help: false,
4244
});
@@ -49,6 +51,7 @@ test.each(['--parallel-workers', '--parallelWorkers'])(
4951
mode: 'write',
5052
patterns: [],
5153
ignorePaths: [],
54+
noErrorOnUnmatchedPattern: false,
5255
maxWorkers: 3,
5356
help: false,
5457
});
@@ -75,6 +78,7 @@ test('preserves file paths and globs', () => {
7578
mode: 'check',
7679
patterns,
7780
ignorePaths: [],
81+
noErrorOnUnmatchedPattern: false,
7882
maxWorkers: undefined,
7983
help: false,
8084
});
@@ -85,6 +89,7 @@ test('treats arguments after the terminator as paths', () => {
8589
mode: 'check',
8690
patterns: ['--write', '--help'],
8791
ignorePaths: [],
92+
noErrorOnUnmatchedPattern: false,
8893
maxWorkers: undefined,
8994
help: false,
9095
});
@@ -101,11 +106,19 @@ test('collects repeated ignore paths', () => {
101106
).toEqual(['.prettierignore', 'config/format.ignore']);
102107
});
103108

109+
test.each(['--no-error-on-unmatched-pattern', '--noErrorOnUnmatchedPattern'])(
110+
'parses %s',
111+
(option) => {
112+
expect(parseFmtCLIArgs([option]).noErrorOnUnmatchedPattern).toBe(true);
113+
},
114+
);
115+
104116
test.each(['--stdin-filepath', '--stdinFilepath'])('parses %s', (option) => {
105117
expect(parseFmtCLIArgs([option, 'src/index.ts'])).toEqual({
106118
mode: 'write',
107119
patterns: [],
108120
ignorePaths: [],
121+
noErrorOnUnmatchedPattern: false,
109122
maxWorkers: undefined,
110123
help: false,
111124
stdinFilepath: 'src/index.ts',
@@ -117,6 +130,7 @@ test('accepts a worker count with --stdin-filepath', () => {
117130
mode: 'write',
118131
patterns: [],
119132
ignorePaths: [],
133+
noErrorOnUnmatchedPattern: false,
120134
maxWorkers: 2,
121135
help: false,
122136
stdinFilepath: 'index.ts',

website/docs/en/guide/cli/fmt.mdx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ rs fmt . --check
4343

4444
The command uses the following exit codes:
4545

46-
| Code | Meaning |
47-
| ---- | --------------------------------------------------------- |
48-
| `0` | All matched files are formatted. |
49-
| `1` | One or more matched files have formatting issues. |
50-
| `2` | `rs fmt` could not run or encountered a formatting error. |
46+
| Code | Meaning |
47+
| ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
48+
| `0` | All matched files are formatted; or no supported files matched, but [`--no-error-on-unmatched-pattern`](#--no-error-on-unmatched-pattern) was specified. |
49+
| `1` | One or more matched files have formatting issues. |
50+
| `2` | `rs fmt` could not run or encountered a formatting error. |
5151

5252
### `-h, --help`
5353

@@ -97,6 +97,16 @@ rs fmt . --list-different
9797

9898
The option uses the same exit codes as `--check` and cannot be combined with `--write` or `--check`.
9999

100+
### `--no-error-on-unmatched-pattern`
101+
102+
Exit successfully without diagnostics when no supported files match the provided paths or globs, including when all matching files are ignored:
103+
104+
```bash
105+
rs fmt --no-error-on-unmatched-pattern 'src/**/*.ts'
106+
```
107+
108+
For example, a pre-commit script may always run `rs fmt`, even when the staged changes contain no supported files. This option lets the command exit successfully in that case instead of blocking the commit.
109+
100110
### `--parallel-workers <count>`
101111

102112
Set the maximum number of formatting workers to a positive integer:

website/docs/zh/guide/cli/fmt.mdx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ rs fmt . --check
4343

4444
该命令使用以下退出状态码:
4545

46-
| 状态码 | 含义 |
47-
| ------ | ------------------------------------------- |
48-
| `0` | 所有匹配的文件均已格式化 |
49-
| `1` | 一个或多个匹配的文件存在格式问题。 |
50-
| `2` | `rs fmt` 无法运行或在格式化过程中遇到错误。 |
46+
| 状态码 | 含义 |
47+
| ------ | -------------------------------------------------------------------------------------------------------------------------------- |
48+
| `0` | 所有匹配的文件均已格式化;或未匹配到支持的文件,但指定了 [`--no-error-on-unmatched-pattern`](#--no-error-on-unmatched-pattern) |
49+
| `1` | 一个或多个匹配的文件存在格式问题。 |
50+
| `2` | `rs fmt` 无法运行或在格式化过程中遇到错误。 |
5151

5252
### `-h, --help`
5353

@@ -97,6 +97,16 @@ rs fmt . --list-different
9797

9898
此选项与 `--check` 使用相同的退出状态码,且不能与 `--write``--check` 同时使用。
9999

100+
### `--no-error-on-unmatched-pattern`
101+
102+
如果传入的路径或 glob 没有匹配任何支持的文件(包括所有匹配文件均被忽略的情况),则不输出诊断信息并成功退出:
103+
104+
```bash
105+
rs fmt --no-error-on-unmatched-pattern 'src/**/*.ts'
106+
```
107+
108+
例如,pre-commit 脚本可能会始终运行 `rs fmt`,即使暂存的改动中没有支持的文件。此选项可让命令在这种情况下成功退出,避免阻止提交。
109+
100110
### `--parallel-workers <count>`
101111

102112
将格式化 worker 的最大数量设置为正整数:

0 commit comments

Comments
 (0)