Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

import-in-the-middle

Package Overview
Dependencies
Maintainers
1
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

import-in-the-middle - npm Package Compare versions

Comparing version 1.0.1 to 1.1.0

lib/register.js

75

index.d.ts

@@ -6,12 +6,70 @@ // Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.

/**
* Property bag representing a module's exports, including the `default` if
* present.
*/
export type Namespace = { [key: string]: any }
/**
* A hook function to be run against loaded modules.
* Not to be confused with `HookFunction`, used by the lower-level API.
* @param {exported} { [string]: any } An object representing the exported
* items of a module.
* @param {name} string The name of the module. If it is (or is part of) a
* package in a node_modules directory, this will be the path of the file
* starting from the package name.
* @param {baseDir} string The absolute path of the module, if not provided in
* `name`.
* @return any A value that can will be assigned to `exports.default`. This is
* equivalent to doing that assignment in the body of this function.
*/
export type HookFn = (exported: Namespace, name: string, baseDir: string|void) => any
export type Options = {
internals?: boolean
}
declare class Hook {
/**
* Creates a hook to be run on any already loaded modules and any that will
* be loaded in the future. It will be run once per loaded module. If
* statically imported, any variables bound directly to exported items will
* be re-bound if those items are re-assigned in the hook function.
* @param {Array<string>} [modules] A list of modules to run this hook on. If
* omitted, it will run on every import everywhere.
* @param {Options} [options] An options object. If omitted, the default is
* `{ internals: false }`. If internals is true, then the hook will operate
* on internal modules of packages in node_modules. Otherwise it will not,
* unless they are mentioned specifically in the modules array.
* @param {HookFunction} hookFn The function to be run on each module.
*/
constructor (modules: Array<string>, options: Options, hookFn: HookFn)
constructor (modules: Array<string>, hookFn: HookFn)
constructor (hookFn: HookFn)
/**
* Disables this hook. It will no longer be run against any subsequently
* loaded modules.
*/
unhook(): void
}
export default Hook
/**
* A hook function to be run against loaded modules. To be used with the
* lower-level APIs `addHook` and `removeHook`.
* @param {url} string The absolute path of the module, as a `file:` URL string.
* @param {exported} { [string]: any } An object representing the exported items of a module.
* @param {exported} { [string]: any } An object representing the exported
* items of a module.
*/
export type HookFunction = (url: string, exported: { [string]: any }) => void
export type HookFunction = (url: string, exported: Namespace) => void
/**
* Adds a hook to be run on any already loaded modules and any that will be loaded in the future.
* It will be run once per loaded module. If statically imported, any variables bound directly to
* exported items will be re-bound if those items are re-assigned in the hook.
* Adds a hook to be run on any already loaded modules and any that will be
* loaded in the future. It will be run once per loaded module. If statically
* imported, any variables bound directly to exported items will be re-bound if
* those items are re-assigned in the hook.
*
* This is the lower-level API for hook creation. It will be run on every
* single imported module, rather than with any filtering.
* @param {HookFunction} hookFn The function to be run on each module.

@@ -22,6 +80,9 @@ */

/**
* Removes a hook that has been previously added with `addHook`. It will no longer be run against
* any subsequently loaded modules.
* Removes a hook that has been previously added with `addHook`. It will no
* longer be run against any subsequently loaded modules.
*
* This is the lower-level API for hook removal, and cannot be used with the
* `Hook` class.
* @param {HookFunction} hookFn The function to be removed.
*/
export declare function removeHook(hookFn: HookFunction): void

93

index.js

@@ -5,22 +5,13 @@ // Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.

