Skip to content

Commit d0d92ed

Browse files
Merge pull request #16939 from nestjs/fix/deeply-nested-transient-providers
fix(core): fix deeply nested transient providers resolution
2 parents 24b6ede + 4263a25 commit d0d92ed

17 files changed

Lines changed: 783 additions & 295 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import * as path from 'path';
2+
3+
type ResolveFilename = (
4+
request: string,
5+
parent: NodeModule | null | undefined,
6+
isMain: boolean,
7+
options?: Record<string, unknown>,
8+
) => string;
9+
10+
const Module = require('module') as {
11+
_resolveFilename: ResolveFilename;
12+
};
13+
14+
const workspaceRoot = path.join(__dirname, '..', '..');
15+
const packageRoots = new Map<string, string>([
16+
['@nestjs/common', path.join(workspaceRoot, 'packages/common')],
17+
['@nestjs/core', path.join(workspaceRoot, 'packages/core')],
18+
['@nestjs/microservices', path.join(workspaceRoot, 'packages/microservices')],
19+
[
20+
'@nestjs/platform-express',
21+
path.join(workspaceRoot, 'packages/platform-express'),
22+
],
23+
[
24+
'@nestjs/platform-fastify',
25+
path.join(workspaceRoot, 'packages/platform-fastify'),
26+
],
27+
[
28+
'@nestjs/platform-socket.io',
29+
path.join(workspaceRoot, 'packages/platform-socket.io'),
30+
],
31+
['@nestjs/platform-ws', path.join(workspaceRoot, 'packages/platform-ws')],
32+
['@nestjs/testing', path.join(workspaceRoot, 'packages/testing')],
33+
['@nestjs/websockets', path.join(workspaceRoot, 'packages/websockets')],
34+
]);
35+
36+
const originalResolveFilename = Module._resolveFilename;
37+
38+
Module._resolveFilename = function resolveFilename(
39+
request,
40+
parent,
41+
isMain,
42+
options,
43+
) {
44+
const directMatch = packageRoots.get(request);
45+
if (directMatch) {
46+
return originalResolveFilename.call(
47+
this,
48+
directMatch,
49+
parent,
50+
isMain,
51+
options,
52+
);
53+
}
54+
55+
for (const [packageName, packageRoot] of packageRoots) {
56+
if (request.startsWith(`${packageName}/`)) {
57+
const relativePath = request.slice(packageName.length + 1);
58+
return originalResolveFilename.call(
59+
this,
60+
path.join(packageRoot, relativePath),
61+
parent,
62+
isMain,
63+
options,
64+
);
65+
}
66+
}
67+
68+
return originalResolveFilename.call(this, request, parent, isMain, options);
69+
};

integration/hooks/e2e/enable-shutdown-hook.spec.ts

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,38 @@ import { spawnSync } from 'child_process';
33
import { join } from 'path';
44

