diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 06fc5a6d396f0..13a97c9ef2702 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4183,7 +4183,8 @@ namespace ts { return { accessibility: SymbolAccessibility.CannotBeNamed, errorSymbolName: symbolToString(symbol, enclosingDeclaration, meaning), - errorModuleName: symbolToString(symbolExternalModule) + errorModuleName: symbolToString(symbolExternalModule), + errorNode: isInJSFile(enclosingDeclaration) ? enclosingDeclaration : undefined, }; } } @@ -4699,7 +4700,7 @@ namespace ts { function createMappedTypeNodeFromType(type: MappedType) { Debug.assert(!!(type.flags & TypeFlags.Object)); - const readonlyToken = type.declaration.readonlyToken ? factory.createToken(type.declaration.readonlyToken.kind) : undefined; + const readonlyToken = type.declaration.readonlyToken ? factory.createToken(type.declaration.readonlyToken.kind) : undefined; const questionToken = type.declaration.questionToken ? factory.createToken(type.declaration.questionToken.kind) : undefined; let appropriateConstraintTypeNode: TypeNode; if (isMappedTypeWithKeyofConstraintDeclaration(type)) { @@ -6183,7 +6184,7 @@ namespace ts { tracker: { ...oldcontext.tracker, trackSymbol: (sym, decl, meaning) => { - const accessibleResult = isSymbolAccessible(sym, decl, meaning, /*computeALiases*/ false); + const accessibleResult = isSymbolAccessible(sym, decl, meaning, /*computeAliases*/ false); if (accessibleResult.accessibility === SymbolAccessibility.Accessible) { // Lookup the root symbol of the chain of refs we'll use to access it and serialize it const chain = lookupSymbolChainWorker(sym, context, meaning); @@ -6625,16 +6626,17 @@ namespace ts { function addResult(node: Statement, additionalModifierFlags: ModifierFlags) { if (canHaveModifiers(node)) { let newModifierFlags: ModifierFlags = ModifierFlags.None; + const enclosingDeclaration = context.enclosingDeclaration && + (isJSDocTypeAlias(context.enclosingDeclaration) ? getSourceFileOfNode(context.enclosingDeclaration) : context.enclosingDeclaration); if (additionalModifierFlags & ModifierFlags.Export && - context.enclosingDeclaration && - (isExportingScope(context.enclosingDeclaration) || isModuleDeclaration(context.enclosingDeclaration)) && + enclosingDeclaration && (isExportingScope(enclosingDeclaration) || isModuleDeclaration(enclosingDeclaration)) && canHaveExportModifier(node) ) { // Classes, namespaces, variables, functions, interfaces, and types should all be `export`ed in a module context if not private newModifierFlags |= ModifierFlags.Export; } if (addingDeclare && !(newModifierFlags & ModifierFlags.Export) && - (!context.enclosingDeclaration || !(context.enclosingDeclaration.flags & NodeFlags.Ambient)) && + (!enclosingDeclaration || !(enclosingDeclaration.flags & NodeFlags.Ambient)) && (isEnumDeclaration(node) || isVariableStatement(node) || isFunctionDeclaration(node) || isClassDeclaration(node) || isModuleDeclaration(node))) { // Classes, namespaces, variables, enums, and functions all need `declare` modifiers to be valid in a declaration file top-level scope newModifierFlags |= ModifierFlags.Ambient; @@ -6657,6 +6659,8 @@ namespace ts { const commentText = jsdocAliasDecl ? jsdocAliasDecl.comment || jsdocAliasDecl.parent.comment : undefined; const oldFlags = context.flags; context.flags |= NodeBuilderFlags.InTypeAlias; + const oldEnclosingDecl = context.enclosingDeclaration; + context.enclosingDeclaration = jsdocAliasDecl; const typeNode = jsdocAliasDecl && jsdocAliasDecl.typeExpression && isJSDocTypeExpression(jsdocAliasDecl.typeExpression) && serializeExistingTypeNode(context, jsdocAliasDecl.typeExpression.type, includePrivateSymbol, bundled) @@ -6666,6 +6670,7 @@ namespace ts { !commentText ? [] : [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }] ), modifierFlags); context.flags = oldFlags; + context.enclosingDeclaration = oldEnclosingDecl; } function serializeInterface(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 99cb2d5a6f238..6fa1d5fb476a8 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3537,6 +3537,10 @@ "category": "Error", "code": 4083 }, + "Exported type alias '{0}' has or is using private name '{1}' from module {2}.": { + "category": "Error", + "code": 4084 + }, "Conflicting definitions for '{0}' found at '{1}' and '{2}'. Consider installing a specific version of this library to resolve the conflict.": { "category": "Error", "code": 4090 diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 0ca8840059801..a6dab51d9c8ab 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -217,12 +217,12 @@ namespace ts { function transformDeclarationsForJS(sourceFile: SourceFile, bundled?: boolean) { const oldDiag = getSymbolAccessibilityDiagnostic; - getSymbolAccessibilityDiagnostic = (s) => ({ + getSymbolAccessibilityDiagnostic = (s) => (s.errorNode && canProduceDiagnostics(s.errorNode) ? createGetSymbolAccessibilityDiagnosticForNode(s.errorNode)(s) : ({ diagnosticMessage: s.errorModuleName ? Diagnostics.Declaration_emit_for_this_file_requires_using_private_name_0_from_module_1_An_explicit_type_annotation_may_unblock_declaration_emit : Diagnostics.Declaration_emit_for_this_file_requires_using_private_name_0_An_explicit_type_annotation_may_unblock_declaration_emit, errorNode: s.errorNode || sourceFile - }); + })); const result = resolver.getDeclarationStatementsForSourceFile(sourceFile, declarationEmitNodeBuilderFlags, symbolTracker, bundled); getSymbolAccessibilityDiagnostic = oldDiag; return result; diff --git a/src/compiler/transformers/declarations/diagnostics.ts b/src/compiler/transformers/declarations/diagnostics.ts index ebb453ee83d9a..7be27b453a0d2 100644 --- a/src/compiler/transformers/declarations/diagnostics.ts +++ b/src/compiler/transformers/declarations/diagnostics.ts @@ -27,7 +27,10 @@ namespace ts { | TypeAliasDeclaration | ConstructorDeclaration | IndexSignatureDeclaration - | PropertyAccessExpression; + | PropertyAccessExpression + | JSDocTypedefTag + | JSDocCallbackTag + | JSDocEnumTag; export function canProduceDiagnostics(node: Node): node is DeclarationDiagnosticProducing { return isVariableDeclaration(node) || @@ -48,7 +51,8 @@ namespace ts { isTypeAliasDeclaration(node) || isConstructorDeclaration(node) || isIndexSignatureDeclaration(node) || - isPropertyAccessExpression(node); + isPropertyAccessExpression(node) || + isJSDocTypeAlias(node); } export function createGetSymbolAccessibilityDiagnosticForNodeName(node: DeclarationDiagnosticProducing) { @@ -124,7 +128,7 @@ namespace ts { } } - export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationDiagnosticProducing): (symbolAccessibilityResult: SymbolAccessibilityResult) => SymbolAccessibilityDiagnostic | undefined { + export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationDiagnosticProducing): GetSymbolAccessibilityDiagnostic { if (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isPropertyAccessExpression(node) || isBindingElement(node) || isConstructorDeclaration(node)) { return getVariableDeclarationTypeVisibilityError; } @@ -149,7 +153,7 @@ namespace ts { else if (isImportEqualsDeclaration(node)) { return getImportEntityNameVisibilityError; } - else if (isTypeAliasDeclaration(node)) { + else if (isTypeAliasDeclaration(node) || isJSDocTypeAlias(node)) { return getTypeAliasDeclarationVisibilityError; } else { @@ -474,11 +478,13 @@ namespace ts { }; } - function getTypeAliasDeclarationVisibilityError(): SymbolAccessibilityDiagnostic { + function getTypeAliasDeclarationVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic { return { - diagnosticMessage: Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1, - errorNode: (node as TypeAliasDeclaration).type, - typeName: (node as TypeAliasDeclaration).name + diagnosticMessage: symbolAccessibilityResult.errorModuleName + ? Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1_from_module_2 + : Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1, + errorNode: isJSDocTypeAlias(node) ? Debug.checkDefined(node.typeExpression) : (node as TypeAliasDeclaration).type, + typeName: isJSDocTypeAlias(node) ? getNameOfDeclaration(node) : (node as TypeAliasDeclaration).name, }; } } diff --git a/tests/baselines/reference/jsDeclarationsClassImplementsGenericsSerialization.js b/tests/baselines/reference/jsDeclarationsClassImplementsGenericsSerialization.js index 04fbe98c54625..285cdae7b42b8 100644 --- a/tests/baselines/reference/jsDeclarationsClassImplementsGenericsSerialization.js +++ b/tests/baselines/reference/jsDeclarationsClassImplementsGenericsSerialization.js @@ -68,4 +68,4 @@ export class Encoder implements IEncoder { */ encode(value: T): Uint8Array; } -export type IEncoder = import("./interface").Encoder; +export type IEncoder = import('./interface').Encoder; diff --git a/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.js b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.js index bc85ba95d0de5..cb8fe79110dfe 100644 --- a/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.js +++ b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.js @@ -60,7 +60,7 @@ export namespace myTypes { /** * - Prop 1. */ - prop1: typeA; + prop1: myTypes.typeA; /** * - Prop 2. */ diff --git a/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js index f635869cea711..bd27e71768a9e 100644 --- a/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js +++ b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js @@ -68,7 +68,7 @@ export namespace myTypes { /** * - Prop 1. */ - prop1: typeA; + prop1: myTypes.typeA; /** * - Prop 2. */ diff --git a/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.errors.txt b/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.errors.txt index a231ff1aaf495..882a221dfef9a 100644 --- a/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.errors.txt +++ b/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.errors.txt @@ -1,4 +1,6 @@ -tests/cases/conformance/jsdoc/declarations/file.js(8,1): error TS9006: Declaration emit for this file requires using private name 'Base' from module '"tests/cases/conformance/jsdoc/declarations/base"'. An explicit type annotation may unblock declaration emit. +tests/cases/conformance/jsdoc/declarations/file.js(1,5): error TS4084: Exported type alias 'BaseFactory' has or is using private name 'Base' from module "tests/cases/conformance/jsdoc/declarations/base". +tests/cases/conformance/jsdoc/declarations/file.js(3,4): error TS4084: Exported type alias 'BaseFactoryFactory' has or is using private name 'Base' from module "tests/cases/conformance/jsdoc/declarations/base". +tests/cases/conformance/jsdoc/declarations/file.js(6,5): error TS4084: Exported type alias 'couldntThinkOfAny' has or is using private name 'Base' from module "tests/cases/conformance/jsdoc/declarations/base". ==== tests/cases/conformance/jsdoc/declarations/base.js (0 errors) ==== @@ -14,8 +16,22 @@ tests/cases/conformance/jsdoc/declarations/file.js(8,1): error TS9006: Declarati module.exports = BaseFactory; -==== tests/cases/conformance/jsdoc/declarations/file.js (1 errors) ==== +==== tests/cases/conformance/jsdoc/declarations/file.js (3 errors) ==== /** @typedef {import('./base')} BaseFactory */ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS4084: Exported type alias 'BaseFactory' has or is using private name 'Base' from module "tests/cases/conformance/jsdoc/declarations/base". + /** + * @callback BaseFactoryFactory + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * @param {import('./base')} factory + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + ~ +!!! error TS4084: Exported type alias 'BaseFactoryFactory' has or is using private name 'Base' from module "tests/cases/conformance/jsdoc/declarations/base". + /** @enum {import('./base')} */ + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS4084: Exported type alias 'couldntThinkOfAny' has or is using private name 'Base' from module "tests/cases/conformance/jsdoc/declarations/base". + const couldntThinkOfAny = {} /** * @@ -23,8 +39,6 @@ tests/cases/conformance/jsdoc/declarations/file.js(8,1): error TS9006: Declarati * @returns {InstanceType} */ const test = (base) => { - ~~~~~ -!!! error TS9006: Declaration emit for this file requires using private name 'Base' from module '"tests/cases/conformance/jsdoc/declarations/base"'. An explicit type annotation may unblock declaration emit. return base; }; \ No newline at end of file diff --git a/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.js b/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.js index c4a5b8c5018a1..fb4abcb308f4b 100644 --- a/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.js +++ b/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.js @@ -15,6 +15,12 @@ module.exports = BaseFactory; //// [file.js] /** @typedef {import('./base')} BaseFactory */ +/** + * @callback BaseFactoryFactory + * @param {import('./base')} factory + */ +/** @enum {import('./base')} */ +const couldntThinkOfAny = {} /** * @@ -37,6 +43,12 @@ BaseFactory.Base = Base; module.exports = BaseFactory; //// [file.js] /** @typedef {import('./base')} BaseFactory */ +/** + * @callback BaseFactoryFactory + * @param {import('./base')} factory + */ +/** @enum {import('./base')} */ +const couldntThinkOfAny = {}; /** * * @param {InstanceType} base diff --git a/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.symbols b/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.symbols index d927bfa797baf..0d20e28fa52cc 100644 --- a/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.symbols +++ b/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.symbols @@ -27,6 +27,13 @@ module.exports = BaseFactory; === tests/cases/conformance/jsdoc/declarations/file.js === /** @typedef {import('./base')} BaseFactory */ +/** + * @callback BaseFactoryFactory + * @param {import('./base')} factory + */ +/** @enum {import('./base')} */ +const couldntThinkOfAny = {} +>couldntThinkOfAny : Symbol(couldntThinkOfAny, Decl(file.js, 6, 5), Decl(file.js, 5, 4)) /** * @@ -34,11 +41,11 @@ module.exports = BaseFactory; * @returns {InstanceType} */ const test = (base) => { ->test : Symbol(test, Decl(file.js, 7, 5)) ->base : Symbol(base, Decl(file.js, 7, 14)) +>test : Symbol(test, Decl(file.js, 13, 5)) +>base : Symbol(base, Decl(file.js, 13, 14)) return base; ->base : Symbol(base, Decl(file.js, 7, 14)) +>base : Symbol(base, Decl(file.js, 13, 14)) }; diff --git a/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.types b/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.types index 0c45177a183b3..17f9522ca5cf3 100644 --- a/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.types +++ b/tests/baselines/reference/jsDeclarationsParameterTagReusesInputNodeInEmit1.types @@ -31,6 +31,14 @@ module.exports = BaseFactory; === tests/cases/conformance/jsdoc/declarations/file.js === /** @typedef {import('./base')} BaseFactory */ +/** + * @callback BaseFactoryFactory + * @param {import('./base')} factory + */ +/** @enum {import('./base')} */ +const couldntThinkOfAny = {} +>couldntThinkOfAny : {} +>{} : {} /** * diff --git a/tests/cases/conformance/jsdoc/declarations/jsDeclarationsParameterTagReusesInputNodeInEmit1.ts b/tests/cases/conformance/jsdoc/declarations/jsDeclarationsParameterTagReusesInputNodeInEmit1.ts index 6fe01d7b515b3..28a293ee63191 100644 --- a/tests/cases/conformance/jsdoc/declarations/jsDeclarationsParameterTagReusesInputNodeInEmit1.ts +++ b/tests/cases/conformance/jsdoc/declarations/jsDeclarationsParameterTagReusesInputNodeInEmit1.ts @@ -18,6 +18,12 @@ module.exports = BaseFactory; // @filename: file.js /** @typedef {import('./base')} BaseFactory */ +/** + * @callback BaseFactoryFactory + * @param {import('./base')} factory + */ +/** @enum {import('./base')} */ +const couldntThinkOfAny = {} /** *