typedoc
Version:
Create api documentation for TypeScript projects.
476 lines (475 loc) • 18.4 kB
JavaScript
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
import { Comment } from "../comments/comment.js";
import { splitUnquotedString } from "./utils.js";
import { ReflectionKind } from "./kind.js";
import { NonEnumerable } from "../../utils/general.js";
/**
* Current reflection id.
*/
let REFLECTION_ID = 0;
/**
* Reset the reflection id.
*
* Used by the test cases to ensure the reflection ids won't change between runs.
*/
export function resetReflectionID() {
REFLECTION_ID = 0;
}
export var ReflectionFlag;
(function (ReflectionFlag) {
ReflectionFlag[ReflectionFlag["None"] = 0] = "None";
ReflectionFlag[ReflectionFlag["Private"] = 1] = "Private";
ReflectionFlag[ReflectionFlag["Protected"] = 2] = "Protected";
ReflectionFlag[ReflectionFlag["Public"] = 4] = "Public";
ReflectionFlag[ReflectionFlag["Static"] = 8] = "Static";
ReflectionFlag[ReflectionFlag["External"] = 16] = "External";
ReflectionFlag[ReflectionFlag["Optional"] = 32] = "Optional";
ReflectionFlag[ReflectionFlag["Rest"] = 64] = "Rest";
ReflectionFlag[ReflectionFlag["Abstract"] = 128] = "Abstract";
ReflectionFlag[ReflectionFlag["Const"] = 256] = "Const";
ReflectionFlag[ReflectionFlag["Readonly"] = 512] = "Readonly";
ReflectionFlag[ReflectionFlag["Inherited"] = 1024] = "Inherited";
})(ReflectionFlag || (ReflectionFlag = {}));
const relevantFlags = [
ReflectionFlag.Private,
ReflectionFlag.Protected,
ReflectionFlag.Static,
ReflectionFlag.Optional,
ReflectionFlag.Abstract,
ReflectionFlag.Const,
ReflectionFlag.Readonly,
];
/**
* This must extend Array in order to work with Handlebar's each helper.
*/
export class ReflectionFlags {
flags = ReflectionFlag.None;
hasFlag(flag) {
return (flag & this.flags) !== 0;
}
/**
* Is this a private member?
*/
get isPrivate() {
return this.hasFlag(ReflectionFlag.Private);
}
/**
* Is this a protected member?
*/
get isProtected() {
return this.hasFlag(ReflectionFlag.Protected);
}
/**
* Is this a public member?
*/
get isPublic() {
return this.hasFlag(ReflectionFlag.Public);
}
/**
* Is this a static member?
*/
get isStatic() {
return this.hasFlag(ReflectionFlag.Static);
}
/**
* Is this a declaration from an external document?
*/
get isExternal() {
return this.hasFlag(ReflectionFlag.External);
}
/**
* Whether this reflection is an optional component or not.
*
* Applies to function parameters and object members.
*/
get isOptional() {
return this.hasFlag(ReflectionFlag.Optional);
}
/**
* Whether it's a rest parameter, like `foo(...params);`.
*/
get isRest() {
return this.hasFlag(ReflectionFlag.Rest);
}
get isAbstract() {
return this.hasFlag(ReflectionFlag.Abstract);
}
get isConst() {
return this.hasFlag(ReflectionFlag.Const);
}
get isReadonly() {
return this.hasFlag(ReflectionFlag.Readonly);
}
get isInherited() {
return this.hasFlag(ReflectionFlag.Inherited);
}
setFlag(flag, set) {
switch (flag) {
case ReflectionFlag.Private:
this.setSingleFlag(ReflectionFlag.Private, set);
if (set) {
this.setFlag(ReflectionFlag.Protected, false);
this.setFlag(ReflectionFlag.Public, false);
}
break;
case ReflectionFlag.Protected:
this.setSingleFlag(ReflectionFlag.Protected, set);
if (set) {
this.setFlag(ReflectionFlag.Private, false);
this.setFlag(ReflectionFlag.Public, false);
}
break;
case ReflectionFlag.Public:
this.setSingleFlag(ReflectionFlag.Public, set);
if (set) {
this.setFlag(ReflectionFlag.Private, false);
this.setFlag(ReflectionFlag.Protected, false);
}
break;
default:
this.setSingleFlag(flag, set);
}
}
getFlagStrings(i18n) {
const strings = [];
for (const flag of relevantFlags) {
if (this.hasFlag(flag)) {
strings.push(i18n.flagString(flag));
}
}
return strings;
}
setSingleFlag(flag, set) {
if (!set && this.hasFlag(flag)) {
this.flags ^= flag;
}
else if (set && !this.hasFlag(flag)) {
this.flags |= flag;
}
}
static serializedFlags = [
"isPrivate",
"isProtected",
"isPublic",
"isStatic",
"isExternal",
"isOptional",
"isRest",
"isAbstract",
"isConst",
"isReadonly",
"isInherited",
];
toObject() {
return Object.fromEntries(ReflectionFlags.serializedFlags
.filter((flag) => this[flag])
.map((flag) => [flag, true]));
}
fromObject(obj) {
for (const key of Object.keys(obj)) {
const flagName = key.substring(2); // isPublic => Public
if (flagName in ReflectionFlag) {
this.setFlag(ReflectionFlag[flagName], true);
}
}
}
}
export var TraverseProperty;
(function (TraverseProperty) {
TraverseProperty[TraverseProperty["Children"] = 0] = "Children";
TraverseProperty[TraverseProperty["Documents"] = 1] = "Documents";
TraverseProperty[TraverseProperty["Parameters"] = 2] = "Parameters";
TraverseProperty[TraverseProperty["TypeLiteral"] = 3] = "TypeLiteral";
TraverseProperty[TraverseProperty["TypeParameter"] = 4] = "TypeParameter";
TraverseProperty[TraverseProperty["Signatures"] = 5] = "Signatures";
TraverseProperty[TraverseProperty["IndexSignature"] = 6] = "IndexSignature";
TraverseProperty[TraverseProperty["GetSignature"] = 7] = "GetSignature";
TraverseProperty[TraverseProperty["SetSignature"] = 8] = "SetSignature";
})(TraverseProperty || (TraverseProperty = {}));
/**
* Base class for all reflection classes.
*
* While generating a documentation, TypeDoc generates an instance of {@link ProjectReflection}
* as the root for all reflections within the project. All other reflections are represented
* by the {@link DeclarationReflection} class.
*
* This base class exposes the basic properties one may use to traverse the reflection tree.
* You can use the {@link ContainerReflection.children} and {@link parent} properties to walk the tree. The {@link ContainerReflection.groups} property
* contains a list of all children grouped and sorted for rendering.
* @category Reflections
*/
let Reflection = (() => {
let _parent_decorators;
let _parent_initializers = [];
let _parent_extraInitializers = [];
let _project_decorators;
let _project_initializers = [];
let _project_extraInitializers = [];
return class Reflection {
static {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
_parent_decorators = [NonEnumerable];
_project_decorators = [NonEnumerable];
__esDecorate(null, null, _parent_decorators, { kind: "field", name: "parent", static: false, private: false, access: { has: obj => "parent" in obj, get: obj => obj.parent, set: (obj, value) => { obj.parent = value; } }, metadata: _metadata }, _parent_initializers, _parent_extraInitializers);
__esDecorate(null, null, _project_decorators, { kind: "field", name: "project", static: false, private: false, access: { has: obj => "project" in obj, get: obj => obj.project, set: (obj, value) => { obj.project = value; } }, metadata: _metadata }, _project_initializers, _project_extraInitializers);
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
}
/**
* Unique id of this reflection.
*/
id;
/**
* The symbol name of this reflection.
*/
name;
/**
* The kind of this reflection.
*/
kind;
flags = new ReflectionFlags();
/**
* The reflection this reflection is a child of.
*/
parent = __runInitializers(this, _parent_initializers, void 0);
project = (__runInitializers(this, _parent_extraInitializers), __runInitializers(this, _project_initializers, void 0));
/**
* The parsed documentation comment attached to this reflection.
*/
comment = __runInitializers(this, _project_extraInitializers);
/**
* The url of this reflection in the generated documentation.
* TODO: Reflections shouldn't know urls exist. Move this to a serializer.
*/
url;
/**
* The name of the anchor of this child.
* TODO: Reflections shouldn't know anchors exist. Move this to a serializer.
*/
anchor;
/**
* Is the url pointing to an individual document?
*
* When FALSE, the url points to an anchor tag on a page of a different reflection.
* TODO: Reflections shouldn't know how they are rendered. Move this to the correct serializer.
*/
hasOwnDocument;
constructor(name, kind, parent) {
this.id = REFLECTION_ID++;
this.parent = parent;
this.project = parent?.project || this;
this.name = name;
this.kind = kind;
// If our parent is external, we are too.
if (parent?.flags.isExternal) {
this.setFlag(ReflectionFlag.External);
}
}
/**
* Test whether this reflection is of the given kind.
*/
kindOf(kind) {
const kindFlags = Array.isArray(kind)
? kind.reduce((a, b) => a | b, 0)
: kind;
return (this.kind & kindFlags) !== 0;
}
/**
* Return the full name of this reflection. Intended for use in debugging. For log messages
* intended to be displayed to the user for them to fix, prefer {@link getFriendlyFullName} instead.
*
* The full name contains the name of this reflection and the names of all parent reflections.
*
* @param separator Separator used to join the names of the reflections.
* @returns The full name of this reflection.
*/
getFullName(separator = ".") {
if (this.parent && !this.parent.isProject()) {
return this.parent.getFullName(separator) + separator + this.name;
}
else {
return this.name;
}
}
/**
* Return the full name of this reflection, with signature names dropped if possible without
* introducing ambiguity in the name.
*/
getFriendlyFullName() {
if (this.parent && !this.parent.isProject()) {
if (this.kindOf(ReflectionKind.ConstructorSignature |
ReflectionKind.CallSignature |
ReflectionKind.GetSignature |
ReflectionKind.SetSignature)) {
return this.parent.getFriendlyFullName();
}
return this.parent.getFriendlyFullName() + "." + this.name;
}
else {
return this.name;
}
}
/**
* Set a flag on this reflection.
*/
setFlag(flag, value = true) {
this.flags.setFlag(flag, value);
}
/**
* Has this reflection a visible comment?
*
* @returns TRUE when this reflection has a visible comment.
*/
hasComment() {
return this.comment ? this.comment.hasVisibleComponent() : false;
}
hasGetterOrSetter() {
return false;
}
/**
* Return a child by its name.
*
* @param arg The name hierarchy of the child to look for.
* @returns The found child or undefined.
*/
getChildByName(arg) {
const names = Array.isArray(arg)
? arg
: splitUnquotedString(arg, ".");
const name = names[0];
let result;
this.traverse((child) => {
if (child.name === name) {
if (names.length <= 1) {
result = child;
}
else {
result = child.getChildByName(names.slice(1));
}
return false;
}
return true;
});
return result;
}
/**
* Return whether this reflection is the root / project reflection.
*/
isProject() {
return false;
}
isDeclaration() {
return false;
}
isParameter() {
return false;
}
isDocument() {
return false;
}
isReference() {
return this.variant === "reference";
}
/**
* Check if this reflection or any of its parents have been marked with the `@deprecated` tag.
*/
isDeprecated() {
let signaturesDeprecated = false;
this.visit({
declaration(decl) {
if (decl.signatures?.length &&
decl.signatures.every((sig) => sig.comment?.getTag("@deprecated"))) {
signaturesDeprecated = true;
}
},
});
if (signaturesDeprecated || this.comment?.getTag("@deprecated")) {
return true;
}
return this.parent?.isDeprecated() ?? false;
}
visit(visitor) {
visitor[this.variant]?.(this);
}
/**
* Return a string representation of this reflection.
*/
toString() {
return ReflectionKind[this.kind] + " " + this.name;
}
/**
* Return a string representation of this reflection and all of its children.
*
* Note: This is intended as a debug tool only, output may change between patch versions.
*
* @param indent Used internally to indent child reflections.
*/
toStringHierarchy(indent = "") {
const lines = [indent + this.toString()];
indent += " ";
this.traverse((child) => {
lines.push(child.toStringHierarchy(indent));
return true;
});
return lines.join("\n");
}
toObject(serializer) {
return {
id: this.id,
name: this.name,
variant: this.variant,
kind: this.kind,
flags: this.flags.toObject(),
comment: this.comment && !this.comment.isEmpty()
? serializer.toObject(this.comment)
: undefined,
};
}
fromObject(de, obj) {
// DO NOT copy id from obj. When deserializing reflections
// they should be given new ids since they belong to a different project.
this.name = obj.name;
// Skip copying variant, we know it's already the correct value because the deserializer
// will construct the correct class type.
this.kind = obj.kind;
this.flags.fromObject(obj.flags);
// Parent is set during construction, so we don't need to do it here.
this.comment = de.revive(obj.comment, () => new Comment());
// url, anchor, hasOwnDocument, _alias, _aliases are set during rendering and only relevant during render.
// It doesn't make sense to serialize them to json, or restore them.
}
};
})();
export { Reflection };