{"id":18396695,"url":"https://github.com/igorskyflyer/npm-recursive-readdir","last_synced_at":"2026-05-14T20:02:06.692Z","repository":{"id":57118122,"uuid":"381142318","full_name":"igorskyflyer/npm-recursive-readdir","owner":"igorskyflyer","description":"📖 Fast, type-safe recursive directory reader for Node.js with depth control, entry filtering, and sync/async APIs. 📁","archived":false,"fork":false,"pushed_at":"2025-09-22T19:50:09.000Z","size":321,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-22T08:30:12.138Z","etag":null,"topics":["back-end","directory","filesystem","igorskyflyer","javascript","node","nodejs","readdir","recursive","traversal"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@igorskyflyer/recursive-readdir","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/igorskyflyer.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":"SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"ko_fi":"igorskyflyer"}},"created_at":"2021-06-28T19:36:05.000Z","updated_at":"2025-09-22T19:50:04.000Z","dependencies_parsed_at":"2025-09-22T21:10:48.615Z","dependency_job_id":"1993b9d1-f195-4508-a19c-05f001d54dc2","html_url":"https://github.com/igorskyflyer/npm-recursive-readdir","commit_stats":null,"previous_names":["igorskyflyer/npm-resursive-readdir"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/igorskyflyer/npm-recursive-readdir","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorskyflyer%2Fnpm-recursive-readdir","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorskyflyer%2Fnpm-recursive-readdir/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorskyflyer%2Fnpm-recursive-readdir/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorskyflyer%2Fnpm-recursive-readdir/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/igorskyflyer","download_url":"https://codeload.github.com/igorskyflyer/npm-recursive-readdir/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorskyflyer%2Fnpm-recursive-readdir/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33041204,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"online","status_checked_at":"2026-05-14T02:00:06.663Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["back-end","directory","filesystem","igorskyflyer","javascript","node","nodejs","readdir","recursive","traversal"],"created_at":"2024-11-06T02:14:36.186Z","updated_at":"2026-05-14T20:02:06.672Z","avatar_url":"https://github.com/igorskyflyer.png","language":"TypeScript","funding_links":["https://ko-fi.com/igorskyflyer"],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/igorskyflyer/npm-recursive-readdir/main/media/recursive-readdir.png\" alt=\"Icon of Recursive ReadDir\" width=\"256\" height=\"256\"\u003e\n  \u003ch1\u003eRecursive ReadDir\u003c/h1\u003e\n\u003c/div\u003e\n\n\u003cblockquote align=\"center\"\u003e\n  Recursive Directory Reading • Sync And Async Usage • Flexible Filters • Depth Control\n\u003c/blockquote\u003e\n\n\u003ch4 align=\"center\"\u003e\n  📖 Fast, type-safe recursive directory reader for Node.js with depth control, entry filtering, and sync/async APIs. 📁\n\u003c/h4\u003e\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n## 📃 Table of Contents\n\n- [**Features**](#-features)\n- [**Motivation**](#-features)\n- [**Usage**](#-usage)\n- [**API**](#-api)\n  - [**Function-based**](#λ-function-based)\n  - [**Class-based**](#-class-based)\n- [**Examples**](#️-examples)\n- [**Changelog**](#-changelog)\n- [**Support**](#-support)\n- [**License**](#-license)\n- [**Related**](#-related)\n- [**Author**](#-author)\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n## 🤖 Features\n\n- 📂 Reads directories recursively with precise depth control\n- 🎯 Filters results by files-only, directories-only, or all entries\n- ⚡ Supports both synchronous and asynchronous operations\n- 🧩 Accepts custom filter functions for advanced selection\n- ✨ Optionally adds trailing slashes to directory paths\n- 🛡️ Skips unreadable entries without stopping traversal\n- 🏗 Provides a fluent class API for easy configuration\n- 💻 Cross-platform paths, powered by [**uPath**](https://www.npmjs.com/package/@igorskyflyer/upath)\n\n\u003cbr\u003e\n\n## 🎯 Motivation\n\nThis npm module was built to provide a reliable and efficient way of listing directories while another project was being developed - a Visual Studio Code extension called [**New Folder**](https://github.com/igorskyflyer/vscode-new-folder), where a custom QuickPick dialog was required to allow the selection of a root directory.\n\n\u003cbr\u003e\n\n## 🕵🏼 Usage\n\nInstall it by executing any of the following, depending on your preferred package manager:\n\n```bash\npnpm add @igorskyflyer/recursive-readdir\n```\n\n```bash\nyarn add @igorskyflyer/recursive-readdir\n```\n\n```bash\nnpm i @igorskyflyer/recursive-readdir\n```\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n## 🤹🏼 API\n\n### λ Function-based\n\n```ts\nasync function readDir(directory: string, options: RecursiveDirOptions): Promise\u003cstring[]\u003e\n```\n\nAsynchronously gets files/directories inside the given directory.\n\n\u003cbr\u003e\n\n**Params**\n\n_**directory**_: `string` - the directory whose files/directories should be listed,\n\n_**options**_: `RecursiveDirOptions` - additional options.\n\n\u003cbr\u003e\n\n```ts\n function readDirSync(directory: string, options: RecursiveDirOptions): string[]\n```\n\nSynchronously gets files/directories inside the given directory.\n\n\u003cbr\u003e\n\n**Params**\n\n_**directory**_: `string` - the directory whose files/directories should be listed,\n\n_**options**_: `RecursiveDirOptions` - additional options.\n\n\u003cbr\u003e\n\n### 💎 Class-based\n\nFor own convenience and code-reuse you can use the class-based approach.\n\nDefine the options once and (re)call the `readDirSync()`/`readDir()` when needed.\n\n\u003cbr\u003e\n\n```ts\nclass RecursiveDir\n```\n\n\u003cbr\u003e\n\n**Available methods**\n\n```ts\nfunction readDirSync(directory: string): string[]\n```\n\nSynchronously gets files/directories inside the given directory.\n\n\u003cbr\u003e\n\n**Params**\n\n_**directory**_: `string` - the directory whose files/directories should be listed.\n\n\u003cbr\u003e\n\n```ts\nfunction readDir(directory: string): Promise\u003cstring[]\u003e\n```\n\nAsynchronously gets files/directories inside the given directory.\n\n\u003cbr\u003e\n\n**Params**\n\n_**directory**_: `string` - the directory whose files/directories should be listed.\n\n\u003cbr\u003e\n\n```ts\nfunction entries(value: Entry): RecursiveDir\n```\n\nSets the **entries** property which controls whether to list files-only, directories-only or **both** (**default**).\n\n**Params**\n**_value_**: `Entry` - a value with three possible values - provided as class consts,\n\n- **`Entry.All`**,\n- **`Entry.FilesOnly`**,\n- **`Entry.DirectoriesOnly`**.\n\n\u003cbr\u003e\n\n```ts\nfunction maxDepth(value: Depth): RecursiveDir\n```\n\nSets **maxDepth** which controls how many child directories' entries are being listed.\n\n\u003cbr\u003e\n\n**Params**\n\n**_value_**: `Depth` - the new `maxDepth` value.\n\n\u003cbr\u003e\n\nYou can use the 2 predefined values or use an arbitrary value. The predefined values are as follows:\n\n- **`Depth.All`** = -1 - return all subdirectories entries,\n- **`Depth.Root`** = 0 (**default**) - return only root directory's entries.\n\n\u003cbr\u003e\n\n\u003e ### ℹ️ NOTE\n\u003e\n\u003e #### Why the default value of `maxDepth` is **_NOT_** `Depth.All`?\n\u003e\n\u003e It is simple: the value must be explicitly set, since traversal through all child subdirectories is highly resource‑ and time‑consuming. For example, if the directory parameter were set to the root of a drive in combination with `maxDepth = Depth.All`, the operation could become extremely heavy.\n\u003e\n\n\u003cbr\u003e\n\nTo use arbitrary values the provided `value` parameter must comply with the expression `maxDepth \u003e= Depth.Root` i.e., `maxDepth \u003e= 0`.  \n\nThe value of `0` means that only directory entries found in the directory specified when calling either `readDir()` or `readDirSync()` methods are returned. By increasing the number we can set the depth/level of subdirectories that the method should return, e.g.\n\n\u003cbr\u003e\n\n`maxDepth = Depth.Root`\n\n```ts\nmaxDepth(Depth.Root)\n// return only the files/directories in the current directory\n```\n\n\u003cbr\u003e\n\n`maxDepth = 3`\n\n```ts\nmaxDepth(3)\n// return the files/directories in the current director files/directories 3-levels deep\n```\n\n\u003cbr\u003e\n\n`maxDepth = Depth.All`\n\n```ts\nmaxDepth(Depth.All)\n// return all child files/directories in the current directory\n```\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n```ts\nfunction filter(value: FilterCallback): RecursiveDir\n```\n\nSets **filter** predicate function used for filtering directory entries (directories/files).\n\n\u003cbr\u003e\n\n**Params**\n\n_value_: `FilterCallback` - the filter function to use when filtering directory entries.\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n```ts\nfunction addTrailingSlash(value: boolean): RecursiveDir\n```\n\nSets whether a trailing slash should be added to directory entries.\n\n \u003cbr\u003e\n\n**Params**\n\n_value_: `boolean` - a Boolean indicating whether a trailing slash should be added to directory entries.\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n## 🗒️ Examples\n\n```ts\nimport { readDirSync, Depth, Entry, RecursiveDir } from '@igorskyflyer/recursive-readdir'\nconst testingPath: string = './somePath'\n\n// Function-based approach\n\nconsole.log(readDirSync('non-existent-directory')) // returns []\n\nconsole.log(\n  readDirSync(testingPath, {\n    maxDepth: Depth.All,\n    filter: (entry) =\u003e entry.isDirectory,\n  })\n) // returns only subdirectories (all subdirectories)\n\n// the following can be used interchangeably\nconsole.log(\n  readDirSync(testingPath, {\n    maxDepth: Depth.All,\n    entries: Entry.DirectoriesOnly,\n  })\n) // returns only subdirectories (all subdirectories)\n\nconsole.log(\n  readDirSync(testingPath, {\n    maxDepth: Depth.All,\n    entries: Entry.FilesOnly,\n    filter: (entry) =\u003e entry.path.indexOf('.js') \u003e -1,\n  })\n) // returns only JavaScript - .js files found in all (sub)directories\n\n// Class-based approach\n\nconst dir: RecursiveDir = new RecursiveDir()\n\ndir\n  .maxDepth(Depth.All)\n  .entries(Entry.FilesOnly)\n  .filter((entry) =\u003e entry.path.indexOf('.md') \u003e -1)\n\nconsole.log(dir.readDirSync(testingPath)) // returns only .md (Markdown) files found in all (sub)directories\n```\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n## 📝 Changelog\n\n📑 Read about the latest changes in the [**CHANGELOG.md**](https://github.com/igorskyflyer/npm-recursive-readdir/blob/main/CHANGELOG.md).\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n## 🪪 License\n\nLicensed under the [**MIT license**](https://github.com/igorskyflyer/npm-recursive-readdir/blob/main/LICENSE).\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n## 💖 Support\n\n\u003cdiv align=\"center\"\u003e\n  I work hard for every project, including this one and your support means a lot to me!\n  \u003cbr\u003e\n  Consider buying me a coffee. ☕\n  \u003cbr\u003e\n  \u003cbr\u003e\n  \u003ca href=\"https://ko-fi.com/igorskyflyer\" target=\"_blank\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/igorskyflyer/igorskyflyer/main/assets/ko-fi.png\" alt=\"Donate to igorskyflyer\" width=\"180\" height=\"46\"\u003e\u003c/a\u003e\n  \u003cbr\u003e\n  \u003cbr\u003e\n  \u003cem\u003eThank you for supporting my efforts!\u003c/em\u003e 🙏😊\n\u003c/div\u003e\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n## 🧬 Related\n\n[**@igorskyflyer/unc-path**](https://www.npmjs.com/package/@igorskyflyer/unc-path)\n\n\u003e _🥽 Provides ways of parsing UNC paths and checking whether they are valid. 🎱_\n\n\u003cbr\u003e\n\n[**@igorskyflyer/comment-it**](https://www.npmjs.com/package/@igorskyflyer/comment-it)\n\n\u003e _📜 Formats the provided string as a comment, either a single or a multi line comment for the given programming language. 💻_\n\n\u003cbr\u003e\n\n[**@igorskyflyer/strip-html**](https://www.npmjs.com/package/@igorskyflyer/strip-html)\n\n\u003e _🥞 Removes HTML code from the given string. Can even extract text-only from the given an HTML string. ✨_\n\n\u003cbr\u003e\n\n[**@igorskyflyer/upath**](https://www.npmjs.com/package/@igorskyflyer/upath)\n\n\u003e _🎍 Provides a universal way of formatting file-paths in Unix-like and Windows operating systems as an alternative to the built-in path.normalize(). 🧬_\n\n\u003cbr\u003e\n\n[**@igorskyflyer/valid-path**](https://www.npmjs.com/package/@igorskyflyer/valid-path)\n\n\u003e _🧰 Determines whether a given value can be a valid file/directory name. 🏜_\n\n\u003cbr\u003e\n\n## 👨🏻‍💻 Author\nCreated by **Igor Dimitrijević** ([*@igorskyflyer*](https://github.com/igorskyflyer/)).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figorskyflyer%2Fnpm-recursive-readdir","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Figorskyflyer%2Fnpm-recursive-readdir","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figorskyflyer%2Fnpm-recursive-readdir/lists"}