Skip to content

Commit e39ffa6

Browse files
committed
perf(fmt): reuse config options resolver
1 parent 09e5b62 commit e39ffa6

4 files changed

Lines changed: 52 additions & 26 deletions

File tree

packages/rstack/src/fmt/config.ts

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { dirname, relative } from 'node:path';
1+
import { dirname } from 'node:path';
22
import micromatch from 'micromatch';
3+
import { createRelativePathResolver } from './relativePath.ts';
34
import type {
45
FmtConfig,
56
FmtConfigDefinition,
@@ -14,6 +15,7 @@ type ResolveFmtConfigOptions = {
1415
};
1516

1617
type PathMatcher = (filePath: string) => boolean;
18+
type FmtOptionsResolver = (filePath: string) => ResolvedFmtOptions;
1719

1820
const neverMatches: PathMatcher = () => false;
1921

@@ -87,26 +89,30 @@ const normalizeFmtConfig = (config: FmtConfig | undefined, rootPath: string): Re
8789
};
8890
};
8991

90-
/** Applies matching overrides to the shared formatter options. */
91-
const resolveFmtOptions = (filePath: string, config: ResolvedFmtConfig): ResolvedFmtOptions => {
92+
/** Creates a reusable resolver for applying per-file formatter overrides. */
93+
const createFmtOptionsResolver = (config: ResolvedFmtConfig): FmtOptionsResolver => {
9294
if (config.overrides.length === 0) {
93-
return config.baseOptions;
95+
return () => config.baseOptions;
9496
}
9597

96-
let options = config.baseOptions;
97-
const relativeFilePath = relative(config.rootPath, filePath);
98+
const resolveRelativePath = createRelativePathResolver(config.rootPath);
9899

99-
for (const override of config.overrides) {
100-
if (!override.options || !override.matches(relativeFilePath)) {
101-
continue;
102-
}
103-
if (options === config.baseOptions) {
104-
options = { ...options };
100+
return (filePath) => {
101+
let options = config.baseOptions;
102+
const relativeFilePath = resolveRelativePath(filePath);
103+
104+
for (const override of config.overrides) {
105+
if (!override.options || !override.matches(relativeFilePath)) {
106+
continue;
107+
}
108+
if (options === config.baseOptions) {
109+
options = { ...options };
110+
}
111+
Object.assign(options, override.options);
105112
}
106-
Object.assign(options, override.options);
107-
}
108113

109-
return options;
114+
return options;
115+
};
110116
};
111117

112118
/** Resolves a formatter config definition and its project root. */
@@ -121,4 +127,5 @@ const resolveFmtConfig = async ({
121127
return normalizeFmtConfig(config, rootPath);
122128
};
123129

124-
export { normalizeFmtConfig, resolveFmtConfig, resolveFmtOptions };
130+
export { createFmtOptionsResolver, normalizeFmtConfig, resolveFmtConfig };
131+
export type { FmtOptionsResolver };

packages/rstack/src/fmt/discovery.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import { resolveFmtOptions } from './config.ts';
1+
import { createFmtOptionsResolver, type FmtOptionsResolver } from './config.ts';
22
import { discoverFmtPaths } from './discoverPaths.ts';
33
import { createIgnoreMatcher } from './ignore.ts';
4-
import type { DiscoverFmtFilesOptions, FmtFileRequest, ResolvedFmtConfig } from './types.ts';
4+
import type { DiscoverFmtFilesOptions, FmtFileRequest } from './types.ts';
55

6-
const createFileRequest = (filePath: string, config: ResolvedFmtConfig): FmtFileRequest => ({
6+
const createFileRequest = (
7+
filePath: string,
8+
resolveOptions: FmtOptionsResolver,
9+
): FmtFileRequest => ({
710
path: filePath,
8-
options: resolveFmtOptions(filePath, config),
11+
options: resolveOptions(filePath),
912
});
1013

1114
/** Discovers worker-ready files without automatically reading Prettier config or ignore files. */
@@ -28,7 +31,8 @@ const discoverFmtFiles = async ({
2831
}
2932

3033
const filePaths = candidates.filter((filePath) => !isIgnored(filePath));
31-
const files = filePaths.map((filePath) => createFileRequest(filePath, config));
34+
const resolveOptions = createFmtOptionsResolver(config);
35+
const files = filePaths.map((filePath) => createFileRequest(filePath, resolveOptions));
3236
if (!files.some((file) => file.options.plugins?.length)) {
3337
return files;
3438
}

packages/rstack/src/fmt/stdin.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { resolve } from 'node:path';
2+
import { createFmtOptionsResolver } from './config.ts';
23
import { createFileRequest } from './discovery.ts';
34
import { formatFmtSource } from './format.ts';
45
import { createIgnoreMatcher } from './ignore.ts';
@@ -78,7 +79,7 @@ const runFmtStdin = async ({
7879
return;
7980
}
8081

81-
let file = createFileRequest(absolutePath, config);
82+
let file = createFileRequest(absolutePath, createFmtOptionsResolver(config));
8283
if (file.options.plugins?.length) {
8384
const { createFmtPluginResolver } = await import(
8485
/* rspackChunkName: 'fmtPlugins' */

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import path from 'node:path';
22
import { expect, test } from 'rstack/test';
3-
import { normalizeFmtConfig, resolveFmtOptions } from '../../src/fmt/config.ts';
3+
import { createFmtOptionsResolver, normalizeFmtConfig } from '../../src/fmt/config.ts';
44

55
const rootPath = path.join(import.meta.dirname, 'project');
66

@@ -12,8 +12,9 @@ test('reuses base options when no override matches', () => {
1212
},
1313
rootPath,
1414
);
15+
const resolveOptions = createFmtOptionsResolver(config);
1516

16-
expect(resolveFmtOptions(path.join(rootPath, 'index.js'), config)).toBe(config.baseOptions);
17+
expect(resolveOptions(path.join(rootPath, 'index.js'))).toBe(config.baseOptions);
1718
});
1819

1920
test('applies basename and path overrides in declaration order', () => {
@@ -38,12 +39,25 @@ test('applies basename and path overrides in declaration order', () => {
3839
},
3940
rootPath,
4041
);
42+
const resolveOptions = createFmtOptionsResolver(config);
4143

42-
const options = resolveFmtOptions(path.join(rootPath, 'src/index.ts'), config);
43-
const testOptions = resolveFmtOptions(path.join(rootPath, 'src/index.test.ts'), config);
44+
const options = resolveOptions(path.join(rootPath, 'src/index.ts'));
45+
const testOptions = resolveOptions(path.join(rootPath, 'src/index.test.ts'));
4446

4547
expect(options).not.toBe(config.baseOptions);
4648
expect(options).toEqual({ semi: true, singleQuote: true, tabWidth: 4 });
4749
expect(testOptions).toEqual({ singleQuote: true });
4850
expect(config.baseOptions).toEqual({ singleQuote: false });
4951
});
52+
53+
test('applies overrides outside the config root', () => {
54+
const config = normalizeFmtConfig(
55+
{
56+
overrides: [{ files: '../shared/*.ts', options: { semi: false } }],
57+
},
58+
rootPath,
59+
);
60+
const resolveOptions = createFmtOptionsResolver(config);
61+
62+
expect(resolveOptions(path.join(rootPath, '../shared/index.ts'))).toEqual({ semi: false });
63+
});

0 commit comments

Comments
 (0)