From fbdd295c5820152487f3331852ce91824808ce81 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Fri, 4 Aug 2023 09:07:03 -0700 Subject: [PATCH] Pass original dependency specifier into the resolver Summary: Changelog: * **[Breaking]**: `DependencyGraph.resolveDependency` now takes a dependency object instead of a string. * **[Feature]**: Custom resolvers may access the original dependency descriptor for diagnostic purposes. Makes the full `TransformResultDependency` object ( = dependency descriptor extracted by `collectDependencies`) available to Metro's resolver, including custom resolvers. For the time being, this infrastructure will be used for improved diagnostics and explicitly *not* for any change to resolution semantics. We will likely loosen this restriction in the future (e.g. to introduce Node-compatible ESM/CJS resolution, more compliant `exports`, etc). The improved diagnostics themselves are coming in a separate diff for ease of review. Reviewed By: GijsWeterings Differential Revision: D47453640 fbshipit-source-id: a743875ec1238c9fd50a14bd250aeae2973c12ab --- docs/Resolution.md | 26 ++ packages/metro-resolver/package.json | 3 + .../src/PackageExportsResolve.js | 2 +- packages/metro-resolver/src/PackageResolve.js | 2 +- .../src/createDefaultContext.js | 7 +- .../src/errors/FailedToResolvePathError.js | 2 +- .../src/errors/InvalidPackageError.js | 2 +- .../src/errors/formatFileCandidates.js | 2 +- packages/metro-resolver/src/resolveAsset.js | 2 +- packages/metro-resolver/src/types.js | 14 +- packages/metro-resolver/types/types.d.ts | 12 +- packages/metro/src/DeltaBundler/Graph.js | 2 +- .../__tests__/DeltaBundler-test.js | 4 +- .../__tests__/DeltaCalculator-context-test.js | 4 +- .../__tests__/DeltaCalculator-test.js | 9 +- .../src/DeltaBundler/__tests__/Graph-test.js | 4 +- .../DeltaBundler/__tests__/resolver-test.js | 421 +++++++++++------- packages/metro/src/DeltaBundler/types.flow.js | 5 +- packages/metro/src/HmrServer.js | 9 +- .../ModuleGraph/worker/collectDependencies.js | 3 +- packages/metro/src/Server.js | 5 +- .../metro/src/Server/__tests__/Server-test.js | 11 +- .../metro/src/__tests__/HmrServer-test.js | 10 +- packages/metro/src/lib/transformHelpers.js | 9 +- .../metro/src/node-haste/DependencyGraph.js | 10 +- .../DependencyGraph/ModuleResolution.js | 83 ++-- packages/metro/src/node-haste/Package.js | 2 +- packages/metro/types/DeltaBundler/types.d.ts | 11 +- .../types/node-haste/DependencyGraph.d.ts | 7 +- 29 files changed, 434 insertions(+), 249 deletions(-) diff --git a/docs/Resolution.md b/docs/Resolution.md index 7ed2bda3ad..bd2fe193ae 100644 --- a/docs/Resolution.md +++ b/docs/Resolution.md @@ -267,6 +267,32 @@ When calling the default resolver with a non-null `resolveRequest` function, it Inside a custom resolver, `resolveRequest` is set to the default resolver function, for easy chaining and customization. +#### `dependency: ?Dependency` + +A dependency descriptor corresponding to the current resolution request. This is provided for diagnostic purposes *only* and may not be used for semantic purposes. See the [Caching](#caching) section for more information. + +```flow +type Dependency = { + // The literal name provided to a require or import call. For example 'foo' in + // case of `require('foo')`. + name: string, + + data: { + // A locally unique key for this dependency within the origin module. + key: string, + + // Source locations from the Babel AST, relative to the origin module, where + // this dependency was encountered. This may be an empty array. + locs: $ReadOnlyArray, + + asyncType: 'async' | 'prefetch' | 'weak' | null, + + // Other properties are considered internal and may change in the future. + ... + }, +}; +``` + ## Caching Resolver results may be cached under the following conditions: diff --git a/packages/metro-resolver/package.json b/packages/metro-resolver/package.json index 28186d9167..7d6a0b9b74 100644 --- a/packages/metro-resolver/package.json +++ b/packages/metro-resolver/package.json @@ -14,5 +14,8 @@ "license": "MIT", "engines": { "node": ">=18" + }, + "devDependencies": { + "metro": "0.77.0" } } diff --git a/packages/metro-resolver/src/PackageExportsResolve.js b/packages/metro-resolver/src/PackageExportsResolve.js index e6a0a282fb..803296f4d9 100644 --- a/packages/metro-resolver/src/PackageExportsResolve.js +++ b/packages/metro-resolver/src/PackageExportsResolve.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict + * @flow strict-local * @format * @oncall react_native */ diff --git a/packages/metro-resolver/src/PackageResolve.js b/packages/metro-resolver/src/PackageResolve.js index 701014637b..55d5e434c2 100644 --- a/packages/metro-resolver/src/PackageResolve.js +++ b/packages/metro-resolver/src/PackageResolve.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict + * @flow strict-local * @format * @oncall react_native */ diff --git a/packages/metro-resolver/src/createDefaultContext.js b/packages/metro-resolver/src/createDefaultContext.js index 44bf8324a1..d318774b89 100644 --- a/packages/metro-resolver/src/createDefaultContext.js +++ b/packages/metro-resolver/src/createDefaultContext.js @@ -9,6 +9,7 @@ * @oncall react_native */ +import type {TransformResultDependency} from 'metro/src/DeltaBundler/types.flow'; import type {ResolutionContext} from './types'; import {redirectModulePath} from './PackageResolve'; @@ -23,10 +24,14 @@ type PartialContext = $ReadOnly<{ * As context values can be overridden by callers, this occurs externally to * `resolve.js`. */ -function createDefaultContext(context: PartialContext): ResolutionContext { +function createDefaultContext( + context: PartialContext, + dependency: TransformResultDependency, +): ResolutionContext { return { redirectModulePath: (modulePath: string) => redirectModulePath(context, modulePath), + dependency, ...context, }; } diff --git a/packages/metro-resolver/src/errors/FailedToResolvePathError.js b/packages/metro-resolver/src/errors/FailedToResolvePathError.js index e4091f1cd5..00f1563446 100644 --- a/packages/metro-resolver/src/errors/FailedToResolvePathError.js +++ b/packages/metro-resolver/src/errors/FailedToResolvePathError.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict + * @flow strict-local * @format * @oncall react_native */ diff --git a/packages/metro-resolver/src/errors/InvalidPackageError.js b/packages/metro-resolver/src/errors/InvalidPackageError.js index 7a08b55517..75388c3760 100644 --- a/packages/metro-resolver/src/errors/InvalidPackageError.js +++ b/packages/metro-resolver/src/errors/InvalidPackageError.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict + * @flow strict-local * @format * @oncall react_native */ diff --git a/packages/metro-resolver/src/errors/formatFileCandidates.js b/packages/metro-resolver/src/errors/formatFileCandidates.js index 92396a8f80..f4ecfcf80a 100644 --- a/packages/metro-resolver/src/errors/formatFileCandidates.js +++ b/packages/metro-resolver/src/errors/formatFileCandidates.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict + * @flow strict-local * @format * @oncall react_native */ diff --git a/packages/metro-resolver/src/resolveAsset.js b/packages/metro-resolver/src/resolveAsset.js index 65308ed8c3..61ce1ab854 100644 --- a/packages/metro-resolver/src/resolveAsset.js +++ b/packages/metro-resolver/src/resolveAsset.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict + * @flow strict-local * @format * @oncall react_native */ diff --git a/packages/metro-resolver/src/types.js b/packages/metro-resolver/src/types.js index 69b1c8c3bb..69d71922d2 100644 --- a/packages/metro-resolver/src/types.js +++ b/packages/metro-resolver/src/types.js @@ -4,13 +4,15 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict + * @flow strict-local * @format * @oncall react_native */ 'use strict'; +import type {TransformResultDependency} from 'metro/src/DeltaBundler/types.flow'; + export type Result<+TResolution, +TCandidates> = | {+type: 'resolved', +resolution: TResolution} | {+type: 'failed', +candidates: TCandidates}; @@ -123,6 +125,13 @@ export type ResolutionContext = $ReadOnly<{ */ getPackageForModule: (modulePath: string) => ?PackageInfo, + /** + * The dependency descriptor, within the origin module, corresponding to the + * current resolution request. This is provided for diagnostic purposes ONLY + * and may not be used for resolution purposes. + */ + dependency?: TransformResultDependency, + /** * The ordered list of fields to read in `package.json` to resolve a main * entry point based on the "browser" field spec. @@ -131,7 +140,8 @@ export type ResolutionContext = $ReadOnly<{ /** * Full path of the module that is requiring or importing the module to be - * resolved. + * resolved. This may not be the only place this dependency was found, + * as resolutions can be cached. */ originModulePath: string, diff --git a/packages/metro-resolver/types/types.d.ts b/packages/metro-resolver/types/types.d.ts index 9285cf67f3..97a14d559e 100644 --- a/packages/metro-resolver/types/types.d.ts +++ b/packages/metro-resolver/types/types.d.ts @@ -8,6 +8,8 @@ * @oncall react_native */ +import {TransformResultDependency} from 'metro'; + export type Result = | {readonly type: 'resolved'; readonly resolution: TResolution} | {readonly type: 'failed'; readonly candidates: TCandidates}; @@ -102,6 +104,13 @@ export interface ResolutionContext { */ readonly getPackageForModule: (modulePath: string) => PackageInfo | null; + /** + * The dependency descriptor, within the origin module, corresponding to the + * current resolution request. This is provided for diagnostic purposes ONLY + * and may not be used for resolution purposes. + */ + readonly dependency?: TransformResultDependency; + /** * The ordered list of fields to read in `package.json` to resolve a main * entry point based on the "browser" field spec. @@ -110,7 +119,8 @@ export interface ResolutionContext { /** * Full path of the module that is requiring or importing the module to be - * resolved. + * resolved. This may not be the only place this dependency was found, + * as resolutions can be cached. */ readonly originModulePath: string; diff --git a/packages/metro/src/DeltaBundler/Graph.js b/packages/metro/src/DeltaBundler/Graph.js index 8e01c4aca1..50c3a23ca7 100644 --- a/packages/metro/src/DeltaBundler/Graph.js +++ b/packages/metro/src/DeltaBundler/Graph.js @@ -574,7 +574,7 @@ export class Graph { } else { try { resolvedDep = { - absolutePath: options.resolve(parentPath, dep.name).filePath, + absolutePath: options.resolve(parentPath, dep).filePath, data: dep, }; diff --git a/packages/metro/src/DeltaBundler/__tests__/DeltaBundler-test.js b/packages/metro/src/DeltaBundler/__tests__/DeltaBundler-test.js index 02a33057fe..ab862aab52 100644 --- a/packages/metro/src/DeltaBundler/__tests__/DeltaBundler-test.js +++ b/packages/metro/src/DeltaBundler/__tests__/DeltaBundler-test.js @@ -11,6 +11,8 @@ 'use strict'; +import type {TransformResultDependency} from '../types.flow'; + jest.mock('../DeltaCalculator'); const DeltaBundler = require('../../DeltaBundler'); @@ -33,7 +35,7 @@ describe('DeltaBundler', () => { unstable_enablePackageExports: false, lazy: false, onProgress: null, - resolve: (from: string, to: string) => { + resolve: (from: string, dependency: TransformResultDependency) => { throw new Error('Never called'); }, shallow: false, diff --git a/packages/metro/src/DeltaBundler/__tests__/DeltaCalculator-context-test.js b/packages/metro/src/DeltaBundler/__tests__/DeltaCalculator-context-test.js index 9b58e96f19..41f8eddc62 100644 --- a/packages/metro/src/DeltaBundler/__tests__/DeltaCalculator-context-test.js +++ b/packages/metro/src/DeltaBundler/__tests__/DeltaCalculator-context-test.js @@ -11,7 +11,7 @@ 'use strict'; -import type {Options} from '../types.flow'; +import type {Options, TransformResultDependency} from '../types.flow'; import type {Result} from '../Graph'; import CountingSet from '../../lib/CountingSet'; import {Graph} from '../Graph'; @@ -41,7 +41,7 @@ describe('DeltaCalculator + require.context', () => { unstable_enablePackageExports: false, lazy: false, onProgress: null, - resolve: (from: string, to: string) => { + resolve: (from: string, to: TransformResultDependency) => { throw new Error('Never called'); }, shallow: false, diff --git a/packages/metro/src/DeltaBundler/__tests__/DeltaCalculator-test.js b/packages/metro/src/DeltaBundler/__tests__/DeltaCalculator-test.js index 6323b7b2b2..7c00ffba74 100644 --- a/packages/metro/src/DeltaBundler/__tests__/DeltaCalculator-test.js +++ b/packages/metro/src/DeltaBundler/__tests__/DeltaCalculator-test.js @@ -9,7 +9,12 @@ * @oncall react_native */ -import type {Module, Options, Dependency} from '../types.flow'; +import type { + Module, + Options, + Dependency, + TransformResultDependency, +} from '../types.flow'; import type {Graph as GraphType, Result} from '../Graph'; import path from 'path'; @@ -34,7 +39,7 @@ describe.each(['linux', 'win32'])('DeltaCalculator (%s)', osPlatform => { unstable_enablePackageExports: true, lazy: false, onProgress: null, - resolve: (from: string, to: string) => { + resolve: (from: string, to: TransformResultDependency) => { throw new Error('Never called'); }, shallow: false, diff --git a/packages/metro/src/DeltaBundler/__tests__/Graph-test.js b/packages/metro/src/DeltaBundler/__tests__/Graph-test.js index dc1b814a01..e15c826fbc 100644 --- a/packages/metro/src/DeltaBundler/__tests__/Graph-test.js +++ b/packages/metro/src/DeltaBundler/__tests__/Graph-test.js @@ -348,9 +348,9 @@ beforeEach(async () => { unstable_enablePackageExports: false, lazy: false, onProgress: null, - resolve: (from: string, to: string) => { + resolve: (from: string, to: TransformResultDependency) => { const deps = getMockDependency(from); - const {path} = deps.filter(dep => dep.name === to)[0]; + const {path} = deps.filter(dep => dep.name === to.name)[0]; if (!mockedDependencies.has(path)) { throw new Error(`Dependency not found: ${from} -> ${path}`); diff --git a/packages/metro/src/DeltaBundler/__tests__/resolver-test.js b/packages/metro/src/DeltaBundler/__tests__/resolver-test.js index 3d63e50e20..33b77eccf0 100644 --- a/packages/metro/src/DeltaBundler/__tests__/resolver-test.js +++ b/packages/metro/src/DeltaBundler/__tests__/resolver-test.js @@ -12,6 +12,7 @@ 'use strict'; import type {ResolverInputOptions} from '../../shared/types.flow'; +import type {TransformResultDependency} from '../types.flow'; import type {InputConfigT} from 'metro-config/src/configTypes.flow'; const {getDefaultConfig, mergeConfig} = require('metro-config'); @@ -41,6 +42,17 @@ type MockFSDirContents = $ReadOnly<{ [name: string]: string | MockFSDirContents, }>; +function dep(name: string): TransformResultDependency { + return { + name, + data: { + asyncType: null, + key: name, + locs: [], + }, + }; +} + ['linux', 'win32'].forEach(osPlatform => { function setMockFileSystem(object: MockFSDirContents) { const root = p('/root'); @@ -103,13 +115,13 @@ type MockFSDirContents = $ReadOnly<{ return { resolve: ( from: string, - to: string, + dependency: TransformResultDependency, resolverOptions?: ResolverInputOptions = {}, options: void | {assumeFlatNodeModules: boolean}, ) => dependencyGraph.resolveDependency( from, - to, + dependency, platform ?? null, resolverOptions, options, @@ -191,7 +203,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), './a.js')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./a.js'))).toEqual({ type: 'sourceFile', filePath: p('/root/a.js'), }); @@ -205,7 +217,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), './a')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./a'))).toEqual({ type: 'sourceFile', filePath: p('/root/a.js'), }); @@ -220,7 +232,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), './a')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./a'))).toEqual({ type: 'sourceFile', filePath: p('/root/a.js'), }); @@ -243,12 +255,12 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); expect( - resolver.resolve(p('/root/folderA/folderB/foo.js'), '..'), + resolver.resolve(p('/root/folderA/folderB/foo.js'), dep('..')), ).toEqual({type: 'sourceFile', filePath: p('/root/folderA/index.js')}); expect( - resolver.resolve(p('/root/folderA/folderB/index.js'), '..'), + resolver.resolve(p('/root/folderA/folderB/index.js'), dep('..')), ).toEqual({type: 'sourceFile', filePath: p('/root/folderA/index.js')}); - expect(resolver.resolve(p('/root/folderA/foo.js'), '..')).toEqual({ + expect(resolver.resolve(p('/root/folderA/foo.js'), dep('..'))).toEqual({ type: 'sourceFile', filePath: p('/root/index.js'), }); @@ -262,7 +274,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); - expect(resolver.resolve(p('/root/foo.js'), '.')).toEqual({ + expect(resolver.resolve(p('/root/foo.js'), dep('.'))).toEqual({ type: 'sourceFile', filePath: p('/root/index.js'), }); @@ -280,11 +292,11 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); - expect(resolver.resolve(p('/root/foo.js'), '.')).toEqual({ + expect(resolver.resolve(p('/root/foo.js'), dep('.'))).toEqual({ type: 'sourceFile', filePath: p('/root/index.js'), }); - expect(resolver.resolve(p('/root/folderA/foo.js'), '.')).toEqual({ + expect(resolver.resolve(p('/root/folderA/foo.js'), dep('.'))).toEqual({ type: 'sourceFile', filePath: p('/root/folderA/index.js'), }); @@ -300,7 +312,7 @@ type MockFSDirContents = $ReadOnly<{ const {resolve, end} = await createResolver({ resolver: {sourceExts: ['another', 'js']}, }); - expect(resolve(p('/root/index.js'), './a')).toEqual({ + expect(resolve(p('/root/index.js'), dep('./a'))).toEqual({ type: 'sourceFile', filePath: p('/root/a.another'), }); @@ -309,7 +321,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver({ resolver: {sourceExts: ['js', 'another']}, }); - expect(resolver.resolve(p('/root/index.js'), './a')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./a'))).toEqual({ type: 'sourceFile', filePath: p('/root/a.js'), }); @@ -323,7 +335,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); expect(() => - resolver.resolve(p('/root/index.js'), './a.another'), + resolver.resolve(p('/root/index.js'), dep('./a.another')), ).toThrowErrorMatchingSnapshot(); }); @@ -337,18 +349,22 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), './folder/foo')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('./folder/foo')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/folder/foo.js'), }); - expect(resolver.resolve(p('/root/index.js'), './folder')).toEqual({ - type: 'sourceFile', - filePath: p('/root/folder/index.js'), - }); - expect(resolver.resolve(p('/root/index.js'), './folder/')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./folder'))).toEqual({ type: 'sourceFile', filePath: p('/root/folder/index.js'), }); + expect(resolver.resolve(p('/root/index.js'), dep('./folder/'))).toEqual( + { + type: 'sourceFile', + filePath: p('/root/folder/index.js'), + }, + ); }); it('resolves files when there is a folder with the same name', async () => { @@ -361,11 +377,13 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), './folder')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./folder'))).toEqual({ type: 'sourceFile', filePath: p('/root/folder.js'), }); - expect(resolver.resolve(p('/root/index.js'), './folder.js')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('./folder.js')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/folder.js'), }); @@ -386,10 +404,12 @@ type MockFSDirContents = $ReadOnly<{ additionalExts: ['cjs'], }, }); - expect(resolver.resolve(p('/root/index.js'), './a.cjs')).toEqual({ - type: 'sourceFile', - filePath: p('/root/a.cjs'), - }); + expect(resolver.resolve(p('/root/index.js'), dep('./a.cjs'))).toEqual( + { + type: 'sourceFile', + filePath: p('/root/a.cjs'), + }, + ); }); it('fails when implicitly requiring a file outside sourceExts', async () => { @@ -407,7 +427,7 @@ type MockFSDirContents = $ReadOnly<{ }, }); expect(() => - resolver.resolve(p('/root/index.js'), './a'), + resolver.resolve(p('/root/index.js'), dep('./a')), ).toThrowErrorMatchingSnapshot(); }); }); @@ -424,7 +444,10 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); expect( - resolver.resolve(p('/root/index.js'), p('/root/folder/index.js')), + resolver.resolve( + p('/root/index.js'), + dep(p('/root/folder/index.js')), + ), ).toEqual({type: 'sourceFile', filePath: p('/root/folder/index.js')}); }); }); @@ -437,9 +460,9 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), './package.json')).toEqual( - {type: 'sourceFile', filePath: p('/root/package.json')}, - ); + expect( + resolver.resolve(p('/root/index.js'), dep('./package.json')), + ).toEqual({type: 'sourceFile', filePath: p('/root/package.json')}); }); it('finds nested packages in node_modules', async () => { @@ -472,21 +495,21 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'bar')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('bar'))).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/bar/index.js'), }); expect(() => - resolver.resolve(p('/root/index.js'), 'qux'), + resolver.resolve(p('/root/index.js'), dep('qux')), ).toThrowErrorMatchingSnapshot(); expect( - resolver.resolve(p('/root/node_modules/foo/index.js'), 'bar'), + resolver.resolve(p('/root/node_modules/foo/index.js'), dep('bar')), ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/foo/node_modules/bar/index.js'), }); expect( - resolver.resolve(p('/root/node_modules/foo/index.js'), 'baz'), + resolver.resolve(p('/root/node_modules/foo/index.js'), dep('baz')), ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/baz/index.js'), @@ -506,11 +529,13 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'foo/lib/foo')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('foo/lib/foo')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/foo/lib/foo.js'), }); - expect(resolver.resolve(p('/root/index.js'), 'foo/lib')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('foo/lib'))).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/foo/lib/index.js'), }); @@ -539,14 +564,14 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/lib/index.js'), 'foo')).toEqual({ + expect(resolver.resolve(p('/root/lib/index.js'), dep('foo'))).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/foo/index.js'), }); expect( resolver.resolve( p('/root/lib/subfolder/anotherSubfolder/index.js'), - 'foo', + dep('foo'), ), ).toEqual({ type: 'sourceFile', @@ -578,7 +603,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); expect( - resolver.resolve(p('/root/lib/index.js'), 'foo', undefined, { + resolver.resolve(p('/root/lib/index.js'), dep('foo'), undefined, { assumeFlatNodeModules: true, }), ).toEqual({ @@ -588,7 +613,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/lib/subfolder/anotherSubfolder/index.js'), - 'foo', + dep('foo'), undefined, {assumeFlatNodeModules: true}, ), @@ -610,7 +635,7 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'sha.js')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('sha.js'))).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/sha.js/index.js'), }); @@ -628,7 +653,7 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'Y')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('Y'))).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/Y/index.js'), }); @@ -650,12 +675,12 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); // TODO: Should we fail here? - expect(resolver.resolve(p('/root/index.js'), 'foo')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('foo'))).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/foo/index.js'), }); expect(() => - resolver.resolve(p('/root/index.js'), 'invalidName'), + resolver.resolve(p('/root/index.js'), dep('invalidName')), ).toThrowErrorMatchingSnapshot(); }); @@ -672,7 +697,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); // TODO: Is this behaviour correct? - expect(resolver.resolve(p('/root/index.js'), 'foo')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('foo'))).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/foo/index.js'), }); @@ -690,7 +715,7 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('aPackage'))).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/index.js'), }); @@ -713,7 +738,7 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('aPackage'))).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/lib/index.js'), }); @@ -738,7 +763,7 @@ type MockFSDirContents = $ReadOnly<{ additionalExts: ['cjs'], }, }); - expect(resolver.resolve(p('/root/index.js'), 'foo')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('foo'))).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/foo/main.cjs'), }); @@ -760,11 +785,13 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'leftpad.js')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('leftpad.js')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/leftpad.js/index.js'), }); - expect(resolver.resolve(p('/root/index.js'), 'x.y.z')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('x.y.z'))).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/x.y.z/index.js'), }); @@ -786,7 +813,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); expect( - resolver.resolve(p('/root/index.js'), './node_modules/aPackage'), + resolver.resolve(p('/root/index.js'), dep('./node_modules/aPackage')), ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/main.js'), @@ -808,7 +835,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); expect( - resolver.resolve(p('/root/index.js'), 'aPackage/lib/foo/bar'), + resolver.resolve(p('/root/index.js'), dep('aPackage/lib/foo/bar')), ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/lib/foo/bar.js'), @@ -832,7 +859,9 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('aPackage')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/client.js'), }); @@ -854,7 +883,9 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('aPackage')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/client.js'), }); @@ -875,7 +906,9 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('aPackage')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/client.js'), }); @@ -898,13 +931,15 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('aPackage')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/client.js'), }); // TODO: Is this behaviour correct? expect( - resolver.resolve(p('/root/index.js'), 'aPackage/main.js'), + resolver.resolve(p('/root/index.js'), dep('aPackage/main.js')), ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/main.js'), @@ -928,12 +963,14 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('aPackage')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/client.js'), }); expect( - resolver.resolve(p('/root/index.js'), 'aPackage/main'), + resolver.resolve(p('/root/index.js'), dep('aPackage/main')), ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/client.js'), @@ -971,7 +1008,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - './main.js', + dep('./main.js'), ), ).toEqual({ type: 'sourceFile', @@ -981,13 +1018,13 @@ type MockFSDirContents = $ReadOnly<{ expect(() => resolver.resolve( p('/root/node_modules/aPackage/index.js'), - './foo.js', + dep('./foo.js'), ), ).toThrowErrorMatchingSnapshot(); expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - './dir/file', + dep('./dir/file'), ), ).toEqual({ type: 'sourceFile', @@ -996,7 +1033,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - './dir', + dep('./dir'), ), ).toEqual({ type: 'sourceFile', @@ -1006,7 +1043,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - './dir/index', + dep('./dir/index'), ), ).toEqual({ type: 'sourceFile', @@ -1015,7 +1052,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/dir/index.js'), - '../main', + dep('../main'), ), ).toEqual({ type: 'sourceFile', @@ -1053,7 +1090,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - 'left-pad', + dep('left-pad'), ), ).toEqual({ type: 'sourceFile', @@ -1063,7 +1100,7 @@ type MockFSDirContents = $ReadOnly<{ expect(() => resolver.resolve( p('/root/node_modules/aPackage/index.js'), - 'left-pad/main', + dep('left-pad/main'), ), ).toThrowErrorMatchingSnapshot(); }); @@ -1089,7 +1126,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - 'left-pad', + dep('left-pad'), ), ).toEqual({ type: 'sourceFile', @@ -1128,7 +1165,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - 'left-pad', + dep('left-pad'), ), ).toEqual({ type: 'sourceFile', @@ -1139,7 +1176,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - 'left-pad/foo', + dep('left-pad/foo'), ), ).toEqual({ type: 'sourceFile', @@ -1171,20 +1208,20 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - './foo', + dep('./foo'), ), ).toEqual({ type: 'sourceFile', filePath: p('/root/emptyModule.js'), }); expect( - resolver.resolve(p('/root/index.js'), 'aPackage/foo'), + resolver.resolve(p('/root/index.js'), dep('aPackage/foo')), ).toEqual({ type: 'sourceFile', filePath: p('/root/emptyModule.js'), }); expect( - resolver.resolve(p('/root/index.js'), 'aPackage/foo.js'), + resolver.resolve(p('/root/index.js'), dep('aPackage/foo.js')), ).toEqual({ type: 'sourceFile', filePath: p('/root/emptyModule.js'), @@ -1213,7 +1250,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - 'left-pad', + dep('left-pad'), ), ).toEqual({ type: 'sourceFile', @@ -1243,7 +1280,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - 'left-pad', + dep('left-pad'), ), ).toEqual({ type: 'sourceFile', @@ -1274,14 +1311,17 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - 'left-pad', + dep('left-pad'), ), ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/left-pad-custom.js'), }); expect( - resolver.resolve(p('/root/node_modules/aPackage/index.js'), 'jest'), + resolver.resolve( + p('/root/node_modules/aPackage/index.js'), + dep('jest'), + ), ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/jest-browser.js'), @@ -1306,7 +1346,7 @@ type MockFSDirContents = $ReadOnly<{ resolver: {resolverMainFields: ['custom-field']}, }); expect( - resolver.resolve(p('/root/node_modules/index.js'), 'aPackage'), + resolver.resolve(p('/root/node_modules/index.js'), dep('aPackage')), ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/aPackage/main-custom.js'), @@ -1323,15 +1363,17 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver({}, 'ios'); - expect(resolver.resolve(p('/root/index.js'), './foo')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./foo'))).toEqual({ type: 'sourceFile', filePath: p('/root/foo.ios.js'), }); // TODO: Is this behaviour expected? expect(() => - resolver.resolve(p('/root/index.js'), './foo.js'), + resolver.resolve(p('/root/index.js'), dep('./foo.js')), ).toThrowErrorMatchingSnapshot(); - expect(resolver.resolve(p('/root/index.js'), './foo.ios.js')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('./foo.ios.js')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/foo.ios.js'), }); @@ -1346,16 +1388,18 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver({}, 'ios'); - expect(resolver.resolve(p('/root/index.js'), './foo')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./foo'))).toEqual({ type: 'sourceFile', filePath: p('/root/foo.ios.js'), }); // TODO: Is this behaviour expected? - expect(resolver.resolve(p('/root/index.js'), './foo.js')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./foo.js'))).toEqual({ type: 'sourceFile', filePath: p('/root/foo.js'), }); - expect(resolver.resolve(p('/root/index.js'), './foo.ios.js')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('./foo.ios.js')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/foo.ios.js'), }); @@ -1370,11 +1414,13 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver({}, 'ios'); - expect(resolver.resolve(p('/root/index.js'), './dir/index')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('./dir/index')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/dir/index.ios.js'), }); - expect(resolver.resolve(p('/root/index.js'), './dir')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./dir'))).toEqual({ type: 'sourceFile', filePath: p('/root/dir/index.ios.js'), }); @@ -1395,7 +1441,7 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver({}, 'ios'); - expect(resolver.resolve(p('/root/index.js'), 'foo')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('foo'))).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/foo/main.ios.js'), }); @@ -1418,7 +1464,9 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver({}, 'ios'); // TODO: Is this behaviour expected? - expect(() => resolver.resolve(p('/root/index.js'), 'foo')).toThrow(); + expect(() => + resolver.resolve(p('/root/index.js'), dep('foo')), + ).toThrow(); }); it('does not resolve when the browser mappings of node_modules packages', async () => { @@ -1441,7 +1489,7 @@ type MockFSDirContents = $ReadOnly<{ // TODO: Is this behaviour expected? expect(() => - resolver.resolve(p('/root/index.js'), 'foo/bar'), + resolver.resolve(p('/root/index.js'), dep('foo/bar')), ).toThrow(); }); @@ -1456,7 +1504,7 @@ type MockFSDirContents = $ReadOnly<{ {resolver: {platforms: ['playstation']}}, 'playstation', ); - expect(resolve(p('/root/index.js'), './foo')).toEqual({ + expect(resolve(p('/root/index.js'), dep('./foo'))).toEqual({ type: 'sourceFile', filePath: p('/root/foo.playstation.js'), }); @@ -1467,7 +1515,7 @@ type MockFSDirContents = $ReadOnly<{ 'xbox', ); // TODO: Is this behaviour expected? - expect(resolver.resolve(p('/root/index.js'), './foo')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./foo'))).toEqual({ type: 'sourceFile', filePath: p('/root/foo.xbox.js'), }); @@ -1482,7 +1530,9 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), './asset.png')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('./asset.png')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/asset.png'), }); @@ -1498,12 +1548,12 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), './a.png')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./a.png'))).toEqual({ type: 'sourceFile', filePath: p('/root/a@1.5x.png'), }); expect(() => - resolver.resolve(p('/root/index.js'), './a@1.5x.png'), + resolver.resolve(p('/root/index.js'), dep('./a@1.5x.png')), ).toThrowErrorMatchingSnapshot(); }); @@ -1517,12 +1567,12 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), './c.png')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('./c.png'))).toEqual({ type: 'sourceFile', filePath: p('/root/c.png'), }); expect(() => - resolver.resolve(p('/root/index.js'), './c@2x.png'), + resolver.resolve(p('/root/index.js'), dep('./c@2x.png')), ).toThrowErrorMatchingSnapshot(); }); @@ -1536,7 +1586,7 @@ type MockFSDirContents = $ReadOnly<{ // TODO: Is this behaviour correct? expect(() => - resolver.resolve(p('/root/index.js'), './asset.PNG'), + resolver.resolve(p('/root/index.js'), dep('./asset.PNG')), ).toThrowErrorMatchingSnapshot(); }); @@ -1549,12 +1599,14 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver({resolver: {assetExts: ['ast']}}); - expect(resolver.resolve(p('/root/index.js'), './asset1.ast')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('./asset1.ast')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/asset1.ast'), }); expect(() => - resolver.resolve(p('/root/index.js'), './asset2.png'), + resolver.resolve(p('/root/index.js'), dep('./asset2.png')), ).toThrowErrorMatchingSnapshot(); }); @@ -1572,7 +1624,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); expect( - resolver.resolve(p('/root/folder/index.js'), 'foo/asset.png'), + resolver.resolve(p('/root/folder/index.js'), dep('foo/asset.png')), ).toEqual({ type: 'sourceFile', filePath: p('/root/node_modules/foo/asset.png'), @@ -1595,17 +1647,19 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ - type: 'sourceFile', - filePath: p('/root/aPackage/main.js'), - }); - expect(resolver.resolve(p('/root/index.js'), 'aPackage/')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('aPackage'))).toEqual({ type: 'sourceFile', filePath: p('/root/aPackage/main.js'), }); - expect(resolver.resolve(p('/root/index.js'), 'aPackage/other')).toEqual( - {type: 'sourceFile', filePath: p('/root/aPackage/other.js')}, + expect(resolver.resolve(p('/root/index.js'), dep('aPackage/'))).toEqual( + { + type: 'sourceFile', + filePath: p('/root/aPackage/main.js'), + }, ); + expect( + resolver.resolve(p('/root/index.js'), dep('aPackage/other')), + ).toEqual({type: 'sourceFile', filePath: p('/root/aPackage/other.js')}); }); it('resolves main package module to index.js by default', async () => { @@ -1618,7 +1672,7 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('aPackage'))).toEqual({ type: 'sourceFile', filePath: p('/root/aPackage/index.js'), }); @@ -1639,9 +1693,9 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); expect(() => - resolver.resolve(p('/root/index.js'), 'aPackage'), + resolver.resolve(p('/root/index.js'), dep('aPackage')), ).toThrowErrorMatchingSnapshot(); - expect(resolver.resolve(p('/root/index.js'), 'bPackage')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('bPackage'))).toEqual({ type: 'sourceFile', filePath: p('/root/randomFolderName/index.js'), }); @@ -1659,7 +1713,7 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('aPackage'))).toEqual({ type: 'sourceFile', filePath: p('/root/aPackage/lib/index.js'), }); @@ -1679,11 +1733,13 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'leftpad.js')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('leftpad.js')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/leftpad.js/index.js'), }); - expect(resolver.resolve(p('/root/index.js'), 'x.y.z')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('x.y.z'))).toEqual({ type: 'sourceFile', filePath: p('/root/x.y.z/index.js'), }); @@ -1703,12 +1759,17 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), './aPackage')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('./aPackage')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/aPackage/main.js'), }); expect( - resolver.resolve(p('/root/aPackage/index.js'), '../anotherPackage'), + resolver.resolve( + p('/root/aPackage/index.js'), + dep('../anotherPackage'), + ), ).toEqual({ type: 'sourceFile', filePath: p('/root/anotherPackage/main.js'), @@ -1790,7 +1851,7 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'foo')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('foo'))).toEqual({ type: 'sourceFile', filePath: p('/root/foo/index.js'), }); @@ -1809,7 +1870,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(); expect( - resolver.resolve(p('/root/index.js'), 'aPackage/lib/foo/bar'), + resolver.resolve(p('/root/index.js'), dep('aPackage/lib/foo/bar')), ).toEqual({ type: 'sourceFile', filePath: p('/root/aPackage/lib/foo/bar.js'), @@ -1831,7 +1892,9 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('aPackage')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/aPackage/client.js'), }); @@ -1852,12 +1915,14 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('aPackage')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/aPackage/client.js'), }); expect( - resolver.resolve(p('/root/index.js'), 'aPackage/main'), + resolver.resolve(p('/root/index.js'), dep('aPackage/main')), ).toEqual({ type: 'sourceFile', filePath: p('/root/aPackage/client.js'), @@ -1884,7 +1949,7 @@ type MockFSDirContents = $ReadOnly<{ }); expect( - resolver.resolve(p('/root/aPackage/index.js'), 'left-pad'), + resolver.resolve(p('/root/aPackage/index.js'), dep('left-pad')), ).toEqual({ type: 'sourceFile', filePath: p('/root/aPackage/left-pad-custom.js'), @@ -1913,7 +1978,9 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(config); - expect(resolver.resolve(p('/root/index.js'), 'hasteModule')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('hasteModule')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/hasteModule.js'), }); @@ -1929,10 +1996,10 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(config); expect(() => - resolver.resolve(p('/root/index.js'), 'hasteModule.js'), + resolver.resolve(p('/root/index.js'), dep('hasteModule.js')), ).toThrowErrorMatchingSnapshot(); expect(() => - resolver.resolve(p('/root/lib.js'), 'invalidName'), + resolver.resolve(p('/root/lib.js'), dep('invalidName')), ).toThrowErrorMatchingSnapshot(); }); @@ -1943,7 +2010,9 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(config); - expect(resolver.resolve(p('/root/index.js'), 'hasteModule')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('hasteModule')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/dir/subdir/hasteModule.js'), }); @@ -1983,7 +2052,9 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(config); - expect(resolver.resolve(p('/root/index.js'), 'hasteModule')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('hasteModule')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/hasteModule.js'), }); @@ -2023,14 +2094,16 @@ type MockFSDirContents = $ReadOnly<{ }); const {resolve, end} = await createResolver(config, 'ios'); - expect(resolve(p('/root/index.js'), 'hasteModule')).toEqual({ + expect(resolve(p('/root/index.js'), dep('hasteModule'))).toEqual({ type: 'sourceFile', filePath: p('/root/hasteModule.ios.js'), }); end(); resolver = await createResolver(config, 'android'); - expect(resolver.resolve(p('/root/index.js'), 'hasteModule')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('hasteModule')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/aPackage/index.js'), }); @@ -2044,14 +2117,16 @@ type MockFSDirContents = $ReadOnly<{ }); const {resolve, end} = await createResolver(config, 'ios'); - expect(resolve(p('/root/index.js'), 'hasteModule')).toEqual({ + expect(resolve(p('/root/index.js'), dep('hasteModule'))).toEqual({ type: 'sourceFile', filePath: p('/root/hasteModule.ios.js'), }); end(); resolver = await createResolver(config, 'android'); - expect(resolver.resolve(p('/root/index.js'), 'hasteModule')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('hasteModule')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/hasteModule.js'), }); @@ -2091,7 +2166,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver(config); expect(() => - resolver.resolve(p('/root/index.js'), 'hasteModule'), + resolver.resolve(p('/root/index.js'), dep('hasteModule')), ).toThrowErrorMatchingSnapshot(); }); @@ -2108,7 +2183,9 @@ type MockFSDirContents = $ReadOnly<{ }); resolver = await createResolver(config); - expect(resolver.resolve(p('/root/index.js'), 'hasteModule')).toEqual({ + expect( + resolver.resolve(p('/root/index.js'), dep('hasteModule')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/hasteModule.js'), }); @@ -2139,7 +2216,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - 'hastePackage', + dep('hastePackage'), ), ).toEqual({ type: 'sourceFile', @@ -2169,7 +2246,7 @@ type MockFSDirContents = $ReadOnly<{ expect( resolver.resolve( p('/root/node_modules/aPackage/index.js'), - 'hasteModule', + dep('hasteModule'), ), ).toEqual({ type: 'sourceFile', @@ -2200,11 +2277,15 @@ type MockFSDirContents = $ReadOnly<{ }, }); - expect(resolver.resolve(p('/root/folder/index.js'), 'foo')).toEqual({ + expect( + resolver.resolve(p('/root/folder/index.js'), dep('foo')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/providesFoo/lib/bar.js'), }); - expect(resolver.resolve(p('/root/folder/index.js'), 'bar')).toEqual({ + expect( + resolver.resolve(p('/root/folder/index.js'), dep('bar')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/providesBar/index.js'), }); @@ -2228,12 +2309,14 @@ type MockFSDirContents = $ReadOnly<{ resolver: {extraNodeModules: {foo: p('/root/providesFoo')}}, }); - expect(resolver.resolve(p('/root/folder/index.js'), 'foo')).toEqual({ + expect( + resolver.resolve(p('/root/folder/index.js'), dep('foo')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/foo/index.js'), }); expect( - resolver.resolve(p('/root/folder/index.js'), 'foo/lib/bar'), + resolver.resolve(p('/root/folder/index.js'), dep('foo/lib/bar')), ).toEqual({type: 'sourceFile', filePath: p('/root/foo/lib/bar.js')}); }); @@ -2252,13 +2335,13 @@ type MockFSDirContents = $ReadOnly<{ }); expect( - resolver.resolve(p('/root/folder/index.js'), '@foo/bar'), + resolver.resolve(p('/root/folder/index.js'), dep('@foo/bar')), ).toEqual({ type: 'sourceFile', filePath: p('/root/providesFoo/index.js'), }); expect( - resolver.resolve(p('/root/folder/index.js'), '@foo/bar/lib/bar'), + resolver.resolve(p('/root/folder/index.js'), dep('@foo/bar/lib/bar')), ).toEqual({ type: 'sourceFile', filePath: p('/root/providesFoo/lib/bar.js'), @@ -2281,7 +2364,9 @@ type MockFSDirContents = $ReadOnly<{ resolver: {extraNodeModules: {foo: p('/root/providesFoo')}}, }); - expect(resolver.resolve(p('/root/folder/index.js'), 'foo')).toEqual({ + expect( + resolver.resolve(p('/root/folder/index.js'), dep('foo')), + ).toEqual({ type: 'sourceFile', filePath: p('/root/providesFoo/index-client.js'), }); @@ -2298,7 +2383,7 @@ type MockFSDirContents = $ReadOnly<{ }); expect( - resolver.resolve(p('/root/folder/index.js'), 'foo/asset.png'), + resolver.resolve(p('/root/folder/index.js'), dep('foo/asset.png')), ).toEqual({ type: 'sourceFile', filePath: p('/root/providesFoo/asset.png'), @@ -2325,13 +2410,15 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver({resolver: {resolveRequest}}); - expect(resolver.resolve(p('/root/index.js'), './myFolder/foo')).toEqual( - {type: 'sourceFile', filePath: p('/root/overriden.js')}, + expect( + resolver.resolve(p('/root/index.js'), dep('./myFolder/foo')), + ).toEqual({type: 'sourceFile', filePath: p('/root/overriden.js')}); + expect(resolver.resolve(p('/root/index.js'), dep('./invalid'))).toEqual( + { + type: 'sourceFile', + filePath: p('/root/overriden.js'), + }, ); - expect(resolver.resolve(p('/root/index.js'), './invalid')).toEqual({ - type: 'sourceFile', - filePath: p('/root/overriden.js'), - }); }); it('overrides node_modules package resolutions', async () => { @@ -2348,7 +2435,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver({resolver: {resolveRequest}}); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('aPackage'))).toEqual({ type: 'sourceFile', filePath: p('/root/overriden.js'), }); @@ -2366,7 +2453,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver({resolver: {resolveRequest}}); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('aPackage'))).toEqual({ type: 'sourceFile', filePath: p('/root/overriden.js'), }); @@ -2389,7 +2476,7 @@ type MockFSDirContents = $ReadOnly<{ }, }); - expect(resolver.resolve(p('/root/index.js'), 'aPackage')).toEqual({ + expect(resolver.resolve(p('/root/index.js'), dep('aPackage'))).toEqual({ type: 'sourceFile', filePath: p('/root/overriden.js'), }); @@ -2404,7 +2491,7 @@ type MockFSDirContents = $ReadOnly<{ resolver = await createResolver({resolver: {resolveRequest}}, 'ios'); - resolver.resolve(p('/root/index.js'), './foo'); + resolver.resolve(p('/root/index.js'), dep('./foo')); const [context, request, platform] = resolveRequest.mock.calls[0]; @@ -2436,16 +2523,16 @@ type MockFSDirContents = $ReadOnly<{ type: 'sourceFile', filePath: p('/target1.js'), }); - expect(resolver.resolve(p('/root1/dir/a.js'), 'target')).toEqual({ + expect(resolver.resolve(p('/root1/dir/a.js'), dep('target'))).toEqual({ type: 'sourceFile', filePath: p('/target1.js'), }); - expect(resolver.resolve(p('/root1/dir/b.js'), 'target')).toEqual({ + expect(resolver.resolve(p('/root1/dir/b.js'), dep('target'))).toEqual({ type: 'sourceFile', filePath: p('/target1.js'), }); expect(resolveRequest).toHaveBeenCalledTimes(1); - expect(resolver.resolve(p('/root1/fake.js'), 'target')).toEqual({ + expect(resolver.resolve(p('/root1/fake.js'), dep('target'))).toEqual({ type: 'sourceFile', filePath: p('/target1.js'), }); @@ -2455,16 +2542,16 @@ type MockFSDirContents = $ReadOnly<{ type: 'sourceFile', filePath: p('/target2.js'), }); - expect(resolver.resolve(p('/root2/dir/a.js'), 'target')).toEqual({ + expect(resolver.resolve(p('/root2/dir/a.js'), dep('target'))).toEqual({ type: 'sourceFile', filePath: p('/target2.js'), }); - expect(resolver.resolve(p('/root2/dir/b.js'), 'target')).toEqual({ + expect(resolver.resolve(p('/root2/dir/b.js'), dep('target'))).toEqual({ type: 'sourceFile', filePath: p('/target2.js'), }); expect(resolveRequest).toHaveBeenCalledTimes(3); - expect(resolver.resolve(p('/root2/fake.js'), 'target')).toEqual({ + expect(resolver.resolve(p('/root2/fake.js'), dep('target'))).toEqual({ type: 'sourceFile', filePath: p('/target2.js'), }); @@ -2495,12 +2582,12 @@ type MockFSDirContents = $ReadOnly<{ filePath: p('/target-always.js'), }); expect( - resolver.resolve(p('/root1/dir/a.js'), 'target', undefined, { + resolver.resolve(p('/root1/dir/a.js'), dep('target'), undefined, { assumeFlatNodeModules: true, }), ).toEqual({type: 'sourceFile', filePath: p('/target-always.js')}); expect( - resolver.resolve(p('/root1/dir/b.js'), 'target', undefined, { + resolver.resolve(p('/root1/dir/b.js'), dep('target'), undefined, { assumeFlatNodeModules: true, }), ).toEqual({type: 'sourceFile', filePath: p('/target-always.js')}); @@ -2510,12 +2597,12 @@ type MockFSDirContents = $ReadOnly<{ filePath: p('/target-never.js'), }); expect( - resolver.resolve(p('/root2/dir/a.js'), 'target', undefined, { + resolver.resolve(p('/root2/dir/a.js'), dep('target'), undefined, { assumeFlatNodeModules: true, }), ).toEqual({type: 'sourceFile', filePath: p('/target-always.js')}); expect( - resolver.resolve(p('/root2/dir/b.js'), 'target', undefined, { + resolver.resolve(p('/root2/dir/b.js'), dep('target'), undefined, { assumeFlatNodeModules: true, }), ).toEqual({type: 'sourceFile', filePath: p('/target-always.js')}); @@ -2547,7 +2634,7 @@ type MockFSDirContents = $ReadOnly<{ filePath: p('/target1.js'), }); expect( - resolver.resolve(p('/root1/dir/a.js'), 'target', { + resolver.resolve(p('/root1/dir/a.js'), dep('target'), { customResolverOptions: { foo: 'bar', key: 'value', @@ -2555,7 +2642,7 @@ type MockFSDirContents = $ReadOnly<{ }), ).toEqual({type: 'sourceFile', filePath: p('/target1.js')}); expect( - resolver.resolve(p('/root1/dir/b.js'), 'target', { + resolver.resolve(p('/root1/dir/b.js'), dep('target'), { customResolverOptions: { // NOTE: reverse order from what we passed above key: 'value', @@ -2567,7 +2654,7 @@ type MockFSDirContents = $ReadOnly<{ resolveRequest.mockClear(); expect( - resolver.resolve(p('/root1/dir/b.js'), 'target', { + resolver.resolve(p('/root1/dir/b.js'), dep('target'), { customResolverOptions: { // NOTE: only a subset of the options passed above foo: 'bar', @@ -2578,7 +2665,7 @@ type MockFSDirContents = $ReadOnly<{ resolveRequest.mockClear(); expect( - resolver.resolve(p('/root1/dir/b.js'), 'target', { + resolver.resolve(p('/root1/dir/b.js'), dep('target'), { customResolverOptions: { something: 'else', }, diff --git a/packages/metro/src/DeltaBundler/types.flow.js b/packages/metro/src/DeltaBundler/types.flow.js index 7aea4dbd90..45dbdc8647 100644 --- a/packages/metro/src/DeltaBundler/types.flow.js +++ b/packages/metro/src/DeltaBundler/types.flow.js @@ -128,7 +128,10 @@ export type BundlerResolution = $ReadOnly<{ }>; export type Options = { - +resolve: (from: string, to: string) => BundlerResolution, + +resolve: ( + from: string, + dependency: TransformResultDependency, + ) => BundlerResolution, +transform: TransformFn, +transformOptions: TransformInputOptions, +onProgress: ?(numProcessed: number, total: number) => mixed, diff --git a/packages/metro/src/HmrServer.js b/packages/metro/src/HmrServer.js index f5b910e249..94969cba51 100644 --- a/packages/metro/src/HmrServer.js +++ b/packages/metro/src/HmrServer.js @@ -120,7 +120,14 @@ class HmrServer { const resolvedEntryFilePath = resolutionFn( (this._config.server.unstable_serverRoot ?? this._config.projectRoot) + '/.', - entryFile, + { + name: entryFile, + data: { + key: entryFile, + asyncType: null, + locs: [], + }, + }, ).filePath; const graphId = getGraphId(resolvedEntryFilePath, transformOptions, { resolverOptions, diff --git a/packages/metro/src/ModuleGraph/worker/collectDependencies.js b/packages/metro/src/ModuleGraph/worker/collectDependencies.js index 7becfbce0c..613f87b84b 100644 --- a/packages/metro/src/ModuleGraph/worker/collectDependencies.js +++ b/packages/metro/src/ModuleGraph/worker/collectDependencies.js @@ -56,13 +56,14 @@ type DependencyData = $ReadOnly<{ // (ex. `require('foo')`) asyncType: AsyncDependencyType | null, isOptional?: boolean, - locs: Array, + locs: $ReadOnlyArray, /** Context for requiring a collection of modules. */ contextParams?: RequireContextParams, }>; export type MutableInternalDependency = { ...DependencyData, + locs: Array, index: number, name: string, }; diff --git a/packages/metro/src/Server.js b/packages/metro/src/Server.js index 543be5559a..bbfd9047d5 100644 --- a/packages/metro/src/Server.js +++ b/packages/metro/src/Server.js @@ -1310,7 +1310,10 @@ class Server { relativeTo === 'server' ? this._getServerRootDir() : this._config.projectRoot; - return resolutionFn(`${rootDir}/.`, filePath).filePath; + return resolutionFn(`${rootDir}/.`, { + name: filePath, + data: {key: filePath, locs: [], asyncType: null}, + }).filePath; } getNewBuildNumber(): number { diff --git a/packages/metro/src/Server/__tests__/Server-test.js b/packages/metro/src/Server/__tests__/Server-test.js index 5b63fd0e5d..bc430bb77a 100644 --- a/packages/metro/src/Server/__tests__/Server-test.js +++ b/packages/metro/src/Server/__tests__/Server-test.js @@ -15,6 +15,7 @@ import type { Module, Options, ReadOnlyGraph, + TransformResultDependency, } from '../../DeltaBundler/types.flow'; // $FlowFixMe[untyped-import] @@ -310,10 +311,12 @@ describe('processRequest', () => { server = new Server(config); getTransformFn.mockReturnValue(() => {}); - getResolveDependencyFn.mockReturnValue((a, b) => ({ - type: 'sourceFile', - filePath: path.resolve(a, `${b}.js`), - })); + getResolveDependencyFn.mockReturnValue( + (a: string, b: TransformResultDependency) => ({ + type: 'sourceFile', + filePath: path.resolve(a, `${b.name}.js`), + }), + ); // $FlowFixMe[cannot-write] fs.realpath = jest.fn((file, cb) => cb?.(null, '/root/foo.js')); diff --git a/packages/metro/src/__tests__/HmrServer-test.js b/packages/metro/src/__tests__/HmrServer-test.js index 6228adeca8..09a89949d4 100644 --- a/packages/metro/src/__tests__/HmrServer-test.js +++ b/packages/metro/src/__tests__/HmrServer-test.js @@ -20,12 +20,14 @@ import EventEmitter from 'events'; const HmrServer = require('../HmrServer'); const getGraphId = require('../lib/getGraphId'); const {getDefaultValues} = require('metro-config/src/defaults'); +import type {TransformResultDependency} from '../DeltaBundler/types.flow'; jest.mock('../lib/transformHelpers', () => ({ - getResolveDependencyFn: () => (from, to) => ({ - type: 'sourceFile', - filePath: `${require('path').resolve(from, to)}.js`, - }), + getResolveDependencyFn: + () => (from: string, to: TransformResultDependency) => ({ + type: 'sourceFile', + filePath: `${require('path').resolve(from, to.name)}.js`, + }), })); jest.mock('../IncrementalBundler'); diff --git a/packages/metro/src/lib/transformHelpers.js b/packages/metro/src/lib/transformHelpers.js index d65197a466..7722e919f9 100644 --- a/packages/metro/src/lib/transformHelpers.js +++ b/packages/metro/src/lib/transformHelpers.js @@ -16,6 +16,7 @@ import type DeltaBundler, {TransformFn} from '../DeltaBundler'; import type { BundlerResolution, TransformInputOptions, + TransformResultDependency, } from '../DeltaBundler/types.flow'; import type {TransformOptions} from '../DeltaBundler/Worker'; import type {ConfigT} from 'metro-config/src/configTypes.flow'; @@ -204,13 +205,15 @@ async function getResolveDependencyFn( bundler: Bundler, platform: ?string, resolverOptions: ResolverInputOptions, -): Promise<(from: string, to: string) => BundlerResolution> { +): Promise< + (from: string, dependency: TransformResultDependency) => BundlerResolution, +> { const dependencyGraph = await await bundler.getDependencyGraph(); - return (from: string, to: string) => + return (from: string, dependency: TransformResultDependency) => dependencyGraph.resolveDependency( from, - to, + dependency, platform ?? null, resolverOptions, ); diff --git a/packages/metro/src/node-haste/DependencyGraph.js b/packages/metro/src/node-haste/DependencyGraph.js index 716cdc072c..07f2db6655 100644 --- a/packages/metro/src/node-haste/DependencyGraph.js +++ b/packages/metro/src/node-haste/DependencyGraph.js @@ -36,7 +36,10 @@ const {InvalidPackageError} = require('metro-resolver'); const nullthrows = require('nullthrows'); const path = require('path'); import type {ResolverInputOptions} from '../shared/types.flow'; -import type {BundlerResolution} from '../DeltaBundler/types.flow'; +import type { + BundlerResolution, + TransformResultDependency, +} from '../DeltaBundler/types.flow'; const NULL_PLATFORM = Symbol(); @@ -310,7 +313,7 @@ class DependencyGraph extends EventEmitter { resolveDependency( from: string, - to: string, + dependency: TransformResultDependency, platform: string | null, resolverOptions: ResolverInputOptions, @@ -319,6 +322,7 @@ class DependencyGraph extends EventEmitter { assumeFlatNodeModules: false, }, ): BundlerResolution { + const to = dependency.name; const isSensitiveToOriginFolder = // Resolution is always relative to the origin folder unless we assume a flat node_modules !assumeFlatNodeModules || @@ -353,7 +357,7 @@ class DependencyGraph extends EventEmitter { try { resolution = this._moduleResolver.resolveDependency( this._moduleCache.getModule(from), - to, + dependency, true, platform, resolverOptions, diff --git a/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js b/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js index f727d1bebf..df1659d34a 100644 --- a/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js +++ b/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js @@ -29,7 +29,10 @@ const Resolver = require('metro-resolver'); const createDefaultContext = require('metro-resolver/src/createDefaultContext'); const path = require('path'); const util = require('util'); -import type {BundlerResolution} from '../../DeltaBundler/types.flow'; +import type { + BundlerResolution, + TransformResultDependency, +} from '../../DeltaBundler/types.flow'; import type {Reporter} from '../../lib/reporting'; export type DirExistsFn = (filePath: string) => boolean; @@ -107,7 +110,14 @@ class ModuleResolver { if (!emptyModule) { emptyModule = this.resolveDependency( this._projectRootFakeModule, - this._options.emptyModulePath, + { + name: this._options.emptyModulePath, + data: { + key: this._options.emptyModulePath, + asyncType: null, + locs: [], + }, + }, false, null, /* resolverOptions */ {}, @@ -119,7 +129,7 @@ class ModuleResolver { resolveDependency( fromModule: Moduleish, - moduleName: string, + dependency: TransformResultDependency, allowHaste: boolean, platform: string | null, resolverOptions: ResolverInputOptions, @@ -143,34 +153,37 @@ class ModuleResolver { try { const result = Resolver.resolve( - createDefaultContext({ - allowHaste, - assetExts, - disableHierarchicalLookup, - doesFileExist, - extraNodeModules, - mainFields, - nodeModulesPaths, - preferNativePlatform, - resolveAsset, - resolveRequest, - sourceExts, - unstable_conditionNames, - unstable_conditionsByPlatform, - unstable_enablePackageExports, - unstable_getRealPath, - unstable_logWarning: this._logWarning, - customResolverOptions: resolverOptions.customResolverOptions ?? {}, - originModulePath: fromModule.path, - resolveHasteModule: (name: string) => - this._options.getHasteModulePath(name, platform), - resolveHastePackage: (name: string) => - this._options.getHastePackagePath(name, platform), - getPackage: this._getPackage, - getPackageForModule: (modulePath: string) => - this._getPackageForModule(fromModule, modulePath), - }), - moduleName, + createDefaultContext( + { + allowHaste, + assetExts, + disableHierarchicalLookup, + doesFileExist, + extraNodeModules, + mainFields, + nodeModulesPaths, + preferNativePlatform, + resolveAsset, + resolveRequest, + sourceExts, + unstable_conditionNames, + unstable_conditionsByPlatform, + unstable_enablePackageExports, + unstable_getRealPath, + unstable_logWarning: this._logWarning, + customResolverOptions: resolverOptions.customResolverOptions ?? {}, + originModulePath: fromModule.path, + resolveHasteModule: (name: string) => + this._options.getHasteModulePath(name, platform), + resolveHastePackage: (name: string) => + this._options.getHastePackagePath(name, platform), + getPackage: this._getPackage, + getPackageForModule: (modulePath: string) => + this._getPackageForModule(fromModule, modulePath), + }, + dependency, + ), + dependency.name, platform, ); return this._getFileResolvedModule(result); @@ -179,7 +192,7 @@ class ModuleResolver { const {candidates} = error; throw new UnableToResolveError( fromModule.path, - moduleName, + dependency.name, [ '\n\nNone of these files exist:', ` * ${Resolver.formatFileCandidates( @@ -206,9 +219,11 @@ class ModuleResolver { throw new UnableToResolveError( fromModule.path, - moduleName, + dependency.name, [ - `${moduleName} could not be found within the project${hint || '.'}`, + `${dependency.name} could not be found within the project${ + hint || '.' + }`, ...displayDirPaths.map((dirPath: string) => ` ${dirPath}`), ].join('\n'), { diff --git a/packages/metro/src/node-haste/Package.js b/packages/metro/src/node-haste/Package.js index 01f2e8858a..5569c5448d 100644 --- a/packages/metro/src/node-haste/Package.js +++ b/packages/metro/src/node-haste/Package.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow strict + * @flow strict-local * @format * @oncall react_native */ diff --git a/packages/metro/types/DeltaBundler/types.d.ts b/packages/metro/types/DeltaBundler/types.d.ts index cbfe0c9dcf..6714fa63bc 100644 --- a/packages/metro/types/DeltaBundler/types.d.ts +++ b/packages/metro/types/DeltaBundler/types.d.ts @@ -19,7 +19,7 @@ export interface MixedOutput { readonly type: string; } -export type AsyncDependencyType = 'async' | 'prefetch'; +export type AsyncDependencyType = 'async' | 'prefetch' | 'weak'; export interface TransformResultDependency { /** @@ -42,13 +42,6 @@ export interface TransformResultDependency { */ readonly asyncType: AsyncDependencyType | null; - /** - * The condition for splitting on this dependency edge. - */ - readonly splitCondition?: { - readonly mobileConfigName: string; - }; - /** * The dependency is enclosed in a try/catch block. */ @@ -133,7 +126,7 @@ export interface BundlerResolution { } export interface Options { - readonly resolve: (from: string, to: string) => string; + readonly resolve: (from: string, to: TransformResultDependency) => string; readonly transform: TransformFn; readonly transformOptions: TransformInputOptions; readonly onProgress: diff --git a/packages/metro/types/node-haste/DependencyGraph.d.ts b/packages/metro/types/node-haste/DependencyGraph.d.ts index af22ccf919..f6c3ac6dd2 100644 --- a/packages/metro/types/node-haste/DependencyGraph.d.ts +++ b/packages/metro/types/node-haste/DependencyGraph.d.ts @@ -11,7 +11,10 @@ import {EventEmitter} from 'events'; import {ConfigT} from 'metro-config'; import {ResolverInputOptions} from '../shared/types'; -import {BundlerResolution} from '../DeltaBundler/types'; +import { + BundlerResolution, + TransformResultDependency, +} from '../DeltaBundler/types'; export default class DependencyGraph extends EventEmitter { constructor( @@ -48,7 +51,7 @@ export default class DependencyGraph extends EventEmitter { resolveDependency( from: string, - to: string, + to: TransformResultDependency, platform: string | null, resolverOptions: ResolverInputOptions, options: {assumeFlatNodeModules: boolean},