Update test framework: fix run_tests.py to support all test files, add auto-import-check for test files

This commit is contained in:
qiaoxinjiu
2026-05-09 15:11:30 +08:00
parent eb053a347f
commit eaba8328da
21739 changed files with 2236758 additions and 719 deletions

14
node_modules/import-in-the-middle/.editorconfig generated vendored Normal file
View File

@@ -0,0 +1,14 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

26
node_modules/import-in-the-middle/.eslintrc.yaml generated vendored Normal file
View File

@@ -0,0 +1,26 @@
overrides:
- files:
- '**/*.{js,cjs,mjs}'
parser: '@babel/eslint-parser'
parserOptions:
ecmaVersion: latest
requireConfigFile: false
sourceType: 'script'
babelOptions:
plugins:
- '@babel/plugin-syntax-import-assertions'
rules:
"import/first": off
extends:
- "standard"
ignorePatterns:
- test/fixtures/circular-a.js
- test/fixtures/circular-b.js
- test/fixtures/reexport.js
- test/fixtures/duplicate-explicit.mjs
- test/fixtures/duplicate.mjs
- test/fixtures/export-types/default-call-expression-renamed.mjs

View File

@@ -0,0 +1,3 @@
{
".": "1.15.0"
}

141
node_modules/import-in-the-middle/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,141 @@
# Changelog
## [1.15.0](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.14.4...import-in-the-middle-v1.15.0) (2025-10-09)
### Features
* Compatibility with specifier imports ([#211](https://github.com/nodejs/import-in-the-middle/issues/211)) ([83d662a](https://github.com/nodejs/import-in-the-middle/commit/83d662a8e1f9a7b8632bc78f7499ccc0ab4d12c2))
## [1.14.4](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.14.3...import-in-the-middle-v1.14.4) (2025-09-25)
### Bug Fixes
* Revert "use `createRequire` to load `hook.js` ([#205](https://github.com/nodejs/import-in-the-middle/issues/205))" ([#208](https://github.com/nodejs/import-in-the-middle/issues/208)) ([f23b7ef](https://github.com/nodejs/import-in-the-middle/commit/f23b7ef9e8d4103f21865ec7a1e5374f41d38ff5))
## [1.14.3](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.14.2...import-in-the-middle-v1.14.3) (2025-09-24)
### Bug Fixes
* use `createRequire` to load `hook.js` ([#205](https://github.com/nodejs/import-in-the-middle/issues/205)) ([81a2ae0](https://github.com/nodejs/import-in-the-middle/commit/81a2ae0ea094df27c9baaf6e267276e0acb21af1))
## [1.14.2](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.14.1...import-in-the-middle-v1.14.2) (2025-06-13)
### Bug Fixes
* do not replace dollar sign in shim variable name ([#200](https://github.com/nodejs/import-in-the-middle/issues/200)) ([20bf0e5](https://github.com/nodejs/import-in-the-middle/commit/20bf0e5c5f6f44f42a8618ad45d08622a63d4d45))
## [1.14.1](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.14.0...import-in-the-middle-v1.14.1) (2025-06-12)
### Bug Fixes
* Account for invalid identifiers ([#198](https://github.com/nodejs/import-in-the-middle/issues/198)) ([2cc8207](https://github.com/nodejs/import-in-the-middle/commit/2cc82070a5ca947463b70f28647b03496a9526f0))
## [1.14.0](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.13.2...import-in-the-middle-v1.14.0) (2025-05-24)
### Features
* Optionally hook internal paths like `require-in-the-middle` ([#194](https://github.com/nodejs/import-in-the-middle/issues/194)) ([976d032](https://github.com/nodejs/import-in-the-middle/commit/976d0320426dcbf8e6260504eccbb62d83513f5a))
## [1.13.2](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.13.1...import-in-the-middle-v1.13.2) (2025-05-12)
### Bug Fixes
* Don't attempt to wrap TypeScript modules ([#191](https://github.com/nodejs/import-in-the-middle/issues/191)) ([6deb87e](https://github.com/nodejs/import-in-the-middle/commit/6deb87ea069ec2ee749ce2297ea47ce071d18cf9))
## [1.13.1](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.13.0...import-in-the-middle-v1.13.1) (2025-02-28)
### Bug Fixes
* handling of circular dependencies ([#181](https://github.com/nodejs/import-in-the-middle/issues/181)) ([b58092e](https://github.com/nodejs/import-in-the-middle/commit/b58092ec9becf4a14f541da4cf5bfb190f2a9a9b))
* importing JSON files ([#182](https://github.com/nodejs/import-in-the-middle/issues/182)) ([8c52014](https://github.com/nodejs/import-in-the-middle/commit/8c52014658fcf698cc340d032b441d9e7a65be36))
* warning from use of context.importAssertions ([#179](https://github.com/nodejs/import-in-the-middle/issues/179)) ([8e56cf1](https://github.com/nodejs/import-in-the-middle/commit/8e56cf1e89752e6c8768d648c10c12fb3178e2ae))
## [1.13.0](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.12.0...import-in-the-middle-v1.13.0) (2025-02-06)
### Features
* Support import attributes ([#176](https://github.com/nodejs/import-in-the-middle/issues/176)) ([916af26](https://github.com/nodejs/import-in-the-middle/commit/916af2627e0e8cb6d50a3b54c1a280dc16e20925))
## [1.12.0](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.11.3...import-in-the-middle-v1.12.0) (2024-12-13)
### Features
* Support absolute paths for `include` ([#168](https://github.com/nodejs/import-in-the-middle/issues/168)) ([d0d9bc3](https://github.com/nodejs/import-in-the-middle/commit/d0d9bc3d1e0bcef1094af58c15cf997507777067))
* Warn on multiple hook initialization ([#165](https://github.com/nodejs/import-in-the-middle/issues/165)) ([9bd539e](https://github.com/nodejs/import-in-the-middle/commit/9bd539ea6ff1684c8807bc30c8b68882cc9e057f))
## [1.11.3](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.11.2...import-in-the-middle-v1.11.3) (2024-12-04)
### Bug Fixes
* Correct type definition for waitForAllMessagesAcknowledged ([#160](https://github.com/nodejs/import-in-the-middle/issues/160)) ([353d535](https://github.com/nodejs/import-in-the-middle/commit/353d535d1ce7ba485e137bcf3db08bbddd6b31d6))
## [1.11.2](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.11.1...import-in-the-middle-v1.11.2) (2024-09-30)
### Bug Fixes
* do nothing if target does not exist in getters map ([#155](https://github.com/nodejs/import-in-the-middle/issues/155)) ([5f6be49](https://github.com/nodejs/import-in-the-middle/commit/5f6be494fc11caf8dcf900807c5b6b646fcd8d74))
## [1.11.1](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.11.0...import-in-the-middle-v1.11.1) (2024-09-26)
### Bug Fixes
* Support Hooking multiple times ([#153](https://github.com/nodejs/import-in-the-middle/issues/153)) ([e0d8080](https://github.com/nodejs/import-in-the-middle/commit/e0d808041eff228f4b4519454f7eea8f0930238a))
## [1.11.0](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.10.0...import-in-the-middle-v1.11.0) (2024-07-29)
### Features
* Optionally only wrap modules hooked in `--import` ([#146](https://github.com/nodejs/import-in-the-middle/issues/146)) ([71c8d7b](https://github.com/nodejs/import-in-the-middle/commit/71c8d7bac512df94566d12c96fc2e438b4de2e2a))
### Bug Fixes
* `node:` prefixed build-in modules with `include`/`exclude` ([#149](https://github.com/nodejs/import-in-the-middle/issues/149)) ([736a944](https://github.com/nodejs/import-in-the-middle/commit/736a9446e209bc8649801a27cb431df663551dc5))
## [1.10.0](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.9.1...import-in-the-middle-v1.10.0) (2024-07-22)
### Features
* Allow regex for `include` and `exclude` options ([#148](https://github.com/nodejs/import-in-the-middle/issues/148)) ([697b0d2](https://github.com/nodejs/import-in-the-middle/commit/697b0d239b9a738f4952bb0f77c521c4a398ac79))
### Bug Fixes
* Use correct `format` when resolving exports from relative paths ([#145](https://github.com/nodejs/import-in-the-middle/issues/145)) ([632802f](https://github.com/nodejs/import-in-the-middle/commit/632802f4e7c797215b4e052ffdfa0fbda1780166))
## [1.9.1](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.9.0...import-in-the-middle-v1.9.1) (2024-07-15)
### Bug Fixes
* Don't wrap native modules ([#142](https://github.com/nodejs/import-in-the-middle/issues/142)) ([f3278a3](https://github.com/nodejs/import-in-the-middle/commit/f3278a3c76af78fe369b599d5b2bf1d87edf0a7a))
* Use correct `format` when resolving exports from sub-modules ([#140](https://github.com/nodejs/import-in-the-middle/issues/140)) ([1db08ef](https://github.com/nodejs/import-in-the-middle/commit/1db08ef5f51346c20b4b3c313bf993e9cf1ca7d5))
## [1.9.0](https://github.com/nodejs/import-in-the-middle/compare/import-in-the-middle-v1.8.1...import-in-the-middle-v1.9.0) (2024-07-08)
### Features
* Allow passing of `include` or `exclude` list via `module.register()` ([#124](https://github.com/nodejs/import-in-the-middle/issues/124)) ([381f48c](https://github.com/nodejs/import-in-the-middle/commit/381f48c07ff755e88495f688c75c4912926194c7))
### Bug Fixes
* CJS `require('.')` resolution ([#108](https://github.com/nodejs/import-in-the-middle/issues/108)) ([29c77b5](https://github.com/nodejs/import-in-the-middle/commit/29c77b560aec0429154632c950923d12db36f79e))
* Include source url for parsing failures ([#109](https://github.com/nodejs/import-in-the-middle/issues/109)) ([49d69ba](https://github.com/nodejs/import-in-the-middle/commit/49d69ba9e785d4b6a1b38d7da1293cb744b6d7e3))
* Use `process.emitWarning` to log wrapping errors ([#114](https://github.com/nodejs/import-in-the-middle/issues/114)) ([a3778ac](https://github.com/nodejs/import-in-the-middle/commit/a3778acfbe2220ce5d521232b41da23b4383e1e3))

4
node_modules/import-in-the-middle/CODE_OF_CONDUCT.md generated vendored Normal file
View File

@@ -0,0 +1,4 @@
# Code of Conduct
The Code of Conduct, which applies to this project, can be found at
https://github.com/nodejs/admin/blob/HEAD/CODE_OF_CONDUCT.md

34
node_modules/import-in-the-middle/CONTRIBUTING.md generated vendored Normal file
View File

@@ -0,0 +1,34 @@
# Contributing to `import-in-the-middle`
## Code of Conduct
Please read the
[Code of Conduct](https://github.com/nodejs/admin/blob/main/CODE_OF_CONDUCT.md)
which explains the minimum behavior expectations for `import-in-the-middle` contributors.
<a id="developers-certificate-of-origin"></a>
## Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
* (a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
* (b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
* (c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
* (d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.

28
node_modules/import-in-the-middle/GOVERNANCE.md generated vendored Normal file
View File

@@ -0,0 +1,28 @@
# `import-in-the-middle` Project Governance
## Collaborators
`import-in-the-middle` core collaborators maintain the
[nodejs/import-in-the-middle](https://github.com/nodejs/import-in-the-middle)
GitHub repository.
The GitHub team for `import-in-the-middle` core collaborators is
[@nodejs/import-in-the-middle-maintainers](https://github.com/orgs/nodejs/teams/import-in-the-middle-maintainers).
Collaborators have commit access to the
[nodejs/import-in-the-middle](https://github.com/nodejs/import-in-the-middle)
repository.
Both collaborators and non-collaborators may propose changes to the `import-in-the-middle`
source code. The mechanism to propose such a change is a GitHub pull request.
Collaborators review and merge (_land_) pull requests.
## PR Approval
Two collaborators must approve a pull request before the pull request can land.
Approving a pull request indicates that the collaborator accepts responsibility
for the change. Approval must be from collaborators who are not authors of the
change and at least one approval must be from a collaborator outside the authors
direct team.
If a collaborator opposes a proposed change, then the change cannot land. Often,
discussions or further changes result in collaborators removing their
opposition.

201
node_modules/import-in-the-middle/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,4 @@
Component,Origin,License,Copyright
require,module-details-from-path,MIT,Copyright 2016 Thomas Watson Steen
dev,c8,ISC,"Copyright (c) 2017, Contributors"
dev,imhotap,MIT,Copyright (c) 2019 Bryan English.
1 Component Origin License Copyright
2 require module-details-from-path MIT Copyright 2016 Thomas Watson Steen
3 dev c8 ISC Copyright (c) 2017, Contributors
4 dev imhotap MIT Copyright (c) 2019 Bryan English.

34
node_modules/import-in-the-middle/NOTICE generated vendored Normal file
View File

@@ -0,0 +1,34 @@
import-in-the-middle is licensed for use as follows:
Copyright 2024 Node.js contributors. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
This license applies to parts of import-in-the-middle originating from the
https://github.com/DataDog/import-in-the-middle repository:
This product includes software developed at Datadog (https://www.datadoghq.com/).
Copyright 2021 Datadog, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

134
node_modules/import-in-the-middle/README.md generated vendored Normal file
View File

@@ -0,0 +1,134 @@
# import-in-the-middle
**`import-in-the-middle`** is an module loading interceptor inspired by
[`require-in-the-middle`](https://npm.im/require-in-the-middle), but
specifically for ESM modules. In fact, it can even modify modules after loading
time.
## Usage
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
dynamically.
```js
import { Hook } from 'import-in-the-middle'
import { foo } from 'package-i-want-to-modify'
console.log(foo) // whatever that module exported
Hook(['package-i-want-to-modify'], (exported, name, baseDir) => {
// `exported` is effectively `import * as exported from ${url}`
exported.foo += 1
})
console.log(foo) // 1 more than whatever that module exported
```
This requires the use of an ESM loader hook, which can be added with the following
command-line option.
```shell
node --loader=import-in-the-middle/hook.mjs my-app.mjs
```
Since `--loader` has been deprecated you can also register the loader hook programmatically via the Node
[`module.register()`](https://nodejs.org/api/module.html#moduleregisterspecifier-parenturl-options)
API. However, for this to be able to hook non-dynamic imports, it needs to be
registered before your app code is evaluated via the `--import` command-line option.
`my-loader.mjs`
```js
import * as module from 'module'
module.register('import-in-the-middle/hook.mjs', import.meta.url)
```
```shell
node --import=./my-loader.mjs ./my-code.mjs
```
When registering the loader hook programmatically, it's possible to pass a list
of modules, file URLs or regular expressions to either `exclude` or specifically
`include` which modules are intercepted. This is useful if a module is not
compatible with the loader hook.
> **Note:** This feature is incompatible with the `{internals: true}` Hook option
```js
import * as module from 'module'
// Exclude intercepting a specific module by name
module.register('import-in-the-middle/hook.mjs', import.meta.url, {
data: { exclude: ['package-i-want-to-exclude'] }
})
// Only intercept a specific module by name
module.register('import-in-the-middle/hook.mjs', import.meta.url, {
data: { include: ['package-i-want-to-include'] }
})
```
### Only Intercepting Hooked modules
> **Note:** This feature is experimental and is incompatible with the `{internals: true}` Hook option
If you are `Hook`'ing all modules before they are imported, for example in a
module loaded via the Node.js `--import` CLI argument, you can configure the
loader to intercept only modules that were specifically hooked.
`instrument.mjs`
```js
import { register } from 'module'
import { Hook, createAddHookMessageChannel } from 'import-in-the-middle'
const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel()
register('import-in-the-middle/hook.mjs', import.meta.url, registerOptions)
Hook(['fs'], (exported, name, baseDir) => {
// Instrument the fs module
})
// Ensure that the loader has acknowledged all the modules
// before we allow execution to continue
await waitForAllMessagesAcknowledged()
```
`my-app.mjs`
```js
import * as fs from 'fs'
// fs will be instrumented!
fs.readFileSync('file.txt')
```
```shell
node --import=./instrument.mjs ./my-app.mjs
```
### Experimental `experimentalPatchInternals` option
It was found that `import-in-the-middle` didn't match the hooking behavior of `require-in-the-middle` in some cases:
https://github.com/nodejs/import-in-the-middle/issues/185
The `experimentalPatchInternals` option forces the loader to match the behavior of `require-in-the-middle` in these cases.
This option is experimental and may be removed or made the default in the future.
```js
import { register } from 'module'
register('import-in-the-middle/hook.mjs', import.meta.url, {
data: { experimentalPatchInternals: true }
})
```
## Limitations
* You cannot add new exports to a module. You can only modify existing ones.
* While bindings to module exports end up being "re-bound" when modified in a
hook, dynamically imported modules cannot be altered after they're loaded.
* Modules loaded via `require` are not affected at all.

498
node_modules/import-in-the-middle/hook.js generated vendored Normal file
View File

@@ -0,0 +1,498 @@
// 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 { URL, fileURLToPath } = require('url')
const { inspect } = require('util')
const { builtinModules } = require('module')
const specifiers = new Map()
const isWin = process.platform === 'win32'
let experimentalPatchInternals = false
// FIXME: Typescript extensions are added temporarily until we find a better
// way of supporting arbitrary extensions
const EXTENSION_RE = /\.(js|mjs|cjs|ts|mts|cts)$/
const NODE_VERSION = process.versions.node.split('.')
const NODE_MAJOR = Number(NODE_VERSION[0])
const NODE_MINOR = Number(NODE_VERSION[1])
const HANDLED_FORMATS = new Set(['builtin', 'module', 'commonjs'])
let entrypoint
let getExports
if (NODE_MAJOR >= 20 || (NODE_MAJOR === 18 && NODE_MINOR >= 19)) {
getExports = require('./lib/get-exports.js')
} else {
getExports = (url) => import(url).then(Object.keys)
}
function hasIitm (url) {
try {
return new URL(url).searchParams.has('iitm')
} catch {
return false
}
}
function isIitm (url, meta) {
return url === meta.url || url === meta.url.replace('hook.mjs', 'hook.js')
}
function deleteIitm (url) {
let resultUrl
try {
const urlObj = new URL(url)
if (urlObj.searchParams.has('iitm')) {
urlObj.searchParams.delete('iitm')
resultUrl = urlObj.href
if (resultUrl.startsWith('file:node:')) {
resultUrl = resultUrl.replace('file:', '')
}
if (resultUrl.startsWith('file:///node:')) {
resultUrl = resultUrl.replace('file:///', '')
}
} else {
resultUrl = urlObj.href
}
} catch {
resultUrl = url
}
return resultUrl
}
function isNodeMajor16AndMinor17OrGreater () {
return NODE_MAJOR === 16 && NODE_MINOR >= 17
}
function isFileProtocol (urlObj) {
return urlObj.protocol === 'file:'
}
function isNodeProtocol (urlObj) {
return urlObj.protocol === 'node:'
}
function needsToAddFileProtocol (urlObj) {
if (NODE_MAJOR === 17) {
return !isFileProtocol(urlObj)
}
if (isNodeMajor16AndMinor17OrGreater()) {
return !isFileProtocol(urlObj) && !isNodeProtocol(urlObj)
}
return !isFileProtocol(urlObj) && NODE_MAJOR < 18
}
/**
* Determines if a specifier represents an export all ESM line.
* Note that the expected `line` isn't 100% valid ESM. It is derived
* from the `getExports` function wherein we have recognized the true
* line and re-mapped it to one we expect.
*
* @param {string} line
* @returns {boolean}
*/
function isStarExportLine (line) {
return /^\* from /.test(line)
}
function isBareSpecifier (specifier) {
// Relative and absolute paths are not bare specifiers.
if (
specifier.startsWith('.') ||
specifier.startsWith('/')) {
return false
}
// Valid URLs are not bare specifiers. (file:, http:, node:, etc.)
// eslint-disable-next-line no-prototype-builtins
if (URL.hasOwnProperty('canParse')) {
return !URL.canParse(specifier)
}
try {
// eslint-disable-next-line no-new
new URL(specifier)
return false
} catch (err) {
return true
}
}
/**
* Determines whether the input is a bare specifier, file URL or a regular expression.
*
* - node: prefixed URL strings are considered bare specifiers in this context.
*/
function isBareSpecifierFileUrlOrRegex (input) {
if (input instanceof RegExp) {
return true
}
// Relative and absolute paths
if (
input.startsWith('.') ||
input.startsWith('/')) {
return false
}
try {
// eslint-disable-next-line no-new
const url = new URL(input)
// We consider node: URLs bare specifiers in this context
return url.protocol === 'file:' || url.protocol === 'node:'
} catch (err) {
// Anything that fails parsing is a bare specifier
return true
}
}
/**
* Ensure an array only contains bare specifiers, file URLs or regular expressions.
*
* - We consider node: prefixed URL string as bare specifiers in this context.
* - For node built-in modules, we add additional node: prefixed modules to the
* output array.
*/
function ensureArrayWithBareSpecifiersFileUrlsAndRegex (array, type) {
if (!Array.isArray(array)) {
return undefined
}
const invalid = array.filter(s => !isBareSpecifierFileUrlOrRegex(s))
if (invalid.length) {
throw new Error(`'${type}' option only supports bare specifiers, file URLs or regular expressions. Invalid entries: ${inspect(invalid)}`)
}
// Rather than evaluate whether we have a node: scoped built-in-module for
// every call to resolve, we just add them to include/exclude now.
for (const each of array) {
if (typeof each === 'string' && !each.startsWith('node:') && builtinModules.includes(each)) {
array.push(`node:${each}`)
}
}
return array
}
function emitWarning (err) {
// Unfortunately, process.emitWarning does not output the full error
// with error.cause like console.warn does so we need to inspect it when
// tracing warnings
const warnMessage = process.execArgv.includes('--trace-warnings') ? inspect(err) : err
process.emitWarning(warnMessage)
}
/**
* Processes a module's exports and builds a set of setter blocks.
*
* @param {object} params
* @param {string} params.srcUrl The full URL to the module to process.
* @param {object} params.context Provided by the loaders API.
* @param {Function} params.parentGetSource Provides the source code for the parent module.
* @param {bool} params.excludeDefault Exclude the default export.
*
* @returns {Promise<Map<string, string>>} The shimmed setters for all the exports
* from the module and any transitive export all modules.
*/
async function processModule ({ srcUrl, context, parentGetSource, parentResolve, excludeDefault }) {
const exportNames = await getExports(srcUrl, context, parentGetSource)
const starExports = new Set()
const setters = new Map()
const addSetter = (name, setter, isStarExport = false) => {
if (setters.has(name)) {
if (isStarExport) {
// If there's already a matching star export, delete it
if (starExports.has(name)) {
setters.delete(name)
}
// and return so this is excluded
return
}
// if we already have this export but it is from a * export, overwrite it
if (starExports.has(name)) {
starExports.delete(name)
setters.set(name, setter)
}
} else {
// Store export * exports so we know they can be overridden by explicit
// named exports
if (isStarExport) {
starExports.add(name)
}
setters.set(name, setter)
}
}
for (const n of exportNames) {
if (n === 'default' && excludeDefault) continue
if (isStarExportLine(n) === true) {
const [, modFile] = n.split('* from ')
// Relative paths need to be resolved relative to the parent module
const newSpecifier = isBareSpecifier(modFile) ? modFile : new URL(modFile, srcUrl).href
// We need to call `parentResolve` to resolve bare specifiers to a full
// URL. We also need to call `parentResolve` for all sub-modules to get
// the `format`. We can't rely on the parents `format` to know if this
// sub-module is ESM or CJS!
const result = await parentResolve(newSpecifier, { parentURL: srcUrl })
const subSetters = await processModule({
srcUrl: result.url,
context: { ...context, format: result.format },
parentGetSource,
parentResolve,
excludeDefault: true
})
for (const [name, setter] of subSetters.entries()) {
addSetter(name, setter, true)
}
} else {
const variableName = `$${n.replace(/[^a-zA-Z0-9_$]/g, '_')}`
const objectKey = JSON.stringify(n)
const reExportedName = n === 'default' || NODE_MAJOR < 16 ? n : objectKey
addSetter(n, `
let ${variableName}
try {
${variableName} = _[${objectKey}] = namespace[${objectKey}]
} catch (err) {
if (!(err instanceof ReferenceError)) throw err
}
export { ${variableName} as ${reExportedName} }
set[${objectKey}] = (v) => {
${variableName} = v
return true
}
get[${objectKey}] = () => ${variableName}
`)
}
}
return setters
}
function addIitm (url) {
const urlObj = new URL(url)
urlObj.searchParams.set('iitm', 'true')
return needsToAddFileProtocol(urlObj) ? 'file:' + urlObj.href : urlObj.href
}
function createHook (meta) {
let cachedResolve
const iitmURL = new URL('lib/register.js', meta.url).toString()
let includeModules, excludeModules
async function initialize (data) {
if (global.__import_in_the_middle_initialized__) {
process.emitWarning("The 'import-in-the-middle' hook has already been initialized")
}
global.__import_in_the_middle_initialized__ = true
if (data) {
if (data.experimentalPatchInternals) {
experimentalPatchInternals = true
}
includeModules = ensureArrayWithBareSpecifiersFileUrlsAndRegex(data.include, 'include')
excludeModules = ensureArrayWithBareSpecifiersFileUrlsAndRegex(data.exclude, 'exclude')
if (data.addHookMessagePort) {
data.addHookMessagePort.on('message', (modules) => {
if (includeModules === undefined) {
includeModules = []
}
for (const each of modules) {
if (!each.startsWith('node:') && builtinModules.includes(each)) {
includeModules.push(`node:${each}`)
}
includeModules.push(each)
}
data.addHookMessagePort.postMessage('ack')
}).unref()
}
}
}
async function resolve (specifier, context, parentResolve) {
cachedResolve = parentResolve
// See https://github.com/nodejs/import-in-the-middle/pull/76.
if (specifier === iitmURL) {
return {
url: specifier,
shortCircuit: true
}
}
const { parentURL = '' } = context
const newSpecifier = deleteIitm(specifier)
if (isWin && parentURL.indexOf('file:node') === 0) {
context.parentURL = ''
}
const result = await parentResolve(newSpecifier, context, parentResolve)
if (parentURL === '' && !EXTENSION_RE.test(result.url)) {
entrypoint = result.url
return { url: result.url, format: 'commonjs' }
}
// For included/excluded modules, we check the specifier to match libraries
// that are loaded with bare specifiers from node_modules.
//
// For non-bare specifier imports, we match to the full file URL because
// using relative paths would be very error prone!
function match (each) {
if (each instanceof RegExp) {
return each.test(result.url)
}
return each === specifier || each === result.url || (result.url.startsWith('file:') && each === fileURLToPath(result.url))
}
if (result.format && !HANDLED_FORMATS.has(result.format)) {
return result
}
if (includeModules && !includeModules.some(match)) {
return result
}
if (excludeModules && excludeModules.some(match)) {
return result
}
if (isIitm(parentURL, meta) || hasIitm(parentURL)) {
return result
}
// We don't want to attempt to wrap native modules
if (result.url.endsWith('.node')) {
return result
}
// Node.js v21 renames importAssertions to importAttributes
const importAttributes = context.importAttributes || context.importAssertions
if (importAttributes && importAttributes.type === 'json') {
return result
}
// If the file is referencing itself, we need to skip adding the iitm search params
if (result.url === parentURL) {
return {
url: result.url,
shortCircuit: true,
format: result.format
}
}
specifiers.set(result.url, specifier)
return {
url: addIitm(result.url),
shortCircuit: true,
format: result.format
}
}
async function getSource (url, context, parentGetSource) {
if (hasIitm(url)) {
const realUrl = deleteIitm(url)
try {
const setters = await processModule({
srcUrl: realUrl,
context,
parentGetSource,
parentResolve: cachedResolve
})
return {
source: `
import { register } from '${iitmURL}'
import * as namespace from ${JSON.stringify(realUrl)}
${experimentalPatchInternals ? `import { setExperimentalPatchInternals } from '${iitmURL}'\nsetExperimentalPatchInternals(true)` : ''}
// Mimic a Module object (https://tc39.es/ecma262/#sec-module-namespace-objects).
const _ = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } })
const set = {}
const get = {}
${Array.from(setters.values()).join('\n')}
register(${JSON.stringify(realUrl)}, _, set, get, ${JSON.stringify(specifiers.get(realUrl))})
`
}
} catch (cause) {
// If there are other ESM loader hooks registered as well as iitm,
// depending on the order they are registered, source might not be
// JavaScript.
//
// If we fail to parse a module for exports, we should fall back to the
// parent loader. These modules will not be wrapped with proxies and
// cannot be Hook'ed but at least this does not take down the entire app
// and block iitm from being used.
//
// We log the error because there might be bugs in iitm and without this
// it would be very tricky to debug
const err = new Error(`'import-in-the-middle' failed to wrap '${realUrl}'`)
err.cause = cause
emitWarning(err)
// Revert back to the non-iitm URL
url = realUrl
}
}
return parentGetSource(url, context, parentGetSource)
}
// For Node.js 16.12.0 and higher.
async function load (url, context, parentLoad) {
if (hasIitm(url)) {
const { source } = await getSource(url, context, parentLoad)
return {
source,
shortCircuit: true,
format: 'module'
}
}
return parentLoad(url, context, parentLoad)
}
if (NODE_MAJOR >= 17 || (NODE_MAJOR === 16 && NODE_MINOR >= 12)) {
return { initialize, load, resolve }
} else {
return {
initialize,
load,
resolve,
getSource,
getFormat (url, context, parentGetFormat) {
if (hasIitm(url)) {
return {
format: 'module'
}
}
if (url === entrypoint) {
return {
format: 'commonjs'
}
}
return parentGetFormat(url, context, parentGetFormat)
}
}
}
}
module.exports = { createHook }

9
node_modules/import-in-the-middle/hook.mjs generated vendored Normal file
View File

@@ -0,0 +1,9 @@
// 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 { createHook } from './hook.js'
const { initialize, load, resolve, getFormat, getSource } = createHook(import.meta)
export { initialize, load, resolve, getFormat, getSource }

122
node_modules/import-in-the-middle/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,122 @@
// 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.
/**
* 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
}
export 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.
*/
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.
*
* 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
type CreateAddHookMessageChannelReturn<Data> = {
addHookMessagePort: MessagePort,
waitForAllMessagesAcknowledged: () => Promise<void>
registerOptions: { data?: Data; transferList?: any[]; }
}
/**
* EXPERIMENTAL
* This feature is experimental and may change in minor versions.
* **NOTE** This feature is incompatible with the {internals: true} Hook option.
*
* Creates a message channel with a port that can be used to add hooks to the
* list of exclusively included modules.
*
* This can be used to only wrap modules that are Hook'ed, however modules need
* to be hooked before they are imported.
*
* ```ts
* import { register } from 'module'
* import { Hook, createAddHookMessageChannel } from 'import-in-the-middle'
*
* const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel()
*
* register('import-in-the-middle/hook.mjs', import.meta.url, registerOptions)
*
* Hook(['fs'], (exported, name, baseDir) => {
* // Instrument the fs module
* })
*
* // Ensure that the loader has acknowledged all the modules
* // before we allow execution to continue
* await waitForAllMessagesAcknowledged()
* ```
*/
export declare function createAddHookMessageChannel<Data = any>(): CreateAddHookMessageChannelReturn<Data>;

170
node_modules/import-in-the-middle/index.js generated vendored Normal file
View File

@@ -0,0 +1,170 @@
// 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 path = require('path')
const parse = require('module-details-from-path')
const { fileURLToPath } = require('url')
const { MessageChannel } = require('worker_threads')
const {
importHooks,
specifiers,
toHook,
getExperimentalPatchInternals
} = require('./lib/register')
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 callHookFn (hookFn, namespace, name, baseDir) {
const newDefault = hookFn(namespace, name, baseDir)
if (newDefault && newDefault !== namespace) {
namespace.default = newDefault
}
}
let sendModulesToLoader
/**
* EXPERIMENTAL
* This feature is experimental and may change in minor versions.
* **NOTE** This feature is incompatible with the {internals: true} Hook option.
*
* Creates a message channel with a port that can be used to add hooks to the
* list of exclusively included modules.
*
* This can be used to only wrap modules that are Hook'ed, however modules need
* to be hooked before they are imported.
*
* ```ts
* import { register } from 'module'
* import { Hook, createAddHookMessageChannel } from 'import-in-the-middle'
*
* const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel()
*
* register('import-in-the-middle/hook.mjs', import.meta.url, registerOptions)
*
* Hook(['fs'], (exported, name, baseDir) => {
* // Instrument the fs module
* })
*
* // Ensure that the loader has acknowledged all the modules
* // before we allow execution to continue
* await waitForAllMessagesAcknowledged()
* ```
*/
function createAddHookMessageChannel () {
const { port1, port2 } = new MessageChannel()
let pendingAckCount = 0
let resolveFn
sendModulesToLoader = (modules) => {
pendingAckCount++
port1.postMessage(modules)
}
port1.on('message', () => {
pendingAckCount--
if (resolveFn && pendingAckCount <= 0) {
resolveFn()
}
}).unref()
function waitForAllMessagesAcknowledged () {
// This timer is to prevent the process from exiting with code 13:
// 13: Unsettled Top-Level Await.
const timer = setInterval(() => { }, 1000)
const promise = new Promise((resolve) => {
resolveFn = resolve
}).then(() => { clearInterval(timer) })
if (pendingAckCount === 0) {
resolveFn()
}
return promise
}
const addHookMessagePort = port2
const registerOptions = { data: { addHookMessagePort, include: [] }, transferList: [addHookMessagePort] }
return { registerOptions, addHookMessagePort, waitForAllMessagesAcknowledged }
}
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
if (sendModulesToLoader && Array.isArray(modules)) {
sendModulesToLoader(modules)
}
this._iitmHook = (name, namespace) => {
const filename = name
const isBuiltin = name.startsWith('node:')
let baseDir
if (isBuiltin) {
name = name.replace(/^node:/, '')
} else {
if (name.startsWith('file://')) {
try {
name = fileURLToPath(name)
} catch (e) {}
}
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 (!getExperimentalPatchInternals() && !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.Hook = Hook
module.exports.addHook = addHook
module.exports.removeHook = removeHook
module.exports.createAddHookMessageChannel = createAddHookMessageChannel

View File

@@ -0,0 +1,118 @@
'use strict'
const { Parser } = require('acorn')
const { importAttributesOrAssertions } = require('acorn-import-attributes')
const acornOpts = {
ecmaVersion: 'latest',
sourceType: 'module'
}
const parser = Parser.extend(importAttributesOrAssertions)
function warn (txt) {
process.emitWarning(txt, 'get-esm-exports')
}
/**
* Utilizes an AST parser to interpret ESM source code and build a list of
* exported identifiers. In the baseline case, the list of identifiers will be
* the simple identifier names as written in the source code of the module.
* However, there is a special case:
*
* When an `export * from './foo.js'` line is encountered it is rewritten
* as `* from ./foo.js`. This allows the interpreting code to recognize a
* transitive export and recursively parse the indicated module. The returned
* identifier list will have "* from ./foo.js" as an item.
*
* @param {object} params
* @param {string} params.moduleSource The source code of the module to parse
* and interpret.
*
* @returns {Set<string>} The identifiers exported by the module along with any
* custom directives.
*/
function getEsmExports (moduleSource) {
const exportedNames = new Set()
const tree = parser.parse(moduleSource, acornOpts)
for (const node of tree.body) {
if (!node.type.startsWith('Export')) continue
switch (node.type) {
case 'ExportNamedDeclaration':
if (node.declaration) {
parseDeclaration(node, exportedNames)
} else {
parseSpecifiers(node, exportedNames)
}
break
case 'ExportDefaultDeclaration': {
exportedNames.add('default')
break
}
case 'ExportAllDeclaration':
if (node.exported) {
exportedNames.add(node.exported.name)
} else {
exportedNames.add(`* from ${node.source.value}`)
}
break
default:
warn('unrecognized export type: ' + node.type)
}
}
return exportedNames
}
function parseDeclaration (node, exportedNames) {
switch (node.declaration.type) {
case 'FunctionDeclaration':
exportedNames.add(node.declaration.id.name)
break
case 'VariableDeclaration':
for (const varDecl of node.declaration.declarations) {
parseVariableDeclaration(varDecl, exportedNames)
}
break
case 'ClassDeclaration':
exportedNames.add(node.declaration.id.name)
break
default:
warn('unknown declaration type: ' + node.delcaration.type)
}
}
function parseVariableDeclaration (node, exportedNames) {
switch (node.id.type) {
case 'Identifier':
exportedNames.add(node.id.name)
break
case 'ObjectPattern':
for (const prop of node.id.properties) {
exportedNames.add(prop.value.name)
}
break
case 'ArrayPattern':
for (const elem of node.id.elements) {
exportedNames.add(elem.name)
}
break
default:
warn('unknown variable declaration type: ' + node.id.type)
}
}
function parseSpecifiers (node, exportedNames) {
for (const specifier of node.specifiers) {
if (specifier.exported.type === 'Identifier') {
exportedNames.add(specifier.exported.name)
} else if (specifier.exported.type === 'Literal') {
exportedNames.add(specifier.exported.value)
} else {
warn('unrecognized specifier type: ' + specifier.exported.type)
}
}
}
module.exports = getEsmExports

192
node_modules/import-in-the-middle/lib/get-exports.js generated vendored Normal file
View File

@@ -0,0 +1,192 @@
'use strict'
const getEsmExports = require('./get-esm-exports.js')
const { parse: parseCjs } = require('cjs-module-lexer')
const { readFileSync, existsSync } = require('fs')
const { builtinModules } = require('module')
const { fileURLToPath, pathToFileURL } = require('url')
const { dirname, join } = require('path')
function addDefault (arr) {
return new Set(['default', ...arr])
}
// Cached exports for Node built-in modules
const BUILT_INS = new Map()
function getExportsForNodeBuiltIn (name) {
let exports = BUILT_INS.get()
if (!exports) {
exports = new Set(addDefault(Object.keys(require(name))))
BUILT_INS.set(name, exports)
}
return exports
}
const urlsBeingProcessed = new Set() // Guard against circular imports.
/**
* This function looks for the package.json which contains the specifier trying to resolve.
* Once the package.json file has been found, we extract the file path from the specifier
* @param {string} specifier The specifier that is being search for inside the imports object
* @param {URL|string} fromUrl The url from which the search starts from
* @returns array with url and resolvedExport
*/
function resolvePackageImports (specifier, fromUrl) {
try {
const fromPath = fileURLToPath(fromUrl)
let currentDir = dirname(fromPath)
// search for package.json file which has the real url to export
while (currentDir !== dirname(currentDir)) {
const packageJsonPath = join(currentDir, 'package.json')
if (existsSync(packageJsonPath)) {
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
if (packageJson.imports && packageJson.imports[specifier]) {
const imports = packageJson.imports[specifier]
// Look for path inside packageJson
let resolvedExport
if (imports && typeof imports === 'object') {
const requireExport = imports.require
const importExport = imports.import
// look for the possibility of require and import which is standard for CJS/ESM
if (requireExport || importExport) {
// trying to resolve based on order of importance
resolvedExport = requireExport.node || requireExport.default || importExport.node || importExport.default
} else if (imports.node || imports.default) {
resolvedExport = imports.node || imports.default
}
} else if (typeof imports === 'string') {
resolvedExport = imports
}
if (resolvedExport) {
const url = resolvedExport.startsWith('.')
? pathToFileURL(join(currentDir, resolvedExport))
: fromUrl
return [url, resolvedExport]
}
}
// return if we find a package.json but did not find an import
return null
}
currentDir = dirname(currentDir)
}
} catch (cause) {
throw Error(`Failed to find export: ${specifier}`, { cause })
}
return null
}
async function getCjsExports (url, context, parentLoad, source) {
if (urlsBeingProcessed.has(url)) {
return []
}
urlsBeingProcessed.add(url)
try {
const result = parseCjs(source)
const full = addDefault(result.exports)
await Promise.all(result.reexports.map(async re => {
if (re.startsWith('node:') || builtinModules.includes(re)) {
for (const each of getExportsForNodeBuiltIn(re)) {
full.add(each)
}
} else {
if (re === '.') {
re = './'
}
// Entries in the import field should always start with #
if (re.startsWith('#')) {
const resolved = resolvePackageImports(re, url)
if (!resolved) return
[url, re] = resolved
}
const newUrl = pathToFileURL(require.resolve(re, { paths: [dirname(fileURLToPath(url))] })).href
if (newUrl.endsWith('.node') || newUrl.endsWith('.json')) {
return
}
for (const each of await getExports(newUrl, context, parentLoad)) {
full.add(each)
}
}
}))
return full
} finally {
urlsBeingProcessed.delete(url)
}
}
/**
* Inspects a module for its type (commonjs or module), attempts to get the
* source code for said module from the loader API, and parses the result
* for the entities exported from that module.
*
* @param {string} url A file URL string pointing to the module that
* we should get the exports of.
* @param {object} context Context object as provided by the `load`
* hook from the loaders API.
* @param {Function} parentLoad Next hook function in the loaders API
* hook chain.
*
* @returns {Promise<Set<string>>} An array of identifiers exported by the module.
* Please see {@link getEsmExports} for caveats on special identifiers that may
* be included in the result set.
*/
async function getExports (url, context, parentLoad) {
// `parentLoad` gives us the possibility of getting the source
// from an upstream loader. This doesn't always work though,
// so later on we fall back to reading it from disk.
const parentCtx = await parentLoad(url, context)
let source = parentCtx.source
const format = parentCtx.format
if (!source) {
if (format === 'builtin') {
// Builtins don't give us the source property, so we're stuck
// just requiring it to get the exports.
return getExportsForNodeBuiltIn(url)
}
// Sometimes source is retrieved by parentLoad, CommonJs isn't.
source = readFileSync(fileURLToPath(url), 'utf8')
}
try {
if (format === 'module') {
return getEsmExports(source)
}
if (format === 'commonjs') {
return await getCjsExports(url, context, parentLoad, source)
}
// At this point our `format` is either undefined or not known by us. Fall
// back to parsing as ESM/CJS.
const esmExports = getEsmExports(source)
if (!esmExports.length) {
// TODO(bengl) it's might be possible to get here if somehow the format
// isn't set at first and yet we have an ESM module with no exports.
// I couldn't construct an example that would do this, so maybe it's
// impossible?
return await getCjsExports(url, context, parentLoad, source)
}
} catch (cause) {
const err = new Error(`Failed to parse '${url}'`)
err.cause = cause
throw err
}
}
module.exports = getExports

61
node_modules/import-in-the-middle/lib/register.js generated vendored Normal file
View File

@@ -0,0 +1,61 @@
// 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 importHooks = [] // TODO should this be a Set?
const setters = new WeakMap()
const getters = new WeakMap()
const specifiers = new Map()
const toHook = []
const proxyHandler = {
set (target, name, value) {
return setters.get(target)[name](value)
},
get (target, name) {
if (name === Symbol.toStringTag) {
return 'Module'
}
const getter = getters.get(target)[name]
if (typeof getter === 'function') {
return getter()
}
},
defineProperty (target, property, descriptor) {
if ((!('value' in descriptor))) {
throw new Error('Getters/setters are not supported for exports property descriptors.')
}
return setters.get(target)[property](descriptor.value)
}
}
function register (name, namespace, set, get, specifier) {
specifiers.set(name, specifier)
setters.set(namespace, set)
getters.set(namespace, get)
const proxy = new Proxy(namespace, proxyHandler)
importHooks.forEach(hook => hook(name, proxy))
toHook.push([name, proxy])
}
let experimentalPatchInternals = false
function getExperimentalPatchInternals () {
return experimentalPatchInternals
}
function setExperimentalPatchInternals (value) {
experimentalPatchInternals = value
}
exports.register = register
exports.importHooks = importHooks
exports.specifiers = specifiers
exports.toHook = toHook
exports.getExperimentalPatchInternals = getExperimentalPatchInternals
exports.setExperimentalPatchInternals = setExperimentalPatchInternals

64
node_modules/import-in-the-middle/package.json generated vendored Normal file
View File

@@ -0,0 +1,64 @@
{
"name": "import-in-the-middle",
"version": "1.15.0",
"description": "Intercept imports in Node.js",
"main": "index.js",
"scripts": {
"test": "c8 --reporter lcov --check-coverage --lines 50 imhotap --files test/{hook,low-level,other,get-esm-exports,register}/*",
"test:e2e": "node test/check-exports/test.mjs",
"test:ts": "c8 --reporter lcov imhotap --files test/typescript/*.test.mts",
"coverage": "c8 --reporter html imhotap --files test/{hook,low-level,other,get-esm-exports}/* && echo '\nNow open coverage/index.html\n'",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/nodejs/import-in-the-middle.git"
},
"keywords": [
"import",
"ritm",
"iitm",
"loader",
"hook",
"hooks"
],
"author": "Bryan English <bryan.english@datadoghq.com>",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/nodejs/import-in-the-middle/issues"
},
"homepage": "https://github.com/nodejs/import-in-the-middle#readme",
"imhotap": {
"runner": "node",
"test-env": "NODE_OPTIONS=--no-warnings --require ./test/version-check.js --experimental-loader ./test/generic-loader.mjs"
},
"devDependencies": {
"@babel/core": "^7.23.7",
"@babel/eslint-parser": "^7.23.3",
"@babel/plugin-syntax-import-assertions": "^7.23.3",
"@node-rs/crc32": "^1.10.3",
"@react-email/components": "^0.0.19",
"@types/node": "^18.0.6",
"c8": "^7.8.0",
"date-fns": "^3.6.0",
"eslint": "^8.55.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-n": "^16.4.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
"got": "^14.3.0",
"imhotap": "^2.1.0",
"openai": "4.47.2",
"ts-node": "^10.9.1",
"typescript": "^4.7.4",
"vue": "^3.4.31"
},
"dependencies": {
"acorn": "^8.14.0",
"acorn-import-attributes": "^1.9.5",
"cjs-module-lexer": "^1.2.2",
"module-details-from-path": "^1.0.3"
}
}

View File

@@ -0,0 +1,10 @@
{
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
"bootstrap-sha": "57d2459748492abd55e04a679d8b5752b90dfab4",
"packages": {
".": {
"pull-request-title-pattern": "chore: release v${version}",
"release-type": "node"
}
}
}

17
node_modules/import-in-the-middle/test/README.md generated vendored Normal file
View File

@@ -0,0 +1,17 @@
These tests are organized as follows:
* Located in the `hook` directory if they use the `Hook` class.
* Located in the `low-level` directory if they use the "low-level" API,
`addHook` and `removeHook`.
* Other tests are in other adjacent directories.
The tests can be run individually as Node.js programs with non-zero exit codes
upon failures. They should be run with the following Node.js command-line
options (assuming they're run from the project root):
```
--require ./test/version-check.js
--experimental-loader ./test/generic-loader.mjs
```
The entire test suite can be run with `npm test`.

View File

@@ -0,0 +1,317 @@
import { spawnSync } from 'child_process'
import { deepStrictEqual } from 'assert'
import { dirname, resolve } from 'path'
import { fileURLToPath } from 'url'
const cwd = dirname(fileURLToPath(import.meta.url))
const hook = resolve(cwd, '..', '..', 'hook.mjs')
const mostPopular240NpmModules = [
'ansi-styles',
'semver',
'supports-color',
'chalk', 'has-flag',
'debug',
'tslib',
'color-convert',
'ms',
'color-name',
'lru-cache',
'minimatch',
'strip-ansi',
'source-map',
'ansi-regex',
'glob',
'readable-stream',
'commander',
'yallist',
'string-width',
'escape-string-regexp',
'brace-expansion',
'find-up',
'p-locate',
'locate-path',
'wrap-ansi',
'p-limit',
'safe-buffer',
'kind-of',
'minipass',
'uuid',
'string_decoder',
'ajv',
'emoji-regex',
'isarray',
'react-is',
'fs-extra',
'is-fullwidth-code-point',
'get-stream',
'json-schema-traverse',
'yargs-parser',
'glob-parent',
'yargs',
'rimraf',
'acorn',
'which',
'estraverse',
'js-yaml',
'path-exists',
'argparse',
'pretty-format',
'resolve-from',
'cliui',
'schema-utils',
'globals',
'camelcase',
'execa',
'punycode',
'path-key',
'signal-exit',
'inherits',
'resolve',
'mkdirp',
'is-stream',
'ws',
'universalify',
'qs',
'slash',
'json5',
'iconv-lite',
'form-data',
'is-number',
'eslint-visitor-keys',
'@jest/types',
'postcss',
'make-dir',
'pify',
'cross-spawn',
'braces',
'whatwg-url',
'fill-range',
'eslint-scope',
'tr46',
'micromatch',
'convert-source-map',
'define-property',
'agent-base',
'shebang-regex',
'shebang-command',
'mimic-fn',
'globby',
'npm-run-path',
'mime',
'@babel/code-frame',
'extend-shallow',
'to-regex-range',
'onetime',
'https-proxy-agent',
'y18n',
'buffer',
'strip-bom',
'is-glob',
'doctrine',
'picocolors',
'pkg-dir',
'@babel/types',
'regenerator-runtime',
'human-signals',
'@jridgewell/trace-mapping',
'ignore',
'jsesc',
'parse-json',
'jest-worker',
'graceful-fs',
'jest-util',
'jsonfile',
'normalize-path',
'strip-json-comments',
'cosmiconfig',
'minimist',
'path-type',
'@babel/parser',
'balanced-match',
'picomatch',
'typescript',
'isexe',
'statuses',
'entities',
'bytes',
'node-fetch',
'http-errors',
'@babel/highlight',
'@babel/helper-validator-identifier',
'function-bind',
'async',
'sprintf-js',
'@babel/generator',
'is-extendable',
'get-intrinsic',
'lodash',
'mime-db',
'source-map-support',
'mime-types',
'is-arrayish',
'@babel/core',
'once',
'anymatch',
'depd',
'hosted-git-info',
'path-to-regexp',
'axios',
'is-core-module',
'@babel/template',
'cookie',
'write-file-atomic',
'js-tokens',
'@typescript-eslint/typescript-estree',
'@typescript-eslint/types',
'object-inspect',
'wrappy',
'is-extglob',
'chokidar',
'@typescript-eslint/visitor-keys',
'call-bind',
'loader-utils',
'browserslist',
'http-proxy-agent',
'fast-glob',
'concat-map',
'inflight',
'ajv-keywords',
'ansi-escapes',
'ci-info',
'fast-deep-equal',
'caniuse-lite',
'fs.realpath',
'@jridgewell/gen-mapping',
'setprototypeof',
'strip-final-newline',
'optionator',
'path-is-absolute',
'@babel/traverse',
'core-util-is',
'has-symbols',
'yocto-queue',
'p-try',
'electron-to-chromium',
'@smithy/smithy-client',
'yaml',
'ini',
'@babel/helper-plugin-utils',
'jest-get-type',
'type-check',
'levn',
'is-descriptor',
'prelude-ls',
'slice-ansi',
'@typescript-eslint/scope-manager',
'isobject',
'esprima',
'@babel/helper-split-export-declaration',
'callsites',
'readdirp',
'escalade',
'import-fresh',
'get-caller-file',
'@jridgewell/sourcemap-codec',
'acorn-walk',
'rxjs',
'ieee754',
'is-plain-obj',
'istanbul-lib-instrument',
'@babel/helper-module-imports',
'side-channel',
'normalize-package-data',
'is-plain-object',
'@jridgewell/resolve-uri',
'follow-redirects',
'array-union',
'json-parse-even-better-errors',
'path-parse',
'has-property-descriptors',
'uri-js',
'safer-buffer',
'@babel/helpers',
'on-finished',
'@babel/helper-function-name',
'p-map',
'postcss-value-parser',
'indent-string',
'@babel/helper-module-transforms',
'object-assign',
'delayed-stream',
'@nodelib/fs.stat',
'require-directory',
'diff',
'parse5',
'asynckit',
'tmp',
'combined-stream'
]
const otherCommonModulesUsedWithInstrumentation = [
'express',
'fastify',
'@hapi/hapi',
'connect',
'svelte',
'@sveltejs/kit',
'next',
'gatsby',
'@remix-run/node',
'@remix-run/react'
]
const modules = [...mostPopular240NpmModules, ...otherCommonModulesUsedWithInstrumentation]
function installLibs (names) {
spawnSync('npm', ['init', '-y'], { cwd })
spawnSync('npm', ['install', ...names], { cwd })
}
function getExports (name, loader) {
const args = ['--input-type=module', '--no-warnings', '-e', `import * as lib from '${name}'; console.log(JSON.stringify(Object.keys(lib)))`]
if (loader) args.push(loader)
const out = spawnSync(process.execPath, args, { cwd })
if (out.status !== 0) {
console.error(out.stderr.toString())
throw new Error(`Getting exports returned non-zero exit code '${name}'`)
}
const stdout = out.stdout.toString()
return JSON.parse(stdout).sort()
}
const NPM_LIST_SEMVER_PARSE = /└──.*@((0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)/
function getVersion (name) {
const result = spawnSync('npm', ['list', name, '--depth', '0'], { cwd })
const stdout = result.output.toString()
const [, version] = stdout.match(NPM_LIST_SEMVER_PARSE)
return version
}
function testLib (name) {
const version = getVersion(name)
try {
const expected = getExports(name)
const actual = getExports(name, `--experimental-loader=${hook}`)
deepStrictEqual(actual, expected, `Exports for ${name} are different`)
console.log(`✅ Exports for ${name}@${version} match`)
return false
} catch (err) {
console.error(`❌ Error getting exports for ${name}@${version}:`, err)
return true
}
}
console.log(`📦 Installing ${modules.length} libraries...`)
installLibs(modules)
let errored = false
for (const mod of modules) {
errored += testLib(mod)
}
if (errored) {
console.error('❌ Some tests failed')
process.exit(1)
}

View File

@@ -0,0 +1,7 @@
export const a = 'a'
export function aFunc () {
return a
}
export * from './foo.mjs'

View File

@@ -0,0 +1,5 @@
export const b = 'b'
export function bFunc () {
return b
}

View File

@@ -0,0 +1,4 @@
import bar from './something.mjs'
export default bar
export * from './a.mjs'
export * from './b.mjs'

View File

@@ -0,0 +1,18 @@
// The following is generated by tslib. __exportStar is a format which cjs-module-lexer exposes as a reexport
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
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 });
__exportStar(require("./circular-b"), exports);
exports.foo = 42;

View File

@@ -0,0 +1,5 @@
import { bar } from './circular-b.mjs'
export const foo = 1
export { bar }

View File

@@ -0,0 +1,15 @@
// The following is generated by tslib. __exportStar is a format which cjs-module-lexer exposes as a reexport
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
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 });
__exportStar(require("./circular-a"), exports);

View File

@@ -0,0 +1,3 @@
import { foo } from './circular-a.mjs'
export const bar = foo + 1

View File

@@ -0,0 +1,7 @@
import { testB } from './cyclical-b.mjs'
export function testA () {
console.log('testA')
}
testB()

View File

@@ -0,0 +1,6 @@
import { testA } from './cyclical-a.mjs'
export function testB () {
console.log('testB')
testA()
}

View File

@@ -0,0 +1,8 @@
// File generated from our OpenAPI spec by Stainless.
import * as BatchesAPI from './cyclical-self.mjs'
export class Batches {}
export class BatchesPage {}
(function (Batches) {
Batches.BatchesPage = BatchesAPI.BatchesPage
// eslint-disable-next-line no-class-assign
})(Batches || (Batches = {}))

View File

@@ -0,0 +1,4 @@
export const foo = 'a'
export default function () {
return 'c'
}

View File

@@ -0,0 +1 @@
export const foo = 'b'

View File

@@ -0,0 +1 @@
export const foo = 'c'

View File

@@ -0,0 +1,5 @@
export * from './duplicate-a.mjs'
export * from './duplicate-b.mjs'
export { foo } from './duplicate-c.mjs'
export * from './duplicate-a.mjs'
export * from './duplicate-b.mjs'

View File

@@ -0,0 +1,5 @@
export * from './duplicate-a.mjs'
export * from './duplicate-b.mjs'
const foo = 'foo'
export default foo

View File

@@ -0,0 +1,8 @@
let env = { FOO: 'baz' }
function setEnv (newEnv) {
console.log('setting env, env.FOO is', newEnv.FOO)
env = newEnv
}
export { setEnv, env }

View File

@@ -0,0 +1,32 @@
// Exporting declarations
export let name1, name2/*, … */; // also var //| name1,name2
export const name1 = 1, name2 = 2/*, … */; // also var, let //| name1,name2
export function functionName() { /* … */ } //| functionName
export class ClassName { /* … */ } //| ClassName
export function* generatorFunctionName() { /* … */ } //| generatorFunctionName
export const { name1, name2: bar } = o; //| name1,bar
export const [ name1, name2 ] = array; //| name1,name2
// Export list
let name1, nameN; export { name1, /* …, */ nameN }; //| name1,nameN
let variable1, variable2, nameN; export { variable1 as name1, variable2 as name2, /* …, */ nameN }; //| name1,name2,nameN
let variable1; export { variable1 as "string name" }; //| string name
let name1; export { name1 as default /*, … */ }; //| default
// Default exports
export default expression; //| default
export default function functionName() { /* … */ } //| default
export default class ClassName { /* … */ } //| default
export default function* generatorFunctionName() { /* … */ } //| default
export default function () { /* … */ } //| default
export default class { /* … */ } //| default
export default function* () { /* … */ } //| default
// Aggregating modules
export * from "module-name"; //| * from module-name
export * as name1 from "module-name"; //| name1
export { name1, /* …, */ nameN } from "module-name"; //| name1,nameN
export { import1 as name1, import2 as name2, /* …, */ nameN } from "module-name"; //| name1,name2,nameN
export { default, /* …, */ } from "module-name"; //| default
export { default as name1 } from "module-name"; //| name1

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env node
// 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.
// This script doesn't actually have to do anything.

View File

@@ -0,0 +1,19 @@
const o = { name5: 1, name6: 1 }
const array = [1, 1]
// Exporting declarations
export const name1 = 1; export const name2 = 1/*, … */ // also var
export const name3 = 1; export const name4 = 1/*, … */ // also var, let
export function functionName () { return 1 }
export class ClassName { getFoo () { return 1 } }
export function * generatorFunctionName () { return 1 }
export const { name5, name6: bar } = o
export const [name7, name8] = array
export async function asyncFunctionName () { return 1 }
export async function * asyncGeneratorFunctionName () { yield 1 }
export const arrowFunction = () => {
return 1
}
export const asyncArrowFunction = async () => {
return 1
}

View File

@@ -0,0 +1,2 @@
export * from './default-call-expression.mjs'
export { default as somethingElse } from './default-call-expression.mjs'

View File

@@ -0,0 +1 @@
export default parseInt('1')

View File

@@ -0,0 +1 @@
export default class { getFoo () { return 1 } }

View File

@@ -0,0 +1 @@
export default class ClassName { getFoo () { return 1 } }

View File

@@ -0,0 +1 @@
export default [1]

View File

@@ -0,0 +1 @@
export default 1

View File

@@ -0,0 +1 @@
export default 'dog'

View File

@@ -0,0 +1 @@
export default function () { return 1 }

View File

@@ -0,0 +1 @@
export default function functionName () { return 1 }

View File

@@ -0,0 +1 @@
export default function * () { return 1 }

View File

@@ -0,0 +1 @@
export default function * generatorFunctionName () { return 1 }

View File

@@ -0,0 +1,3 @@
export default function () {
return 1
}

View File

@@ -0,0 +1,2 @@
import fnDefaultExport from './fn-default-export.mjs'
export default fnDefaultExport

View File

@@ -0,0 +1,12 @@
// Export list
const name1 = 1
const name2 = 1
const name5 = 1
const variable1 = 1
const variable2 = 1
const variable3 = 1
const name6 = 1
export { name1, name2 }
export { variable1 as name3, variable2 as name4, /* …, */ name5 }
export { variable3 as 'name' }
export { name6 as default /*, … */ }

View File

@@ -0,0 +1,5 @@
const temp = function () {
return 1
}
export default temp

View File

@@ -0,0 +1,5 @@
export function foo () {
return 'foo'
}
export * from './lib/baz.mjs'

View File

@@ -0,0 +1,11 @@
// This replicates the way the in-the-wild `got` module does things:
// https://github.com/sindresorhus/got/blob/3822412/source/index.ts
class got {
foo = 'foo'
}
export default got
export { got }
export * from './something.mjs'
export { default as renamedDefaultExport } from './lib/baz.mjs'

View File

@@ -0,0 +1,10 @@
import { strictEqual } from 'assert'
import * as foo from './foo.mjs'
import { dirname, join } from 'path'
import { fileURLToPath } from 'url'
const fooPath = join(dirname(fileURLToPath(import.meta.url)), 'foo.mjs')
strictEqual(typeof foo.foo, 'function')
strictEqual(global.hooked.length, 1)
strictEqual(global.hooked[0], fooPath)

View File

@@ -0,0 +1,18 @@
import { register } from 'module'
import { Hook, createAddHookMessageChannel } from '../../index.js'
import { dirname, join } from 'path'
import { fileURLToPath } from 'url'
const fooPath = join(dirname(fileURLToPath(import.meta.url)), 'foo.mjs')
const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel()
register('../../hook.mjs', import.meta.url, registerOptions)
global.hooked = []
Hook([fooPath], (_, name) => {
global.hooked.push(name)
})
await waitForAllMessagesAcknowledged()

View File

@@ -0,0 +1,16 @@
import { strictEqual } from 'assert'
import { sep } from 'path'
import * as os from 'node:os'
import { Hook } from '../../index.js'
const hooked = []
Hook((_, name) => {
hooked.push(name)
})
strictEqual(hooked.length, 2)
strictEqual(hooked[0], 'path')
strictEqual(hooked[1], 'os')
strictEqual(sep, '@')
strictEqual(os.arch(), 'new_crazy_arch')

View File

@@ -0,0 +1,23 @@
import { register } from 'module'
import { Hook, createAddHookMessageChannel } from '../../index.js'
// We've imported path here to ensure that the hook is still applied later even
// if the library is used here.
import * as path from 'path'
const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel()
register('../../hook.mjs', import.meta.url, registerOptions)
Hook(['path'], (exports) => {
exports.sep = '@'
})
Hook(['os'], (exports) => {
exports.arch = function () {
return 'new_crazy_arch'
}
})
console.assert(path.sep !== '@')
await waitForAllMessagesAcknowledged()

View File

@@ -0,0 +1 @@
module.exports.foo = 'something'

View File

@@ -0,0 +1,8 @@
// These export identifiers are only supported in Node 16+
exports['one.two'] = () => console.log('b')
// See: https://github.com/nodejs/import-in-the-middle/issues/94
exports['unsigned short'] = 'something'
exports._ = 'foo'
exports.$ = 'bar'

View File

@@ -0,0 +1,5 @@
import coolFile from './something.json' with { type: 'json' }
export default {
data: coolFile.data
}

View File

@@ -0,0 +1,9 @@
// 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 coolFile from './something.json' assert { type: 'json' }
export default {
data: coolFile.data
}

View File

@@ -0,0 +1,4 @@
export function baz () {
return 'baz'
}
export default baz

View File

@@ -0,0 +1,7 @@
// Regression test for https://github.com/nodejs/import-in-the-middle/issues/196
export default function foo () {
// do nothing
}
export { foo as 'module.exports' }

View File

@@ -0,0 +1,2 @@
console.log(`skipping ${process.env.IITM_TEST_FILE} as no native module is available for ${process.platform}-${process.arch}`)
process.exit(0)

View File

@@ -0,0 +1 @@
module.exports = require('@node-rs/crc32-darwin-arm64')

View File

@@ -0,0 +1 @@
module.exports = require('@node-rs/crc32-darwin-x64')

View File

@@ -0,0 +1 @@
module.exports = require('@node-rs/crc32-linux-arm64-gnu')

View File

@@ -0,0 +1,2 @@
console.log(`skipping ${process.env.IITM_TEST_FILE} as no native module is available for ${process.platform}-${process.arch}`)
process.exit(0)

View File

@@ -0,0 +1,2 @@
console.log(`skipping ${process.env.IITM_TEST_FILE} as no native module is available for ${process.platform}-${process.arch}`)
process.exit(0)

View File

@@ -0,0 +1 @@
module.exports = require('@node-rs/crc32-linux-x64-gnu')

View File

@@ -0,0 +1 @@
module.exports = require('@node-rs/crc32-win32-arm64-msvc')

View File

@@ -0,0 +1 @@
module.exports = require('@node-rs/crc32-win32-x64-msvc')

View File

@@ -0,0 +1 @@
module.exports = { ...require('#main-entry-point') }

View File

@@ -0,0 +1,17 @@
{
"name": "test-fixtures",
"imports": {
"#main-entry-point": {
"require": {
"node": "./something.js",
"default": "./something.js"
},
"import": {
"node":"./something.mjs",
"default": "./something.mjs"
}
},
"#main-entry-point-string" : "./something.js",
"#main-entry-point-external" : "some-external-cjs-module"
}
}

View File

@@ -0,0 +1 @@
module.exports = require('util').deprecate

View File

@@ -0,0 +1 @@
module.exports = require('./something.json')

View File

@@ -0,0 +1 @@
module.exports = require('some-external-cjs-module').foo

View File

@@ -0,0 +1 @@
export * from 'some-external-module'

View File

@@ -0,0 +1,15 @@
// The following is generated by tslib. __exportStar is a format which cjs-module-lexer exposes as a reexport
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
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 });
__exportStar(require("./something"), exports);

View File

@@ -0,0 +1 @@
module.exports = { ...require('.') }

View File

@@ -0,0 +1,3 @@
export const sayHi = (name: string) => {
return `Hi ${name}`
};

View File

@@ -0,0 +1,10 @@
// 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.
'use strict'
module.exports = function bar () {
return 42
}
module.exports.foo = 42

View File

@@ -0,0 +1,3 @@
{
"data": "dog"
}

View File

@@ -0,0 +1,9 @@
// 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.
export const foo = 42
export default function bar () {
return foo
}

View File

@@ -0,0 +1,7 @@
export type { Debugger } from 'node:inspector'
export const foo: number = 42
export function bar(): number {
return foo
}

View File

@@ -0,0 +1 @@
module.exports = { ...require('#main-entry-point-external') }

View File

@@ -0,0 +1 @@
module.exports = { ...require('#main-entry-point-string') }

View File

@@ -0,0 +1 @@
export * from '#main-entry-point'

View File

@@ -0,0 +1 @@
export * from 'some-external-module/sub'

View File

@@ -0,0 +1,14 @@
// 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 2024 Datadog, Inc.
import * as tsLoader from './typescript/iitm-ts-node-loader.mjs'
import * as regularLoader from '../hook.mjs'
import path from 'path'
const filename = process.env.IITM_TEST_FILE
export const { initialize, load, resolve, getFormat, getSource } =
filename.includes('disabled') || filename.includes('register')
? {}
: (path.extname(filename).slice(-2) === 'ts' ? tsLoader : regularLoader)

View File

@@ -0,0 +1,3 @@
// v18.19.0 backported ESM hook execution to a separate thread,
// thus being equivalent to >=v20.
require('./v20-get-esm-exports')

View File

@@ -0,0 +1,31 @@
'use strict'
const getEsmExports = require('../../lib/get-esm-exports.js')
const fs = require('fs')
const assert = require('assert')
const path = require('path')
const fixturePath = path.join(__dirname, '../fixtures/esm-exports.txt')
const fixture = fs.readFileSync(fixturePath, 'utf8')
fixture.split('\n').forEach(line => {
if (!line.includes(' //| ')) return
const [mod, testStr] = line.split(' //| ')
const expectedNames = testStr.split(',').map(x => x.trim())
if (expectedNames[0] === '') {
expectedNames.length = 0
}
const names = Array.from(getEsmExports(mod))
assert.deepEqual(expectedNames, names)
console.log(`${mod}\n ✅ contains exports: ${testStr}`)
})
// // Generate fixture data
// fixture.split('\n').forEach(line => {
// if (!line.includes('export ')) {
// console.log(line)
// return
// }
// const names = getEsmExports(line)
// console.log(line, '//|', names.join(','))
// })

View File

@@ -0,0 +1,11 @@
import { foo } from '../fixtures/circular-b.js'
import Hook from '../../index.js'
import { strictEqual } from 'assert'
Hook((exports, name) => {
if (name.match(/circular-[ab].js/)) {
exports.foo += 15
}
})
strictEqual(foo, 57)

View File

@@ -0,0 +1,4 @@
import { Batches, BatchesPage } from '../fixtures/cyclical-self.mjs'
import { strictEqual } from 'assert'
strictEqual(Batches.BatchesPage, BatchesPage)

View File

@@ -0,0 +1,86 @@
// 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 Hook from '../../index.js'
import a from '../fixtures/export-types/default-expression-array.mjs'
import n from '../fixtures/export-types/default-expression-num.mjs'
import s from '../fixtures/export-types/default-expression-string.mjs'
import fn from '../fixtures/export-types/default-function.mjs'
import cn from '../fixtures/export-types/default-class.mjs'
import gfn from '../fixtures/export-types/default-generator.mjs'
import afn from '../fixtures/export-types/default-function-anon.mjs'
import acn from '../fixtures/export-types/default-class-anon.mjs'
import agfn from '../fixtures/export-types/default-generator-anon.mjs'
import callEx from '../fixtures/export-types/default-call-expression.mjs'
import { somethingElse } from '../fixtures/export-types/default-call-expression-renamed.mjs'
import defaultImportExport from '../fixtures/export-types/import-default-export.mjs'
import varDefaultExport from '../fixtures/export-types/variable-default-export.mjs'
import { strictEqual } from 'assert'
Hook((exports, name) => {
if (name.match(/default-expression-array\.m?js/)) {
exports.default[0] += 1
} else if (name.match(/default-expression-num\.m?js/)) {
exports.default += 1
} else if (name.match(/default-expression-string\.m?js/)) {
exports.default += 'dawg'
} else if (name.match(/default-function\.m?js/)) {
const orig = exports.default
exports.default = function () {
return orig() + 1
}
} else if (name.match(/default-class\.m?js/)) {
exports.default.prototype.getFoo = function () {
return 2
}
} else if (name.match(/default-generator\.m?js/)) {
const orig2 = exports.default
exports.default = function * () {
return orig2().next().value + 1
}
} else if (name.match(/default-function-anon\.m?js/)) {
const orig = exports.default
exports.default = function () {
return orig() + 1
}
} else if (name.match(/default-class-anon\.m?js/)) {
exports.default.prototype.getFoo = function () {
return 2
}
} else if (name.match(/default-generator-anon\.m?js/)) {
const orig2 = exports.default
exports.default = function * () {
return orig2().next().value + 1
}
} else if (name.match(/import-default-export\.m?js/)) {
const orig3 = exports.default
exports.default = function () {
return orig3() + 1
}
} else if (name.match(/variable-default-export\.m?js/)) {
const orig4 = exports.default
exports.default = function () {
return orig4() + 1
}
} else if (name.match(/default-call-expression\.m?js/)) {
exports.default += 1
} else if (name.match(/default-call-expression-renamed\.m?js/)) {
exports.somethingElse += 1
}
})
/* eslint-disable new-cap */
strictEqual(defaultImportExport(), 2)
strictEqual(varDefaultExport(), 2)
strictEqual(a[0], 2)
strictEqual(fn(), 2)
strictEqual(new cn().getFoo(), 2)
strictEqual(gfn().next().value, 2)
strictEqual(afn(), 2)
strictEqual(new acn().getFoo(), 2)
strictEqual(agfn().next().value, 2)
strictEqual(n, 2)
strictEqual(s, 'dogdawg')
strictEqual(callEx, 2)
strictEqual(somethingElse, 2)

Some files were not shown because too many files have changed in this diff Show More