Skip to content

perf(loader): synchronous import-in-the-middle hooks and 3.2.0 shouldInclude matcher#9026

Merged
BridgeAR merged 5 commits into
masterfrom
BridgeAR/2026-06-22-iitm-shouldinclude
Jun 26, 2026
Merged

perf(loader): synchronous import-in-the-middle hooks and 3.2.0 shouldInclude matcher#9026
BridgeAR merged 5 commits into
masterfrom
BridgeAR/2026-06-22-iitm-shouldinclude

Conversation

@BridgeAR

@BridgeAR BridgeAR commented Jun 22, 2026

Copy link
Copy Markdown
Member

Summary

Standalone PR combining the synchronous import-in-the-middle loader (originally #8942, commits by @juan-fernandez) with the import-in-the-middle 3.2.0 upgrade and a consumer-owned shouldInclude matcher.

  1. Run the iitm loader synchronously via module.registerHooks() on Node.js versions that support it, else the async module.register loader (@juan-fernandez).
  2. Bump import-in-the-middle to 3.2.0, which exposes the shouldInclude predicate.
  3. Replace iitm's per-resolve include/exclude array scan (~290 entries plus a fileURLToPath) with a shouldInclude predicate: one Set for bare specifiers (built-ins carry both their bare and node: form), one combined RegExp for instrumented node_modules paths and security-control subpaths, one RegExp for the exclusions.
  4. register.js warns and falls back to the asynchronous loader instead of throwing when synchronous hooks are expected but cannot register.

Why

The matcher drops per-resolve cost from ~2.5µs to ~25ns (~100x) on a mixed corpus — the startup hot path on large ESM graphs. Package names pass through regexpEscape so a future metacharacter cannot mis-match.

Open question

register.js keeps a small Node-version pre-check rather than importing iitm's supportsSyncHooks directly: it is CJS, and importing the ESM helper would load iitm's machinery (acorn + the code transformer) on the main thread for unsupported runtimes, regressing their startup. iitm's supportsSyncHooks stays the runtime authority inside loader-hook.mjs; the pre-check only avoids that load. The clean fix is upstream — iitm exposing supportsSyncHooks from a dependency-free module.

Test plan

  • mocha packages/dd-trace/test/register.spec.js
  • mocha packages/datadog-instrumentations/test/helpers/rewriter/loader.spec.mjs

@dd-octo-sts

dd-octo-sts Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Overall package size

Self size: 6.37 MB
Deduped: 7.44 MB
No deduping: 7.44 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.2.0 | 104.26 kB | 843.44 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Jun 22, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 59.38%
Overall Coverage: 88.00% (+0.01%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 978fd05 | Docs | Datadog PR Page | Give us feedback!

@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 62.50000% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.69%. Comparing base (0b5307d) to head (978fd05).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
loader-hook.mjs 63.33% 11 Missing ⚠️
initialize.mjs 50.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master    #9026   +/-   ##
=======================================
  Coverage   93.68%   93.69%           
=======================================
  Files         889      889           
  Lines       50841    50842    +1     
  Branches    11799    11800    +1     
=======================================
+ Hits        47632    47636    +4     
+ Misses       3209     3206    -3     
Flag Coverage Δ
aiguard 34.87% <ø> (-0.08%) ⬇️
aiguard-integration 41.78% <ø> (ø)
apm-bucket-0 34.83% <ø> (-0.08%) ⬇️
apm-bucket-1 40.33% <ø> (-0.07%) ⬇️
apm-bucket-2 37.33% <ø> (-0.07%) ⬇️
apm-capabilities-tracing 48.57% <ø> (ø)
apm-integrations-aerospike 33.11% <ø> (-0.08%) ⬇️
apm-integrations-confluentinc-kafka-javascript 40.02% <ø> (-0.08%) ⬇️
apm-integrations-couchbase 33.23% <ø> (-0.24%) ⬇️
apm-integrations-http 42.03% <ø> (-0.08%) ⬇️
apm-integrations-kafkajs 40.25% <ø> (-0.08%) ⬇️
apm-integrations-next 29.47% <ø> (-0.10%) ⬇️
apm-integrations-prisma 35.03% <ø> (-0.07%) ⬇️
apm-integrations-tedious 33.89% <ø> (-0.08%) ⬇️
appsec 57.37% <ø> (+0.03%) ⬆️
appsec-express_fastify_graphql 53.74% <ø> (-0.09%) ⬇️
appsec-integration 36.16% <ø> (ø)
appsec-kafka_ldapjs_lodash 43.59% <ø> (-0.07%) ⬇️
appsec-mongodb-core_mongoose_mysql 48.83% <ø> (-0.06%) ⬇️
appsec-next 27.99% <ø> (-0.07%) ⬇️
appsec-node-serialize_passport_postgres 48.00% <ø> (-0.11%) ⬇️
appsec-sourcing_stripe_template 45.55% <ø> (-0.06%) ⬇️
debugger 44.41% <40.62%> (+0.10%) ⬆️
instrumentations-bucket-0 28.14% <ø> (-0.08%) ⬇️
instrumentations-bucket-1 37.40% <ø> (-0.07%) ⬇️
instrumentations-bucket-10 40.42% <ø> (-0.07%) ⬇️
instrumentations-bucket-11 27.94% <ø> (-0.08%) ⬇️
instrumentations-bucket-12 28.66% <ø> (-0.08%) ⬇️
instrumentations-bucket-13 27.77% <ø> (-0.08%) ⬇️
instrumentations-bucket-2 30.22% <ø> (-0.07%) ⬇️
instrumentations-bucket-3 35.90% <ø> (-0.07%) ⬇️
instrumentations-bucket-4 28.06% <ø> (-0.08%) ⬇️
instrumentations-bucket-5 36.27% <ø> (-0.07%) ⬇️
instrumentations-bucket-6 38.25% <ø> (-0.08%) ⬇️
instrumentations-bucket-7 35.99% <ø> (+0.01%) ⬆️
instrumentations-bucket-8 36.95% <ø> (-0.07%) ⬇️
instrumentations-bucket-9 39.52% <ø> (-0.07%) ⬇️
instrumentations-instrumentation-couchbase 46.40% <ø> (ø)
instrumentations-integration-esbuild 24.75% <ø> (ø)
llmobs-ai_anthropic_bedrock 39.53% <ø> (-0.07%) ⬇️
llmobs-google-genai_langchain_vertex-ai 36.96% <ø> (-0.06%) ⬇️
llmobs-openai 39.58% <ø> (-0.07%) ⬇️
llmobs-sdk 43.59% <ø> (-0.08%) ⬇️
master-coverage 93.69% <62.50%> (?)
openfeature 37.75% <ø> (ø)
openfeature-unit 50.35% <ø> (ø)
platform-core_esbuild_instrumentations-misc 23.25% <63.33%> (+0.21%) ⬆️
platform-integration 47.42% <62.50%> (+<0.01%) ⬆️
platform-shimmer_unit-guardrails_webpack 18.80% <ø> (ø)
plugins-bucket-0 36.33% <ø> (-0.07%) ⬇️
plugins-bucket-1 39.59% <ø> (ø)
plugins-bucket-11 38.46% <ø> (-0.08%) ⬇️
plugins-bucket-17 39.15% <ø> (-0.07%) ⬇️
plugins-bucket-18 42.08% <ø> (-0.07%) ⬇️
plugins-bucket-19 39.55% <ø> (-0.07%) ⬇️
plugins-bucket-20 43.25% <ø> (-0.07%) ⬇️
plugins-bucket-4 37.71% <ø> (-0.07%) ⬇️
plugins-bullmq_cassandra_cookie 39.76% <ø> (-0.07%) ⬇️
plugins-cookie-parser_crypto_dd-trace-api 33.21% <ø> (-0.08%) ⬇️
plugins-fetch_fs_generic-pool 36.05% <ø> (-0.07%) ⬇️
plugins-google-cloud-pubsub_grpc_handlebars 43.10% <ø> (-0.07%) ⬇️
plugins-hapi_hono_ioredis 37.78% <ø> (-0.07%) ⬇️
plugins-jest_knex_langgraph 32.60% <ø> (-0.08%) ⬇️
plugins-ldapjs_light-my-request_limitd-client 27.84% <ø> (-0.14%) ⬇️
plugins-lodash_mariadb_memcached 35.17% <ø> (-0.08%) ⬇️
plugins-mongodb_mongodb-core_mongoose 36.30% <ø> (-0.07%) ⬇️
plugins-multer_mysql_mysql2 35.14% <ø> (-0.08%) ⬇️
plugins-nats_node-serialize_opensearch 37.14% <ø> (-0.02%) ⬇️
plugins-passport-http_pino_postgres 35.52% <ø> (-0.17%) ⬇️
plugins-process_pug_redis 34.25% <ø> (-0.09%) ⬇️
plugins-undici_url_valkey 35.75% <ø> (-0.20%) ⬇️
plugins-vm_winston_ws 37.55% <ø> (-0.08%) ⬇️
profiling 43.61% <ø> (-0.07%) ⬇️
serverless-aws-sdk-aws-sdk 33.29% <ø> (-0.07%) ⬇️
serverless-aws-sdk-bedrockruntime 32.15% <ø> (-0.07%) ⬇️
serverless-aws-sdk-client 37.08% <ø> (ø)
serverless-aws-sdk-dynamodb 34.14% <ø> (-0.07%) ⬇️
serverless-aws-sdk-eventbridge 27.24% <ø> (-0.07%) ⬇️
serverless-aws-sdk-kinesis 37.40% <ø> (-0.07%) ⬇️
serverless-aws-sdk-lambda 34.59% <ø> (-0.07%) ⬇️
serverless-aws-sdk-s3 32.59% <ø> (-0.07%) ⬇️
serverless-aws-sdk-serverless-peer-service 39.55% <ø> (-0.08%) ⬇️
serverless-aws-sdk-sns 38.25% <ø> (-0.07%) ⬇️
serverless-aws-sdk-sqs 37.99% <ø> (-0.07%) ⬇️
serverless-aws-sdk-stepfunctions 33.18% <ø> (-0.07%) ⬇️
serverless-aws-sdk-util 47.82% <ø> (ø)
serverless-bucket-0 39.46% <ø> (ø)
serverless-lambda 34.32% <ø> (-0.09%) ⬇️
test-optimization-cucumber 52.57% <ø> (+0.11%) ⬆️
test-optimization-cypress 49.62% <ø> (+0.07%) ⬆️
test-optimization-jest 55.63% <ø> (+0.04%) ⬆️
test-optimization-mocha 53.65% <ø> (+0.08%) ⬆️
test-optimization-playwright-playwright-atr 43.82% <ø> (+0.32%) ⬆️
test-optimization-playwright-playwright-efd 43.87% <ø> (+0.08%) ⬆️
test-optimization-playwright-playwright-final-status 43.92% <ø> (+0.08%) ⬆️
test-optimization-playwright-playwright-impacted-tests 43.41% <ø> (ø)
test-optimization-playwright-playwright-reporting 43.49% <ø> (+0.08%) ⬆️
test-optimization-playwright-playwright-test-management 44.93% <ø> (+0.08%) ⬆️
test-optimization-playwright-playwright-test-span 44.78% <ø> (+0.07%) ⬆️
test-optimization-selenium 45.52% <ø> (+0.06%) ⬆️
test-optimization-testopt 48.27% <63.33%> (+0.09%) ⬆️
test-optimization-vitest 50.93% <63.33%> (+0.10%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pr-commenter

pr-commenter Bot commented Jun 22, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-06-26 21:14:21

Comparing candidate commit 978fd05 in PR branch BridgeAR/2026-06-22-iitm-shouldinclude with baseline commit 0b5307d in branch master.

📊 Benchmarking dashboard

Found 0 performance improvements and 0 performance regressions! Performance is the same for 2257 metrics, 29 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

Unstable benchmarks

These benchmarks have a confidence interval too wide to call a change; treat them as noise rather than signal.

scenario:appsec-appsec-enabled-20

  • unstable execution_time [-187.948ms; +198.486ms] or [-5.064%; +5.348%]

scenario:appsec-appsec-enabled-24

  • unstable execution_time [-181503.517µs; +180765.550µs] or [-6.880%; +6.852%]

scenario:appsec-appsec-enabled-26

  • unstable execution_time [-209.026ms; +202.546ms] or [-8.285%; +8.028%]

scenario:appsec-appsec-enabled-with-attacks-26

  • unstable execution_time [-153.438ms; +150.337ms] or [-5.317%; +5.209%]

scenario:appsec-control-20

  • unstable execution_time [-146.908ms; +163.883ms] or [-8.387%; +9.356%]

scenario:appsec-control-24

  • unstable execution_time [-100161.603µs; +99303.103µs] or [-8.265%; +8.194%]

scenario:appsec-control-26

  • unstable execution_time [-110.959ms; +115.706ms] or [-9.194%; +9.587%]

scenario:debugger-line-probe-with-snapshot-default-24

  • unstable cpu_user_time [-2583.213ms; +2585.783ms] or [-30.503%; +30.533%]
  • unstable execution_time [-2680.819ms; +2652.871ms] or [-29.248%; +28.943%]
  • unstable instructions [-22242.7M instructions; +22087.7M instructions] or [-32.185%; +31.960%]
  • unstable max_rss_usage [-9453.748KB; +9400.948KB] or [-5.917%; +5.884%]
  • unstable throughput [-779.138op/s; +792.406op/s] or [-21.221%; +21.583%]

scenario:debugger-line-probe-without-snapshot-24

  • unstable cpu_user_time [-2659.951ms; +2720.789ms] or [-31.381%; +32.099%]
  • unstable execution_time [-2683.875ms; +2759.853ms] or [-29.270%; +30.098%]
  • unstable instructions [-22866.7M instructions; +23390.3M instructions] or [-33.023%; +33.779%]
  • unstable max_rss_usage [-9761.452KB; +10064.652KB] or [-6.101%; +6.291%]
  • unstable throughput [-798.842op/s; +782.163op/s] or [-21.755%; +21.301%]

scenario:debugger-line-probe-without-snapshot-26

  • unstable cpu_user_time [-1814.906ms; +590.358ms] or [-19.295%; +6.276%]
  • unstable execution_time [-1817.128ms; +596.099ms] or [-18.000%; +5.905%]
  • unstable instructions [-16.1G instructions; +5.2G instructions] or [-20.548%; +6.700%]
  • unstable throughput [-132.019op/s; +396.330op/s] or [-4.062%; +12.196%]

scenario:dogstatsd-with-tags-20

  • unstable cpu_user_time [-562.098ms; +173.326ms] or [-11.191%; +3.451%]
  • unstable execution_time [-561.274ms; +170.514ms] or [-11.013%; +3.346%]
  • unstable throughput [-57303.092op/s; +191832.616op/s] or [-3.477%; +11.642%]

scenario:plugin-graphql-long-with-depth-and-collapse-off-24

  • unstable cpu_user_time [-34.934ms; +465.234ms] or [-0.765%; +10.192%]
  • unstable execution_time [-37.641ms; +498.454ms] or [-0.775%; +10.267%]
  • unstable max_rss_usage [-6.666MB; +60.908MB] or [-1.215%; +11.105%]
  • unstable throughput [-4.816op/s; +0.157op/s] or [-10.911%; +0.356%]

scenario:plugin-graphql-long-with-depth-off-20

  • unstable max_rss_usage [-16.526MB; +5.724MB] or [-11.313%; +3.919%]

@BridgeAR
BridgeAR force-pushed the BridgeAR/2026-06-22-iitm-shouldinclude branch 3 times, most recently from e2b5c0e to 05a0194 Compare June 22, 2026 21:58
@BridgeAR BridgeAR changed the title perf(loader): match modules via import-in-the-middle 3.2.0 shouldInclude perf(loader): synchronous import-in-the-middle hooks and 3.2.0 shouldInclude matcher Jun 22, 2026
@BridgeAR
BridgeAR changed the base branch from juan-fernandez/iitm-sync-loader-hooks to master June 22, 2026 22:05
@BridgeAR
BridgeAR marked this pull request as ready for review June 23, 2026 19:33
@BridgeAR
BridgeAR requested review from a team as code owners June 23, 2026 19:33
@BridgeAR
BridgeAR requested review from wconti27 and removed request for a team June 23, 2026 19:33

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 782da9406b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread loader-hook.mjs
BridgeAR added 3 commits June 25, 2026 21:31
import-in-the-middle scanned the include and exclude options once per resolved
module — up to ~290 include entries (RegExp.test or string compare) plus a
fileURLToPath on every resolve, nearly all against modules that match nothing.
Supply iitm's shouldInclude predicate instead: a single Set answers the
bare-specifier check and one combined RegExp covers every instrumented
node_modules path and the configured security-control subpaths, with one more
RegExp for the exclusions.

The Set also carries each built-in's node: specifier (mirroring iitm's include
expansion), so `import 'node:crypto'` stays instrumented as well as
`import 'crypto'`.

Over a mixed resolve corpus this drops the per-resolve matching cost from
~2.5us to ~25ns (about 100x), reproduced across runs. Package names now pass
through regexpEscape so a metacharacter in a future package name cannot
mis-match.
The rewriter loader spec is the repository's only `.spec.mjs`, and no CI job
ran it: the misc suite glob matched `.spec.js` only, and the exercised-tests
gate collected `.spec.js`/`.test.mjs` but not `.spec.mjs`, so it could not flag
the orphan.

1. Match `*.spec.{js,mjs}` in `test:instrumentations:misc` so the spec runs.
2. Widen the verify-exercised-tests test-file globs to `@(spec|test).@(js|mjs|cjs)`
   so every naming convention is tracked and an unrun one fails the gate.
3. Load the loader through require(esm) in the spec so its async and sync
   transforms land on nyc's CommonJS instrumentation path; the top-level import
   bypassed coverage entirely.
@BridgeAR
BridgeAR force-pushed the BridgeAR/2026-06-22-iitm-shouldinclude branch from f2f52ac to 1788919 Compare June 25, 2026 19:42
@BridgeAR
BridgeAR requested a review from a team as a code owner June 25, 2026 19:42
@BridgeAR
BridgeAR requested review from khanayan123 and removed request for a team June 25, 2026 19:42
…sm) support

The loader spec require()s the .mjs loader so nyc instruments it through the
CommonJS require extension and its transforms count as covered. On Node 18 that
require has no native require(esm) to fall through to, so nyc's .mjs extension
hands the source to the CommonJS compiler, which throws a SyntaxError on the
loader's ESM import rather than ERR_REQUIRE_ESM. The before hook only caught the
latter and crashed the whole suite.

Gate on process.features.require_module instead: require(esm) where the runtime
supports it (covered), import() where it does not.
@BridgeAR
BridgeAR merged commit d4a75c2 into master Jun 26, 2026
842 of 844 checks passed
@BridgeAR
BridgeAR deleted the BridgeAR/2026-06-22-iitm-shouldinclude branch June 26, 2026 21:34
dd-octo-sts Bot pushed a commit that referenced this pull request Jun 29, 2026
…te (#9026)

import-in-the-middle scanned the include and exclude arrays once per resolved
module — up to ~290 include entries (RegExp.test or string compare) plus a
fileURLToPath on every resolve, nearly all against modules that match nothing.
Supplying iitm 3.2.0's shouldInclude predicate replaces that scan with a single
Set lookup for bare specifiers and one combined RegExp covering every
instrumented node_modules path and the configured security-control subpaths,
plus one RegExp for the exclusions. Over a mixed resolve corpus this drops the
per-resolve matching cost from ~2.5µs to ~25ns (about 100x).

The Set also carries each built-in's node: specifier, mirroring iitm's include
expansion, so `import 'node:crypto'` stays instrumented alongside
`import 'crypto'`. Package names pass through regexpEscape so a metacharacter in
a future package name cannot mis-match.

The .mjs rewriter loader spec was the repository's only .spec.mjs and no CI job
ran it: the misc suite glob matched .spec.js only, and the exercised-tests gate
collected .spec.js/.test.mjs but not .spec.mjs, so it could not flag the orphan.

1. Match *.spec.{js,mjs} in test:instrumentations:misc so the spec runs.
2. Widen verify-exercised-tests globs to @(spec|test).@(js|mjs|cjs) so every
   naming convention is tracked and an unrun one fails the gate.
3. Load the loader through require(esm) where the runtime supports it so its
   transforms land on nyc's CommonJS instrumentation path; gate on
   process.features.require_module so Node 18 falls back to import() instead of
   crashing the suite on the CommonJS compiler's SyntaxError.
@dd-octo-sts dd-octo-sts Bot mentioned this pull request Jun 29, 2026
This was referenced Jun 30, 2026
rochdev pushed a commit that referenced this pull request Jul 2, 2026
…te (#9026)

import-in-the-middle scanned the include and exclude arrays once per resolved
module — up to ~290 include entries (RegExp.test or string compare) plus a
fileURLToPath on every resolve, nearly all against modules that match nothing.
Supplying iitm 3.2.0's shouldInclude predicate replaces that scan with a single
Set lookup for bare specifiers and one combined RegExp covering every
instrumented node_modules path and the configured security-control subpaths,
plus one RegExp for the exclusions. Over a mixed resolve corpus this drops the
per-resolve matching cost from ~2.5µs to ~25ns (about 100x).

The Set also carries each built-in's node: specifier, mirroring iitm's include
expansion, so `import 'node:crypto'` stays instrumented alongside
`import 'crypto'`. Package names pass through regexpEscape so a metacharacter in
a future package name cannot mis-match.

The .mjs rewriter loader spec was the repository's only .spec.mjs and no CI job
ran it: the misc suite glob matched .spec.js only, and the exercised-tests gate
collected .spec.js/.test.mjs but not .spec.mjs, so it could not flag the orphan.

1. Match *.spec.{js,mjs} in test:instrumentations:misc so the spec runs.
2. Widen verify-exercised-tests globs to @(spec|test).@(js|mjs|cjs) so every
   naming convention is tracked and an unrun one fails the gate.
3. Load the loader through require(esm) where the runtime supports it so its
   transforms land on nyc's CommonJS instrumentation path; gate on
   process.features.require_module so Node 18 falls back to import() instead of
   crashing the suite on the CommonJS compiler's SyntaxError.
rochdev pushed a commit that referenced this pull request Jul 2, 2026
…te (#9026)

import-in-the-middle scanned the include and exclude arrays once per resolved
module — up to ~290 include entries (RegExp.test or string compare) plus a
fileURLToPath on every resolve, nearly all against modules that match nothing.
Supplying iitm 3.2.0's shouldInclude predicate replaces that scan with a single
Set lookup for bare specifiers and one combined RegExp covering every
instrumented node_modules path and the configured security-control subpaths,
plus one RegExp for the exclusions. Over a mixed resolve corpus this drops the
per-resolve matching cost from ~2.5µs to ~25ns (about 100x).

The Set also carries each built-in's node: specifier, mirroring iitm's include
expansion, so `import 'node:crypto'` stays instrumented alongside
`import 'crypto'`. Package names pass through regexpEscape so a metacharacter in
a future package name cannot mis-match.

The .mjs rewriter loader spec was the repository's only .spec.mjs and no CI job
ran it: the misc suite glob matched .spec.js only, and the exercised-tests gate
collected .spec.js/.test.mjs but not .spec.mjs, so it could not flag the orphan.

1. Match *.spec.{js,mjs} in test:instrumentations:misc so the spec runs.
2. Widen verify-exercised-tests globs to @(spec|test).@(js|mjs|cjs) so every
   naming convention is tracked and an unrun one fails the gate.
3. Load the loader through require(esm) where the runtime supports it so its
   transforms land on nyc's CommonJS instrumentation path; gate on
   process.features.require_module so Node 18 falls back to import() instead of
   crashing the suite on the CommonJS compiler's SyntaxError.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants