mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-15 02:53:31 +01:00
feat: docgen package (#8029)
This commit is contained in:
143
packages/docgen/src/documentation.ts
Normal file
143
packages/docgen/src/documentation.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import { join } from 'path';
|
||||
import { Collection } from '@discordjs/collection';
|
||||
import type { ChildTypes, Class, Config, CustomDocs, RootTypes } from './interfaces/index.js';
|
||||
import { DocumentedClass } from './types/class.js';
|
||||
import { DocumentedConstructor } from './types/constructor.js';
|
||||
import { DocumentedEvent } from './types/event.js';
|
||||
import { DocumentedExternal } from './types/external.js';
|
||||
import { DocumentedInterface } from './types/interface.js';
|
||||
import { DocumentedMember } from './types/member.js';
|
||||
import { DocumentedMethod } from './types/method.js';
|
||||
import { DocumentedTypeDef } from './types/typedef.js';
|
||||
import packageFile from '../package.json';
|
||||
|
||||
export class Documentation {
|
||||
public readonly classes = new Collection<string, DocumentedClass>();
|
||||
|
||||
public readonly functions = new Collection<string, DocumentedMethod>();
|
||||
|
||||
public readonly interfaces = new Collection<string, DocumentedInterface>();
|
||||
|
||||
public readonly typedefs = new Collection<string, DocumentedTypeDef>();
|
||||
|
||||
public readonly externals = new Collection<string, DocumentedExternal>();
|
||||
|
||||
public constructor(
|
||||
data: RootTypes[],
|
||||
private readonly config: Config,
|
||||
private readonly custom?: Record<string, CustomDocs>,
|
||||
) {
|
||||
let items = data;
|
||||
for (const item of items) {
|
||||
switch (item.kind) {
|
||||
case 'class': {
|
||||
this.classes.set(item.name, new DocumentedClass(item, config));
|
||||
items = items.filter((i) => i.longname !== item.longname);
|
||||
break;
|
||||
}
|
||||
case 'function': {
|
||||
if (item.scope === 'global' || !item.memberof) {
|
||||
this.functions.set(item.name, new DocumentedMethod(item, config));
|
||||
items = items.filter((i) => i.longname !== item.longname);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'interface': {
|
||||
this.interfaces.set(item.name, new DocumentedInterface(item as unknown as Class, config));
|
||||
items = items.filter((i) => i.longname !== item.longname);
|
||||
break;
|
||||
}
|
||||
case 'typedef': {
|
||||
this.typedefs.set(item.name, new DocumentedTypeDef(item, config));
|
||||
items = items.filter((i) => i.longname !== item.longname);
|
||||
break;
|
||||
}
|
||||
case 'external': {
|
||||
this.externals.set(item.name, new DocumentedExternal(item, config));
|
||||
items = items.filter((i) => i.longname !== item.longname);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.parse(items as ChildTypes[]);
|
||||
}
|
||||
|
||||
public parse(items: ChildTypes[]) {
|
||||
for (const member of items) {
|
||||
let item: DocumentedMethod | DocumentedConstructor | DocumentedMember | DocumentedEvent | null = null;
|
||||
|
||||
switch (member.kind) {
|
||||
case 'constructor': {
|
||||
item = new DocumentedConstructor(member, this.config);
|
||||
break;
|
||||
}
|
||||
case 'function': {
|
||||
item = new DocumentedMethod(member, this.config);
|
||||
break;
|
||||
}
|
||||
case 'member': {
|
||||
item = new DocumentedMember(member, this.config);
|
||||
break;
|
||||
}
|
||||
case 'event': {
|
||||
item = new DocumentedEvent(member, this.config);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// @ts-expect-error
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
console.warn(`- Unknown documentation kind "${member.kind}" - \n${JSON.stringify(member)}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
const parent = this.classes.get(member.memberof ?? '') ?? this.interfaces.get(member.memberof ?? '');
|
||||
if (parent) {
|
||||
if (item) {
|
||||
parent.add(item);
|
||||
} else {
|
||||
console.warn(
|
||||
`- Documentation item could not be constructed for "${member.name}" - \n${JSON.stringify(member)}\n`,
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const info = [];
|
||||
const name = (member.name || item?.data.name) ?? 'UNKNOWN';
|
||||
const memberof = member.memberof ?? item?.data.memberof;
|
||||
const meta =
|
||||
member.kind === 'constructor'
|
||||
? null
|
||||
: { file: member.meta.filename, line: member.meta.lineno, path: member.meta.path };
|
||||
|
||||
if (memberof) info.push(`member of "${memberof}"`);
|
||||
if (meta) info.push(`${join(meta.path, meta.file)}${meta.line ? `:${meta.line}` : ''}`);
|
||||
|
||||
console.warn(`- "${name}"${info.length ? ` (${info.join(', ')})` : ''} has no accessible parent.`);
|
||||
if (!name && !info.length) console.warn('Raw object:', member);
|
||||
}
|
||||
}
|
||||
|
||||
public serialize() {
|
||||
return {
|
||||
meta: {
|
||||
generator: packageFile.version,
|
||||
format: Documentation.FORMAT_VERSION,
|
||||
date: Date.now(),
|
||||
},
|
||||
classes: this.classes.map((c) => c.serialize()),
|
||||
functions: this.functions.map((f) => f.serialize()),
|
||||
interfaces: this.interfaces.map((i) => i.serialize()),
|
||||
typedefs: this.typedefs.map((t) => t.serialize()),
|
||||
externals: this.externals.map((e) => e.serialize()),
|
||||
custom: this.custom,
|
||||
};
|
||||
}
|
||||
|
||||
public static get FORMAT_VERSION() {
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
88
packages/docgen/src/index.ts
Normal file
88
packages/docgen/src/index.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env node
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
import { join, basename, extname, dirname, relative } from 'path';
|
||||
import { createCommand } from 'commander';
|
||||
import jsdoc2md from 'jsdoc-to-markdown';
|
||||
import { Documentation } from './documentation.js';
|
||||
import type { ChildTypes, CustomDocs, RootTypes } from './interfaces/index.js';
|
||||
import packageFile from '../package.json';
|
||||
|
||||
interface CLIOptions {
|
||||
input: string[];
|
||||
custom: string;
|
||||
root: string;
|
||||
output: string;
|
||||
}
|
||||
|
||||
interface CustomFiles {
|
||||
id?: string;
|
||||
name: string;
|
||||
path?: string;
|
||||
files: {
|
||||
id?: string;
|
||||
name: string;
|
||||
path: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
const command = createCommand()
|
||||
.version(packageFile.version)
|
||||
.option('-i, --input <string...>', 'Source directories to parse JSDocs in')
|
||||
.option('-c, --custom <string>', 'Custom docs definition file to use')
|
||||
.option('-r, --root [string]', 'Root directory of the project', '.')
|
||||
.option('-o, --output <string>', 'Path to output file');
|
||||
|
||||
const program = command.parse(process.argv);
|
||||
const options = program.opts<CLIOptions>();
|
||||
|
||||
console.log('Parsing JSDocs in source files...');
|
||||
const data = jsdoc2md.getTemplateDataSync({ files: options.input }) as (RootTypes & ChildTypes)[];
|
||||
console.log(`${data.length} JSDoc items parsed.`);
|
||||
|
||||
const custom: Record<string, CustomDocs> = {};
|
||||
if (options.custom) {
|
||||
console.log('Loading custom docs files...');
|
||||
const customDir = dirname(options.custom);
|
||||
const file = readFileSync(options.custom, 'utf-8');
|
||||
const data = JSON.parse(file) as CustomFiles[];
|
||||
|
||||
for (const category of data) {
|
||||
const categoryId = category.id ?? category.name.toLowerCase();
|
||||
const dir = join(customDir, category.path ?? categoryId);
|
||||
custom[categoryId] = {
|
||||
name: category.name || category.id,
|
||||
files: {},
|
||||
};
|
||||
|
||||
for (const f of category.files) {
|
||||
const fileRootPath = join(dir, f.path);
|
||||
const extension = extname(f.path);
|
||||
const fileId = f.id ?? basename(f.path, extension);
|
||||
const fileData = readFileSync(fileRootPath, 'utf-8');
|
||||
custom[categoryId]!.files[fileId] = {
|
||||
name: f.name,
|
||||
type: extension.toLowerCase().replace(/^\./, ''),
|
||||
content: fileData,
|
||||
path: relative(options.root, fileRootPath).replace(/\\/g, '/'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const fileCount = Object.keys(custom)
|
||||
.map((k) => Object.keys(custom[k]!))
|
||||
.reduce((prev, c) => prev + c.length, 0);
|
||||
const categoryCount = Object.keys(custom).length;
|
||||
console.log(
|
||||
`${fileCount} custom docs file${fileCount === 1 ? '' : 's'} in ` +
|
||||
`${categoryCount} categor${categoryCount === 1 ? 'y' : 'ies'} loaded.`,
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`Serializing documentation with format version ${Documentation.FORMAT_VERSION}...`);
|
||||
const docs = new Documentation(data, options, custom);
|
||||
|
||||
if (options.output) {
|
||||
console.log(`Writing to ${options.output}...`);
|
||||
writeFileSync(options.output, JSON.stringify(docs.serialize()));
|
||||
}
|
||||
console.log('Done!');
|
||||
1
packages/docgen/src/interfaces/access.type.ts
Normal file
1
packages/docgen/src/interfaces/access.type.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type Access = 'public' | 'private' | 'protected';
|
||||
3
packages/docgen/src/interfaces/childTypes.type.ts
Normal file
3
packages/docgen/src/interfaces/childTypes.type.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import type { Constructor, Event, Member, Method } from './index.js';
|
||||
|
||||
export type ChildTypes = Constructor | Member | Method | Event;
|
||||
13
packages/docgen/src/interfaces/class.interface.ts
Normal file
13
packages/docgen/src/interfaces/class.interface.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { Access, Item, Meta, Scope } from './index.js';
|
||||
|
||||
export interface Class extends Item {
|
||||
kind: 'class';
|
||||
scope: Scope;
|
||||
implements?: string[];
|
||||
augments?: string[];
|
||||
see?: string[];
|
||||
access?: Access;
|
||||
virtual?: boolean;
|
||||
deprecated?: boolean | string;
|
||||
meta: Meta;
|
||||
}
|
||||
3
packages/docgen/src/interfaces/config.interface.ts
Normal file
3
packages/docgen/src/interfaces/config.interface.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface Config {
|
||||
root: string;
|
||||
}
|
||||
9
packages/docgen/src/interfaces/constructor.interface.ts
Normal file
9
packages/docgen/src/interfaces/constructor.interface.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { Access, Item, Param } from './index.js';
|
||||
|
||||
export interface Constructor extends Item {
|
||||
kind: 'constructor';
|
||||
memberof: string;
|
||||
see?: string[];
|
||||
access?: Access;
|
||||
params?: Param[];
|
||||
}
|
||||
12
packages/docgen/src/interfaces/customDocs.interface.ts
Normal file
12
packages/docgen/src/interfaces/customDocs.interface.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export interface CustomDocs {
|
||||
name?: string;
|
||||
files: Record<
|
||||
string,
|
||||
{
|
||||
name?: string;
|
||||
type?: string;
|
||||
content?: string;
|
||||
path?: string;
|
||||
}
|
||||
>;
|
||||
}
|
||||
11
packages/docgen/src/interfaces/event.interface.ts
Normal file
11
packages/docgen/src/interfaces/event.interface.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { Item, Meta, Param, Scope } from './index.js';
|
||||
|
||||
export interface Event extends Item {
|
||||
kind: 'event';
|
||||
scope: Scope;
|
||||
memberof: string;
|
||||
see?: string[];
|
||||
deprecated?: boolean | string;
|
||||
params?: Param[];
|
||||
meta: Meta;
|
||||
}
|
||||
7
packages/docgen/src/interfaces/exception.interface.ts
Normal file
7
packages/docgen/src/interfaces/exception.interface.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { Type } from './index.js';
|
||||
|
||||
export interface Exception {
|
||||
type: Type;
|
||||
nullable?: boolean;
|
||||
description?: string;
|
||||
}
|
||||
7
packages/docgen/src/interfaces/external.interface.ts
Normal file
7
packages/docgen/src/interfaces/external.interface.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { Item, Meta } from './index.js';
|
||||
|
||||
export interface External extends Item {
|
||||
kind: 'external';
|
||||
see?: string[];
|
||||
meta: Meta;
|
||||
}
|
||||
21
packages/docgen/src/interfaces/index.ts
Normal file
21
packages/docgen/src/interfaces/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export * from './access.type.js';
|
||||
export * from './childTypes.type';
|
||||
export * from './class.interface.js';
|
||||
export * from './config.interface.js';
|
||||
export * from './constructor.interface.js';
|
||||
export * from './customDocs.interface.js';
|
||||
export * from './event.interface.js';
|
||||
export * from './exception.interface.js';
|
||||
export * from './external.interface.js';
|
||||
export * from './interface.interface.js';
|
||||
export * from './item.interface.js';
|
||||
export * from './member.interface.js';
|
||||
export * from './meta.interface.js';
|
||||
export * from './method.interface.js';
|
||||
export * from './param.interface.js';
|
||||
export * from './return.interface.js';
|
||||
export * from './rootTypes.type.js';
|
||||
export * from './scope.type.js';
|
||||
export * from './type.interface.js';
|
||||
export * from './typedef.interface.js';
|
||||
export * from './var-type.interface';
|
||||
7
packages/docgen/src/interfaces/interface.interface.ts
Normal file
7
packages/docgen/src/interfaces/interface.interface.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { Class } from './index.js';
|
||||
|
||||
// @ts-expect-error
|
||||
export interface Interface extends Class {
|
||||
kind: 'interface';
|
||||
classdesc: string;
|
||||
}
|
||||
8
packages/docgen/src/interfaces/item.interface.ts
Normal file
8
packages/docgen/src/interfaces/item.interface.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export interface Item {
|
||||
id: string;
|
||||
longname: string;
|
||||
name: string;
|
||||
kind: string;
|
||||
description: string;
|
||||
order: number;
|
||||
}
|
||||
17
packages/docgen/src/interfaces/member.interface.ts
Normal file
17
packages/docgen/src/interfaces/member.interface.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { Access, Item, Meta, Param, Scope, Type } from './index.js';
|
||||
|
||||
export interface Member extends Item {
|
||||
kind: 'member';
|
||||
see?: string[];
|
||||
scope: Scope;
|
||||
memberof: string;
|
||||
type: Type;
|
||||
access?: Access;
|
||||
readonly?: boolean;
|
||||
nullable?: boolean;
|
||||
virtual?: boolean;
|
||||
deprecated?: boolean | string;
|
||||
default?: string;
|
||||
properties?: Param[];
|
||||
meta: Meta;
|
||||
}
|
||||
5
packages/docgen/src/interfaces/meta.interface.ts
Normal file
5
packages/docgen/src/interfaces/meta.interface.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface Meta {
|
||||
lineno: number;
|
||||
filename: string;
|
||||
path: string;
|
||||
}
|
||||
22
packages/docgen/src/interfaces/method.interface.ts
Normal file
22
packages/docgen/src/interfaces/method.interface.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import type { Access, Exception, Item, Meta, Param, Return, Scope } from './index.js';
|
||||
|
||||
export interface Method extends Item {
|
||||
kind: 'function';
|
||||
see?: string[];
|
||||
scope: Scope;
|
||||
access?: Access;
|
||||
inherits?: string;
|
||||
inherited?: boolean;
|
||||
implements?: string[];
|
||||
examples?: string[];
|
||||
virtual?: boolean;
|
||||
deprecated?: boolean | string;
|
||||
memberof?: string;
|
||||
params?: Param[];
|
||||
async?: boolean;
|
||||
generator?: boolean;
|
||||
fires?: string[];
|
||||
returns?: Return[];
|
||||
exceptions?: Exception[];
|
||||
meta: Meta;
|
||||
}
|
||||
11
packages/docgen/src/interfaces/param.interface.ts
Normal file
11
packages/docgen/src/interfaces/param.interface.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { Type } from './index.js';
|
||||
|
||||
export interface Param {
|
||||
type: Type;
|
||||
description: string;
|
||||
name: string;
|
||||
optional?: boolean;
|
||||
defaultvalue?: string;
|
||||
variable?: string;
|
||||
nullable?: boolean;
|
||||
}
|
||||
7
packages/docgen/src/interfaces/return.interface.ts
Normal file
7
packages/docgen/src/interfaces/return.interface.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { Type } from './index.js';
|
||||
|
||||
export interface Return {
|
||||
type: Type;
|
||||
nullable?: boolean;
|
||||
description?: string;
|
||||
}
|
||||
3
packages/docgen/src/interfaces/rootTypes.type.ts
Normal file
3
packages/docgen/src/interfaces/rootTypes.type.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import type { Class, External, Interface, Method, Typedef } from './index.js';
|
||||
|
||||
export type RootTypes = Class | Method | Interface | Typedef | External;
|
||||
1
packages/docgen/src/interfaces/scope.type.ts
Normal file
1
packages/docgen/src/interfaces/scope.type.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type Scope = 'global' | 'instance' | 'static';
|
||||
3
packages/docgen/src/interfaces/type.interface.ts
Normal file
3
packages/docgen/src/interfaces/type.interface.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface Type {
|
||||
names?: string[];
|
||||
}
|
||||
14
packages/docgen/src/interfaces/typedef.interface.ts
Normal file
14
packages/docgen/src/interfaces/typedef.interface.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { Access, Item, Meta, Param, Return, Scope, Type } from './index.js';
|
||||
|
||||
export interface Typedef extends Item {
|
||||
kind: 'typedef';
|
||||
scope: Scope;
|
||||
see?: string[];
|
||||
access?: Access;
|
||||
deprecated?: boolean | string;
|
||||
type: Type;
|
||||
properties?: Param[];
|
||||
params?: Param[];
|
||||
returns?: Return[];
|
||||
meta: Meta;
|
||||
}
|
||||
6
packages/docgen/src/interfaces/var-type.interface.ts
Normal file
6
packages/docgen/src/interfaces/var-type.interface.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { Type } from './index.js';
|
||||
|
||||
export interface VarType extends Type {
|
||||
description?: string;
|
||||
nullable?: boolean;
|
||||
}
|
||||
76
packages/docgen/src/types/class.ts
Normal file
76
packages/docgen/src/types/class.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { Collection } from '@discordjs/collection';
|
||||
import { DocumentedConstructor } from './constructor.js';
|
||||
import { DocumentedEvent } from './event.js';
|
||||
import { DocumentedItemMeta } from './item-meta.js';
|
||||
import { DocumentedItem } from './item.js';
|
||||
import { DocumentedMember } from './member.js';
|
||||
import { DocumentedMethod } from './method.js';
|
||||
import { DocumentedVarType } from './var-type.js';
|
||||
import type { Class, Config } from '../interfaces/index.js';
|
||||
|
||||
export class DocumentedClass extends DocumentedItem<Class> {
|
||||
public readonly props = new Collection<string, DocumentedMember>();
|
||||
|
||||
public readonly methods = new Collection<string, DocumentedMethod>();
|
||||
|
||||
public readonly events = new Collection<string, DocumentedEvent>();
|
||||
|
||||
public construct: DocumentedConstructor | null = null;
|
||||
|
||||
public extends: DocumentedVarType | null = null;
|
||||
|
||||
public implements: DocumentedVarType | null = null;
|
||||
|
||||
public constructor(data: Class, config: Config) {
|
||||
super(data, config);
|
||||
|
||||
if (data.augments) {
|
||||
this.extends = new DocumentedVarType({ names: data.augments }, this.config);
|
||||
}
|
||||
|
||||
if (data.implements) {
|
||||
this.implements = new DocumentedVarType({ names: data.implements }, this.config);
|
||||
}
|
||||
}
|
||||
|
||||
public add(item: DocumentedConstructor | DocumentedMethod | DocumentedMember | DocumentedEvent) {
|
||||
if (item instanceof DocumentedConstructor) {
|
||||
if (this.construct) throw new Error(`Doc ${this.data.name} already has constructor`);
|
||||
this.construct = item;
|
||||
} else if (item instanceof DocumentedMethod) {
|
||||
const prefix = item.data.scope === 'static' ? 's-' : '';
|
||||
if (this.methods.has(prefix + item.data.name)) {
|
||||
throw new Error(`Doc ${this.data.name} already has method ${item.data.name}`);
|
||||
}
|
||||
this.methods.set(prefix + item.data.name, item);
|
||||
} else if (item instanceof DocumentedMember) {
|
||||
if (this.props.has(item.data.name)) {
|
||||
throw new Error(`Doc ${this.data.name} already has prop ${item.data.name}`);
|
||||
}
|
||||
this.props.set(item.data.name, item);
|
||||
} else if (item instanceof DocumentedEvent) {
|
||||
if (this.events.has(item.data.name)) {
|
||||
throw new Error(`Doc ${this.data.name} already has event ${item.data.name}`);
|
||||
}
|
||||
this.events.set(item.data.name, item);
|
||||
}
|
||||
}
|
||||
|
||||
public override serializer() {
|
||||
return {
|
||||
name: this.data.name,
|
||||
description: this.data.description,
|
||||
see: this.data.see,
|
||||
extends: this.extends?.serialize(),
|
||||
implements: this.implements?.serialize(),
|
||||
access: this.data.access,
|
||||
abstract: this.data.virtual,
|
||||
deprecated: this.data.deprecated,
|
||||
construct: this.construct?.serialize(),
|
||||
props: this.props.size ? this.props.map((p) => p.serialize()) : undefined,
|
||||
methods: this.methods.size ? this.methods.map((m) => m.serialize()) : undefined,
|
||||
events: this.events.size ? this.events.map((e) => e.serialize()) : undefined,
|
||||
meta: new DocumentedItemMeta(this.data.meta, this.config).serialize(),
|
||||
};
|
||||
}
|
||||
}
|
||||
17
packages/docgen/src/types/constructor.ts
Normal file
17
packages/docgen/src/types/constructor.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { DocumentedItem } from './item.js';
|
||||
import { DocumentedParam } from './param.js';
|
||||
import type { Constructor } from '../interfaces/index.js';
|
||||
|
||||
export class DocumentedConstructor extends DocumentedItem<Constructor> {
|
||||
public override serializer() {
|
||||
return {
|
||||
name: this.data.name,
|
||||
description: this.data.description,
|
||||
see: this.data.see,
|
||||
access: this.data.access,
|
||||
params: this.data.params?.length
|
||||
? this.data.params.map((p) => new DocumentedParam(p, this.config).serialize())
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
19
packages/docgen/src/types/event.ts
Normal file
19
packages/docgen/src/types/event.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { DocumentedItemMeta } from './item-meta.js';
|
||||
import { DocumentedItem } from './item.js';
|
||||
import { DocumentedParam } from './param.js';
|
||||
import type { Event } from '../interfaces/index.js';
|
||||
|
||||
export class DocumentedEvent extends DocumentedItem<Event> {
|
||||
public override serializer() {
|
||||
return {
|
||||
name: this.data.name,
|
||||
description: this.data.description,
|
||||
see: this.data.see,
|
||||
deprecated: this.data.deprecated,
|
||||
params: this.data.params?.length
|
||||
? this.data.params.map((p) => new DocumentedParam(p, this.config).serialize())
|
||||
: undefined,
|
||||
meta: new DocumentedItemMeta(this.data.meta, this.config).serialize(),
|
||||
};
|
||||
}
|
||||
}
|
||||
14
packages/docgen/src/types/external.ts
Normal file
14
packages/docgen/src/types/external.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { DocumentedItemMeta } from './item-meta.js';
|
||||
import { DocumentedItem } from './item.js';
|
||||
import type { External } from '../interfaces/index.js';
|
||||
|
||||
export class DocumentedExternal extends DocumentedItem<External> {
|
||||
public override serializer() {
|
||||
return {
|
||||
name: this.data.name,
|
||||
description: this.data.description,
|
||||
see: this.data.see,
|
||||
meta: new DocumentedItemMeta(this.data.meta, this.config).serialize(),
|
||||
};
|
||||
}
|
||||
}
|
||||
11
packages/docgen/src/types/interface.ts
Normal file
11
packages/docgen/src/types/interface.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { DocumentedClass } from './class.js';
|
||||
import type { Interface } from '../interfaces/index.js';
|
||||
|
||||
export class DocumentedInterface extends DocumentedClass {
|
||||
public override serializer() {
|
||||
const data = this.data as unknown as Interface;
|
||||
const serialized = super.serializer();
|
||||
serialized.description = data.classdesc;
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
13
packages/docgen/src/types/item-meta.ts
Normal file
13
packages/docgen/src/types/item-meta.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { relative } from 'path';
|
||||
import { DocumentedItem } from './item.js';
|
||||
import type { Meta } from '../interfaces/index.js';
|
||||
|
||||
export class DocumentedItemMeta extends DocumentedItem<Meta> {
|
||||
public override serializer() {
|
||||
return {
|
||||
line: this.data.lineno,
|
||||
file: this.data.filename,
|
||||
path: relative(this.config.root, this.data.path).replace(/\\/g, '/'),
|
||||
};
|
||||
}
|
||||
}
|
||||
27
packages/docgen/src/types/item.ts
Normal file
27
packages/docgen/src/types/item.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import type { Config, Item } from '../interfaces/index.js';
|
||||
|
||||
export class DocumentedItem<T = Item> {
|
||||
public constructor(public readonly data: T, public readonly config: Config) {}
|
||||
|
||||
public serialize() {
|
||||
try {
|
||||
return this.serializer();
|
||||
} catch (err) {
|
||||
const error = err as Error;
|
||||
error.message = `Error while serializing ${this.detailedName()}: ${error.message}`;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
protected serializer() {
|
||||
throw new Error("Method 'serializer()' must be implemented.");
|
||||
}
|
||||
|
||||
private detailedName() {
|
||||
const data = this.data as Item | undefined;
|
||||
if (!data) return this.constructor.name;
|
||||
if (data.id) return `${data.id} (${this.constructor.name})`;
|
||||
if (data.name) return `${data.name} (${this.constructor.name})`;
|
||||
return this.constructor.name;
|
||||
}
|
||||
}
|
||||
44
packages/docgen/src/types/member.ts
Normal file
44
packages/docgen/src/types/member.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { DocumentedItemMeta } from './item-meta.js';
|
||||
import { DocumentedItem } from './item.js';
|
||||
import { DocumentedParam } from './param.js';
|
||||
import { DocumentedVarType } from './var-type.js';
|
||||
import type { Member } from '../interfaces/index.js';
|
||||
|
||||
export class DocumentedMember extends DocumentedItem<Member> {
|
||||
public override serializer() {
|
||||
return {
|
||||
name: this.data.name,
|
||||
description: this.data.description,
|
||||
see: this.data.see,
|
||||
scope: this.data.scope,
|
||||
access: this.data.access,
|
||||
readonly: this.data.readonly,
|
||||
nullable: this.data.nullable,
|
||||
abstract: this.data.virtual,
|
||||
deprecated: this.data.deprecated,
|
||||
default: this.data.default,
|
||||
type: new DocumentedVarType(this.data.type, this.config).serialize(),
|
||||
props: this.data.properties?.length
|
||||
? this.data.properties.map((p) => new DocumentedParam(p, this.config).serialize())
|
||||
: undefined,
|
||||
meta: new DocumentedItemMeta(this.data.meta, this.config).serialize(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
{ id: 'Client#rest',
|
||||
longname: 'Client#rest',
|
||||
name: 'rest',
|
||||
scope: 'instance',
|
||||
kind: 'member',
|
||||
description: 'The REST manager of the client',
|
||||
memberof: 'Client',
|
||||
type: { names: [ 'RESTManager' ] },
|
||||
access: 'private',
|
||||
meta:
|
||||
{ lineno: 32,
|
||||
filename: 'Client.js',
|
||||
path: 'src/client' },
|
||||
order: 11 }
|
||||
*/
|
||||
34
packages/docgen/src/types/method.ts
Normal file
34
packages/docgen/src/types/method.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { DocumentedItemMeta } from './item-meta.js';
|
||||
import { DocumentedItem } from './item.js';
|
||||
import { DocumentedParam } from './param.js';
|
||||
import { DocumentedVarType } from './var-type.js';
|
||||
import type { Method } from '../interfaces/index.js';
|
||||
|
||||
export class DocumentedMethod extends DocumentedItem<Method> {
|
||||
public override serializer() {
|
||||
return {
|
||||
name: this.data.name,
|
||||
description: this.data.description,
|
||||
see: this.data.see,
|
||||
scope: this.data.scope,
|
||||
access: this.data.access,
|
||||
inherits: this.data.inherits,
|
||||
inherited: this.data.inherited,
|
||||
implements: this.data.implements,
|
||||
examples: this.data.examples,
|
||||
abstract: this.data.virtual && !this.data.inherited,
|
||||
deprecated: this.data.deprecated,
|
||||
emits: this.data.fires,
|
||||
throws: this.data.exceptions,
|
||||
params: this.data.params?.length
|
||||
? this.data.params.map((p) => new DocumentedParam(p, this.config).serialize())
|
||||
: undefined,
|
||||
async: this.data.async,
|
||||
generator: this.data.generator,
|
||||
returns: this.data.returns?.length
|
||||
? this.data.returns.map((p) => new DocumentedVarType(p, this.config).serialize())
|
||||
: undefined,
|
||||
meta: new DocumentedItemMeta(this.data.meta, this.config).serialize(),
|
||||
};
|
||||
}
|
||||
}
|
||||
17
packages/docgen/src/types/param.ts
Normal file
17
packages/docgen/src/types/param.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { DocumentedItem } from './item.js';
|
||||
import { DocumentedVarType } from './var-type.js';
|
||||
import type { Param } from '../interfaces/index.js';
|
||||
|
||||
export class DocumentedParam extends DocumentedItem<Param> {
|
||||
public override serializer() {
|
||||
return {
|
||||
name: this.data.name,
|
||||
description: this.data.description,
|
||||
optional: this.data.optional,
|
||||
default: this.data.defaultvalue,
|
||||
variable: this.data.variable,
|
||||
nullable: this.data.nullable,
|
||||
type: new DocumentedVarType(this.data.type, this.config).serialize(),
|
||||
};
|
||||
}
|
||||
}
|
||||
28
packages/docgen/src/types/typedef.ts
Normal file
28
packages/docgen/src/types/typedef.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { DocumentedItemMeta } from './item-meta.js';
|
||||
import { DocumentedItem } from './item.js';
|
||||
import { DocumentedParam } from './param.js';
|
||||
import { DocumentedVarType } from './var-type.js';
|
||||
import type { Typedef } from '../interfaces/index.js';
|
||||
|
||||
export class DocumentedTypeDef extends DocumentedItem<Typedef> {
|
||||
public override serializer() {
|
||||
return {
|
||||
name: this.data.name,
|
||||
description: this.data.description,
|
||||
see: this.data.see,
|
||||
access: this.data.access,
|
||||
deprecated: this.data.deprecated,
|
||||
type: new DocumentedVarType(this.data.type, this.config).serialize(),
|
||||
props: this.data.properties?.length
|
||||
? this.data.properties.map((p) => new DocumentedParam(p, this.config).serialize())
|
||||
: undefined,
|
||||
params: this.data.params?.length
|
||||
? this.data.params.map((p) => new DocumentedParam(p, this.config).serialize())
|
||||
: undefined,
|
||||
returns: this.data.returns?.length
|
||||
? this.data.returns.map((p) => new DocumentedVarType(p, this.config).serialize())
|
||||
: undefined,
|
||||
meta: new DocumentedItemMeta(this.data.meta, this.config).serialize(),
|
||||
};
|
||||
}
|
||||
}
|
||||
34
packages/docgen/src/types/var-type.ts
Normal file
34
packages/docgen/src/types/var-type.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { DocumentedItem } from './item.js';
|
||||
import type { VarType } from '../interfaces/index.js';
|
||||
|
||||
export class DocumentedVarType extends DocumentedItem<VarType> {
|
||||
public override serializer() {
|
||||
const names = this.data.names?.map((name) => this.splitVarName(name));
|
||||
|
||||
if (!this.data.description && !this.data.nullable) {
|
||||
return names;
|
||||
}
|
||||
|
||||
return {
|
||||
types: names,
|
||||
description: this.data.description,
|
||||
nullable: this.data.nullable,
|
||||
};
|
||||
}
|
||||
|
||||
private splitVarName(str: string) {
|
||||
if (str === '*') return ['*'];
|
||||
str = str.replace(/\./g, '');
|
||||
const matches = str.match(/([\w*]+)([^\w*]+)/g);
|
||||
const output = [];
|
||||
if (matches) {
|
||||
for (const match of matches) {
|
||||
const groups = /([\w*]+)([^\w*]+)/.exec(match);
|
||||
output.push([groups![1], groups![2]]);
|
||||
}
|
||||
} else {
|
||||
output.push([str.match(/([\w*]+)/g)![0]]);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user