Skip to content

Commit

Permalink
feat: add parse Enum type (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
mingtianyihou33 committed Apr 10, 2024
1 parent b24070a commit cefa7d2
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 21 deletions.
51 changes: 49 additions & 2 deletions src/lib/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import type {
TypeChecker,
Symbol as TypeScriptSymbol,
VariableDeclaration,
VariableStatement
VariableStatement,
EnumDeclaration,
} from 'typescript';
import {
ModifierFlags,
Expand All @@ -32,7 +33,8 @@ import {
isModuleDeclaration,
isPropertySignature,
isTypeAliasDeclaration,
isVariableStatement
isVariableStatement,
isEnumDeclaration,
} from 'typescript';
import type {BuildOptions, DocEntry, DocEntryConstructor, DocEntryType} from './types';

Expand All @@ -55,6 +57,41 @@ const serializeSymbol = ({
};
};

const serializeEnum = ({
checker,
symbol,
}: {
checker: TypeChecker;
symbol: TypeScriptSymbol;
doc_type?: DocEntryType;
}): DocEntry => {
const node = symbol.valueDeclaration as EnumDeclaration
const properties: DocEntry[] = []
node.members.forEach(member=>{
const type = member.initializer?.getText()
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
const documentation = displayPartsToString(member.symbol.getDocumentationComment(checker))
const property: DocEntry = {
name: member.name.getText(),
}
if (type){
property.type = type
}
if (documentation){
property.documentation = documentation
}
properties.push(property)
})
return {
name: symbol.getName(),
documentation: displayPartsToString(symbol.getDocumentationComment(checker)),
properties,
jsDocs: symbol.getJsDocTags(),
doc_type: 'enum',
};
};

/** Serialize a class symbol information */
const serializeClass = ({
checker,
Expand Down Expand Up @@ -299,6 +336,16 @@ const visit = ({

entries.push(typeEntry);
}
} else if (isEnumDeclaration(node)) {
const symbol = checker.getSymbolAtLocation((node as EnumDeclaration).name)!;
const details = serializeEnum({checker, symbol});
entries.push({
...details,
...buildSource({
node,
...rest
})
});
}
}

Expand Down
15 changes: 12 additions & 3 deletions src/lib/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ const toMarkdown = ({
}: {
entries: DocEntry[];
headingLevel: MarkdownHeadingLevel | '####';
docType: 'Constant' | 'Function' | 'Method' | 'Type';
docType: 'Constant' | 'Function' | 'Method' | 'Type' | 'Enum';
} & Pick<MarkdownOptions, 'emoji'>): string => {
const jsDocsToParams = (jsDocs: JSDocTagInfo[]): Params[] => {
const params: JSDocTagInfo[] = jsDocs.filter(({name}: JSDocTagInfo) => name === 'param');
Expand Down Expand Up @@ -234,6 +234,7 @@ const DEFAULT_EMOJI: MarkdownEmoji = {
classes: 'factory',
functions: 'toolbox',
constants: 'wrench',
enum: 'tropical_drink',
entry: 'gear',
link: 'link',
interfaces: 'tropical_drink',
Expand Down Expand Up @@ -267,6 +268,7 @@ export const documentationToMarkdown = ({
const functions: DocEntry[] = entries.filter(({doc_type}: DocEntry) => doc_type === 'function');
const classes: DocEntry[] = entries.filter(({doc_type}: DocEntry) => doc_type === 'class');
const constants: DocEntry[] = entries.filter(({doc_type}: DocEntry) => doc_type === 'const');
const enums: DocEntry[] = entries.filter(({doc_type}: DocEntry) => doc_type === 'enum');
const types: DocEntry[] = entries.filter(({doc_type}: DocEntry) => doc_type === 'type');
const interfaces: DocEntry[] = entries.filter(({doc_type}: DocEntry) => doc_type === 'interface');

Expand All @@ -287,11 +289,18 @@ export const documentationToMarkdown = ({
`${toMarkdown({entries: constants, headingLevel, emoji, docType: 'Constant'})}\n`
);
}

markdown.push(
classes.map((entry: DocEntry) => classesToMarkdown({entry, headingLevel, emoji})).join('\n')
);

if (enums.length) {
markdown.push(`${headingLevel}${emojiTitle({emoji, key: 'enum'})} Enum\n`);
markdown.push(`${tableOfContent({entries: enums, emoji})}\n`);
markdown.push(
enums
.map((entry: DocEntry) => interfacesToMarkdown({entry, headingLevel, emoji}))
.join('\n')
);
}
if (interfaces.length) {
markdown.push(`${headingLevel}${emojiTitle({emoji, key: 'interfaces'})} Interfaces\n`);
markdown.push(`${tableOfContent({entries: interfaces, emoji})}\n`);
Expand Down
3 changes: 2 additions & 1 deletion src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type {CompilerOptions, JSDocTagInfo} from 'typescript';

export type DocEntryType = 'function' | 'method' | 'class' | 'const' | 'interface' | 'type';
export type DocEntryType = 'function' | 'method' | 'class' | 'const' | 'interface' | 'type' | 'enum';

export type DocEntryConstructor = Pick<DocEntry, 'parameters' | 'returnType' | 'documentation'> & {
visibility: 'private' | 'public';
Expand Down Expand Up @@ -29,6 +29,7 @@ export interface MarkdownEmoji {
classes: string;
functions: string;
constants: string;
enum: string;
// A function, method or constant title - i.e. an entry of one above titles
entry: string;
link: string;
Expand Down
2 changes: 0 additions & 2 deletions src/test/markdown.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ describe('markdown', () => {
types: true
}
});

const markdown: string = documentationToMarkdown({
entries: doc
});

const expectedDoc = readFileSync('./src/test/mock.md', 'utf8').replace(/\r\n/g, '\n');

expect(markdown).toEqual(expectedDoc);
Expand Down
138 changes: 125 additions & 13 deletions src/test/mock.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
{
"name": "param",
"text": [
{"kind": "parameterName", "text": "yolo"},
{
"kind": "parameterName",
"text": "yolo"
},
{
"kind": "space",
"text": " "
Expand Down Expand Up @@ -57,7 +60,10 @@
{
"name": "param",
"text": [
{"kind": "parameterName", "text": "agent"},
{
"kind": "parameterName",
"text": "agent"
},
{
"kind": "space",
"text": " "
Expand All @@ -74,13 +80,33 @@
},
{
"documentation": "",
"jsDocs": [{"name": "param", "text": [{"kind": "text", "text": "canisterId"}]}],
"jsDocs": [
{
"name": "param",
"text": [
{
"kind": "text",
"text": "canisterId"
}
]
}
],
"name": "canisterId",
"type": "{ canisterId: string; }"
},
{
"documentation": "",
"jsDocs": [{"name": "param", "text": [{"kind": "text", "text": "hardwareWallet"}]}],
"jsDocs": [
{
"name": "param",
"text": [
{
"kind": "text",
"text": "hardwareWallet"
}
]
}
],
"name": "hardwareWallet",
"type": "boolean"
}
Expand All @@ -97,22 +123,52 @@
{
"doc_type": "method",
"documentation": "Create a LedgerCanister",
"jsDocs": [{"name": "param", "text": [{"kind": "text", "text": "params"}]}],
"jsDocs": [
{
"name": "param",
"text": [
{
"kind": "text",
"text": "params"
}
]
}
],
"name": "create",
"type": "(options: { canisterId?: string | undefined; }) => LedgerCanister"
},
{
"doc_type": "function",
"documentation": "Returns the balance of the specified account identifier.",
"jsDocs": [
{"name": "param", "text": [{"kind": "text", "text": "params"}]},
{
"name": "param",
"text": [
{
"kind": "text",
"text": "params"
}
]
},
{
"name": "throws",
"text": [
{"kind": "text", "text": "an "},
{"kind": "link", "text": "{@link "},
{"kind": "linkText", "text": "Error "},
{"kind": "link", "text": "}"}
{
"kind": "text",
"text": "an "
},
{
"kind": "link",
"text": "{@link "
},
{
"kind": "linkText",
"text": "Error "
},
{
"kind": "link",
"text": "}"
}
]
}
],
Expand Down Expand Up @@ -190,14 +246,34 @@
"jsDocs": [],
"doc_type": "interface",
"properties": [
{"name": "hello", "documentation": "Says hello.", "type": "string", "jsDocs": []},
{
"name": "hello",
"documentation": "Says hello.",
"type": "string",
"jsDocs": []
},
{
"name": "world",
"documentation": "Something",
"type": "string | undefined",
"jsDocs": [{"name": "default", "text": [{"text": "`hello`", "kind": "text"}]}]
"jsDocs": [
{
"name": "default",
"text": [
{
"text": "`hello`",
"kind": "text"
}
]
}
]
},
{"name": "abc", "documentation": "", "type": "Abc", "jsDocs": []}
{
"name": "abc",
"documentation": "",
"type": "Abc",
"jsDocs": []
}
],
"fileName": "src/test/mock.ts"
},
Expand All @@ -216,5 +292,41 @@
"jsDocs": [],
"doc_type": "type",
"fileName": "src/test/mock.ts"
},
{
"name": "Time",
"documentation": "",
"properties": [
{
"name": "SECOND",
"type": "1000"
},
{
"name": "MINUTE",
"type": "60 * SECOND"
}
],
"jsDocs": [],
"doc_type": "enum",
"fileName": "src/test/mock.ts"
},
{
"name": "MemberType",
"documentation": "",
"properties": [
{
"name": "T1"
},
{
"name": "T2",
"documentation": "comment"
},
{
"name": "T3"
}
],
"jsDocs": [],
"doc_type": "enum",
"fileName": "src/test/mock.ts"
}
]
26 changes: 26 additions & 0 deletions src/test/mock.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,32 @@ Description
[:link: Source](https://github.com/peterpeterparker/tsdoc-markdown/tree/main/src/test/mock.ts#L118)


## :tropical_drink: Enum

- [Time](#gear-time)
- [MemberType](#gear-membertype)

### :gear: Time



| Property | Type | Description |
| ---------- | ---------- | ---------- |
| `SECOND` | `1000` | |
| `MINUTE` | `60 * SECOND` | |


### :gear: MemberType



| Property | Type | Description |
| ---------- | ---------- | ---------- |
| `T1` | `` | |
| `T2` | `` | comment |
| `T3` | `` | |


## :tropical_drink: Interfaces

- [Foo](#gear-foo)
Expand Down
Loading

0 comments on commit cefa7d2

Please sign in to comment.