Skip to content

Commit

Permalink
re-add the original API and tests for it as a 'low-level' API, making…
Browse files Browse the repository at this point in the history
… this semver minor
  • Loading branch information
bengl committed Aug 25, 2021
1 parent c9c5649 commit 14b1cdd
Show file tree
Hide file tree
Showing 22 changed files with 215 additions and 12 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ time.

## Usage

See the Typescript definition file for API docs. The API for
`require-in-the-middle` is followed as closely as possible.
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.

You can modify anything exported from any given ESM or CJS module that's
imported in ESM files, regardless of whether they're imported statically or
Expand Down
31 changes: 28 additions & 3 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export type Options = {
internals?: boolean
}

export declare class Hook {
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
Expand All @@ -37,7 +37,9 @@ export declare class Hook {
* 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: HookFunction)
constructor (modules: Array<string>, options: Options, hookFn: HookFunction)
constructor (modules: Array<string>, hookFn: HookFunction)
constructor (hookFn: HookFunction)

/**
* Disables this hook. It will no longer be run against any subsequently
Expand All @@ -46,9 +48,32 @@ export declare class Hook {
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.
*/
export type LLHookFunction = (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.
*
* 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.
*/
export declare function addHook(hookFn: HookFunction): void

/**
* 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
export declare function removeHook(hookFn: LLHookFunction): void
23 changes: 16 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ const proxyHandler = {
}
}

function addHook(hook) {
importHooks.push(hook)
toHook.forEach(([name, namespace]) => hook(name, namespace))
}

function removeHook(hook) {
const index = importHooks.indexOf(hook)
if (index > -1) {
importHooks.splice(index, 1)
}
}

function _register(name, namespace, set, specifier) {
specifiers.set(name, specifier)
setters.set(namespace, set)
Expand Down Expand Up @@ -80,17 +92,14 @@ function Hook(modules, options, hookFn) {
}
}

importHooks.push(this._iitmHook)
toHook.forEach(([name, namespace]) => this._iitmHook(name, namespace))
addHook(this._iitmHook)
}

Hook.prototype.unhook = function () {
const index = importHooks.indexOf(this._iitmHook)
if (index > -1) {
importHooks.splice(index, 1)
}
removeHook(this._iitmHook)
}

module.exports = Hook

module.exports._register = _register
module.exports.addHook = addHook
module.exports.removeHook = removeHook
13 changes: 13 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
These tests have the following nomenclature:

* Prefixed with `hook-` if they use the `Hook` class.
* Prefixed with `ll-` if they use the "low-level" API, `addHook` and
`removeHook`.

The tests should be run with the `runtest` command found in this directory. If
the command exits with a non-zero code, then it's a test failure.

Running of all the tests can be done with `npm test`.

Coverage must be 100% according to `c8`. If you don't have 100% coverage, you
can run `npm run coverage` to get coverage data in HTML form.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
23 changes: 23 additions & 0 deletions test/ll-dynamic-import-default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
//
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.

const { addHook } = require('../index.js')
const { strictEqual } = require('assert')

addHook((name, exports) => {
if (name.match(/something\.m?js/)) {
const orig = exports.default
exports.default = function bar() {
return orig() + 15
}
}
})

;(async () => {
const { default: barMjs } = await import('./fixtures/something.mjs')
const { default: barJs } = await import('./fixtures/something.js')

strictEqual(barMjs(), 57)
strictEqual(barJs(), 57)
})()
23 changes: 23 additions & 0 deletions test/ll-dynamic-import-default.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
//
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.

import { addHook } from '../index.js'
import { strictEqual } from 'assert'

addHook((name, exports) => {
if (name.match(/something\.m?js/)) {
const orig = exports.default
exports.default = function bar() {
return orig() + 15
}
}
})

;(async () => {
const { default: barMjs } = await import('./fixtures/something.mjs')
const { default: barJs } = await import('./fixtures/something.js')

strictEqual(barMjs(), 57)
strictEqual(barJs(), 57)
})()
25 changes: 25 additions & 0 deletions test/ll-dynamic-import.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
//
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.

const { addHook } = require('../index.js')
const { strictEqual } = require('assert')

addHook((name, exports) => {
if (name.match(/something\.m?js/)) {
exports.foo += 15
}
if (name.match('os')) {
exports.freemem = () => 47
}
})

;(async () => {
const { foo: fooMjs } = await import('./fixtures/something.mjs')
const { foo: fooJs } = await import('./fixtures/something.js')
const { freemem } = await import('os')

strictEqual(fooMjs, 57)
strictEqual(fooJs, 57)
strictEqual(freemem(), 47)
})()
25 changes: 25 additions & 0 deletions test/ll-remove.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
//
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.

import { addHook, removeHook } from '../index.js'
import { strictEqual } from 'assert'

const hook = (name, exports) => {
if (name.match(/something\.m?js/)) {
exports.foo += 15
}
}

addHook(hook)

;(async () => {
const { foo: fooMjs } = await import('./fixtures/something.mjs')

removeHook(hook)

const { foo: fooJs } = await import('./fixtures/something.js')

strictEqual(fooMjs, 57)
strictEqual(fooJs, 42)
})()
20 changes: 20 additions & 0 deletions test/ll-static-import-default.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
//
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.

import { addHook } from '../index.js'
import barMjs from './fixtures/something.mjs'
import barJs from './fixtures/something.js'
import { strictEqual } from 'assert'

addHook((name, exports) => {
if (name.match(/something\.m?js/)) {
const orig = exports.default
exports.default = function bar() {
return orig() + 15
}
}
})

strictEqual(barMjs(), 57)
strictEqual(barJs(), 57)
15 changes: 15 additions & 0 deletions test/ll-static-import-disabled.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
//
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.

import { addHook } from '../index.js'
import { foo as fooMjs } from './fixtures/something.mjs'
import { foo as fooJs } from './fixtures/something.js'
import { strictEqual, fail } from 'assert'

addHook(() => {
fail('should not have been called at all')
})

strictEqual(fooMjs, 42)
strictEqual(fooJs, 42)
22 changes: 22 additions & 0 deletions test/ll-static-import.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
//
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.

import { addHook } from '../index.js'
import { foo as fooMjs } from './fixtures/something.mjs'
import { foo as fooJs } from './fixtures/something.js'
import { freemem } from 'os'
import { strictEqual } from 'assert'

addHook((name, exports) => {
if (name.match(/something\.m?js/)) {
exports.foo += 15
}
if (name.match('os')) {
exports.freemem = () => 47
}
})

strictEqual(fooMjs, 57)
strictEqual(fooJs, 57)
strictEqual(freemem(), 47)

0 comments on commit 14b1cdd

Please sign in to comment.