X Tutup
Skip to content

Commit dea9b87

Browse files
committed
Introduce a concept of "ancillary" declarations, and make property setters ancillary to getters
1 parent 248c0a8 commit dea9b87

File tree

4 files changed

+60
-0
lines changed

4 files changed

+60
-0
lines changed

apps/api-extractor/src/analyzer/AstDeclaration.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ export class AstDeclaration {
234234
case ts.SyntaxKind.EnumDeclaration:
235235
case ts.SyntaxKind.EnumMember:
236236
case ts.SyntaxKind.FunctionDeclaration: // Example: "(x: number): number"
237+
case ts.SyntaxKind.GetAccessor:
238+
case ts.SyntaxKind.SetAccessor:
237239
case ts.SyntaxKind.IndexSignature: // Example: "[key: string]: string"
238240
case ts.SyntaxKind.InterfaceDeclaration:
239241
case ts.SyntaxKind.MethodDeclaration:
@@ -245,6 +247,9 @@ export class AstDeclaration {
245247
case ts.SyntaxKind.VariableDeclaration:
246248
return true;
247249

250+
// NOTE: Prior to TypeScript 3.7, in the emitted .d.ts files, the compiler would merge a GetAccessor/SetAccessor
251+
// pair into a single PropertyDeclaration.
252+
248253
// NOTE: In contexts where a source file is treated as a module, we do create "nominal analysis"
249254
// AstSymbol objects corresponding to a ts.SyntaxKind.SourceFile node. However, a source file
250255
// is NOT considered a nesting structure, and it does NOT act as a root for the declarations

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,18 @@ export class Collector {
525525
if (effectiveReleaseTag > maxEffectiveReleaseTag) {
526526
maxEffectiveReleaseTag = effectiveReleaseTag;
527527
}
528+
529+
// For a getter/setter pair, make the setter ancillary to the getter
530+
if (astDeclaration.declaration.kind === ts.SyntaxKind.SetAccessor) {
531+
for (const getterAstDeclaration of astDeclaration.astSymbol.astDeclarations) {
532+
if (getterAstDeclaration.declaration.kind === ts.SyntaxKind.GetAccessor) {
533+
const getterMetadata: DeclarationMetadata = getterAstDeclaration.metadata as DeclarationMetadata;
534+
535+
// Associate it with the getter
536+
getterMetadata.addAncillaryDeclaration(astDeclaration);
537+
}
538+
}
539+
}
528540
}
529541

530542
const symbolMetadata: SymbolMetadata = new SymbolMetadata();

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import * as tsdoc from '@microsoft/tsdoc';
55
import { ReleaseTag } from '@microsoft/api-extractor-model';
66
import { VisitorState } from './VisitorState';
7+
import { AstDeclaration } from '../analyzer/AstDeclaration';
8+
import { InternalError } from '@microsoft/node-core-library';
79

810
export class DeclarationMetadata {
911
/**
@@ -47,4 +49,41 @@ export class DeclarationMetadata {
4749
public releaseTagSameAsParent: boolean = false;
4850

4951
public docCommentEnhancerVisitorState: VisitorState = VisitorState.Unvisited;
52+
53+
/**
54+
* If true, then this declaration is treated as part of another declaration.
55+
*/
56+
public isAncillary: boolean = false;
57+
58+
/**
59+
* A list of other declarations that are treated as being part of this declaration. For example, a property
60+
* getter/setter pair will be treated as a single API item, with the setter being treated as ancillary to the getter.
61+
*
62+
* If the `ancillaryDeclarations` array is non-empty, then `isAncillary` will be false for this declaration,
63+
* and `isAncillary` will be true for all the array items.
64+
*/
65+
public ancillaryDeclarations: AstDeclaration[] = [];
66+
67+
public addAncillaryDeclaration(otherDeclaration: AstDeclaration): void {
68+
const otherMetadata: DeclarationMetadata = otherDeclaration.metadata as DeclarationMetadata;
69+
70+
if (!otherMetadata) {
71+
throw new InternalError('addAncillaryDeclaration() cannot be called before the declaration metadata is solved');
72+
}
73+
74+
if (this.ancillaryDeclarations.indexOf(otherDeclaration) >= 0) {
75+
return; // already added
76+
}
77+
78+
if (this.isAncillary) {
79+
throw new InternalError('Invalid call to addAncillaryDeclaration() because the target is ancillary itself');
80+
}
81+
82+
if (otherMetadata.isAncillary) {
83+
throw new InternalError('Invalid call to addAncillaryDeclaration() because source is already ancillary to another declaration');
84+
}
85+
86+
otherMetadata.isAncillary = true;
87+
this.ancillaryDeclarations.push(otherDeclaration);
88+
}
5089
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ export class ApiModelGenerator {
132132
this._processApiFunction(astDeclaration, exportedName, parentApiItem);
133133
break;
134134

135+
case ts.SyntaxKind.GetAccessor:
136+
this._processApiProperty(astDeclaration, exportedName, parentApiItem);
137+
break;
138+
135139
case ts.SyntaxKind.IndexSignature:
136140
this._processApiIndexSignature(astDeclaration, exportedName, parentApiItem);
137141
break;

0 commit comments

Comments
 (0)
X Tutup