From bf47b96cec4b1c8c029a0668ea4c1cf8cbcd05f0 Mon Sep 17 00:00:00 2001 From: streamich Date: Wed, 14 Jun 2023 20:47:13 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20implement=20.resolve()?= =?UTF-8?q?=20method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NodeFileSystemDirectoryHandle.ts | 28 +++++++++----- src/node-to-fsa/NodeFileSystemFileHandle.ts | 4 +- .../NodeFileSystemDirectoryHandle.test.ts | 38 +++++++++++++++++++ 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/node-to-fsa/NodeFileSystemDirectoryHandle.ts b/src/node-to-fsa/NodeFileSystemDirectoryHandle.ts index 2cdfd47c8..d767c9d84 100644 --- a/src/node-to-fsa/NodeFileSystemDirectoryHandle.ts +++ b/src/node-to-fsa/NodeFileSystemDirectoryHandle.ts @@ -10,10 +10,10 @@ import type Dirent from "../Dirent"; export class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle { constructor ( protected readonly fs: NodeFsaFs, - protected readonly path: string, + public readonly __path: string, protected readonly ctx: Partial = createCtx(ctx), ) { - super('directory', basename(path, ctx.separator!)); + super('directory', basename(__path, ctx.separator!)); } /** @@ -23,7 +23,7 @@ export class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle { * @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle/keys */ public async * keys(): AsyncIterableIterator { - const list = await this.fs.promises.readdir(this.path); + const list = await this.fs.promises.readdir(this.__path); for (const name of list) yield '' + name; } @@ -31,7 +31,7 @@ export class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle { * @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle/entries */ public async * entries(): AsyncIterableIterator<[string, NodeFileSystemHandle]> { - const {path, fs, ctx} = this; + const {__path: path, fs, ctx} = this; const list = await fs.promises.readdir(path, {withFileTypes: true}); for (const d of list) { const dirent = d as Dirent; @@ -64,7 +64,7 @@ export class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle { */ public async getDirectoryHandle(name: string, options?: GetDirectoryHandleOptions): Promise { assertName(name, 'getDirectoryHandle', 'FileSystemDirectoryHandle'); - const filename = this.path + this.ctx.separator! + name; + const filename = this.__path + this.ctx.separator! + name; try { const stats = await this.fs.promises.stat(filename); if (!stats.isDirectory()) throw newTypeMismatchError(); @@ -100,7 +100,7 @@ export class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle { */ public async getFileHandle(name: string, options?: GetFileHandleOptions): Promise { assertName(name, 'getFileHandle', 'FileSystemDirectoryHandle'); - const filename = this.path + this.ctx.separator! + name; + const filename = this.__path + this.ctx.separator! + name; try { const stats = await this.fs.promises.stat(filename); if (!stats.isFile()) throw newTypeMismatchError(); @@ -136,7 +136,7 @@ export class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle { */ public async removeEntry(name: string, {recursive = false}: RemoveEntryOptions = {}): Promise { assertName(name, 'removeEntry', 'FileSystemDirectoryHandle'); - const filename = this.path + this.ctx.separator! + name; + const filename = this.__path + this.ctx.separator! + name; const promises = this.fs.promises; try { const stats = await promises.stat(filename); @@ -172,8 +172,18 @@ export class NodeFileSystemDirectoryHandle extends NodeFileSystemHandle { * @param possibleDescendant The {@link NodeFileSystemFileHandle} from which * to return the relative path. */ - public resolve(possibleDescendant: NodeFileSystemHandle): Promise { - throw new Error('Not implemented'); + public async resolve(possibleDescendant: NodeFileSystemHandle): Promise { + if (possibleDescendant instanceof NodeFileSystemDirectoryHandle || possibleDescendant instanceof NodeFileSystemFileHandle) { + const path = this.__path; + const childPath = possibleDescendant.__path; + if (!childPath.startsWith(path)) return null; + let relative = childPath.slice(path.length); + if (relative === '') return []; + const separator = this.ctx.separator!; + if (relative[0] === separator) relative = relative.slice(1); + return relative.split(separator); + } + return null; } } diff --git a/src/node-to-fsa/NodeFileSystemFileHandle.ts b/src/node-to-fsa/NodeFileSystemFileHandle.ts index 7df0e7d94..6b13174ad 100644 --- a/src/node-to-fsa/NodeFileSystemFileHandle.ts +++ b/src/node-to-fsa/NodeFileSystemFileHandle.ts @@ -6,10 +6,10 @@ import type {NodeFsaContext, NodeFsaFs} from "./types"; export class NodeFileSystemFileHandle extends NodeFileSystemHandle { constructor ( protected readonly fs: NodeFsaFs, - protected readonly path: string, + public readonly __path: string, protected readonly ctx: Partial = createCtx(ctx), ) { - super('file', basename(path, ctx.separator!)); + super('file', basename(__path, ctx.separator!)); } /** diff --git a/src/node-to-fsa/__tests__/NodeFileSystemDirectoryHandle.test.ts b/src/node-to-fsa/__tests__/NodeFileSystemDirectoryHandle.test.ts index be9724760..68d70b73b 100644 --- a/src/node-to-fsa/__tests__/NodeFileSystemDirectoryHandle.test.ts +++ b/src/node-to-fsa/__tests__/NodeFileSystemDirectoryHandle.test.ts @@ -321,3 +321,41 @@ describe('.removeEntry()', () => { expect(res).toBe(undefined); }); }); + +describe('.resolve()', () => { + test('return empty array for itself', async () => { + const {dir} = setup({}); + const res = await dir.resolve(dir); + expect(res).toEqual([]); + }); + + test('can resolve one level deep child', async () => { + const {dir} = setup({ + file: 'contents', + }); + const child = await dir.getFileHandle('file'); + const res = await dir.resolve(child); + expect(res).toEqual(['file']); + }); + + test('can resolve two level deep child', async () => { + const {dir} = setup({ + 'dir/file': 'contents', + }); + const child1 = await dir.getDirectoryHandle('dir'); + const child2 = await child1.getFileHandle('file'); + const res = await dir.resolve(child2); + expect(res).toEqual(['dir', 'file']); + const res2 = await child1.resolve(child2); + expect(res2).toEqual(['file']); + }); + + test('returns "null" if not a descendant', async () => { + const {dir} = setup({ + 'dir/file': 'contents', + }); + const child1 = await dir.getDirectoryHandle('dir'); + const res = await child1.resolve(dir); + expect(res).toBe(null); + }); +});