vfile-find-down
Advanced tools
Comparing version 6.0.0 to 6.1.0
@@ -1,34 +0,5 @@ | ||
/// <reference types="node" /> | ||
export const INCLUDE: 1 | ||
export const SKIP: 4 | ||
export const BREAK: 8 | ||
export const findDown: { | ||
( | ||
test: Test, | ||
paths: string | Array<string>, | ||
callback: (error: Error | null, files: Array<VFile>) => void | ||
): void | ||
( | ||
test: Test, | ||
callback: (error: Error | null, files: Array<VFile>) => void | ||
): void | ||
(test: Test, paths?: string | Array<string>): Promise<Array<VFile>> | ||
} | ||
export const findDownOne: { | ||
( | ||
test: Test, | ||
paths: string | Array<string>, | ||
callback: (error: Error | null, file?: VFile) => void | ||
): void | ||
(test: Test, callback: (error: Error | null, file?: VFile) => void): void | ||
(test: Test, paths?: string | Array<string>): Promise<VFile> | ||
} | ||
export type VFile = import('vfile').VFile | ||
export type Test = string | Assert | Array<string | Assert> | ||
export type Assert = (file: VFile, stats: fs.Stats) => number | boolean | void | ||
export type State = { | ||
checked: string[] | ||
test: Assert | ||
broken?: boolean | ||
} | ||
import fs from 'fs' | ||
export type Assert = import('./lib/index.js').Assert | ||
export type Callback = import('./lib/index.js').Callback | ||
export type CallbackOne = import('./lib/index.js').CallbackOne | ||
export type Test = import('./lib/index.js').Test | ||
export {BREAK, INCLUDE, SKIP, findDown, findDownOne} from './lib/index.js' |
291
index.js
/** | ||
* @typedef {import('vfile').VFile} VFile | ||
* @typedef {string|Assert|Array.<string|Assert>} Test | ||
* @typedef {(file: VFile, stats: fs.Stats) => number|boolean|void} Assert | ||
* @typedef {{checked: string[], test: Assert, broken?: boolean}} State | ||
* @typedef {import('./lib/index.js').Assert} Assert | ||
* @typedef {import('./lib/index.js').Callback} Callback | ||
* @typedef {import('./lib/index.js').CallbackOne} CallbackOne | ||
* @typedef {import('./lib/index.js').Test} Test | ||
*/ | ||
import fs from 'fs' | ||
import path from 'path' | ||
import {toVFile} from 'to-vfile' | ||
export const INCLUDE = 1 | ||
export const SKIP = 4 | ||
export const BREAK = 8 | ||
export const findDown = | ||
/** | ||
* @type {{ | ||
* (test: Test, paths: string|Array.<string>, callback: (error: Error|null, files: Array.<VFile>) => void): void | ||
* (test: Test, callback: (error: Error|null, files: Array.<VFile>) => void): void | ||
* (test: Test, paths?: string|Array.<string>): Promise.<Array.<VFile>> | ||
* }} | ||
*/ | ||
( | ||
/** | ||
* Find files or directories downwards. | ||
* | ||
* @param {Test} test | ||
* @param {string|Array.<string>} paths | ||
* @param {(error: Error|null, files: Array.<VFile>) => void} callback | ||
* @returns {unknown} | ||
*/ | ||
function (test, paths, callback) { | ||
return find(test, paths, callback) | ||
} | ||
) | ||
export const findDownOne = | ||
/** | ||
* @type {{ | ||
* (test: Test, paths: string|Array.<string>, callback: (error: Error|null, file?: VFile) => void): void | ||
* (test: Test, callback: (error: Error|null, file?: VFile) => void): void | ||
* (test: Test, paths?: string|Array.<string>): Promise.<VFile> | ||
* }} | ||
*/ | ||
( | ||
/** | ||
* Find a file or a directory downwards. | ||
* | ||
* @param {Test} test | ||
* @param {string|Array.<string>} paths | ||
* @param {(error: Error|null, file?: VFile) => void} callback | ||
* @returns {unknown} | ||
*/ | ||
function (test, paths, callback) { | ||
return find(test, paths, callback, true) | ||
} | ||
) | ||
/** | ||
* Find applicable files. | ||
* | ||
* @param {Test} test | ||
* @param {string|Array.<string>|((error: Error|null, result?: VFile|Array.<VFile>) => void)} cwds | ||
* @param {null|undefined|((error: Error|null, result?: VFile|Array.<VFile>) => void)} cb | ||
* @param {boolean} [one] | ||
* @returns {Promise.<VFile|Array.<VFile>>} | ||
*/ | ||
function find(test, cwds, cb, one) { | ||
var state = {checked: [], test: convert(test)} | ||
/** @type {Array.<string>} */ | ||
var paths | ||
/** @type {(error: Error|null, result?: VFile|Array.<VFile>) => void} */ | ||
var callback | ||
if (typeof cwds === 'string') { | ||
paths = [cwds] | ||
callback = cb | ||
} else if (Array.isArray(cwds)) { | ||
paths = cwds | ||
callback = cb | ||
} else { | ||
paths = [process.cwd()] | ||
callback = cwds | ||
} | ||
if (!callback) return new Promise(executor) | ||
executor(resolve) | ||
/** | ||
* @param {VFile|Array.<VFile>} result | ||
*/ | ||
function resolve(result) { | ||
callback(null, result) | ||
} | ||
/** | ||
* @param {(x: VFile|Array.<VFile>) => void} resolve | ||
*/ | ||
function executor(resolve) { | ||
visitAll(state, paths, null, one, done) | ||
/** | ||
* @param {Array.<VFile>} result | ||
*/ | ||
function done(result) { | ||
resolve(one ? result[0] || null : result) | ||
} | ||
} | ||
} | ||
/** | ||
* Find files in `filePath`. | ||
* | ||
* @param {State} state | ||
* @param {string} filePath | ||
* @param {boolean} one | ||
* @param {Function} done | ||
*/ | ||
function visit(state, filePath, one, done) { | ||
// Donβt walk into places multiple times. | ||
if (state.checked.includes(filePath)) { | ||
done([]) | ||
return | ||
} | ||
state.checked.push(filePath) | ||
fs.stat(path.resolve(filePath), function (_, stats) { | ||
var real = Boolean(stats) | ||
/** @type {Array.<VFile>} */ | ||
var results = [] | ||
/** @type {VFile} */ | ||
var file | ||
/** @type {number} */ | ||
var result | ||
if (state.broken || !real) { | ||
done([]) | ||
} else { | ||
file = toVFile(filePath) | ||
result = Number(state.test(file, stats)) | ||
if ((result & INCLUDE) === INCLUDE /* Include. */) { | ||
results.push(file) | ||
if (one) { | ||
state.broken = true | ||
return done(results) | ||
} | ||
} | ||
if ((result & BREAK) === BREAK /* Break. */) { | ||
state.broken = true | ||
} | ||
if ( | ||
state.broken || | ||
!stats.isDirectory() || | ||
(result & SKIP) === SKIP /* Skip. */ | ||
) { | ||
return done(results) | ||
} | ||
fs.readdir(filePath, function (_, entries) { | ||
visitAll(state, entries, filePath, one, onvisit) | ||
}) | ||
} | ||
/** | ||
* @param {Array.<VFile>} files | ||
*/ | ||
function onvisit(files) { | ||
done([...results, ...files]) | ||
} | ||
}) | ||
} | ||
/** | ||
* Find files in `paths`. | ||
* | ||
* @param {State} state | ||
* @param {Array.<string>} paths | ||
* @param {string} cwd | ||
* @param {boolean} one | ||
* @param {Function} done | ||
*/ | ||
// eslint-disable-next-line max-params | ||
function visitAll(state, paths, cwd, one, done) { | ||
var actual = -1 | ||
var expected = -1 | ||
/** @type {Array.<VFile>} */ | ||
var result = [] | ||
while (++expected < paths.length) { | ||
visit(state, path.join(cwd || '', paths[expected]), one, onvisit) | ||
} | ||
next() | ||
/** | ||
* @param {Array.<VFile>} files | ||
*/ | ||
function onvisit(files) { | ||
result.push(...files) | ||
next() | ||
} | ||
function next() { | ||
if (++actual === expected) { | ||
done(result) | ||
} | ||
} | ||
} | ||
/** | ||
* Convert `test` | ||
* | ||
* @param {Test} test | ||
* @returns {Assert} | ||
*/ | ||
function convert(test) { | ||
return typeof test === 'function' | ||
? test | ||
: typeof test === 'string' | ||
? testString(test) | ||
: multiple(test) | ||
} | ||
/** | ||
* Wrap a string given as a test. | ||
* | ||
* @param {string} test | ||
* @returns {Assert} | ||
*/ | ||
function testString(test) { | ||
return check | ||
/** | ||
* Check whether the given `file` matches the bound value. | ||
* | ||
* @type {Assert} | ||
*/ | ||
function check(file) { | ||
if (test === file.basename || test === file.extname) { | ||
return INCLUDE | ||
} | ||
if (file.basename.charAt(0) === '.' || file.basename === 'node_modules') { | ||
return SKIP | ||
} | ||
} | ||
} | ||
/** | ||
* Check multiple tests. | ||
* | ||
* @param {Array.<string|Assert>} test | ||
* @returns {Assert} | ||
*/ | ||
function multiple(test) { | ||
/** @type {Array.<Assert>} */ | ||
var tests = [] | ||
var index = -1 | ||
while (++index < test.length) { | ||
tests[index] = convert(test[index]) | ||
} | ||
return check | ||
/** @type {Assert} */ | ||
function check(file, stats) { | ||
var index = -1 | ||
/** @type {number|boolean|void} */ | ||
var result | ||
while (++index < tests.length) { | ||
result = tests[index](file, stats) | ||
if (result) { | ||
return result | ||
} | ||
} | ||
return false | ||
} | ||
} | ||
export {BREAK, INCLUDE, SKIP, findDown, findDownOne} from './lib/index.js' |
{ | ||
"name": "vfile-find-down", | ||
"version": "6.0.0", | ||
"version": "6.1.0", | ||
"description": "vfile utility to find one or more files by searching the file system downwards", | ||
@@ -33,2 +33,3 @@ "license": "MIT", | ||
"files": [ | ||
"lib/", | ||
"index.d.ts", | ||
@@ -42,19 +43,17 @@ "index.js" | ||
"devDependencies": { | ||
"@types/tape": "^4.0.0", | ||
"@types/node": "^18.0.0", | ||
"c8": "^7.0.0", | ||
"prettier": "^2.0.0", | ||
"remark-cli": "^9.0.0", | ||
"remark-preset-wooorm": "^8.0.0", | ||
"rimraf": "^3.0.0", | ||
"tape": "^5.0.0", | ||
"remark-cli": "^11.0.0", | ||
"remark-preset-wooorm": "^9.0.0", | ||
"type-coverage": "^2.0.0", | ||
"typescript": "^4.0.0", | ||
"xo": "^0.39.0" | ||
"xo": "^0.53.0" | ||
}, | ||
"scripts": { | ||
"prepack": "npm run build && npm run format", | ||
"build": "rimraf \"*.d.ts\" && tsc && type-coverage", | ||
"build": "tsc --build --clean && tsc --build && type-coverage", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
"test-api": "node test/index.js", | ||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node test/index.js", | ||
"test-api": "node --conditions development test/index.js", | ||
"test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", | ||
"test": "npm run build && npm run format && npm run test-coverage" | ||
@@ -73,4 +72,3 @@ }, | ||
"rules": { | ||
"no-var": "off", | ||
"prefer-arrow-callback": "off" | ||
"no-bitwise": "off" | ||
} | ||
@@ -77,0 +75,0 @@ }, |
233
readme.md
@@ -10,11 +10,41 @@ # vfile-find-down | ||
Find [vfile][]s by searching the file system downwards. | ||
[vfile][] utility to find files by searching the file system downwards. | ||
## Contents | ||
* [What is this?](#what-is-this) | ||
* [When should I use this?](#when-should-i-use-this) | ||
* [Install](#install) | ||
* [Use](#use) | ||
* [API](#api) | ||
* [`findDown(test[, paths][, callback])`](#finddowntest-paths-callback) | ||
* [`findDownOne(test[, paths][, callback])`](#finddownonetest-paths-callback) | ||
* [`BREAK`](#break) | ||
* [`INCLUDE`](#include) | ||
* [`SKIP`](#skip) | ||
* [`Assert`](#assert) | ||
* [`Callback`](#callback) | ||
* [`CallbackOne`](#callbackone) | ||
* [`Test`](#test) | ||
* [Types](#types) | ||
* [Compatibility](#compatibility) | ||
* [Contribute](#contribute) | ||
* [License](#license) | ||
## What is this? | ||
This utility lets you find one or many files downwards. | ||
## When should I use this? | ||
You can use this utility if you want to find files in, say, a folder. | ||
One example is all markdown files. | ||
If you instead want to find files upwards, such as config files, you can use | ||
[`vfile-find-up`][vfile-find-up]. | ||
## Install | ||
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c): | ||
Node 12+ is needed to use it and it must be `import`ed instead of `require`d. | ||
This package is [ESM only][esm]. | ||
In Node.js (version 14.14+ and 16.0+), install with [npm][]: | ||
[npm][]: | ||
```sh | ||
@@ -27,5 +57,5 @@ npm install vfile-find-down | ||
```js | ||
var findDown = require('vfile-find-down') | ||
import {findDown} from 'vfile-find-down' | ||
findDown('.md', console.log) | ||
console.log(await findDown('.md')) | ||
``` | ||
@@ -36,3 +66,3 @@ | ||
```js | ||
null [ VFile { | ||
[ VFile { | ||
data: {}, | ||
@@ -46,61 +76,152 @@ messages: [], | ||
This package exports the following identifiers: `findDown`, `findDownOne`, | ||
`INCLUDE`, `SKIP`, `BREAK`. | ||
This package exports the identifiers | ||
[`BREAK`][api-break], | ||
[`INCLUDE`][api-include], | ||
[`SKIP`][api-skip], | ||
[`findDown`][api-find-down], and | ||
[`findDownOne`][api-find-down-one]. | ||
There is no default export. | ||
### `findDown(tests[, paths][, callback])` | ||
### `findDown(test[, paths][, callback])` | ||
Search for `tests` downwards. | ||
Calls callback with either an error or an array of files passing `tests`. | ||
Note: Virtual Files are not read (their `contents` is not populated). | ||
Find files or folders downwards. | ||
##### Signatures | ||
> π **Note**: files are not read (their `value` is not populated). | ||
* `(tests: Tests, paths?: string|Array.<string>, callback: Callback): void` | ||
* `(tests: Tests, paths?: string|Array.<string>): Promise.<Array.<VFile>>` | ||
###### Signatures | ||
##### Parameters | ||
* `(test[, paths], callback) => void` | ||
* `(test[, paths]) => Promise<Array<VFile>>` | ||
###### `tests` | ||
###### Parameters | ||
Things to search for (`string|Function|Array.<Tests>`). | ||
* `test` ([`Test`][api-test]) | ||
β things to search for | ||
* `paths` (`Array<string> | string`, default: `process.cwd()`) | ||
β places to search from | ||
* `callback` ([`Callback`][api-callback], optional) | ||
β callback called when done | ||
If an array is passed in, any test must match a given file for it to be | ||
included. | ||
###### Returns | ||
If a `string` is passed in, the `basename` or `extname` of files must match it | ||
for them to be included (and hidden directories and `node_modules` will not be | ||
searched). | ||
Nothing when `callback` is given (`void`), otherwise a promise that resolves to | ||
files ([`Array<VFile>`][vfile]). | ||
Otherwise, they must be [`function`][test]. | ||
### `findDownOne(test[, paths][, callback])` | ||
###### `paths` | ||
Find the first file or folder downwards. | ||
Place(s) to searching from (`Array.<string>` or `string`, default: | ||
`process.cwd()`). | ||
> π **Note**: files are not read (their `value` is not populated). | ||
###### `callback` | ||
###### Signatures | ||
Function called with all matching files (`function cb(err[, files])`). | ||
* `(test[, paths], callback) => void` | ||
* `(test[, paths]) => Promise<VFile>` | ||
### `findDownOne(tests[, paths][, callback])` | ||
###### Parameters | ||
Like `findDown`, but either calls `callback` with the first found file or | ||
`null`, or returns a promise that resolved to a file or `null`. | ||
* `test` ([`Test`][api-test]) | ||
β things to search for | ||
* `paths` (`Array<string> | string`, default: `process.cwd()`) | ||
β places to search from | ||
* `callback` ([`CallbackOne`][api-callback-one], optional) | ||
β callback called when done | ||
### `function test(file, stats)` | ||
###### Returns | ||
Check whether a virtual file should be included. | ||
Called with a [vfile][] and a [stats][] object. | ||
Nothing when `callback` is given (`void`), otherwise a promise that resolves to | ||
a file ([`VFile | null`][vfile]). | ||
### `BREAK` | ||
Stop searching (`number`). | ||
### `INCLUDE` | ||
Include this file (`number`). | ||
### `SKIP` | ||
Skip this folder (`number`). | ||
### `Assert` | ||
Handle a file (TypeScript type). | ||
###### Parameters | ||
* `file` ([`VFile`][vfile]) | ||
β file to handle | ||
* `stats` ([`Stats`][stats]) | ||
β stats from `fs.stat` | ||
###### Returns | ||
* `true` or `INCLUDE` β Include the file in the results | ||
* `SKIP` β Do not search inside this directory | ||
* `BREAK` β Stop searching for files | ||
* anything else is ignored: files are neither included nor skipped | ||
How to handle this file (`boolean | number`, optional). | ||
Booleans are treated as `INCLUDE` (when `true`) or `SKIP` (when `false`). | ||
No result is treated as `SKIP`. | ||
The different flags can be combined by using the pipe operator: | ||
`INCLUDE | SKIP`. | ||
### `Callback` | ||
Callback called when done (TypeScript type). | ||
###### Parameters | ||
* `error` (`Error | null`) | ||
β error; errors are currently never passed | ||
* `files` ([`Array<VFile>`][vfile]) | ||
β files | ||
###### Returns | ||
Nothing (`void`). | ||
### `CallbackOne` | ||
Callback called when done finding one file (TypeScript type). | ||
###### Parameters | ||
* `error` (`Error | null`) | ||
β error; errors are currently never passed | ||
* `file` ([`VFile | null`][vfile]) | ||
β file | ||
###### Returns | ||
Nothing (`void`). | ||
### `Test` | ||
Things to search for (TypeScript type). | ||
For strings, the `basename` or `extname` of files must match them and | ||
hidden folders and `node_modules` will not be searched. | ||
For arrays, any test in them must match. | ||
###### Type | ||
```ts | ||
type Test = Array<Assert | string> | Assert | string | ||
``` | ||
## Types | ||
This package is fully typed with [TypeScript][]. | ||
It exports the additional types | ||
[`Assert`][api-assert], | ||
[`Callback`][api-callback], | ||
[`CallbackOne`][api-callback-one], and | ||
[`Test`][api-test]. | ||
## Compatibility | ||
Projects maintained by the unified collective are compatible with all maintained | ||
versions of Node.js. | ||
As of now, that is Node.js 14.14+ and 16.0+. | ||
Our projects sometimes work with older versions, but this is not guaranteed. | ||
## Contribute | ||
@@ -146,9 +267,13 @@ | ||
[contributing]: https://github.com/vfile/.github/blob/HEAD/contributing.md | ||
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c | ||
[support]: https://github.com/vfile/.github/blob/HEAD/support.md | ||
[typescript]: https://www.typescriptlang.org | ||
[contributing]: https://github.com/vfile/.github/blob/main/contributing.md | ||
[support]: https://github.com/vfile/.github/blob/main/support.md | ||
[health]: https://github.com/vfile/.github | ||
[coc]: https://github.com/vfile/.github/blob/HEAD/code-of-conduct.md | ||
[coc]: https://github.com/vfile/.github/blob/main/code-of-conduct.md | ||
@@ -161,4 +286,22 @@ [license]: license | ||
[vfile-find-up]: https://github.com/vfile/vfile-find-up | ||
[stats]: https://nodejs.org/api/fs.html#fs_class_fs_stats | ||
[test]: #function-testfile-stats | ||
[api-break]: #break | ||
[api-include]: #include | ||
[api-skip]: #skip | ||
[api-find-down]: #finddowntest-paths-callback | ||
[api-find-down-one]: #finddownonetest-paths-callback | ||
[api-assert]: #assert | ||
[api-callback]: #callback | ||
[api-callback-one]: #callbackone | ||
[api-test]: #test |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
22621
8
7
492
302
1