From 39be1b01045c175e72645a5f2beaeea0095e82a5 Mon Sep 17 00:00:00 2001 From: adventure-yunfei Date: Wed, 3 Sep 2025 13:37:42 +0800 Subject: [PATCH 1/8] parse entity from export declarations inside namespace; keep modifiers inside namespace untouched --- .../src/analyzer/AstSymbolTable.ts | 1 + .../src/generators/DtsRollupGenerator.ts | 34 +++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/apps/api-extractor/src/analyzer/AstSymbolTable.ts b/apps/api-extractor/src/analyzer/AstSymbolTable.ts index e589ea10097..1bbd014cb3c 100644 --- a/apps/api-extractor/src/analyzer/AstSymbolTable.ts +++ b/apps/api-extractor/src/analyzer/AstSymbolTable.ts @@ -350,6 +350,7 @@ export class AstSymbolTable { case ts.SyntaxKind.ExpressionWithTypeArguments: // special case for e.g. the "extends" keyword case ts.SyntaxKind.ComputedPropertyName: // used for EcmaScript "symbols", e.g. "[toPrimitive]". case ts.SyntaxKind.TypeQuery: // represents for "typeof X" as a type + case ts.SyntaxKind.ExportSpecifier: // NamedExports inside namespace, e.g. "export { A as B };", "export { A }" { // Sometimes the type reference will involve multiple identifiers, e.g. "a.b.C". // In this case, we only need to worry about importing the first identifier, diff --git a/apps/api-extractor/src/generators/DtsRollupGenerator.ts b/apps/api-extractor/src/generators/DtsRollupGenerator.ts index 2d7c497f4dd..6ee3fc935c0 100644 --- a/apps/api-extractor/src/generators/DtsRollupGenerator.ts +++ b/apps/api-extractor/src/generators/DtsRollupGenerator.ts @@ -271,6 +271,20 @@ export class DtsRollupGenerator { case ts.SyntaxKind.ExportKeyword: case ts.SyntaxKind.DefaultKeyword: case ts.SyntaxKind.DeclareKeyword: + if (astDeclaration.parent) { + // Keep it as is for nested declarations. + break; + } + if ( + ts.isModuleDeclaration(astDeclaration.declaration) && + !astDeclaration.declaration.modifiers?.includes(span.node as ts.Modifier) + ) { + // Keep it as is for nested declarations. Handle special cases inside namespace. e.g.: + // - export declaration: "export {};", "export { A as B };" + // - variable declaration: "export const a: number, b: number;" + break; + } + // Delete any explicit "export" or "declare" keywords -- we will re-add them below span.modification.skipAll(); break; @@ -282,13 +296,16 @@ export class DtsRollupGenerator { case ts.SyntaxKind.ModuleKeyword: case ts.SyntaxKind.TypeKeyword: case ts.SyntaxKind.FunctionKeyword: + if (astDeclaration.parent) { + // Keep it as is for nested declarations + break; + } + // Replace the stuff we possibly deleted above let replacedModifiers: string = ''; // Add a declare statement for root declarations (but not for nested declarations) - if (!astDeclaration.parent) { - replacedModifiers += 'declare '; - } + replacedModifiers += 'declare '; if (entity.shouldInlineExport) { replacedModifiers = 'export ' + replacedModifiers; @@ -362,6 +379,17 @@ export class DtsRollupGenerator { } span.modification.prefix = referencedEntity.nameForEmit; + + if ( + ts.isExportSpecifier(span.node.parent) && + !span.node.parent.propertyName && + span.node.getText().trim() !== referencedEntity.nameForEmit + ) { + // For "export { A }" (inside namespace), if "A" is renamed (e.g. renamed to "B"), + // we need to emit as "export { B as A }" instead + span.modification.prefix += ' as ' + span.node.getText().trim(); + } + // For debugging: // span.modification.prefix += '/*R=FIX*/'; } else { From b2de03d89ed9041116d1cc4d8580f3c7f16c9804 Mon Sep 17 00:00:00 2001 From: adventure-yunfei Date: Wed, 3 Sep 2025 13:39:42 +0800 Subject: [PATCH 2/8] rush build --- .../etc/inheritedMembers/rollup.d.ts | 2 +- .../dist/api-extractor-lib1-test.d.ts | 6 +++--- .../etc/apiItemKinds/rollup.d.ts | 8 ++++---- .../etc/docReferences/rollup.d.ts | 2 +- .../etc/docReferences3/rollup.d.ts | 2 +- .../etc/includeForgottenExports/rollup.d.ts | 4 ++-- .../etc/mergedDeclarations/rollup.d.ts | 4 ++-- .../etc/preapproved/rollup.d.ts | 4 ++-- .../etc/referenceTokens/rollup.d.ts | 12 ++++++------ .../dist/api-extractor-test-04-alpha.d.ts | 6 +++--- .../dist/api-extractor-test-04-beta.d.ts | 4 ++-- .../dist/api-extractor-test-04.d.ts | 8 ++++---- 12 files changed, 31 insertions(+), 31 deletions(-) diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/rollup.d.ts b/build-tests/api-documenter-scenarios/etc/inheritedMembers/rollup.d.ts index 5a2309fcc4f..979e5723eed 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/rollup.d.ts +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/rollup.d.ts @@ -109,7 +109,7 @@ export declare type IInterfaceLikeTypeAlias = { /** @public */ export declare namespace Namespace1 { /** @public */ - export class Class3 { + class Class3 { /** Some prop. */ someProp: number; /** Some method. */ diff --git a/build-tests/api-extractor-lib1-test/dist/api-extractor-lib1-test.d.ts b/build-tests/api-extractor-lib1-test/dist/api-extractor-lib1-test.d.ts index 19117b01216..9e7a7efa134 100644 --- a/build-tests/api-extractor-lib1-test/dist/api-extractor-lib1-test.d.ts +++ b/build-tests/api-extractor-lib1-test/dist/api-extractor-lib1-test.d.ts @@ -28,11 +28,11 @@ export declare interface Lib1Interface { /** @public */ export declare namespace Lib1Namespace { - export namespace Inner { - export class X { + namespace Inner { + class X { } } - export class Y { + class Y { } } diff --git a/build-tests/api-extractor-scenarios/etc/apiItemKinds/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/apiItemKinds/rollup.d.ts index dbe1c3219c1..b8bfb0cac3f 100644 --- a/build-tests/api-extractor-scenarios/etc/apiItemKinds/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/apiItemKinds/rollup.d.ts @@ -28,20 +28,20 @@ export declare interface IInterface { /** @public */ export declare namespace n1 { - export class SomeClass1 { + class SomeClass1 { } export class SomeClass2 extends SomeClass1 { } export namespace n2 { - export class SomeClass3 { + class SomeClass3 { } } - {}; + export {}; } /** @public */ export declare namespace n1 { - export class SomeClass4 { + class SomeClass4 { } } diff --git a/build-tests/api-extractor-scenarios/etc/docReferences/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/docReferences/rollup.d.ts index 2739af6b264..0cdea7d2bc8 100644 --- a/build-tests/api-extractor-scenarios/etc/docReferences/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/docReferences/rollup.d.ts @@ -14,7 +14,7 @@ export declare function failWithMissingReference(): void; * @public */ export declare namespace MyNamespace { - export class MyClass { + class MyClass { /** * Summary for myMethod * @remarks diff --git a/build-tests/api-extractor-scenarios/etc/docReferences3/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/docReferences3/rollup.d.ts index 9823fc73ee2..e9202a7d392 100644 --- a/build-tests/api-extractor-scenarios/etc/docReferences3/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/docReferences3/rollup.d.ts @@ -1,6 +1,6 @@ /** @public */ export declare namespace A { - export class B { + class B { myMethod(): void; } } diff --git a/build-tests/api-extractor-scenarios/etc/includeForgottenExports/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/rollup.d.ts index 8010e499625..e0cd9bce51c 100644 --- a/build-tests/api-extractor-scenarios/etc/includeForgottenExports/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/rollup.d.ts @@ -77,10 +77,10 @@ export declare function someFunction7(): AnotherDuplicateName_2; /** @public */ export declare namespace SomeNamespace1 { - export class ForgottenExport3 { + class ForgottenExport3 { } export function someFunction3(): ForgottenExport3; - {}; + export {}; } export { } diff --git a/build-tests/api-extractor-scenarios/etc/mergedDeclarations/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/mergedDeclarations/rollup.d.ts index 3f28488b2f8..4dc4e66b05a 100644 --- a/build-tests/api-extractor-scenarios/etc/mergedDeclarations/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/mergedDeclarations/rollup.d.ts @@ -31,13 +31,13 @@ export declare interface MergedInterfaces { /** @public */ export declare namespace MergedNamespaces { - export class SomeClass { + class SomeClass { } } /** @public */ export declare namespace MergedNamespaces { - export class AnotherClass { + class AnotherClass { } } diff --git a/build-tests/api-extractor-scenarios/etc/preapproved/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/preapproved/rollup.d.ts index aff9acaaeb3..42cfaaee63a 100644 --- a/build-tests/api-extractor-scenarios/etc/preapproved/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/preapproved/rollup.d.ts @@ -16,9 +16,9 @@ export declare interface _PreapprovedInterface { /** @internal @preapproved */ export declare namespace _PreapprovedNamespace { - export class X { + class X { } - export function f(): void; + function f(): void; } export { } diff --git a/build-tests/api-extractor-scenarios/etc/referenceTokens/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/referenceTokens/rollup.d.ts index d1e60042702..2d621d67d77 100644 --- a/build-tests/api-extractor-scenarios/etc/referenceTokens/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/referenceTokens/rollup.d.ts @@ -5,18 +5,18 @@ import { Lib2Class } from 'api-extractor-lib2-test'; * @public */ export declare namespace n1 { - export type SomeType1 = number; + type SomeType1 = number; export function someFunction1(): SomeType1; export namespace n2 { - export type SomeType2 = number; + type SomeType2 = number; export function someFunction2(): SomeType2; export namespace n3 { - export type SomeType3 = number; - export function someFunction3(): n2.n3.SomeType3; + type SomeType3 = number; + function someFunction3(): n2.n3.SomeType3; } - {}; + export {}; } - {}; + export {}; } /** @public */ diff --git a/build-tests/api-extractor-test-04/dist/api-extractor-test-04-alpha.d.ts b/build-tests/api-extractor-test-04/dist/api-extractor-test-04-alpha.d.ts index 8e6b3a433e4..2301d0ad058 100644 --- a/build-tests/api-extractor-test-04/dist/api-extractor-test-04-alpha.d.ts +++ b/build-tests/api-extractor-test-04/dist/api-extractor-test-04-alpha.d.ts @@ -80,12 +80,12 @@ export declare namespace EntangledNamespace { * This is a nested namespace. * The "beta" release tag is inherited from the parent. */ - export namespace N2 { + namespace N2 { /** * This class is in a nested namespace. * @alpha */ - export class ClassX { + class ClassX { /** * The "alpha" release tag is inherited from the parent. */ @@ -96,7 +96,7 @@ export declare namespace EntangledNamespace { * This is a nested namespace. * The "beta" release tag is inherited from the parent. */ - export namespace N3 { + namespace N3 { /* Excluded from this release type: _ClassY */ } } diff --git a/build-tests/api-extractor-test-04/dist/api-extractor-test-04-beta.d.ts b/build-tests/api-extractor-test-04/dist/api-extractor-test-04-beta.d.ts index 449c8aedea6..6fb584a4e10 100644 --- a/build-tests/api-extractor-test-04/dist/api-extractor-test-04-beta.d.ts +++ b/build-tests/api-extractor-test-04/dist/api-extractor-test-04-beta.d.ts @@ -58,14 +58,14 @@ export declare namespace EntangledNamespace { * This is a nested namespace. * The "beta" release tag is inherited from the parent. */ - export namespace N2 { + namespace N2 { /* Excluded from this release type: ClassX */ } /** * This is a nested namespace. * The "beta" release tag is inherited from the parent. */ - export namespace N3 { + namespace N3 { /* Excluded from this release type: _ClassY */ } } diff --git a/build-tests/api-extractor-test-04/dist/api-extractor-test-04.d.ts b/build-tests/api-extractor-test-04/dist/api-extractor-test-04.d.ts index 5accf4e7216..f70690a84e2 100644 --- a/build-tests/api-extractor-test-04/dist/api-extractor-test-04.d.ts +++ b/build-tests/api-extractor-test-04/dist/api-extractor-test-04.d.ts @@ -96,12 +96,12 @@ export declare namespace EntangledNamespace { * This is a nested namespace. * The "beta" release tag is inherited from the parent. */ - export namespace N2 { + namespace N2 { /** * This class is in a nested namespace. * @alpha */ - export class ClassX { + class ClassX { /** * The "alpha" release tag is inherited from the parent. */ @@ -112,12 +112,12 @@ export declare namespace EntangledNamespace { * This is a nested namespace. * The "beta" release tag is inherited from the parent. */ - export namespace N3 { + namespace N3 { /** * This class is in a nested namespace. * @internal */ - export class _ClassY { + class _ClassY { /** * This definition refers to a "alpha" namespaced class. */ From 488cc95ea5428d4cc59abc4efe564b9a8165eb47 Mon Sep 17 00:00:00 2001 From: adventure-yunfei Date: Wed, 3 Sep 2025 13:55:14 +0800 Subject: [PATCH 3/8] add namespace test case --- .../api-extractor-scenarios.api.json | 391 ++++++++++++++++++ .../api-extractor-scenarios.api.md | 45 ++ .../etc/namespaceDeclaration/rollup.d.ts | 26 ++ .../src/namespaceDeclaration/index.ts | 22 + 4 files changed, 484 insertions(+) create mode 100644 build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.json create mode 100644 build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.md create mode 100644 build-tests/api-extractor-scenarios/etc/namespaceDeclaration/rollup.d.ts create mode 100644 build-tests/api-extractor-scenarios/src/namespaceDeclaration/index.ts diff --git a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.json new file mode 100644 index 00000000000..b66f69b1aad --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.json @@ -0,0 +1,391 @@ +{ + "metadata": { + "toolPackage": "@microsoft/api-extractor", + "toolVersion": "[test mode]", + "schemaVersion": 1011, + "oldestForwardsCompatibleVersion": 1001, + "tsdocConfig": { + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "noStandardTags": true, + "tagDefinitions": [ + { + "tagName": "@alpha", + "syntaxKind": "modifier" + }, + { + "tagName": "@beta", + "syntaxKind": "modifier" + }, + { + "tagName": "@defaultValue", + "syntaxKind": "block" + }, + { + "tagName": "@decorator", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@deprecated", + "syntaxKind": "block" + }, + { + "tagName": "@eventProperty", + "syntaxKind": "modifier" + }, + { + "tagName": "@example", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@experimental", + "syntaxKind": "modifier" + }, + { + "tagName": "@inheritDoc", + "syntaxKind": "inline" + }, + { + "tagName": "@internal", + "syntaxKind": "modifier" + }, + { + "tagName": "@label", + "syntaxKind": "inline" + }, + { + "tagName": "@link", + "syntaxKind": "inline", + "allowMultiple": true + }, + { + "tagName": "@override", + "syntaxKind": "modifier" + }, + { + "tagName": "@packageDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@param", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@privateRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@public", + "syntaxKind": "modifier" + }, + { + "tagName": "@readonly", + "syntaxKind": "modifier" + }, + { + "tagName": "@remarks", + "syntaxKind": "block" + }, + { + "tagName": "@returns", + "syntaxKind": "block" + }, + { + "tagName": "@sealed", + "syntaxKind": "modifier" + }, + { + "tagName": "@see", + "syntaxKind": "block" + }, + { + "tagName": "@throws", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@typeParam", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@virtual", + "syntaxKind": "modifier" + }, + { + "tagName": "@betaDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@internalRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@preapproved", + "syntaxKind": "modifier" + } + ], + "supportForTags": { + "@alpha": true, + "@beta": true, + "@defaultValue": true, + "@decorator": true, + "@deprecated": true, + "@eventProperty": true, + "@example": true, + "@experimental": true, + "@inheritDoc": true, + "@internal": true, + "@label": true, + "@link": true, + "@override": true, + "@packageDocumentation": true, + "@param": true, + "@privateRemarks": true, + "@public": true, + "@readonly": true, + "@remarks": true, + "@returns": true, + "@sealed": true, + "@see": true, + "@throws": true, + "@typeParam": true, + "@virtual": true, + "@betaDocumentation": true, + "@internalRemarks": true, + "@preapproved": true + }, + "reportUnsupportedHtmlElements": false + } + }, + "kind": "Package", + "canonicalReference": "api-extractor-scenarios!", + "docComment": "", + "name": "api-extractor-scenarios", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "api-extractor-scenarios!", + "name": "", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!AllExportedNS:namespace", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare namespace AllExportedNS " + } + ], + "fileUrlPath": "src/namespaceDeclaration/index.ts", + "releaseTag": "Public", + "name": "AllExportedNS", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!AllExportedNS.ExportedClass:class", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "class ExportedClass " + } + ], + "releaseTag": "Public", + "isAbstract": false, + "name": "ExportedClass", + "preserveMemberOrder": false, + "members": [], + "implementsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!AllExportedNS.ExportedInterface:interface", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "interface ExportedInterface " + } + ], + "releaseTag": "Public", + "name": "ExportedInterface", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRanges": [] + } + ] + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!FinalRenamedClass:interface", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "interface RenamedClass " + } + ], + "fileUrlPath": "src/namespaceDeclaration/index.ts", + "releaseTag": "Public", + "name": "FinalRenamedClass", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRanges": [] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!PartalExportedNS:namespace", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare namespace PartalExportedNS " + } + ], + "fileUrlPath": "src/namespaceDeclaration/index.ts", + "releaseTag": "Public", + "name": "PartalExportedNS", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!PartalExportedNS.ExportedInterface:interface", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface ExportedInterface " + } + ], + "releaseTag": "Public", + "name": "ExportedInterface", + "preserveMemberOrder": false, + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "api-extractor-scenarios!PartalExportedNS.ExportedInterface#prop:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "prop: " + }, + { + "kind": "Reference", + "text": "UnexportedClass", + "canonicalReference": "api-extractor-scenarios!PartalExportedNS~UnexportedClass:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "prop", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "api-extractor-scenarios!PartalExportedNS.UnexportedClass:interface", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "interface UnexportedClass " + } + ], + "releaseTag": "Public", + "name": "UnexportedClass", + "preserveMemberOrder": false, + "members": [], + "extendsTokenRanges": [] + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!PartalExportedNS.var1:var", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "var1 = " + }, + { + "kind": "Content", + "text": "1" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Public", + "name": "var1", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!PartalExportedNS.var2:var", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "var2 = " + }, + { + "kind": "Content", + "text": "2" + } + ], + "initializerTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isReadonly": true, + "releaseTag": "Public", + "name": "var2", + "variableTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + } + } + ] + }, + { + "kind": "Namespace", + "canonicalReference": "api-extractor-scenarios!ReexportNS:namespace", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare namespace ReexportNS " + } + ], + "fileUrlPath": "src/namespaceDeclaration/index.ts", + "releaseTag": "Public", + "name": "ReexportNS", + "preserveMemberOrder": false, + "members": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..788e76fcd03 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.md @@ -0,0 +1,45 @@ +## API Report File for "api-extractor-scenarios" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export namespace AllExportedNS { + // (undocumented) + export class ExportedClass { + } + // (undocumented) + export interface ExportedInterface { + } +} + +// @public (undocumented) +export interface FinalRenamedClass { +} + +// @public (undocumented) +export namespace PartalExportedNS { + const // (undocumented) + var1 = 1, // (undocumented) + var2 = 2; + // (undocumented) + export interface ExportedInterface { + // (undocumented) + prop: UnexportedClass; + } + // (undocumented) + export interface UnexportedClass { + } + {}; +} + +// @public (undocumented) +export namespace ReexportNS { + { FinalRenamedClass }; + { FinalRenamedClass as RenamedClass3 }; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/rollup.d.ts new file mode 100644 index 00000000000..438550c0cc6 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/rollup.d.ts @@ -0,0 +1,26 @@ +export declare namespace AllExportedNS { + class ExportedClass { + } + interface ExportedInterface { + } +} + +export declare interface FinalRenamedClass { +} + +export declare namespace PartalExportedNS { + export const var1 = 1, var2 = 2; + interface UnexportedClass { + } + export interface ExportedInterface { + prop: UnexportedClass; + } + export {}; +} + +export declare namespace ReexportNS { + export { FinalRenamedClass as RenamedClass }; + export { FinalRenamedClass as RenamedClass3 }; +} + +export { } diff --git a/build-tests/api-extractor-scenarios/src/namespaceDeclaration/index.ts b/build-tests/api-extractor-scenarios/src/namespaceDeclaration/index.ts new file mode 100644 index 00000000000..c5b76a7541c --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/namespaceDeclaration/index.ts @@ -0,0 +1,22 @@ +export namespace PartalExportedNS { + export const var1 = 1, + var2 = 2; + interface UnexportedClass {} + export interface ExportedInterface { + prop: UnexportedClass; + } +} + +export namespace AllExportedNS { + export class ExportedClass {} + export interface ExportedInterface {} +} + +export declare namespace ReexportNS { + export { RenamedClass }; + export { RenamedClass as RenamedClass3 }; +} + +interface RenamedClass {} + +export { RenamedClass as FinalRenamedClass }; From fcea3a925f432f9d8625a5911a48ca15b4276dab Mon Sep 17 00:00:00 2001 From: adventure-yunfei Date: Wed, 3 Sep 2025 14:01:10 +0800 Subject: [PATCH 4/8] rush change --- ...tractor-fix-namespace-support_2025-09-03-06-00.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/@microsoft/api-extractor/feat-api-extractor-fix-namespace-support_2025-09-03-06-00.json diff --git a/common/changes/@microsoft/api-extractor/feat-api-extractor-fix-namespace-support_2025-09-03-06-00.json b/common/changes/@microsoft/api-extractor/feat-api-extractor-fix-namespace-support_2025-09-03-06-00.json new file mode 100644 index 00000000000..32ddddaf5d6 --- /dev/null +++ b/common/changes/@microsoft/api-extractor/feat-api-extractor-fix-namespace-support_2025-09-03-06-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/api-extractor", + "comment": "fix namespace support: support re-exported entity; fix export declarations", + "type": "patch" + } + ], + "packageName": "@microsoft/api-extractor" +} \ No newline at end of file From 363af5b176a9073def07603ca706e245859dacac Mon Sep 17 00:00:00 2001 From: adventure-yunfei Date: Wed, 3 Sep 2025 14:35:43 +0800 Subject: [PATCH 5/8] update test case --- .../api-extractor-scenarios.api.json | 9 +++++---- .../namespaceDeclaration/api-extractor-scenarios.api.md | 2 +- .../etc/namespaceDeclaration/rollup.d.ts | 2 +- .../src/namespaceDeclaration/index.ts | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.json index b66f69b1aad..46ce7794849 100644 --- a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.json @@ -223,21 +223,22 @@ ] }, { - "kind": "Interface", - "canonicalReference": "api-extractor-scenarios!FinalRenamedClass:interface", + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!FinalRenamedClass:class", "docComment": "", "excerptTokens": [ { "kind": "Content", - "text": "interface RenamedClass " + "text": "declare class RenamedClass " } ], "fileUrlPath": "src/namespaceDeclaration/index.ts", "releaseTag": "Public", + "isAbstract": false, "name": "FinalRenamedClass", "preserveMemberOrder": false, "members": [], - "extendsTokenRanges": [] + "implementsTokenRanges": [] }, { "kind": "Namespace", diff --git a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.md index 788e76fcd03..bf55c884127 100644 --- a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.md @@ -15,7 +15,7 @@ export namespace AllExportedNS { } // @public (undocumented) -export interface FinalRenamedClass { +export class FinalRenamedClass { } // @public (undocumented) diff --git a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/rollup.d.ts index 438550c0cc6..305b359bc49 100644 --- a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/rollup.d.ts @@ -5,7 +5,7 @@ export declare namespace AllExportedNS { } } -export declare interface FinalRenamedClass { +export declare class FinalRenamedClass { } export declare namespace PartalExportedNS { diff --git a/build-tests/api-extractor-scenarios/src/namespaceDeclaration/index.ts b/build-tests/api-extractor-scenarios/src/namespaceDeclaration/index.ts index c5b76a7541c..7594c6ff6bc 100644 --- a/build-tests/api-extractor-scenarios/src/namespaceDeclaration/index.ts +++ b/build-tests/api-extractor-scenarios/src/namespaceDeclaration/index.ts @@ -17,6 +17,6 @@ export declare namespace ReexportNS { export { RenamedClass as RenamedClass3 }; } -interface RenamedClass {} +class RenamedClass {} export { RenamedClass as FinalRenamedClass }; From c036f6894dd2a9dd599e51e8ce24e754e1746322 Mon Sep 17 00:00:00 2001 From: adventure-yunfei Date: Wed, 3 Sep 2025 16:52:52 +0800 Subject: [PATCH 6/8] support api review --- .../src/generators/ApiReportGenerator.ts | 30 +++++++++++++++++++ .../api-documenter-scenarios.api.md | 2 +- .../etc/api-extractor-lib1-test.api.md | 6 ++-- .../api-extractor-scenarios.api.md | 8 ++--- .../api-extractor-scenarios.api.md | 2 +- .../api-extractor-scenarios.api.md | 2 +- .../api-extractor-scenarios.api.md | 4 +-- .../api-extractor-scenarios.api.md | 4 +-- .../api-extractor-scenarios.api.md | 14 ++++----- .../api-extractor-scenarios.api.md | 12 ++++---- .../etc/api-extractor-test-04.api.md | 8 ++--- 11 files changed, 61 insertions(+), 31 deletions(-) diff --git a/apps/api-extractor/src/generators/ApiReportGenerator.ts b/apps/api-extractor/src/generators/ApiReportGenerator.ts index 0c5ed48c981..ac1e95b5c4b 100644 --- a/apps/api-extractor/src/generators/ApiReportGenerator.ts +++ b/apps/api-extractor/src/generators/ApiReportGenerator.ts @@ -303,6 +303,20 @@ export class ApiReportGenerator { case ts.SyntaxKind.ExportKeyword: case ts.SyntaxKind.DefaultKeyword: case ts.SyntaxKind.DeclareKeyword: + if (astDeclaration.parent) { + // Keep it as is for nested declarations. + break; + } + if ( + ts.isModuleDeclaration(astDeclaration.declaration) && + !astDeclaration.declaration.modifiers?.includes(span.node as ts.Modifier) + ) { + // Keep it as is for nested declarations. Handle special cases inside namespace. e.g.: + // - export declaration: "export {};", "export { A as B };" + // - variable declaration: "export const a: number, b: number;" + break; + } + // Delete any explicit "export" or "declare" keywords -- we will re-add them below span.modification.skipAll(); break; @@ -314,6 +328,11 @@ export class ApiReportGenerator { case ts.SyntaxKind.ModuleKeyword: case ts.SyntaxKind.TypeKeyword: case ts.SyntaxKind.FunctionKeyword: + if (astDeclaration.parent) { + // Keep it as is for nested declarations + break; + } + // Replace the stuff we possibly deleted above let replacedModifiers: string = ''; @@ -385,6 +404,17 @@ export class ApiReportGenerator { } span.modification.prefix = referencedEntity.nameForEmit; + + if ( + ts.isExportSpecifier(span.node.parent) && + !span.node.parent.propertyName && + span.node.getText().trim() !== referencedEntity.nameForEmit + ) { + // For "export { A }" (inside namespace), if "A" is renamed (e.g. renamed to "B"), + // we need to emit as "export { B as A }" instead + span.modification.prefix += ' as ' + span.node.getText().trim(); + } + // For debugging: // span.modification.prefix += '/*R=FIX*/'; } else { diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/api-documenter-scenarios.api.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/api-documenter-scenarios.api.md index e3a1dc2acaf..ff074586dca 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/api-documenter-scenarios.api.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/api-documenter-scenarios.api.md @@ -76,7 +76,7 @@ export type IInterfaceLikeTypeAlias = { // @public (undocumented) export namespace Namespace1 { // (undocumented) - export class Class3 { + class Class3 { someMethod(x: boolean | string): void; someOverload(x: boolean): void; someOverload(x: string): void; diff --git a/build-tests/api-extractor-lib1-test/etc/api-extractor-lib1-test.api.md b/build-tests/api-extractor-lib1-test/etc/api-extractor-lib1-test.api.md index ae7e32783b4..1f229bcfc27 100644 --- a/build-tests/api-extractor-lib1-test/etc/api-extractor-lib1-test.api.md +++ b/build-tests/api-extractor-lib1-test/etc/api-extractor-lib1-test.api.md @@ -27,13 +27,13 @@ export interface Lib1Interface { // @public (undocumented) export namespace Lib1Namespace { // (undocumented) - export namespace Inner { + namespace Inner { // (undocumented) - export class X { + class X { } } // (undocumented) - export class Y { + class Y { } } diff --git a/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.md index c0743f1c37e..07829a32c98 100644 --- a/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.md @@ -42,22 +42,22 @@ export namespace n1 { // (undocumented) export namespace n2 { // (undocumented) - export class SomeClass3 { + class SomeClass3 { } } // (undocumented) - export class SomeClass1 { + class SomeClass1 { } // (undocumented) export class SomeClass2 extends SomeClass1 { } - {}; + export {}; } // @public (undocumented) export namespace n1 { // (undocumented) - export class SomeClass4 { + class SomeClass4 { } } diff --git a/build-tests/api-extractor-scenarios/etc/docReferences/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/docReferences/api-extractor-scenarios.api.md index 14031441b3b..8e0f8d0c5f5 100644 --- a/build-tests/api-extractor-scenarios/etc/docReferences/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/docReferences/api-extractor-scenarios.api.md @@ -17,7 +17,7 @@ export function failWithMissingReference(): void; // @public (undocumented) export namespace MyNamespace { // (undocumented) - export class MyClass { + class MyClass { // @beta myMethod(x: number): number; } diff --git a/build-tests/api-extractor-scenarios/etc/docReferences3/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/docReferences3/api-extractor-scenarios.api.md index cae6a88eaf1..ccd971329b6 100644 --- a/build-tests/api-extractor-scenarios/etc/docReferences3/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/docReferences3/api-extractor-scenarios.api.md @@ -7,7 +7,7 @@ // @public (undocumented) export namespace A { // (undocumented) - export class B { + class B { // (undocumented) myMethod(): void; } diff --git a/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.md index 43157fe55bb..c2c21c60b68 100644 --- a/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.md @@ -82,11 +82,11 @@ export function someFunction7(): AnotherDuplicateName_2; // @public (undocumented) export namespace SomeNamespace1 { // (undocumented) - export class ForgottenExport3 { + class ForgottenExport3 { } // (undocumented) export function someFunction3(): ForgottenExport3; - {}; + export {}; } // (No @packageDocumentation comment for this package) diff --git a/build-tests/api-extractor-scenarios/etc/mergedDeclarations/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/mergedDeclarations/api-extractor-scenarios.api.md index 16be4bda395..40c4e68cbc7 100644 --- a/build-tests/api-extractor-scenarios/etc/mergedDeclarations/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/mergedDeclarations/api-extractor-scenarios.api.md @@ -45,14 +45,14 @@ export interface MergedInterfaces { // @public (undocumented) export namespace MergedNamespaces { // (undocumented) - export class SomeClass { + class SomeClass { } } // @public (undocumented) export namespace MergedNamespaces { // (undocumented) - export class AnotherClass { + class AnotherClass { } } diff --git a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.md index bf55c884127..3847cea4c23 100644 --- a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.md @@ -7,10 +7,10 @@ // @public (undocumented) export namespace AllExportedNS { // (undocumented) - export class ExportedClass { + class ExportedClass { } // (undocumented) - export interface ExportedInterface { + interface ExportedInterface { } } @@ -20,7 +20,7 @@ export class FinalRenamedClass { // @public (undocumented) export namespace PartalExportedNS { - const // (undocumented) + export const // (undocumented) var1 = 1, // (undocumented) var2 = 2; // (undocumented) @@ -29,15 +29,15 @@ export namespace PartalExportedNS { prop: UnexportedClass; } // (undocumented) - export interface UnexportedClass { + interface UnexportedClass { } - {}; + export {}; } // @public (undocumented) export namespace ReexportNS { - { FinalRenamedClass }; - { FinalRenamedClass as RenamedClass3 }; + export { FinalRenamedClass as RenamedClass }; + export { FinalRenamedClass as RenamedClass3 }; } // (No @packageDocumentation comment for this package) diff --git a/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.md index 065b8df0b85..1d76d69994a 100644 --- a/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.md @@ -13,21 +13,21 @@ export namespace n1 { // (undocumented) export namespace n3 { // (undocumented) - export function someFunction3(): n2.n3.SomeType3; + function someFunction3(): n2.n3.SomeType3; // (undocumented) - export type SomeType3 = number; + type SomeType3 = number; } // (undocumented) export function someFunction2(): SomeType2; // (undocumented) - export type SomeType2 = number; - {}; + type SomeType2 = number; + export {}; } // (undocumented) export function someFunction1(): SomeType1; // (undocumented) - export type SomeType1 = number; - {}; + type SomeType1 = number; + export {}; } // @public (undocumented) diff --git a/build-tests/api-extractor-test-04/etc/api-extractor-test-04.api.md b/build-tests/api-extractor-test-04/etc/api-extractor-test-04.api.md index b6f80fc8894..8ef8c5f3c26 100644 --- a/build-tests/api-extractor-test-04/etc/api-extractor-test-04.api.md +++ b/build-tests/api-extractor-test-04/etc/api-extractor-test-04.api.md @@ -42,15 +42,15 @@ export const enum ConstEnum { // @beta export namespace EntangledNamespace { - export namespace N2 { + namespace N2 { // @alpha - export class ClassX { + class ClassX { static a: string; } } - export namespace N3 { + namespace N3 { // @internal - export class _ClassY { + class _ClassY { b: EntangledNamespace.N2.ClassX; c(): typeof N2.ClassX.a; } From 251e31f6d3f91178003817ce26c571f170409f93 Mon Sep 17 00:00:00 2001 From: adventure-yunfei Date: Wed, 3 Sep 2025 19:11:24 +0800 Subject: [PATCH 7/8] clean code --- .../src/generators/ApiReportGenerator.ts | 23 +++++++----------- .../src/generators/DtsEmitHelpers.ts | 24 +++++++++++++++++++ .../src/generators/DtsRollupGenerator.ts | 23 +++++++----------- .../src/namespaceDeclaration/index.ts | 4 ++++ 4 files changed, 44 insertions(+), 30 deletions(-) diff --git a/apps/api-extractor/src/generators/ApiReportGenerator.ts b/apps/api-extractor/src/generators/ApiReportGenerator.ts index ac1e95b5c4b..f7a22c21332 100644 --- a/apps/api-extractor/src/generators/ApiReportGenerator.ts +++ b/apps/api-extractor/src/generators/ApiReportGenerator.ts @@ -309,11 +309,11 @@ export class ApiReportGenerator { } if ( ts.isModuleDeclaration(astDeclaration.declaration) && - !astDeclaration.declaration.modifiers?.includes(span.node as ts.Modifier) + (TypeScriptHelpers.findFirstParent(span.node, ts.SyntaxKind.ExportDeclaration) || + TypeScriptHelpers.findFirstParent(span.node, ts.SyntaxKind.VariableStatement)) ) { - // Keep it as is for nested declarations. Handle special cases inside namespace. e.g.: - // - export declaration: "export {};", "export { A as B };" - // - variable declaration: "export const a: number, b: number;" + // Keep it as is for nested declarations. + // (special cases inside namespace. e.g. "export {};", "export const a: number;") break; } @@ -392,6 +392,10 @@ export class ApiReportGenerator { } break; + case ts.SyntaxKind.ExportSpecifier: + DtsEmitHelpers.modifyExportSpecifierSpan(collector, span); + break; + case ts.SyntaxKind.Identifier: const referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode( span.node as ts.Identifier @@ -404,17 +408,6 @@ export class ApiReportGenerator { } span.modification.prefix = referencedEntity.nameForEmit; - - if ( - ts.isExportSpecifier(span.node.parent) && - !span.node.parent.propertyName && - span.node.getText().trim() !== referencedEntity.nameForEmit - ) { - // For "export { A }" (inside namespace), if "A" is renamed (e.g. renamed to "B"), - // we need to emit as "export { B as A }" instead - span.modification.prefix += ' as ' + span.node.getText().trim(); - } - // For debugging: // span.modification.prefix += '/*R=FIX*/'; } else { diff --git a/apps/api-extractor/src/generators/DtsEmitHelpers.ts b/apps/api-extractor/src/generators/DtsEmitHelpers.ts index 3e7a339115e..4187ee02bcd 100644 --- a/apps/api-extractor/src/generators/DtsEmitHelpers.ts +++ b/apps/api-extractor/src/generators/DtsEmitHelpers.ts @@ -93,6 +93,30 @@ export class DtsEmitHelpers { } } + public static modifyExportSpecifierSpan(collector: Collector, span: Span): void { + // For "export { A }" (inside namespace), we need to emit as "export { AcutalName as A }" + const node: ts.ExportSpecifier = span.node as ts.ExportSpecifier; + if (!node.propertyName) { + if (!ts.isIdentifier(node.name)) { + throw new Error( + `Export specifier name should be an identifier, but got ${ts.SyntaxKind[node.name.kind]}.\n` + + SourceFileLocationFormatter.formatDeclaration(node) + ); + } + + const referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode(node.name); + if (!referencedEntity?.nameForEmit) { + throw new InternalError('referencedEntry or referencedEntry.nameForEmit is undefined'); + } + + const exportName: string = node.name.getText().trim(); + if (referencedEntity.nameForEmit !== exportName) { + span.modification.skipAll(); + span.modification.prefix = `${referencedEntity.nameForEmit} as ${span.getText()}`; + } + } + } + public static modifyImportTypeSpan( collector: Collector, span: Span, diff --git a/apps/api-extractor/src/generators/DtsRollupGenerator.ts b/apps/api-extractor/src/generators/DtsRollupGenerator.ts index 6ee3fc935c0..7de3705aba4 100644 --- a/apps/api-extractor/src/generators/DtsRollupGenerator.ts +++ b/apps/api-extractor/src/generators/DtsRollupGenerator.ts @@ -277,11 +277,11 @@ export class DtsRollupGenerator { } if ( ts.isModuleDeclaration(astDeclaration.declaration) && - !astDeclaration.declaration.modifiers?.includes(span.node as ts.Modifier) + (TypeScriptHelpers.findFirstParent(span.node, ts.SyntaxKind.ExportDeclaration) || + TypeScriptHelpers.findFirstParent(span.node, ts.SyntaxKind.VariableStatement)) ) { - // Keep it as is for nested declarations. Handle special cases inside namespace. e.g.: - // - export declaration: "export {};", "export { A as B };" - // - variable declaration: "export const a: number, b: number;" + // Keep it as is for nested declarations. + // (special cases inside namespace. e.g. "export {};", "export const a: number;") break; } @@ -366,6 +366,10 @@ export class DtsRollupGenerator { } break; + case ts.SyntaxKind.ExportSpecifier: + DtsEmitHelpers.modifyExportSpecifierSpan(collector, span); + break; + case ts.SyntaxKind.Identifier: { const referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode( @@ -379,17 +383,6 @@ export class DtsRollupGenerator { } span.modification.prefix = referencedEntity.nameForEmit; - - if ( - ts.isExportSpecifier(span.node.parent) && - !span.node.parent.propertyName && - span.node.getText().trim() !== referencedEntity.nameForEmit - ) { - // For "export { A }" (inside namespace), if "A" is renamed (e.g. renamed to "B"), - // we need to emit as "export { B as A }" instead - span.modification.prefix += ' as ' + span.node.getText().trim(); - } - // For debugging: // span.modification.prefix += '/*R=FIX*/'; } else { diff --git a/build-tests/api-extractor-scenarios/src/namespaceDeclaration/index.ts b/build-tests/api-extractor-scenarios/src/namespaceDeclaration/index.ts index 7594c6ff6bc..9ff231ba68c 100644 --- a/build-tests/api-extractor-scenarios/src/namespaceDeclaration/index.ts +++ b/build-tests/api-extractor-scenarios/src/namespaceDeclaration/index.ts @@ -1,3 +1,4 @@ +/** @public */ export namespace PartalExportedNS { export const var1 = 1, var2 = 2; @@ -7,16 +8,19 @@ export namespace PartalExportedNS { } } +/** @public */ export namespace AllExportedNS { export class ExportedClass {} export interface ExportedInterface {} } +/** @public */ export declare namespace ReexportNS { export { RenamedClass }; export { RenamedClass as RenamedClass3 }; } +/** @public */ class RenamedClass {} export { RenamedClass as FinalRenamedClass }; From 0235c5dc799c3590d8681b7c29b6976001b64fce Mon Sep 17 00:00:00 2001 From: adventure-yunfei Date: Fri, 5 Sep 2025 14:28:19 +0800 Subject: [PATCH 8/8] rush build --- .../api-documenter-test/etc/api-documenter-test.api.md | 6 +++--- .../namespaceDeclaration/api-extractor-scenarios.api.json | 8 ++++---- .../etc/namespaceDeclaration/rollup.d.ts | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/build-tests/api-documenter-test/etc/api-documenter-test.api.md b/build-tests/api-documenter-test/etc/api-documenter-test.api.md index 4b6989eff89..05f1d6f5a1d 100644 --- a/build-tests/api-documenter-test/etc/api-documenter-test.api.md +++ b/build-tests/api-documenter-test/etc/api-documenter-test.api.md @@ -83,7 +83,7 @@ export enum DocEnumNamespaceMerge { // @public export namespace DocEnumNamespaceMerge { - export function exampleFunction(): void; + function exampleFunction(): void; } // @public @@ -178,8 +178,8 @@ export interface IDocInterface7 { // @public export namespace OuterNamespace { - export namespace InnerNamespace { - export function nestedFunction(x: number): number; + namespace InnerNamespace { + function nestedFunction(x: number): number; } let nestedVariable: boolean; } diff --git a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.json index 46ce7794849..c21a8a21e84 100644 --- a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/api-extractor-scenarios.api.json @@ -175,7 +175,7 @@ { "kind": "Namespace", "canonicalReference": "api-extractor-scenarios!AllExportedNS:namespace", - "docComment": "", + "docComment": "/**\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", @@ -225,7 +225,7 @@ { "kind": "Class", "canonicalReference": "api-extractor-scenarios!FinalRenamedClass:class", - "docComment": "", + "docComment": "/**\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", @@ -243,7 +243,7 @@ { "kind": "Namespace", "canonicalReference": "api-extractor-scenarios!PartalExportedNS:namespace", - "docComment": "", + "docComment": "/**\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", @@ -373,7 +373,7 @@ { "kind": "Namespace", "canonicalReference": "api-extractor-scenarios!ReexportNS:namespace", - "docComment": "", + "docComment": "/**\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", diff --git a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/rollup.d.ts index 305b359bc49..d5b685f4415 100644 --- a/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/namespaceDeclaration/rollup.d.ts @@ -1,3 +1,4 @@ +/** @public */ export declare namespace AllExportedNS { class ExportedClass { } @@ -5,9 +6,11 @@ export declare namespace AllExportedNS { } } +/** @public */ export declare class FinalRenamedClass { } +/** @public */ export declare namespace PartalExportedNS { export const var1 = 1, var2 = 2; interface UnexportedClass { @@ -18,6 +21,7 @@ export declare namespace PartalExportedNS { export {}; } +/** @public */ export declare namespace ReexportNS { export { FinalRenamedClass as RenamedClass }; export { FinalRenamedClass as RenamedClass3 };