diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 78bf9e1f3a682..b08550bf7d6b5 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -84,7 +84,6 @@ import { getContainingClass, getEffectiveContainerForJSDocTemplateTag, getElementOrPropertyAccessName, - getEmitModuleResolutionKind, getEmitScriptTarget, getEnclosingBlockScopeContainer, getErrorSpanForNode, @@ -241,7 +240,6 @@ import { ModifierFlags, ModuleBlock, ModuleDeclaration, - ModuleResolutionKind, Mutable, NamespaceExportDeclaration, Node, @@ -279,6 +277,7 @@ import { setValueDeclaration, ShorthandPropertyAssignment, shouldPreserveConstEnums, + shouldResolveJsRequire, SignatureDeclaration, skipParentheses, sliceAfter, @@ -3532,7 +3531,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { if (!isBindingPattern(node.name)) { const possibleVariableDecl = node.kind === SyntaxKind.VariableDeclaration ? node : node.parent.parent; if (isInJSFile(node) && - getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Bundler && + shouldResolveJsRequire(options) && isVariableDeclarationInitializedToBareOrAccessedRequire(possibleVariableDecl) && !getJSDocTypeTag(node) && !(getCombinedModifierFlags(node) & ModifierFlags.Export) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 406313020adff..dca3a2a9f5275 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -934,6 +934,7 @@ import { ShorthandPropertyAssignment, shouldAllowImportingTsExtension, shouldPreserveConstEnums, + shouldResolveJsRequire, Signature, SignatureDeclaration, SignatureFlags, @@ -3995,7 +3996,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const hasDefaultOnly = isOnlyImportedAsDefault(specifier); const hasSyntheticDefault = canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, specifier); if (!exportDefaultSymbol && !hasSyntheticDefault && !hasDefaultOnly) { - if (hasExportAssignmentSymbol(moduleSymbol) && !(getAllowSyntheticDefaultImports(compilerOptions) || getESModuleInterop(compilerOptions))) { + if (hasExportAssignmentSymbol(moduleSymbol) && !allowSyntheticDefaultImports) { const compilerOptionName = moduleKind >= ModuleKind.ES2015 ? "allowSyntheticDefaultImports" : "esModuleInterop"; const exportEqualsSymbol = moduleSymbol.exports!.get(InternalSymbolName.ExportEquals); const exportAssignment = exportEqualsSymbol!.valueDeclaration; @@ -4138,7 +4139,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isIdentifier(name)) { return undefined; } - const suppressInteropError = name.escapedText === InternalSymbolName.Default && !!(compilerOptions.allowSyntheticDefaultImports || getESModuleInterop(compilerOptions)); + const suppressInteropError = name.escapedText === InternalSymbolName.Default && allowSyntheticDefaultImports; const targetSymbol = resolveESModuleSymbol(moduleSymbol, moduleSpecifier, /*dontResolveAlias*/ false, suppressInteropError); if (targetSymbol) { if (name.escapedText) { @@ -9177,7 +9178,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // If `target` refers to a shorthand module symbol, the name we're trying to pull out isn;t recoverable from the target symbol // In such a scenario, we must fall back to looking for an alias declaration on `symbol` and pulling the target name from that let verbatimTargetName = isShorthandAmbientModuleSymbol(target) && getSomeTargetNameFromDeclarations(symbol.declarations) || unescapeLeadingUnderscores(target.escapedName); - if (verbatimTargetName === InternalSymbolName.ExportEquals && (getESModuleInterop(compilerOptions) || compilerOptions.allowSyntheticDefaultImports)) { + if (verbatimTargetName === InternalSymbolName.ExportEquals && allowSyntheticDefaultImports) { // target refers to an `export=` symbol that was hoisted into a synthetic default - rename here to match verbatimTargetName = InternalSymbolName.Default; } @@ -33993,7 +33994,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // In JavaScript files, calls to any identifier 'require' are treated as external module imports - if (isInJSFile(node) && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Bundler && isCommonJsRequire(node)) { + if (isInJSFile(node) && shouldResolveJsRequire(compilerOptions) && isCommonJsRequire(node)) { return resolveExternalModuleTypeByLiteral(node.arguments![0] as StringLiteral); } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index a3d49f9b600f1..440ddd9cfc0b0 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -284,6 +284,7 @@ import { setParentRecursive, setResolvedModule, setResolvedTypeReferenceDirective, + shouldResolveJsRequire, skipTrivia, skipTypeChecking, some, @@ -3207,8 +3208,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg collectModuleReferences(node, /*inAmbientModule*/ false); } - // `require` has no special meaning in `--moduleResolution bundler` - const shouldProcessRequires = isJavaScriptFile && getEmitModuleResolutionKind(options) !== ModuleResolutionKind.Bundler; + const shouldProcessRequires = isJavaScriptFile && shouldResolveJsRequire(options); if ((file.flags & NodeFlags.PossiblyContainsDynamicImport) || shouldProcessRequires) { collectDynamicImportOrRequireCalls(file); } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index af4730f848460..57b02beea9432 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -8421,6 +8421,12 @@ export function moduleResolutionSupportsPackageJsonExportsAndImports(moduleResol || moduleResolution === ModuleResolutionKind.Bundler; } +/** @internal */ +export function shouldResolveJsRequire(compilerOptions: CompilerOptions): boolean { + // `bundler` doesn't support resolving `require`, but needs to in `noDtsResolution` to support Find Source Definition + return !!compilerOptions.noDtsResolution || getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Bundler; +} + /** @internal */ export function getResolvePackageJsonExports(compilerOptions: CompilerOptions) { const moduleResolution = getEmitModuleResolutionKind(compilerOptions); diff --git a/tests/baselines/reference/goToSource15_bundler.baseline.jsonc b/tests/baselines/reference/goToSource15_bundler.baseline.jsonc new file mode 100644 index 0000000000000..dc233e8fa79f4 --- /dev/null +++ b/tests/baselines/reference/goToSource15_bundler.baseline.jsonc @@ -0,0 +1,34 @@ +// === goToSourceDefinition === +// === /node_modules/react/cjs/react.production.min.js === +// 'use strict';exports.[|{| defId: 0 |}useState|]=function(a){};exports.version='16.8.6'; + +// === /node_modules/react/cjs/react.development.js === +// 'use strict'; +// if (process.env.NODE_ENV !== 'production') { +// (function() { +// function useState(initialState) {} +// exports.[|{| defId: 1 |}useState|] = useState; +// exports.version = '16.8.6'; +// }()); +// } + +// === /index.ts === +// import { /*GOTO SOURCE DEF*/useState } from 'react'; + + // === Details === + [ + { + "defId": 0, + "containerKind": "", + "containerName": "", + "kind": "", + "name": "" + }, + { + "defId": 1, + "containerKind": "", + "containerName": "", + "kind": "", + "name": "" + } + ] \ No newline at end of file diff --git a/tests/cases/fourslash/server/goToSource15_bundler.ts b/tests/cases/fourslash/server/goToSource15_bundler.ts new file mode 100644 index 0000000000000..290caa62cbba3 --- /dev/null +++ b/tests/cases/fourslash/server/goToSource15_bundler.ts @@ -0,0 +1,34 @@ +/// + +// @Filename: /tsconfig.json +//// { "compilerOptions": { "module": "esnext", "moduleResolution": "bundler" } } + +// @Filename: /node_modules/react/package.json +//// { "name": "react", "version": "16.8.6", "main": "index.js" } + +// @Filename: /node_modules/react/index.js +//// 'use strict'; +//// +//// if (process.env.NODE_ENV === 'production') { +//// module.exports = require('./cjs/react.production.min.js'); +//// } else { +//// module.exports = require('./cjs/react.development.js'); +//// } + +// @Filename: /node_modules/react/cjs/react.production.min.js +//// 'use strict';exports./*production*/useState=function(a){};exports.version='16.8.6'; + +// @Filename: /node_modules/react/cjs/react.development.js +//// 'use strict'; +//// if (process.env.NODE_ENV !== 'production') { +//// (function() { +//// function useState(initialState) {} +//// exports./*development*/useState = useState; +//// exports.version = '16.8.6'; +//// }()); +//// } + +// @Filename: /index.ts +//// import { [|/*start*/useState|] } from 'react'; + +verify.goToSourceDefinition("start", ["production", "development"]);