optional-require
Advanced tools
Comparing version
91
index.js
"use strict"; | ||
const assert = require("assert"); | ||
/** | ||
* Compatibility bridge to the new typescript code. | ||
* | ||
*/ | ||
function findModuleNotFound(err, name) { | ||
// Check the first line of the error message | ||
const msg = err.message.split("\n")[0]; | ||
return msg && ( | ||
// Check for "Cannot find module 'foo'" | ||
msg.includes(`'${name}'`) | ||
// Check for "Your application tried to access foo (a peer dependency) ..." (Yarn v2 PnP) | ||
// https://github.com/yarnpkg/berry/blob/e81dc0d29bb2f41818d9c5c1c74bab1406fb979b/packages/yarnpkg-pnp/sources/loader/makeApi.ts#L680 | ||
|| msg.includes(` ${name} `) | ||
// Check for "Your application tried to access foo. While ..." (Yarn v2 PnP) | ||
// https://github.com/yarnpkg/berry/blob/e81dc0d29bb2f41818d9c5c1c74bab1406fb979b/packages/yarnpkg-pnp/sources/loader/makeApi.ts#L704 | ||
|| msg.includes(` ${name}. `) | ||
// Check for "Your application tried to access foo, but ..." (Yarn v2 PnP) | ||
// https://github.com/yarnpkg/berry/blob/e81dc0d29bb2f41818d9c5c1c74bab1406fb979b/packages/yarnpkg-pnp/sources/loader/makeApi.ts#L718 | ||
|| msg.includes(` ${name}, `) | ||
); | ||
} | ||
const lib = require("./dist"); | ||
function _optionalRequire(callerRequire, resolve, path, message) { | ||
let opts; | ||
module.exports = (...args) => lib.makeOptionalRequire(...args); | ||
if (typeof message === "object") { | ||
opts = message; | ||
assert( | ||
!(opts.hasOwnProperty("notFound") && opts.hasOwnProperty("default")), | ||
"optionalRequire: options set with both `notFound` and `default`" | ||
); | ||
} else { | ||
opts = { message }; | ||
} | ||
module.exports.tryRequire = lib.tryRequire; | ||
module.exports.tryResolve = lib.tryResolve; | ||
module.exports.try = lib.tryRequire; | ||
module.exports.resolve = lib.tryResolve; | ||
module.exports.makeOptionalRequire = lib.makeOptionalRequire; | ||
module.exports.optionalRequire = lib.optionalRequire; | ||
module.exports.optionalRequireCwd = lib.optionalRequireCwd; | ||
module.exports.optionalRequireTop = lib.optionalRequireTop; | ||
try { | ||
return resolve ? callerRequire.resolve(path) : callerRequire(path); | ||
} catch (e) { | ||
if (e.code !== "MODULE_NOT_FOUND" || !findModuleNotFound(e, path)) { | ||
// if the module we are requiring fail because it try to require a | ||
// module that's not found, then we have to report this as failed. | ||
if (typeof opts.fail === "function") { | ||
return opts.fail(e); | ||
} | ||
throw e; | ||
} | ||
let __defaultLog; | ||
if (opts.message) { | ||
const message = typeof opts.message === "string" ? `${opts.message} - ` : ""; | ||
const r = resolve ? "resolved" : "found"; | ||
optionalRequire.log(`${message}optional module not ${r}`, path); | ||
} | ||
Object.defineProperty(module.exports, "log", { | ||
set(func) { | ||
__defaultLog = func; | ||
lib.setDefaultLog(func); | ||
}, | ||
if (typeof opts.notFound === "function") { | ||
return opts.notFound(e); | ||
} | ||
return opts.default; | ||
} | ||
} | ||
const tryRequire = (callerRequire, path, message) => _optionalRequire(callerRequire, false, path, message); | ||
const tryResolve = (callerRequire, path, message) => _optionalRequire(callerRequire, true, path, message); | ||
function optionalRequire(callerRequire) { | ||
const x = (path, message) => tryRequire(callerRequire, path, message); | ||
x.resolve = (path, message) => tryResolve(callerRequire, path, message); | ||
return x; | ||
} | ||
optionalRequire.try = tryRequire; | ||
optionalRequire.tryResolve = tryResolve; | ||
optionalRequire.resolve = tryResolve; | ||
optionalRequire.log = (message, path) => console.log(`Just FYI: ${message}; Path "${path}"`); | ||
module.exports = optionalRequire; | ||
get() { | ||
return __defaultLog; | ||
}, | ||
}); |
{ | ||
"name": "optional-require", | ||
"version": "1.0.3", | ||
"version": "1.1.0", | ||
"description": "NodeJS Require that let you handle module not found error without try/catch", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "mocha test/spec", | ||
"coverage": "istanbul cover _mocha -- test/spec/*.js" | ||
"build": "tsc", | ||
"test": "xrun --serial build xarc/test-only", | ||
"coverage": "xrun --serial build xarc/test-cov", | ||
"publish-util-pre": "publish-util-prepublishonly", | ||
"prepublishOnly": "xrun --serial [[build, docs], xarc/check, publish-util-pre]", | ||
"docs": "xrun xarc/docs && touch docs/.nojekyll", | ||
"postpack": "publish-util-postpack" | ||
}, | ||
@@ -20,2 +25,3 @@ "repository": { | ||
"files": [ | ||
"dist", | ||
"index.js" | ||
@@ -28,13 +34,5 @@ ], | ||
"license": "Apache-2.0", | ||
"devDependencies": { | ||
"chai": "^3.5.0", | ||
"istanbul": "^0.4.5", | ||
"mocha": "^3.2.0", | ||
"prettier": "1.19.1", | ||
"require-at": "^1.0.0" | ||
}, | ||
"dependencies": {}, | ||
"prettier": { | ||
"printWidth": 120 | ||
"dependencies": { | ||
"require-at": "^1.0.6" | ||
} | ||
} |
@@ -6,70 +6,74 @@ [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] | ||
NodeJS Require that let you handle module not found error without try/catch. Allows you to gracefully require a module only if it exists and contains no error. | ||
node.js require that let you handle module not found error without try/catch. Allows you to gracefully require a module only if it exists and contains no error. | ||
# Usage | ||
## Why not try/catch? | ||
```js | ||
const optionalRequire = require("optional-require")(require); | ||
So why not just do: | ||
const foo = optionalRequire("foo") || {}; | ||
const bar = optionalRequire("bar", true); // true enables console.log a message when not found | ||
const xyz = optionalRequire("xyz", "test"); // "test" enables console.log a message with "test" added. | ||
const fbPath = optionalRequire.resolve("foo", "foo doesn't exist"); | ||
const rel = optionalRequire("../foo/bar"); // relative module path works | ||
```ts | ||
let some; | ||
try { | ||
some = require("some-optional-module"); | ||
} catch { | ||
// do nothing | ||
} | ||
``` | ||
# Install | ||
1. You need to keep the variable outside: `let some` before try/catch | ||
2. If `"some-optional-module"` contains error itself, above code will silently ignore it, leaving you, and more importantly, your users, puzzling on why it's not working. | ||
```bash | ||
$ npm i optional-require --save | ||
``` | ||
## Usage | ||
# API | ||
TypeScript: | ||
#### [optionalRequire(require)](#optionalrequirerequire) | ||
```ts | ||
import { optionalRequire } from "optional-require"; | ||
The single function this module exports. Call it with `require` to get a custom function for you to do optional require from your file's require context. See [Usage](#usage) above. | ||
const some = optionalRequire("some-optional-module"); | ||
``` | ||
#### [customOptionalRequire(path, \[message|options\])](#customoptionalrequirepath-messageoptions) | ||
JavaScript: | ||
The function [optionalRequire](#optionalrequirerequire) returns for you to do optional require from your file's require context. | ||
```js | ||
const { optionalRequire } = require("optional-require"); | ||
##### Params | ||
const foo = optionalRequire("foo") || {}; | ||
const bar = optionalRequire("bar", true); // true enables console.log a message when not found | ||
const xyz = optionalRequire("xyz", "test"); // "test" enables console.log a message with "test" added. | ||
const fbPath = optionalRequire.resolve("foo", "foo doesn't exist"); | ||
// relative module path works - *but* you need to pass in `require` from your file | ||
const rel = optionalRequire("../foo/bar", { require }); | ||
``` | ||
- `path` - name/path to the module your want to optionally require | ||
- `message` - optional flag/message to enable `console.log` a message when module is not found | ||
- `options` - an optional object with the following fields | ||
- `message` - see above | ||
- `fail` - callback for when an error that's _not_ `MODULE_NOT_FOUND` for `path` occurred | ||
- `notFound` - callback for when `path` was not found | ||
- The value from this is returned | ||
- `default` - default value to returned when not found - not allowed with `notFound` together | ||
### Binding `require` | ||
##### Returns | ||
The default `optionalRequire` uses `require` from the context of this module. While you can pass in your `require` in `options`, if you want to create your own function that's bound to your `require`, you can do it with `makeOptionalRequire`: | ||
- module required or one of the following if not found | ||
- `undefined` or | ||
- return value from `options.notFound` if it's specified | ||
- `options.default` if it's specified | ||
```ts | ||
import { makeOptionalRequire } from "optional-require"; | ||
##### Throws | ||
const optionalRequire = makeOptionalRequire(require); | ||
- rethrows any error that's not `MODULE_NOT_FOUND` for the module `path` | ||
// now you can optional require files in same dir as your file | ||
const myModule = optionalRequire("./my-module"); | ||
``` | ||
#### [customOptionalRequire.resolve(path, \[message\])](#customoptionalrequireresolvepath-message) | ||
### Legacy Usage | ||
Same as [customOptionalRequire](#customoptionalrequirepath-messageoptions) but acts like `require.resolve` | ||
In older versions, this module exports `makeOptionalRequire` directly and this is the legacy usage in JavaScript, which is still supported: | ||
#### [optionalRequire.log(message, path)](#optionalrequirelogmessage-path) | ||
```js | ||
const optionalRequire = require("optional-require")(require); | ||
The function that will be called to log the message when optional module is not found. You can override this with your own function. | ||
const foo = optionalRequire("foo") || {}; | ||
const bar = optionalRequire("bar", true); // true enables console.log a message when not found | ||
const xyz = optionalRequire("xyz", "test"); // "test" enables console.log a message with "test" added. | ||
const fbPath = optionalRequire.resolve("foo", "foo doesn't exist"); | ||
const rel = optionalRequire("../foo/bar"); // relative module path works | ||
``` | ||
#### [optionalRequire.try(require, path, \[message|options\])](#optionalrequiretryrequire-path-messageoptions) | ||
## API | ||
Same as [customOptionalRequire](#customoptionalrequirepath-messageoptions) but you have to pass in `require` from your file's context. | ||
<https://jchip.github.io/optional-require/modules.html#optionalrequire> | ||
#### [optionalRequire.resolve(require, path, \[message|options\])](#optionalrequireresolverequire-path-messageoptions) | ||
Same as [customOptionalRequire.resolve](#customoptionalrequirepath-messageoptions) but you have to pass in `require` from your file's context. | ||
# LICENSE | ||
@@ -80,15 +84,8 @@ | ||
[travis-image]: https://travis-ci.org/jchip/optional-require.svg?branch=master | ||
[travis-url]: https://travis-ci.org/jchip/optional-require | ||
[npm-image]: https://badge.fury.io/js/optional-require.svg | ||
[npm-url]: https://npmjs.org/package/optional-require | ||
[daviddm-image]: https://david-dm.org/jchip/optional-require/status.svg | ||
[daviddm-url]: https://david-dm.org/jchip/optional-require | ||
[daviddm-dev-image]: https://david-dm.org/jchip/optional-require/dev-status.svg | ||
[daviddm-dev-url]: https://david-dm.org/jchip/optional-require?type=dev |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
20215
173.18%0
-100%6
100%326
409.38%1
Infinity%90
-3.23%2
Infinity%+ Added
+ Added