Updated the files.

This commit is contained in:
Batuhan Berk Başoğlu 2024-02-08 19:38:41 -05:00
parent 1553e6b971
commit 753967d4f5
23418 changed files with 3784666 additions and 0 deletions

15
my-app/node_modules/@npmcli/git/LICENSE generated vendored Executable file
View file

@ -0,0 +1,15 @@
The ISC License
Copyright (c) npm, Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE NPM DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE NPM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

158
my-app/node_modules/@npmcli/git/README.md generated vendored Executable file
View file

@ -0,0 +1,158 @@
# @npmcli/git
A utility for spawning git from npm CLI contexts.
This is _not_ an implementation of git itself, it's just a thing that
spawns child processes to tell the system git CLI implementation to do
stuff.
## USAGE
```js
const git = require('@npmcli/git')
git.clone('git://foo/bar.git', 'some-branch', 'some-path', opts) // clone a repo
.then(() => git.spawn(['checkout', 'some-branch'], {cwd: 'bar'}))
.then(() => git.spawn(['you get the idea']))
```
## API
Most methods take an options object. Options are described below.
### `git.spawn(args, opts = {})`
Launch a `git` subprocess with the arguments specified.
All the other functions call this one at some point.
Processes are launched using
[`@npmcli/promise-spawn`](http://npm.im/@npmcli/promise-spawn), with the
`stdioString: true` option enabled by default, since git output is
generally in readable string format.
Return value is a `Promise` that resolves to a result object with `{cmd,
args, code, signal, stdout, stderr}` members, or rejects with an error with
the same fields, passed back from
[`@npmcli/promise-spawn`](http://npm.im/@npmcli/promise-spawn).
### `git.clone(repo, ref = 'HEAD', target = null, opts = {})` -> `Promise<sha String>`
Clone the repository into `target` path (or the default path for the name
of the repository), checking out `ref`.
Return value is the sha of the current HEAD in the locally cloned
repository.
In lieu of a specific `ref`, you may also pass in a `spec` option, which is
a [`npm-package-arg`](http://npm.im/npm-package-arg) object for a `git`
package dependency reference. In this way, you can select SemVer tags
within a range, or any git committish value. For example:
```js
const npa = require('npm-package-arg')
git.clone('git@github.com:npm/git.git', '', null, {
spec: npa('github:npm/git#semver:1.x'),
})
// only gitRange and gitCommittish are relevant, so this works, too
git.clone('git@github.com:npm/git.git', null, null, {
spec: { gitRange: '1.x' }
})
```
This will automatically do a shallow `--depth=1` clone on any hosts that
are known to support it. To force a shallow or deep clone, you can set the
`gitShallow` option to `true` or `false` respectively.
### `git.revs(repo, opts = {})` -> `Promise<rev doc Object>`
Fetch a representation of all of the named references in a given
repository. The resulting doc is intentionally somewhat
[packument](https://www.npmjs.com/package/pacote#packuments)-like, so that
git semver ranges can be applied using the same
[`npm-pick-manifest`](http://npm.im/npm-pick-manifest) logic.
The resulting object looks like:
```js
revs = {
versions: {
// all semver-looking tags go in here...
// version: { sha, ref, rawRef, type }
'1.0.0': {
sha: '1bc5fba3353f8e1b56493b266bc459276ab23139',
ref: 'v1.0.0',
rawRef: 'refs/tags/v1.0.0',
type: 'tag',
},
},
'dist-tags': {
HEAD: '1.0.0',
latest: '1.0.0',
},
refs: {
// all the advertised refs that can be cloned down remotely
HEAD: { sha, ref, rawRef, type: 'head' },
master: { ... },
'v1.0.0': { ... },
'refs/tags/v1.0.0': { ... },
},
shas: {
// all named shas referenced above
// sha: [list, of, refs]
'6b2501f9183a1753027a9bf89a184b7d3d4602c7': [
'HEAD',
'master',
'refs/heads/master',
],
'1bc5fba3353f8e1b56493b266bc459276ab23139': [ 'v1.0.0', 'refs/tags/v1.0.0' ],
},
}
```
### `git.is(opts)` -> `Promise<Boolean>`
Resolve to `true` if the path argument refers to the root of a git
repository.
It does this by looking for a file in `${path}/.git/index`, which is not an
airtight indicator, but at least avoids being fooled by an empty directory
or a file named `.git`.
### `git.find(opts)` -> `Promise<String | null>`
Given a path, walk up the file system tree until a git repo working
directory is found. Since this calls `stat` a bunch of times, it's
probably best to only call it if you're reasonably sure you're likely to be
in a git project somewhere. Pass in `opts.root` to stop checking at that
directory.
Resolves to `null` if not in a git project.
### `git.isClean(opts = {})` -> `Promise<Boolean>`
Return true if in a git dir, and that git dir is free of changes. This
will resolve `true` if the git working dir is clean, or `false` if not, and
reject if the path is not within a git directory or some other error
occurs.
## OPTIONS
- `retry` An object to configure retry behavior for transient network
errors with exponential backoff.
- `retries`: Defaults to `opts.fetchRetries` or 2
- `factor`: Defaults to `opts.fetchRetryFactor` or 10
- `maxTimeout`: Defaults to `opts.fetchRetryMaxtimeout` or 60000
- `minTimeout`: Defaults to `opts.fetchRetryMintimeout` or 1000
- `git` Path to the `git` binary to use. Will look up the first `git` in
the `PATH` if not specified.
- `spec` The [`npm-package-arg`](http://npm.im/npm-package-arg) specifier
object for the thing being fetched (if relevant).
- `fakePlatform` set to a fake value of `process.platform` to use. (Just
for testing `win32` behavior on Unix, and vice versa.)
- `cwd` The current working dir for the git command. Particularly for
`find` and `is` and `isClean`, it's good to know that this defaults to
`process.cwd()`, as one might expect.
- Any other options that can be passed to
[`@npmcli/promise-spawn`](http://npm.im/@npmcli/promise-spawn), or
`child_process.spawn()`.

172
my-app/node_modules/@npmcli/git/lib/clone.js generated vendored Executable file
View file

@ -0,0 +1,172 @@
// The goal here is to minimize both git workload and
// the number of refs we download over the network.
//
// Every method ends up with the checked out working dir
// at the specified ref, and resolves with the git sha.
// Only certain whitelisted hosts get shallow cloning.
// Many hosts (including GHE) don't always support it.
// A failed shallow fetch takes a LOT longer than a full
// fetch in most cases, so we skip it entirely.
// Set opts.gitShallow = true/false to force this behavior
// one way or the other.
const shallowHosts = new Set([
'github.com',
'gist.github.com',
'gitlab.com',
'bitbucket.com',
'bitbucket.org',
])
// we have to use url.parse until we add the same shim that hosted-git-info has
// to handle scp:// urls
const { parse } = require('url') // eslint-disable-line node/no-deprecated-api
const path = require('path')
const getRevs = require('./revs.js')
const spawn = require('./spawn.js')
const { isWindows } = require('./utils.js')
const pickManifest = require('npm-pick-manifest')
const fs = require('fs/promises')
module.exports = (repo, ref = 'HEAD', target = null, opts = {}) =>
getRevs(repo, opts).then(revs => clone(
repo,
revs,
ref,
resolveRef(revs, ref, opts),
target || defaultTarget(repo, opts.cwd),
opts
))
const maybeShallow = (repo, opts) => {
if (opts.gitShallow === false || opts.gitShallow) {
return opts.gitShallow
}
return shallowHosts.has(parse(repo).host)
}
const defaultTarget = (repo, /* istanbul ignore next */ cwd = process.cwd()) =>
path.resolve(cwd, path.basename(repo.replace(/[/\\]?\.git$/, '')))
const clone = (repo, revs, ref, revDoc, target, opts) => {
if (!revDoc) {
return unresolved(repo, ref, target, opts)
}
if (revDoc.sha === revs.refs.HEAD.sha) {
return plain(repo, revDoc, target, opts)
}
if (revDoc.type === 'tag' || revDoc.type === 'branch') {
return branch(repo, revDoc, target, opts)
}
return other(repo, revDoc, target, opts)
}
const resolveRef = (revs, ref, opts) => {
const { spec = {} } = opts
ref = spec.gitCommittish || ref
/* istanbul ignore next - will fail anyway, can't pull */
if (!revs) {
return null
}
if (spec.gitRange) {
return pickManifest(revs, spec.gitRange, opts)
}
if (!ref) {
return revs.refs.HEAD
}
if (revs.refs[ref]) {
return revs.refs[ref]
}
if (revs.shas[ref]) {
return revs.refs[revs.shas[ref][0]]
}
return null
}
// pull request or some other kind of advertised ref
const other = (repo, revDoc, target, opts) => {
const shallow = maybeShallow(repo, opts)
const fetchOrigin = ['fetch', 'origin', revDoc.rawRef]
.concat(shallow ? ['--depth=1'] : [])
const git = (args) => spawn(args, { ...opts, cwd: target })
return fs.mkdir(target, { recursive: true })
.then(() => git(['init']))
.then(() => isWindows(opts)
? git(['config', '--local', '--add', 'core.longpaths', 'true'])
: null)
.then(() => git(['remote', 'add', 'origin', repo]))
.then(() => git(fetchOrigin))
.then(() => git(['checkout', revDoc.sha]))
.then(() => updateSubmodules(target, opts))
.then(() => revDoc.sha)
}
// tag or branches. use -b
const branch = (repo, revDoc, target, opts) => {
const args = [
'clone',
'-b',
revDoc.ref,
repo,
target,
'--recurse-submodules',
]
if (maybeShallow(repo, opts)) {
args.push('--depth=1')
}
if (isWindows(opts)) {
args.push('--config', 'core.longpaths=true')
}
return spawn(args, opts).then(() => revDoc.sha)
}
// just the head. clone it
const plain = (repo, revDoc, target, opts) => {
const args = [
'clone',
repo,
target,
'--recurse-submodules',
]
if (maybeShallow(repo, opts)) {
args.push('--depth=1')
}
if (isWindows(opts)) {
args.push('--config', 'core.longpaths=true')
}
return spawn(args, opts).then(() => revDoc.sha)
}
const updateSubmodules = async (target, opts) => {
const hasSubmodules = await fs.stat(`${target}/.gitmodules`)
.then(() => true)
.catch(() => false)
if (!hasSubmodules) {
return null
}
return spawn([
'submodule',
'update',
'-q',
'--init',
'--recursive',
], { ...opts, cwd: target })
}
const unresolved = (repo, ref, target, opts) => {
// can't do this one shallowly, because the ref isn't advertised
// but we can avoid checking out the working dir twice, at least
const lp = isWindows(opts) ? ['--config', 'core.longpaths=true'] : []
const cloneArgs = ['clone', '--mirror', '-q', repo, target + '/.git']
const git = (args) => spawn(args, { ...opts, cwd: target })
return fs.mkdir(target, { recursive: true })
.then(() => git(cloneArgs.concat(lp)))
.then(() => git(['init']))
.then(() => git(['checkout', ref]))
.then(() => updateSubmodules(target, opts))
.then(() => git(['rev-parse', '--revs-only', 'HEAD']))
.then(({ stdout }) => stdout.trim())
}

36
my-app/node_modules/@npmcli/git/lib/errors.js generated vendored Executable file
View file

@ -0,0 +1,36 @@
const maxRetry = 3
class GitError extends Error {
shouldRetry () {
return false
}
}
class GitConnectionError extends GitError {
constructor (message) {
super('A git connection error occurred')
}
shouldRetry (number) {
return number < maxRetry
}
}
class GitPathspecError extends GitError {
constructor (message) {
super('The git reference could not be found')
}
}
class GitUnknownError extends GitError {
constructor (message) {
super('An unknown git error occurred')
}
}
module.exports = {
GitConnectionError,
GitPathspecError,
GitUnknownError,
}

15
my-app/node_modules/@npmcli/git/lib/find.js generated vendored Executable file
View file

@ -0,0 +1,15 @@
const is = require('./is.js')
const { dirname } = require('path')
module.exports = async ({ cwd = process.cwd(), root } = {}) => {
while (true) {
if (await is({ cwd })) {
return cwd
}
const next = dirname(cwd)
if (cwd === root || cwd === next) {
return null
}
cwd = next
}
}

9
my-app/node_modules/@npmcli/git/lib/index.js generated vendored Executable file
View file

@ -0,0 +1,9 @@
module.exports = {
clone: require('./clone.js'),
revs: require('./revs.js'),
spawn: require('./spawn.js'),
is: require('./is.js'),
find: require('./find.js'),
isClean: require('./is-clean.js'),
errors: require('./errors.js'),
}

6
my-app/node_modules/@npmcli/git/lib/is-clean.js generated vendored Executable file
View file

@ -0,0 +1,6 @@
const spawn = require('./spawn.js')
module.exports = (opts = {}) =>
spawn(['status', '--porcelain=v1', '-uno'], opts)
.then(res => !res.stdout.trim().split(/\r?\n+/)
.map(l => l.trim()).filter(l => l).length)

6
my-app/node_modules/@npmcli/git/lib/is.js generated vendored Executable file
View file

@ -0,0 +1,6 @@
// not an airtight indicator, but a good gut-check to even bother trying
const { promisify } = require('util')
const fs = require('fs')
const stat = promisify(fs.stat)
module.exports = ({ cwd = process.cwd() } = {}) =>
stat(cwd + '/.git').then(() => true, () => false)

147
my-app/node_modules/@npmcli/git/lib/lines-to-revs.js generated vendored Executable file
View file

@ -0,0 +1,147 @@
// turn an array of lines from `git ls-remote` into a thing
// vaguely resembling a packument, where docs are a resolved ref
const semver = require('semver')
module.exports = lines => finish(lines.reduce(linesToRevsReducer, {
versions: {},
'dist-tags': {},
refs: {},
shas: {},
}))
const finish = revs => distTags(shaList(peelTags(revs)))
// We can check out shallow clones on specific SHAs if we have a ref
const shaList = revs => {
Object.keys(revs.refs).forEach(ref => {
const doc = revs.refs[ref]
if (!revs.shas[doc.sha]) {
revs.shas[doc.sha] = [ref]
} else {
revs.shas[doc.sha].push(ref)
}
})
return revs
}
// Replace any tags with their ^{} counterparts, if those exist
const peelTags = revs => {
Object.keys(revs.refs).filter(ref => ref.endsWith('^{}')).forEach(ref => {
const peeled = revs.refs[ref]
const unpeeled = revs.refs[ref.replace(/\^\{\}$/, '')]
if (unpeeled) {
unpeeled.sha = peeled.sha
delete revs.refs[ref]
}
})
return revs
}
const distTags = revs => {
// not entirely sure what situations would result in an
// ichabod repo, but best to be careful in Sleepy Hollow anyway
const HEAD = revs.refs.HEAD || /* istanbul ignore next */ {}
const versions = Object.keys(revs.versions)
versions.forEach(v => {
// simulate a dist-tags with latest pointing at the
// 'latest' branch if one exists and is a version,
// or HEAD if not.
const ver = revs.versions[v]
if (revs.refs.latest && ver.sha === revs.refs.latest.sha) {
revs['dist-tags'].latest = v
} else if (ver.sha === HEAD.sha) {
revs['dist-tags'].HEAD = v
if (!revs.refs.latest) {
revs['dist-tags'].latest = v
}
}
})
return revs
}
const refType = ref => {
if (ref.startsWith('refs/tags/')) {
return 'tag'
}
if (ref.startsWith('refs/heads/')) {
return 'branch'
}
if (ref.startsWith('refs/pull/')) {
return 'pull'
}
if (ref === 'HEAD') {
return 'head'
}
// Could be anything, ignore for now
/* istanbul ignore next */
return 'other'
}
// return the doc, or null if we should ignore it.
const lineToRevDoc = line => {
const split = line.trim().split(/\s+/, 2)
if (split.length < 2) {
return null
}
const sha = split[0].trim()
const rawRef = split[1].trim()
const type = refType(rawRef)
if (type === 'tag') {
// refs/tags/foo^{} is the 'peeled tag', ie the commit
// that is tagged by refs/tags/foo they resolve to the same
// content, just different objects in git's data structure.
// But, we care about the thing the tag POINTS to, not the tag
// object itself, so we only look at the peeled tag refs, and
// ignore the pointer.
// For now, though, we have to save both, because some tags
// don't have peels, if they were not annotated.
const ref = rawRef.slice('refs/tags/'.length)
return { sha, ref, rawRef, type }
}
if (type === 'branch') {
const ref = rawRef.slice('refs/heads/'.length)
return { sha, ref, rawRef, type }
}
if (type === 'pull') {
// NB: merged pull requests installable with #pull/123/merge
// for the merged pr, or #pull/123 for the PR head
const ref = rawRef.slice('refs/'.length).replace(/\/head$/, '')
return { sha, ref, rawRef, type }
}
if (type === 'head') {
const ref = 'HEAD'
return { sha, ref, rawRef, type }
}
// at this point, all we can do is leave the ref un-munged
return { sha, ref: rawRef, rawRef, type }
}
const linesToRevsReducer = (revs, line) => {
const doc = lineToRevDoc(line)
if (!doc) {
return revs
}
revs.refs[doc.ref] = doc
revs.refs[doc.rawRef] = doc
if (doc.type === 'tag') {
// try to pull a semver value out of tags like `release-v1.2.3`
// which is a pretty common pattern.
const match = !doc.ref.endsWith('^{}') &&
doc.ref.match(/v?(\d+\.\d+\.\d+(?:[-+].+)?)$/)
if (match && semver.valid(match[1], true)) {
revs.versions[semver.clean(match[1], true)] = doc
}
}
return revs
}

33
my-app/node_modules/@npmcli/git/lib/make-error.js generated vendored Executable file
View file

@ -0,0 +1,33 @@
const {
GitConnectionError,
GitPathspecError,
GitUnknownError,
} = require('./errors.js')
const connectionErrorRe = new RegExp([
'remote error: Internal Server Error',
'The remote end hung up unexpectedly',
'Connection timed out',
'Operation timed out',
'Failed to connect to .* Timed out',
'Connection reset by peer',
'SSL_ERROR_SYSCALL',
'The requested URL returned error: 503',
].join('|'))
const missingPathspecRe = /pathspec .* did not match any file\(s\) known to git/
function makeError (er) {
const message = er.stderr
let gitEr
if (connectionErrorRe.test(message)) {
gitEr = new GitConnectionError(message)
} else if (missingPathspecRe.test(message)) {
gitEr = new GitPathspecError(message)
} else {
gitEr = new GitUnknownError(message)
}
return Object.assign(gitEr, er)
}
module.exports = makeError

12
my-app/node_modules/@npmcli/git/lib/opts.js generated vendored Executable file
View file

@ -0,0 +1,12 @@
// Values we want to set if they're not already defined by the end user
// This defaults to accepting new ssh host key fingerprints
const gitEnv = {
GIT_ASKPASS: 'echo',
GIT_SSH_COMMAND: 'ssh -oStrictHostKeyChecking=accept-new',
}
module.exports = (opts = {}) => ({
stdioString: true,
...opts,
shell: false,
env: opts.env || { ...gitEnv, ...process.env },
})

28
my-app/node_modules/@npmcli/git/lib/revs.js generated vendored Executable file
View file

@ -0,0 +1,28 @@
const pinflight = require('promise-inflight')
const spawn = require('./spawn.js')
const { LRUCache } = require('lru-cache')
const revsCache = new LRUCache({
max: 100,
ttl: 5 * 60 * 1000,
})
const linesToRevs = require('./lines-to-revs.js')
module.exports = async (repo, opts = {}) => {
if (!opts.noGitRevCache) {
const cached = revsCache.get(repo)
if (cached) {
return cached
}
}
return pinflight(`ls-remote:${repo}`, () =>
spawn(['ls-remote', repo], opts)
.then(({ stdout }) => linesToRevs(stdout.trim().split('\n')))
.then(revs => {
revsCache.set(repo, revs)
return revs
})
)
}

44
my-app/node_modules/@npmcli/git/lib/spawn.js generated vendored Executable file
View file

@ -0,0 +1,44 @@
const spawn = require('@npmcli/promise-spawn')
const promiseRetry = require('promise-retry')
const log = require('proc-log')
const makeError = require('./make-error.js')
const makeOpts = require('./opts.js')
module.exports = (gitArgs, opts = {}) => {
const whichGit = require('./which.js')
const gitPath = whichGit(opts)
if (gitPath instanceof Error) {
return Promise.reject(gitPath)
}
// undocumented option, mostly only here for tests
const args = opts.allowReplace || gitArgs[0] === '--no-replace-objects'
? gitArgs
: ['--no-replace-objects', ...gitArgs]
let retryOpts = opts.retry
if (retryOpts === null || retryOpts === undefined) {
retryOpts = {
retries: opts.fetchRetries || 2,
factor: opts.fetchRetryFactor || 10,
maxTimeout: opts.fetchRetryMaxtimeout || 60000,
minTimeout: opts.fetchRetryMintimeout || 1000,
}
}
return promiseRetry((retryFn, number) => {
if (number !== 1) {
log.silly('git', `Retrying git command: ${
args.join(' ')} attempt # ${number}`)
}
return spawn(gitPath, args, makeOpts(opts))
.catch(er => {
const gitError = makeError(er)
if (!gitError.shouldRetry(number)) {
throw gitError
}
retryFn(gitError)
})
}, retryOpts)
}

3
my-app/node_modules/@npmcli/git/lib/utils.js generated vendored Executable file
View file

@ -0,0 +1,3 @@
const isWindows = opts => (opts.fakePlatform || process.platform) === 'win32'
exports.isWindows = isWindows

18
my-app/node_modules/@npmcli/git/lib/which.js generated vendored Executable file
View file

@ -0,0 +1,18 @@
const which = require('which')
let gitPath
try {
gitPath = which.sync('git')
} catch {
// ignore errors
}
module.exports = (opts = {}) => {
if (opts.git) {
return opts.git
}
if (!gitPath || opts.git === false) {
return Object.assign(new Error('No git binary found in $PATH'), { code: 'ENOGIT' })
}
return gitPath
}

View file

@ -0,0 +1 @@
../which/bin/which.js

15
my-app/node_modules/@npmcli/git/node_modules/isexe/LICENSE generated vendored Executable file
View file

@ -0,0 +1,15 @@
The ISC License
Copyright (c) 2016-2022 Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

74
my-app/node_modules/@npmcli/git/node_modules/isexe/README.md generated vendored Executable file
View file

@ -0,0 +1,74 @@
# isexe
Minimal module to check if a file is executable, and a normal file.
Uses `fs.stat` and tests against the `PATHEXT` environment variable on
Windows.
## USAGE
```js
import { isexe, sync } from 'isexe'
// or require() works too
// const { isexe } = require('isexe')
isexe('some-file-name').then(isExe => {
if (isExe) {
console.error('this thing can be run')
} else {
console.error('cannot be run')
}
}, (err) => {
console.error('probably file doesnt exist or something')
})
// same thing but synchronous, throws errors
isExe = sync('some-file-name')
// treat errors as just "not executable"
const isExe = await isexe('maybe-missing-file', { ignoreErrors: true })
const isExe = sync('maybe-missing-file', { ignoreErrors: true })
```
## API
### `isexe(path, [options]) => Promise<boolean>`
Check if the path is executable.
Will raise whatever errors may be raised by `fs.stat`, unless
`options.ignoreErrors` is set to true.
### `sync(path, [options]) => boolean`
Same as `isexe` but returns the value and throws any errors raised.
## Platform Specific Implementations
If for some reason you want to use the implementation for a
specific platform, you can do that.
```js
import { win32, posix } from 'isexe'
win32.isexe(...)
win32.sync(...)
// etc
// or:
import { isexe, sync } from 'isexe/posix'
```
The default exported implementation will be chosen based on
`process.platform`.
### Options
```ts
import type IsexeOptions from 'isexe'
```
* `ignoreErrors` Treat all errors as "no, this is not
executable", but don't raise them.
* `uid` Number to use as the user id on posix
* `gid` Number to use as the group id on posix
* `pathExt` List of path extensions to use instead of `PATHEXT`
environment variable on Windows.

View file

@ -0,0 +1,14 @@
import * as posix from './posix.js';
import * as win32 from './win32.js';
export * from './options.js';
export { win32, posix };
/**
* Determine whether a path is executable on the current platform.
*/
export declare const isexe: (path: string, options?: import("./options.js").IsexeOptions) => Promise<boolean>;
/**
* Synchronously determine whether a path is executable on the
* current platform.
*/
export declare const sync: (path: string, options?: import("./options.js").IsexeOptions) => boolean;
//# sourceMappingURL=index.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;AAKvB;;GAEG;AACH,eAAO,MAAM,KAAK,mFAAa,CAAA;AAC/B;;;GAGG;AACH,eAAO,MAAM,IAAI,0EAAY,CAAA"}

View file

@ -0,0 +1,46 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.sync = exports.isexe = exports.posix = exports.win32 = void 0;
const posix = __importStar(require("./posix.js"));
exports.posix = posix;
const win32 = __importStar(require("./win32.js"));
exports.win32 = win32;
__exportStar(require("./options.js"), exports);
const platform = process.env._ISEXE_TEST_PLATFORM_ || process.platform;
const impl = platform === 'win32' ? win32 : posix;
/**
* Determine whether a path is executable on the current platform.
*/
exports.isexe = impl.isexe;
/**
* Synchronously determine whether a path is executable on the
* current platform.
*/
exports.sync = impl.sync;
//# sourceMappingURL=index.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAAmC;AAGnB,sBAAK;AAFrB,kDAAmC;AAE1B,sBAAK;AADd,+CAA4B;AAG5B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,OAAO,CAAC,QAAQ,CAAA;AACtE,MAAM,IAAI,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAA;AAEjD;;GAEG;AACU,QAAA,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;AAC/B;;;GAGG;AACU,QAAA,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA","sourcesContent":["import * as posix from './posix.js'\nimport * as win32 from './win32.js'\nexport * from './options.js'\nexport { win32, posix }\n\nconst platform = process.env._ISEXE_TEST_PLATFORM_ || process.platform\nconst impl = platform === 'win32' ? win32 : posix\n\n/**\n * Determine whether a path is executable on the current platform.\n */\nexport const isexe = impl.isexe\n/**\n * Synchronously determine whether a path is executable on the\n * current platform.\n */\nexport const sync = impl.sync\n"]}

View file

@ -0,0 +1,32 @@
export interface IsexeOptions {
/**
* Ignore errors arising from attempting to get file access status
* Note that EACCES is always ignored, because that just means
* it's not executable. If this is not set, then attempting to check
* the executable-ness of a nonexistent file will raise ENOENT, for
* example.
*/
ignoreErrors?: boolean;
/**
* effective uid when checking executable mode flags on posix
* Defaults to process.getuid()
*/
uid?: number;
/**
* effective gid when checking executable mode flags on posix
* Defaults to process.getgid()
*/
gid?: number;
/**
* effective group ID list to use when checking executable mode flags
* on posix
* Defaults to process.getgroups()
*/
groups?: number[];
/**
* The ;-delimited path extension list for win32 implementation.
* Defaults to process.env.PATHEXT
*/
pathExt?: string;
}
//# sourceMappingURL=options.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/options.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IAEtB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB"}

View file

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=options.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/options.ts"],"names":[],"mappings":"","sourcesContent":["export interface IsexeOptions {\n /**\n * Ignore errors arising from attempting to get file access status\n * Note that EACCES is always ignored, because that just means\n * it's not executable. If this is not set, then attempting to check\n * the executable-ness of a nonexistent file will raise ENOENT, for\n * example.\n */\n ignoreErrors?: boolean\n\n /**\n * effective uid when checking executable mode flags on posix\n * Defaults to process.getuid()\n */\n uid?: number\n\n /**\n * effective gid when checking executable mode flags on posix\n * Defaults to process.getgid()\n */\n gid?: number\n\n /**\n * effective group ID list to use when checking executable mode flags\n * on posix\n * Defaults to process.getgroups()\n */\n groups?: number[]\n\n /**\n * The ;-delimited path extension list for win32 implementation.\n * Defaults to process.env.PATHEXT\n */\n pathExt?: string\n}\n"]}

View file

@ -0,0 +1,3 @@
{
"type": "commonjs"
}

View file

@ -0,0 +1,18 @@
/**
* This is the Posix implementation of isexe, which uses the file
* mode and uid/gid values.
*
* @module
*/
import { IsexeOptions } from './options';
/**
* Determine whether a path is executable according to the mode and
* current (or specified) user and group IDs.
*/
export declare const isexe: (path: string, options?: IsexeOptions) => Promise<boolean>;
/**
* Synchronously determine whether a path is executable according to
* the mode and current (or specified) user and group IDs.
*/
export declare const sync: (path: string, options?: IsexeOptions) => boolean;
//# sourceMappingURL=posix.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"posix.d.ts","sourceRoot":"","sources":["../../src/posix.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAExC;;;GAGG;AACH,eAAO,MAAM,KAAK,SACV,MAAM,YACH,YAAY,KACpB,QAAQ,OAAO,CASjB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI,SACT,MAAM,YACH,YAAY,KACpB,OASF,CAAA"}

View file

@ -0,0 +1,67 @@
"use strict";
/**
* This is the Posix implementation of isexe, which uses the file
* mode and uid/gid values.
*
* @module
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.sync = exports.isexe = void 0;
const fs_1 = require("fs");
const promises_1 = require("fs/promises");
/**
* Determine whether a path is executable according to the mode and
* current (or specified) user and group IDs.
*/
const isexe = async (path, options = {}) => {
const { ignoreErrors = false } = options;
try {
return checkStat(await (0, promises_1.stat)(path), options);
}
catch (e) {
const er = e;
if (ignoreErrors || er.code === 'EACCES')
return false;
throw er;
}
};
exports.isexe = isexe;
/**
* Synchronously determine whether a path is executable according to
* the mode and current (or specified) user and group IDs.
*/
const sync = (path, options = {}) => {
const { ignoreErrors = false } = options;
try {
return checkStat((0, fs_1.statSync)(path), options);
}
catch (e) {
const er = e;
if (ignoreErrors || er.code === 'EACCES')
return false;
throw er;
}
};
exports.sync = sync;
const checkStat = (stat, options) => stat.isFile() && checkMode(stat, options);
const checkMode = (stat, options) => {
const myUid = options.uid ?? process.getuid?.();
const myGroups = options.groups ?? process.getgroups?.() ?? [];
const myGid = options.gid ?? process.getgid?.() ?? myGroups[0];
if (myUid === undefined || myGid === undefined) {
throw new Error('cannot get uid or gid');
}
const groups = new Set([myGid, ...myGroups]);
const mod = stat.mode;
const uid = stat.uid;
const gid = stat.gid;
const u = parseInt('100', 8);
const g = parseInt('010', 8);
const o = parseInt('001', 8);
const ug = u | g;
return !!(mod & o ||
(mod & g && groups.has(gid)) ||
(mod & u && uid === myUid) ||
(mod & ug && myUid === 0));
};
//# sourceMappingURL=posix.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"posix.js","sourceRoot":"","sources":["../../src/posix.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,2BAAoC;AACpC,0CAAkC;AAGlC;;;GAGG;AACI,MAAM,KAAK,GAAG,KAAK,EACxB,IAAY,EACZ,UAAwB,EAAE,EACR,EAAE;IACpB,MAAM,EAAE,YAAY,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IACxC,IAAI;QACF,OAAO,SAAS,CAAC,MAAM,IAAA,eAAI,EAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAA;KAC5C;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAA0B,CAAA;QACrC,IAAI,YAAY,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QACtD,MAAM,EAAE,CAAA;KACT;AACH,CAAC,CAAA;AAZY,QAAA,KAAK,SAYjB;AAED;;;GAGG;AACI,MAAM,IAAI,GAAG,CAClB,IAAY,EACZ,UAAwB,EAAE,EACjB,EAAE;IACX,MAAM,EAAE,YAAY,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IACxC,IAAI;QACF,OAAO,SAAS,CAAC,IAAA,aAAQ,EAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAA;KAC1C;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAA0B,CAAA;QACrC,IAAI,YAAY,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QACtD,MAAM,EAAE,CAAA;KACT;AACH,CAAC,CAAA;AAZY,QAAA,IAAI,QAYhB;AAED,MAAM,SAAS,GAAG,CAAC,IAAW,EAAE,OAAqB,EAAE,EAAE,CACvD,IAAI,CAAC,MAAM,EAAE,IAAI,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AAE3C,MAAM,SAAS,GAAG,CAAC,IAAW,EAAE,OAAqB,EAAE,EAAE;IACvD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAA;IAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,CAAA;IAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAA;IAC9D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE;QAC9C,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAA;KACzC;IAED,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAA;IAE5C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAA;IACrB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAA;IACpB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAA;IAEpB,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAC5B,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAC5B,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAC5B,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAA;IAEhB,OAAO,CAAC,CAAC,CACP,GAAG,GAAG,CAAC;QACP,CAAC,GAAG,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC,GAAG,GAAG,CAAC,IAAI,GAAG,KAAK,KAAK,CAAC;QAC1B,CAAC,GAAG,GAAG,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,CAC1B,CAAA;AACH,CAAC,CAAA","sourcesContent":["/**\n * This is the Posix implementation of isexe, which uses the file\n * mode and uid/gid values.\n *\n * @module\n */\n\nimport { Stats, statSync } from 'fs'\nimport { stat } from 'fs/promises'\nimport { IsexeOptions } from './options'\n\n/**\n * Determine whether a path is executable according to the mode and\n * current (or specified) user and group IDs.\n */\nexport const isexe = async (\n path: string,\n options: IsexeOptions = {}\n): Promise<boolean> => {\n const { ignoreErrors = false } = options\n try {\n return checkStat(await stat(path), options)\n } catch (e) {\n const er = e as NodeJS.ErrnoException\n if (ignoreErrors || er.code === 'EACCES') return false\n throw er\n }\n}\n\n/**\n * Synchronously determine whether a path is executable according to\n * the mode and current (or specified) user and group IDs.\n */\nexport const sync = (\n path: string,\n options: IsexeOptions = {}\n): boolean => {\n const { ignoreErrors = false } = options\n try {\n return checkStat(statSync(path), options)\n } catch (e) {\n const er = e as NodeJS.ErrnoException\n if (ignoreErrors || er.code === 'EACCES') return false\n throw er\n }\n}\n\nconst checkStat = (stat: Stats, options: IsexeOptions) =>\n stat.isFile() && checkMode(stat, options)\n\nconst checkMode = (stat: Stats, options: IsexeOptions) => {\n const myUid = options.uid ?? process.getuid?.()\n const myGroups = options.groups ?? process.getgroups?.() ?? []\n const myGid = options.gid ?? process.getgid?.() ?? myGroups[0]\n if (myUid === undefined || myGid === undefined) {\n throw new Error('cannot get uid or gid')\n }\n\n const groups = new Set([myGid, ...myGroups])\n\n const mod = stat.mode\n const uid = stat.uid\n const gid = stat.gid\n\n const u = parseInt('100', 8)\n const g = parseInt('010', 8)\n const o = parseInt('001', 8)\n const ug = u | g\n\n return !!(\n mod & o ||\n (mod & g && groups.has(gid)) ||\n (mod & u && uid === myUid) ||\n (mod & ug && myUid === 0)\n )\n}\n"]}

View file

@ -0,0 +1,18 @@
/**
* This is the Windows implementation of isexe, which uses the file
* extension and PATHEXT setting.
*
* @module
*/
import { IsexeOptions } from './options';
/**
* Determine whether a path is executable based on the file extension
* and PATHEXT environment variable (or specified pathExt option)
*/
export declare const isexe: (path: string, options?: IsexeOptions) => Promise<boolean>;
/**
* Synchronously determine whether a path is executable based on the file
* extension and PATHEXT environment variable (or specified pathExt option)
*/
export declare const sync: (path: string, options?: IsexeOptions) => boolean;
//# sourceMappingURL=win32.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"win32.d.ts","sourceRoot":"","sources":["../../src/win32.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAExC;;;GAGG;AACH,eAAO,MAAM,KAAK,SACV,MAAM,YACH,YAAY,KACpB,QAAQ,OAAO,CASjB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI,SACT,MAAM,YACH,YAAY,KACpB,OASF,CAAA"}

View file

@ -0,0 +1,62 @@
"use strict";
/**
* This is the Windows implementation of isexe, which uses the file
* extension and PATHEXT setting.
*
* @module
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.sync = exports.isexe = void 0;
const fs_1 = require("fs");
const promises_1 = require("fs/promises");
/**
* Determine whether a path is executable based on the file extension
* and PATHEXT environment variable (or specified pathExt option)
*/
const isexe = async (path, options = {}) => {
const { ignoreErrors = false } = options;
try {
return checkStat(await (0, promises_1.stat)(path), path, options);
}
catch (e) {
const er = e;
if (ignoreErrors || er.code === 'EACCES')
return false;
throw er;
}
};
exports.isexe = isexe;
/**
* Synchronously determine whether a path is executable based on the file
* extension and PATHEXT environment variable (or specified pathExt option)
*/
const sync = (path, options = {}) => {
const { ignoreErrors = false } = options;
try {
return checkStat((0, fs_1.statSync)(path), path, options);
}
catch (e) {
const er = e;
if (ignoreErrors || er.code === 'EACCES')
return false;
throw er;
}
};
exports.sync = sync;
const checkPathExt = (path, options) => {
const { pathExt = process.env.PATHEXT || '' } = options;
const peSplit = pathExt.split(';');
if (peSplit.indexOf('') !== -1) {
return true;
}
for (let i = 0; i < peSplit.length; i++) {
const p = peSplit[i].toLowerCase();
const ext = path.substring(path.length - p.length).toLowerCase();
if (p && ext === p) {
return true;
}
}
return false;
};
const checkStat = (stat, path, options) => stat.isFile() && checkPathExt(path, options);
//# sourceMappingURL=win32.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"win32.js","sourceRoot":"","sources":["../../src/win32.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,2BAAoC;AACpC,0CAAkC;AAGlC;;;GAGG;AACI,MAAM,KAAK,GAAG,KAAK,EACxB,IAAY,EACZ,UAAwB,EAAE,EACR,EAAE;IACpB,MAAM,EAAE,YAAY,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IACxC,IAAI;QACF,OAAO,SAAS,CAAC,MAAM,IAAA,eAAI,EAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;KAClD;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAA0B,CAAA;QACrC,IAAI,YAAY,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QACtD,MAAM,EAAE,CAAA;KACT;AACH,CAAC,CAAA;AAZY,QAAA,KAAK,SAYjB;AAED;;;GAGG;AACI,MAAM,IAAI,GAAG,CAClB,IAAY,EACZ,UAAwB,EAAE,EACjB,EAAE;IACX,MAAM,EAAE,YAAY,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IACxC,IAAI;QACF,OAAO,SAAS,CAAC,IAAA,aAAQ,EAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;KAChD;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAA0B,CAAA;QACrC,IAAI,YAAY,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QACtD,MAAM,EAAE,CAAA;KACT;AACH,CAAC,CAAA;AAZY,QAAA,IAAI,QAYhB;AAED,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,OAAqB,EAAE,EAAE;IAC3D,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,GAAG,OAAO,CAAA;IACvD,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAClC,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE;QAC9B,OAAO,IAAI,CAAA;KACZ;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACvC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAA;QAEhE,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,EAAE;YAClB,OAAO,IAAI,CAAA;SACZ;KACF;IACD,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,CAAC,IAAW,EAAE,IAAY,EAAE,OAAqB,EAAE,EAAE,CACrE,IAAI,CAAC,MAAM,EAAE,IAAI,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA","sourcesContent":["/**\n * This is the Windows implementation of isexe, which uses the file\n * extension and PATHEXT setting.\n *\n * @module\n */\n\nimport { Stats, statSync } from 'fs'\nimport { stat } from 'fs/promises'\nimport { IsexeOptions } from './options'\n\n/**\n * Determine whether a path is executable based on the file extension\n * and PATHEXT environment variable (or specified pathExt option)\n */\nexport const isexe = async (\n path: string,\n options: IsexeOptions = {}\n): Promise<boolean> => {\n const { ignoreErrors = false } = options\n try {\n return checkStat(await stat(path), path, options)\n } catch (e) {\n const er = e as NodeJS.ErrnoException\n if (ignoreErrors || er.code === 'EACCES') return false\n throw er\n }\n}\n\n/**\n * Synchronously determine whether a path is executable based on the file\n * extension and PATHEXT environment variable (or specified pathExt option)\n */\nexport const sync = (\n path: string,\n options: IsexeOptions = {}\n): boolean => {\n const { ignoreErrors = false } = options\n try {\n return checkStat(statSync(path), path, options)\n } catch (e) {\n const er = e as NodeJS.ErrnoException\n if (ignoreErrors || er.code === 'EACCES') return false\n throw er\n }\n}\n\nconst checkPathExt = (path: string, options: IsexeOptions) => {\n const { pathExt = process.env.PATHEXT || '' } = options\n const peSplit = pathExt.split(';')\n if (peSplit.indexOf('') !== -1) {\n return true\n }\n\n for (let i = 0; i < peSplit.length; i++) {\n const p = peSplit[i].toLowerCase()\n const ext = path.substring(path.length - p.length).toLowerCase()\n\n if (p && ext === p) {\n return true\n }\n }\n return false\n}\n\nconst checkStat = (stat: Stats, path: string, options: IsexeOptions) =>\n stat.isFile() && checkPathExt(path, options)\n"]}

View file

@ -0,0 +1,14 @@
import * as posix from './posix.js';
import * as win32 from './win32.js';
export * from './options.js';
export { win32, posix };
/**
* Determine whether a path is executable on the current platform.
*/
export declare const isexe: (path: string, options?: import("./options.js").IsexeOptions) => Promise<boolean>;
/**
* Synchronously determine whether a path is executable on the
* current platform.
*/
export declare const sync: (path: string, options?: import("./options.js").IsexeOptions) => boolean;
//# sourceMappingURL=index.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;AAKvB;;GAEG;AACH,eAAO,MAAM,KAAK,mFAAa,CAAA;AAC/B;;;GAGG;AACH,eAAO,MAAM,IAAI,0EAAY,CAAA"}

View file

@ -0,0 +1,16 @@
import * as posix from './posix.js';
import * as win32 from './win32.js';
export * from './options.js';
export { win32, posix };
const platform = process.env._ISEXE_TEST_PLATFORM_ || process.platform;
const impl = platform === 'win32' ? win32 : posix;
/**
* Determine whether a path is executable on the current platform.
*/
export const isexe = impl.isexe;
/**
* Synchronously determine whether a path is executable on the
* current platform.
*/
export const sync = impl.sync;
//# sourceMappingURL=index.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,cAAc,cAAc,CAAA;AAC5B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;AAEvB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,OAAO,CAAC,QAAQ,CAAA;AACtE,MAAM,IAAI,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAA;AAEjD;;GAEG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;AAC/B;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA","sourcesContent":["import * as posix from './posix.js'\nimport * as win32 from './win32.js'\nexport * from './options.js'\nexport { win32, posix }\n\nconst platform = process.env._ISEXE_TEST_PLATFORM_ || process.platform\nconst impl = platform === 'win32' ? win32 : posix\n\n/**\n * Determine whether a path is executable on the current platform.\n */\nexport const isexe = impl.isexe\n/**\n * Synchronously determine whether a path is executable on the\n * current platform.\n */\nexport const sync = impl.sync\n"]}

View file

@ -0,0 +1,32 @@
export interface IsexeOptions {
/**
* Ignore errors arising from attempting to get file access status
* Note that EACCES is always ignored, because that just means
* it's not executable. If this is not set, then attempting to check
* the executable-ness of a nonexistent file will raise ENOENT, for
* example.
*/
ignoreErrors?: boolean;
/**
* effective uid when checking executable mode flags on posix
* Defaults to process.getuid()
*/
uid?: number;
/**
* effective gid when checking executable mode flags on posix
* Defaults to process.getgid()
*/
gid?: number;
/**
* effective group ID list to use when checking executable mode flags
* on posix
* Defaults to process.getgroups()
*/
groups?: number[];
/**
* The ;-delimited path extension list for win32 implementation.
* Defaults to process.env.PATHEXT
*/
pathExt?: string;
}
//# sourceMappingURL=options.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/options.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;IAEtB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB"}

View file

@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=options.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/options.ts"],"names":[],"mappings":"","sourcesContent":["export interface IsexeOptions {\n /**\n * Ignore errors arising from attempting to get file access status\n * Note that EACCES is always ignored, because that just means\n * it's not executable. If this is not set, then attempting to check\n * the executable-ness of a nonexistent file will raise ENOENT, for\n * example.\n */\n ignoreErrors?: boolean\n\n /**\n * effective uid when checking executable mode flags on posix\n * Defaults to process.getuid()\n */\n uid?: number\n\n /**\n * effective gid when checking executable mode flags on posix\n * Defaults to process.getgid()\n */\n gid?: number\n\n /**\n * effective group ID list to use when checking executable mode flags\n * on posix\n * Defaults to process.getgroups()\n */\n groups?: number[]\n\n /**\n * The ;-delimited path extension list for win32 implementation.\n * Defaults to process.env.PATHEXT\n */\n pathExt?: string\n}\n"]}

View file

@ -0,0 +1,3 @@
{
"type": "module"
}

View file

@ -0,0 +1,18 @@
/**
* This is the Posix implementation of isexe, which uses the file
* mode and uid/gid values.
*
* @module
*/
import { IsexeOptions } from './options';
/**
* Determine whether a path is executable according to the mode and
* current (or specified) user and group IDs.
*/
export declare const isexe: (path: string, options?: IsexeOptions) => Promise<boolean>;
/**
* Synchronously determine whether a path is executable according to
* the mode and current (or specified) user and group IDs.
*/
export declare const sync: (path: string, options?: IsexeOptions) => boolean;
//# sourceMappingURL=posix.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"posix.d.ts","sourceRoot":"","sources":["../../src/posix.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAExC;;;GAGG;AACH,eAAO,MAAM,KAAK,SACV,MAAM,YACH,YAAY,KACpB,QAAQ,OAAO,CASjB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI,SACT,MAAM,YACH,YAAY,KACpB,OASF,CAAA"}

View file

@ -0,0 +1,62 @@
/**
* This is the Posix implementation of isexe, which uses the file
* mode and uid/gid values.
*
* @module
*/
import { statSync } from 'fs';
import { stat } from 'fs/promises';
/**
* Determine whether a path is executable according to the mode and
* current (or specified) user and group IDs.
*/
export const isexe = async (path, options = {}) => {
const { ignoreErrors = false } = options;
try {
return checkStat(await stat(path), options);
}
catch (e) {
const er = e;
if (ignoreErrors || er.code === 'EACCES')
return false;
throw er;
}
};
/**
* Synchronously determine whether a path is executable according to
* the mode and current (or specified) user and group IDs.
*/
export const sync = (path, options = {}) => {
const { ignoreErrors = false } = options;
try {
return checkStat(statSync(path), options);
}
catch (e) {
const er = e;
if (ignoreErrors || er.code === 'EACCES')
return false;
throw er;
}
};
const checkStat = (stat, options) => stat.isFile() && checkMode(stat, options);
const checkMode = (stat, options) => {
const myUid = options.uid ?? process.getuid?.();
const myGroups = options.groups ?? process.getgroups?.() ?? [];
const myGid = options.gid ?? process.getgid?.() ?? myGroups[0];
if (myUid === undefined || myGid === undefined) {
throw new Error('cannot get uid or gid');
}
const groups = new Set([myGid, ...myGroups]);
const mod = stat.mode;
const uid = stat.uid;
const gid = stat.gid;
const u = parseInt('100', 8);
const g = parseInt('010', 8);
const o = parseInt('001', 8);
const ug = u | g;
return !!(mod & o ||
(mod & g && groups.has(gid)) ||
(mod & u && uid === myUid) ||
(mod & ug && myUid === 0));
};
//# sourceMappingURL=posix.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"posix.js","sourceRoot":"","sources":["../../src/posix.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAS,QAAQ,EAAE,MAAM,IAAI,CAAA;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAGlC;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,EACxB,IAAY,EACZ,UAAwB,EAAE,EACR,EAAE;IACpB,MAAM,EAAE,YAAY,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IACxC,IAAI;QACF,OAAO,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAA;KAC5C;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAA0B,CAAA;QACrC,IAAI,YAAY,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QACtD,MAAM,EAAE,CAAA;KACT;AACH,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,IAAY,EACZ,UAAwB,EAAE,EACjB,EAAE;IACX,MAAM,EAAE,YAAY,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IACxC,IAAI;QACF,OAAO,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAA;KAC1C;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAA0B,CAAA;QACrC,IAAI,YAAY,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QACtD,MAAM,EAAE,CAAA;KACT;AACH,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,CAAC,IAAW,EAAE,OAAqB,EAAE,EAAE,CACvD,IAAI,CAAC,MAAM,EAAE,IAAI,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AAE3C,MAAM,SAAS,GAAG,CAAC,IAAW,EAAE,OAAqB,EAAE,EAAE;IACvD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAA;IAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,CAAA;IAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAA;IAC9D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE;QAC9C,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAA;KACzC;IAED,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAA;IAE5C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAA;IACrB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAA;IACpB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAA;IAEpB,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAC5B,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAC5B,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAC5B,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAA;IAEhB,OAAO,CAAC,CAAC,CACP,GAAG,GAAG,CAAC;QACP,CAAC,GAAG,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC,GAAG,GAAG,CAAC,IAAI,GAAG,KAAK,KAAK,CAAC;QAC1B,CAAC,GAAG,GAAG,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,CAC1B,CAAA;AACH,CAAC,CAAA","sourcesContent":["/**\n * This is the Posix implementation of isexe, which uses the file\n * mode and uid/gid values.\n *\n * @module\n */\n\nimport { Stats, statSync } from 'fs'\nimport { stat } from 'fs/promises'\nimport { IsexeOptions } from './options'\n\n/**\n * Determine whether a path is executable according to the mode and\n * current (or specified) user and group IDs.\n */\nexport const isexe = async (\n path: string,\n options: IsexeOptions = {}\n): Promise<boolean> => {\n const { ignoreErrors = false } = options\n try {\n return checkStat(await stat(path), options)\n } catch (e) {\n const er = e as NodeJS.ErrnoException\n if (ignoreErrors || er.code === 'EACCES') return false\n throw er\n }\n}\n\n/**\n * Synchronously determine whether a path is executable according to\n * the mode and current (or specified) user and group IDs.\n */\nexport const sync = (\n path: string,\n options: IsexeOptions = {}\n): boolean => {\n const { ignoreErrors = false } = options\n try {\n return checkStat(statSync(path), options)\n } catch (e) {\n const er = e as NodeJS.ErrnoException\n if (ignoreErrors || er.code === 'EACCES') return false\n throw er\n }\n}\n\nconst checkStat = (stat: Stats, options: IsexeOptions) =>\n stat.isFile() && checkMode(stat, options)\n\nconst checkMode = (stat: Stats, options: IsexeOptions) => {\n const myUid = options.uid ?? process.getuid?.()\n const myGroups = options.groups ?? process.getgroups?.() ?? []\n const myGid = options.gid ?? process.getgid?.() ?? myGroups[0]\n if (myUid === undefined || myGid === undefined) {\n throw new Error('cannot get uid or gid')\n }\n\n const groups = new Set([myGid, ...myGroups])\n\n const mod = stat.mode\n const uid = stat.uid\n const gid = stat.gid\n\n const u = parseInt('100', 8)\n const g = parseInt('010', 8)\n const o = parseInt('001', 8)\n const ug = u | g\n\n return !!(\n mod & o ||\n (mod & g && groups.has(gid)) ||\n (mod & u && uid === myUid) ||\n (mod & ug && myUid === 0)\n )\n}\n"]}

View file

@ -0,0 +1,18 @@
/**
* This is the Windows implementation of isexe, which uses the file
* extension and PATHEXT setting.
*
* @module
*/
import { IsexeOptions } from './options';
/**
* Determine whether a path is executable based on the file extension
* and PATHEXT environment variable (or specified pathExt option)
*/
export declare const isexe: (path: string, options?: IsexeOptions) => Promise<boolean>;
/**
* Synchronously determine whether a path is executable based on the file
* extension and PATHEXT environment variable (or specified pathExt option)
*/
export declare const sync: (path: string, options?: IsexeOptions) => boolean;
//# sourceMappingURL=win32.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"win32.d.ts","sourceRoot":"","sources":["../../src/win32.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAExC;;;GAGG;AACH,eAAO,MAAM,KAAK,SACV,MAAM,YACH,YAAY,KACpB,QAAQ,OAAO,CASjB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI,SACT,MAAM,YACH,YAAY,KACpB,OASF,CAAA"}

View file

@ -0,0 +1,57 @@
/**
* This is the Windows implementation of isexe, which uses the file
* extension and PATHEXT setting.
*
* @module
*/
import { statSync } from 'fs';
import { stat } from 'fs/promises';
/**
* Determine whether a path is executable based on the file extension
* and PATHEXT environment variable (or specified pathExt option)
*/
export const isexe = async (path, options = {}) => {
const { ignoreErrors = false } = options;
try {
return checkStat(await stat(path), path, options);
}
catch (e) {
const er = e;
if (ignoreErrors || er.code === 'EACCES')
return false;
throw er;
}
};
/**
* Synchronously determine whether a path is executable based on the file
* extension and PATHEXT environment variable (or specified pathExt option)
*/
export const sync = (path, options = {}) => {
const { ignoreErrors = false } = options;
try {
return checkStat(statSync(path), path, options);
}
catch (e) {
const er = e;
if (ignoreErrors || er.code === 'EACCES')
return false;
throw er;
}
};
const checkPathExt = (path, options) => {
const { pathExt = process.env.PATHEXT || '' } = options;
const peSplit = pathExt.split(';');
if (peSplit.indexOf('') !== -1) {
return true;
}
for (let i = 0; i < peSplit.length; i++) {
const p = peSplit[i].toLowerCase();
const ext = path.substring(path.length - p.length).toLowerCase();
if (p && ext === p) {
return true;
}
}
return false;
};
const checkStat = (stat, path, options) => stat.isFile() && checkPathExt(path, options);
//# sourceMappingURL=win32.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"win32.js","sourceRoot":"","sources":["../../src/win32.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAS,QAAQ,EAAE,MAAM,IAAI,CAAA;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAGlC;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,EACxB,IAAY,EACZ,UAAwB,EAAE,EACR,EAAE;IACpB,MAAM,EAAE,YAAY,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IACxC,IAAI;QACF,OAAO,SAAS,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;KAClD;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAA0B,CAAA;QACrC,IAAI,YAAY,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QACtD,MAAM,EAAE,CAAA;KACT;AACH,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAClB,IAAY,EACZ,UAAwB,EAAE,EACjB,EAAE;IACX,MAAM,EAAE,YAAY,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IACxC,IAAI;QACF,OAAO,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;KAChD;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAA0B,CAAA;QACrC,IAAI,YAAY,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QACtD,MAAM,EAAE,CAAA;KACT;AACH,CAAC,CAAA;AAED,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,OAAqB,EAAE,EAAE;IAC3D,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,GAAG,OAAO,CAAA;IACvD,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAClC,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE;QAC9B,OAAO,IAAI,CAAA;KACZ;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACvC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAA;QAEhE,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,EAAE;YAClB,OAAO,IAAI,CAAA;SACZ;KACF;IACD,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,CAAC,IAAW,EAAE,IAAY,EAAE,OAAqB,EAAE,EAAE,CACrE,IAAI,CAAC,MAAM,EAAE,IAAI,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA","sourcesContent":["/**\n * This is the Windows implementation of isexe, which uses the file\n * extension and PATHEXT setting.\n *\n * @module\n */\n\nimport { Stats, statSync } from 'fs'\nimport { stat } from 'fs/promises'\nimport { IsexeOptions } from './options'\n\n/**\n * Determine whether a path is executable based on the file extension\n * and PATHEXT environment variable (or specified pathExt option)\n */\nexport const isexe = async (\n path: string,\n options: IsexeOptions = {}\n): Promise<boolean> => {\n const { ignoreErrors = false } = options\n try {\n return checkStat(await stat(path), path, options)\n } catch (e) {\n const er = e as NodeJS.ErrnoException\n if (ignoreErrors || er.code === 'EACCES') return false\n throw er\n }\n}\n\n/**\n * Synchronously determine whether a path is executable based on the file\n * extension and PATHEXT environment variable (or specified pathExt option)\n */\nexport const sync = (\n path: string,\n options: IsexeOptions = {}\n): boolean => {\n const { ignoreErrors = false } = options\n try {\n return checkStat(statSync(path), path, options)\n } catch (e) {\n const er = e as NodeJS.ErrnoException\n if (ignoreErrors || er.code === 'EACCES') return false\n throw er\n }\n}\n\nconst checkPathExt = (path: string, options: IsexeOptions) => {\n const { pathExt = process.env.PATHEXT || '' } = options\n const peSplit = pathExt.split(';')\n if (peSplit.indexOf('') !== -1) {\n return true\n }\n\n for (let i = 0; i < peSplit.length; i++) {\n const p = peSplit[i].toLowerCase()\n const ext = path.substring(path.length - p.length).toLowerCase()\n\n if (p && ext === p) {\n return true\n }\n }\n return false\n}\n\nconst checkStat = (stat: Stats, path: string, options: IsexeOptions) =>\n stat.isFile() && checkPathExt(path, options)\n"]}

View file

@ -0,0 +1,96 @@
{
"name": "isexe",
"version": "3.1.1",
"description": "Minimal module to check if a file is executable.",
"main": "./dist/cjs/index.js",
"module": "./dist/mjs/index.js",
"types": "./dist/cjs/index.js",
"files": [
"dist"
],
"exports": {
".": {
"import": {
"types": "./dist/mjs/index.d.ts",
"default": "./dist/mjs/index.js"
},
"require": {
"types": "./dist/cjs/index.d.ts",
"default": "./dist/cjs/index.js"
}
},
"./posix": {
"import": {
"types": "./dist/mjs/posix.d.ts",
"default": "./dist/mjs/posix.js"
},
"require": {
"types": "./dist/cjs/posix.d.ts",
"default": "./dist/cjs/posix.js"
}
},
"./win32": {
"import": {
"types": "./dist/mjs/win32.d.ts",
"default": "./dist/mjs/win32.js"
},
"require": {
"types": "./dist/cjs/win32.d.ts",
"default": "./dist/cjs/win32.js"
}
},
"./package.json": "./package.json"
},
"devDependencies": {
"@types/node": "^20.4.5",
"@types/tap": "^15.0.8",
"c8": "^8.0.1",
"mkdirp": "^0.5.1",
"prettier": "^2.8.8",
"rimraf": "^2.5.0",
"sync-content": "^1.0.2",
"tap": "^16.3.8",
"ts-node": "^10.9.1",
"typedoc": "^0.24.8",
"typescript": "^5.1.6"
},
"scripts": {
"preversion": "npm test",
"postversion": "npm publish",
"prepublishOnly": "git push origin --follow-tags",
"prepare": "tsc -p tsconfig/cjs.json && tsc -p tsconfig/esm.json && bash ./scripts/fixup.sh",
"pretest": "npm run prepare",
"presnap": "npm run prepare",
"test": "c8 tap",
"snap": "c8 tap",
"format": "prettier --write . --loglevel warn --ignore-path ../../.prettierignore --cache",
"typedoc": "typedoc --tsconfig tsconfig/esm.json ./src/*.ts"
},
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"license": "ISC",
"tap": {
"coverage": false,
"node-arg": [
"--enable-source-maps",
"--no-warnings",
"--loader",
"ts-node/esm"
],
"ts": false
},
"prettier": {
"semi": false,
"printWidth": 75,
"tabWidth": 2,
"useTabs": false,
"singleQuote": true,
"jsxSingleQuote": false,
"bracketSameLine": true,
"arrowParens": "avoid",
"endOfLine": "lf"
},
"repository": "https://github.com/isaacs/isexe",
"engines": {
"node": ">=16"
}
}

View file

@ -0,0 +1,15 @@
The ISC License
Copyright (c) 2010-2023 Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,856 @@
/**
* @module LRUCache
*/
declare const TYPE: unique symbol;
export type PosInt = number & {
[TYPE]: 'Positive Integer';
};
export type Index = number & {
[TYPE]: 'LRUCache Index';
};
export type UintArray = Uint8Array | Uint16Array | Uint32Array;
export type NumberArray = UintArray | number[];
declare class ZeroArray extends Array<number> {
constructor(size: number);
}
export type { ZeroArray };
export type { Stack };
export type StackLike = Stack | Index[];
declare class Stack {
#private;
heap: NumberArray;
length: number;
static create(max: number): StackLike;
constructor(max: number, HeapCls: {
new (n: number): NumberArray;
});
push(n: Index): void;
pop(): Index;
}
/**
* Promise representing an in-progress {@link LRUCache#fetch} call
*/
export type BackgroundFetch<V> = Promise<V | undefined> & {
__returned: BackgroundFetch<V> | undefined;
__abortController: AbortController;
__staleWhileFetching: V | undefined;
};
export type DisposeTask<K, V> = [
value: V,
key: K,
reason: LRUCache.DisposeReason
];
export declare namespace LRUCache {
/**
* An integer greater than 0, reflecting the calculated size of items
*/
type Size = number;
/**
* Integer greater than 0, representing some number of milliseconds, or the
* time at which a TTL started counting from.
*/
type Milliseconds = number;
/**
* An integer greater than 0, reflecting a number of items
*/
type Count = number;
/**
* The reason why an item was removed from the cache, passed
* to the {@link Disposer} methods.
*/
type DisposeReason = 'evict' | 'set' | 'delete';
/**
* A method called upon item removal, passed as the
* {@link OptionsBase.dispose} and/or
* {@link OptionsBase.disposeAfter} options.
*/
type Disposer<K, V> = (value: V, key: K, reason: DisposeReason) => void;
/**
* A function that returns the effective calculated size
* of an entry in the cache.
*/
type SizeCalculator<K, V> = (value: V, key: K) => Size;
/**
* Options provided to the
* {@link OptionsBase.fetchMethod} function.
*/
interface FetcherOptions<K, V, FC = unknown> {
signal: AbortSignal;
options: FetcherFetchOptions<K, V, FC>;
/**
* Object provided in the {@link FetchOptions.context} option to
* {@link LRUCache#fetch}
*/
context: FC;
}
/**
* Status object that may be passed to {@link LRUCache#fetch},
* {@link LRUCache#get}, {@link LRUCache#set}, and {@link LRUCache#has}.
*/
interface Status<V> {
/**
* The status of a set() operation.
*
* - add: the item was not found in the cache, and was added
* - update: the item was in the cache, with the same value provided
* - replace: the item was in the cache, and replaced
* - miss: the item was not added to the cache for some reason
*/
set?: 'add' | 'update' | 'replace' | 'miss';
/**
* the ttl stored for the item, or undefined if ttls are not used.
*/
ttl?: Milliseconds;
/**
* the start time for the item, or undefined if ttls are not used.
*/
start?: Milliseconds;
/**
* The timestamp used for TTL calculation
*/
now?: Milliseconds;
/**
* the remaining ttl for the item, or undefined if ttls are not used.
*/
remainingTTL?: Milliseconds;
/**
* The calculated size for the item, if sizes are used.
*/
entrySize?: Size;
/**
* The total calculated size of the cache, if sizes are used.
*/
totalCalculatedSize?: Size;
/**
* A flag indicating that the item was not stored, due to exceeding the
* {@link OptionsBase.maxEntrySize}
*/
maxEntrySizeExceeded?: true;
/**
* The old value, specified in the case of `set:'update'` or
* `set:'replace'`
*/
oldValue?: V;
/**
* The results of a {@link LRUCache#has} operation
*
* - hit: the item was found in the cache
* - stale: the item was found in the cache, but is stale
* - miss: the item was not found in the cache
*/
has?: 'hit' | 'stale' | 'miss';
/**
* The status of a {@link LRUCache#fetch} operation.
* Note that this can change as the underlying fetch() moves through
* various states.
*
* - inflight: there is another fetch() for this key which is in process
* - get: there is no fetchMethod, so {@link LRUCache#get} was called.
* - miss: the item is not in cache, and will be fetched.
* - hit: the item is in the cache, and was resolved immediately.
* - stale: the item is in the cache, but stale.
* - refresh: the item is in the cache, and not stale, but
* {@link FetchOptions.forceRefresh} was specified.
*/
fetch?: 'get' | 'inflight' | 'miss' | 'hit' | 'stale' | 'refresh';
/**
* The {@link OptionsBase.fetchMethod} was called
*/
fetchDispatched?: true;
/**
* The cached value was updated after a successful call to
* {@link OptionsBase.fetchMethod}
*/
fetchUpdated?: true;
/**
* The reason for a fetch() rejection. Either the error raised by the
* {@link OptionsBase.fetchMethod}, or the reason for an
* AbortSignal.
*/
fetchError?: Error;
/**
* The fetch received an abort signal
*/
fetchAborted?: true;
/**
* The abort signal received was ignored, and the fetch was allowed to
* continue.
*/
fetchAbortIgnored?: true;
/**
* The fetchMethod promise resolved successfully
*/
fetchResolved?: true;
/**
* The fetchMethod promise was rejected
*/
fetchRejected?: true;
/**
* The status of a {@link LRUCache#get} operation.
*
* - fetching: The item is currently being fetched. If a previous value
* is present and allowed, that will be returned.
* - stale: The item is in the cache, and is stale.
* - hit: the item is in the cache
* - miss: the item is not in the cache
*/
get?: 'stale' | 'hit' | 'miss';
/**
* A fetch or get operation returned a stale value.
*/
returnedStale?: true;
}
/**
* options which override the options set in the LRUCache constructor
* when calling {@link LRUCache#fetch}.
*
* This is the union of {@link GetOptions} and {@link SetOptions}, plus
* {@link OptionsBase.noDeleteOnFetchRejection},
* {@link OptionsBase.allowStaleOnFetchRejection},
* {@link FetchOptions.forceRefresh}, and
* {@link FetcherOptions.context}
*
* Any of these may be modified in the {@link OptionsBase.fetchMethod}
* function, but the {@link GetOptions} fields will of course have no
* effect, as the {@link LRUCache#get} call already happened by the time
* the fetchMethod is called.
*/
interface FetcherFetchOptions<K, V, FC = unknown> extends Pick<OptionsBase<K, V, FC>, 'allowStale' | 'updateAgeOnGet' | 'noDeleteOnStaleGet' | 'sizeCalculation' | 'ttl' | 'noDisposeOnSet' | 'noUpdateTTL' | 'noDeleteOnFetchRejection' | 'allowStaleOnFetchRejection' | 'ignoreFetchAbort' | 'allowStaleOnFetchAbort'> {
status?: Status<V>;
size?: Size;
}
/**
* Options that may be passed to the {@link LRUCache#fetch} method.
*/
interface FetchOptions<K, V, FC> extends FetcherFetchOptions<K, V, FC> {
/**
* Set to true to force a re-load of the existing data, even if it
* is not yet stale.
*/
forceRefresh?: boolean;
/**
* Context provided to the {@link OptionsBase.fetchMethod} as
* the {@link FetcherOptions.context} param.
*
* If the FC type is specified as unknown (the default),
* undefined or void, then this is optional. Otherwise, it will
* be required.
*/
context?: FC;
signal?: AbortSignal;
status?: Status<V>;
}
/**
* Options provided to {@link LRUCache#fetch} when the FC type is something
* other than `unknown`, `undefined`, or `void`
*/
interface FetchOptionsWithContext<K, V, FC> extends FetchOptions<K, V, FC> {
context: FC;
}
/**
* Options provided to {@link LRUCache#fetch} when the FC type is
* `undefined` or `void`
*/
interface FetchOptionsNoContext<K, V> extends FetchOptions<K, V, undefined> {
context?: undefined;
}
/**
* Options that may be passed to the {@link LRUCache#has} method.
*/
interface HasOptions<K, V, FC> extends Pick<OptionsBase<K, V, FC>, 'updateAgeOnHas'> {
status?: Status<V>;
}
/**
* Options that may be passed to the {@link LRUCache#get} method.
*/
interface GetOptions<K, V, FC> extends Pick<OptionsBase<K, V, FC>, 'allowStale' | 'updateAgeOnGet' | 'noDeleteOnStaleGet'> {
status?: Status<V>;
}
/**
* Options that may be passed to the {@link LRUCache#peek} method.
*/
interface PeekOptions<K, V, FC> extends Pick<OptionsBase<K, V, FC>, 'allowStale'> {
}
/**
* Options that may be passed to the {@link LRUCache#set} method.
*/
interface SetOptions<K, V, FC> extends Pick<OptionsBase<K, V, FC>, 'sizeCalculation' | 'ttl' | 'noDisposeOnSet' | 'noUpdateTTL'> {
/**
* If size tracking is enabled, then setting an explicit size
* in the {@link LRUCache#set} call will prevent calling the
* {@link OptionsBase.sizeCalculation} function.
*/
size?: Size;
/**
* If TTL tracking is enabled, then setting an explicit start
* time in the {@link LRUCache#set} call will override the
* default time from `performance.now()` or `Date.now()`.
*
* Note that it must be a valid value for whichever time-tracking
* method is in use.
*/
start?: Milliseconds;
status?: Status<V>;
}
/**
* The type signature for the {@link OptionsBase.fetchMethod} option.
*/
type Fetcher<K, V, FC = unknown> = (key: K, staleValue: V | undefined, options: FetcherOptions<K, V, FC>) => Promise<V | undefined | void> | V | undefined | void;
/**
* Options which may be passed to the {@link LRUCache} constructor.
*
* Most of these may be overridden in the various options that use
* them.
*
* Despite all being technically optional, the constructor requires that
* a cache is at minimum limited by one or more of {@link OptionsBase.max},
* {@link OptionsBase.ttl}, or {@link OptionsBase.maxSize}.
*
* If {@link OptionsBase.ttl} is used alone, then it is strongly advised
* (and in fact required by the type definitions here) that the cache
* also set {@link OptionsBase.ttlAutopurge}, to prevent potentially
* unbounded storage.
*/
interface OptionsBase<K, V, FC> {
/**
* The maximum number of items to store in the cache before evicting
* old entries. This is read-only on the {@link LRUCache} instance,
* and may not be overridden.
*
* If set, then storage space will be pre-allocated at construction
* time, and the cache will perform significantly faster.
*
* Note that significantly fewer items may be stored, if
* {@link OptionsBase.maxSize} and/or {@link OptionsBase.ttl} are also
* set.
*/
max?: Count;
/**
* Max time in milliseconds for items to live in cache before they are
* considered stale. Note that stale items are NOT preemptively removed
* by default, and MAY live in the cache long after they have expired.
*
* Also, as this cache is optimized for LRU/MRU operations, some of
* the staleness/TTL checks will reduce performance, as they will incur
* overhead by deleting items.
*
* Must be an integer number of ms. If set to 0, this indicates "no TTL"
*
* @default 0
*/
ttl?: Milliseconds;
/**
* Minimum amount of time in ms in which to check for staleness.
* Defaults to 1, which means that the current time is checked
* at most once per millisecond.
*
* Set to 0 to check the current time every time staleness is tested.
* (This reduces performance, and is theoretically unnecessary.)
*
* Setting this to a higher value will improve performance somewhat
* while using ttl tracking, albeit at the expense of keeping stale
* items around a bit longer than their TTLs would indicate.
*
* @default 1
*/
ttlResolution?: Milliseconds;
/**
* Preemptively remove stale items from the cache.
* Note that this may significantly degrade performance,
* especially if the cache is storing a large number of items.
* It is almost always best to just leave the stale items in
* the cache, and let them fall out as new items are added.
*
* Note that this means that {@link OptionsBase.allowStale} is a bit
* pointless, as stale items will be deleted almost as soon as they
* expire.
*
* @default false
*/
ttlAutopurge?: boolean;
/**
* Update the age of items on {@link LRUCache#get}, renewing their TTL
*
* Has no effect if {@link OptionsBase.ttl} is not set.
*
* @default false
*/
updateAgeOnGet?: boolean;
/**
* Update the age of items on {@link LRUCache#has}, renewing their TTL
*
* Has no effect if {@link OptionsBase.ttl} is not set.
*
* @default false
*/
updateAgeOnHas?: boolean;
/**
* Allow {@link LRUCache#get} and {@link LRUCache#fetch} calls to return
* stale data, if available.
*/
allowStale?: boolean;
/**
* Function that is called on items when they are dropped from the cache.
* This can be handy if you want to close file descriptors or do other
* cleanup tasks when items are no longer accessible. Called with `key,
* value`. It's called before actually removing the item from the
* internal cache, so it is *NOT* safe to re-add them.
*
* Use {@link OptionsBase.disposeAfter} if you wish to dispose items after
* they have been full removed, when it is safe to add them back to the
* cache.
*/
dispose?: Disposer<K, V>;
/**
* The same as {@link OptionsBase.dispose}, but called *after* the entry
* is completely removed and the cache is once again in a clean state.
* It is safe to add an item right back into the cache at this point.
* However, note that it is *very* easy to inadvertently create infinite
* recursion this way.
*/
disposeAfter?: Disposer<K, V>;
/**
* Set to true to suppress calling the
* {@link OptionsBase.dispose} function if the entry key is
* still accessible within the cache.
* This may be overridden by passing an options object to
* {@link LRUCache#set}.
*/
noDisposeOnSet?: boolean;
/**
* Boolean flag to tell the cache to not update the TTL when
* setting a new value for an existing key (ie, when updating a value
* rather than inserting a new value). Note that the TTL value is
* _always_ set (if provided) when adding a new entry into the cache.
*
* Has no effect if a {@link OptionsBase.ttl} is not set.
*/
noUpdateTTL?: boolean;
/**
* If you wish to track item size, you must provide a maxSize
* note that we still will only keep up to max *actual items*,
* if max is set, so size tracking may cause fewer than max items
* to be stored. At the extreme, a single item of maxSize size
* will cause everything else in the cache to be dropped when it
* is added. Use with caution!
*
* Note also that size tracking can negatively impact performance,
* though for most cases, only minimally.
*/
maxSize?: Size;
/**
* The maximum allowed size for any single item in the cache.
*
* If a larger item is passed to {@link LRUCache#set} or returned by a
* {@link OptionsBase.fetchMethod}, then it will not be stored in the
* cache.
*/
maxEntrySize?: Size;
/**
* A function that returns a number indicating the item's size.
*
* If not provided, and {@link OptionsBase.maxSize} or
* {@link OptionsBase.maxEntrySize} are set, then all
* {@link LRUCache#set} calls **must** provide an explicit
* {@link SetOptions.size} or sizeCalculation param.
*/
sizeCalculation?: SizeCalculator<K, V>;
/**
* Method that provides the implementation for {@link LRUCache#fetch}
*/
fetchMethod?: Fetcher<K, V, FC>;
/**
* Set to true to suppress the deletion of stale data when a
* {@link OptionsBase.fetchMethod} returns a rejected promise.
*/
noDeleteOnFetchRejection?: boolean;
/**
* Do not delete stale items when they are retrieved with
* {@link LRUCache#get}.
*
* Note that the `get` return value will still be `undefined`
* unless {@link OptionsBase.allowStale} is true.
*/
noDeleteOnStaleGet?: boolean;
/**
* Set to true to allow returning stale data when a
* {@link OptionsBase.fetchMethod} throws an error or returns a rejected
* promise.
*
* This differs from using {@link OptionsBase.allowStale} in that stale
* data will ONLY be returned in the case that the
* {@link LRUCache#fetch} fails, not any other times.
*/
allowStaleOnFetchRejection?: boolean;
/**
* Set to true to return a stale value from the cache when the
* `AbortSignal` passed to the {@link OptionsBase.fetchMethod} dispatches an `'abort'`
* event, whether user-triggered, or due to internal cache behavior.
*
* Unless {@link OptionsBase.ignoreFetchAbort} is also set, the underlying
* {@link OptionsBase.fetchMethod} will still be considered canceled, and
* any value it returns will be ignored and not cached.
*
* Caveat: since fetches are aborted when a new value is explicitly
* set in the cache, this can lead to fetch returning a stale value,
* since that was the fallback value _at the moment the `fetch()` was
* initiated_, even though the new updated value is now present in
* the cache.
*
* For example:
*
* ```ts
* const cache = new LRUCache<string, any>({
* ttl: 100,
* fetchMethod: async (url, oldValue, { signal }) => {
* const res = await fetch(url, { signal })
* return await res.json()
* }
* })
* cache.set('https://example.com/', { some: 'data' })
* // 100ms go by...
* const result = cache.fetch('https://example.com/')
* cache.set('https://example.com/', { other: 'thing' })
* console.log(await result) // { some: 'data' }
* console.log(cache.get('https://example.com/')) // { other: 'thing' }
* ```
*/
allowStaleOnFetchAbort?: boolean;
/**
* Set to true to ignore the `abort` event emitted by the `AbortSignal`
* object passed to {@link OptionsBase.fetchMethod}, and still cache the
* resulting resolution value, as long as it is not `undefined`.
*
* When used on its own, this means aborted {@link LRUCache#fetch} calls are not
* immediately resolved or rejected when they are aborted, and instead
* take the full time to await.
*
* When used with {@link OptionsBase.allowStaleOnFetchAbort}, aborted
* {@link LRUCache#fetch} calls will resolve immediately to their stale
* cached value or `undefined`, and will continue to process and eventually
* update the cache when they resolve, as long as the resulting value is
* not `undefined`, thus supporting a "return stale on timeout while
* refreshing" mechanism by passing `AbortSignal.timeout(n)` as the signal.
*
* **Note**: regardless of this setting, an `abort` event _is still
* emitted on the `AbortSignal` object_, so may result in invalid results
* when passed to other underlying APIs that use AbortSignals.
*
* This may be overridden in the {@link OptionsBase.fetchMethod} or the
* call to {@link LRUCache#fetch}.
*/
ignoreFetchAbort?: boolean;
}
interface OptionsMaxLimit<K, V, FC> extends OptionsBase<K, V, FC> {
max: Count;
}
interface OptionsTTLLimit<K, V, FC> extends OptionsBase<K, V, FC> {
ttl: Milliseconds;
ttlAutopurge: boolean;
}
interface OptionsSizeLimit<K, V, FC> extends OptionsBase<K, V, FC> {
maxSize: Size;
}
/**
* The valid safe options for the {@link LRUCache} constructor
*/
type Options<K, V, FC> = OptionsMaxLimit<K, V, FC> | OptionsSizeLimit<K, V, FC> | OptionsTTLLimit<K, V, FC>;
/**
* Entry objects used by {@link LRUCache#load} and {@link LRUCache#dump},
* and returned by {@link LRUCache#info}.
*/
interface Entry<V> {
value: V;
ttl?: Milliseconds;
size?: Size;
start?: Milliseconds;
}
}
/**
* Default export, the thing you're using this module to get.
*
* All properties from the options object (with the exception of
* {@link OptionsBase.max} and {@link OptionsBase.maxSize}) are added as
* normal public members. (`max` and `maxBase` are read-only getters.)
* Changing any of these will alter the defaults for subsequent method calls,
* but is otherwise safe.
*/
export declare class LRUCache<K extends {}, V extends {}, FC = unknown> implements Map<K, V> {
#private;
/**
* {@link LRUCache.OptionsBase.ttl}
*/
ttl: LRUCache.Milliseconds;
/**
* {@link LRUCache.OptionsBase.ttlResolution}
*/
ttlResolution: LRUCache.Milliseconds;
/**
* {@link LRUCache.OptionsBase.ttlAutopurge}
*/
ttlAutopurge: boolean;
/**
* {@link LRUCache.OptionsBase.updateAgeOnGet}
*/
updateAgeOnGet: boolean;
/**
* {@link LRUCache.OptionsBase.updateAgeOnHas}
*/
updateAgeOnHas: boolean;
/**
* {@link LRUCache.OptionsBase.allowStale}
*/
allowStale: boolean;
/**
* {@link LRUCache.OptionsBase.noDisposeOnSet}
*/
noDisposeOnSet: boolean;
/**
* {@link LRUCache.OptionsBase.noUpdateTTL}
*/
noUpdateTTL: boolean;
/**
* {@link LRUCache.OptionsBase.maxEntrySize}
*/
maxEntrySize: LRUCache.Size;
/**
* {@link LRUCache.OptionsBase.sizeCalculation}
*/
sizeCalculation?: LRUCache.SizeCalculator<K, V>;
/**
* {@link LRUCache.OptionsBase.noDeleteOnFetchRejection}
*/
noDeleteOnFetchRejection: boolean;
/**
* {@link LRUCache.OptionsBase.noDeleteOnStaleGet}
*/
noDeleteOnStaleGet: boolean;
/**
* {@link LRUCache.OptionsBase.allowStaleOnFetchAbort}
*/
allowStaleOnFetchAbort: boolean;
/**
* {@link LRUCache.OptionsBase.allowStaleOnFetchRejection}
*/
allowStaleOnFetchRejection: boolean;
/**
* {@link LRUCache.OptionsBase.ignoreFetchAbort}
*/
ignoreFetchAbort: boolean;
/**
* Do not call this method unless you need to inspect the
* inner workings of the cache. If anything returned by this
* object is modified in any way, strange breakage may occur.
*
* These fields are private for a reason!
*
* @internal
*/
static unsafeExposeInternals<K extends {}, V extends {}, FC extends unknown = unknown>(c: LRUCache<K, V, FC>): {
starts: ZeroArray | undefined;
ttls: ZeroArray | undefined;
sizes: ZeroArray | undefined;
keyMap: Map<K, number>;
keyList: (K | undefined)[];
valList: (V | BackgroundFetch<V> | undefined)[];
next: NumberArray;
prev: NumberArray;
readonly head: Index;
readonly tail: Index;
free: StackLike;
isBackgroundFetch: (p: any) => boolean;
backgroundFetch: (k: K, index: number | undefined, options: LRUCache.FetchOptions<K, V, FC>, context: any) => BackgroundFetch<V>;
moveToTail: (index: number) => void;
indexes: (options?: {
allowStale: boolean;
}) => Generator<Index, void, unknown>;
rindexes: (options?: {
allowStale: boolean;
}) => Generator<Index, void, unknown>;
isStale: (index: number | undefined) => boolean;
};
/**
* {@link LRUCache.OptionsBase.max} (read-only)
*/
get max(): LRUCache.Count;
/**
* {@link LRUCache.OptionsBase.maxSize} (read-only)
*/
get maxSize(): LRUCache.Count;
/**
* The total computed size of items in the cache (read-only)
*/
get calculatedSize(): LRUCache.Size;
/**
* The number of items stored in the cache (read-only)
*/
get size(): LRUCache.Count;
/**
* {@link LRUCache.OptionsBase.fetchMethod} (read-only)
*/
get fetchMethod(): LRUCache.Fetcher<K, V, FC> | undefined;
/**
* {@link LRUCache.OptionsBase.dispose} (read-only)
*/
get dispose(): LRUCache.Disposer<K, V> | undefined;
/**
* {@link LRUCache.OptionsBase.disposeAfter} (read-only)
*/
get disposeAfter(): LRUCache.Disposer<K, V> | undefined;
constructor(options: LRUCache.Options<K, V, FC> | LRUCache<K, V, FC>);
/**
* Return the remaining TTL time for a given entry key
*/
getRemainingTTL(key: K): number;
/**
* Return a generator yielding `[key, value]` pairs,
* in order from most recently used to least recently used.
*/
entries(): Generator<[K, V], void, unknown>;
/**
* Inverse order version of {@link LRUCache.entries}
*
* Return a generator yielding `[key, value]` pairs,
* in order from least recently used to most recently used.
*/
rentries(): Generator<(K | V | BackgroundFetch<V> | undefined)[], void, unknown>;
/**
* Return a generator yielding the keys in the cache,
* in order from most recently used to least recently used.
*/
keys(): Generator<K, void, unknown>;
/**
* Inverse order version of {@link LRUCache.keys}
*
* Return a generator yielding the keys in the cache,
* in order from least recently used to most recently used.
*/
rkeys(): Generator<K, void, unknown>;
/**
* Return a generator yielding the values in the cache,
* in order from most recently used to least recently used.
*/
values(): Generator<V, void, unknown>;
/**
* Inverse order version of {@link LRUCache.values}
*
* Return a generator yielding the values in the cache,
* in order from least recently used to most recently used.
*/
rvalues(): Generator<V | BackgroundFetch<V> | undefined, void, unknown>;
/**
* Iterating over the cache itself yields the same results as
* {@link LRUCache.entries}
*/
[Symbol.iterator](): Generator<[K, V], void, unknown>;
/**
* A String value that is used in the creation of the default string description of an object.
* Called by the built-in method Object.prototype.toString.
*/
[Symbol.toStringTag]: string;
/**
* Find a value for which the supplied fn method returns a truthy value,
* similar to Array.find(). fn is called as fn(value, key, cache).
*/
find(fn: (v: V, k: K, self: LRUCache<K, V, FC>) => boolean, getOptions?: LRUCache.GetOptions<K, V, FC>): V | undefined;
/**
* Call the supplied function on each item in the cache, in order from
* most recently used to least recently used. fn is called as
* fn(value, key, cache). Does not update age or recenty of use.
* Does not iterate over stale values.
*/
forEach(fn: (v: V, k: K, self: LRUCache<K, V, FC>) => any, thisp?: any): void;
/**
* The same as {@link LRUCache.forEach} but items are iterated over in
* reverse order. (ie, less recently used items are iterated over first.)
*/
rforEach(fn: (v: V, k: K, self: LRUCache<K, V, FC>) => any, thisp?: any): void;
/**
* Delete any stale entries. Returns true if anything was removed,
* false otherwise.
*/
purgeStale(): boolean;
/**
* Get the extended info about a given entry, to get its value, size, and
* TTL info simultaneously. Like {@link LRUCache#dump}, but just for a
* single key. Always returns stale values, if their info is found in the
* cache, so be sure to check for expired TTLs if relevant.
*/
info(key: K): LRUCache.Entry<V> | undefined;
/**
* Return an array of [key, {@link LRUCache.Entry}] tuples which can be
* passed to cache.load()
*/
dump(): [K, LRUCache.Entry<V>][];
/**
* Reset the cache and load in the items in entries in the order listed.
* Note that the shape of the resulting cache may be different if the
* same options are not used in both caches.
*/
load(arr: [K, LRUCache.Entry<V>][]): void;
/**
* Add a value to the cache.
*
* Note: if `undefined` is specified as a value, this is an alias for
* {@link LRUCache#delete}
*/
set(k: K, v: V | BackgroundFetch<V> | undefined, setOptions?: LRUCache.SetOptions<K, V, FC>): this;
/**
* Evict the least recently used item, returning its value or
* `undefined` if cache is empty.
*/
pop(): V | undefined;
/**
* Check if a key is in the cache, without updating the recency of use.
* Will return false if the item is stale, even though it is technically
* in the cache.
*
* Will not update item age unless
* {@link LRUCache.OptionsBase.updateAgeOnHas} is set.
*/
has(k: K, hasOptions?: LRUCache.HasOptions<K, V, FC>): boolean;
/**
* Like {@link LRUCache#get} but doesn't update recency or delete stale
* items.
*
* Returns `undefined` if the item is stale, unless
* {@link LRUCache.OptionsBase.allowStale} is set.
*/
peek(k: K, peekOptions?: LRUCache.PeekOptions<K, V, FC>): V | undefined;
/**
* Make an asynchronous cached fetch using the
* {@link LRUCache.OptionsBase.fetchMethod} function.
*
* If multiple fetches for the same key are issued, then they will all be
* coalesced into a single call to fetchMethod.
*
* Note that this means that handling options such as
* {@link LRUCache.OptionsBase.allowStaleOnFetchAbort},
* {@link LRUCache.FetchOptions.signal},
* and {@link LRUCache.OptionsBase.allowStaleOnFetchRejection} will be
* determined by the FIRST fetch() call for a given key.
*
* This is a known (fixable) shortcoming which will be addresed on when
* someone complains about it, as the fix would involve added complexity and
* may not be worth the costs for this edge case.
*/
fetch(k: K, fetchOptions: unknown extends FC ? LRUCache.FetchOptions<K, V, FC> : FC extends undefined | void ? LRUCache.FetchOptionsNoContext<K, V> : LRUCache.FetchOptionsWithContext<K, V, FC>): Promise<undefined | V>;
fetch(k: unknown extends FC ? K : FC extends undefined | void ? K : never, fetchOptions?: unknown extends FC ? LRUCache.FetchOptions<K, V, FC> : FC extends undefined | void ? LRUCache.FetchOptionsNoContext<K, V> : never): Promise<undefined | V>;
/**
* Return a value from the cache. Will update the recency of the cache
* entry found.
*
* If the key is not found, get() will return `undefined`.
*/
get(k: K, getOptions?: LRUCache.GetOptions<K, V, FC>): V | undefined;
/**
* Deletes a key out of the cache.
* Returns true if the key was deleted, false otherwise.
*/
delete(k: K): boolean;
/**
* Clear the cache entirely, throwing away all values.
*/
clear(): void;
}
//# sourceMappingURL=index.d.ts.map

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,3 @@
{
"type": "commonjs"
}

View file

@ -0,0 +1,856 @@
/**
* @module LRUCache
*/
declare const TYPE: unique symbol;
export type PosInt = number & {
[TYPE]: 'Positive Integer';
};
export type Index = number & {
[TYPE]: 'LRUCache Index';
};
export type UintArray = Uint8Array | Uint16Array | Uint32Array;
export type NumberArray = UintArray | number[];
declare class ZeroArray extends Array<number> {
constructor(size: number);
}
export type { ZeroArray };
export type { Stack };
export type StackLike = Stack | Index[];
declare class Stack {
#private;
heap: NumberArray;
length: number;
static create(max: number): StackLike;
constructor(max: number, HeapCls: {
new (n: number): NumberArray;
});
push(n: Index): void;
pop(): Index;
}
/**
* Promise representing an in-progress {@link LRUCache#fetch} call
*/
export type BackgroundFetch<V> = Promise<V | undefined> & {
__returned: BackgroundFetch<V> | undefined;
__abortController: AbortController;
__staleWhileFetching: V | undefined;
};
export type DisposeTask<K, V> = [
value: V,
key: K,
reason: LRUCache.DisposeReason
];
export declare namespace LRUCache {
/**
* An integer greater than 0, reflecting the calculated size of items
*/
type Size = number;
/**
* Integer greater than 0, representing some number of milliseconds, or the
* time at which a TTL started counting from.
*/
type Milliseconds = number;
/**
* An integer greater than 0, reflecting a number of items
*/
type Count = number;
/**
* The reason why an item was removed from the cache, passed
* to the {@link Disposer} methods.
*/
type DisposeReason = 'evict' | 'set' | 'delete';
/**
* A method called upon item removal, passed as the
* {@link OptionsBase.dispose} and/or
* {@link OptionsBase.disposeAfter} options.
*/
type Disposer<K, V> = (value: V, key: K, reason: DisposeReason) => void;
/**
* A function that returns the effective calculated size
* of an entry in the cache.
*/
type SizeCalculator<K, V> = (value: V, key: K) => Size;
/**
* Options provided to the
* {@link OptionsBase.fetchMethod} function.
*/
interface FetcherOptions<K, V, FC = unknown> {
signal: AbortSignal;
options: FetcherFetchOptions<K, V, FC>;
/**
* Object provided in the {@link FetchOptions.context} option to
* {@link LRUCache#fetch}
*/
context: FC;
}
/**
* Status object that may be passed to {@link LRUCache#fetch},
* {@link LRUCache#get}, {@link LRUCache#set}, and {@link LRUCache#has}.
*/
interface Status<V> {
/**
* The status of a set() operation.
*
* - add: the item was not found in the cache, and was added
* - update: the item was in the cache, with the same value provided
* - replace: the item was in the cache, and replaced
* - miss: the item was not added to the cache for some reason
*/
set?: 'add' | 'update' | 'replace' | 'miss';
/**
* the ttl stored for the item, or undefined if ttls are not used.
*/
ttl?: Milliseconds;
/**
* the start time for the item, or undefined if ttls are not used.
*/
start?: Milliseconds;
/**
* The timestamp used for TTL calculation
*/
now?: Milliseconds;
/**
* the remaining ttl for the item, or undefined if ttls are not used.
*/
remainingTTL?: Milliseconds;
/**
* The calculated size for the item, if sizes are used.
*/
entrySize?: Size;
/**
* The total calculated size of the cache, if sizes are used.
*/
totalCalculatedSize?: Size;
/**
* A flag indicating that the item was not stored, due to exceeding the
* {@link OptionsBase.maxEntrySize}
*/
maxEntrySizeExceeded?: true;
/**
* The old value, specified in the case of `set:'update'` or
* `set:'replace'`
*/
oldValue?: V;
/**
* The results of a {@link LRUCache#has} operation
*
* - hit: the item was found in the cache
* - stale: the item was found in the cache, but is stale
* - miss: the item was not found in the cache
*/
has?: 'hit' | 'stale' | 'miss';
/**
* The status of a {@link LRUCache#fetch} operation.
* Note that this can change as the underlying fetch() moves through
* various states.
*
* - inflight: there is another fetch() for this key which is in process
* - get: there is no fetchMethod, so {@link LRUCache#get} was called.
* - miss: the item is not in cache, and will be fetched.
* - hit: the item is in the cache, and was resolved immediately.
* - stale: the item is in the cache, but stale.
* - refresh: the item is in the cache, and not stale, but
* {@link FetchOptions.forceRefresh} was specified.
*/
fetch?: 'get' | 'inflight' | 'miss' | 'hit' | 'stale' | 'refresh';
/**
* The {@link OptionsBase.fetchMethod} was called
*/
fetchDispatched?: true;
/**
* The cached value was updated after a successful call to
* {@link OptionsBase.fetchMethod}
*/
fetchUpdated?: true;
/**
* The reason for a fetch() rejection. Either the error raised by the
* {@link OptionsBase.fetchMethod}, or the reason for an
* AbortSignal.
*/
fetchError?: Error;
/**
* The fetch received an abort signal
*/
fetchAborted?: true;
/**
* The abort signal received was ignored, and the fetch was allowed to
* continue.
*/
fetchAbortIgnored?: true;
/**
* The fetchMethod promise resolved successfully
*/
fetchResolved?: true;
/**
* The fetchMethod promise was rejected
*/
fetchRejected?: true;
/**
* The status of a {@link LRUCache#get} operation.
*
* - fetching: The item is currently being fetched. If a previous value
* is present and allowed, that will be returned.
* - stale: The item is in the cache, and is stale.
* - hit: the item is in the cache
* - miss: the item is not in the cache
*/
get?: 'stale' | 'hit' | 'miss';
/**
* A fetch or get operation returned a stale value.
*/
returnedStale?: true;
}
/**
* options which override the options set in the LRUCache constructor
* when calling {@link LRUCache#fetch}.
*
* This is the union of {@link GetOptions} and {@link SetOptions}, plus
* {@link OptionsBase.noDeleteOnFetchRejection},
* {@link OptionsBase.allowStaleOnFetchRejection},
* {@link FetchOptions.forceRefresh}, and
* {@link FetcherOptions.context}
*
* Any of these may be modified in the {@link OptionsBase.fetchMethod}
* function, but the {@link GetOptions} fields will of course have no
* effect, as the {@link LRUCache#get} call already happened by the time
* the fetchMethod is called.
*/
interface FetcherFetchOptions<K, V, FC = unknown> extends Pick<OptionsBase<K, V, FC>, 'allowStale' | 'updateAgeOnGet' | 'noDeleteOnStaleGet' | 'sizeCalculation' | 'ttl' | 'noDisposeOnSet' | 'noUpdateTTL' | 'noDeleteOnFetchRejection' | 'allowStaleOnFetchRejection' | 'ignoreFetchAbort' | 'allowStaleOnFetchAbort'> {
status?: Status<V>;
size?: Size;
}
/**
* Options that may be passed to the {@link LRUCache#fetch} method.
*/
interface FetchOptions<K, V, FC> extends FetcherFetchOptions<K, V, FC> {
/**
* Set to true to force a re-load of the existing data, even if it
* is not yet stale.
*/
forceRefresh?: boolean;
/**
* Context provided to the {@link OptionsBase.fetchMethod} as
* the {@link FetcherOptions.context} param.
*
* If the FC type is specified as unknown (the default),
* undefined or void, then this is optional. Otherwise, it will
* be required.
*/
context?: FC;
signal?: AbortSignal;
status?: Status<V>;
}
/**
* Options provided to {@link LRUCache#fetch} when the FC type is something
* other than `unknown`, `undefined`, or `void`
*/
interface FetchOptionsWithContext<K, V, FC> extends FetchOptions<K, V, FC> {
context: FC;
}
/**
* Options provided to {@link LRUCache#fetch} when the FC type is
* `undefined` or `void`
*/
interface FetchOptionsNoContext<K, V> extends FetchOptions<K, V, undefined> {
context?: undefined;
}
/**
* Options that may be passed to the {@link LRUCache#has} method.
*/
interface HasOptions<K, V, FC> extends Pick<OptionsBase<K, V, FC>, 'updateAgeOnHas'> {
status?: Status<V>;
}
/**
* Options that may be passed to the {@link LRUCache#get} method.
*/
interface GetOptions<K, V, FC> extends Pick<OptionsBase<K, V, FC>, 'allowStale' | 'updateAgeOnGet' | 'noDeleteOnStaleGet'> {
status?: Status<V>;
}
/**
* Options that may be passed to the {@link LRUCache#peek} method.
*/
interface PeekOptions<K, V, FC> extends Pick<OptionsBase<K, V, FC>, 'allowStale'> {
}
/**
* Options that may be passed to the {@link LRUCache#set} method.
*/
interface SetOptions<K, V, FC> extends Pick<OptionsBase<K, V, FC>, 'sizeCalculation' | 'ttl' | 'noDisposeOnSet' | 'noUpdateTTL'> {
/**
* If size tracking is enabled, then setting an explicit size
* in the {@link LRUCache#set} call will prevent calling the
* {@link OptionsBase.sizeCalculation} function.
*/
size?: Size;
/**
* If TTL tracking is enabled, then setting an explicit start
* time in the {@link LRUCache#set} call will override the
* default time from `performance.now()` or `Date.now()`.
*
* Note that it must be a valid value for whichever time-tracking
* method is in use.
*/
start?: Milliseconds;
status?: Status<V>;
}
/**
* The type signature for the {@link OptionsBase.fetchMethod} option.
*/
type Fetcher<K, V, FC = unknown> = (key: K, staleValue: V | undefined, options: FetcherOptions<K, V, FC>) => Promise<V | undefined | void> | V | undefined | void;
/**
* Options which may be passed to the {@link LRUCache} constructor.
*
* Most of these may be overridden in the various options that use
* them.
*
* Despite all being technically optional, the constructor requires that
* a cache is at minimum limited by one or more of {@link OptionsBase.max},
* {@link OptionsBase.ttl}, or {@link OptionsBase.maxSize}.
*
* If {@link OptionsBase.ttl} is used alone, then it is strongly advised
* (and in fact required by the type definitions here) that the cache
* also set {@link OptionsBase.ttlAutopurge}, to prevent potentially
* unbounded storage.
*/
interface OptionsBase<K, V, FC> {
/**
* The maximum number of items to store in the cache before evicting
* old entries. This is read-only on the {@link LRUCache} instance,
* and may not be overridden.
*
* If set, then storage space will be pre-allocated at construction
* time, and the cache will perform significantly faster.
*
* Note that significantly fewer items may be stored, if
* {@link OptionsBase.maxSize} and/or {@link OptionsBase.ttl} are also
* set.
*/
max?: Count;
/**
* Max time in milliseconds for items to live in cache before they are
* considered stale. Note that stale items are NOT preemptively removed
* by default, and MAY live in the cache long after they have expired.
*
* Also, as this cache is optimized for LRU/MRU operations, some of
* the staleness/TTL checks will reduce performance, as they will incur
* overhead by deleting items.
*
* Must be an integer number of ms. If set to 0, this indicates "no TTL"
*
* @default 0
*/
ttl?: Milliseconds;
/**
* Minimum amount of time in ms in which to check for staleness.
* Defaults to 1, which means that the current time is checked
* at most once per millisecond.
*
* Set to 0 to check the current time every time staleness is tested.
* (This reduces performance, and is theoretically unnecessary.)
*
* Setting this to a higher value will improve performance somewhat
* while using ttl tracking, albeit at the expense of keeping stale
* items around a bit longer than their TTLs would indicate.
*
* @default 1
*/
ttlResolution?: Milliseconds;
/**
* Preemptively remove stale items from the cache.
* Note that this may significantly degrade performance,
* especially if the cache is storing a large number of items.
* It is almost always best to just leave the stale items in
* the cache, and let them fall out as new items are added.
*
* Note that this means that {@link OptionsBase.allowStale} is a bit
* pointless, as stale items will be deleted almost as soon as they
* expire.
*
* @default false
*/
ttlAutopurge?: boolean;
/**
* Update the age of items on {@link LRUCache#get}, renewing their TTL
*
* Has no effect if {@link OptionsBase.ttl} is not set.
*
* @default false
*/
updateAgeOnGet?: boolean;
/**
* Update the age of items on {@link LRUCache#has}, renewing their TTL
*
* Has no effect if {@link OptionsBase.ttl} is not set.
*
* @default false
*/
updateAgeOnHas?: boolean;
/**
* Allow {@link LRUCache#get} and {@link LRUCache#fetch} calls to return
* stale data, if available.
*/
allowStale?: boolean;
/**
* Function that is called on items when they are dropped from the cache.
* This can be handy if you want to close file descriptors or do other
* cleanup tasks when items are no longer accessible. Called with `key,
* value`. It's called before actually removing the item from the
* internal cache, so it is *NOT* safe to re-add them.
*
* Use {@link OptionsBase.disposeAfter} if you wish to dispose items after
* they have been full removed, when it is safe to add them back to the
* cache.
*/
dispose?: Disposer<K, V>;
/**
* The same as {@link OptionsBase.dispose}, but called *after* the entry
* is completely removed and the cache is once again in a clean state.
* It is safe to add an item right back into the cache at this point.
* However, note that it is *very* easy to inadvertently create infinite
* recursion this way.
*/
disposeAfter?: Disposer<K, V>;
/**
* Set to true to suppress calling the
* {@link OptionsBase.dispose} function if the entry key is
* still accessible within the cache.
* This may be overridden by passing an options object to
* {@link LRUCache#set}.
*/
noDisposeOnSet?: boolean;
/**
* Boolean flag to tell the cache to not update the TTL when
* setting a new value for an existing key (ie, when updating a value
* rather than inserting a new value). Note that the TTL value is
* _always_ set (if provided) when adding a new entry into the cache.
*
* Has no effect if a {@link OptionsBase.ttl} is not set.
*/
noUpdateTTL?: boolean;
/**
* If you wish to track item size, you must provide a maxSize
* note that we still will only keep up to max *actual items*,
* if max is set, so size tracking may cause fewer than max items
* to be stored. At the extreme, a single item of maxSize size
* will cause everything else in the cache to be dropped when it
* is added. Use with caution!
*
* Note also that size tracking can negatively impact performance,
* though for most cases, only minimally.
*/
maxSize?: Size;
/**
* The maximum allowed size for any single item in the cache.
*
* If a larger item is passed to {@link LRUCache#set} or returned by a
* {@link OptionsBase.fetchMethod}, then it will not be stored in the
* cache.
*/
maxEntrySize?: Size;
/**
* A function that returns a number indicating the item's size.
*
* If not provided, and {@link OptionsBase.maxSize} or
* {@link OptionsBase.maxEntrySize} are set, then all
* {@link LRUCache#set} calls **must** provide an explicit
* {@link SetOptions.size} or sizeCalculation param.
*/
sizeCalculation?: SizeCalculator<K, V>;
/**
* Method that provides the implementation for {@link LRUCache#fetch}
*/
fetchMethod?: Fetcher<K, V, FC>;
/**
* Set to true to suppress the deletion of stale data when a
* {@link OptionsBase.fetchMethod} returns a rejected promise.
*/
noDeleteOnFetchRejection?: boolean;
/**
* Do not delete stale items when they are retrieved with
* {@link LRUCache#get}.
*
* Note that the `get` return value will still be `undefined`
* unless {@link OptionsBase.allowStale} is true.
*/
noDeleteOnStaleGet?: boolean;
/**
* Set to true to allow returning stale data when a
* {@link OptionsBase.fetchMethod} throws an error or returns a rejected
* promise.
*
* This differs from using {@link OptionsBase.allowStale} in that stale
* data will ONLY be returned in the case that the
* {@link LRUCache#fetch} fails, not any other times.
*/
allowStaleOnFetchRejection?: boolean;
/**
* Set to true to return a stale value from the cache when the
* `AbortSignal` passed to the {@link OptionsBase.fetchMethod} dispatches an `'abort'`
* event, whether user-triggered, or due to internal cache behavior.
*
* Unless {@link OptionsBase.ignoreFetchAbort} is also set, the underlying
* {@link OptionsBase.fetchMethod} will still be considered canceled, and
* any value it returns will be ignored and not cached.
*
* Caveat: since fetches are aborted when a new value is explicitly
* set in the cache, this can lead to fetch returning a stale value,
* since that was the fallback value _at the moment the `fetch()` was
* initiated_, even though the new updated value is now present in
* the cache.
*
* For example:
*
* ```ts
* const cache = new LRUCache<string, any>({
* ttl: 100,
* fetchMethod: async (url, oldValue, { signal }) => {
* const res = await fetch(url, { signal })
* return await res.json()
* }
* })
* cache.set('https://example.com/', { some: 'data' })
* // 100ms go by...
* const result = cache.fetch('https://example.com/')
* cache.set('https://example.com/', { other: 'thing' })
* console.log(await result) // { some: 'data' }
* console.log(cache.get('https://example.com/')) // { other: 'thing' }
* ```
*/
allowStaleOnFetchAbort?: boolean;
/**
* Set to true to ignore the `abort` event emitted by the `AbortSignal`
* object passed to {@link OptionsBase.fetchMethod}, and still cache the
* resulting resolution value, as long as it is not `undefined`.
*
* When used on its own, this means aborted {@link LRUCache#fetch} calls are not
* immediately resolved or rejected when they are aborted, and instead
* take the full time to await.
*
* When used with {@link OptionsBase.allowStaleOnFetchAbort}, aborted
* {@link LRUCache#fetch} calls will resolve immediately to their stale
* cached value or `undefined`, and will continue to process and eventually
* update the cache when they resolve, as long as the resulting value is
* not `undefined`, thus supporting a "return stale on timeout while
* refreshing" mechanism by passing `AbortSignal.timeout(n)` as the signal.
*
* **Note**: regardless of this setting, an `abort` event _is still
* emitted on the `AbortSignal` object_, so may result in invalid results
* when passed to other underlying APIs that use AbortSignals.
*
* This may be overridden in the {@link OptionsBase.fetchMethod} or the
* call to {@link LRUCache#fetch}.
*/
ignoreFetchAbort?: boolean;
}
interface OptionsMaxLimit<K, V, FC> extends OptionsBase<K, V, FC> {
max: Count;
}
interface OptionsTTLLimit<K, V, FC> extends OptionsBase<K, V, FC> {
ttl: Milliseconds;
ttlAutopurge: boolean;
}
interface OptionsSizeLimit<K, V, FC> extends OptionsBase<K, V, FC> {
maxSize: Size;
}
/**
* The valid safe options for the {@link LRUCache} constructor
*/
type Options<K, V, FC> = OptionsMaxLimit<K, V, FC> | OptionsSizeLimit<K, V, FC> | OptionsTTLLimit<K, V, FC>;
/**
* Entry objects used by {@link LRUCache#load} and {@link LRUCache#dump},
* and returned by {@link LRUCache#info}.
*/
interface Entry<V> {
value: V;
ttl?: Milliseconds;
size?: Size;
start?: Milliseconds;
}
}
/**
* Default export, the thing you're using this module to get.
*
* All properties from the options object (with the exception of
* {@link OptionsBase.max} and {@link OptionsBase.maxSize}) are added as
* normal public members. (`max` and `maxBase` are read-only getters.)
* Changing any of these will alter the defaults for subsequent method calls,
* but is otherwise safe.
*/
export declare class LRUCache<K extends {}, V extends {}, FC = unknown> implements Map<K, V> {
#private;
/**
* {@link LRUCache.OptionsBase.ttl}
*/
ttl: LRUCache.Milliseconds;
/**
* {@link LRUCache.OptionsBase.ttlResolution}
*/
ttlResolution: LRUCache.Milliseconds;
/**
* {@link LRUCache.OptionsBase.ttlAutopurge}
*/
ttlAutopurge: boolean;
/**
* {@link LRUCache.OptionsBase.updateAgeOnGet}
*/
updateAgeOnGet: boolean;
/**
* {@link LRUCache.OptionsBase.updateAgeOnHas}
*/
updateAgeOnHas: boolean;
/**
* {@link LRUCache.OptionsBase.allowStale}
*/
allowStale: boolean;
/**
* {@link LRUCache.OptionsBase.noDisposeOnSet}
*/
noDisposeOnSet: boolean;
/**
* {@link LRUCache.OptionsBase.noUpdateTTL}
*/
noUpdateTTL: boolean;
/**
* {@link LRUCache.OptionsBase.maxEntrySize}
*/
maxEntrySize: LRUCache.Size;
/**
* {@link LRUCache.OptionsBase.sizeCalculation}
*/
sizeCalculation?: LRUCache.SizeCalculator<K, V>;
/**
* {@link LRUCache.OptionsBase.noDeleteOnFetchRejection}
*/
noDeleteOnFetchRejection: boolean;
/**
* {@link LRUCache.OptionsBase.noDeleteOnStaleGet}
*/
noDeleteOnStaleGet: boolean;
/**
* {@link LRUCache.OptionsBase.allowStaleOnFetchAbort}
*/
allowStaleOnFetchAbort: boolean;
/**
* {@link LRUCache.OptionsBase.allowStaleOnFetchRejection}
*/
allowStaleOnFetchRejection: boolean;
/**
* {@link LRUCache.OptionsBase.ignoreFetchAbort}
*/
ignoreFetchAbort: boolean;
/**
* Do not call this method unless you need to inspect the
* inner workings of the cache. If anything returned by this
* object is modified in any way, strange breakage may occur.
*
* These fields are private for a reason!
*
* @internal
*/
static unsafeExposeInternals<K extends {}, V extends {}, FC extends unknown = unknown>(c: LRUCache<K, V, FC>): {
starts: ZeroArray | undefined;
ttls: ZeroArray | undefined;
sizes: ZeroArray | undefined;
keyMap: Map<K, number>;
keyList: (K | undefined)[];
valList: (V | BackgroundFetch<V> | undefined)[];
next: NumberArray;
prev: NumberArray;
readonly head: Index;
readonly tail: Index;
free: StackLike;
isBackgroundFetch: (p: any) => boolean;
backgroundFetch: (k: K, index: number | undefined, options: LRUCache.FetchOptions<K, V, FC>, context: any) => BackgroundFetch<V>;
moveToTail: (index: number) => void;
indexes: (options?: {
allowStale: boolean;
}) => Generator<Index, void, unknown>;
rindexes: (options?: {
allowStale: boolean;
}) => Generator<Index, void, unknown>;
isStale: (index: number | undefined) => boolean;
};
/**
* {@link LRUCache.OptionsBase.max} (read-only)
*/
get max(): LRUCache.Count;
/**
* {@link LRUCache.OptionsBase.maxSize} (read-only)
*/
get maxSize(): LRUCache.Count;
/**
* The total computed size of items in the cache (read-only)
*/
get calculatedSize(): LRUCache.Size;
/**
* The number of items stored in the cache (read-only)
*/
get size(): LRUCache.Count;
/**
* {@link LRUCache.OptionsBase.fetchMethod} (read-only)
*/
get fetchMethod(): LRUCache.Fetcher<K, V, FC> | undefined;
/**
* {@link LRUCache.OptionsBase.dispose} (read-only)
*/
get dispose(): LRUCache.Disposer<K, V> | undefined;
/**
* {@link LRUCache.OptionsBase.disposeAfter} (read-only)
*/
get disposeAfter(): LRUCache.Disposer<K, V> | undefined;
constructor(options: LRUCache.Options<K, V, FC> | LRUCache<K, V, FC>);
/**
* Return the remaining TTL time for a given entry key
*/
getRemainingTTL(key: K): number;
/**
* Return a generator yielding `[key, value]` pairs,
* in order from most recently used to least recently used.
*/
entries(): Generator<[K, V], void, unknown>;
/**
* Inverse order version of {@link LRUCache.entries}
*
* Return a generator yielding `[key, value]` pairs,
* in order from least recently used to most recently used.
*/
rentries(): Generator<(K | V | BackgroundFetch<V> | undefined)[], void, unknown>;
/**
* Return a generator yielding the keys in the cache,
* in order from most recently used to least recently used.
*/
keys(): Generator<K, void, unknown>;
/**
* Inverse order version of {@link LRUCache.keys}
*
* Return a generator yielding the keys in the cache,
* in order from least recently used to most recently used.
*/
rkeys(): Generator<K, void, unknown>;
/**
* Return a generator yielding the values in the cache,
* in order from most recently used to least recently used.
*/
values(): Generator<V, void, unknown>;
/**
* Inverse order version of {@link LRUCache.values}
*
* Return a generator yielding the values in the cache,
* in order from least recently used to most recently used.
*/
rvalues(): Generator<V | BackgroundFetch<V> | undefined, void, unknown>;
/**
* Iterating over the cache itself yields the same results as
* {@link LRUCache.entries}
*/
[Symbol.iterator](): Generator<[K, V], void, unknown>;
/**
* A String value that is used in the creation of the default string description of an object.
* Called by the built-in method Object.prototype.toString.
*/
[Symbol.toStringTag]: string;
/**
* Find a value for which the supplied fn method returns a truthy value,
* similar to Array.find(). fn is called as fn(value, key, cache).
*/
find(fn: (v: V, k: K, self: LRUCache<K, V, FC>) => boolean, getOptions?: LRUCache.GetOptions<K, V, FC>): V | undefined;
/**
* Call the supplied function on each item in the cache, in order from
* most recently used to least recently used. fn is called as
* fn(value, key, cache). Does not update age or recenty of use.
* Does not iterate over stale values.
*/
forEach(fn: (v: V, k: K, self: LRUCache<K, V, FC>) => any, thisp?: any): void;
/**
* The same as {@link LRUCache.forEach} but items are iterated over in
* reverse order. (ie, less recently used items are iterated over first.)
*/
rforEach(fn: (v: V, k: K, self: LRUCache<K, V, FC>) => any, thisp?: any): void;
/**
* Delete any stale entries. Returns true if anything was removed,
* false otherwise.
*/
purgeStale(): boolean;
/**
* Get the extended info about a given entry, to get its value, size, and
* TTL info simultaneously. Like {@link LRUCache#dump}, but just for a
* single key. Always returns stale values, if their info is found in the
* cache, so be sure to check for expired TTLs if relevant.
*/
info(key: K): LRUCache.Entry<V> | undefined;
/**
* Return an array of [key, {@link LRUCache.Entry}] tuples which can be
* passed to cache.load()
*/
dump(): [K, LRUCache.Entry<V>][];
/**
* Reset the cache and load in the items in entries in the order listed.
* Note that the shape of the resulting cache may be different if the
* same options are not used in both caches.
*/
load(arr: [K, LRUCache.Entry<V>][]): void;
/**
* Add a value to the cache.
*
* Note: if `undefined` is specified as a value, this is an alias for
* {@link LRUCache#delete}
*/
set(k: K, v: V | BackgroundFetch<V> | undefined, setOptions?: LRUCache.SetOptions<K, V, FC>): this;
/**
* Evict the least recently used item, returning its value or
* `undefined` if cache is empty.
*/
pop(): V | undefined;
/**
* Check if a key is in the cache, without updating the recency of use.
* Will return false if the item is stale, even though it is technically
* in the cache.
*
* Will not update item age unless
* {@link LRUCache.OptionsBase.updateAgeOnHas} is set.
*/
has(k: K, hasOptions?: LRUCache.HasOptions<K, V, FC>): boolean;
/**
* Like {@link LRUCache#get} but doesn't update recency or delete stale
* items.
*
* Returns `undefined` if the item is stale, unless
* {@link LRUCache.OptionsBase.allowStale} is set.
*/
peek(k: K, peekOptions?: LRUCache.PeekOptions<K, V, FC>): V | undefined;
/**
* Make an asynchronous cached fetch using the
* {@link LRUCache.OptionsBase.fetchMethod} function.
*
* If multiple fetches for the same key are issued, then they will all be
* coalesced into a single call to fetchMethod.
*
* Note that this means that handling options such as
* {@link LRUCache.OptionsBase.allowStaleOnFetchAbort},
* {@link LRUCache.FetchOptions.signal},
* and {@link LRUCache.OptionsBase.allowStaleOnFetchRejection} will be
* determined by the FIRST fetch() call for a given key.
*
* This is a known (fixable) shortcoming which will be addresed on when
* someone complains about it, as the fix would involve added complexity and
* may not be worth the costs for this edge case.
*/
fetch(k: K, fetchOptions: unknown extends FC ? LRUCache.FetchOptions<K, V, FC> : FC extends undefined | void ? LRUCache.FetchOptionsNoContext<K, V> : LRUCache.FetchOptionsWithContext<K, V, FC>): Promise<undefined | V>;
fetch(k: unknown extends FC ? K : FC extends undefined | void ? K : never, fetchOptions?: unknown extends FC ? LRUCache.FetchOptions<K, V, FC> : FC extends undefined | void ? LRUCache.FetchOptionsNoContext<K, V> : never): Promise<undefined | V>;
/**
* Return a value from the cache. Will update the recency of the cache
* entry found.
*
* If the key is not found, get() will return `undefined`.
*/
get(k: K, getOptions?: LRUCache.GetOptions<K, V, FC>): V | undefined;
/**
* Deletes a key out of the cache.
* Returns true if the key was deleted, false otherwise.
*/
delete(k: K): boolean;
/**
* Clear the cache entirely, throwing away all values.
*/
clear(): void;
}
//# sourceMappingURL=index.d.ts.map

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,3 @@
{
"type": "module"
}

View file

@ -0,0 +1,118 @@
{
"name": "lru-cache",
"description": "A cache object that deletes the least-recently-used items.",
"version": "10.2.0",
"author": "Isaac Z. Schlueter <i@izs.me>",
"keywords": [
"mru",
"lru",
"cache"
],
"sideEffects": false,
"scripts": {
"build": "npm run prepare",
"prepare": "tshy",
"postprepare": "bash fixup.sh",
"pretest": "npm run prepare",
"presnap": "npm run prepare",
"test": "tap",
"snap": "tap",
"preversion": "npm test",
"postversion": "npm publish",
"prepublishOnly": "git push origin --follow-tags",
"format": "prettier --write .",
"typedoc": "typedoc --tsconfig ./.tshy/esm.json ./src/*.ts",
"benchmark-results-typedoc": "bash scripts/benchmark-results-typedoc.sh",
"prebenchmark": "npm run prepare",
"benchmark": "make -C benchmark",
"preprofile": "npm run prepare",
"profile": "make -C benchmark profile"
},
"main": "./dist/commonjs/index.js",
"types": "./dist/commonjs/index.d.ts",
"tshy": {
"exports": {
".": "./src/index.ts",
"./min": {
"import": {
"types": "./dist/mjs/index.d.ts",
"default": "./dist/mjs/index.min.js"
},
"require": {
"types": "./dist/commonjs/index.d.ts",
"default": "./dist/commonjs/index.min.js"
}
}
}
},
"repository": {
"type": "git",
"url": "git://github.com/isaacs/node-lru-cache.git"
},
"devDependencies": {
"@tapjs/clock": "^1.1.16",
"@types/node": "^20.2.5",
"@types/tap": "^15.0.6",
"benchmark": "^2.1.4",
"clock-mock": "^2.0.2",
"esbuild": "^0.17.11",
"eslint-config-prettier": "^8.5.0",
"marked": "^4.2.12",
"mkdirp": "^2.1.5",
"prettier": "^2.6.2",
"tap": "^18.5.7",
"tshy": "^1.8.0",
"tslib": "^2.4.0",
"typedoc": "^0.25.3",
"typescript": "^5.2.2"
},
"license": "ISC",
"files": [
"dist"
],
"engines": {
"node": "14 || >=16.14"
},
"prettier": {
"semi": false,
"printWidth": 70,
"tabWidth": 2,
"useTabs": false,
"singleQuote": true,
"jsxSingleQuote": false,
"bracketSameLine": true,
"arrowParens": "avoid",
"endOfLine": "lf"
},
"tap": {
"node-arg": [
"--expose-gc"
],
"plugin": [
"@tapjs/clock"
]
},
"exports": {
".": {
"import": {
"types": "./dist/esm/index.d.ts",
"default": "./dist/esm/index.js"
},
"require": {
"types": "./dist/commonjs/index.d.ts",
"default": "./dist/commonjs/index.js"
}
},
"./min": {
"import": {
"types": "./dist/mjs/index.d.ts",
"default": "./dist/mjs/index.min.js"
},
"require": {
"types": "./dist/commonjs/index.d.ts",
"default": "./dist/commonjs/index.min.js"
}
}
},
"type": "module"
}

15
my-app/node_modules/@npmcli/git/node_modules/which/LICENSE generated vendored Executable file
View file

@ -0,0 +1,15 @@
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

51
my-app/node_modules/@npmcli/git/node_modules/which/README.md generated vendored Executable file
View file

@ -0,0 +1,51 @@
# which
Like the unix `which` utility.
Finds the first instance of a specified executable in the PATH
environment variable. Does not cache the results, so `hash -r` is not
needed when the PATH changes.
## USAGE
```javascript
const which = require('which')
// async usage
// rejects if not found
const resolved = await which('node')
// if nothrow option is used, returns null if not found
const resolvedOrNull = await which('node', { nothrow: true })
// sync usage
// throws if not found
const resolved = which.sync('node')
// if nothrow option is used, returns null if not found
const resolvedOrNull = which.sync('node', { nothrow: true })
// Pass options to override the PATH and PATHEXT environment vars.
await which('node', { path: someOtherPath, pathExt: somePathExt })
```
## CLI USAGE
Just like the BSD `which(1)` binary but using `node-which`.
```
usage: node-which [-as] program ...
```
You can learn more about why the binary is `node-which` and not `which`
[here](https://github.com/npm/node-which/pull/67)
## OPTIONS
You may pass an options object as the second argument.
- `path`: Use instead of the `PATH` environment variable.
- `pathExt`: Use instead of the `PATHEXT` environment variable.
- `all`: Return all matches, instead of just the first one. Note that
this means the function returns an array of strings instead of a
single string.

View file

@ -0,0 +1,52 @@
#!/usr/bin/env node
const which = require('../lib')
const argv = process.argv.slice(2)
const usage = (err) => {
if (err) {
console.error(`which: ${err}`)
}
console.error('usage: which [-as] program ...')
process.exit(1)
}
if (!argv.length) {
return usage()
}
let dashdash = false
const [commands, flags] = argv.reduce((acc, arg) => {
if (dashdash || arg === '--') {
dashdash = true
return acc
}
if (!/^-/.test(arg)) {
acc[0].push(arg)
return acc
}
for (const flag of arg.slice(1).split('')) {
if (flag === 's') {
acc[1].silent = true
} else if (flag === 'a') {
acc[1].all = true
} else {
usage(`illegal option -- ${flag}`)
}
}
return acc
}, [[], {}])
for (const command of commands) {
try {
const res = which.sync(command, { all: flags.all })
if (!flags.silent) {
console.log([].concat(res).join('\n'))
}
} catch (err) {
process.exitCode = 1
}
}

View file

@ -0,0 +1,111 @@
const { isexe, sync: isexeSync } = require('isexe')
const { join, delimiter, sep, posix } = require('path')
const isWindows = process.platform === 'win32'
// used to check for slashed in commands passed in. always checks for the posix
// seperator on all platforms, and checks for the current separator when not on
// a posix platform. don't use the isWindows check for this since that is mocked
// in tests but we still need the code to actually work when called. that is also
// why it is ignored from coverage.
/* istanbul ignore next */
const rSlash = new RegExp(`[${posix.sep}${sep === posix.sep ? '' : sep}]`.replace(/(\\)/g, '\\$1'))
const rRel = new RegExp(`^\\.${rSlash.source}`)
const getNotFoundError = (cmd) =>
Object.assign(new Error(`not found: ${cmd}`), { code: 'ENOENT' })
const getPathInfo = (cmd, {
path: optPath = process.env.PATH,
pathExt: optPathExt = process.env.PATHEXT,
delimiter: optDelimiter = delimiter,
}) => {
// If it has a slash, then we don't bother searching the pathenv.
// just check the file itself, and that's it.
const pathEnv = cmd.match(rSlash) ? [''] : [
// windows always checks the cwd first
...(isWindows ? [process.cwd()] : []),
...(optPath || /* istanbul ignore next: very unusual */ '').split(optDelimiter),
]
if (isWindows) {
const pathExtExe = optPathExt ||
['.EXE', '.CMD', '.BAT', '.COM'].join(optDelimiter)
const pathExt = pathExtExe.split(optDelimiter).flatMap((item) => [item, item.toLowerCase()])
if (cmd.includes('.') && pathExt[0] !== '') {
pathExt.unshift('')
}
return { pathEnv, pathExt, pathExtExe }
}
return { pathEnv, pathExt: [''] }
}
const getPathPart = (raw, cmd) => {
const pathPart = /^".*"$/.test(raw) ? raw.slice(1, -1) : raw
const prefix = !pathPart && rRel.test(cmd) ? cmd.slice(0, 2) : ''
return prefix + join(pathPart, cmd)
}
const which = async (cmd, opt = {}) => {
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt)
const found = []
for (const envPart of pathEnv) {
const p = getPathPart(envPart, cmd)
for (const ext of pathExt) {
const withExt = p + ext
const is = await isexe(withExt, { pathExt: pathExtExe, ignoreErrors: true })
if (is) {
if (!opt.all) {
return withExt
}
found.push(withExt)
}
}
}
if (opt.all && found.length) {
return found
}
if (opt.nothrow) {
return null
}
throw getNotFoundError(cmd)
}
const whichSync = (cmd, opt = {}) => {
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt)
const found = []
for (const pathEnvPart of pathEnv) {
const p = getPathPart(pathEnvPart, cmd)
for (const ext of pathExt) {
const withExt = p + ext
const is = isexeSync(withExt, { pathExt: pathExtExe, ignoreErrors: true })
if (is) {
if (!opt.all) {
return withExt
}
found.push(withExt)
}
}
}
if (opt.all && found.length) {
return found
}
if (opt.nothrow) {
return null
}
throw getNotFoundError(cmd)
}
module.exports = which
which.sync = whichSync

View file

@ -0,0 +1,57 @@
{
"author": "GitHub Inc.",
"name": "which",
"description": "Like which(1) unix command. Find the first instance of an executable in the PATH.",
"version": "4.0.0",
"repository": {
"type": "git",
"url": "https://github.com/npm/node-which.git"
},
"main": "lib/index.js",
"bin": {
"node-which": "./bin/which.js"
},
"license": "ISC",
"dependencies": {
"isexe": "^3.1.1"
},
"devDependencies": {
"@npmcli/eslint-config": "^4.0.0",
"@npmcli/template-oss": "4.18.0",
"tap": "^16.3.0"
},
"scripts": {
"test": "tap",
"lint": "eslint \"**/*.js\"",
"postlint": "template-oss-check",
"template-oss-apply": "template-oss-apply --force",
"lintfix": "npm run lint -- --fix",
"snap": "tap",
"posttest": "npm run lint"
},
"files": [
"bin/",
"lib/"
],
"tap": {
"check-coverage": true,
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
]
},
"engines": {
"node": "^16.13.0 || >=18.0.0"
},
"templateOSS": {
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
"ciVersions": [
"16.13.0",
"16.x",
"18.0.0",
"18.x"
],
"version": "4.18.0",
"publish": "true"
}
}

57
my-app/node_modules/@npmcli/git/package.json generated vendored Executable file
View file

@ -0,0 +1,57 @@
{
"name": "@npmcli/git",
"version": "5.0.4",
"main": "lib/index.js",
"files": [
"bin/",
"lib/"
],
"description": "a util for spawning git from npm CLI contexts",
"repository": {
"type": "git",
"url": "https://github.com/npm/git.git"
},
"author": "GitHub Inc.",
"license": "ISC",
"scripts": {
"lint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"",
"snap": "tap",
"test": "tap",
"posttest": "npm run lint",
"postlint": "template-oss-check",
"lintfix": "npm run lint -- --fix",
"template-oss-apply": "template-oss-apply --force"
},
"tap": {
"timeout": 600,
"nyc-arg": [
"--exclude",
"tap-snapshots/**"
]
},
"devDependencies": {
"@npmcli/eslint-config": "^4.0.0",
"@npmcli/template-oss": "4.21.3",
"npm-package-arg": "^11.0.0",
"slash": "^3.0.0",
"tap": "^16.0.1"
},
"dependencies": {
"@npmcli/promise-spawn": "^7.0.0",
"lru-cache": "^10.0.1",
"npm-pick-manifest": "^9.0.0",
"proc-log": "^3.0.0",
"promise-inflight": "^1.0.1",
"promise-retry": "^2.0.1",
"semver": "^7.3.5",
"which": "^4.0.0"
},
"engines": {
"node": "^16.14.0 || >=18.0.0"
},
"templateOSS": {
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
"version": "4.21.3",
"publish": true
}
}