{"id":26126196,"url":"https://github.com/discoveryjs/scan-fs","last_synced_at":"2026-05-28T06:10:31.323Z","repository":{"id":35102605,"uuid":"206987949","full_name":"discoveryjs/scan-fs","owner":"discoveryjs","description":"An utility for seeking files by file system scanning and optionally populating file info with processing their content","archived":false,"fork":false,"pushed_at":"2024-03-15T15:50:27.000Z","size":355,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-25T12:30:58.334Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/discoveryjs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-07T15:30:47.000Z","updated_at":"2022-06-09T13:00:21.000Z","dependencies_parsed_at":"2024-03-15T16:51:11.153Z","dependency_job_id":"54a2661b-5b07-495b-8f75-63c5cfcf7af7","html_url":"https://github.com/discoveryjs/scan-fs","commit_stats":{"total_commits":49,"total_committers":1,"mean_commits":49.0,"dds":0.0,"last_synced_commit":"676dd6a5be2b0435b12a0d8e3a8cf9506531f22a"},"previous_names":["discoveryjs/fs"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/discoveryjs/scan-fs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discoveryjs%2Fscan-fs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discoveryjs%2Fscan-fs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discoveryjs%2Fscan-fs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discoveryjs%2Fscan-fs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/discoveryjs","download_url":"https://codeload.github.com/discoveryjs/scan-fs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/discoveryjs%2Fscan-fs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33596370,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"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":[],"created_at":"2025-03-10T17:28:02.421Z","updated_at":"2026-05-28T06:10:31.305Z","avatar_url":"https://github.com/discoveryjs.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @discoveryjs/scan-fs\n\n[![NPM version](https://img.shields.io/npm/v/@discoveryjs/scan-fs.svg)](https://www.npmjs.com/package/@discoveryjs/scan-fs)\n[![Build](https://github.com/discoveryjs/scan-fs/actions/workflows/build.yml/badge.svg)](https://github.com/discoveryjs/scan-fs/actions/workflows/build.yml)\n[![Coverage Status](https://coveralls.io/repos/github/discoveryjs/scan-fs/badge.svg?branch=master)](https://coveralls.io/github/discoveryjs/scan-fs?branch=master)\n[![Twitter](https://img.shields.io/badge/Twitter-@js_discovery-blue.svg)](https://twitter.com/js_discovery)\n\nAn utility for seeking files by file system scanning and optionally populating file info with processing their content. It's like a Webpack's loaders but for extracting data from a FS and files.\n\nIs a part of [Discovery.js](https://github.com/discoveryjs) projects.\n\n\u003c!-- TOC depthFrom:2 --\u003e\n\n- [How to use](#how-to-use)\n- [API](#api)\n  - [scanFs(options?: Options | string): Promise\\\u003cScanResult\u003e](#scanfsoptions-options--string-promisescanresult)\n  - [normalizeOptions(options: Options | string = {}): NormalizedOptions](#normalizeoptionsoptions-options--string---normalizedoptions)\n  - [Types](#types)\n- [Examples](#examples)\n- [License](#license)\n\n\u003c!-- /TOC --\u003e\n\n## How to use\n\nInstall:\n\n```\nnpm install @discoveryjs/scan-fs\n```\n\nUse:\n\n```js\nimport { scanFs } from '@discoveryjs/scan-fs';\n// or const { scanFs } = require('@discoveryjs/scan-fs')\n\nconst { files, symlinks, errors } = scanFs({\n  /* options */\n});\n```\n\n## API\n\n### scanFs(options?: Options | string): Promise\u003cScanResult\u003e\n\nMain method that scans a file system for files and symlinks, returns an object with the following fields:\n\n- `basedir` - a directory path which is using to make an absolute path for files and symlinks\n- `files` – a list of files that meet a path requirements and match to one of rules if any\n- `symlinks` – a list of symlinks that meet a path requirements\n- `errors` – a list of errors occuried during file processing or symlink resolving\n- `pathsScanned` – a number of paths which was examinated during a scanning\n- `filesTested` – a number of file paths which was examinated by rules\n\nA value of `options` parameter is a string (which equivalent to `{ basedir: \u003cstring\u003e }` object) or an object with all optional fields:\n\n\u003e Note: `options` argument is also optional which equivalent to a call `scanFs({})` or `scanFs({ basedir: process.pwd() })`.\n\n- **basedir**\n\n  Type: `string`  \n  Default: `process.cwd()`\n\n  Base directory to scan and resolve paths to. All the paths in a result are relative to `basedir`.\n\n- **include**\n\n  Type: `string`, `string[]` or `null`  \n  Default: `null`\n\n  A list of directories to scan relative to `basedir`. When used, a scanned file path must start with one of the directories from the list. `include` has priority over `exclude` option, i.e. `include` wins when the same path is used in `include` and `exclude` options. Paths should be specified in POSIX disregarding of used operating system.\n\n- **exclude**\n\n  Type: `string`, `string[]` or `null`  \n  Default: `null`\n\n  A list of directories to avoid scan relative to `basedir`. When used, a file relative path must not start with any of the directories from the list. Paths should be specified in POSIX disregarding of used operating system.\n\n- **rules**\n\n  Type: `Rule` or `Rule[]`  \n  Default: `[{}]`\n\n  `rules` defines which files should be added to a result and how to process them. When not set no any file will be matched. A first rule that can be applied wins, so other rules are skipping.\n\n- **resolveSymlinks**\n\n  Type: `boolean`  \n  Default: `false`\n\n  Try to resolve the canonical pathname for symbolic links, the result is storing in `realpath` of `Symlink`. In case a resolving is failed or disabled the `realpath` field will contain `null`. On failure, an error is emitting with reason `resolve-symlink`.\n\n- **onError**\n\n  Type: `function(error)` or `null`  \n  Default: `null`\n\n  A handler that is used when an error is occuring during FS scan or file processing. By default nothing happens, but adds to errors `array` which can be reached by `errors` field of a result.\n\nA **rule** is an object with following fields (all are optional):\n\n- **test**\n\n  Type: `RegExp`, `RegExp[]` or `null`  \n  Default: `null`\n\n  A list of RegExps that applies to a POSIX path relative to `options.basedir`.\n\n- **include**\n\n  Type: `string`, `string[]` or `null`  \n  Default: `null`\n\n  The same as for `options.include` but applies on a rule's level. When used it also populates `options.include`.\n\n- **exclude**\n\n  Type: `string`, `string[]` or `null`  \n  Default: `undefnullined`\n\n  The same as for `options.exclude` but applies on a rule's level.\n\n- **extract**\n\n  Type: `function(file: File, content: string, rule: MatchRule)`  \n  Default: `undefined`\n\n  A function that extract some data from a file content. Such a function receives three arguments:\n\n  - `file` – an instance of `File`\n  - `content` – a string or `Buffer` (depends on `encoding` option, see below) which contain a content of file\n  - `rule` – rule object with normalized options and `basedir` (as a value of `options.basedir`)\n\n  On failure, an error is emitting with reason `extract`.\n\n- **encoding**\n\n  Type: `BufferEncoding` or `null`  \n  Default: `'utf8'`\n\n  Specifies an enconding for `content` parameter of `extract` callback when used. Allowed values are the same as for Node.js's `Buffer` (see [Buffers and character encodings](https://nodejs.org/docs/latest-v18.x/api/buffer.html#buffers-and-character-encodings)). When option value is set to `null`, the value of `content` is `Buffer` instead of string\n\n- **only**\n\n  Type: `boolean`  \n  Default: `false`\n\n  When `only` is true only single rule applies. If several rules have truthy value for `only`, then first rule wins. The option is useful for debugging.\n\n### normalizeOptions(options: Options = {}): NormalizedOptions\n\nThis method is used internally to normalize options, which is reducing checking and potential errors during a FS scan. The method can be useful to understand how `scanFs()` transforms passed options.\n\n### Types\n\n```ts\ntype Rule = {\n  only?: boolean;\n  test?: RegExp | RegExp[];\n  include?: string | string[];\n  exclude?: string | string[];\n  extract?: ExtractCallback;\n  encoding?: BufferEncoding | null;\n};\ntype Options = {\n  basedir?: string;\n  include?: string | string[];\n  exclude?: string | string[];\n  rules?: Rule | Rule[];\n  resolveSymlinks?: boolean;\n  onError?: boolean | ((error: Error) =\u003e void);\n};\n\ntype AcceptCallback = (relpath: string) =\u003e boolean;\ntype ExtractCallback = (file: File, content: string | Buffer, rule: MatchRule) =\u003e void;\ntype MatchRule = {\n  basedir: string;\n  accept: AcceptCallback;\n  extract: ExtractCallback | null;\n  encoding: BufferEncoding | null;\n  config: Rule;\n  test: RegExp[] | null;\n  include: string[] | null;\n  exclude: string[] | null;\n};\ntype NormalizedOptions = {\n  basedir: string;\n  include: string[];\n  exclude: string[];\n  rules: MatchRule[];\n  resolveSymlinks: boolean;\n  onError: (error: Error) =\u003e void;\n};\n\ntype ScanResult = {\n  basedir: string;\n  files: File[];\n  symlinks: Symlink[];\n  errors: ScanError[];\n  pathsScanned: number;\n  filesTested: number;\n};\n\ntype File = {\n  path: string;\n  posixPath: string;\n  errors?: Array\u003c{ message: string; details: any }\u003e;\n  error(message: string, details: any): void;\n};\ntype Symlink = {\n  path: string;\n  posixPath: string;\n  realpath: string | null;\n};\ntype ScanError = Error \u0026 {\n  reason: 'resolve-symlink' | 'extract';\n  path: string;\n  toJSON(): { reason: string; path: string; message: string };\n};\n```\n\n## Examples\n\nFind all `package.json` files from `node_modules` and extract `name` and `dependencies` from each one:\n\n```js\nimport { scanFs } from '@discoveryjs/scan-fs';\n\nconst { files } = await scanFs({\n  exclude: ['.git', 'node_modules'],\n  rules: [\n    {\n      test: /\\/package.json$/,\n      extract(file, content) {\n        const pkg = JSON.parse(content);\n        file.name = pkg.name;\n        file.dependencies = pkg.dependencies;\n      }\n    }\n  ]\n});\n\nfor (const file of files) {\n  console.log(file);\n}\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiscoveryjs%2Fscan-fs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiscoveryjs%2Fscan-fs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiscoveryjs%2Fscan-fs/lists"}