diff --git a/src/documentation.ts b/src/documentation.ts index 928bb0d..4650404 100644 --- a/src/documentation.ts +++ b/src/documentation.ts @@ -2,6 +2,7 @@ import path from 'path'; import type { JSONOutput } from 'typedoc'; import type { customSettings, ProjectData } from './index'; import { ClassDoc, parseClass } from './util/class'; +import { NamespaceDoc, parseNamespace } from './util/namespace'; import { TypedefDoc, parseTypedef } from './util/typedef'; import { version } from '../package.json'; @@ -26,21 +27,24 @@ interface CodeDoc { // interfaces: unknown[] // external: unknown[] typedefs: TypedefDoc[]; + namespaces: NamespaceDoc[]; } export function generateDocs(data: ProjectData): CodeDoc { - const classes = []; + const classes: ClassDoc[] = []; // interfaces = [], // not using this at the moment // externals = [], // ??? - const typedefs = []; + const typedefs: TypedefDoc[] = []; + const namespaces: NamespaceDoc[] = []; for (const c of data.children ?? []) { const { type, value } = parseRootElement(c); if (!value) continue; if (type === 'class') classes.push(value); - // if (type == 'interface') interfaces.push(value) - if (type === 'typedef') typedefs.push(value); + // if (type === 'interface') interfaces.push(value); + if (type === 'typedef') typedefs.push(value as TypedefDoc); + if (type === 'namespace') namespaces.push(value); // if (type == 'external') externals.push(value) } @@ -49,6 +53,7 @@ export function generateDocs(data: ProjectData): CodeDoc { // interfaces, // externals, typedefs, + namespaces, }; } @@ -67,6 +72,11 @@ function parseRootElement(element: DeclarationReflection) { type: 'typedef', value: parseTypedef(element), }; + case 'Namespace': + return { + type: 'namespace', + value: parseNamespace(element), + }; // Externals? @@ -91,4 +101,6 @@ export function parseMeta(element: DeclarationReflection): DocMeta | undefined { path: path.dirname(meta.fileName), }; } + + return undefined; } diff --git a/src/util/class.ts b/src/util/class.ts index 6fc224d..9c32b83 100644 --- a/src/util/class.ts +++ b/src/util/class.ts @@ -1,27 +1,31 @@ import path from 'node:path'; - import { DeclarationReflection, DocMeta, parseMeta } from '../documentation'; import { DocType, parseType, parseTypeSimple } from './types'; export interface ClassDoc { - name: string; - description?: string | undefined; - see?: string[] | undefined; - extends?: [string] | undefined; - implements?: [string] | undefined; - access?: 'private' | undefined; abstract?: boolean | undefined; - deprecated?: boolean | undefined; + access?: 'private' | undefined; construct?: ClassMethodDoc | undefined; - props?: ClassPropDoc[] | undefined; - methods?: ClassMethodDoc[] | undefined; + deprecated?: boolean | undefined; + description?: string | undefined; events?: ClassEventDoc[] | undefined; + examples?: string[] | undefined; + extendedDescription?: string | undefined; + extends?: [string] | undefined; + implements?: [string] | undefined; + isExternal?: boolean | undefined; meta?: DocMeta | undefined; + methods?: ClassMethodDoc[] | undefined; + name: string; + props?: ClassPropDoc[] | undefined; + see?: string[] | undefined; } export function parseClass(element: DeclarationReflection): ClassDoc { const extended = element.extendedTypes?.[0]; const implemented = element.implementedTypes?.[0]; + const examples = element.comment?.tags?.filter((t) => t.tag === 'example')?.map((t) => t.text.trim()); + const construct = element.children?.find((c) => c.kindString === 'Constructor'); // Ignore setter-only accessors (the typings still exist, but the docs don't show them) const props = element.children?.filter( @@ -35,9 +39,11 @@ export function parseClass(element: DeclarationReflection): ClassDoc { return { name: element.name === 'default' ? path.parse(meta?.file ?? 'default').name : element.name, description: element.comment?.shortText?.trim(), + extendedDescription: element.comment?.text?.trim(), see: element.comment?.tags?.filter((t) => t.tag === 'see').map((t) => t.text.trim()), extends: extended ? [parseTypeSimple(extended)] : undefined, implements: implemented ? [parseTypeSimple(implemented)] : undefined, + examples: examples ? examples : undefined, access: element.flags.isPrivate || element.comment?.tags?.some((t) => t.tag === 'private' || t.tag === 'internal') ? 'private' @@ -49,29 +55,32 @@ export function parseClass(element: DeclarationReflection): ClassDoc { methods: methods && methods.length > 0 ? methods.map(parseClassMethod) : undefined, events: events && events.length > 0 ? events.map(parseClassEvent) : undefined, meta, + isExternal: element.flags.isExternal, }; } interface ClassPropDoc { - name: string; - description?: string | undefined; - see?: string[] | undefined; - scope?: 'static' | undefined; - access?: 'private' | undefined; - readonly?: boolean | undefined; - nullable?: never | undefined; // it would already be in the type abstract?: boolean | undefined; - deprecated?: boolean | undefined; + access?: 'private' | undefined; default?: string | boolean | number | undefined; - type?: DocType | undefined; - props?: never | undefined; // prefer using a type reference (like a dedicated instance) instead of documenting using @property tags + deprecated?: boolean | undefined; + description?: string | undefined; + extendedDescription?: string | undefined; meta?: DocMeta | undefined; + name: string; + nullable?: never | undefined; // it would already be in the type + props?: never | undefined; // prefer using a type reference (like a dedicated instance) instead of documenting using @property tags + readonly?: boolean | undefined; + scope?: 'static' | undefined; + see?: string[] | undefined; + type?: DocType | undefined; } function parseClassProp(element: DeclarationReflection): ClassPropDoc { const base: ClassPropDoc = { name: element.name, description: element.comment?.shortText?.trim(), + extendedDescription: element.comment?.text?.trim(), see: element.comment?.tags?.filter((t) => t.tag === 'see').map((t) => t.text.trim()), scope: element.flags.isStatic ? 'static' : undefined, access: @@ -108,6 +117,7 @@ function parseClassProp(element: DeclarationReflection): ClassPropDoc { return { ...res, description: getter.comment?.shortText?.trim(), + extendedDescription: getter.comment?.text?.trim(), see: getter.comment?.tags?.filter((t) => t.tag === 'see').map((t) => t.text.trim()), access: getter.flags.isPrivate || getter.comment?.tags?.some((t) => t.tag === 'private' || t.tag === 'internal') @@ -130,19 +140,20 @@ function parseClassProp(element: DeclarationReflection): ClassPropDoc { } interface ClassMethodDoc { - name: string; - description?: string | undefined; - see?: string[] | undefined; - scope?: 'static' | undefined; - access?: 'private' | undefined; - inherits?: never | undefined; // let's just don't - inherited?: never | undefined; // let's just don't - implements?: never | undefined; // let's just don't - examples?: string[] | undefined; abstract?: boolean | undefined; + access?: 'private' | undefined; + async?: never | undefined; // it would already be in the type deprecated?: boolean | undefined; + description?: string | undefined; emits?: string[] | undefined; - throws?: never | undefined; // let's just don't + examples?: string[] | undefined; + extendDescription?: string | undefined; + generator?: never | undefined; // not used by djs + implements?: never | undefined; // let's just don't + inherited?: never | undefined; // let's just don't + inherits?: never | undefined; // let's just don't + meta?: DocMeta | undefined; + name: string; params?: | { name: string; @@ -154,11 +165,11 @@ interface ClassMethodDoc { type?: DocType | undefined; }[] | undefined; - async?: never | undefined; // it would already be in the type - generator?: never | undefined; // not used by djs returns?: DocType | undefined; returnsDescription?: string | undefined; - meta?: DocMeta | undefined; + scope?: 'static' | undefined; + see?: string[] | undefined; + throws?: never | undefined; // let's just don't } export function parseClassMethod(element: DeclarationReflection): ClassMethodDoc { @@ -167,6 +178,7 @@ export function parseClassMethod(element: DeclarationReflection): ClassMethodDoc return { name: element.name, description: signature.comment?.shortText?.trim(), + extendDescription: signature.comment?.text?.trim(), see: signature.comment?.tags?.filter((t) => t.tag === 'see').map((t) => t.text.trim()), scope: element.flags.isStatic ? 'static' : undefined, access: @@ -201,10 +213,11 @@ export function parseParam(param: DeclarationReflection): ClassMethodParamDoc { } interface ClassEventDoc { - name: string; - description?: string | undefined; - see?: string[] | undefined; deprecated?: boolean | undefined; + description?: string | undefined; + extendedDescription?: string | undefined; + meta?: DocMeta | undefined; + name: string; params?: | { name: string; @@ -216,7 +229,7 @@ interface ClassEventDoc { type?: DocType | undefined; }[] | undefined; - meta?: DocMeta | undefined; + see?: string[] | undefined; } function parseClassEvent(element: DeclarationReflection): ClassEventDoc { diff --git a/src/util/namespace.ts b/src/util/namespace.ts new file mode 100644 index 0000000..ff9963a --- /dev/null +++ b/src/util/namespace.ts @@ -0,0 +1,34 @@ +import { DocMeta, parseMeta, type DeclarationReflection } from '../documentation'; +import { parseTypedef, TypedefDoc } from './typedef'; + +export interface NamespaceDoc { + deprecated?: boolean | undefined; + description?: string | undefined; + enumerations?: TypedefDoc[] | undefined; + extendedDescription?: string | undefined; + interfaces?: TypedefDoc[] | undefined; + isExternal?: boolean | undefined; + meta?: DocMeta | undefined; + name: string; + see?: string[] | undefined; + typeAliases?: TypedefDoc[] | undefined; +} + +export function parseNamespace(element: DeclarationReflection): NamespaceDoc { + const typeAliases = element.children?.filter((c) => c.kindString === 'Type alias'); + const interfaces = element.children?.filter((c) => c.kindString === 'Interface'); + const enumerations = element.children?.filter((c) => c.kindString === 'Enumeration'); + + return { + name: element.name, + description: element.comment?.shortText?.trim(), + extendedDescription: element.comment?.text?.trim(), + see: element.comment?.tags?.filter((t) => t.tag === 'see').map((t) => t.text.trim()), + deprecated: element.comment?.tags?.some((t) => t.tag === 'deprecated'), + typeAliases: typeAliases && typeAliases.length > 0 ? typeAliases.map(parseTypedef) : undefined, + interfaces: interfaces && interfaces.length > 0 ? interfaces.map(parseTypedef) : undefined, + enumerations: enumerations && enumerations.length > 0 ? enumerations.map(parseTypedef) : undefined, + meta: parseMeta(element), + isExternal: element.flags.isExternal, + }; +} diff --git a/src/util/typedef.ts b/src/util/typedef.ts index f173067..9df80a2 100644 --- a/src/util/typedef.ts +++ b/src/util/typedef.ts @@ -3,23 +3,39 @@ import type { ClassMethodParamDoc } from './class'; import { DocType, parseType, typeUtil } from './types'; export interface TypedefDoc { - name: string; - description?: string | undefined; - see?: string[] | undefined; access?: 'private' | undefined; deprecated?: boolean | undefined; - type?: DocType | undefined; - props?: ClassMethodParamDoc[] | undefined; + description?: string | undefined; + extendedDescription?: string | undefined; + isExternal?: boolean | undefined; + meta?: DocMeta | undefined; + name: string; params?: ClassMethodParamDoc[] | undefined; + props?: ClassMethodParamDoc[] | undefined; returns?: DocType | undefined; returnsDescription?: string | undefined; - meta?: DocMeta | undefined; + see?: string[] | undefined; + type?: DocType | undefined; + variant: 'type' | 'interface' | 'enum'; +} + +function parseKindString(kindString: DeclarationReflection['kindString']): TypedefDoc['variant'] { + switch (kindString?.toLowerCase()) { + case 'interface': + return 'interface'; + case 'enumeration': + return 'enum'; + case 'type alias': + default: + return 'type'; + } } export function parseTypedef(element: DeclarationReflection): TypedefDoc { const baseReturn: TypedefDoc = { name: element.name, description: element.comment?.shortText?.trim(), + extendedDescription: element.comment?.text?.trim(), see: element.comment?.tags?.filter((t) => t.tag === 'see').map((t) => t.text.trim()), access: element.flags.isPrivate || element.comment?.tags?.some((t) => t.tag === 'private' || t.tag === 'internal') @@ -29,6 +45,8 @@ export function parseTypedef(element: DeclarationReflection): TypedefDoc { // @ts-ignore type: element.type ? parseType(element.type) : undefined, meta: parseMeta(element), + variant: parseKindString(element.kindString), + isExternal: element.flags.isExternal, }; let typeDef: DeclarationReflection | undefined; diff --git a/tsup.config.ts b/tsup.config.ts index c4b0515..910ec4c 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -5,8 +5,16 @@ export const tsup: Options = { dts: true, entryPoints: ['src/index.ts'], format: ['esm', 'cjs'], - minify: true, + minify: false, + keepNames: true, skipNodeModulesBundle: true, sourcemap: true, target: 'es2021', + esbuildOptions: (options, context) => { + if (context.format === 'cjs') { + options.banner = { + js: '"use strict";', + }; + } + }, };