mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
docs(docs-infra): Add dedicated support for decorators. (#57595)
PR Close #57595
This commit is contained in:
committed by
Andrew Scott
parent
88457ab9be
commit
07a485fdba
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
ClassEntry,
|
||||
ConstantEntry,
|
||||
DecoratorEntry,
|
||||
DocEntry,
|
||||
EntryType,
|
||||
EnumEntry,
|
||||
@@ -20,6 +21,7 @@ import {
|
||||
ClassEntryRenderable,
|
||||
CliCommandRenderable,
|
||||
ConstantEntryRenderable,
|
||||
DecoratorEntryRenderable,
|
||||
DocEntryRenderable,
|
||||
EnumEntryRenderable,
|
||||
FunctionEntryRenderable,
|
||||
@@ -42,11 +44,16 @@ export function isClassEntry(entry: DocEntry): entry is ClassEntry {
|
||||
entry.entryType === EntryType.Component ||
|
||||
entry.entryType === EntryType.Pipe ||
|
||||
entry.entryType === EntryType.NgModule ||
|
||||
entry.entryType === EntryType.Directive ||
|
||||
entry.entryType === EntryType.Decorator
|
||||
entry.entryType === EntryType.Directive
|
||||
);
|
||||
}
|
||||
|
||||
export function isDecoratorEntry(entry: DocEntryRenderable): entry is DecoratorEntryRenderable;
|
||||
export function isDecoratorEntry(entry: DocEntry): entry is DecoratorEntry;
|
||||
export function isDecoratorEntry(entry: DocEntry): entry is DecoratorEntry {
|
||||
return entry.entryType === EntryType.Decorator;
|
||||
}
|
||||
|
||||
/** Gets whether the given entry represents a constant */
|
||||
export function isConstantEntry(entry: DocEntryRenderable): entry is ConstantEntryRenderable;
|
||||
export function isConstantEntry(entry: DocEntry): entry is ConstantEntry;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import {
|
||||
ClassEntry,
|
||||
ConstantEntry,
|
||||
DecoratorEntry,
|
||||
DocEntry,
|
||||
EnumEntry,
|
||||
FunctionEntry,
|
||||
@@ -59,6 +60,12 @@ export type ClassEntryRenderable = ClassEntry &
|
||||
members: MemberEntryRenderable[];
|
||||
};
|
||||
|
||||
export type DecoratorEntryRenderable = DecoratorEntry &
|
||||
DocEntryRenderable &
|
||||
HasRenderableToc & {
|
||||
members: MemberEntryRenderable[];
|
||||
};
|
||||
|
||||
/** Documentation entity for a TypeScript enum augmented transformed content for rendering. */
|
||||
export type EnumEntryRenderable = EnumEntry &
|
||||
DocEntryRenderable &
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
isClassEntry,
|
||||
isCliEntry,
|
||||
isConstantEntry,
|
||||
isDecoratorEntry,
|
||||
isEnumEntry,
|
||||
isFunctionEntry,
|
||||
isInitializerApiFunctionEntry,
|
||||
@@ -20,6 +21,7 @@ import {
|
||||
} from './entities/categorization';
|
||||
import {CliCommandRenderable, DocEntryRenderable} from './entities/renderables';
|
||||
import {getClassRenderable} from './transforms/class-transforms';
|
||||
import {getDecoratorRenderable} from './transforms/decorator-transforms';
|
||||
import {getCliRenderable} from './transforms/cli-transforms';
|
||||
import {getConstantRenderable} from './transforms/constant-transforms';
|
||||
import {getEnumRenderable} from './transforms/enum-transforms';
|
||||
@@ -43,6 +45,9 @@ export function getRenderable(
|
||||
if (isClassEntry(entry)) {
|
||||
return getClassRenderable(entry, moduleName);
|
||||
}
|
||||
if (isDecoratorEntry(entry)) {
|
||||
return getDecoratorRenderable(entry, moduleName);
|
||||
}
|
||||
if (isConstantEntry(entry)) {
|
||||
return getConstantRenderable(entry, moduleName);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
isClassEntry,
|
||||
isCliEntry,
|
||||
isConstantEntry,
|
||||
isDecoratorEntry,
|
||||
isEnumEntry,
|
||||
isFunctionEntry,
|
||||
isInitializerApiFunctionEntry,
|
||||
@@ -36,7 +37,7 @@ export function renderEntry(renderable: DocEntryRenderable | CliCommandRenderabl
|
||||
return render(CliCommandReference(renderable));
|
||||
}
|
||||
|
||||
if (isClassEntry(renderable) || isInterfaceEntry(renderable)) {
|
||||
if (isClassEntry(renderable) || isInterfaceEntry(renderable) || isDecoratorEntry(renderable)) {
|
||||
return render(ClassReference(renderable));
|
||||
}
|
||||
if (isConstantEntry(renderable)) {
|
||||
|
||||
@@ -37,18 +37,22 @@ export function codeToHtml(
|
||||
});
|
||||
|
||||
if (options?.removeFunctionKeyword) {
|
||||
return removeFunctionKeywordFromShikiHtml(html);
|
||||
return replaceKeywordFromShikiHtml('function', html);
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
export function removeFunctionKeywordFromShikiHtml(shikiHtml: string): string {
|
||||
export function replaceKeywordFromShikiHtml(
|
||||
keyword: string,
|
||||
shikiHtml: string,
|
||||
replaceWith = '',
|
||||
): string {
|
||||
return (
|
||||
shikiHtml
|
||||
// remove the leading space of the element after the "function" element
|
||||
.replace(/(<[^>]*>function<\/\w+><[^>]*>)(\s)(\w+<\/\w+>)/g, '$1$3')
|
||||
.replace(new RegExp(`(<[^>]*>${keyword}<\\/\\w+><[^>]*>)(\\s)(\\w+<\\/\\w+>)`, 'g'), '$1$3')
|
||||
// Shiki requires the keyword function for highlighting functions signatures
|
||||
// We don't want to display it so we remove elements with the keyword
|
||||
.replace(/<[^>]*>function<\/\w+>/g, '')
|
||||
.replace(new RegExp(`<[^>]*>${keyword}<\\/\\w+>`, 'g'), replaceWith)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {Fragment, h} from 'preact';
|
||||
import {ClassEntryRenderable} from '../entities/renderables';
|
||||
import {ClassEntryRenderable, DecoratorEntryRenderable} from '../entities/renderables';
|
||||
import {ClassMemberList} from './class-member-list';
|
||||
import {HeaderApi} from './header-api';
|
||||
import {REFERENCE_MEMBERS_CONTAINER} from '../styling/css-classes';
|
||||
@@ -16,20 +16,20 @@ import {TabUsageNotes} from './tab-usage-notes';
|
||||
import {TabApi} from './tab-api';
|
||||
|
||||
/** Component to render a class API reference document. */
|
||||
export function ClassReference(entry: ClassEntryRenderable) {
|
||||
export function ClassReference(entry: ClassEntryRenderable | DecoratorEntryRenderable) {
|
||||
return (
|
||||
<div class="api">
|
||||
<HeaderApi entry={entry} />
|
||||
<TabApi entry={entry} />
|
||||
<TabDescription entry={entry} />
|
||||
<TabUsageNotes entry={entry} />
|
||||
{
|
||||
entry.members.length > 0
|
||||
? (<div class={REFERENCE_MEMBERS_CONTAINER}>
|
||||
<ClassMemberList members={entry.members} />
|
||||
</div>)
|
||||
: (<></>)
|
||||
}
|
||||
{entry.members.length > 0 ? (
|
||||
<div class={REFERENCE_MEMBERS_CONTAINER}>
|
||||
<ClassMemberList members={entry.members} />
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
isClassEntry,
|
||||
isClassMethodEntry,
|
||||
isConstantEntry,
|
||||
isDecoratorEntry,
|
||||
isDeprecatedEntry,
|
||||
isEnumEntry,
|
||||
isFunctionEntry,
|
||||
@@ -30,8 +31,8 @@ import {
|
||||
} from '../entities/categorization';
|
||||
import {CodeLineRenderable} from '../entities/renderables';
|
||||
import {HasModuleName, HasRenderableToc} from '../entities/traits';
|
||||
import {codeToHtml} from '../shiki/shiki';
|
||||
import {getModuleName} from '../symbol-context';
|
||||
import {codeToHtml, replaceKeywordFromShikiHtml} from '../shiki/shiki';
|
||||
|
||||
import {filterLifecycleMethods, mergeGettersAndSetters} from './member-transforms';
|
||||
import {getLinkToModule} from './url-transforms';
|
||||
@@ -65,10 +66,20 @@ export function addRenderableCodeToc<T extends DocEntry & HasModuleName>(
|
||||
const metadata = mapDocEntryToCode(entry);
|
||||
appendPrefixAndSuffix(entry, metadata);
|
||||
|
||||
const codeWithSyntaxHighlighting = codeToHtml(metadata.contents, 'typescript', {
|
||||
let codeWithSyntaxHighlighting = codeToHtml(metadata.contents, 'typescript', {
|
||||
removeFunctionKeyword: true,
|
||||
});
|
||||
|
||||
if (isDecoratorEntry(entry)) {
|
||||
// Shiki requires a keyword for correct formating of Decorators
|
||||
// We use an interface and then replace it with a '@'
|
||||
codeWithSyntaxHighlighting = replaceKeywordFromShikiHtml(
|
||||
'interface',
|
||||
codeWithSyntaxHighlighting,
|
||||
'@',
|
||||
);
|
||||
}
|
||||
|
||||
// shiki returns the lines wrapped by 2 node : 1 pre node, 1 code node.
|
||||
// As leveraging jsdom isn't trivial here, we rely on a regex to extract the line nodes
|
||||
const pattern = /(.*?)<code.*?>(.*?)<\/code>(.*)/s;
|
||||
@@ -126,6 +137,10 @@ export function mapDocEntryToCode(entry: DocEntry): CodeTableOfContentsData {
|
||||
return getCodeTocData(members, true, isDeprecated);
|
||||
}
|
||||
|
||||
if (isDecoratorEntry(entry)) {
|
||||
return getCodeTocData(entry.members, true, isDeprecated);
|
||||
}
|
||||
|
||||
if (isConstantEntry(entry)) {
|
||||
return {
|
||||
contents: `const ${entry.name}: ${entry.type};`,
|
||||
@@ -454,8 +469,8 @@ function appendPrefixAndSuffix(entry: DocEntry, codeTocData: CodeTableOfContents
|
||||
appendFirstAndLastLines(codeTocData, `enum ${entry.name} {`, `}`);
|
||||
}
|
||||
|
||||
if (isInterfaceEntry(entry)) {
|
||||
appendFirstAndLastLines(codeTocData, `interface ${entry.name} {`, `}`);
|
||||
if (isDecoratorEntry(entry)) {
|
||||
appendFirstAndLastLines(codeTocData, `interface ${entry.name} ({`, `})`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {DecoratorEntry} from '../entities';
|
||||
import {DecoratorEntryRenderable} from '../entities/renderables';
|
||||
import {addRenderableCodeToc} from './code-transforms';
|
||||
import {
|
||||
addHtmlAdditionalLinks,
|
||||
addHtmlDescription,
|
||||
addHtmlJsDocTagComments,
|
||||
addHtmlUsageNotes,
|
||||
setEntryFlags,
|
||||
} from './jsdoc-transforms';
|
||||
import {addRenderableMembers} from './member-transforms';
|
||||
import {addModuleName} from './module-name';
|
||||
|
||||
/** Given an unprocessed class entry, get the fully renderable class entry. */
|
||||
export function getDecoratorRenderable(
|
||||
classEntry: DecoratorEntry,
|
||||
moduleName: string,
|
||||
): DecoratorEntryRenderable {
|
||||
return setEntryFlags(
|
||||
addRenderableCodeToc(
|
||||
addRenderableMembers(
|
||||
addHtmlAdditionalLinks(
|
||||
addHtmlUsageNotes(
|
||||
addHtmlJsDocTagComments(addHtmlDescription(addModuleName(classEntry, moduleName))),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
) as DecoratorEntryRenderable;
|
||||
}
|
||||
Reference in New Issue
Block a user