Skip to content

Commit 3b2129d

Browse files
committed
Responded to PR comments and prepared PR for review
1 parent 84de9f3 commit 3b2129d

File tree

10 files changed

+221
-33
lines changed

10 files changed

+221
-33
lines changed

apps/api-extractor/src/collector/CollectorEntity.ts

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ export class CollectorEntity {
3737
}
3838

3939
/**
40-
* The declaration name that will be emitted in a .d.ts rollup. For non-exported declarations,
41-
* Collector._makeUniqueNames() may need to rename the declaration to avoid conflicts with other declarations
42-
* in that module.
40+
* The declaration name that will be emitted in the .d.ts rollup, .api.md, and .api.json files. Generated by
41+
* `Collector._makeUniqueNames`. Be aware that the declaration may be renamed to avoid conflicts with (1)
42+
* global names (e.g. `Promise`) and (2) if local, other local names across different files.
4343
*/
4444
public get nameForEmit(): string | undefined {
4545
return this._nameForEmit;
@@ -97,7 +97,7 @@ export class CollectorEntity {
9797

9898
/**
9999
* Indicates that this entity is exported from its parent module (i.e. either the package entry point or
100-
* a local namespace).
100+
* a local namespace). Compare to `CollectorEntity.consumable`.
101101
*
102102
* @remarks
103103
* In the example below:
@@ -115,23 +115,23 @@ export class CollectorEntity {
115115
* but not consumable.
116116
*/
117117
public get exported(): boolean {
118-
const exportedFromTopLevel: boolean = this.exportNames.size > 0;
118+
// Exported from top-level?
119+
if (this.exportNames.size > 0) return true;
119120

120-
let exportedFromParent: boolean = false;
121+
// Exported from parent?
121122
for (const localExportNames of this._localExportNamesByParent.values()) {
122123
if (localExportNames.size > 0) {
123-
exportedFromParent = true;
124-
break;
124+
return true;
125125
}
126126
}
127127

128-
return exportedFromTopLevel || exportedFromParent;
128+
return false;
129129
}
130130

131131
/**
132-
* Indicates that it is possible for a consumer of the API to access this entity, either by importing
133-
* it directly, or via some other alias such as a member of a namespace. If an entity is not consumable,
134-
* then API Extractor will report an `ae-forgotten-export` warning.
132+
* Indicates that it is possible for a consumer of the API to "consume" this entity, either by importing
133+
* it directly or via a namespace. If an entity is not consumable, then API Extractor will report an
134+
* `ae-forgotten-export` warning. Compare to `CollectorEntity.exported`.
135135
*
136136
* @remarks
137137
* An API item is consumable if:
@@ -155,21 +155,35 @@ export class CollectorEntity {
155155
* In this example, `add` is exported via the consumable `calculator` namespace.
156156
*/
157157
public get consumable(): boolean {
158-
const exportedFromTopLevel: boolean = this.exportNames.size > 0;
158+
// Exported from top-level?
159+
if (this.exportNames.size > 0) return true;
159160

160-
let exportedFromExportedParent: boolean = false;
161+
// Exported from consumable parent?
161162
for (const [parent, localExportNames] of this._localExportNamesByParent) {
162163
if (localExportNames.size > 0 && parent.consumable) {
163-
exportedFromExportedParent = true;
164-
break;
164+
return true;
165165
}
166166
}
167167

168-
return exportedFromTopLevel || exportedFromExportedParent;
168+
return false;
169169
}
170170

171171
/**
172172
* Whether the entity has any parent entities.
173+
*
174+
* @remarks
175+
* In the example below:
176+
*
177+
* ```ts
178+
* declare function add(): void;
179+
* declare namespace calculator {
180+
* export {
181+
* add
182+
* }
183+
* }
184+
* ```
185+
*
186+
* The `CollectorEntity` for `calculator` is the parent of the `CollectorEntity` for `add`.
173187
*/
174188
public get hasParents(): boolean {
175189
return this._localExportNamesByParent.size > 0;
@@ -193,6 +207,20 @@ export class CollectorEntity {
193207

194208
/**
195209
* Adds a new local export name to the entity.
210+
*
211+
* @remarks
212+
* In the example below:
213+
*
214+
* ```ts
215+
* declare function add(): void;
216+
* declare namespace calculator {
217+
* export {
218+
* add
219+
* }
220+
* }
221+
* ```
222+
*
223+
* `add` is the local export name for the `CollectorEntity` for `add`.
196224
*/
197225
public addLocalExportName(localExportName: string, parent: CollectorEntity): void {
198226
const localExportNames: Set<string> = this._localExportNamesByParent.get(parent) || new Set();

apps/api-extractor/src/enhancers/DocCommentEnhancer.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ export class DocCommentEnhancer {
2828
public analyze(): void {
2929
for (const entity of this._collector.entities) {
3030
if (entity.astEntity instanceof AstSymbol) {
31-
if (entity.consumable || this._collector.extractorConfig.apiReportIncludeForgottenExports) {
31+
if (
32+
entity.consumable ||
33+
this._collector.extractorConfig.apiReportIncludeForgottenExports ||
34+
this._collector.extractorConfig.docModelIncludeForgottenExports
35+
) {
3236
entity.astEntity.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => {
3337
this._analyzeApiItem(astDeclaration);
3438
});

apps/api-extractor/src/enhancers/ValidationEnhancer.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ export class ValidationEnhancer {
2121
const alreadyWarnedEntities: Set<AstEntity> = new Set<AstEntity>();
2222

2323
for (const entity of collector.entities) {
24-
if (!(entity.consumable || collector.extractorConfig.apiReportIncludeForgottenExports)) {
24+
if (
25+
!(
26+
entity.consumable ||
27+
collector.extractorConfig.apiReportIncludeForgottenExports ||
28+
collector.extractorConfig.docModelIncludeForgottenExports
29+
)
30+
) {
2531
continue;
2632
}
2733

apps/api-extractor/src/generators/ApiModelGenerator.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,9 @@ export class ApiModelGenerator {
11441144

11451145
if (!entity) {
11461146
// This should never happen.
1147-
throw new InternalError('Failed to get collector entity for root symbol of declaration');
1147+
throw new InternalError(
1148+
`Failed to get collector entity for root symbol of declaration ${astDeclaration.astSymbol.localName}`
1149+
);
11481150
}
11491151

11501152
return entity.exported;

apps/api-extractor/src/generators/ApiReportGenerator.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,20 +172,21 @@ export class ApiReportGenerator {
172172
writer.increaseIndent();
173173

174174
const exportClauses: string[] = [];
175-
for (const [exportName, astEntity] of astModuleExportInfo.exportedLocalEntities) {
176-
const collectorEntity: CollectorEntity | undefined = collector.tryGetCollectorEntity(astEntity);
175+
for (const [exportedName, exportedEntity] of astModuleExportInfo.exportedLocalEntities) {
176+
const collectorEntity: CollectorEntity | undefined =
177+
collector.tryGetCollectorEntity(exportedEntity);
177178
if (collectorEntity === undefined) {
178179
// This should never happen
179180
// top-level exports of local imported module should be added as collector entities before
180181
throw new InternalError(
181-
`Cannot find collector entity for ${entity.nameForEmit}.${astEntity.localName}`
182+
`Cannot find collector entity for ${entity.nameForEmit}.${exportedEntity.localName}`
182183
);
183184
}
184185

185-
if (collectorEntity.nameForEmit === exportName) {
186+
if (collectorEntity.nameForEmit === exportedName) {
186187
exportClauses.push(collectorEntity.nameForEmit);
187188
} else {
188-
exportClauses.push(`${collectorEntity.nameForEmit} as ${exportName}`);
189+
exportClauses.push(`${collectorEntity.nameForEmit} as ${exportedName}`);
189190
}
190191
}
191192
writer.writeLine(exportClauses.join(',\n'));

build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.json

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,38 @@
172172
"name": "",
173173
"preserveMemberOrder": false,
174174
"members": [
175+
{
176+
"kind": "Class",
177+
"canonicalReference": "api-extractor-scenarios!~AnotherDuplicateName_2:class",
178+
"docComment": "",
179+
"excerptTokens": [
180+
{
181+
"kind": "Content",
182+
"text": "declare class AnotherDuplicateName "
183+
}
184+
],
185+
"releaseTag": "None",
186+
"name": "AnotherDuplicateName_2",
187+
"preserveMemberOrder": false,
188+
"members": [],
189+
"implementsTokenRanges": []
190+
},
191+
{
192+
"kind": "Class",
193+
"canonicalReference": "api-extractor-scenarios!~AnotherDuplicateName:class",
194+
"docComment": "/**\n * This forgotten item has the same name as another forgotten item in another file. They should be given unique names.\n */\n",
195+
"excerptTokens": [
196+
{
197+
"kind": "Content",
198+
"text": "declare class AnotherDuplicateName "
199+
}
200+
],
201+
"releaseTag": "None",
202+
"name": "AnotherDuplicateName",
203+
"preserveMemberOrder": false,
204+
"members": [],
205+
"implementsTokenRanges": []
206+
},
175207
{
176208
"kind": "TypeAlias",
177209
"canonicalReference": "api-extractor-scenarios!~DuplicateName_2:type",
@@ -200,7 +232,7 @@
200232
{
201233
"kind": "TypeAlias",
202234
"canonicalReference": "api-extractor-scenarios!DuplicateName:type",
203-
"docComment": "/**\n * This type is exported but has the same name as an unexported type in './internal.ts'. This unexported type is also included in the API report and doc model files. The unexported type will be renamed to avoid a name conflict.\n *\n * @public\n */\n",
235+
"docComment": "/**\n * This type is exported but has the same name as a forgotten type in './internal.ts'. This forgotten type is also included in the API report and doc model files. The forgotten type will be renamed to avoid a name conflict.\n *\n * @public\n */\n",
204236
"excerptTokens": [
205237
{
206238
"kind": "Content",
@@ -225,7 +257,7 @@
225257
{
226258
"kind": "Class",
227259
"canonicalReference": "api-extractor-scenarios!~ForgottenExport1:class",
228-
"docComment": "/**\n * This doc comment should be inherited by `ForgottenExport2`\n */\n",
260+
"docComment": "/**\n * `ForgottenExport2` wants to inherit this doc comment, but unfortunately this isn't supported yet\n */\n",
229261
"excerptTokens": [
230262
{
231263
"kind": "Content",
@@ -484,6 +516,62 @@
484516
"parameters": [],
485517
"name": "someFunction5"
486518
},
519+
{
520+
"kind": "Function",
521+
"canonicalReference": "api-extractor-scenarios!someFunction6:function(1)",
522+
"docComment": "/**\n * @public\n */\n",
523+
"excerptTokens": [
524+
{
525+
"kind": "Content",
526+
"text": "export declare function someFunction6(): "
527+
},
528+
{
529+
"kind": "Reference",
530+
"text": "AnotherDuplicateName",
531+
"canonicalReference": "api-extractor-scenarios!~AnotherDuplicateName:class"
532+
},
533+
{
534+
"kind": "Content",
535+
"text": ";"
536+
}
537+
],
538+
"returnTypeTokenRange": {
539+
"startIndex": 1,
540+
"endIndex": 2
541+
},
542+
"releaseTag": "Public",
543+
"overloadIndex": 1,
544+
"parameters": [],
545+
"name": "someFunction6"
546+
},
547+
{
548+
"kind": "Function",
549+
"canonicalReference": "api-extractor-scenarios!someFunction7:function(1)",
550+
"docComment": "/**\n * @public\n */\n",
551+
"excerptTokens": [
552+
{
553+
"kind": "Content",
554+
"text": "export declare function someFunction7(): "
555+
},
556+
{
557+
"kind": "Reference",
558+
"text": "AnotherDuplicateName",
559+
"canonicalReference": "api-extractor-scenarios!~AnotherDuplicateName:class"
560+
},
561+
{
562+
"kind": "Content",
563+
"text": ";"
564+
}
565+
],
566+
"returnTypeTokenRange": {
567+
"startIndex": 1,
568+
"endIndex": 2
569+
},
570+
"releaseTag": "Public",
571+
"overloadIndex": 1,
572+
"parameters": [],
573+
"name": "someFunction7"
574+
},
487575
{
488576
"kind": "Namespace",
489577
"canonicalReference": "api-extractor-scenarios!SomeNamespace1:namespace",

build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
55
```ts
66

7+
class AnotherDuplicateName {
8+
}
9+
10+
// (undocumented)
11+
class AnotherDuplicateName_2 {
12+
}
13+
714
// @public
815
export type DuplicateName = boolean;
916

@@ -59,6 +66,16 @@ export function someFunction4(): ForgottenExport4.ForgottenExport5;
5966
// @public (undocumented)
6067
export function someFunction5(): internal2.ForgottenExport6;
6168

69+
// Warning: (ae-forgotten-export) The symbol "AnotherDuplicateName" needs to be exported by the entry point index.d.ts
70+
//
71+
// @public (undocumented)
72+
export function someFunction6(): AnotherDuplicateName;
73+
74+
// Warning: (ae-forgotten-export) The symbol "AnotherDuplicateName_2" needs to be exported by the entry point index.d.ts
75+
//
76+
// @public (undocumented)
77+
export function someFunction7(): AnotherDuplicateName_2;
78+
6279
// @public (undocumented)
6380
export namespace SomeNamespace1 {
6481
// (undocumented)

build-tests/api-extractor-scenarios/etc/includeForgottenExports/rollup.d.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
/**
2-
* This type is exported but has the same name as an unexported type in './internal.ts'. This
3-
* unexported type is also included in the API report and doc model files. The unexported type
2+
* This forgotten item has the same name as another forgotten item in another
3+
* file. They should be given unique names.
4+
*/
5+
declare class AnotherDuplicateName {
6+
}
7+
8+
declare class AnotherDuplicateName_2 {
9+
}
10+
11+
/**
12+
* This type is exported but has the same name as a forgotten type in './internal.ts'. This
13+
* forgotten type is also included in the API report and doc model files. The forgotten type
414
* will be renamed to avoid a name conflict.
515
* @public
616
*/
@@ -12,7 +22,10 @@ export declare type DuplicateName = boolean;
1222
*/
1323
declare type DuplicateName_2 = number;
1424

15-
/** This doc comment should be inherited by `ForgottenExport2` */
25+
/**
26+
* `ForgottenExport2` wants to inherit this doc comment, but unfortunately this isn't
27+
* supported yet
28+
*/
1629
declare class ForgottenExport1 {
1730
prop?: ForgottenExport2;
1831
constructor();
@@ -47,6 +60,12 @@ export declare function someFunction4(): ForgottenExport4.ForgottenExport5;
4760
/** @public */
4861
export declare function someFunction5(): internal2.ForgottenExport6;
4962

63+
/** @public */
64+
export declare function someFunction6(): AnotherDuplicateName;
65+
66+
/** @public */
67+
export declare function someFunction7(): AnotherDuplicateName_2;
68+
5069
/** @public */
5170
export declare namespace SomeNamespace1 {
5271
export class ForgottenExport3 {

0 commit comments

Comments
 (0)