Make the implicitly exported rule consistent between checker and binder (#54659)

This commit is contained in:
Gabriela Araujo Britto 2023-06-22 16:27:53 -03:00 committed by GitHub
parent 70fe93fe33
commit 49deff209a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 97 additions and 5 deletions

View File

@ -87,6 +87,7 @@ import {
getElementOrPropertyAccessName,
getEmitScriptTarget,
getEnclosingBlockScopeContainer,
getEnclosingContainer,
getErrorSpanForNode,
getEscapedTextOfIdentifierOrLiteral,
getEscapedTextOfJsxNamespacedName,
@ -455,7 +456,8 @@ function getModuleInstanceStateForAliasTarget(specifier: ExportSpecifier, visite
return ModuleInstanceState.Instantiated; // Couldn't locate, assume could refer to a value
}
const enum ContainerFlags {
/** @internal */
export const enum ContainerFlags {
// The current node is not a container, and no container manipulation should happen before
// recursing into it.
None = 0,
@ -2356,7 +2358,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
const saveCurrentFlow = currentFlow;
for (const typeAlias of delayedTypeAliases) {
const host = typeAlias.parent.parent;
container = (findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) as IsContainer | undefined) || file;
container = (getEnclosingContainer(host) as IsContainer | undefined) || file;
blockScopeContainer = (getEnclosingBlockScopeContainer(host) as IsBlockScopedContainer | undefined) || file;
currentFlow = initFlowNode({ flags: FlowFlags.Start });
parent = typeAlias;
@ -3768,7 +3770,8 @@ export function isExportsOrModuleExportsOrAlias(sourceFile: SourceFile, node: Ex
return false;
}
function getContainerFlags(node: Node): ContainerFlags {
/** @internal */
export function getContainerFlags(node: Node): ContainerFlags {
switch (node.kind) {
case SyntaxKind.ClassExpression:
case SyntaxKind.ClassDeclaration:

View File

@ -274,6 +274,7 @@ import {
getEmitModuleResolutionKind,
getEmitScriptTarget,
getEnclosingBlockScopeContainer,
getEnclosingContainer,
getEntityNameFromTypeNode,
getErrorSpanForNode,
getEscapedTextOfIdentifierOrLiteral,
@ -39038,8 +39039,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
n.parent.kind !== SyntaxKind.ClassDeclaration &&
n.parent.kind !== SyntaxKind.ClassExpression &&
n.flags & NodeFlags.Ambient) {
if (!(flags & ModifierFlags.Ambient) && !(isModuleBlock(n.parent) && isModuleDeclaration(n.parent.parent) && isGlobalScopeAugmentation(n.parent.parent))) {
// It is nested in an ambient context, which means it is automatically exported
const container = getEnclosingContainer(n);
if ((container && container.flags & NodeFlags.ExportContext) && !(flags & ModifierFlags.Ambient) && !(isModuleBlock(n.parent) && isModuleDeclaration(n.parent.parent) && isGlobalScopeAugmentation(n.parent.parent))) {
// It is nested in an ambient export context, which means it is automatically exported
flags |= ModifierFlags.Export;
}
flags |= ModifierFlags.Ambient;

View File

@ -73,6 +73,7 @@ import {
ConditionalExpression,
ConstructorDeclaration,
ConstructSignatureDeclaration,
ContainerFlags,
contains,
containsPath,
createGetCanonicalFileName,
@ -162,6 +163,7 @@ import {
GetCanonicalFileName,
getCombinedModifierFlags,
getCombinedNodeFlags,
getContainerFlags,
getDirectoryPath,
getJSDocAugmentsTag,
getJSDocDeprecatedTagNoCache,
@ -2022,6 +2024,11 @@ export function isAnyImportOrReExport(node: Node): node is AnyImportOrReExport {
return isAnyImportSyntax(node) || isExportDeclaration(node);
}
/** @internal */
export function getEnclosingContainer(node: Node): Node | undefined {
return findAncestor(node.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer));
}
// Gets the nearest enclosing block scope container that has the provided node
// as a descendant, that is not the provided node.
/** @internal */

View File

@ -0,0 +1,19 @@
replace-in-file/types/index.d.ts(4,19): error TS2395: Individual declarations in merged declaration 'replaceInFile' must be all exported or all local.
replace-in-file/types/index.d.ts(7,13): error TS2395: Individual declarations in merged declaration 'replaceInFile' must be all exported or all local.
==== replace-in-file/types/index.d.ts (2 errors) ====
// repro from https://github.com/microsoft/TypeScript/issues/54342
declare module 'replace-in-file' {
export function replaceInFile(config: unknown): Promise<unknown[]>;
~~~~~~~~~~~~~
!!! error TS2395: Individual declarations in merged declaration 'replaceInFile' must be all exported or all local.
export default replaceInFile;
namespace replaceInFile {
~~~~~~~~~~~~~
!!! error TS2395: Individual declarations in merged declaration 'replaceInFile' must be all exported or all local.
export function sync(config: unknown): unknown[];
}
}

View File

@ -0,0 +1,24 @@
//// [tests/cases/compiler/namespaceNotMergedWithFunctionDefaultExport.ts] ////
=== replace-in-file/types/index.d.ts ===
// repro from https://github.com/microsoft/TypeScript/issues/54342
declare module 'replace-in-file' {
>'replace-in-file' : Symbol("replace-in-file", Decl(index.d.ts, 0, 0))
export function replaceInFile(config: unknown): Promise<unknown[]>;
>replaceInFile : Symbol(replaceInFile, Decl(index.d.ts, 2, 34))
>config : Symbol(config, Decl(index.d.ts, 3, 32))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
export default replaceInFile;
>replaceInFile : Symbol(replaceInFile, Decl(index.d.ts, 2, 34), Decl(index.d.ts, 4, 31))
namespace replaceInFile {
>replaceInFile : Symbol(replaceInFile, Decl(index.d.ts, 2, 34), Decl(index.d.ts, 4, 31))
export function sync(config: unknown): unknown[];
>sync : Symbol(sync, Decl(index.d.ts, 6, 27))
>config : Symbol(config, Decl(index.d.ts, 7, 25))
}
}

View File

@ -0,0 +1,23 @@
//// [tests/cases/compiler/namespaceNotMergedWithFunctionDefaultExport.ts] ////
=== replace-in-file/types/index.d.ts ===
// repro from https://github.com/microsoft/TypeScript/issues/54342
declare module 'replace-in-file' {
>'replace-in-file' : typeof import("replace-in-file")
export function replaceInFile(config: unknown): Promise<unknown[]>;
>replaceInFile : (config: unknown) => Promise<unknown[]>
>config : unknown
export default replaceInFile;
>replaceInFile : typeof replaceInFile
namespace replaceInFile {
>replaceInFile : typeof replaceInFile
export function sync(config: unknown): unknown[];
>sync : (config: unknown) => unknown[]
>config : unknown
}
}

View File

@ -0,0 +1,14 @@
// @moduleResolution: node10
// @module: commonjs
// repro from https://github.com/microsoft/TypeScript/issues/54342
// @Filename: replace-in-file/types/index.d.ts
declare module 'replace-in-file' {
export function replaceInFile(config: unknown): Promise<unknown[]>;
export default replaceInFile;
namespace replaceInFile {
export function sync(config: unknown): unknown[];
}
}