Repository: perry-mitchell/webdav-client (ts)

Issue:
Return current directory info on getDirectoryContents
Hello!
Thanks for your awesome lib :)

I would like to not filter out the current directory while doing a `getDirectoryContents` to avoid an extra request to store the data, is this possible? !

https://github.com/perry-mitchell/webdav-client/blob/94f70538d1f47dce8f450efb647c9006d9a72bec/source/interface/directoryContents.js#L42-L47

Have a great day!

Pull request:
feat(getDirectoryContents): allow returning current directory
fix #178 

Allows you to get the directory within its contents results.

- [x] Feature
- [x] Testing
- [x] Formatting

Patch:
diff --git a/source/operations/directoryContents.ts b/source/operations/directoryContents.ts
index 086015f..1933e9d 100644
--- a/source/operations/directoryContents.ts
+++ b/source/operations/directoryContents.ts
@@ -37,7 +37,13 @@ export async function getDirectoryContents(
     }
     const davResp = await parseXML(responseData);
     const _remotePath = remotePath.startsWith("/") ? remotePath : "/" + remotePath;
-    let files = getDirectoryFiles(davResp, context.remotePath, _remotePath, options.details);
+    let files = getDirectoryFiles(
+        davResp,
+        context.remotePath,
+        _remotePath,
+        options.details,
+        options.includeSelf
+    );
     if (options.glob) {
         files = processGlobFilter(files, options.glob);
     }
@@ -48,35 +54,40 @@ function getDirectoryFiles(
     result: DAVResult,
     serverBasePath: string,
     requestPath: string,
-    isDetailed: boolean = false
+    isDetailed: boolean = false,
+    includeSelf: boolean = false
 ): Array<FileStat> {
     const serverBase = pathPosix.join(serverBasePath, "/");
     // Extract the response items (directory contents)
     const {
         multistatus: { response: responseItems }
     } = result;
-    return (
-        responseItems
-            // Map all items to a consistent output structure (results)
-            .map(item => {
-                // HREF is the file path (in full)
-                const href = normaliseHREF(item.href);
-                // Each item should contain a stat object
-                const {
-                    propstat: { prop: props }
-                } = item;
-                // Process the true full filename (minus the base server path)
-                const filename =
-                    serverBase === "/"
-                        ? decodeURIComponent(normalisePath(href))
-                        : decodeURIComponent(normalisePath(pathPosix.relative(serverBase, href)));
-                return prepareFileFromProps(props, filename, isDetailed);
-            })
-            // Filter out the item pointing to the current directory (not needed)
-            .filter(
-                item =>
-                    item.basename &&
-                    (item.type === "file" || item.filename !== requestPath.replace(/\/$/, ""))
-            )
+
+    // Map all items to a consistent output structure (results)
+    const nodes = responseItems.map(item => {
+        // HREF is the file path (in full)
+        const href = normaliseHREF(item.href);
+        // Each item should contain a stat object
+        const {
+            propstat: { prop: props }
+        } = item;
+        // Process the true full filename (minus the base server path)
+        const filename =
+            serverBase === "/"
+                ? decodeURIComponent(normalisePath(href))
+                : decodeURIComponent(normalisePath(pathPosix.relative(serverBase, href)));
+        return prepareFileFromProps(props, filename, isDetailed);
+    });
+
+    // If specified, also return the current directory
+    if (includeSelf) {
+        return nodes;
+    }
+
+    // Else, filter out the item pointing to the current directory (not needed)
+    return nodes.filter(
+        item =>
+            item.basename &&
+            (item.type === "file" || item.filename !== requestPath.replace(/\/$/, ""))
     );
 }
diff --git a/source/types.ts b/source/types.ts
index 5d6f2b0..6055446 100644
--- a/source/types.ts
+++ b/source/types.ts
@@ -109,6 +109,7 @@ export interface GetDirectoryContentsOptions extends WebDAVMethodOptions {
     deep?: boolean;
     details?: boolean;
     glob?: string;
+    includeSelf?: boolean;
 }
 
 export interface GetFileContentsOptions extends WebDAVMethodOptions {


Test patch:
diff --git a/test/node/operations/getDirectoryContents.spec.ts b/test/node/operations/getDirectoryContents.spec.ts
index 56a51cf..39baed6 100644
--- a/test/node/operations/getDirectoryContents.spec.ts
+++ b/test/node/operations/getDirectoryContents.spec.ts
@@ -1,5 +1,5 @@
 import { expect } from "chai";
-import { AuthType } from "../../../source/index.js";
+import { AuthType, FileStat } from "../../../source/index.js";
 import {
     SERVER_PASSWORD,
     SERVER_PORT,
@@ -262,4 +262,30 @@ describe("getDirectoryContents", function () {
             });
         });
     });
+
+    describe("when using includeSelf: true", function () {
+        it("returns correct directory results with directory itself", function () {
+            return this.client
+                .getDirectoryContents("/", { includeSelf: true })
+                .then(function (contents: Array<FileStat>) {
+                    const root = contents.find(item => item.basename === "");
+                    expect(root.filename).to.equal("/");
+                    expect(root.size).to.equal(0);
+                    expect(root.type).to.equal("directory");
+                    expect(contents.length).to.equal(12);
+                });
+        });
+
+        it("returns correct file results in sub-directory", function () {
+            return this.client
+                .getDirectoryContents("/sub1", { includeSelf: true })
+                .then(function (contents: Array<FileStat>) {
+                    const sub1 = contents.find(item => item.basename === "sub1");
+                    expect(sub1.filename).to.equal("/sub1");
+                    expect(sub1.size).to.equal(0);
+                    expect(sub1.type).to.equal("directory");
+                    expect(contents.length).to.equal(3);
+                });
+        });
+    });
 });