Documentation Abstract Syntax Tree.
docast is a specification for representing comments as abstract syntax trees.
It implements the unist spec.
This document defines a format for representing comments as abstract syntax trees. Development of docast started in October 2022. This specification is written in a TypeScript-like grammar.
docast extends unist, a format for syntax trees, to benefit from its ecosystem of utilities. It also integrates with mdast, a specification for representing markdown.
docast relates to JavaScript and TypeScript in that both languages support docblock comments. docast is language-agnostic, however, and can be used with any source language that supports comments.
docast relates to JSDoc, TSDoc, and typedoc in that these tools parse docblock comments.
These tools also define or recognize sets of tags with established semantics. If developers already have a set of tags
they're using, they must spend additional time configuring those tags for their chosen tool.
docast, however, does not enforce any tag semantics — the user does.
Tag specifications can be left to an ESLint rule, or a setting akin to jsdoc/check-tag-names
or jsdoc.structuredTags.
TypeScript users can integrate docast type definitions into their project by installing the appropriate packages:
yarn add @flex-development/docastinterface Node extends unist.Node {}Node (unist.Node) is a syntactic unit in docast syntax trees.
interface Literal extends Node {
value: bigint | boolean | number | string | null | undefined
}Literal is an abstract interface in docast containing a scalar value.
interface Parent extends unist.Parent {
children: Child[]
}Parent (unist.Parent) is an abstract interface in docast containing other nodes (said to be children).
Its content is limited to docast content and mdast content.
interface CodeSegment extends Parent {
children: [CodeSegment | Comment, ...(CodeSegment | Comment)[]]
data?: CodeSegmentData | undefined
name?: CodeSegmentName extends never ? string : CodeSegmentName | undefined
type: 'codeSegment'
}CodeSegment (Parent) is an abstract representation of a source language AST (or CST) node that a
Comment documents.
type CodeSegmentName = CodeSegmentNameMap[keyof CodeSegmentNameMap]Union of registered source language AST or CST node types.
When developing source language parsers compatible with docast,
the CodeSegmentNameMap should be augmented (and exported! 😉) to register custom node types:
declare module '@flex-development/docast' {
interface CodeSegmentNameMap {
arrayType: ArrayType['type']
assertionPredicate: AssertionPredicate['type']
bigint: BigIntLiteral['type']
boolean: BooleanLiteral['type']
conditionalType: ConditionalType['type']
constructorType: ConstructorType['type']
functionType: FunctionType['type']
genericType: GenericType['type']
identifier: Identifier['type']
inferType: InferType['type']
intersectionType: IntersectionType['type']
nonNullableType: NonNullableType['type']
null: NullLiteral['type']
nullableType: NullableType['type']
number: NumberLiteral['type']
objectLiteralType: ObjectLiteralType['type']
optionalType: OptionalType['type']
parenthesizedType: ParenthesizedType['type']
propertyAccessType: PropertyAccessType['type']
string: StringLiteral['type']
super: Super['type']
templateLiteral: TemplateLiteral['type']
this: This['type']
tupleType: TupleType['type']
typeOperation: TypeOperation['type']
typePredicate: TypePredicate['type']
typeSymbol: TypeSymbol['type']
undefined: UndefinedLiteral['type']
unionType: UnionType['type']
variadicType: VariadicType['type']
}
}interface Comment extends Parent {
children:
| FreeformCommentContent[]
| [summary: Summary, ...FreeformCommentContent[]]
data?: CommentData | undefined
type: 'comment'
}Comment (Parent) represents a comment in source content.
Comment can be used in root nodes.
Its content model is comment content.
interface Identifier extends Literal {
data?: IdentifierData | undefined
type: 'identifier'
value: string
}Identifier (Literal) represents an identifier.
It cannot contain any children — it is a leaf.
Identifier can be used in tag name and namepath nodes.
interface InlineTag extends Parent {
children: [name: TagName, ...InlineTagContent[]]
data?: InlineTagData | undefined
name: string
type: 'inlineTag'
}InlineTag (Parent) represents inline metadata.
Inline tags are denoted by wrapping a TagName and any tag content
in curly braces ({ and }).
InlineTag can be used in comment, summary and tag nodes.
interface Namepath extends Parent {
children: [identifier: Identifier, ...(Identifier | NamepathConnector)[]]
data?: NamepathData | undefined
type: 'namepath'
}Namepath (Parent) represents a source language namepath.
A namepath consists of one or more identifier nodes separated by namepath connectors.
Namepath can be used in tag nodes.
interface NamepathConnector extends Literal {
data?: NamepathConnectorData | undefined
type: 'namepathConnector'
value: SerializedNamepathConnector
}NamepathConnector (Literal) represents a connector between identifier nodes in a namepath.
It cannot contain any children — it is a leaf.
type SerializedNamepathConnector = '#' | '.' | '~'The serialized form of a namepath connector.
Its value is one of #, ., or ~.
interface Root extends Parent {
children: RootContent[]
data?: RootData | undefined
type: 'root'
}Root (Parent) represents a documentation fragment or an entire documented file.
A documented file, also known as a documentation root, is any source file containing comments.
In docast, all comments are considered documentation, with info comments being comments identified as documentation
by the surrounding source language.
Parser extensions and other tools can be used to differentiate between info comments and their counterpart,
petty comments.
Root can be used as the root of a tree, never as a child.
It can contain code segment and comment nodes.
interface Summary extends Parent {
children: SummaryContent[]
data?: SummaryData | undefined
type: 'summary'
}Summary (Parent) represents text at the beginning of a comment.
It starts and ends before any other comment syntax, and may contain markdown content.
Summary can be used in comment nodes.
Its content model is summary.
interface Tag extends Parent {
children:
| [name: TagName, ...UntypedTagContent[]]
| [name: TagName, Namepath | TypeMetadata, ...UntypedTagContent[]]
| [name: TagName, type: TypeMetadata, namepath: Namepath, ...UntypedTagContent[]]
data?: TagData | undefined
type: 'tag'
}Tag (Parent) represents top-level metadata.
Tags should be the only element on their line, except in cases where special meaning is assigned to succeeding text. All text following the tag name, up until the start of the next tag name or a comment closer, is considered to be tag content.
Tag can be used in comment nodes. Its content model is tag content.
interface TagName extends Parent {
children: [identifier: Identifier]
data?: TagNameData | undefined
type: 'tagName'
}TagName (Parent) represents a tag name.
A tag name consists of an at-sign (@) followed by an identifier.
TagName can be used in tag and inline tag nodes.
type SerializedTagName<Identifier extends string = string> = `@${Identifier}`The serialized form of a tag name.
interface TypeMetadata extends Parent {
children: [expression: TypeExpression]
data?: TypeMetadataData | undefined
raw: string
type: 'typeMetadata'
}TypeMetadata (Parent) represents an inline type expression (e.g. {number}).
A raw field must be present.
Its value is the raw type expression (e.g. number).
TypeMetadata can be used in tag nodes.
Its content model is type expression.
type Content =
| CommentContent
| InlineTagContent
| PhrasingContent
| RootContent
| SummaryContent
| TagContent
| TypeExpressionNodes are grouped by content type, if applicable.
Each node in docast falls into one or more categories of Content.
type CommentContent = Summary | SummaryContent | TagComment content represents content that can occur in a comment.
type FreeformCommentContent = Exclude<CommentContent, Summary>FreeformComment content represents content that can occur in a comment without a summary.
type InlineTagContent = Exclude<PhrasingContent, InlineTag> | IdentifierInlineTag content represents content that can occur inside an inline tag.
It consists of phrasing content and identifier nodes, but cannot contain nested inline tags.
type PhrasingContent = InlineTag | mdast.PhrasingContentPhrasing content represents inline text and markup.
type RootContent = CodeSegment | CommentRoot content represents content that can occur in at the root of a tree.
It consists of code segment and comment nodes.
type SummaryContent = PhrasingContent | mdast.RootContentSummary content represents summary text and its markup.
type TagContent = PhrasingContent | TypeMetadataTag content represents tag text and its markup.
type UntypedTagContent = Exclude<TagContent, TypeMetadata>UntypedTag content represents tag content that does not contain type metadata.
type TypeExpression = TypeExpressionMap[keyof TypeExpressionMap]TypeExpression content is a type expression.
When developing type expression parsers compatible with docast,
the TypeExpressionMap should be augmented (and exported! 😉) to register custom nodes:
declare module '@flex-development/docast' {
interface TypeExpressionMap {
arrayType: ArrayType
assertionPredicate: AssertionPredicate
bigint: BigIntLiteral
boolean: BooleanLiteral
conditionalType: ConditionalType
constructorType: ConstructorType
functionType: FunctionType
genericType: GenericType
identifier: Identifier
inferType: InferType
intersectionType: IntersectionType
nonNullableType: NonNullableType
null: NullLiteral
nullableType: NullableType
number: NumberLiteral
objectLiteralType: ObjectLiteralType
optionalType: OptionalType
parenthesizedType: ParenthesizedType
propertyAccessType: PropertyAccessType
string: StringLiteral
super: Super
templateLiteral: TemplateLiteral
this: This
tupleType: TupleType
typeOperation: TypeOperation
typePredicate: TypePredicate
typeSymbol: TypeSymbol
undefined: UndefinedLiteral
unionType: UnionType
variadicType: VariadicType
}
}See the unist glossary for more terms.
A region of source content used to provide additional information.
Text following a tag name (e.g. @example, @param) up until the start of the next tag or
comment closer, or text following an inline tag name up until the closing punctuator (}).
See the unist list of utilities for more utilities.
docast-util-from-comments— parse comments
docast adheres to semver.
See CONTRIBUTING.md.
Ideas for new utilities and tools can be posted in docast/ideas.
This project has a code of conduct.
By interacting with this repository, organization, or community you agree to abide by its terms.
Small primitives power larger systems. Support long-term stability by sponsoring Flex Development.