Skip to content

Commit ea909e8

Browse files
committed
fix: 🐛 correctly handle directory paths
1 parent 403c271 commit ea909e8

File tree

4 files changed

+26
-18
lines changed

4 files changed

+26
-18
lines changed

src/node-to-fsa/NodeFileSystemDirectoryHandle.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,17 @@ import type {
2424
*/
2525
export class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle implements IFileSystemDirectoryHandle {
2626
protected readonly ctx: Partial<NodeFsaContext>;
27+
/** Directory path with trailing slash. */
28+
public readonly __path: string;
29+
2730
public constructor(
2831
protected readonly fs: NodeFsaFs,
29-
public readonly __path: string,
32+
path: string,
3033
ctx: Partial<NodeFsaContext> = {},
3134
) {
32-
super('directory', basename(__path, ctx.separator || '/'));
35+
super('directory', basename(path, ctx.separator || '/'));
3336
this.ctx = createCtx(ctx);
37+
this.__path = path[path.length - 1] === this.ctx.separator ? path : path + this.ctx.separator;
3438
}
3539

3640
/**
@@ -84,7 +88,7 @@ export class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle implemen
8488
options?: GetDirectoryHandleOptions,
8589
): Promise<IFileSystemDirectoryHandle> {
8690
assertName(name, 'getDirectoryHandle', 'FileSystemDirectoryHandle');
87-
const filename = this.__path + this.ctx.separator! + name;
91+
const filename = this.__path + name;
8892
try {
8993
const stats = await this.fs.promises.stat(filename);
9094
if (!stats.isDirectory()) throw newTypeMismatchError();
@@ -121,7 +125,7 @@ export class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle implemen
121125
*/
122126
public async getFileHandle(name: string, options?: GetFileHandleOptions): Promise<IFileSystemFileHandle> {
123127
assertName(name, 'getFileHandle', 'FileSystemDirectoryHandle');
124-
const filename = this.__path + this.ctx.separator! + name;
128+
const filename = this.__path + name;
125129
try {
126130
const stats = await this.fs.promises.stat(filename);
127131
if (!stats.isFile()) throw newTypeMismatchError();
@@ -159,7 +163,7 @@ export class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle implemen
159163
public async removeEntry(name: string, { recursive = false }: RemoveEntryOptions = {}): Promise<void> {
160164
assertCanWrite(this.ctx.mode!);
161165
assertName(name, 'removeEntry', 'FileSystemDirectoryHandle');
162-
const filename = this.__path + this.ctx.separator! + name;
166+
const filename = this.__path + name;
163167
const promises = this.fs.promises;
164168
try {
165169
const stats = await promises.stat(filename);

src/node-to-fsa/__tests__/util.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ describe('basename()', () => {
99
expect(basename('scary.exe', '/')).toBe('scary.exe');
1010
});
1111

12+
test('ignores slash, if it is the last char', () => {
13+
expect(basename('scary.exe/', '/')).toBe('scary.exe');
14+
expect(basename('/ab/c/scary.exe/', '/')).toBe('scary.exe');
15+
});
16+
1217
test('returns last step in path', () => {
1318
expect(basename('/gg/wp/hf/gl.txt', '/')).toBe('gl.txt');
1419
expect(basename('gg/wp/hf/gl.txt', '/')).toBe('gl.txt');

src/node-to-fsa/types.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
1-
import type { IFs } from '..';
1+
import type {FsPromisesApi, FsSynchronousApi} from '../node/types';
2+
import type {FsCommonObjects} from '../node/types/FsCommonObjects';
23

34
/**
45
* Required Node.js `fs` module functions for File System Access API.
56
*/
6-
export type NodeFsaFs = Pick<
7-
IFs,
8-
| 'promises'
9-
| 'constants'
10-
| 'openSync'
11-
| 'fsyncSync'
12-
| 'statSync'
13-
| 'closeSync'
14-
| 'readSync'
15-
| 'truncateSync'
16-
| 'writeSync'
17-
>;
7+
export type NodeFsaFs = Pick<FsCommonObjects, 'constants'> & {promises: FsPromisesApi} &
8+
Pick<FsSynchronousApi,
9+
| 'openSync'
10+
| 'fsyncSync'
11+
| 'statSync'
12+
| 'closeSync'
13+
| 'readSync'
14+
| 'truncateSync'
15+
| 'writeSync'>;
1816

1917
export interface NodeFsaContext {
2018
separator: '/' | '\\';

src/node-to-fsa/util.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const ctx = (partial: Partial<NodeFsaContext> = {}): NodeFsaContext => {
1313
};
1414

1515
export const basename = (path: string, separator: string) => {
16+
if (path[path.length - 1] === separator) path = path.slice(0, -1);
1617
const lastSlashIndex = path.lastIndexOf(separator);
1718
return lastSlashIndex === -1 ? path : path.slice(lastSlashIndex + 1);
1819
};

0 commit comments

Comments
 (0)