mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Only look up package.json type if module is node16/nodenext or file is in node_modules (#58825)
Co-authored-by: Jake Bailey <5341706+jakebailey@users.noreply.github.com>
This commit is contained in:
co-authored by
Jake Bailey
parent
f37482cd16
commit
a9139bfdfe
@@ -54,7 +54,7 @@ export * from "../transformers/generators.js";
|
||||
export * from "../transformers/module/module.js";
|
||||
export * from "../transformers/module/system.js";
|
||||
export * from "../transformers/module/esnextAnd2015.js";
|
||||
export * from "../transformers/module/node.js";
|
||||
export * from "../transformers/module/impliedNodeFormatDependent.js";
|
||||
export * from "../transformers/declarations/diagnostics.js";
|
||||
export * from "../transformers/declarations.js";
|
||||
export * from "../transformer.js";
|
||||
|
||||
+63
-34
@@ -60,6 +60,7 @@ import {
|
||||
canHaveJSDoc,
|
||||
canHaveLocals,
|
||||
canHaveModifiers,
|
||||
canHaveModuleSpecifier,
|
||||
canHaveSymbol,
|
||||
canIncludeBindAndCheckDiagnostics,
|
||||
canUsePropertyAccess,
|
||||
@@ -3653,27 +3654,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|| isNamespaceExport(node));
|
||||
}
|
||||
|
||||
function getUsageModeForExpression(usage: Expression) {
|
||||
return isStringLiteralLike(usage) ? host.getModeForUsageLocation(getSourceFileOfNode(usage), usage) : undefined;
|
||||
function getEmitSyntaxForModuleSpecifierExpression(usage: Expression) {
|
||||
return isStringLiteralLike(usage) ? host.getEmitSyntaxForUsageLocation(getSourceFileOfNode(usage), usage) : undefined;
|
||||
}
|
||||
|
||||
function isESMFormatImportImportingCommonjsFormatFile(usageMode: ResolutionMode, targetMode: ResolutionMode) {
|
||||
return usageMode === ModuleKind.ESNext && targetMode === ModuleKind.CommonJS;
|
||||
}
|
||||
|
||||
function isOnlyImportedAsDefault(usage: Expression) {
|
||||
const usageMode = getUsageModeForExpression(usage);
|
||||
return usageMode === ModuleKind.ESNext && endsWith((usage as StringLiteralLike).text, Extension.Json);
|
||||
function isOnlyImportableAsDefault(usage: Expression) {
|
||||
// In Node.js, JSON modules don't get named exports
|
||||
if (ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) {
|
||||
const usageMode = getEmitSyntaxForModuleSpecifierExpression(usage);
|
||||
return usageMode === ModuleKind.ESNext && endsWith((usage as StringLiteralLike).text, Extension.Json);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function canHaveSyntheticDefault(file: SourceFile | undefined, moduleSymbol: Symbol, dontResolveAlias: boolean, usage: Expression) {
|
||||
const usageMode = file && getUsageModeForExpression(usage);
|
||||
if (file && usageMode !== undefined && ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) {
|
||||
const result = isESMFormatImportImportingCommonjsFormatFile(usageMode, file.impliedNodeFormat);
|
||||
if (usageMode === ModuleKind.ESNext || result) {
|
||||
return result;
|
||||
const usageMode = file && getEmitSyntaxForModuleSpecifierExpression(usage);
|
||||
if (file && usageMode !== undefined) {
|
||||
const targetMode = host.getImpliedNodeFormatForEmit(file);
|
||||
if (usageMode === ModuleKind.ESNext && targetMode === ModuleKind.CommonJS && ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) {
|
||||
// In Node.js, CommonJS modules always have a synthetic default when imported into ESM
|
||||
return true;
|
||||
}
|
||||
if (usageMode === ModuleKind.ESNext && targetMode === ModuleKind.ESNext) {
|
||||
// No matter what the `module` setting is, if we're confident that both files
|
||||
// are ESM, there cannot be a synthetic default.
|
||||
return false;
|
||||
}
|
||||
// fallthrough on cjs usages so we imply defaults for interop'd imports, too
|
||||
}
|
||||
if (!allowSyntheticDefaultImports) {
|
||||
return false;
|
||||
@@ -3726,7 +3736,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (!specifier) {
|
||||
return exportDefaultSymbol;
|
||||
}
|
||||
const hasDefaultOnly = isOnlyImportedAsDefault(specifier);
|
||||
const hasDefaultOnly = isOnlyImportableAsDefault(specifier);
|
||||
const hasSyntheticDefault = canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, specifier);
|
||||
if (!exportDefaultSymbol && !hasSyntheticDefault && !hasDefaultOnly) {
|
||||
if (hasExportAssignmentSymbol(moduleSymbol) && !allowSyntheticDefaultImports) {
|
||||
@@ -3911,7 +3921,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
let symbolFromModule = getExportOfModule(targetSymbol, nameText, specifier, dontResolveAlias);
|
||||
if (symbolFromModule === undefined && nameText === InternalSymbolName.Default) {
|
||||
const file = moduleSymbol.declarations?.find(isSourceFile);
|
||||
if (isOnlyImportedAsDefault(moduleSpecifier) || canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, moduleSpecifier)) {
|
||||
if (isOnlyImportableAsDefault(moduleSpecifier) || canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, moduleSpecifier)) {
|
||||
symbolFromModule = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias);
|
||||
}
|
||||
}
|
||||
@@ -4575,7 +4585,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
findAncestor(location, isImportDeclaration)?.moduleSpecifier ||
|
||||
findAncestor(location, isExternalModuleImportEqualsDeclaration)?.moduleReference.expression ||
|
||||
findAncestor(location, isExportDeclaration)?.moduleSpecifier;
|
||||
const mode = contextSpecifier && isStringLiteralLike(contextSpecifier) ? host.getModeForUsageLocation(currentSourceFile, contextSpecifier) : currentSourceFile.impliedNodeFormat;
|
||||
const mode = contextSpecifier && isStringLiteralLike(contextSpecifier)
|
||||
? host.getModeForUsageLocation(currentSourceFile, contextSpecifier)
|
||||
: host.getDefaultResolutionModeForFile(currentSourceFile);
|
||||
const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions);
|
||||
const resolvedModule = host.getResolvedModule(currentSourceFile, moduleReference, mode)?.resolvedModule;
|
||||
const resolutionDiagnostic = errorNode && resolvedModule && getResolutionDiagnostic(compilerOptions, resolvedModule, currentSourceFile);
|
||||
@@ -4833,7 +4845,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
const targetFile = moduleSymbol?.declarations?.find(isSourceFile);
|
||||
const isEsmCjsRef = targetFile && isESMFormatImportImportingCommonjsFormatFile(getUsageModeForExpression(reference), targetFile.impliedNodeFormat);
|
||||
const isEsmCjsRef = targetFile && isESMFormatImportImportingCommonjsFormatFile(getEmitSyntaxForModuleSpecifierExpression(reference), host.getImpliedNodeFormatForEmit(targetFile));
|
||||
if (getESModuleInterop(compilerOptions) || isEsmCjsRef) {
|
||||
let sigs = getSignaturesOfStructuredType(type, SignatureKind.Call);
|
||||
if (!sigs || !sigs.length) {
|
||||
@@ -7786,8 +7798,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
return getSourceFileOfNode(getNonAugmentationDeclaration(symbol)!).fileName; // A resolver may not be provided for baselines and errors - in those cases we use the fileName in full
|
||||
}
|
||||
const enclosingDeclaration = getOriginalNode(context.enclosingDeclaration);
|
||||
const originalModuleSpecifier = canHaveModuleSpecifier(enclosingDeclaration) ? tryGetModuleSpecifierFromDeclaration(enclosingDeclaration) : undefined;
|
||||
const contextFile = context.enclosingFile;
|
||||
const resolutionMode = overrideImportMode || contextFile?.impliedNodeFormat;
|
||||
const resolutionMode = overrideImportMode
|
||||
|| originalModuleSpecifier && host.getModeForUsageLocation(contextFile, originalModuleSpecifier)
|
||||
|| contextFile && host.getDefaultResolutionModeForFile(contextFile);
|
||||
const cacheKey = createModeAwareCacheKey(contextFile.path, resolutionMode);
|
||||
const links = getSymbolLinks(symbol);
|
||||
let specifier = links.specifierCache && links.specifierCache.get(cacheKey);
|
||||
@@ -36897,7 +36913,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function getTypeWithSyntheticDefaultOnly(type: Type, symbol: Symbol, originalSymbol: Symbol, moduleSpecifier: Expression) {
|
||||
const hasDefaultOnly = isOnlyImportedAsDefault(moduleSpecifier);
|
||||
const hasDefaultOnly = isOnlyImportableAsDefault(moduleSpecifier);
|
||||
if (hasDefaultOnly && type && !isErrorType(type)) {
|
||||
const synthType = type as SyntheticDefaultModuleType;
|
||||
if (!synthType.defaultOnlyType) {
|
||||
@@ -43483,7 +43499,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: Identifier | undefined) {
|
||||
// No need to check for require or exports for ES6 modules and later
|
||||
if (moduleKind >= ModuleKind.ES2015 && !(moduleKind >= ModuleKind.Node16 && getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)) {
|
||||
if (host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) >= ModuleKind.ES2015) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45372,7 +45388,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
function checkClassNameCollisionWithObject(name: Identifier): void {
|
||||
if (
|
||||
languageVersion >= ScriptTarget.ES5 && name.escapedText === "Object"
|
||||
&& (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(name).impliedNodeFormat === ModuleKind.CommonJS)
|
||||
&& host.getEmitModuleFormatOfFile(getSourceFileOfNode(name)) < ModuleKind.ES2015
|
||||
) {
|
||||
error(name, Diagnostics.Class_name_cannot_be_Object_when_targeting_ES5_with_module_0, ModuleKind[moduleKind]); // https://github.com/Microsoft/TypeScript/issues/17494
|
||||
}
|
||||
@@ -46711,7 +46727,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (
|
||||
compilerOptions.verbatimModuleSyntax &&
|
||||
node.parent.kind === SyntaxKind.SourceFile &&
|
||||
(moduleKind === ModuleKind.CommonJS || node.parent.impliedNodeFormat === ModuleKind.CommonJS)
|
||||
host.getEmitModuleFormatOfFile(node.parent) === ModuleKind.CommonJS
|
||||
) {
|
||||
const exportModifier = node.modifiers?.find(m => m.kind === SyntaxKind.ExportKeyword);
|
||||
if (exportModifier) {
|
||||
@@ -47003,10 +47019,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
compilerOptions.verbatimModuleSyntax &&
|
||||
node.kind !== SyntaxKind.ImportEqualsDeclaration &&
|
||||
!isInJSFile(node) &&
|
||||
(moduleKind === ModuleKind.CommonJS || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)
|
||||
host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) === ModuleKind.CommonJS
|
||||
) {
|
||||
error(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled);
|
||||
}
|
||||
else if (
|
||||
moduleKind === ModuleKind.Preserve &&
|
||||
node.kind !== SyntaxKind.ImportEqualsDeclaration &&
|
||||
node.kind !== SyntaxKind.VariableDeclaration &&
|
||||
host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) === ModuleKind.CommonJS
|
||||
) {
|
||||
// In `--module preserve`, ESM input syntax emits ESM output syntax, but there will be times
|
||||
// when we look at the `impliedNodeFormat` of this file and decide it's CommonJS (i.e., currently,
|
||||
// only if the file extension is .cjs/.cts). To avoid that inconsistency, we disallow ESM syntax
|
||||
// in files that are unambiguously CommonJS in this mode.
|
||||
error(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_module_is_set_to_preserve);
|
||||
}
|
||||
}
|
||||
|
||||
if (isImportSpecifier(node)) {
|
||||
@@ -47056,7 +47084,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (
|
||||
moduleExportNameIsDefault(node.propertyName || node.name) &&
|
||||
getESModuleInterop(compilerOptions) &&
|
||||
moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)
|
||||
host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < ModuleKind.System
|
||||
) {
|
||||
checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportDefault);
|
||||
}
|
||||
@@ -47078,7 +47106,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return; // Other grammar checks do not apply to type-only imports with resolution mode assertions
|
||||
}
|
||||
|
||||
const mode = (moduleKind === ModuleKind.NodeNext) && declaration.moduleSpecifier && getUsageModeForExpression(declaration.moduleSpecifier);
|
||||
const mode = (moduleKind === ModuleKind.NodeNext) && declaration.moduleSpecifier && getEmitSyntaxForModuleSpecifierExpression(declaration.moduleSpecifier);
|
||||
if (mode !== ModuleKind.ESNext && moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.Preserve) {
|
||||
const message = isImportAttributes
|
||||
? moduleKind === ModuleKind.NodeNext
|
||||
@@ -47122,7 +47150,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (importClause.namedBindings) {
|
||||
if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
|
||||
checkImportBinding(importClause.namedBindings);
|
||||
if (moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) && getESModuleInterop(compilerOptions)) {
|
||||
if (host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < ModuleKind.System && getESModuleInterop(compilerOptions)) {
|
||||
// import * as ns from "foo";
|
||||
checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportStar);
|
||||
}
|
||||
@@ -47169,8 +47197,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (moduleKind >= ModuleKind.ES2015 && moduleKind !== ModuleKind.Preserve && getSourceFileOfNode(node).impliedNodeFormat === undefined && !node.isTypeOnly && !(node.flags & NodeFlags.Ambient)) {
|
||||
// Import equals declaration is deprecated in es6 or above
|
||||
if (ModuleKind.ES2015 <= moduleKind && moduleKind <= ModuleKind.ESNext && !node.isTypeOnly && !(node.flags & NodeFlags.Ambient)) {
|
||||
// Import equals declaration cannot be emitted as ESM
|
||||
grammarErrorOnNode(node, Diagnostics.Import_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_import_d_from_mod_or_another_module_format_instead);
|
||||
}
|
||||
}
|
||||
@@ -47211,7 +47239,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
checkAliasSymbol(node.exportClause);
|
||||
checkModuleExportName(node.exportClause.name);
|
||||
}
|
||||
if (moduleKind !== ModuleKind.System && (moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)) {
|
||||
if (host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < ModuleKind.System) {
|
||||
if (node.exportClause) {
|
||||
// export * as ns from "foo";
|
||||
// For ES2015 modules, we emit it as a pair of `import * as a_1 ...; export { a_1 as ns }` and don't need the helper.
|
||||
@@ -47270,8 +47298,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
else {
|
||||
if (
|
||||
getESModuleInterop(compilerOptions) &&
|
||||
moduleKind !== ModuleKind.System &&
|
||||
(moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) &&
|
||||
host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < ModuleKind.System &&
|
||||
moduleExportNameIsDefault(node.propertyName || node.name)
|
||||
) {
|
||||
checkExternalEmitHelpers(node, ExternalEmitHelpers.ImportDefault);
|
||||
@@ -47312,7 +47339,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
const isIllegalExportDefaultInCJS = !node.isExportEquals &&
|
||||
!(node.flags & NodeFlags.Ambient) &&
|
||||
compilerOptions.verbatimModuleSyntax &&
|
||||
(moduleKind === ModuleKind.CommonJS || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS);
|
||||
host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) === ModuleKind.CommonJS;
|
||||
|
||||
if (node.expression.kind === SyntaxKind.Identifier) {
|
||||
const id = node.expression as Identifier;
|
||||
@@ -47410,8 +47437,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (
|
||||
moduleKind >= ModuleKind.ES2015 &&
|
||||
moduleKind !== ModuleKind.Preserve &&
|
||||
((node.flags & NodeFlags.Ambient && getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.ESNext) ||
|
||||
(!(node.flags & NodeFlags.Ambient) && getSourceFileOfNode(node).impliedNodeFormat !== ModuleKind.CommonJS))
|
||||
((node.flags & NodeFlags.Ambient && host.getImpliedNodeFormatForEmit(getSourceFileOfNode(node)) === ModuleKind.ESNext) ||
|
||||
(!(node.flags & NodeFlags.Ambient) && host.getImpliedNodeFormatForEmit(getSourceFileOfNode(node)) !== ModuleKind.CommonJS))
|
||||
) {
|
||||
// export assignment is not supported in es6 modules
|
||||
grammarErrorOnNode(node, Diagnostics.Export_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_export_default_or_another_module_format_instead);
|
||||
@@ -50354,7 +50381,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// ModuleDeclaration needs to be checked that it is uninstantiated later
|
||||
node.kind !== SyntaxKind.ModuleDeclaration &&
|
||||
node.parent.kind === SyntaxKind.SourceFile &&
|
||||
(moduleKind === ModuleKind.CommonJS || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS)
|
||||
host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) === ModuleKind.CommonJS
|
||||
) {
|
||||
return grammarErrorOnNode(modifier, Diagnostics.A_top_level_export_modifier_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled);
|
||||
}
|
||||
@@ -51513,7 +51540,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
if (
|
||||
(moduleKind < ModuleKind.ES2015 || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) && moduleKind !== ModuleKind.System &&
|
||||
host.getEmitModuleFormatOfFile(getSourceFileOfNode(node)) < ModuleKind.System &&
|
||||
!(node.parent.parent.flags & NodeFlags.Ambient) && hasSyntacticModifier(node.parent.parent, ModifierFlags.Export)
|
||||
) {
|
||||
checkESModuleMarker(node.name);
|
||||
@@ -52159,6 +52186,8 @@ function createBasicNodeBuilderModuleSpecifierResolutionHost(host: TypeCheckerHo
|
||||
fileExists: fileName => host.fileExists(fileName),
|
||||
getFileIncludeReasons: () => host.getFileIncludeReasons(),
|
||||
readFile: host.readFile ? (fileName => host.readFile!(fileName)) : undefined,
|
||||
getDefaultResolutionModeForFile: file => host.getDefaultResolutionModeForFile(file),
|
||||
getModeForResolutionAtIndex: (file, index) => host.getModeForResolutionAtIndex(file, index),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -967,6 +967,10 @@
|
||||
"category": "Error",
|
||||
"code": 1292
|
||||
},
|
||||
"ESM syntax is not allowed in a CommonJS module when 'module' is set to 'preserve'.": {
|
||||
"category": "Error",
|
||||
"code": 1293
|
||||
},
|
||||
|
||||
"'with' statements are not allowed in an async function block.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -131,6 +131,7 @@ import {
|
||||
getEmitFlags,
|
||||
getEmitHelpers,
|
||||
getEmitModuleKind,
|
||||
getEmitModuleResolutionKind,
|
||||
getEmitScriptTarget,
|
||||
getExternalModuleName,
|
||||
getIdentifierTypeArguments,
|
||||
@@ -828,6 +829,7 @@ export function emitFiles(
|
||||
newLine: compilerOptions.newLine,
|
||||
noEmitHelpers: compilerOptions.noEmitHelpers,
|
||||
module: getEmitModuleKind(compilerOptions),
|
||||
moduleResolution: getEmitModuleResolutionKind(compilerOptions),
|
||||
target: getEmitScriptTarget(compilerOptions),
|
||||
sourceMap: compilerOptions.sourceMap,
|
||||
inlineSourceMap: compilerOptions.inlineSourceMap,
|
||||
@@ -903,6 +905,7 @@ export function emitFiles(
|
||||
newLine: compilerOptions.newLine,
|
||||
noEmitHelpers: true,
|
||||
module: compilerOptions.module,
|
||||
moduleResolution: compilerOptions.moduleResolution,
|
||||
target: compilerOptions.target,
|
||||
sourceMap: !forceDtsEmit && compilerOptions.declarationMap,
|
||||
inlineSourceMap: compilerOptions.inlineSourceMap,
|
||||
|
||||
@@ -51,10 +51,12 @@ import {
|
||||
getAllAccessorDeclarations,
|
||||
getEmitFlags,
|
||||
getEmitHelpers,
|
||||
getEmitModuleFormatOfFileWorker,
|
||||
getEmitModuleKind,
|
||||
getESModuleInterop,
|
||||
getExternalModuleName,
|
||||
getExternalModuleNameFromPath,
|
||||
getImpliedNodeFormatForEmitWorker,
|
||||
getJSDocType,
|
||||
getJSDocTypeTag,
|
||||
getModifiers,
|
||||
@@ -687,7 +689,7 @@ export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: Node
|
||||
if (compilerOptions.importHelpers && isEffectiveExternalModule(sourceFile, compilerOptions)) {
|
||||
let namedBindings: NamedImportBindings | undefined;
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
if ((moduleKind >= ModuleKind.ES2015 && moduleKind <= ModuleKind.ESNext) || sourceFile.impliedNodeFormat === ModuleKind.ESNext) {
|
||||
if ((moduleKind >= ModuleKind.ES2015 && moduleKind <= ModuleKind.ESNext) || getImpliedNodeFormatForEmitWorker(sourceFile, compilerOptions) === ModuleKind.ESNext) {
|
||||
// use named imports
|
||||
const helpers = getEmitHelpers(sourceFile);
|
||||
if (helpers) {
|
||||
@@ -743,10 +745,8 @@ function getOrCreateExternalHelpersModuleNameIfNeeded(factory: NodeFactory, node
|
||||
return externalHelpersModuleName;
|
||||
}
|
||||
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
let create = (hasExportStarsToExportValues || (getESModuleInterop(compilerOptions) && hasImportStarOrImportDefault))
|
||||
&& moduleKind !== ModuleKind.System
|
||||
&& (moduleKind < ModuleKind.ES2015 || node.impliedNodeFormat === ModuleKind.CommonJS);
|
||||
&& getEmitModuleFormatOfFileWorker(node, compilerOptions) < ModuleKind.System;
|
||||
if (!create) {
|
||||
const helpers = getEmitHelpers(node);
|
||||
if (helpers) {
|
||||
|
||||
@@ -37,9 +37,9 @@ import {
|
||||
getBaseFileName,
|
||||
GetCanonicalFileName,
|
||||
getConditions,
|
||||
getDefaultResolutionModeForFileWorker,
|
||||
getDirectoryPath,
|
||||
getEmitModuleResolutionKind,
|
||||
getModeForResolutionAtIndex,
|
||||
getModuleNameStringLiteralAt,
|
||||
getModuleSpecifierEndingPreference,
|
||||
getNodeModulePathParts,
|
||||
@@ -143,12 +143,13 @@ export interface ModuleSpecifierPreferences {
|
||||
/**
|
||||
* @param syntaxImpliedNodeFormat Used when the import syntax implies ESM or CJS irrespective of the mode of the file.
|
||||
*/
|
||||
getAllowedEndingsInPreferredOrder(syntaxImpliedNodeFormat?: SourceFile["impliedNodeFormat"]): ModuleSpecifierEnding[];
|
||||
getAllowedEndingsInPreferredOrder(syntaxImpliedNodeFormat?: ResolutionMode): ModuleSpecifierEnding[];
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getModuleSpecifierPreferences(
|
||||
{ importModuleSpecifierPreference, importModuleSpecifierEnding }: UserPreferences,
|
||||
host: Pick<ModuleSpecifierResolutionHost, "getDefaultResolutionModeForFile">,
|
||||
compilerOptions: CompilerOptions,
|
||||
importingSourceFile: Pick<SourceFile, "fileName" | "impliedNodeFormat">,
|
||||
oldImportSpecifier?: string,
|
||||
@@ -163,8 +164,10 @@ export function getModuleSpecifierPreferences(
|
||||
importModuleSpecifierPreference === "project-relative" ? RelativePreference.ExternalNonRelative :
|
||||
RelativePreference.Shortest,
|
||||
getAllowedEndingsInPreferredOrder: syntaxImpliedNodeFormat => {
|
||||
const preferredEnding = syntaxImpliedNodeFormat !== importingSourceFile.impliedNodeFormat ? getPreferredEnding(syntaxImpliedNodeFormat) : filePreferredEnding;
|
||||
if ((syntaxImpliedNodeFormat ?? importingSourceFile.impliedNodeFormat) === ModuleKind.ESNext) {
|
||||
const impliedNodeFormat = getDefaultResolutionModeForFile(importingSourceFile, host, compilerOptions);
|
||||
const preferredEnding = syntaxImpliedNodeFormat !== impliedNodeFormat ? getPreferredEnding(syntaxImpliedNodeFormat) : filePreferredEnding;
|
||||
const moduleResolution = getEmitModuleResolutionKind(compilerOptions);
|
||||
if ((syntaxImpliedNodeFormat ?? impliedNodeFormat) === ModuleKind.ESNext && ModuleResolutionKind.Node16 <= moduleResolution && moduleResolution <= ModuleResolutionKind.NodeNext) {
|
||||
if (shouldAllowImportingTsExtension(compilerOptions, importingSourceFile.fileName)) {
|
||||
return [ModuleSpecifierEnding.TsExtension, ModuleSpecifierEnding.JsExtension];
|
||||
}
|
||||
@@ -204,7 +207,7 @@ export function getModuleSpecifierPreferences(
|
||||
}
|
||||
return getModuleSpecifierEndingPreference(
|
||||
importModuleSpecifierEnding,
|
||||
resolutionMode ?? importingSourceFile.impliedNodeFormat,
|
||||
resolutionMode ?? getDefaultResolutionModeForFile(importingSourceFile, host, compilerOptions),
|
||||
compilerOptions,
|
||||
isFullSourceFile(importingSourceFile) ? importingSourceFile : undefined,
|
||||
);
|
||||
@@ -225,7 +228,7 @@ export function updateModuleSpecifier(
|
||||
oldImportSpecifier: string,
|
||||
options: ModuleSpecifierOptions = {},
|
||||
): string | undefined {
|
||||
const res = getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getModuleSpecifierPreferences({}, compilerOptions, importingSourceFile, oldImportSpecifier), {}, options);
|
||||
const res = getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getModuleSpecifierPreferences({}, host, compilerOptions, importingSourceFile, oldImportSpecifier), {}, options);
|
||||
if (res === oldImportSpecifier) return undefined;
|
||||
return res;
|
||||
}
|
||||
@@ -245,7 +248,7 @@ export function getModuleSpecifier(
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
options: ModuleSpecifierOptions = {},
|
||||
): string {
|
||||
return getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getModuleSpecifierPreferences({}, compilerOptions, importingSourceFile), {}, options);
|
||||
return getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getModuleSpecifierPreferences({}, host, compilerOptions, importingSourceFile), {}, options);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -275,7 +278,7 @@ function getModuleSpecifierWorker(
|
||||
const info = getInfo(importingSourceFileName, host);
|
||||
const modulePaths = getAllModulePaths(info, toFileName, host, userPreferences, compilerOptions, options);
|
||||
return firstDefined(modulePaths, modulePath => tryGetModuleNameAsNodeModule(modulePath, info, importingSourceFile, host, compilerOptions, userPreferences, /*packageNameOnly*/ undefined, options.overrideImportMode)) ||
|
||||
getLocalModuleSpecifier(toFileName, info, compilerOptions, host, options.overrideImportMode || importingSourceFile.impliedNodeFormat, preferences);
|
||||
getLocalModuleSpecifier(toFileName, info, compilerOptions, host, options.overrideImportMode || getDefaultResolutionModeForFile(importingSourceFile, host, compilerOptions), preferences);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -403,7 +406,7 @@ export function getLocalModuleSpecifierBetweenFileNames(
|
||||
compilerOptions,
|
||||
host,
|
||||
importMode,
|
||||
getModuleSpecifierPreferences({}, compilerOptions, importingFile),
|
||||
getModuleSpecifierPreferences({}, host, compilerOptions, importingFile),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -417,7 +420,7 @@ function computeModuleSpecifiers(
|
||||
forAutoImport: boolean,
|
||||
): ModuleSpecifierResult {
|
||||
const info = getInfo(importingSourceFile.fileName, host);
|
||||
const preferences = getModuleSpecifierPreferences(userPreferences, compilerOptions, importingSourceFile);
|
||||
const preferences = getModuleSpecifierPreferences(userPreferences, host, compilerOptions, importingSourceFile);
|
||||
const existingSpecifier = isFullSourceFile(importingSourceFile) && forEach(modulePaths, modulePath =>
|
||||
forEach(
|
||||
host.getFileIncludeReasons().get(toPath(modulePath.path, host.getCurrentDirectory(), info.getCanonicalFileName)),
|
||||
@@ -425,7 +428,11 @@ function computeModuleSpecifiers(
|
||||
if (reason.kind !== FileIncludeKind.Import || reason.file !== importingSourceFile.path) return undefined;
|
||||
// If the candidate import mode doesn't match the mode we're generating for, don't consider it
|
||||
// TODO: maybe useful to keep around as an alternative option for certain contexts where the mode is overridable
|
||||
if (importingSourceFile.impliedNodeFormat && importingSourceFile.impliedNodeFormat !== getModeForResolutionAtIndex(importingSourceFile, reason.index, compilerOptions)) return undefined;
|
||||
const existingMode = host.getModeForResolutionAtIndex(importingSourceFile, reason.index);
|
||||
const targetMode = options.overrideImportMode ?? host.getDefaultResolutionModeForFile(importingSourceFile);
|
||||
if (existingMode !== targetMode && existingMode !== undefined && targetMode !== undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const specifier = getModuleNameStringLiteralAt(importingSourceFile, reason.index).text;
|
||||
// If the preference is for non relative and the module specifier is relative, ignore it
|
||||
return preferences.relativePreference !== RelativePreference.NonRelative || !pathIsRelative(specifier) ?
|
||||
@@ -1093,7 +1100,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
|
||||
|
||||
// Simplify the full file path to something that can be resolved by Node.
|
||||
|
||||
const preferences = getModuleSpecifierPreferences(userPreferences, options, importingSourceFile);
|
||||
const preferences = getModuleSpecifierPreferences(userPreferences, host, options, importingSourceFile);
|
||||
const allowedEndings = preferences.getAllowedEndingsInPreferredOrder();
|
||||
let moduleSpecifier = path;
|
||||
let isPackageRootPath = false;
|
||||
@@ -1153,7 +1160,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
|
||||
const cachedPackageJson = host.getPackageJsonInfoCache?.()?.getPackageJsonInfo(packageJsonPath);
|
||||
if (isPackageJsonInfo(cachedPackageJson) || cachedPackageJson === undefined && host.fileExists(packageJsonPath)) {
|
||||
const packageJsonContent: Record<string, any> | undefined = cachedPackageJson?.contents.packageJsonContent || tryParseJson(host.readFile!(packageJsonPath)!);
|
||||
const importMode = overrideMode || importingSourceFile.impliedNodeFormat;
|
||||
const importMode = overrideMode || getDefaultResolutionModeForFile(importingSourceFile, host, options);
|
||||
if (getResolvePackageJsonExports(options)) {
|
||||
// The package name that we found in node_modules could be different from the package
|
||||
// name in the package.json content via url/filepath dependency specifiers. We need to
|
||||
@@ -1348,3 +1355,7 @@ function getRelativePathIfInSameVolume(path: string, directoryPath: string, getC
|
||||
function isPathRelativeToParent(path: string): boolean {
|
||||
return startsWith(path, "..");
|
||||
}
|
||||
|
||||
function getDefaultResolutionModeForFile(file: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, host: Pick<ModuleSpecifierResolutionHost, "getDefaultResolutionModeForFile">, compilerOptions: CompilerOptions) {
|
||||
return isFullSourceFile(file) ? host.getDefaultResolutionModeForFile(file) : getDefaultResolutionModeForFileWorker(file, compilerOptions);
|
||||
}
|
||||
|
||||
+143
-27
@@ -175,6 +175,7 @@ import {
|
||||
ImportClause,
|
||||
ImportDeclaration,
|
||||
ImportOrExportSpecifier,
|
||||
importSyntaxAffectsModuleResolution,
|
||||
InternalEmitFlags,
|
||||
inverseJsxOptionMap,
|
||||
isAmbientModule,
|
||||
@@ -840,9 +841,11 @@ export function flattenDiagnosticMessageText(diag: string | DiagnosticMessageCha
|
||||
* @internal
|
||||
*/
|
||||
export interface SourceFileImportsList {
|
||||
/** @internal */ imports: SourceFile["imports"];
|
||||
/** @internal */ moduleAugmentations: SourceFile["moduleAugmentations"];
|
||||
imports: SourceFile["imports"];
|
||||
moduleAugmentations: SourceFile["moduleAugmentations"];
|
||||
impliedNodeFormat?: ResolutionMode;
|
||||
fileName: string;
|
||||
packageJsonScope?: SourceFile["packageJsonScope"];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -866,7 +869,7 @@ export function getModeForFileReference(ref: FileReference | string, containingF
|
||||
* should be the options of the referenced project, not the referencing project.
|
||||
*/
|
||||
export function getModeForResolutionAtIndex(file: SourceFile, index: number, compilerOptions: CompilerOptions): ResolutionMode;
|
||||
/** @internal */
|
||||
/** @internal @knipignore */
|
||||
// eslint-disable-next-line @typescript-eslint/unified-signatures
|
||||
export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number, compilerOptions: CompilerOptions): ResolutionMode;
|
||||
export function getModeForResolutionAtIndex(file: SourceFileImportsList, index: number, compilerOptions?: CompilerOptions): ResolutionMode {
|
||||
@@ -888,22 +891,47 @@ export function isExclusivelyTypeOnlyImportOrExport(decl: ImportDeclaration | Ex
|
||||
|
||||
/**
|
||||
* Use `program.getModeForUsageLocation`, which retrieves the correct `compilerOptions`, instead of this function whenever possible.
|
||||
* Calculates the final resolution mode for a given module reference node. This is the resolution mode explicitly provided via import
|
||||
* attributes, if present, or the syntax the usage would have if emitted to JavaScript. In `--module node16` or `nodenext`, this may
|
||||
* depend on the file's `impliedNodeFormat`. In `--module preserve`, it depends only on the input syntax of the reference. In other
|
||||
* `module` modes, when overriding import attributes are not provided, this function returns `undefined`, as the result would have no
|
||||
* impact on module resolution, emit, or type checking.
|
||||
* Calculates the final resolution mode for a given module reference node. This function only returns a result when module resolution
|
||||
* settings allow differing resolution between ESM imports and CJS requires, or when a mode is explicitly provided via import attributes,
|
||||
* which cause an `import` or `require` condition to be used during resolution regardless of module resolution settings. In absence of
|
||||
* overriding attributes, and in modes that support differing resolution, the result indicates the syntax the usage would emit to JavaScript.
|
||||
* Some examples:
|
||||
*
|
||||
* ```ts
|
||||
* // tsc foo.mts --module nodenext
|
||||
* import {} from "mod";
|
||||
* // Result: ESNext - the import emits as ESM due to `impliedNodeFormat` set by .mts file extension
|
||||
*
|
||||
* // tsc foo.cts --module nodenext
|
||||
* import {} from "mod";
|
||||
* // Result: CommonJS - the import emits as CJS due to `impliedNodeFormat` set by .cts file extension
|
||||
*
|
||||
* // tsc foo.ts --module preserve --moduleResolution bundler
|
||||
* import {} from "mod";
|
||||
* // Result: ESNext - the import emits as ESM due to `--module preserve` and `--moduleResolution bundler`
|
||||
* // supports conditional imports/exports
|
||||
*
|
||||
* // tsc foo.ts --module preserve --moduleResolution node10
|
||||
* import {} from "mod";
|
||||
* // Result: undefined - the import emits as ESM due to `--module preserve`, but `--moduleResolution node10`
|
||||
* // does not support conditional imports/exports
|
||||
*
|
||||
* // tsc foo.ts --module commonjs --moduleResolution node10
|
||||
* import type {} from "mod" with { "resolution-mode": "import" };
|
||||
* // Result: ESNext - conditional imports/exports always supported with "resolution-mode" attribute
|
||||
* ```
|
||||
*
|
||||
* @param file The file the import or import-like reference is contained within
|
||||
* @param usage The module reference string
|
||||
* @param compilerOptions The compiler options for the program that owns the file. If the file belongs to a referenced project, the compiler options
|
||||
* should be the options of the referenced project, not the referencing project.
|
||||
* @returns The final resolution mode of the import
|
||||
*/
|
||||
export function getModeForUsageLocation(file: { impliedNodeFormat?: ResolutionMode; }, usage: StringLiteralLike, compilerOptions: CompilerOptions) {
|
||||
export function getModeForUsageLocation(file: SourceFile, usage: StringLiteralLike, compilerOptions: CompilerOptions) {
|
||||
return getModeForUsageLocationWorker(file, usage, compilerOptions);
|
||||
}
|
||||
|
||||
function getModeForUsageLocationWorker(file: { impliedNodeFormat?: ResolutionMode; }, usage: StringLiteralLike, compilerOptions?: CompilerOptions) {
|
||||
function getModeForUsageLocationWorker(file: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, usage: StringLiteralLike, compilerOptions?: CompilerOptions) {
|
||||
if (isImportDeclaration(usage.parent) || isExportDeclaration(usage.parent) || isJSDocImportTag(usage.parent)) {
|
||||
const isTypeOnly = isExclusivelyTypeOnlyImportOrExport(usage.parent);
|
||||
if (isTypeOnly) {
|
||||
@@ -919,20 +947,36 @@ function getModeForUsageLocationWorker(file: { impliedNodeFormat?: ResolutionMod
|
||||
return override;
|
||||
}
|
||||
}
|
||||
if (compilerOptions && getEmitModuleKind(compilerOptions) === ModuleKind.Preserve) {
|
||||
return (usage.parent.parent && isImportEqualsDeclaration(usage.parent.parent) || isRequireCall(usage.parent, /*requireStringLiteralLikeArgument*/ false))
|
||||
? ModuleKind.CommonJS
|
||||
: ModuleKind.ESNext;
|
||||
|
||||
if (compilerOptions && importSyntaxAffectsModuleResolution(compilerOptions)) {
|
||||
return getEmitSyntaxForUsageLocationWorker(file, usage, compilerOptions);
|
||||
}
|
||||
if (file.impliedNodeFormat === undefined) return undefined;
|
||||
if (file.impliedNodeFormat !== ModuleKind.ESNext) {
|
||||
// in cjs files, import call expressions are esm format, otherwise everything is cjs
|
||||
return isImportCall(walkUpParenthesizedExpressions(usage.parent)) ? ModuleKind.ESNext : ModuleKind.CommonJS;
|
||||
}
|
||||
|
||||
function getEmitSyntaxForUsageLocationWorker(file: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, usage: StringLiteralLike, compilerOptions?: CompilerOptions): ResolutionMode {
|
||||
if (!compilerOptions) {
|
||||
// This should always be provided, but we try to fail somewhat
|
||||
// gracefully to allow projects like ts-node time to update.
|
||||
return undefined;
|
||||
}
|
||||
// in esm files, import=require statements are cjs format, otherwise everything is esm
|
||||
// imports are only parent'd up to their containing declaration/expression, so access farther parents with care
|
||||
const exprParentParent = walkUpParenthesizedExpressions(usage.parent)?.parent;
|
||||
return exprParentParent && isImportEqualsDeclaration(exprParentParent) ? ModuleKind.CommonJS : ModuleKind.ESNext;
|
||||
if (exprParentParent && isImportEqualsDeclaration(exprParentParent) || isRequireCall(usage.parent, /*requireStringLiteralLikeArgument*/ false)) {
|
||||
return ModuleKind.CommonJS;
|
||||
}
|
||||
if (isImportCall(walkUpParenthesizedExpressions(usage.parent))) {
|
||||
return shouldTransformImportCallWorker(file, compilerOptions) ? ModuleKind.CommonJS : ModuleKind.ESNext;
|
||||
}
|
||||
// If we're in --module preserve on an input file, we know that an import
|
||||
// is an import. But if this is a declaration file, we'd prefer to use the
|
||||
// impliedNodeFormat. Since we want things to be consistent between the two,
|
||||
// we need to issue errors when the user writes ESM syntax in a definitely-CJS
|
||||
// file, until/unless declaration emit can indicate a true ESM import. On the
|
||||
// other hand, writing CJS syntax in a definitely-ESM file is fine, since declaration
|
||||
// emit preserves the CJS syntax.
|
||||
const fileEmitMode = getEmitModuleFormatOfFileWorker(file, compilerOptions);
|
||||
return fileEmitMode === ModuleKind.CommonJS ? ModuleKind.CommonJS :
|
||||
emitModuleKindIsNonNodeESM(fileEmitMode) || fileEmitMode === ModuleKind.Preserve ? ModuleKind.ESNext :
|
||||
undefined;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -1028,7 +1072,7 @@ function getTypeReferenceResolutionName<T extends FileReference | string>(entry:
|
||||
|
||||
const typeReferenceResolutionNameAndModeGetter: ResolutionNameAndModeGetter<FileReference | string, SourceFile | undefined> = {
|
||||
getName: getTypeReferenceResolutionName,
|
||||
getMode: (entry, file) => getModeForFileReference(entry, file?.impliedNodeFormat),
|
||||
getMode: (entry, file, compilerOptions) => getModeForFileReference(entry, file && getDefaultResolutionModeForFileWorker(file, compilerOptions)),
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
@@ -1358,6 +1402,7 @@ export function getImpliedNodeFormatForFileWorker(
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function lookupFromPackageJson(): Partial<CreateSourceFileOptions> {
|
||||
const state = getTemporaryModuleResolutionState(packageJsonInfoCache, host, options);
|
||||
const packageJsonLocations: string[] = [];
|
||||
@@ -1927,6 +1972,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
isSourceFileFromExternalLibrary,
|
||||
isSourceFileDefaultLibrary,
|
||||
getModeForUsageLocation,
|
||||
getEmitSyntaxForUsageLocation,
|
||||
getModeForResolutionAtIndex,
|
||||
getSourceFileFromReference,
|
||||
getLibFileFromReference,
|
||||
@@ -1955,6 +2001,11 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
forEachResolvedProjectReference,
|
||||
isSourceOfProjectReferenceRedirect,
|
||||
getRedirectReferenceForResolutionFromSourceOfProject,
|
||||
getCompilerOptionsForFile,
|
||||
getDefaultResolutionModeForFile,
|
||||
getEmitModuleFormatOfFile,
|
||||
getImpliedNodeFormatForEmit,
|
||||
shouldTransformImportCall,
|
||||
emitBuildInfo,
|
||||
fileExists,
|
||||
readFile,
|
||||
@@ -2669,6 +2720,10 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
getSymlinkCache,
|
||||
writeFile: writeFileCallback || writeFile,
|
||||
isEmitBlocked,
|
||||
shouldTransformImportCall,
|
||||
getEmitModuleFormatOfFile,
|
||||
getDefaultResolutionModeForFile,
|
||||
getModeForResolutionAtIndex,
|
||||
readFile: f => host.readFile(f),
|
||||
fileExists: f => {
|
||||
// Use local caches
|
||||
@@ -3955,11 +4010,15 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
// store resolved type directive on the file
|
||||
const fileName = ref.fileName;
|
||||
resolutionsInFile.set(fileName, getModeForFileReference(ref, file.impliedNodeFormat), resolvedTypeReferenceDirective);
|
||||
const mode = ref.resolutionMode || file.impliedNodeFormat;
|
||||
const mode = ref.resolutionMode || getDefaultResolutionModeForFile(file);
|
||||
processTypeReferenceDirective(fileName, mode, resolvedTypeReferenceDirective, { kind: FileIncludeKind.TypeReferenceDirective, file: file.path, index });
|
||||
}
|
||||
}
|
||||
|
||||
function getCompilerOptionsForFile(file: SourceFile): CompilerOptions {
|
||||
return getRedirectReferenceForResolution(file)?.commandLine.options || options;
|
||||
}
|
||||
|
||||
function processTypeReferenceDirective(
|
||||
typeReferenceDirective: string,
|
||||
mode: ResolutionMode,
|
||||
@@ -4074,7 +4133,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
const resolutions = resolvedModulesProcessing?.get(file.path) ||
|
||||
resolveModuleNamesReusingOldState(moduleNames, file);
|
||||
Debug.assert(resolutions.length === moduleNames.length);
|
||||
const optionsForFile = getRedirectReferenceForResolution(file)?.commandLine.options || options;
|
||||
const optionsForFile = getCompilerOptionsForFile(file);
|
||||
const resolutionsInFile = createModeAwareCache<ResolutionWithFailedLookupLocations>();
|
||||
(resolvedModules ??= new Map()).set(file.path, resolutionsInFile);
|
||||
for (let index = 0; index < moduleNames.length; index++) {
|
||||
@@ -4664,7 +4723,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
}
|
||||
else {
|
||||
reasons?.forEach(processReason);
|
||||
redirectInfo = file && explainIfFileIsRedirectAndImpliedFormat(file);
|
||||
redirectInfo = file && explainIfFileIsRedirectAndImpliedFormat(file, getCompilerOptionsForFile(file));
|
||||
}
|
||||
|
||||
if (fileProcessingReason) processReason(fileProcessingReason);
|
||||
@@ -5098,13 +5157,70 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
}
|
||||
|
||||
function getModeForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode {
|
||||
const optionsForFile = getRedirectReferenceForResolution(file)?.commandLine.options || options;
|
||||
return getModeForUsageLocationWorker(file, usage, optionsForFile);
|
||||
return getModeForUsageLocationWorker(file, usage, getCompilerOptionsForFile(file));
|
||||
}
|
||||
|
||||
function getEmitSyntaxForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode {
|
||||
return getEmitSyntaxForUsageLocationWorker(file, usage, getCompilerOptionsForFile(file));
|
||||
}
|
||||
|
||||
function getModeForResolutionAtIndex(file: SourceFile, index: number): ResolutionMode {
|
||||
return getModeForUsageLocation(file, getModuleNameStringLiteralAt(file, index));
|
||||
}
|
||||
|
||||
function getDefaultResolutionModeForFile(sourceFile: SourceFile): ResolutionMode {
|
||||
return getDefaultResolutionModeForFileWorker(sourceFile, getCompilerOptionsForFile(sourceFile));
|
||||
}
|
||||
|
||||
function getImpliedNodeFormatForEmit(sourceFile: SourceFile): ResolutionMode {
|
||||
return getImpliedNodeFormatForEmitWorker(sourceFile, getCompilerOptionsForFile(sourceFile));
|
||||
}
|
||||
|
||||
function getEmitModuleFormatOfFile(sourceFile: SourceFile): ModuleKind {
|
||||
return getEmitModuleFormatOfFileWorker(sourceFile, getCompilerOptionsForFile(sourceFile));
|
||||
}
|
||||
|
||||
function shouldTransformImportCall(sourceFile: SourceFile): boolean {
|
||||
return shouldTransformImportCallWorker(sourceFile, getCompilerOptionsForFile(sourceFile));
|
||||
}
|
||||
}
|
||||
|
||||
function shouldTransformImportCallWorker(sourceFile: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, options: CompilerOptions): boolean {
|
||||
const moduleKind = getEmitModuleKind(options);
|
||||
if (ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext || moduleKind === ModuleKind.Preserve) {
|
||||
return false;
|
||||
}
|
||||
return getEmitModuleFormatOfFileWorker(sourceFile, options) < ModuleKind.ES2015;
|
||||
}
|
||||
/** @internal Prefer `program.getEmitModuleFormatOfFile` when possible. */
|
||||
export function getEmitModuleFormatOfFileWorker(sourceFile: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, options: CompilerOptions): ModuleKind {
|
||||
return getImpliedNodeFormatForEmitWorker(sourceFile, options) ?? getEmitModuleKind(options);
|
||||
}
|
||||
/** @internal Prefer `program.getImpliedNodeFormatForEmit` when possible. */
|
||||
export function getImpliedNodeFormatForEmitWorker(sourceFile: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, options: CompilerOptions): ResolutionMode {
|
||||
const moduleKind = getEmitModuleKind(options);
|
||||
if (ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) {
|
||||
return sourceFile.impliedNodeFormat;
|
||||
}
|
||||
if (
|
||||
sourceFile.impliedNodeFormat === ModuleKind.CommonJS
|
||||
&& (sourceFile.packageJsonScope?.contents.packageJsonContent.type === "commonjs"
|
||||
|| fileExtensionIsOneOf(sourceFile.fileName, [Extension.Cjs, Extension.Cts]))
|
||||
) {
|
||||
return ModuleKind.CommonJS;
|
||||
}
|
||||
if (
|
||||
sourceFile.impliedNodeFormat === ModuleKind.ESNext
|
||||
&& (sourceFile.packageJsonScope?.contents.packageJsonContent.type === "module"
|
||||
|| fileExtensionIsOneOf(sourceFile.fileName, [Extension.Mjs, Extension.Mts]))
|
||||
) {
|
||||
return ModuleKind.ESNext;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/** @internal Prefer `program.getDefaultResolutionModeForFile` when possible. */
|
||||
export function getDefaultResolutionModeForFileWorker(sourceFile: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, options: CompilerOptions): ResolutionMode {
|
||||
return importSyntaxAffectsModuleResolution(options) ? getImpliedNodeFormatForEmitWorker(sourceFile, options) : undefined;
|
||||
}
|
||||
|
||||
interface HostForUseSourceOfProjectReferenceRedirect {
|
||||
|
||||
@@ -65,10 +65,10 @@ import {
|
||||
transformESDecorators,
|
||||
transformESNext,
|
||||
transformGenerators,
|
||||
transformImpliedNodeFormatDependentModule,
|
||||
transformJsx,
|
||||
transformLegacyDecorators,
|
||||
transformModule,
|
||||
transformNodeModule,
|
||||
transformSystemModule,
|
||||
transformTypeScript,
|
||||
VariableDeclaration,
|
||||
@@ -77,17 +77,23 @@ import * as performance from "./_namespaces/ts.performance.js";
|
||||
|
||||
function getModuleTransformer(moduleKind: ModuleKind): TransformerFactory<SourceFile | Bundle> {
|
||||
switch (moduleKind) {
|
||||
case ModuleKind.Preserve:
|
||||
// `transformECMAScriptModule` contains logic for preserving
|
||||
// CJS input syntax in `--module preserve`
|
||||
return transformECMAScriptModule;
|
||||
case ModuleKind.ESNext:
|
||||
case ModuleKind.ES2022:
|
||||
case ModuleKind.ES2020:
|
||||
case ModuleKind.ES2015:
|
||||
case ModuleKind.Preserve:
|
||||
return transformECMAScriptModule;
|
||||
case ModuleKind.System:
|
||||
return transformSystemModule;
|
||||
case ModuleKind.Node16:
|
||||
case ModuleKind.NodeNext:
|
||||
return transformNodeModule;
|
||||
case ModuleKind.CommonJS:
|
||||
// Wraps `transformModule` and `transformECMAScriptModule` and
|
||||
// selects between them based on the `impliedNodeFormat` of the
|
||||
// source file.
|
||||
return transformImpliedNodeFormatDependentModule;
|
||||
case ModuleKind.System:
|
||||
return transformSystemModule;
|
||||
default:
|
||||
return transformModule;
|
||||
}
|
||||
|
||||
+5
-4
@@ -14,7 +14,7 @@ import {
|
||||
} from "../../_namespaces/ts.js";
|
||||
|
||||
/** @internal */
|
||||
export function transformNodeModule(context: TransformationContext) {
|
||||
export function transformImpliedNodeFormatDependentModule(context: TransformationContext) {
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
const previousOnEmitNode = context.onEmitNode;
|
||||
|
||||
@@ -30,6 +30,7 @@ export function transformNodeModule(context: TransformationContext) {
|
||||
|
||||
const cjsOnSubstituteNode = context.onSubstituteNode;
|
||||
const cjsOnEmitNode = context.onEmitNode;
|
||||
const getEmitModuleFormatOfFile = (file: SourceFile) => context.getEmitHost().getEmitModuleFormatOfFile(file);
|
||||
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
context.onEmitNode = onEmitNode;
|
||||
@@ -51,7 +52,7 @@ export function transformNodeModule(context: TransformationContext) {
|
||||
if (!currentSourceFile) {
|
||||
return previousOnSubstituteNode(hint, node);
|
||||
}
|
||||
if (currentSourceFile.impliedNodeFormat === ModuleKind.ESNext) {
|
||||
if (getEmitModuleFormatOfFile(currentSourceFile) >= ModuleKind.ES2015) {
|
||||
return esmOnSubstituteNode(hint, node);
|
||||
}
|
||||
return cjsOnSubstituteNode(hint, node);
|
||||
@@ -65,14 +66,14 @@ export function transformNodeModule(context: TransformationContext) {
|
||||
if (!currentSourceFile) {
|
||||
return previousOnEmitNode(hint, node, emitCallback);
|
||||
}
|
||||
if (currentSourceFile.impliedNodeFormat === ModuleKind.ESNext) {
|
||||
if (getEmitModuleFormatOfFile(currentSourceFile) >= ModuleKind.ES2015) {
|
||||
return esmOnEmitNode(hint, node, emitCallback);
|
||||
}
|
||||
return cjsOnEmitNode(hint, node, emitCallback);
|
||||
}
|
||||
|
||||
function getModuleTransformForFile(file: SourceFile): typeof esmTransform {
|
||||
return file.impliedNodeFormat === ModuleKind.ESNext ? esmTransform : cjsTransform;
|
||||
return getEmitModuleFormatOfFile(file) >= ModuleKind.ES2015 ? esmTransform : cjsTransform;
|
||||
}
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
@@ -797,7 +797,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile
|
||||
case SyntaxKind.PartiallyEmittedExpression:
|
||||
return visitPartiallyEmittedExpression(node as PartiallyEmittedExpression, valueIsDiscarded);
|
||||
case SyntaxKind.CallExpression:
|
||||
if (isImportCall(node) && currentSourceFile.impliedNodeFormat === undefined) {
|
||||
if (isImportCall(node) && host.shouldTransformImportCall(currentSourceFile)) {
|
||||
return visitImportCallExpression(node);
|
||||
}
|
||||
break;
|
||||
|
||||
+81
-10
@@ -4755,21 +4755,79 @@ export interface Program extends ScriptReferenceHost {
|
||||
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
|
||||
isSourceFileDefaultLibrary(file: SourceFile): boolean;
|
||||
/**
|
||||
* Calculates the final resolution mode for a given module reference node. This is the resolution mode explicitly provided via import
|
||||
* attributes, if present, or the syntax the usage would have if emitted to JavaScript. In `--module node16` or `nodenext`, this may
|
||||
* depend on the file's `impliedNodeFormat`. In `--module preserve`, it depends only on the input syntax of the reference. In other
|
||||
* `module` modes, when overriding import attributes are not provided, this function returns `undefined`, as the result would have no
|
||||
* impact on module resolution, emit, or type checking.
|
||||
* Calculates the final resolution mode for a given module reference node. This function only returns a result when module resolution
|
||||
* settings allow differing resolution between ESM imports and CJS requires, or when a mode is explicitly provided via import attributes,
|
||||
* which cause an `import` or `require` condition to be used during resolution regardless of module resolution settings. In absence of
|
||||
* overriding attributes, and in modes that support differing resolution, the result indicates the syntax the usage would emit to JavaScript.
|
||||
* Some examples:
|
||||
*
|
||||
* ```ts
|
||||
* // tsc foo.mts --module nodenext
|
||||
* import {} from "mod";
|
||||
* // Result: ESNext - the import emits as ESM due to `impliedNodeFormat` set by .mts file extension
|
||||
*
|
||||
* // tsc foo.cts --module nodenext
|
||||
* import {} from "mod";
|
||||
* // Result: CommonJS - the import emits as CJS due to `impliedNodeFormat` set by .cts file extension
|
||||
*
|
||||
* // tsc foo.ts --module preserve --moduleResolution bundler
|
||||
* import {} from "mod";
|
||||
* // Result: ESNext - the import emits as ESM due to `--module preserve` and `--moduleResolution bundler`
|
||||
* // supports conditional imports/exports
|
||||
*
|
||||
* // tsc foo.ts --module preserve --moduleResolution node10
|
||||
* import {} from "mod";
|
||||
* // Result: undefined - the import emits as ESM due to `--module preserve`, but `--moduleResolution node10`
|
||||
* // does not support conditional imports/exports
|
||||
*
|
||||
* // tsc foo.ts --module commonjs --moduleResolution node10
|
||||
* import type {} from "mod" with { "resolution-mode": "import" };
|
||||
* // Result: ESNext - conditional imports/exports always supported with "resolution-mode" attribute
|
||||
* ```
|
||||
*/
|
||||
getModeForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode;
|
||||
/**
|
||||
* Calculates the final resolution mode for an import at some index within a file's `imports` list. This is the resolution mode
|
||||
* explicitly provided via import attributes, if present, or the syntax the usage would have if emitted to JavaScript. In
|
||||
* `--module node16` or `nodenext`, this may depend on the file's `impliedNodeFormat`. In `--module preserve`, it depends only on the
|
||||
* input syntax of the reference. In other `module` modes, when overriding import attributes are not provided, this function returns
|
||||
* `undefined`, as the result would have no impact on module resolution, emit, or type checking.
|
||||
* Calculates the final resolution mode for an import at some index within a file's `imports` list. This function only returns a result
|
||||
* when module resolution settings allow differing resolution between ESM imports and CJS requires, or when a mode is explicitly provided
|
||||
* via import attributes, which cause an `import` or `require` condition to be used during resolution regardless of module resolution
|
||||
* settings. In absence of overriding attributes, and in modes that support differing resolution, the result indicates the syntax the
|
||||
* usage would emit to JavaScript. Some examples:
|
||||
*
|
||||
* ```ts
|
||||
* // tsc foo.mts --module nodenext
|
||||
* import {} from "mod";
|
||||
* // Result: ESNext - the import emits as ESM due to `impliedNodeFormat` set by .mts file extension
|
||||
*
|
||||
* // tsc foo.cts --module nodenext
|
||||
* import {} from "mod";
|
||||
* // Result: CommonJS - the import emits as CJS due to `impliedNodeFormat` set by .cts file extension
|
||||
*
|
||||
* // tsc foo.ts --module preserve --moduleResolution bundler
|
||||
* import {} from "mod";
|
||||
* // Result: ESNext - the import emits as ESM due to `--module preserve` and `--moduleResolution bundler`
|
||||
* // supports conditional imports/exports
|
||||
*
|
||||
* // tsc foo.ts --module preserve --moduleResolution node10
|
||||
* import {} from "mod";
|
||||
* // Result: undefined - the import emits as ESM due to `--module preserve`, but `--moduleResolution node10`
|
||||
* // does not support conditional imports/exports
|
||||
*
|
||||
* // tsc foo.ts --module commonjs --moduleResolution node10
|
||||
* import type {} from "mod" with { "resolution-mode": "import" };
|
||||
* // Result: ESNext - conditional imports/exports always supported with "resolution-mode" attribute
|
||||
* ```
|
||||
*/
|
||||
getModeForResolutionAtIndex(file: SourceFile, index: number): ResolutionMode;
|
||||
/**
|
||||
* @internal
|
||||
* The resolution mode to use for module resolution or module specifier resolution
|
||||
* outside the context of an existing module reference, where
|
||||
* `program.getModeForUsageLocation` should be used instead.
|
||||
*/
|
||||
getDefaultResolutionModeForFile(sourceFile: SourceFile): ResolutionMode;
|
||||
/** @internal */ getImpliedNodeFormatForEmit(sourceFile: SourceFile): ResolutionMode;
|
||||
/** @internal */ getEmitModuleFormatOfFile(sourceFile: SourceFile): ModuleKind;
|
||||
/** @internal */ shouldTransformImportCall(sourceFile: SourceFile): boolean;
|
||||
|
||||
// For testing purposes only.
|
||||
// This is set on created program to let us know how the program was created using old program
|
||||
@@ -4824,6 +4882,7 @@ export interface Program extends ScriptReferenceHost {
|
||||
/** @internal */ getResolvedProjectReferenceByPath(projectReferencePath: Path): ResolvedProjectReference | undefined;
|
||||
/** @internal */ getRedirectReferenceForResolutionFromSourceOfProject(filePath: Path): ResolvedProjectReference | undefined;
|
||||
/** @internal */ isSourceOfProjectReferenceRedirect(fileName: string): boolean;
|
||||
/** @internal */ getCompilerOptionsForFile(file: SourceFile): CompilerOptions;
|
||||
/** @internal */ getBuildInfo?(): BuildInfo;
|
||||
/** @internal */ emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
|
||||
/**
|
||||
@@ -4939,8 +4998,12 @@ export interface TypeCheckerHost extends ModuleSpecifierResolutionHost {
|
||||
getSourceFile(fileName: string): SourceFile | undefined;
|
||||
getProjectReferenceRedirect(fileName: string): string | undefined;
|
||||
isSourceOfProjectReferenceRedirect(fileName: string): boolean;
|
||||
getEmitSyntaxForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode;
|
||||
getRedirectReferenceForResolutionFromSourceOfProject(filePath: Path): ResolvedProjectReference | undefined;
|
||||
getModeForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode;
|
||||
getDefaultResolutionModeForFile(sourceFile: SourceFile): ResolutionMode;
|
||||
getImpliedNodeFormatForEmit(sourceFile: SourceFile): ResolutionMode;
|
||||
getEmitModuleFormatOfFile(sourceFile: SourceFile): ModuleKind;
|
||||
|
||||
getResolvedModule(f: SourceFile, moduleName: string, mode: ResolutionMode): ResolvedModuleWithFailedLookupLocations | undefined;
|
||||
|
||||
@@ -5604,6 +5667,9 @@ export interface RequireVariableDeclarationList extends VariableDeclarationList
|
||||
readonly declarations: NodeArray<VariableDeclarationInitializedTo<RequireOrImportCall>>;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export type CanHaveModuleSpecifier = AnyImportOrBareOrAccessedRequire | AliasDeclarationNode | ExportDeclaration | ImportTypeNode;
|
||||
|
||||
/** @internal */
|
||||
export type LateVisibilityPaintedStatement =
|
||||
| AnyImportOrJsDocImport
|
||||
@@ -8365,6 +8431,8 @@ export interface EmitHost extends ScriptReferenceHost, ModuleSpecifierResolution
|
||||
getCanonicalFileName(fileName: string): string;
|
||||
|
||||
isEmitBlocked(emitFileName: string): boolean;
|
||||
shouldTransformImportCall(sourceFile: SourceFile): boolean;
|
||||
getEmitModuleFormatOfFile(sourceFile: SourceFile): ModuleKind;
|
||||
|
||||
writeFile: WriteFileCallback;
|
||||
getBuildInfo(): BuildInfo | undefined;
|
||||
@@ -9605,6 +9673,7 @@ export interface PrinterOptions {
|
||||
omitTrailingSemicolon?: boolean;
|
||||
noEmitHelpers?: boolean;
|
||||
/** @internal */ module?: CompilerOptions["module"];
|
||||
/** @internal */ moduleResolution?: CompilerOptions["moduleResolution"];
|
||||
/** @internal */ target?: CompilerOptions["target"];
|
||||
/** @internal */ sourceMap?: boolean;
|
||||
/** @internal */ inlineSourceMap?: boolean;
|
||||
@@ -9739,6 +9808,8 @@ export interface ModuleSpecifierResolutionHost {
|
||||
isSourceOfProjectReferenceRedirect(fileName: string): boolean;
|
||||
getFileIncludeReasons(): MultiMap<Path, FileIncludeReason>;
|
||||
getCommonSourceDirectory(): string;
|
||||
getDefaultResolutionModeForFile(sourceFile: SourceFile): ResolutionMode;
|
||||
getModeForResolutionAtIndex(file: SourceFile, index: number): ResolutionMode;
|
||||
|
||||
getModuleResolutionCache?(): ModuleResolutionCache | undefined;
|
||||
trace?(s: string): void;
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
addRange,
|
||||
affectsDeclarationPathOptionDeclarations,
|
||||
affectsEmitOptionDeclarations,
|
||||
AliasDeclarationNode,
|
||||
AllAccessorDeclarations,
|
||||
AmbientModuleDeclaration,
|
||||
AmpersandAmpersandEqualsToken,
|
||||
@@ -41,6 +40,7 @@ import {
|
||||
canHaveDecorators,
|
||||
canHaveLocals,
|
||||
canHaveModifiers,
|
||||
CanHaveModuleSpecifier,
|
||||
CanonicalDiagnostic,
|
||||
CaseBlock,
|
||||
CaseClause,
|
||||
@@ -167,6 +167,7 @@ import {
|
||||
getCommonSourceDirectory,
|
||||
getContainerFlags,
|
||||
getDirectoryPath,
|
||||
getImpliedNodeFormatForEmitWorker,
|
||||
getJSDocAugmentsTag,
|
||||
getJSDocDeprecatedTagNoCache,
|
||||
getJSDocImplementsTags,
|
||||
@@ -4148,7 +4149,26 @@ export function isFunctionSymbol(symbol: Symbol | undefined) {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire | AliasDeclarationNode | ExportDeclaration | ImportTypeNode | JSDocImportTag): StringLiteralLike | undefined {
|
||||
export function canHaveModuleSpecifier(node: Node | undefined): node is CanHaveModuleSpecifier {
|
||||
switch (node?.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.BindingElement:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
case SyntaxKind.ImportClause:
|
||||
case SyntaxKind.NamespaceExport:
|
||||
case SyntaxKind.NamespaceImport:
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
case SyntaxKind.ImportType:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function tryGetModuleSpecifierFromDeclaration(node: CanHaveModuleSpecifier | JSDocImportTag): StringLiteralLike | undefined {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.BindingElement:
|
||||
@@ -8719,11 +8739,11 @@ function isFileModuleFromUsingJSXTag(file: SourceFile): Node | undefined {
|
||||
* Note that this requires file.impliedNodeFormat be set already; meaning it must be set very early on
|
||||
* in SourceFile construction.
|
||||
*/
|
||||
function isFileForcedToBeModuleByFormat(file: SourceFile): true | undefined {
|
||||
function isFileForcedToBeModuleByFormat(file: SourceFile, options: CompilerOptions): true | undefined {
|
||||
// Excludes declaration files - they still require an explicit `export {}` or the like
|
||||
// for back compat purposes. The only non-declaration files _not_ forced to be a module are `.js` files
|
||||
// that aren't esm-mode (meaning not in a `type: module` scope).
|
||||
return (file.impliedNodeFormat === ModuleKind.ESNext || (fileExtensionIsOneOf(file.fileName, [Extension.Cjs, Extension.Cts, Extension.Mjs, Extension.Mts]))) && !file.isDeclarationFile ? true : undefined;
|
||||
return (getImpliedNodeFormatForEmitWorker(file, options) === ModuleKind.ESNext || (fileExtensionIsOneOf(file.fileName, [Extension.Cjs, Extension.Cts, Extension.Mjs, Extension.Mts]))) && !file.isDeclarationFile ? true : undefined;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -8744,17 +8764,29 @@ export function getSetExternalModuleIndicator(options: CompilerOptions): (file:
|
||||
// If module is nodenext or node16, all esm format files are modules
|
||||
// If jsx is react-jsx or react-jsxdev then jsx tags force module-ness
|
||||
// otherwise, the presence of import or export statments (or import.meta) implies module-ness
|
||||
const checks: ((file: SourceFile) => Node | true | undefined)[] = [isFileProbablyExternalModule];
|
||||
const checks: ((file: SourceFile, options: CompilerOptions) => Node | true | undefined)[] = [isFileProbablyExternalModule];
|
||||
if (options.jsx === JsxEmit.ReactJSX || options.jsx === JsxEmit.ReactJSXDev) {
|
||||
checks.push(isFileModuleFromUsingJSXTag);
|
||||
}
|
||||
checks.push(isFileForcedToBeModuleByFormat);
|
||||
const combined = or(...checks);
|
||||
const callback = (file: SourceFile) => void (file.externalModuleIndicator = combined(file));
|
||||
const callback = (file: SourceFile) => void (file.externalModuleIndicator = combined(file, options));
|
||||
return callback;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Returns true if an `import` and a `require` of the same module specifier
|
||||
* can resolve to a different file.
|
||||
*/
|
||||
export function importSyntaxAffectsModuleResolution(options: CompilerOptions) {
|
||||
const moduleResolution = getEmitModuleResolutionKind(options);
|
||||
return ModuleResolutionKind.Node16 <= moduleResolution && moduleResolution <= ModuleResolutionKind.NodeNext
|
||||
|| getResolvePackageJsonExports(options)
|
||||
|| getResolvePackageJsonImports(options);
|
||||
}
|
||||
|
||||
type CompilerOptionKeys = keyof { [K in keyof CompilerOptions as string extends K ? never : K]: any; };
|
||||
function createComputedCompilerOptions<T extends Record<string, CompilerOptionKeys[]>>(
|
||||
options: {
|
||||
|
||||
@@ -57,6 +57,7 @@ import {
|
||||
getDirectoryPath,
|
||||
getEmitDeclarations,
|
||||
getEmitScriptTarget,
|
||||
getImpliedNodeFormatForEmitWorker,
|
||||
getLineAndCharacterOfPosition,
|
||||
getNameOfScriptTarget,
|
||||
getNewLineCharacter,
|
||||
@@ -352,13 +353,14 @@ export function explainFiles(program: Program, write: (s: string) => void) {
|
||||
for (const file of program.getSourceFiles()) {
|
||||
write(`${toFileName(file, relativeFileName)}`);
|
||||
reasons.get(file.path)?.forEach(reason => write(` ${fileIncludeReasonToDiagnostics(program, reason, relativeFileName).messageText}`));
|
||||
explainIfFileIsRedirectAndImpliedFormat(file, relativeFileName)?.forEach(d => write(` ${d.messageText}`));
|
||||
explainIfFileIsRedirectAndImpliedFormat(file, program.getCompilerOptionsForFile(file), relativeFileName)?.forEach(d => write(` ${d.messageText}`));
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function explainIfFileIsRedirectAndImpliedFormat(
|
||||
file: SourceFile,
|
||||
options: CompilerOptions,
|
||||
fileNameConvertor?: (fileName: string) => string,
|
||||
): DiagnosticMessageChain[] | undefined {
|
||||
let result: DiagnosticMessageChain[] | undefined;
|
||||
@@ -377,7 +379,7 @@ export function explainIfFileIsRedirectAndImpliedFormat(
|
||||
));
|
||||
}
|
||||
if (isExternalOrCommonJsModule(file)) {
|
||||
switch (file.impliedNodeFormat) {
|
||||
switch (getImpliedNodeFormatForEmitWorker(file, options)) {
|
||||
case ModuleKind.ESNext:
|
||||
if (file.packageJsonScope) {
|
||||
(result ??= []).push(chainDiagnosticMessages(
|
||||
|
||||
@@ -50,10 +50,12 @@ import {
|
||||
getDeclarationOfKind,
|
||||
getDefaultLikeExportInfo,
|
||||
getDirectoryPath,
|
||||
getEmitModuleFormatOfFileWorker,
|
||||
getEmitModuleKind,
|
||||
getEmitModuleResolutionKind,
|
||||
getEmitScriptTarget,
|
||||
getExportInfoMap,
|
||||
getImpliedNodeFormatForEmitWorker,
|
||||
getIsFileExcluded,
|
||||
getMeaningFromLocation,
|
||||
getNameForExportedSymbol,
|
||||
@@ -335,7 +337,7 @@ function createImportAdderWorker(sourceFile: SourceFile | FutureSourceFile, prog
|
||||
compilerOptions,
|
||||
createModuleSpecifierResolutionHost(program, host),
|
||||
);
|
||||
const importKind = getImportKind(futureExportingSourceFile, exportKind, compilerOptions);
|
||||
const importKind = getImportKind(futureExportingSourceFile, exportKind, program);
|
||||
const addAsTypeOnly = getAddAsTypeOnly(
|
||||
isImportUsageValidAsTypeOnly,
|
||||
/*isForNewImportDeclaration*/ true,
|
||||
@@ -699,7 +701,7 @@ export interface ImportSpecifierResolver {
|
||||
/** @internal */
|
||||
export function createImportSpecifierResolver(importingFile: SourceFile, program: Program, host: LanguageServiceHost, preferences: UserPreferences): ImportSpecifierResolver {
|
||||
const packageJsonImportFilter = createPackageJsonImportFilter(importingFile, preferences, host);
|
||||
const importMap = createExistingImportMap(program.getTypeChecker(), importingFile, program.getCompilerOptions());
|
||||
const importMap = createExistingImportMap(importingFile, program);
|
||||
return { getModuleSpecifierForBestExportInfo };
|
||||
|
||||
function getModuleSpecifierForBestExportInfo(
|
||||
@@ -911,7 +913,7 @@ function getImportFixes(
|
||||
sourceFile: SourceFile | FutureSourceFile,
|
||||
host: LanguageServiceHost,
|
||||
preferences: UserPreferences,
|
||||
importMap = isFullSourceFile(sourceFile) ? createExistingImportMap(program.getTypeChecker(), sourceFile, program.getCompilerOptions()) : undefined,
|
||||
importMap = isFullSourceFile(sourceFile) ? createExistingImportMap(sourceFile, program) : undefined,
|
||||
fromCacheOnly?: boolean,
|
||||
): { computedWithoutCacheCount: number; fixes: readonly ImportFixWithModuleSpecifier[]; } {
|
||||
const checker = program.getTypeChecker();
|
||||
@@ -1078,7 +1080,8 @@ function tryAddToExistingImport(existingImports: readonly FixAddToExistingImport
|
||||
}
|
||||
}
|
||||
|
||||
function createExistingImportMap(checker: TypeChecker, importingFile: SourceFile, compilerOptions: CompilerOptions) {
|
||||
function createExistingImportMap(importingFile: SourceFile, program: Program) {
|
||||
const checker = program.getTypeChecker();
|
||||
let importMap: MultiMap<SymbolId, AnyImportOrRequire> | undefined;
|
||||
for (const moduleSpecifier of importingFile.imports) {
|
||||
const i = importFromModuleSpecifier(moduleSpecifier);
|
||||
@@ -1108,7 +1111,7 @@ function createExistingImportMap(checker: TypeChecker, importingFile: SourceFile
|
||||
&& !every(matchingDeclarations, isJSDocImportTag)
|
||||
) return emptyArray;
|
||||
|
||||
const importKind = getImportKind(importingFile, exportKind, compilerOptions);
|
||||
const importKind = getImportKind(importingFile, exportKind, program);
|
||||
return matchingDeclarations.map(declaration => ({ declaration, importKind, symbol, targetFlags }));
|
||||
},
|
||||
};
|
||||
@@ -1132,8 +1135,9 @@ function shouldUseRequire(sourceFile: SourceFile | FutureSourceFile, program: Pr
|
||||
|
||||
// 4. In --module nodenext, assume we're not emitting JS -> JS, so use
|
||||
// whatever syntax Node expects based on the detected module kind
|
||||
if (sourceFile.impliedNodeFormat === ModuleKind.CommonJS) return true;
|
||||
if (sourceFile.impliedNodeFormat === ModuleKind.ESNext) return false;
|
||||
// TODO: consider removing `impliedNodeFormatForEmit`
|
||||
if (getImpliedNodeFormatForEmit(sourceFile, program) === ModuleKind.CommonJS) return true;
|
||||
if (getImpliedNodeFormatForEmit(sourceFile, program) === ModuleKind.ESNext) return false;
|
||||
|
||||
// 5. Match the first other JS file in the program that's unambiguously CJS or ESM
|
||||
for (const otherFile of program.getSourceFiles()) {
|
||||
@@ -1186,7 +1190,7 @@ function getNewImportFixes(
|
||||
// `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types.
|
||||
return { kind: ImportFixKind.JsdocTypeImport, moduleSpecifierKind, moduleSpecifier, usagePosition, exportInfo, isReExport: i > 0 };
|
||||
}
|
||||
const importKind = getImportKind(sourceFile, exportInfo.exportKind, compilerOptions);
|
||||
const importKind = getImportKind(sourceFile, exportInfo.exportKind, program);
|
||||
let qualification: Qualification | undefined;
|
||||
if (usagePosition !== undefined && importKind === ImportKind.CommonJS && exportInfo.exportKind === ExportKind.Named) {
|
||||
// Compiler options are restricting our import options to a require, but we need to access
|
||||
@@ -1198,7 +1202,7 @@ function getNewImportFixes(
|
||||
const exportEquals = checker.resolveExternalModuleSymbol(exportInfo.moduleSymbol);
|
||||
let namespacePrefix;
|
||||
if (exportEquals !== exportInfo.moduleSymbol) {
|
||||
namespacePrefix = forEachNameOfDefaultExport(exportEquals, checker, compilerOptions, /*preferCapitalizedNames*/ false, identity)!;
|
||||
namespacePrefix = forEachNameOfDefaultExport(exportEquals, checker, getEmitScriptTarget(compilerOptions), identity)!;
|
||||
}
|
||||
namespacePrefix ||= moduleSymbolToValidIdentifier(
|
||||
exportInfo.moduleSymbol,
|
||||
@@ -1417,8 +1421,8 @@ function getUmdSymbol(token: Node, checker: TypeChecker): Symbol | undefined {
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function getImportKind(importingFile: SourceFile | FutureSourceFile, exportKind: ExportKind, compilerOptions: CompilerOptions, forceImportKeyword?: boolean): ImportKind {
|
||||
if (compilerOptions.verbatimModuleSyntax && (getEmitModuleKind(compilerOptions) === ModuleKind.CommonJS || importingFile.impliedNodeFormat === ModuleKind.CommonJS)) {
|
||||
export function getImportKind(importingFile: SourceFile | FutureSourceFile, exportKind: ExportKind, program: Program, forceImportKeyword?: boolean): ImportKind {
|
||||
if (program.getCompilerOptions().verbatimModuleSyntax && getEmitModuleFormatOfFile(importingFile, program) === ModuleKind.CommonJS) {
|
||||
// TODO: if the exporting file is ESM under nodenext, or `forceImport` is given in a JS file, this is impossible
|
||||
return ImportKind.CommonJS;
|
||||
}
|
||||
@@ -1428,22 +1432,22 @@ export function getImportKind(importingFile: SourceFile | FutureSourceFile, expo
|
||||
case ExportKind.Default:
|
||||
return ImportKind.Default;
|
||||
case ExportKind.ExportEquals:
|
||||
return getExportEqualsImportKind(importingFile, compilerOptions, !!forceImportKeyword);
|
||||
return getExportEqualsImportKind(importingFile, program.getCompilerOptions(), !!forceImportKeyword);
|
||||
case ExportKind.UMD:
|
||||
return getUmdImportKind(importingFile, compilerOptions, !!forceImportKeyword);
|
||||
return getUmdImportKind(importingFile, program, !!forceImportKeyword);
|
||||
default:
|
||||
return Debug.assertNever(exportKind);
|
||||
}
|
||||
}
|
||||
|
||||
function getUmdImportKind(importingFile: SourceFile | FutureSourceFile, compilerOptions: CompilerOptions, forceImportKeyword: boolean): ImportKind {
|
||||
function getUmdImportKind(importingFile: SourceFile | FutureSourceFile, program: Program, forceImportKeyword: boolean): ImportKind {
|
||||
// Import a synthetic `default` if enabled.
|
||||
if (getAllowSyntheticDefaultImports(compilerOptions)) {
|
||||
if (getAllowSyntheticDefaultImports(program.getCompilerOptions())) {
|
||||
return ImportKind.Default;
|
||||
}
|
||||
|
||||
// When a synthetic `default` is unavailable, use `import..require` if the module kind supports it.
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
const moduleKind = getEmitModuleKind(program.getCompilerOptions());
|
||||
switch (moduleKind) {
|
||||
case ModuleKind.AMD:
|
||||
case ModuleKind.CommonJS:
|
||||
@@ -1463,7 +1467,7 @@ function getUmdImportKind(importingFile: SourceFile | FutureSourceFile, compiler
|
||||
return ImportKind.Namespace;
|
||||
case ModuleKind.Node16:
|
||||
case ModuleKind.NodeNext:
|
||||
return importingFile.impliedNodeFormat === ModuleKind.ESNext ? ImportKind.Namespace : ImportKind.CommonJS;
|
||||
return getImpliedNodeFormatForEmit(importingFile, program) === ModuleKind.ESNext ? ImportKind.Namespace : ImportKind.CommonJS;
|
||||
default:
|
||||
return Debug.assertNever(moduleKind, `Unexpected moduleKind ${moduleKind}`);
|
||||
}
|
||||
@@ -1555,7 +1559,7 @@ function getExportInfos(
|
||||
if (
|
||||
defaultInfo
|
||||
&& symbolFlagsHaveMeaning(checker.getSymbolFlags(defaultInfo.symbol), currentTokenMeaning)
|
||||
&& forEachNameOfDefaultExport(defaultInfo.symbol, checker, compilerOptions, isJsxTagName, name => name === symbolName)
|
||||
&& forEachNameOfDefaultExport(defaultInfo.symbol, checker, getEmitScriptTarget(compilerOptions), (name, capitalizedName) => (isJsxTagName ? capitalizedName ?? name : name) === symbolName)
|
||||
) {
|
||||
addSymbol(moduleSymbol, sourceFile, defaultInfo.symbol, defaultInfo.exportKind, program, isFromPackageJson);
|
||||
}
|
||||
@@ -2038,3 +2042,11 @@ function symbolFlagsHaveMeaning(flags: SymbolFlags, meaning: SemanticMeaning): b
|
||||
meaning & SemanticMeaning.Namespace ? !!(flags & SymbolFlags.Namespace) :
|
||||
false;
|
||||
}
|
||||
|
||||
function getImpliedNodeFormatForEmit(file: SourceFile | FutureSourceFile, program: Program) {
|
||||
return isFullSourceFile(file) ? program.getImpliedNodeFormatForEmit(file) : getImpliedNodeFormatForEmitWorker(file, program.getCompilerOptions());
|
||||
}
|
||||
|
||||
function getEmitModuleFormatOfFile(file: SourceFile | FutureSourceFile, program: Program) {
|
||||
return isFullSourceFile(file) ? program.getEmitModuleFormatOfFile(file) : getEmitModuleFormatOfFileWorker(file, program.getCompilerOptions());
|
||||
}
|
||||
|
||||
@@ -1161,11 +1161,13 @@ function getJSDocParamAnnotation(
|
||||
? createSnippetPrinter({
|
||||
removeComments: true,
|
||||
module: options.module,
|
||||
moduleResolution: options.moduleResolution,
|
||||
target: options.target,
|
||||
})
|
||||
: createPrinter({
|
||||
removeComments: true,
|
||||
module: options.module,
|
||||
moduleResolution: options.moduleResolution,
|
||||
target: options.target,
|
||||
});
|
||||
setEmitFlags(typeNode, EmitFlags.SingleLine);
|
||||
@@ -1459,6 +1461,7 @@ function getExhaustiveCaseSnippets(
|
||||
const printer = createSnippetPrinter({
|
||||
removeComments: true,
|
||||
module: options.module,
|
||||
moduleResolution: options.moduleResolution,
|
||||
target: options.target,
|
||||
newLine: getNewLineKind(newLineChar),
|
||||
});
|
||||
@@ -1720,7 +1723,7 @@ function createCompletionEntry(
|
||||
if (originIsResolvedExport(origin)) {
|
||||
sourceDisplay = [textPart(origin.moduleSpecifier)];
|
||||
if (importStatementCompletion) {
|
||||
({ insertText, replacementSpan } = getInsertTextAndReplacementSpanForImportCompletion(name, importStatementCompletion, origin, useSemicolons, sourceFile, options, preferences));
|
||||
({ insertText, replacementSpan } = getInsertTextAndReplacementSpanForImportCompletion(name, importStatementCompletion, origin, useSemicolons, sourceFile, program, preferences));
|
||||
isSnippet = preferences.includeCompletionsWithSnippetText ? true : undefined;
|
||||
}
|
||||
}
|
||||
@@ -1978,6 +1981,7 @@ function getEntryForMemberCompletion(
|
||||
const printer = createSnippetPrinter({
|
||||
removeComments: true,
|
||||
module: options.module,
|
||||
moduleResolution: options.moduleResolution,
|
||||
target: options.target,
|
||||
omitTrailingSemicolon: false,
|
||||
newLine: getNewLineKind(getNewLineOrDefaultFromHost(host, formatContext?.options)),
|
||||
@@ -2204,6 +2208,7 @@ function getEntryForObjectLiteralMethodCompletion(
|
||||
const printer = createSnippetPrinter({
|
||||
removeComments: true,
|
||||
module: options.module,
|
||||
moduleResolution: options.moduleResolution,
|
||||
target: options.target,
|
||||
omitTrailingSemicolon: false,
|
||||
newLine: getNewLineKind(getNewLineOrDefaultFromHost(host, formatContext?.options)),
|
||||
@@ -2218,6 +2223,7 @@ function getEntryForObjectLiteralMethodCompletion(
|
||||
const signaturePrinter = createPrinter({
|
||||
removeComments: true,
|
||||
module: options.module,
|
||||
moduleResolution: options.moduleResolution,
|
||||
target: options.target,
|
||||
omitTrailingSemicolon: true,
|
||||
});
|
||||
@@ -2520,14 +2526,14 @@ function completionEntryDataToSymbolOriginInfo(data: CompletionEntryData, comple
|
||||
return unresolvedOrigin;
|
||||
}
|
||||
|
||||
function getInsertTextAndReplacementSpanForImportCompletion(name: string, importStatementCompletion: ImportStatementCompletionInfo, origin: SymbolOriginInfoResolvedExport, useSemicolons: boolean, sourceFile: SourceFile, options: CompilerOptions, preferences: UserPreferences) {
|
||||
function getInsertTextAndReplacementSpanForImportCompletion(name: string, importStatementCompletion: ImportStatementCompletionInfo, origin: SymbolOriginInfoResolvedExport, useSemicolons: boolean, sourceFile: SourceFile, program: Program, preferences: UserPreferences) {
|
||||
const replacementSpan = importStatementCompletion.replacementSpan;
|
||||
const quotedModuleSpecifier = escapeSnippetText(quote(sourceFile, preferences, origin.moduleSpecifier));
|
||||
const exportKind = origin.isDefaultExport ? ExportKind.Default :
|
||||
origin.exportName === InternalSymbolName.ExportEquals ? ExportKind.ExportEquals :
|
||||
ExportKind.Named;
|
||||
const tabStop = preferences.includeCompletionsWithSnippetText ? "$1" : "";
|
||||
const importKind = codefix.getImportKind(sourceFile, exportKind, options, /*forceImportKeyword*/ true);
|
||||
const importKind = codefix.getImportKind(sourceFile, exportKind, program, /*forceImportKeyword*/ true);
|
||||
const isImportSpecifierTypeOnly = importStatementCompletion.couldBeTypeOnlyImportSpecifier;
|
||||
const topLevelTypeOnlyText = importStatementCompletion.isTopLevelTypeOnly ? ` ${tokenToString(SyntaxKind.TypeKeyword)} ` : " ";
|
||||
const importSpecifierTypeOnlyText = isImportSpecifierTypeOnly ? `${tokenToString(SyntaxKind.TypeKeyword)} ` : "";
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
append,
|
||||
arrayIsEqualTo,
|
||||
CancellationToken,
|
||||
CompilerOptions,
|
||||
consumesNodeCoreModules,
|
||||
createMultiMap,
|
||||
Debug,
|
||||
@@ -18,9 +17,7 @@ import {
|
||||
GetCanonicalFileName,
|
||||
getDefaultLikeExportNameFromDeclaration,
|
||||
getDirectoryPath,
|
||||
getEmitScriptTarget,
|
||||
getLocalSymbolForExportDefault,
|
||||
getNamesForExportedSymbol,
|
||||
getNodeModulePathParts,
|
||||
getPackageNameFromTypesPackageName,
|
||||
getRegexFromPattern,
|
||||
@@ -46,6 +43,7 @@ import {
|
||||
Path,
|
||||
pathContainsNodeModules,
|
||||
Program,
|
||||
ScriptTarget,
|
||||
skipAlias,
|
||||
SourceFile,
|
||||
startsWith,
|
||||
@@ -198,7 +196,7 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost):
|
||||
// get a better name.
|
||||
const names = exportKind === ExportKind.Named || isExternalModuleSymbol(namedSymbol)
|
||||
? unescapeLeadingUnderscores(symbolTableKey)
|
||||
: getNamesForExportedSymbol(namedSymbol, /*scriptTarget*/ undefined);
|
||||
: getNamesForExportedSymbol(namedSymbol, checker, /*scriptTarget*/ undefined);
|
||||
|
||||
const symbolName = typeof names === "string" ? names : names[0];
|
||||
const capitalizedSymbolName = typeof names === "string" ? undefined : names[1];
|
||||
@@ -572,12 +570,21 @@ function isImportableSymbol(symbol: Symbol, checker: TypeChecker) {
|
||||
return !checker.isUndefinedSymbol(symbol) && !checker.isUnknownSymbol(symbol) && !isKnownSymbol(symbol) && !isPrivateIdentifierSymbol(symbol);
|
||||
}
|
||||
|
||||
function getNamesForExportedSymbol(defaultExport: Symbol, checker: TypeChecker, scriptTarget: ScriptTarget | undefined) {
|
||||
let names: string | string[] | undefined;
|
||||
forEachNameOfDefaultExport(defaultExport, checker, scriptTarget, (name, capitalizedName) => {
|
||||
names = capitalizedName ? [name, capitalizedName] : name;
|
||||
return true;
|
||||
});
|
||||
return Debug.checkDefined(names);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* May call `cb` multiple times with the same name.
|
||||
* Terminates when `cb` returns a truthy value.
|
||||
*/
|
||||
export function forEachNameOfDefaultExport<T>(defaultExport: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions, preferCapitalizedNames: boolean, cb: (name: string) => T | undefined): T | undefined {
|
||||
export function forEachNameOfDefaultExport<T>(defaultExport: Symbol, checker: TypeChecker, scriptTarget: ScriptTarget | undefined, cb: (name: string, capitalizedName?: string) => T | undefined): T | undefined {
|
||||
let chain: Symbol[] | undefined;
|
||||
let current: Symbol | undefined = defaultExport;
|
||||
const seen = new Map<Symbol, true>();
|
||||
@@ -604,7 +611,10 @@ export function forEachNameOfDefaultExport<T>(defaultExport: Symbol, checker: Ty
|
||||
|
||||
for (const symbol of chain ?? emptyArray) {
|
||||
if (symbol.parent && isExternalModuleSymbol(symbol.parent)) {
|
||||
const final = cb(moduleSymbolToValidIdentifier(symbol.parent, getEmitScriptTarget(compilerOptions), preferCapitalizedNames));
|
||||
const final = cb(
|
||||
moduleSymbolToValidIdentifier(symbol.parent, scriptTarget, /*forceCapitalize*/ false),
|
||||
moduleSymbolToValidIdentifier(symbol.parent, scriptTarget, /*forceCapitalize*/ true),
|
||||
);
|
||||
if (final) return final;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ export function getStringLiteralCompletions(
|
||||
includeSymbol: boolean,
|
||||
): CompletionInfo | undefined {
|
||||
if (isInReferenceComment(sourceFile, position)) {
|
||||
const entries = getTripleSlashReferenceCompletion(sourceFile, position, options, host);
|
||||
const entries = getTripleSlashReferenceCompletion(sourceFile, position, program, host);
|
||||
return entries && convertPathCompletions(entries);
|
||||
}
|
||||
if (isInString(sourceFile, position, contextToken)) {
|
||||
@@ -614,8 +614,8 @@ function getStringLiteralCompletionsFromModuleNamesWorker(sourceFile: SourceFile
|
||||
const extensionOptions = getExtensionOptions(compilerOptions, ReferenceKind.ModuleSpecifier, sourceFile, typeChecker, preferences, mode);
|
||||
|
||||
return isPathRelativeToScript(literalValue) || !compilerOptions.baseUrl && !compilerOptions.paths && (isRootedDiskPath(literalValue) || isUrl(literalValue))
|
||||
? getCompletionEntriesForRelativeModules(literalValue, scriptDirectory, compilerOptions, host, scriptPath, extensionOptions)
|
||||
: getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, mode, compilerOptions, host, extensionOptions, typeChecker);
|
||||
? getCompletionEntriesForRelativeModules(literalValue, scriptDirectory, program, host, scriptPath, extensionOptions)
|
||||
: getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, mode, program, host, extensionOptions);
|
||||
}
|
||||
|
||||
interface ExtensionOptions {
|
||||
@@ -635,20 +635,21 @@ function getExtensionOptions(compilerOptions: CompilerOptions, referenceKind: Re
|
||||
resolutionMode,
|
||||
};
|
||||
}
|
||||
function getCompletionEntriesForRelativeModules(literalValue: string, scriptDirectory: string, compilerOptions: CompilerOptions, host: LanguageServiceHost, scriptPath: Path, extensionOptions: ExtensionOptions) {
|
||||
function getCompletionEntriesForRelativeModules(literalValue: string, scriptDirectory: string, program: Program, host: LanguageServiceHost, scriptPath: Path, extensionOptions: ExtensionOptions) {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
if (compilerOptions.rootDirs) {
|
||||
return getCompletionEntriesForDirectoryFragmentWithRootDirs(
|
||||
compilerOptions.rootDirs,
|
||||
literalValue,
|
||||
scriptDirectory,
|
||||
extensionOptions,
|
||||
compilerOptions,
|
||||
program,
|
||||
host,
|
||||
scriptPath,
|
||||
);
|
||||
}
|
||||
else {
|
||||
return arrayFrom(getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ true, scriptPath).values());
|
||||
return arrayFrom(getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, program, host, /*moduleSpecifierIsRelative*/ true, scriptPath).values());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,12 +687,13 @@ function getBaseDirectoriesFromRootDirs(rootDirs: string[], basePath: string, sc
|
||||
);
|
||||
}
|
||||
|
||||
function getCompletionEntriesForDirectoryFragmentWithRootDirs(rootDirs: string[], fragment: string, scriptDirectory: string, extensionOptions: ExtensionOptions, compilerOptions: CompilerOptions, host: LanguageServiceHost, exclude: string): readonly NameAndKind[] {
|
||||
function getCompletionEntriesForDirectoryFragmentWithRootDirs(rootDirs: string[], fragment: string, scriptDirectory: string, extensionOptions: ExtensionOptions, program: Program, host: LanguageServiceHost, exclude: string): readonly NameAndKind[] {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const basePath = compilerOptions.project || host.getCurrentDirectory();
|
||||
const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames());
|
||||
const baseDirectories = getBaseDirectoriesFromRootDirs(rootDirs, basePath, scriptDirectory, ignoreCase);
|
||||
return deduplicate<NameAndKind>(
|
||||
flatMap(baseDirectories, baseDirectory => arrayFrom(getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ true, exclude).values())),
|
||||
flatMap(baseDirectories, baseDirectory => arrayFrom(getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensionOptions, program, host, /*moduleSpecifierIsRelative*/ true, exclude).values())),
|
||||
(itemA, itemB) => itemA.name === itemB.name && itemA.kind === itemB.kind && itemA.extension === itemB.extension,
|
||||
);
|
||||
}
|
||||
@@ -707,6 +709,7 @@ function getCompletionEntriesForDirectoryFragment(
|
||||
fragment: string,
|
||||
scriptDirectory: string,
|
||||
extensionOptions: ExtensionOptions,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
moduleSpecifierIsRelative: boolean,
|
||||
exclude?: string,
|
||||
@@ -746,7 +749,7 @@ function getCompletionEntriesForDirectoryFragment(
|
||||
if (versionPaths) {
|
||||
const packageDirectory = getDirectoryPath(packageJsonPath);
|
||||
const pathInPackage = absolutePath.slice(ensureTrailingDirectorySeparator(packageDirectory).length);
|
||||
if (addCompletionEntriesFromPaths(result, pathInPackage, packageDirectory, extensionOptions, host, versionPaths)) {
|
||||
if (addCompletionEntriesFromPaths(result, pathInPackage, packageDirectory, extensionOptions, program, host, versionPaths)) {
|
||||
// A true result means one of the `versionPaths` was matched, which will block relative resolution
|
||||
// to files and folders from here. All reachable paths given the pattern match are already added.
|
||||
return result;
|
||||
@@ -769,7 +772,7 @@ function getCompletionEntriesForDirectoryFragment(
|
||||
continue;
|
||||
}
|
||||
|
||||
const { name, extension } = getFilenameWithExtensionOption(getBaseFileName(filePath), host.getCompilationSettings(), extensionOptions, /*isExportsWildcard*/ false);
|
||||
const { name, extension } = getFilenameWithExtensionOption(getBaseFileName(filePath), program, extensionOptions, /*isExportsWildcard*/ false);
|
||||
result.add(nameAndKind(name, ScriptElementKind.scriptElement, extension));
|
||||
}
|
||||
}
|
||||
@@ -789,7 +792,7 @@ function getCompletionEntriesForDirectoryFragment(
|
||||
return result;
|
||||
}
|
||||
|
||||
function getFilenameWithExtensionOption(name: string, compilerOptions: CompilerOptions, extensionOptions: ExtensionOptions, isExportsWildcard: boolean): { name: string; extension: Extension | undefined; } {
|
||||
function getFilenameWithExtensionOption(name: string, program: Program, extensionOptions: ExtensionOptions, isExportsWildcard: boolean): { name: string; extension: Extension | undefined; } {
|
||||
const nonJsResult = moduleSpecifiers.tryGetRealFileNameForNonJsDeclarationFileName(name);
|
||||
if (nonJsResult) {
|
||||
return { name: nonJsResult, extension: tryGetExtensionFromPath(nonJsResult) };
|
||||
@@ -800,7 +803,8 @@ function getFilenameWithExtensionOption(name: string, compilerOptions: CompilerO
|
||||
|
||||
let allowedEndings = getModuleSpecifierPreferences(
|
||||
{ importModuleSpecifierEnding: extensionOptions.endingPreference },
|
||||
compilerOptions,
|
||||
program,
|
||||
program.getCompilerOptions(),
|
||||
extensionOptions.importingSourceFile,
|
||||
).getAllowedEndingsInPreferredOrder(extensionOptions.resolutionMode);
|
||||
|
||||
@@ -814,7 +818,7 @@ function getFilenameWithExtensionOption(name: string, compilerOptions: CompilerO
|
||||
if (fileExtensionIsOneOf(name, supportedTSImplementationExtensions)) {
|
||||
return { name, extension: tryGetExtensionFromPath(name) };
|
||||
}
|
||||
const outputExtension = moduleSpecifiers.tryGetJSExtensionForFile(name, compilerOptions);
|
||||
const outputExtension = moduleSpecifiers.tryGetJSExtensionForFile(name, program.getCompilerOptions());
|
||||
return outputExtension
|
||||
? { name: changeExtension(name, outputExtension), extension: outputExtension }
|
||||
: { name, extension: tryGetExtensionFromPath(name) };
|
||||
@@ -828,7 +832,7 @@ function getFilenameWithExtensionOption(name: string, compilerOptions: CompilerO
|
||||
return { name: removeFileExtension(name), extension: tryGetExtensionFromPath(name) };
|
||||
}
|
||||
|
||||
const outputExtension = moduleSpecifiers.tryGetJSExtensionForFile(name, compilerOptions);
|
||||
const outputExtension = moduleSpecifiers.tryGetJSExtensionForFile(name, program.getCompilerOptions());
|
||||
return outputExtension
|
||||
? { name: changeExtension(name, outputExtension), extension: outputExtension }
|
||||
: { name, extension: tryGetExtensionFromPath(name) };
|
||||
@@ -840,6 +844,7 @@ function addCompletionEntriesFromPaths(
|
||||
fragment: string,
|
||||
baseDirectory: string,
|
||||
extensionOptions: ExtensionOptions,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
paths: MapLike<string[]>,
|
||||
) {
|
||||
@@ -851,7 +856,7 @@ function addCompletionEntriesFromPaths(
|
||||
const lengthB = typeof patternB === "object" ? patternB.prefix.length : b.length;
|
||||
return compareValues(lengthB, lengthA);
|
||||
};
|
||||
return addCompletionEntriesFromPathsOrExports(result, /*isExports*/ false, fragment, baseDirectory, extensionOptions, host, getOwnKeys(paths), getPatternsForKey, comparePaths);
|
||||
return addCompletionEntriesFromPathsOrExports(result, /*isExports*/ false, fragment, baseDirectory, extensionOptions, program, host, getOwnKeys(paths), getPatternsForKey, comparePaths);
|
||||
}
|
||||
|
||||
/** @returns whether `fragment` was a match for any `paths` (which should indicate whether any other path completions should be offered) */
|
||||
@@ -861,6 +866,7 @@ function addCompletionEntriesFromPathsOrExports(
|
||||
fragment: string,
|
||||
baseDirectory: string,
|
||||
extensionOptions: ExtensionOptions,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
keys: readonly string[],
|
||||
getPatternsForKey: (key: string) => string[] | undefined,
|
||||
@@ -895,7 +901,7 @@ function addCompletionEntriesFromPathsOrExports(
|
||||
if (typeof pathPattern === "string" || matchedPath === undefined || comparePaths(key, matchedPath) !== Comparison.GreaterThan) {
|
||||
pathResults.push({
|
||||
matchedPattern: isMatch,
|
||||
results: getCompletionsForPathMapping(keyWithoutLeadingDotSlash, patterns, fragment, baseDirectory, extensionOptions, isExports && isMatch, host)
|
||||
results: getCompletionsForPathMapping(keyWithoutLeadingDotSlash, patterns, fragment, baseDirectory, extensionOptions, isExports && isMatch, program, host)
|
||||
.map(({ name, kind, extension }) => nameAndKind(name, kind, extension)),
|
||||
});
|
||||
}
|
||||
@@ -917,11 +923,12 @@ function getCompletionEntriesForNonRelativeModules(
|
||||
fragment: string,
|
||||
scriptPath: string,
|
||||
mode: ResolutionMode,
|
||||
compilerOptions: CompilerOptions,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
extensionOptions: ExtensionOptions,
|
||||
typeChecker: TypeChecker,
|
||||
): readonly NameAndKind[] {
|
||||
const typeChecker = program.getTypeChecker();
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const { baseUrl, paths } = compilerOptions;
|
||||
|
||||
const result = createNameAndKindSet();
|
||||
@@ -929,12 +936,12 @@ function getCompletionEntriesForNonRelativeModules(
|
||||
|
||||
if (baseUrl) {
|
||||
const absolute = normalizePath(combinePaths(host.getCurrentDirectory(), baseUrl));
|
||||
getCompletionEntriesForDirectoryFragment(fragment, absolute, extensionOptions, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result);
|
||||
getCompletionEntriesForDirectoryFragment(fragment, absolute, extensionOptions, program, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result);
|
||||
}
|
||||
|
||||
if (paths) {
|
||||
const absolute = getPathsBasePath(compilerOptions, host)!;
|
||||
addCompletionEntriesFromPaths(result, fragment, absolute, extensionOptions, host, paths);
|
||||
addCompletionEntriesFromPaths(result, fragment, absolute, extensionOptions, program, host, paths);
|
||||
}
|
||||
|
||||
const fragmentDirectory = getFragmentDirectory(fragment);
|
||||
@@ -942,7 +949,7 @@ function getCompletionEntriesForNonRelativeModules(
|
||||
result.add(nameAndKind(ambientName, ScriptElementKind.externalModuleName, /*extension*/ undefined));
|
||||
}
|
||||
|
||||
getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, fragmentDirectory, extensionOptions, result);
|
||||
getCompletionEntriesFromTypings(host, program, scriptPath, fragmentDirectory, extensionOptions, result);
|
||||
|
||||
if (moduleResolutionUsesNodeModules(moduleResolution)) {
|
||||
// If looking for a global package name, don't just include everything in `node_modules` because that includes dependencies' own dependencies.
|
||||
@@ -961,7 +968,7 @@ function getCompletionEntriesForNonRelativeModules(
|
||||
let ancestorLookup: (directory: string) => void | undefined = ancestor => {
|
||||
const nodeModules = combinePaths(ancestor, "node_modules");
|
||||
if (tryDirectoryExists(host, nodeModules)) {
|
||||
getCompletionEntriesForDirectoryFragment(fragment, nodeModules, extensionOptions, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result);
|
||||
getCompletionEntriesForDirectoryFragment(fragment, nodeModules, extensionOptions, program, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result);
|
||||
}
|
||||
};
|
||||
if (fragmentDirectory && getResolvePackageJsonExports(compilerOptions)) {
|
||||
@@ -998,6 +1005,7 @@ function getCompletionEntriesForNonRelativeModules(
|
||||
fragmentSubpath,
|
||||
packageDirectory,
|
||||
extensionOptions,
|
||||
program,
|
||||
host,
|
||||
keys,
|
||||
key => singleElementArray(getPatternFromFirstMatchingCondition(exports[key], conditions)),
|
||||
@@ -1041,6 +1049,7 @@ function getCompletionsForPathMapping(
|
||||
packageDirectory: string,
|
||||
extensionOptions: ExtensionOptions,
|
||||
isExportsWildcard: boolean,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
): readonly NameAndKind[] {
|
||||
if (!endsWith(path, "*")) {
|
||||
@@ -1052,9 +1061,9 @@ function getCompletionsForPathMapping(
|
||||
const remainingFragment = tryRemovePrefix(fragment, pathPrefix);
|
||||
if (remainingFragment === undefined) {
|
||||
const starIsFullPathComponent = path[path.length - 2] === "/";
|
||||
return starIsFullPathComponent ? justPathMappingName(pathPrefix, ScriptElementKind.directory) : flatMap(patterns, pattern => getModulesForPathsPattern("", packageDirectory, pattern, extensionOptions, isExportsWildcard, host)?.map(({ name, ...rest }) => ({ name: pathPrefix + name, ...rest })));
|
||||
return starIsFullPathComponent ? justPathMappingName(pathPrefix, ScriptElementKind.directory) : flatMap(patterns, pattern => getModulesForPathsPattern("", packageDirectory, pattern, extensionOptions, isExportsWildcard, program, host)?.map(({ name, ...rest }) => ({ name: pathPrefix + name, ...rest })));
|
||||
}
|
||||
return flatMap(patterns, pattern => getModulesForPathsPattern(remainingFragment, packageDirectory, pattern, extensionOptions, isExportsWildcard, host));
|
||||
return flatMap(patterns, pattern => getModulesForPathsPattern(remainingFragment, packageDirectory, pattern, extensionOptions, isExportsWildcard, program, host));
|
||||
|
||||
function justPathMappingName(name: string, kind: ScriptElementKind.directory | ScriptElementKind.scriptElement): readonly NameAndKind[] {
|
||||
return startsWith(name, fragment) ? [{ name: removeTrailingDirectorySeparator(name), kind, extension: undefined }] : emptyArray;
|
||||
@@ -1067,6 +1076,7 @@ function getModulesForPathsPattern(
|
||||
pattern: string,
|
||||
extensionOptions: ExtensionOptions,
|
||||
isExportsWildcard: boolean,
|
||||
program: Program,
|
||||
host: LanguageServiceHost,
|
||||
): readonly NameAndKind[] | undefined {
|
||||
if (!host.readDirectory) {
|
||||
@@ -1115,7 +1125,7 @@ function getModulesForPathsPattern(
|
||||
if (containsSlash(trimmedWithPattern)) {
|
||||
return directoryResult(getPathComponents(removeLeadingDirectorySeparator(trimmedWithPattern))[1]);
|
||||
}
|
||||
const { name, extension } = getFilenameWithExtensionOption(trimmedWithPattern, host.getCompilationSettings(), extensionOptions, isExportsWildcard);
|
||||
const { name, extension } = getFilenameWithExtensionOption(trimmedWithPattern, program, extensionOptions, isExportsWildcard);
|
||||
return nameAndKind(name, ScriptElementKind.scriptElement, extension);
|
||||
}
|
||||
});
|
||||
@@ -1159,7 +1169,8 @@ function getAmbientModuleCompletions(fragment: string, fragmentDirectory: string
|
||||
return nonRelativeModuleNames;
|
||||
}
|
||||
|
||||
function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number, compilerOptions: CompilerOptions, host: LanguageServiceHost): readonly PathCompletion[] | undefined {
|
||||
function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number, program: Program, host: LanguageServiceHost): readonly PathCompletion[] | undefined {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const token = getTokenAtPosition(sourceFile, position);
|
||||
const commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos);
|
||||
const range = commentRanges && find(commentRanges, commentRange => position >= commentRange.pos && position <= commentRange.end);
|
||||
@@ -1174,13 +1185,14 @@ function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: num
|
||||
|
||||
const [, prefix, kind, toComplete] = match;
|
||||
const scriptPath = getDirectoryPath(sourceFile.path);
|
||||
const names = kind === "path" ? getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getExtensionOptions(compilerOptions, ReferenceKind.Filename, sourceFile), host, /*moduleSpecifierIsRelative*/ true, sourceFile.path)
|
||||
: kind === "types" ? getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, getFragmentDirectory(toComplete), getExtensionOptions(compilerOptions, ReferenceKind.ModuleSpecifier, sourceFile))
|
||||
const names = kind === "path" ? getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getExtensionOptions(compilerOptions, ReferenceKind.Filename, sourceFile), program, host, /*moduleSpecifierIsRelative*/ true, sourceFile.path)
|
||||
: kind === "types" ? getCompletionEntriesFromTypings(host, program, scriptPath, getFragmentDirectory(toComplete), getExtensionOptions(compilerOptions, ReferenceKind.ModuleSpecifier, sourceFile))
|
||||
: Debug.fail();
|
||||
return addReplacementSpans(toComplete, range.pos + prefix.length, arrayFrom(names.values()));
|
||||
}
|
||||
|
||||
function getCompletionEntriesFromTypings(host: LanguageServiceHost, options: CompilerOptions, scriptPath: string, fragmentDirectory: string | undefined, extensionOptions: ExtensionOptions, result = createNameAndKindSet()): NameAndKindSet {
|
||||
function getCompletionEntriesFromTypings(host: LanguageServiceHost, program: Program, scriptPath: string, fragmentDirectory: string | undefined, extensionOptions: ExtensionOptions, result = createNameAndKindSet()): NameAndKindSet {
|
||||
const options = program.getCompilerOptions();
|
||||
// Check for typings specified in compiler options
|
||||
const seen = new Map<string, true>();
|
||||
|
||||
@@ -1215,7 +1227,7 @@ function getCompletionEntriesFromTypings(host: LanguageServiceHost, options: Com
|
||||
const baseDirectory = combinePaths(directory, typeDirectoryName);
|
||||
const remainingFragment = tryRemoveDirectoryPrefix(fragmentDirectory, packageName, hostGetCanonicalFileName(host));
|
||||
if (remainingFragment !== undefined) {
|
||||
getCompletionEntriesForDirectoryFragment(remainingFragment, baseDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result);
|
||||
getCompletionEntriesForDirectoryFragment(remainingFragment, baseDirectory, extensionOptions, program, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Pr
|
||||
program.getSemanticDiagnostics(sourceFile, cancellationToken);
|
||||
const diags: DiagnosticWithLocation[] = [];
|
||||
const checker = program.getTypeChecker();
|
||||
const isCommonJSFile = sourceFile.impliedNodeFormat === ModuleKind.CommonJS || fileExtensionIsOneOf(sourceFile.fileName, [Extension.Cts, Extension.Cjs]);
|
||||
const isCommonJSFile = program.getImpliedNodeFormatForEmit(sourceFile) === ModuleKind.CommonJS || fileExtensionIsOneOf(sourceFile.fileName, [Extension.Cts, Extension.Cjs]);
|
||||
|
||||
if (
|
||||
!isCommonJSFile &&
|
||||
|
||||
+20
-24
@@ -95,6 +95,7 @@ import {
|
||||
getEmitModuleKind,
|
||||
getEmitScriptTarget,
|
||||
getExternalModuleImportEqualsDeclarationExpression,
|
||||
getImpliedNodeFormatForEmitWorker,
|
||||
getImpliedNodeFormatForFile,
|
||||
getImpliedNodeFormatForFileWorker,
|
||||
getIndentString,
|
||||
@@ -2476,6 +2477,8 @@ export function createModuleSpecifierResolutionHost(program: Program, host: Lang
|
||||
getNearestAncestorDirectoryWithPackageJson: maybeBind(host, host.getNearestAncestorDirectoryWithPackageJson),
|
||||
getFileIncludeReasons: () => program.getFileIncludeReasons(),
|
||||
getCommonSourceDirectory: () => program.getCommonSourceDirectory(),
|
||||
getDefaultResolutionModeForFile: file => program.getDefaultResolutionModeForFile(file),
|
||||
getModeForResolutionAtIndex: (file, index) => program.getModeForResolutionAtIndex(file, index),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3987,22 +3990,13 @@ export function firstOrOnly<T>(valueOrArray: T | readonly T[]): T {
|
||||
return isArray(valueOrArray) ? first(valueOrArray) : valueOrArray;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getNamesForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTarget | undefined): string | [lowercase: string, capitalized: string] {
|
||||
if (needsNameFromDeclaration(symbol)) {
|
||||
const fromDeclaration = getDefaultLikeExportNameFromDeclaration(symbol);
|
||||
if (fromDeclaration) return fromDeclaration;
|
||||
const fileNameCase = moduleSymbolToValidIdentifier(getSymbolParentOrFail(symbol), scriptTarget, /*forceCapitalize*/ false);
|
||||
const capitalized = moduleSymbolToValidIdentifier(getSymbolParentOrFail(symbol), scriptTarget, /*forceCapitalize*/ true);
|
||||
if (fileNameCase === capitalized) return fileNameCase;
|
||||
return [fileNameCase, capitalized];
|
||||
}
|
||||
return symbol.name;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
/**
|
||||
* If a type checker and multiple files are available, consider using `forEachNameOfDefaultExport`
|
||||
* instead, which searches for names of re-exported defaults/namespaces in target files.
|
||||
* @internal
|
||||
*/
|
||||
export function getNameForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTarget | undefined, preferCapitalized?: boolean) {
|
||||
if (needsNameFromDeclaration(symbol)) {
|
||||
if (symbol.escapedName === InternalSymbolName.ExportEquals || symbol.escapedName === InternalSymbolName.Default) {
|
||||
// Names for default exports:
|
||||
// - export default foo => foo
|
||||
// - export { foo as default } => foo
|
||||
@@ -4013,11 +4007,11 @@ export function getNameForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTar
|
||||
return symbol.name;
|
||||
}
|
||||
|
||||
function needsNameFromDeclaration(symbol: Symbol) {
|
||||
return !(symbol.flags & SymbolFlags.Transient) && (symbol.escapedName === InternalSymbolName.ExportEquals || symbol.escapedName === InternalSymbolName.Default);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
/**
|
||||
* If a type checker and multiple files are available, consider using `forEachNameOfDefaultExport`
|
||||
* instead, which searches for names of re-exported defaults/namespaces in target files.
|
||||
* @internal
|
||||
*/
|
||||
export function getDefaultLikeExportNameFromDeclaration(symbol: Symbol): string | undefined {
|
||||
return firstDefined(symbol.declarations, d => {
|
||||
// "export default" in this case. See `ExportAssignment`for more details.
|
||||
@@ -4250,11 +4244,13 @@ export function fileShouldUseJavaScriptRequire(file: SourceFile | string, progra
|
||||
if (!hasJSFileExtension(fileName)) {
|
||||
return false;
|
||||
}
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const compilerOptions = typeof file === "string" ? program.getCompilerOptions() : program.getCompilerOptionsForFile(file);
|
||||
const moduleKind = getEmitModuleKind(compilerOptions);
|
||||
const impliedNodeFormat = typeof file === "string"
|
||||
? getImpliedNodeFormatForFile(toPath(file, host.getCurrentDirectory(), hostGetCanonicalFileName(host)), program.getPackageJsonInfoCache?.(), host, compilerOptions)
|
||||
: file.impliedNodeFormat;
|
||||
const sourceFileLike = typeof file === "string" ? {
|
||||
fileName: file,
|
||||
impliedNodeFormat: getImpliedNodeFormatForFile(toPath(file, host.getCurrentDirectory(), hostGetCanonicalFileName(host)), program.getPackageJsonInfoCache?.(), host, compilerOptions),
|
||||
} : file;
|
||||
const impliedNodeFormat = getImpliedNodeFormatForEmitWorker(sourceFileLike, compilerOptions);
|
||||
|
||||
if (impliedNodeFormat === ModuleKind.ESNext) {
|
||||
return false;
|
||||
|
||||
@@ -44,6 +44,51 @@ describe("unittests:: tsc:: projectReferences::", () => {
|
||||
commandLineArgs: ["--p", "src/project"],
|
||||
});
|
||||
|
||||
verifyTsc({
|
||||
scenario: "projectReferences",
|
||||
subScenario: "default import interop uses referenced project settings",
|
||||
fs: () =>
|
||||
loadProjectFromFiles({
|
||||
"/node_modules/ambiguous-package/package.json": `{ "name": "ambiguous-package" }`,
|
||||
"/node_modules/ambiguous-package/index.d.ts": "export declare const ambiguous: number;",
|
||||
"/node_modules/esm-package/package.json": `{ "name": "esm-package", "type": "module" }`,
|
||||
"/node_modules/esm-package/index.d.ts": "export declare const esm: number;",
|
||||
"/lib/tsconfig.json": jsonToReadableText({
|
||||
compilerOptions: {
|
||||
composite: true,
|
||||
declaration: true,
|
||||
rootDir: "src",
|
||||
outDir: "dist",
|
||||
module: "esnext",
|
||||
moduleResolution: "bundler",
|
||||
},
|
||||
include: ["src"],
|
||||
}),
|
||||
"/lib/src/a.ts": "export const a = 0;",
|
||||
"/lib/dist/a.d.ts": "export declare const a = 0;",
|
||||
"/app/tsconfig.json": jsonToReadableText({
|
||||
compilerOptions: {
|
||||
module: "esnext",
|
||||
moduleResolution: "bundler",
|
||||
rootDir: "src",
|
||||
outDir: "dist",
|
||||
},
|
||||
include: ["src"],
|
||||
references: [
|
||||
{ path: "../lib" },
|
||||
],
|
||||
}),
|
||||
"/app/src/local.ts": "export const local = 0;",
|
||||
"/app/src/index.ts": `
|
||||
import local from "./local"; // Error
|
||||
import esm from "esm-package"; // Error
|
||||
import referencedSource from "../../lib/src/a"; // Error
|
||||
import referencedDeclaration from "../../lib/dist/a"; // Error
|
||||
import ambiguous from "ambiguous-package"; // Ok`,
|
||||
}),
|
||||
commandLineArgs: ["--p", "app", "--pretty", "false"],
|
||||
});
|
||||
|
||||
verifyTsc({
|
||||
scenario: "projectReferences",
|
||||
subScenario: "referencing ambient const enum from referenced project with preserveConstEnums",
|
||||
|
||||
Reference in New Issue
Block a user