Skip to content

Commit 015bbd7

Browse files
committed
refactor(fmt): reuse relative path resolver
1 parent c62e4d9 commit 015bbd7

4 files changed

Lines changed: 49 additions & 29 deletions

File tree

packages/rstack/src/fmt/discoverPaths.ts

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import ignore from 'ignore';
44
import isBinaryPath from 'is-binary-path';
55
import micromatch from 'micromatch';
66
import readdir, { type Dirent, type DirentLike } from 'tiny-readdir';
7+
import { createRelativePathResolver, type RelativePathResolver } from './relativePath.ts';
78

89
const defaultIgnoredDirNames = new Set(['.git', '.sl', '.svn', '.hg', '.jj', 'node_modules']);
910

@@ -38,19 +39,6 @@ const isRelativePathInside = (relativePath: string): boolean =>
3839
const isPathInside = (rootPath: string, filePath: string): boolean =>
3940
isRelativePathInside(path.relative(rootPath, filePath));
4041

41-
type RelativePathResolver = (filePath: string) => string;
42-
43-
const createRelativePathResolver = (rootPath: string): RelativePathResolver => {
44-
const rootPrefix = rootPath.endsWith(path.sep) ? rootPath : `${rootPath}${path.sep}`;
45-
46-
return (filePath) =>
47-
filePath === rootPath
48-
? ''
49-
: filePath.startsWith(rootPrefix)
50-
? filePath.slice(rootPrefix.length)
51-
: path.relative(rootPath, filePath);
52-
};
53-
5442
const toPosixPath = (filePath: string): string =>
5543
path.sep === '\\' ? filePath.replaceAll('\\', '/') : filePath;
5644

@@ -86,14 +74,14 @@ const findGitRoot = async (cwd: string): Promise<string> => {
8674

8775
class GitIgnoreMatcher {
8876
readonly #rootPath: string;
89-
readonly #rootPrefix: string;
77+
readonly #resolveRelativePath: RelativePathResolver;
9078
readonly #matchers = new Map<string, ReturnType<typeof ignore>>();
9179
readonly #loads = new Map<string, Promise<void>>();
9280
readonly #ignoredDirectories = new Map<string, boolean>();
9381

9482
private constructor(rootPath: string) {
9583
this.#rootPath = rootPath;
96-
this.#rootPrefix = rootPath.endsWith(path.sep) ? rootPath : `${rootPath}${path.sep}`;
84+
this.#resolveRelativePath = createRelativePathResolver(rootPath);
9785
}
9886

9987
static async create(cwd: string): Promise<GitIgnoreMatcher> {
@@ -103,11 +91,11 @@ class GitIgnoreMatcher {
10391
}
10492

10593
async loadThrough(directoryPath: string): Promise<void> {
106-
if (!isPathInside(this.#rootPath, directoryPath)) {
94+
const relativePath = this.#resolveRelativePath(directoryPath);
95+
if (!isRelativePathInside(relativePath)) {
10796
return;
10897
}
10998

110-
const relativePath = path.relative(this.#rootPath, directoryPath);
11199
const segments = relativePath ? relativePath.split(path.sep) : [];
112100
const loads = [this.#load(this.#rootPath)];
113101
let currentPath = this.#rootPath;
@@ -121,7 +109,7 @@ class GitIgnoreMatcher {
121109
}
122110

123111
async load(directoryPath: string): Promise<void> {
124-
if (isPathInside(this.#rootPath, directoryPath)) {
112+
if (isRelativePathInside(this.#resolveRelativePath(directoryPath))) {
125113
await this.#load(directoryPath);
126114
}
127115
}
@@ -131,12 +119,7 @@ class GitIgnoreMatcher {
131119
return false;
132120
}
133121

134-
const relativePath =
135-
filePath === this.#rootPath
136-
? ''
137-
: filePath.startsWith(this.#rootPrefix)
138-
? filePath.slice(this.#rootPrefix.length)
139-
: path.relative(this.#rootPath, filePath);
122+
const relativePath = this.#resolveRelativePath(filePath);
140123
if (relativePath === '' || !isRelativePathInside(relativePath)) {
141124
return false;
142125
}
@@ -175,7 +158,7 @@ class GitIgnoreMatcher {
175158
return cached;
176159
}
177160

178-
relativePath ??= path.relative(this.#rootPath, directoryPath);
161+
relativePath ??= this.#resolveRelativePath(directoryPath);
179162

180163
// Git cannot re-include a path below an ignored directory.
181164
const parentPath = path.dirname(directoryPath);

packages/rstack/src/fmt/ignore.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { readFile } from 'node:fs/promises';
22
import path from 'node:path';
33
import createIgnore from 'ignore';
4+
import { createRelativePathResolver } from './relativePath.ts';
45
import type { ResolvedFmtConfig } from './types.ts';
56

67
/**
@@ -28,12 +29,10 @@ const createDefaultIgnoreMatcher = (): IgnoreMatcher => {
2829

2930
const createPatternMatcher = (rootPath: string, patterns: string): IgnoreMatcher => {
3031
const matcher = createIgnore({ allowRelativePaths: true }).add(patterns);
31-
const rootPrefix = rootPath.endsWith(path.sep) ? rootPath : `${rootPath}${path.sep}`;
32+
const resolveRelativePath = createRelativePathResolver(rootPath);
3233

3334
return (filePath, isDirectory = false) => {
34-
const relativePath = filePath.startsWith(rootPrefix)
35-
? filePath.slice(rootPrefix.length)
36-
: path.relative(rootPath, filePath);
35+
const relativePath = resolveRelativePath(filePath);
3736
if (relativePath === '') {
3837
return false;
3938
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import path from 'node:path';
2+
3+
type RelativePathResolver = (filePath: string) => string;
4+
5+
const createRelativePathResolver = (rootPath: string): RelativePathResolver => {
6+
const rootPrefix = rootPath.endsWith(path.sep) ? rootPath : `${rootPath}${path.sep}`;
7+
8+
return (filePath) =>
9+
filePath === rootPath
10+
? ''
11+
: filePath.startsWith(rootPrefix)
12+
? filePath.slice(rootPrefix.length)
13+
: path.relative(rootPath, filePath);
14+
};
15+
16+
export { createRelativePathResolver };
17+
export type { RelativePathResolver };
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import path from 'node:path';
2+
import { expect, test } from 'rstack/test';
3+
import { createRelativePathResolver } from '../../src/fmt/relativePath.ts';
4+
5+
const rootPath = path.join(import.meta.dirname, 'project');
6+
7+
test('resolves paths relative to a fixed root', () => {
8+
const resolveRelativePath = createRelativePathResolver(rootPath);
9+
10+
expect(resolveRelativePath(rootPath)).toBe('');
11+
expect(resolveRelativePath(path.join(rootPath, 'src/index.ts'))).toBe(
12+
path.join('src', 'index.ts'),
13+
);
14+
});
15+
16+
test('falls back for paths outside the fixed root', () => {
17+
const resolveRelativePath = createRelativePathResolver(rootPath);
18+
const siblingPath = path.join(`${rootPath}-other`, 'index.ts');
19+
20+
expect(resolveRelativePath(siblingPath)).toBe(path.relative(rootPath, siblingPath));
21+
});

0 commit comments

Comments
 (0)