Skip to content

Commit

Permalink
fix: 🐛 handle root folder better
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Jun 17, 2023
1 parent 43da1d6 commit 76de780
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 12 deletions.
18 changes: 13 additions & 5 deletions src/fsa-to-node/FsaNodeFs.ts
Expand Up @@ -14,6 +14,7 @@ import {
getWriteFileOptions,
} from '../node/options';
import {
bufferToEncoding,
createError,
dataToBuffer,
flagsToNumber,
Expand All @@ -31,19 +32,19 @@ import { pathToLocation, testDirectoryIsWritable } from './util';
import { ERRSTR, MODE } from '../node/constants';
import { strToEncoding } from '../encoding';
import { FsaToNodeConstants } from './constants';
import { bufferToEncoding } from '../volume';
import { FsaNodeFsOpenFile } from './FsaNodeFsOpenFile';
import { FsaNodeDirent } from './FsaNodeDirent';
import { FLAG } from '../consts/FLAG';
import { AMODE } from '../consts/AMODE';
import { constants } from '../constants';
import { FsaNodeStats } from './FsaNodeStats';
import process from '../process';
import { FsSynchronousApi } from '../node/types/FsSynchronousApi';
import type { FsCallbackApi, FsPromisesApi } from '../node/types';
import type * as misc from '../node/types/misc';
import type * as opts from '../node/types/options';
import type * as fsa from '../fsa/types';
import type { FsCommonObjects } from '../node/types/FsCommonObjects';
import { FsSynchronousApi } from '../node/types/FsSynchronousApi';

const notSupported: (...args: any[]) => any = () => {
throw new Error('Method not supported by the File System Access API.');
Expand Down Expand Up @@ -78,9 +79,13 @@ export class FsaNodeFs implements FsCallbackApi, FsSynchronousApi, FsCommonObjec
*/
private async getDir(path: string[], create: boolean, funcName?: string): Promise<fsa.IFileSystemDirectoryHandle> {
let curr: fsa.IFileSystemDirectoryHandle = this.root;

const options: fsa.GetDirectoryHandleOptions = { create };

try {
for (const name of path) curr = await curr.getDirectoryHandle(name, options);
for (const name of path) {
curr = await curr.getDirectoryHandle(name, options);
}
} catch (error) {
if (error && typeof error === 'object' && error.name === 'TypeMismatchError')
throw createError('ENOTDIR', funcName, path.join(FsaToNodeConstants.Separator));
Expand Down Expand Up @@ -447,7 +452,7 @@ export class FsaNodeFs implements FsCallbackApi, FsSynchronousApi, FsCommonObjec
const filename = pathToFilename(path);
const [folder, name] = pathToLocation(filename);
(async () => {
const node = await this.getFileOrDir(folder, name, 'access');
const node = folder.length || name ? await this.getFileOrDir(folder, name, 'access') : this.root;
const checkIfCanExecute = mode & AMODE.X_OK;
if (checkIfCanExecute) throw createError('EACCESS', 'access', filename);
const checkIfCanWrite = mode & AMODE.W_OK;
Expand Down Expand Up @@ -508,7 +513,7 @@ export class FsaNodeFs implements FsCallbackApi, FsSynchronousApi, FsCommonObjec
const [options, callback] = getReaddirOptsAndCb(a, b);
const filename = pathToFilename(path);
const [folder, name] = pathToLocation(filename);
folder.push(name);
if (name) folder.push(name);
this.getDir(folder, false, 'readdir')
.then(dir =>
(async () => {
Expand All @@ -527,8 +532,11 @@ export class FsaNodeFs implements FsCallbackApi, FsSynchronousApi, FsCommonObjec
return list;
} else {
const list: string[] = [];

for await (const key of dir.keys()) list.push(key);

if (!isWin && options.encoding !== 'buffer') list.sort();

return list;
}
})(),
Expand Down
6 changes: 5 additions & 1 deletion src/fsa-to-node/__tests__/util.test.ts
@@ -1,10 +1,14 @@
import { pathToLocation } from '../util';

describe('pathToLocation()', () => {
test('handles empty string', () => {
test('handles an empty string', () => {
expect(pathToLocation('')).toStrictEqual([[], '']);
});

test('handles a single slash', () => {
expect(pathToLocation('/')).toStrictEqual([[], '']);
});

test('no path, just filename', () => {
expect(pathToLocation('scary.exe')).toStrictEqual([[], 'scary.exe']);
});
Expand Down
8 changes: 8 additions & 0 deletions src/fsa-to-node/index.ts
@@ -0,0 +1,8 @@
import { FsaNodeFs } from './FsaNodeFs';
import type { IFileSystemDirectoryHandle } from '../fsa/types';

export { FsaNodeFs };

export const fsaToNode = (root: IFileSystemDirectoryHandle) => {
return new FsaNodeFs(root);
};
7 changes: 6 additions & 1 deletion src/node/util.ts
Expand Up @@ -2,7 +2,7 @@ import { ERRSTR, FLAGS } from './constants';
import * as errors from '../internal/errors';
import type { FsCallbackApi } from './types';
import type * as misc from './types/misc';
import { ENCODING_UTF8 } from '../encoding';
import { ENCODING_UTF8, TEncodingExtended } from '../encoding';
import { bufferFrom } from '../internal/buffer';

export const isWin = process.platform === 'win32';
Expand Down Expand Up @@ -241,3 +241,8 @@ export const getWriteArgs = (
const cb = validateCallback(callback);
return [fd, tipa === 'string', buf, offset, length!, position, cb];
};

export function bufferToEncoding(buffer: Buffer, encoding?: TEncodingExtended): misc.TDataOut {
if (!encoding || encoding === 'buffer') return buffer;
else return buffer.toString(encoding);
}
6 changes: 1 addition & 5 deletions src/volume.ts
Expand Up @@ -47,6 +47,7 @@ import {
isWin,
dataToBuffer,
getWriteArgs,
bufferToEncoding,
} from './node/util';
import type { PathLike, symlink } from 'fs';

Expand Down Expand Up @@ -201,11 +202,6 @@ export function dataToStr(data: TData, encoding: string = ENCODING_UTF8): string
else return String(data);
}

export function bufferToEncoding(buffer: Buffer, encoding?: TEncodingExtended): TDataOut {
if (!encoding || encoding === 'buffer') return buffer;
else return buffer.toString(encoding);
}

// converts Date or number to a fractional UNIX timestamp
export function toUnixTimestamp(time) {
// tslint:disable-next-line triple-equals
Expand Down

0 comments on commit 76de780

Please sign in to comment.