kompendium
Version:
Documentation generator for Stencil components
290 lines (248 loc) • 7.68 kB
text/typescript
import {
Application,
Decorator,
Reflection,
ReflectionKind,
DeclarationReflection,
TypeDocAndTSOptions,
} from 'typedoc';
import {
CommentTag,
ParameterReflection,
SignatureReflection,
} from 'typedoc/dist/lib/models';
import {
JsonDocsTag,
JsonDocsProp,
JsonDocsMethodReturn,
} from '@stencil/core/internal';
import negate from 'lodash/negate';
import {
InterfaceDescription,
AliasDescription,
EnumDescription,
EnumMember,
TypeDescription,
MethodDescription,
ParameterDescription,
ClassDescription,
} from '../types';
import { existsSync } from 'fs';
interface MethodSignature {
parameters: ParameterDescription[];
returns: JsonDocsMethodReturn;
}
export function parseFile(filename: string): TypeDescription[] {
if (!existsSync(filename)) {
// eslint-disable-next-line no-console
console.warn('typeRoot file does not exist', filename);
return [];
}
const app = new Application();
const options: Partial<TypeDocAndTSOptions> = {
readme: 'none',
ignoreCompilerErrors: true,
};
if (filename.endsWith('.d.ts')) {
options.includeDeclarations = true;
options.exclude = ['**/+(*test*|node_modules)/**'];
}
app.bootstrap(options);
const reflection = app.convert([filename]);
if (!reflection) {
// eslint-disable-next-line no-console
console.warn('Could not find any type information');
return [];
}
const data: TypeDescription[] = [];
reflection.traverse(traverseCallback(data));
return data;
}
const fns = {
[ReflectionKind.Interface]: addInterface,
[ReflectionKind.Class]: addClass,
[ReflectionKind.CallSignature]: addSignature,
[ReflectionKind.Parameter]: addParam,
[ReflectionKind.TypeAlias]: addType,
// [ReflectionKind.TypeLiteral]: addType,
[ReflectionKind.Enum]: addEnum,
[ReflectionKind.EnumMember]: addEnumMember,
};
const traverseCallback = (data: any) => (reflection: Reflection) => {
const fn = fns[reflection.kind];
if (fn) {
fn(reflection, data);
} else {
reflection.traverse(traverseCallback(data));
}
};
function addInterface(
reflection: DeclarationReflection,
data: InterfaceDescription[],
) {
if (!reflection.flags.isExported) {
return;
}
data.push({
type: 'interface',
name: reflection.name,
typeParams: getTypeParams(reflection),
docs: getDocs(reflection),
docsTags: getDocsTags(reflection),
props: reflection.children.filter(isProperty).map(getProperty),
methods: reflection.children.filter(isMethod).map(getMethod),
sources: getSources(reflection),
});
}
function addClass(reflection: DeclarationReflection, data: ClassDescription[]) {
if (!reflection.flags.isExported) {
return;
}
data.push({
type: 'class',
name: reflection.name,
typeParams: getTypeParams(reflection),
docs: getDocs(reflection),
docsTags: getDocsTags(reflection),
props: reflection.children?.filter(isProperty).map(getProperty),
methods: reflection.children?.filter(isMethod).map(getMethod),
sources: getSources(reflection),
decorators: reflection.decorators?.map(getDecorator),
});
}
function addSignature(reflection: SignatureReflection, data: MethodSignature) {
if (Array.isArray(data)) {
return;
}
data.parameters = [];
data.returns = {
type: reflection.type.toString(),
docs:
reflection.parent.parent.comment?.tags?.find(isReturns)?.text || '',
};
reflection.traverse(traverseCallback(data));
}
function addParam(reflection: ParameterReflection, data: MethodSignature) {
data.parameters.push({
name: reflection.name,
type: reflection.type.toString(),
docs:
reflection.parent.parent.parent.comment?.tags
?.filter(isParam)
.find((tag) => tag.paramName === reflection.name)
?.text.trim() || '',
default: reflection.defaultValue,
optional: reflection.flags.isOptional,
});
}
function addType(reflection: DeclarationReflection, data: AliasDescription[]) {
if (!reflection.flags.isExported) {
return;
}
data.push({
type: 'alias',
name: reflection.name,
docs: getDocs(reflection),
docsTags: getDocsTags(reflection),
alias: reflection.type.toString(),
sources: getSources(reflection),
});
}
function addEnum(reflection: DeclarationReflection, data: EnumDescription[]) {
if (!reflection.flags.isExported) {
return;
}
const members = [];
reflection.traverse(traverseCallback(members));
data.push({
type: 'enum',
name: reflection.name,
docs: getDocs(reflection),
docsTags: getDocsTags(reflection),
members: members,
sources: getSources(reflection),
});
}
function addEnumMember(reflection: DeclarationReflection, data: EnumMember[]) {
data.push({
name: reflection.name,
docs: getDocs(reflection),
docsTags: getDocsTags(reflection),
value: reflection.defaultValue,
});
}
function getDocs(reflection: Reflection): string {
return [reflection.comment?.shortText, reflection.comment?.text]
.join('\n')
.trim();
}
function getDocsTags(reflection: DeclarationReflection) {
return reflection.comment?.tags?.map(getTag) || [];
}
function getTag(tag: CommentTag): JsonDocsTag {
return {
name: tag.tagName,
text: tag.text.trim(),
};
}
function isProperty(reflection: DeclarationReflection): boolean {
return (
reflection.kind === ReflectionKind.Property &&
reflection.type.toString() !== 'function'
);
}
function isMethod(reflection: DeclarationReflection): boolean {
return (
reflection.kind === ReflectionKind.Property &&
reflection.type.toString() === 'function'
);
}
function isParam(tag: CommentTag): boolean {
return tag.tagName === 'param';
}
function isReturns(tag: CommentTag): boolean {
return tag.tagName === 'returns';
}
function getProperty(reflection: DeclarationReflection): Partial<JsonDocsProp> {
return {
name: reflection.name,
type: reflection.type.toString(),
docs: getDocs(reflection),
docsTags: getDocsTags(reflection),
default: reflection.defaultValue,
optional: reflection.flags.isOptional,
};
}
function getMethod(reflection: DeclarationReflection): MethodDescription {
const signature = getSignature(reflection);
return {
name: reflection.name,
docs: getDocs(reflection),
docsTags: reflection.comment?.tags
?.filter(negate(isParam))
.filter(negate(isReturns))
.map(getTag),
...signature,
};
}
function getSignature(reflection: Reflection): MethodSignature {
const signature: Partial<MethodSignature> = {};
reflection.traverse(traverseCallback(signature));
return signature as MethodSignature;
}
function getTypeParams(reflection: DeclarationReflection) {
return (
reflection.typeParameters?.map((param) => ({
name: param.name,
})) || []
);
}
function getSources(reflection: DeclarationReflection) {
return reflection.sources.map((source) => source.file.fullFileName);
}
function getDecorator(decorator: Decorator) {
return {
name: decorator.name,
arguments: decorator.arguments,
};
}