Skip to content

Commit 7960d11

Browse files
authored
Merge pull request microsoft#1681 from microsoft/octogonz/ae-issue-1679
[api-extractor] Fix issue where ae-incompatible-release-tags is sometimes reported incorrectly
2 parents 25ba669 + ad17065 commit 7960d11

19 files changed

Lines changed: 541 additions & 257 deletions

File tree

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,18 @@ export class AstDeclaration {
4949
public readonly modifierFlags: ts.ModifierFlags;
5050

5151
/**
52-
* Additional information applied later by the Collector.
52+
* Additional information that is calculated later by the `Collector`. The actual type is `DeclarationMetadata`,
53+
* but we declare it as `unknown` because consumers must obtain this object by calling
54+
* `Collector.fetchDeclarationMetadata()`.
5355
*/
54-
public metadata: unknown;
56+
public declarationMetadata: unknown;
57+
58+
/**
59+
* Additional information that is calculated later by the `Collector`. The actual type is `ApiItemMetadata`,
60+
* but we declare it as `unknown` because consumers must obtain this object by calling
61+
* `Collector.fetchApiItemMetadata()`.
62+
*/
63+
public apiItemMetadata: unknown;
5564

5665
// NOTE: This array becomes immutable after astSymbol.analyze() sets astSymbol.analyzed=true
5766
private readonly _analyzedChildren: AstDeclaration[] = [];

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,8 @@ export class AstReferenceResolver {
252252
let result: AstDeclaration | undefined = undefined;
253253

254254
for (const match of matches) {
255-
const metadata: DeclarationMetadata = this._collector.fetchMetadata(match);
256-
if (!metadata.isAncillary) {
255+
const declarationMetadata: DeclarationMetadata = this._collector.fetchDeclarationMetadata(match);
256+
if (!declarationMetadata.isAncillary) {
257257
if (result) {
258258
return undefined; // more than one match
259259
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,11 @@ export class AstSymbol {
108108
public readonly rootAstSymbol: AstSymbol;
109109

110110
/**
111-
* Additional information applied later by the Collector.
111+
* Additional information that is calculated later by the `Collector`. The actual type is `SymbolMetadata`,
112+
* but we declare it as `unknown` because consumers must obtain this object by calling
113+
* `Collector.fetchSymbolMetadata()`.
112114
*/
113-
public metadata: unknown;
115+
public symbolMetadata: unknown;
114116

115117
private readonly _astDeclarations: AstDeclaration[];
116118

apps/api-extractor/src/api/ExtractorMessageId.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ export const enum ExtractorMessageId {
6363
PreapprovedBadReleaseTag = 'ae-preapproved-bad-release-tag',
6464

6565
/**
66-
* "The `@inheritDoc` reference could not be resolved".
66+
* "The `@inheritDoc` reference could not be resolved."
6767
*/
6868
UnresolvedInheritDocReference = 'ae-unresolved-inheritdoc-reference',
6969

7070
/**
71-
* "The `@inheritDoc` tag needs a TSDoc declaration reference; signature matching is not supported yet".
71+
* "The `@inheritDoc` tag needs a TSDoc declaration reference; signature matching is not supported yet."
7272
*
7373
* @privateRemarks
7474
* In the future, we will implement signature matching so that you can write `{@inheritDoc}` and API Extractor
@@ -78,22 +78,22 @@ export const enum ExtractorMessageId {
7878
UnresolvedInheritDocBase = 'ae-unresolved-inheritdoc-base',
7979

8080
/**
81-
* "The `@inheritDoc` tag for ___ refers to its own declaration".
81+
* "The `@inheritDoc` tag for ___ refers to its own declaration."
8282
*/
8383
CyclicInheritDoc = 'ae-cyclic-inherit-doc',
8484

8585
/**
86-
* "The `@link` reference could not be resolved".
86+
* "The `@link` reference could not be resolved."
8787
*/
8888
UnresolvedLink = 'ae-unresolved-link',
8989

9090
/**
91-
* "The doc comment for the property ___ must appear on the getter, not the setter.".
91+
* "The doc comment for the property ___ must appear on the getter, not the setter."
9292
*/
9393
SetterWithDocs = 'ae-setter-with-docs',
9494

9595
/**
96-
* "The property ___ has a setter but no getter.".
96+
* "The property ___ has a setter but no getter."
9797
*/
9898
MissingGetter = 'ae-missing-getter',
9999
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2+
// See LICENSE in the project root for license information.
3+
4+
import * as tsdoc from '@microsoft/tsdoc';
5+
import { ReleaseTag } from '@microsoft/api-extractor-model';
6+
import { VisitorState } from './VisitorState';
7+
8+
/**
9+
* Constructor parameters for `ApiItemMetadata`.
10+
*/
11+
export interface IApiItemMetadataOptions {
12+
declaredReleaseTag: ReleaseTag;
13+
effectiveReleaseTag: ReleaseTag;
14+
releaseTagSameAsParent: boolean;
15+
isEventProperty: boolean;
16+
isOverride: boolean;
17+
isSealed: boolean;
18+
isVirtual: boolean;
19+
isPreapproved: boolean;
20+
}
21+
22+
/**
23+
* Stores the Collector's additional analysis for an `AstDeclaration`. This object is assigned to
24+
* `AstDeclaration.apiItemMetadata` but consumers must always obtain it by calling `Collector.fetchApiItemMetadata()`.
25+
*
26+
* @remarks
27+
* Note that ancillary declarations share their `ApiItemMetadata` with the main declaration,
28+
* whereas a separate `DeclarationMetadata` object is created for each declaration.
29+
*
30+
* Consider this example:
31+
* ```ts
32+
* export declare class A {
33+
* get b(): string;
34+
* set b(value: string);
35+
* }
36+
* export declare namespace A { }
37+
* ```
38+
*
39+
* In this example, there are two "symbols": `A` and `b`
40+
*
41+
* There are four "declarations": `A` class, `A` namespace, `b` getter, `b` setter
42+
*
43+
* There are three "API items": `A` class, `A` namespace, `b` property. The property getter is the main declaration
44+
* for `b`, and the setter is the "ancillary" declaration.
45+
*/
46+
export class ApiItemMetadata {
47+
/**
48+
* This is the release tag that was explicitly specified in the original doc comment, if any.
49+
*/
50+
public readonly declaredReleaseTag: ReleaseTag;
51+
52+
/**
53+
* The "effective" release tag is a normalized value that is based on `declaredReleaseTag`,
54+
* but may be inherited from a parent, or corrected if the declared value was somehow invalid.
55+
* When actually trimming .d.ts files or generating docs, API Extractor uses the "effective" value
56+
* instead of the "declared" value.
57+
*/
58+
public readonly effectiveReleaseTag: ReleaseTag;
59+
60+
// If true, then it would be redundant to show this release tag
61+
public readonly releaseTagSameAsParent: boolean;
62+
63+
// NOTE: In the future, the Collector may infer or error-correct some of these states.
64+
// Generators should rely on these instead of tsdocComment.modifierTagSet.
65+
public readonly isEventProperty: boolean;
66+
public readonly isOverride: boolean;
67+
public readonly isSealed: boolean;
68+
public readonly isVirtual: boolean;
69+
70+
public readonly isPreapproved: boolean;
71+
72+
/**
73+
* This is the TSDoc comment for the declaration. It may be modified (or constructed artificially) by
74+
* the DocCommentEnhancer.
75+
*/
76+
public tsdocComment: tsdoc.DocComment | undefined;
77+
78+
// Assigned by DocCommentEnhancer
79+
public needsDocumentation: boolean = true;
80+
81+
public docCommentEnhancerVisitorState: VisitorState = VisitorState.Unvisited;
82+
83+
public constructor(options: IApiItemMetadataOptions) {
84+
this.declaredReleaseTag = options.declaredReleaseTag;
85+
this.effectiveReleaseTag = options.effectiveReleaseTag;
86+
this.releaseTagSameAsParent = options.releaseTagSameAsParent;
87+
this.isEventProperty = options.isEventProperty;
88+
this.isOverride = options.isOverride;
89+
this.isSealed = options.isSealed;
90+
this.isVirtual = options.isVirtual;
91+
this.isPreapproved = options.isPreapproved;
92+
}
93+
}

0 commit comments

Comments
 (0)