Skip to content

Commit 652cbbb

Browse files
authored
feat: add excludeErrorMessage option to filter errors by message (#45)
1 parent 277e174 commit 652cbbb

File tree

7 files changed

+83
-26
lines changed

7 files changed

+83
-26
lines changed

README.md

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ At this time, the build artifacts can include all syntax supported by ES2020, su
169169
- **Type:** `RegExp | RegExp[]`
170170
- **Default:** `undefined`
171171
172-
`exclude` is used to exclude a portion of source files during detection. You can pass in one or more regular expressions to match the paths of source files. Files that match the regular expression will be ignored and will not trigger syntax checking.
172+
Excludes a portion of source files during detection. You can pass in one or more regular expressions to match the paths of source files. Files that match the regular expression will be ignored and will not trigger syntax checking.
173173
174174
- **Example:**
175175
@@ -186,7 +186,7 @@ pluginCheckSyntax({
186186
- **Type:** `RegExp | RegExp[]`
187187
- **Default:** `undefined`
188188
189-
`excludeOutput` is used to exclude a portion of output files before detection. You can pass in one or more regular expressions to match the paths of output files. Files that match the regular expression will be ignored and will not trigger syntax checking.
189+
Excludes a portion of output files before detection. You can pass in one or more regular expressions to match the paths of output files. Files that match the regular expression will be ignored and will not trigger syntax checking.
190190
191191
- **Example:**
192192
@@ -198,12 +198,37 @@ pluginCheckSyntax({
198198
});
199199
```
200200
201+
### excludeErrorMessage
202+
203+
- **Type:** `RegExp | RegExp[]`
204+
- **Default:** `undefined`
205+
206+
Excludes files by error message (reason) before detection. You can pass in one or more regular expressions to match the error messages. Files that match the regular expression will be ignored and will not trigger syntax checking.
207+
208+
- **Example:**
209+
210+
For example, to ignore the error messages when using dynamic import:
211+
212+
```ts
213+
pluginCheckSyntax({
214+
excludeErrorMessage: /'import' and 'export' may only appear at the top level/,
215+
});
216+
```
217+
218+
Or ignore the error messages when using `let` or `const` keywords:
219+
220+
```ts
221+
pluginCheckSyntax({
222+
excludeErrorMessage: /The keyword '(let|const)' is reserved/,
223+
});
224+
```
225+
201226
### excludeErrorLogs
202227
203228
- **Type:** `('source' | 'output' | 'reason' | 'code')[]`
204229
- **Default:** `[]`
205230
206-
`excludeErrorLogs` is used to ignore specified syntax error messages after detection. You can pass in one or more error message types to ignore.
231+
Ignores specified syntax error messages after detection. You can pass in one or more error message types to ignore.
207232
208233
- **Example:**
209234

src/CheckSyntaxPlugin.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { resolve } from 'node:path';
22
import type { Rspack } from '@rsbuild/core';
33
import { CheckSyntax } from './checkSyntax.js';
44
import { printErrors } from './printErrors.js';
5-
import { checkIsExclude } from './utils.js';
5+
import { isPathExcluded } from './utils.js';
66

77
type Compiler = Rspack.Compiler;
88
type Compilation = Rspack.Compilation;
@@ -29,10 +29,10 @@ export class CheckSyntaxRspackPlugin extends CheckSyntax {
2929
// remove query from name
3030
const resourcePath = a.name.split('?')[0];
3131
const file = resolve(outputPath, resourcePath);
32-
if (!checkIsExclude(file, this.excludeOutput)) {
33-
return file;
32+
if (isPathExcluded(file, this.excludeOutput)) {
33+
return '';
3434
}
35-
return '';
35+
return file;
3636
});
3737

3838
const files = emittedAssets.filter(

src/checkSyntax.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type {
1111
EcmaVersion,
1212
SyntaxErrorKey,
1313
} from './types.js';
14-
import { checkIsExclude } from './utils.js';
14+
import { isPathExcluded } from './utils.js';
1515

1616
const HTML_REGEX = /\.html$/;
1717
export const JS_REGEX: RegExp = /\.(?:js|mjs|cjs|jsx)$/;
@@ -32,9 +32,11 @@ export class CheckSyntax {
3232

3333
rootPath: string;
3434

35-
exclude: CheckSyntaxExclude | undefined;
35+
exclude?: CheckSyntaxExclude;
3636

37-
excludeOutput: CheckSyntaxExclude | undefined;
37+
excludeOutput?: CheckSyntaxExclude;
38+
39+
excludeErrorMessage?: CheckSyntaxExclude;
3840

3941
excludeErrorLogs: SyntaxErrorKey[];
4042

@@ -54,6 +56,7 @@ export class CheckSyntax {
5456
this.ecmaVersion = ecmaVersion || browserslistToESVersion(targets);
5557

5658
this.exclude = options.exclude;
59+
this.excludeErrorMessage = options.excludeErrorMessage;
5760
this.excludeOutput = options.excludeOutput;
5861
this.rootPath = options.rootPath || '';
5962
this.excludeErrorLogs = options.excludeErrorLogs || [];
@@ -69,7 +72,7 @@ export class CheckSyntax {
6972
const htmlScripts = await generateHtmlScripts(filepath);
7073
await Promise.all(
7174
htmlScripts.map(async (script) => {
72-
if (!checkIsExclude(filepath, this.exclude)) {
75+
if (!isPathExcluded(filepath, this.exclude)) {
7376
await this.tryParse(filepath, script);
7477
}
7578
}),
@@ -93,6 +96,7 @@ export class CheckSyntax {
9396
code,
9497
filepath,
9598
exclude: this.exclude,
99+
excludeErrorMessage: this.excludeErrorMessage,
96100
rootPath: this.rootPath,
97101
});
98102

src/generateError.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
type CheckSyntaxExclude,
77
ECMASyntaxError,
88
} from './types.js';
9-
import { checkIsExclude } from './utils.js';
9+
import { isExcluded, isPathExcluded } from './utils.js';
1010

1111
export function displayCodePointer(code: string, pos: number) {
1212
const SUB_LEN = 80;
@@ -23,12 +23,14 @@ export async function generateError({
2323
filepath,
2424
rootPath,
2525
exclude,
26+
excludeErrorMessage,
2627
}: {
2728
err: AcornParseError;
2829
code: string;
2930
filepath: string;
3031
rootPath: string;
3132
exclude?: CheckSyntaxExclude;
33+
excludeErrorMessage?: CheckSyntaxExclude;
3234
}): Promise<ECMASyntaxError | null> {
3335
const relativeOutputPath = filepath.replace(rootPath, '');
3436
let error = await tryGenerateErrorFromSourceMap({
@@ -49,7 +51,11 @@ export async function generateError({
4951
});
5052
}
5153

52-
if (checkIsExclude(error.source.path, exclude)) {
54+
if (isPathExcluded(error.source.path, exclude)) {
55+
return null;
56+
}
57+
58+
if (isExcluded(error.message, excludeErrorMessage)) {
5359
return null;
5460
}
5561

src/types.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,30 @@ export type CheckSyntaxOptions = {
1111
*/
1212
targets?: string[];
1313
/**
14-
* Used to exclude a portion of source files during detection.
14+
* Excludes a portion of source files during detection.
1515
* You can pass in one or more regular expressions to match the paths of source files.
1616
*/
1717
exclude?: CheckSyntaxExclude;
1818
/**
19-
* Used to exclude files by output path before detection.
19+
* Excludes files by output path before detection.
2020
* You can pass in one or more regular expressions to match the paths of source files.
2121
*/
2222
excludeOutput?: CheckSyntaxExclude;
2323
/**
24-
* The minimum ECMAScript syntax version that can be used in the build artifact.
25-
* The priority of `ecmaVersion` is higher than `targets`.
24+
* Excludes files by error message (reason) before detection.
25+
* You can pass in one or more regular expressions to match the reasons.
2626
*/
27-
ecmaVersion?: EcmaVersion;
27+
excludeErrorMessage?: CheckSyntaxExclude;
2828
/**
29-
* Used to ignore specified syntax error messages after detection.
29+
* Ignores specified syntax error messages after detection.
3030
* You can pass in one or more error message types to ignore.
3131
*/
3232
excludeErrorLogs?: SyntaxErrorKey[];
33+
/**
34+
* The minimum ECMAScript syntax version that can be used in the build artifact.
35+
* The priority of `ecmaVersion` is higher than `targets`.
36+
*/
37+
ecmaVersion?: EcmaVersion;
3338
};
3439

3540
export interface Location {

src/utils.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import type { CheckSyntaxExclude } from './types.js';
22

3-
export function checkIsExclude(
4-
path: string,
5-
exclude?: CheckSyntaxExclude,
6-
): boolean {
3+
export const isExcluded = (input: string, exclude?: CheckSyntaxExclude) => {
74
if (!exclude) {
85
return false;
96
}
10-
117
const excludes = Array.isArray(exclude) ? exclude : [exclude];
8+
return excludes.some((reg) => reg.test(input));
9+
};
1210

11+
export function isPathExcluded(
12+
path: string,
13+
exclude?: CheckSyntaxExclude,
14+
): boolean {
1315
// normalize to posix path
1416
const normalizedPath = path.replace(/\\/g, '/');
15-
16-
return excludes.some((reg) => reg.test(normalizedPath));
17+
return isExcluded(normalizedPath, exclude);
1718
}

test/rsbuild-basic/index.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,22 @@ test('should not throw error when the output file is excluded', async () => {
124124
await expect(rsbuild.build()).resolves.toBeTruthy();
125125
});
126126

127+
test('should not throw error when the error message is excluded', async () => {
128+
const rsbuild = await createRsbuild({
129+
cwd: __dirname,
130+
rsbuildConfig: {
131+
...(await loadConfig({ cwd: __dirname })).content,
132+
plugins: [
133+
pluginCheckSyntax({
134+
excludeErrorMessage: /The keyword '(let|const)' is reserved/,
135+
}),
136+
],
137+
},
138+
});
139+
140+
await expect(rsbuild.build()).resolves.toBeTruthy();
141+
});
142+
127143
test('should not throw error when the targets are support es6', async () => {
128144
const rsbuild = await createRsbuild({
129145
cwd: __dirname,

0 commit comments

Comments
 (0)