diff --git a/packages/jsii-pacmak/lib/dependency-graph.ts b/packages/jsii-pacmak/lib/dependency-graph.ts index d00bdae639..2661bdb8d9 100644 --- a/packages/jsii-pacmak/lib/dependency-graph.ts +++ b/packages/jsii-pacmak/lib/dependency-graph.ts @@ -58,6 +58,8 @@ export interface TraverseDependencyGraphHost { export interface PackageJson { readonly dependencies?: { readonly [name: string]: string }; readonly peerDependencies?: { readonly [name: string]: string }; + readonly bundleDependencies?: string[]; + readonly bundledDependencies?: string[]; readonly [key: string]: unknown; } @@ -88,7 +90,13 @@ async function real$traverseDependencyGraph( ]); return Promise.all( Array.from(deps) - .filter((m) => !util.isBuiltinModule(m)) + // No need to pacmak the dependency if it's built-in, or if it's bundled + .filter( + (m) => + !util.isBuiltinModule(m) && + !meta.bundledDependencies?.includes(m) && + !meta.bundleDependencies?.includes(m), + ) .map(async (dep) => { const dependencyDir = await host.findDependencyDirectory( dep, diff --git a/packages/jsii-pacmak/test/dependency-graph.test.ts b/packages/jsii-pacmak/test/dependency-graph.test.ts index e46446c167..cf0eac3a97 100644 --- a/packages/jsii-pacmak/test/dependency-graph.test.ts +++ b/packages/jsii-pacmak/test/dependency-graph.test.ts @@ -113,3 +113,91 @@ test('stops traversing when callback returns false', async () => { expect(mockHost.readJson).toHaveBeenCalledTimes(2); expect(mockHost.findDependencyDirectory).toHaveBeenCalledTimes(1); }); + +test('dont call findDependencyDirectory for bundledDependencies', async () => { + const packages: Record = { + A: { + root: join(tmpdir(), 'A'), + meta: { dependencies: { B: '*' }, bundledDependencies: ['B'] }, + }, + }; + + const cb: Callback = jest.fn().mockName('callback').mockReturnValue(true); + + fakeReadJson(packages); + + // WHEN + await expect( + traverseDependencyGraph(packages.A.root, cb, mockHost), + ).resolves.not.toThrow(); + + // THEN + expect(mockHost.findDependencyDirectory).not.toHaveBeenCalled(); +}); + +test('dont call findDependencyDirectory for bundleDependencies', async () => { + const packages: Record = { + A: { + root: join(tmpdir(), 'A'), + meta: { dependencies: { B: '*' }, bundleDependencies: ['B'] }, + }, + }; + + const cb: Callback = jest.fn().mockName('callback').mockReturnValue(true); + + fakeReadJson(packages); + + // WHEN + await expect( + traverseDependencyGraph(packages.A.root, cb, mockHost), + ).resolves.not.toThrow(); + + // THEN + expect(mockHost.findDependencyDirectory).not.toHaveBeenCalled(); +}); + +test('dont call findDependencyDirectory for bundleDependencies AND bundledDependencies', async () => { + const packages: Record = { + A: { + root: join(tmpdir(), 'A'), + meta: { + dependencies: { B: '*', C: '*' }, + bundleDependencies: ['B'], + bundledDependencies: ['C'], + }, + }, + }; + + const cb: Callback = jest.fn().mockName('callback').mockReturnValue(true); + + fakeReadJson(packages); + + // WHEN + await expect( + traverseDependencyGraph(packages.A.root, cb, mockHost), + ).resolves.not.toThrow(); + + // THEN + expect(mockHost.findDependencyDirectory).not.toHaveBeenCalled(); +}); + +function fakeReadJson( + fakePackages: Record, +) { + mockHost.readJson.mockImplementation((file) => { + const result = Object.values(fakePackages).find( + ({ root }) => file === join(root, 'package.json'), + )?.meta; + return result != null + ? Promise.resolve(result) + : Promise.reject(new Error(`Unexpected file access: ${file}`)); + }); + + mockHost.findDependencyDirectory.mockImplementation(async (dep, _dir) => { + const result = fakePackages[dep]?.root; + if (result == null) { + throw new Error(`Unknown dependency: ${dep}`); + } + return result; + }); +}