55
describe('enableShutdownHooks', () => {
6+
const workspaceRoot = join(__dirname, '../../..');
7+
const localPackageResolver = join(
8+
workspaceRoot,
9+
'integration/_support/register-local-packages.ts',
10+
);
11+
const entrypoint = join(__dirname, '../src/enable-shutdown-hooks-main.ts');
12+
13+
const runScript = (...args: string[]) =>
14+
spawnSync(
15+
process.execPath,
16+
[
17+
'-r',
18+
'ts-node/register/transpile-only',
19+
'-r',
20+
localPackageResolver,
21+
entrypoint,
22+
...args,
23+
],
24+
{
25+
cwd: workspaceRoot,
26+
env: {
27+
...process.env,
28+
TS_NODE_PROJECT: join(
29+
workspaceRoot,
30+
'integration/hooks/tsconfig.json',
31+
),
32+
},
33+
},
34+
);
35+
636
it('should call the correct hooks if any shutdown signal gets invoked', done => {
7-
const result = spawnSync('ts-node', [
8-
join(__dirname, '../src/enable-shutdown-hooks-main.ts'),
9-
'SIGHUP',
10-
]);
37+
const result = runScript('SIGHUP');
1138
const calls = result.stdout
1239
.toString()
1340
.split('\n')
@@ -18,11 +45,7 @@ describe('enableShutdownHooks', () => {
1845
}).timeout(10000);
1946

2047
it('should call the correct hooks if a specific shutdown signal gets invoked', done => {
21-
const result = spawnSync('ts-node', [
22-
join(__dirname, '../src/enable-shutdown-hooks-main.ts'),
23-
'SIGINT',
24-
'SIGINT',
25-
]);
48+
const result = runScript('SIGINT', 'SIGINT');
2649
const calls = result.stdout
2750
.toString()
2851
.split('\n')
@@ -33,32 +56,19 @@ describe('enableShutdownHooks', () => {
3356
}).timeout(10000);
3457

3558
it('should ignore system signals which are not specified', done => {
36-
const result = spawnSync('ts-node', [
37-
join(__dirname, '../src/enable-shutdown-hooks-main.ts'),
38-
'SIGINT',
39-
'SIGHUP',
40-
]);
59+
const result = runScript('SIGINT', 'SIGHUP');
4160
expect(result.stdout.toString().trim()).to.be.eq('');
4261
done();
4362
}).timeout(10000);
4463

4564
it('should ignore system signals if "enableShutdownHooks" was not called', done => {
46-
const result = spawnSync('ts-node', [
47-
join(__dirname, '../src/enable-shutdown-hooks-main.ts'),
48-
'SIGINT',
49-
'NONE',
50-
]);
65+
const result = runScript('SIGINT', 'NONE');
5166
expect(result.stdout.toString().trim()).to.be.eq('');
5267
done();
5368
}).timeout(10000);
5469

5570
it('should call the correct hooks with useProcessExit option', done => {
56-
const result = spawnSync('ts-node', [
57-
join(__dirname, '../src/enable-shutdown-hooks-main.ts'),
58-
'SIGHUP',
59-
'SIGHUP',
60-
'graceful',
61-
]);
71+
const result = runScript('SIGHUP', 'SIGHUP', 'graceful');
6272
const calls = result.stdout
6373
.toString()
6474
.split('\n')

integration/lazy-modules/src/eager.module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Module, Injectable } from '@nestjs/common';
1+
import { Injectable, Module } from '@nestjs/common';
22
import { GlobalService } from './global.module';
33

44
@Injectable()

integration/nest-application/get-url/e2e/express.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Test, TestingModule } from '@nestjs/testing';
33
import { expect } from 'chai';
44
import * as express from 'express';
55
import { AppModule } from '../src/app.module';
6-
import { randomPort } from './utils';
6+
import { getAvailableIpv4Host, randomPort } from './utils';
77

88
describe('Get URL (Express Application)', () => {
99
let testModule: TestingModule;
@@ -27,8 +27,9 @@ describe('Get URL (Express Application)', () => {
2727
});
2828
it('should be able to get the IPv4 address', async () => {
2929
const app = testModule.createNestApplication(new ExpressAdapter(express()));
30-
await app.listen(port, '127.0.0.5');
31-
expect(await app.getUrl()).to.be.eql(`http://127.0.0.5:${port}`);
30+
const host = await getAvailableIpv4Host();
31+
await app.listen(port, host);
32+
expect(await app.getUrl()).to.be.eql(`http://${host}:${port}`);
3233
await app.close();
3334
});
3435
it('should return 127.0.0.1 for 0.0.0.0', async () => {

integration/nest-application/get-url/e2e/fastify.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { FastifyAdapter } from '@nestjs/platform-fastify';
22
import { Test, TestingModule } from '@nestjs/testing';
33
import { expect } from 'chai';
44
import { AppModule } from '../src/app.module';
5-
import { randomPort } from './utils';
5+
import { getAvailableIpv4Host, randomPort } from './utils';
66

77
describe('Get URL (Fastify Application)', () => {
88
let testModule: TestingModule;
@@ -20,8 +20,9 @@ describe('Get URL (Fastify Application)', () => {
2020

2121
it('should be able to get the IPv4 address', async () => {
2222
const app = testModule.createNestApplication(new FastifyAdapter());
23-
await app.listen(port, '127.0.0.5');
24-
expect(await app.getUrl()).to.be.eql(`http://127.0.0.5:${port}`);
23+
const host = await getAvailableIpv4Host();
24+
await app.listen(port, host);
25+
expect(await app.getUrl()).to.be.eql(`http://${host}:${port}`);
2526
await app.close();
2627
});
2728
it('should return 127.0.0.1 for 0.0.0.0', async () => {

integration/nest-application/get-url/e2e/utils.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,18 @@ export async function randomPort(): Promise<number> {
1515
});
1616
});
1717
}
18+
19+
export async function getAvailableIpv4Host(
20+
preferredHost = '127.0.0.5',
21+
): Promise<string> {
22+
const server = net.createServer();
23+
24+
return new Promise(resolve => {
25+
server.once('error', () => {
26+
resolve('127.0.0.1');
27+
});
28+
server.listen(0, preferredHost, () => {
29+
server.close(() => resolve(preferredHost));
30+
});
31+
});
32+
}

integration/repl/e2e/repl-process.spec.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { expect } from 'chai';
22
import { spawn } from 'child_process';
3+
import { join } from 'path';
34

45
const PROMPT = '> ';
6+
const workspaceRoot = join(__dirname, '../../..');
7+
const localPackageResolver = join(
8+
workspaceRoot,
9+
'integration/_support/register-local-packages.ts',
10+
);
11+
const replEntrypoint = join(__dirname, '../src/repl.ts');
512

613
describe('REPL process', function () {
714
let replProcess: ReturnType<typeof spawn>;
@@ -37,7 +44,26 @@ describe('REPL process', function () {
3744

3845
beforeEach(async function () {
3946
this.timeout(15000);
40-
replProcess = spawn('ts-node', ['../src/repl.ts'], { cwd: __dirname });
47+
replProcess = spawn(
48+
process.execPath,
49+
[
50+
'-r',
51+
'ts-node/register/transpile-only',
52+
'-r',
53+
localPackageResolver,
54+
replEntrypoint,
55+
],
56+
{
57+
cwd: workspaceRoot,
58+
env: {
59+
...process.env,
60+
TS_NODE_PROJECT: join(
61+
workspaceRoot,
62+
'integration/repl/tsconfig.json',
63+
),
64+
},
65+
},
66+
);
4167
await waitForReplToStart(replProcess, PROMPT);
4268
});
4369

0 commit comments

Comments
 (0)