const importHooks = [] // TODO should this be a Set?
const path = require('path')
const parse = require('module-details-from-path')
const { fileURLToPath } = require('url')
const setters = new WeakMap()
const {
importHooks,
specifiers,
toHook
} = require('./lib/register')
const toHook = []
const proxyHandler = {
set(target, name, value) {
return setters.get(target)[name](value)
}
}
exports._register = function _register(name, namespace, set) {
setters.set(namespace, set)
const proxy = new Proxy(namespace, proxyHandler)
importHooks.forEach(hook => hook(name, proxy))
toHook.push([name, proxy])
}
exports.addHook = function addHook(hook) {
function addHook(hook) {
importHooks.push(hook)

@@ -30,3 +21,3 @@ toHook.forEach(([name, namespace]) => hook(name, namespace))

exports.removeHook = function removeHook(hook) {
function removeHook(hook) {
const index = importHooks.indexOf(hook)

@@ -37,1 +28,65 @@ if (index > -1) {

}
function callHookFn(hookFn, namespace, name, baseDir) {
const newDefault = hookFn(namespace, name, baseDir)
if (newDefault && newDefault !== namespace) {
namespace.default = newDefault
}
}
function Hook(modules, options, hookFn) {
if ((this instanceof Hook) === false) return new Hook(modules, options, hookFn)
if (typeof modules === 'function') {
hookFn = modules
modules = null
options = null
} else if (typeof options === 'function') {
hookFn = options
options = null
}
const internals = options ? options.internals === true : false
this._iitmHook = (name, namespace) => {
const filename = name
const isBuiltin = name.startsWith('node:')
let baseDir
if (isBuiltin) {
name = name.replace(/^node:/, '')
} else {
name = name.replace(/^file:\/\//, '')
const details = parse(name)
if (details) {
name = details.name
baseDir = details.basedir
}
}
if (modules) {
for (const moduleName of modules) {
if (moduleName === name) {
if (baseDir) {
if (internals) {
name = name + path.sep + path.relative(baseDir, fileURLToPath(filename))
} else {
if (!baseDir.endsWith(specifiers.get(filename))) continue
}
}
callHookFn(hookFn, namespace, name, baseDir)
}
}
} else {
callHookFn(hookFn, namespace, name, baseDir)
}
}
addHook(this._iitmHook)
}
Hook.prototype.unhook = function () {
removeHook(this._iitmHook)
}
module.exports = Hook
module.exports.addHook = addHook
module.exports.removeHook = removeHook
{
"name": "import-in-the-middle",
"version": "1.0.1",
"version": "1.1.0",
"description": "Intercept imports in Node.js",
"main": "index.js",
"scripts": {
"test": "c8 --check-coverage --lines 100 imhotap --runner test/runtest --files test/*.*js"
"test": "c8 --check-coverage --lines 100 imhotap --runner test/runtest --files test/{hook,low-level}/*.*js",
"coverage": "c8 --reporter html imhotap --runner test/runtest --files test/{hook,low-level}/*.*js && echo '\nNow open coverage/index.html\n'"
},

@@ -30,3 +31,6 @@ "repository": {

"imhotap": "^1.1.0"
},
"dependencies": {
"module-details-from-path": "^1.0.3"
}
}

@@ -10,3 +10,7 @@ # import-in-the-middle

See the Typescript definition file for API docs.
The API for
`require-in-the-middle` is followed as closely as possible as the default
export. There are lower-level `addHook` and `removeHook` exports available which
don't do any filtering of modules, and present the full file URL as a parameter
to the hook. See the Typescript definition file for detailed API docs.

@@ -18,12 +22,10 @@ You can modify anything exported from any given ESM or CJS module that's

```js
import { addHook } from 'import-in-the-middle'
import { foo } from './module-i-want-to-modify.mjs'
import Hook from 'import-in-the-middle'
import { foo } from 'package-i-want-to-modify'
console.log(foo) // whatever that module exported
addHook((url, exported) => {
Hook(['package-i-want-to-modify'], (exported, name, baseDir) => {
// `exported` is effectively `import * as exported from ${url}`
if (url.match(/module-i-want-to-modify.mjs$/)) {
exported.foo += 1
}
exported.foo += 1
})

@@ -38,3 +40,3 @@

```
--loader=/path/to/import-in-the-middle/hook.mjs
--loader=import-in-the-middle/hook.mjs
```

@@ -41,0 +43,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc