Skip to content

Commit e53e36b

Browse files
devversiondylhunn
authored andcommitted
refactor(compiler-cli): support ignoring specific doc entries during extraction (#54925)
This commit adds support for ignoring specific doc entries when extracting doc entries. This allows us to drop e.g. `InputFunction` from the API docs, given that the `input` API entry holds all the relevant information. `InputFunction` only exists for type purposes in the `.d.ts`. PR Close #54925
1 parent 0b38172 commit e53e36b

File tree

5 files changed

+92
-6
lines changed

5 files changed

+92
-6
lines changed

packages/compiler-cli/src/ngtsc/docs/src/extractor.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ export class DocsExtractor {
4242
const exportedDeclarations = this.getExportedDeclarations(sourceFile);
4343
for (const [exportName, node] of exportedDeclarations) {
4444
// Skip any symbols with an Angular-internal name.
45-
if (isAngularPrivateName(exportName)) continue;
45+
if (isAngularPrivateName(exportName)) {
46+
continue;
47+
}
4648

4749
const entry = this.extractDeclaration(node);
48-
if (entry) {
50+
if (entry && !isIgnoredDocEntry(entry)) {
4951
// The exported name of an API may be different from its declaration name, so
5052
// use the declaration name.
5153
entries.push({...entry, name: exportName});
@@ -77,10 +79,8 @@ export class DocsExtractor {
7779
}
7880

7981
if (ts.isVariableDeclaration(node) && !isSyntheticAngularConstant(node)) {
80-
if (isDecoratorDeclaration(node)) {
81-
return extractorDecorator(node, this.typeChecker);
82-
}
83-
return extractConstant(node, this.typeChecker);
82+
return isDecoratorDeclaration(node) ? extractorDecorator(node, this.typeChecker) :
83+
extractConstant(node, this.typeChecker);
8484
}
8585

8686
if (ts.isTypeAliasDeclaration(node)) {
@@ -138,3 +138,22 @@ function isIgnoredInterface(node: ts.InterfaceDeclaration) {
138138
// that contain the decorator options.
139139
return node.name.getText().endsWith('Decorator') || isDecoratorOptionsInterface(node);
140140
}
141+
142+
/**
143+
* Whether the doc entry should be ignored.
144+
*
145+
* Note: We cannot check whether a node is marked as docs private
146+
* before extraction because the extractor may find the attached
147+
* JSDoc tags on different AST nodes. For example, a variable declaration
148+
* never has JSDoc tags attached, but rather the parent variable statement.
149+
*/
150+
function isIgnoredDocEntry(entry: DocEntry): boolean {
151+
const isDocsPrivate = entry.jsdocTags.find(e => e.name === 'docsPrivate');
152+
if (isDocsPrivate !== undefined && isDocsPrivate.comment === '') {
153+
throw new Error(
154+
`Docs extraction: Entry "${entry.name}" is marked as ` +
155+
`"@docsPrivate" but without reasoning.`);
156+
}
157+
158+
return isDocsPrivate !== undefined;
159+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {DocEntry} from '@angular/compiler-cli/src/ngtsc/docs/src/entities';
10+
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
11+
12+
import {NgtscTestEnvironment} from '../env';
13+
14+
runInEachFileSystem(() => {
15+
describe('ngtsc docs: @docsPrivate tag', () => {
16+
let env: NgtscTestEnvironment;
17+
18+
beforeEach(() => {
19+
env = NgtscTestEnvironment.setup({});
20+
env.tsconfig();
21+
});
22+
23+
function test(input: string): DocEntry[] {
24+
env.write('index.ts', input);
25+
return env.driveDocsExtraction('index.ts');
26+
}
27+
28+
it('should omit constant annotated with `@docsPrivate`', () => {
29+
expect(test(`
30+
/** @docsPrivate <reason> */
31+
export const bla = true;
32+
`)).toEqual([]);
33+
});
34+
35+
it('should omit class annotated with `@docsPrivate`', () => {
36+
expect(test(`
37+
/** @docsPrivate <reason> */
38+
export class Bla {}
39+
`)).toEqual([]);
40+
});
41+
42+
it('should omit function annotated with `@docsPrivate`', () => {
43+
expect(test(`
44+
/** @docsPrivate <reason> */
45+
export function bla() {};
46+
`)).toEqual([]);
47+
});
48+
49+
it('should omit interface annotated with `@docsPrivate`', () => {
50+
expect(test(`
51+
/** @docsPrivate <reason> */
52+
export interface BlaFunction {}
53+
`)).toEqual([]);
54+
});
55+
56+
it('should error if marked as private without reasoning', () => {
57+
expect(() => test(`
58+
/** @docsPrivate */
59+
export interface BlaFunction {}
60+
`)).toThrowError(/Entry "BlaFunction" is marked as "@docsPrivate" but without reasoning./);
61+
});
62+
});
63+
});

packages/core/src/authoring/input/input.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export function inputRequiredFunction<ReadT, WriteT = ReadT>(opts?: InputOptions
3232
* `input.required` function.
3333
*
3434
* @developerPreview
35+
* @docsPrivate Ignored because `input` is the canonical API entry.
3536
*/
3637
export interface InputFunction {
3738
/**

packages/core/src/authoring/model/model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export function modelRequiredFunction<T>(): ModelSignal<T> {
3232
* `model.required` function.
3333
*
3434
* @developerPreview
35+
* @docsPrivate Ignored because `model` is the canonical API entry.
3536
*/
3637
export interface ModelFunction {
3738
/**

packages/core/src/authoring/queries.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ function viewChildRequiredFn<LocatorT, ReadT>(
3131
* property.
3232
*
3333
* @developerPreview
34+
* @docsPrivate Ignored because `viewChild` is the canonical API entry.
3435
*/
3536
export interface ViewChildFunction {
3637
/**
@@ -140,6 +141,7 @@ function contentChildRequiredFn<LocatorT, ReadT>(
140141
* provides access to required query results via the `.required` property.
141142
*
142143
* @developerPreview
144+
* @docsPrivate Ignored because `contentChild` is the canonical API entry.
143145
*/
144146
export interface ContentChildFunction {
145147
/**

0 commit comments

Comments
 (0)