Skip to content

Commit fd9615e

Browse files
committed
feat: 🎸 add JSDoc parsing for classes and methods
1 parent 8d08a90 commit fd9615e

13 files changed

Lines changed: 154 additions & 7 deletions

src/parser/component/component.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ export interface NgParselComponent extends NgParselOutput {
1414
template: string;
1515
styles: string | string[];
1616
methodsPublicExplicit: NgParselMethod[];
17+
classJsDoc?: string | undefined;
1718
}

src/parser/component/component.parser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { tsquery } from '@phenomnomnominal/tsquery';
66
import { parseInputsAndOutputs } from '../shared/parser/field-decorator.parser.js';
77
import { parseExplicitPublicMethods } from '../shared/parser/method.parser.js';
88
import { NgParselOutputType } from '../shared/model/types.model.js';
9-
import { parseClassName } from '../shared/parser/class.parser.js';
9+
import { parseClassName, parseClassJsDoc } from '../shared/parser/class.parser.js';
1010

1111
import { NgParselComponent } from './component.model.js';
1212
import { getDecoratorProperties } from '../shared/parser/decorator.parser.js';
@@ -39,6 +39,7 @@ export function parseComponent(ast: ts.SourceFile, componentFilePath: string): N
3939
inputs: inputsAndOutputs.inputs,
4040
outputs: inputsAndOutputs.outputs,
4141
methodsPublicExplicit: parseExplicitPublicMethods(ast),
42+
classJsDoc: parseClassJsDoc(ast),
4243
};
4344
}
4445

src/parser/directive/directive.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ export interface NgParselDirective extends NgParselOutput {
1010
inputs: NgParselFieldDecorator[];
1111
outputs: NgParselFieldDecorator[];
1212
methodsPublicExplicit: NgParselMethod[];
13+
classJsDoc?: string | undefined;
1314
}

src/parser/directive/directive.parser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { readFileSync } from 'fs';
22
import * as ts from 'typescript';
33

4-
import { parseClassName } from '../shared/parser/class.parser.js';
4+
import { parseClassName, parseClassJsDoc } from '../shared/parser/class.parser.js';
55
import { NgParselOutputType } from '../shared/model/types.model.js';
66
import { getDecoratorProperties } from '../shared/parser/decorator.parser.js';
77
import { parseInputsAndOutputs } from '../shared/parser/field-decorator.parser.js';
@@ -26,5 +26,6 @@ export function parseDirective(ast: ts.SourceFile, directiveFilePath: string): N
2626
inputs: inputsAndOutputs.inputs,
2727
outputs: inputsAndOutputs.outputs,
2828
methodsPublicExplicit: parseExplicitPublicMethods(ast),
29+
classJsDoc: parseClassJsDoc(ast),
2930
};
3031
}

src/parser/pipe/pipe.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ export interface NgParselPipe extends NgParselOutput {
66
pure: boolean;
77
standalone: boolean;
88
implementation: string;
9+
classJsDoc?: string | undefined;
910
}

src/parser/pipe/pipe.parser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as ts from 'typescript';
22
import { readFileSync } from 'fs';
33

4-
import { parseClassName } from '../shared/parser/class.parser.js';
4+
import { parseClassName, parseClassJsDoc } from '../shared/parser/class.parser.js';
55
import { NgParselOutputType } from '../shared/model/types.model.js';
66
import { getDecoratorProperties } from '../shared/parser/decorator.parser.js';
77

@@ -19,5 +19,6 @@ export function parsePipe(ast: ts.SourceFile, pipeFilePath: string): NgParselPip
1919
pure: pipeDecorators.pure || true,
2020
standalone: pipeDecorators.standalone || false,
2121
implementation: pipeImplementation,
22+
classJsDoc: parseClassJsDoc(ast),
2223
};
2324
}

src/parser/services/service.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ import { NgParselField } from '../shared/model/field.model.js';
55
export interface NgParselService extends NgParselOutput {
66
fieldsPublicExplicit: NgParselField[];
77
methodsPublicExplicit: NgParselMethod[];
8+
classJsDoc?: string | undefined;
89
}

src/parser/services/service.parser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as ts from 'typescript';
22

33
import { NgParselOutputType } from '../shared/model/types.model.js';
4-
import { parseClassName } from '../shared/parser/class.parser.js';
4+
import { parseClassName, parseClassJsDoc } from '../shared/parser/class.parser.js';
55
import { parseExplicitPublicMethods } from '../shared/parser/method.parser.js';
66

77
import { NgParselService } from './service.model.js';
@@ -14,5 +14,6 @@ export function parseService(ast: ts.SourceFile, filePath: string): NgParselServ
1414
filePath,
1515
fieldsPublicExplicit: parseExplicitPublicFields(ast),
1616
methodsPublicExplicit: parseExplicitPublicMethods(ast),
17+
classJsDoc: parseClassJsDoc(ast),
1718
};
1819
}

src/parser/shared/model/method.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export interface NgParselMethod {
44
name: string;
55
args: NgParselArgs[];
66
returnType: string;
7+
jsDoc?: string | undefined;
78
}
Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { tsquery } from '@phenomnomnominal/tsquery';
22

3-
import { parseClassName } from './class.parser.js';
3+
import { parseClassName, parseClassJsDoc } from './class.parser.js';
44

55
describe('ClassParser', () => {
66
it('should extract the class name', () => {
@@ -9,4 +9,51 @@ describe('ClassParser', () => {
99
`);
1010
expect(parseClassName(ast)).toEqual('MyTestClass');
1111
});
12+
13+
it('should return undefined for class JSDoc when no JSDoc exists', () => {
14+
const ast = tsquery.ast(`
15+
export class MyTestClass {
16+
public myExplicitMethod(foo: string, bar: boolean): string {
17+
}
18+
}
19+
`);
20+
21+
expect(parseClassJsDoc(ast)).toBeUndefined();
22+
});
23+
24+
it('should parse JSDoc comments for class declarations', () => {
25+
const ast = tsquery.ast(`
26+
/**
27+
* This is a JSDoc comment for MyTestClass
28+
* @description A test class
29+
* @example
30+
* const myClass = new MyTestClass();
31+
*/
32+
export class MyTestClass {
33+
public myExplicitMethod(foo: string, bar: boolean): string {
34+
return 'test';
35+
}
36+
}
37+
`);
38+
39+
expect(parseClassJsDoc(ast)).toEqual('This is a JSDoc comment for MyTestClass\n@description A test class\n@example const myClass = new MyTestClass();');
40+
});
41+
42+
it('should parse JSDoc comments with multiple tags', () => {
43+
const ast = tsquery.ast(`
44+
/**
45+
* This is a JSDoc comment for MyTestClass
46+
* @description A test class
47+
* @deprecated Use NewTestClass instead
48+
* @since 1.0.0
49+
*/
50+
export class MyTestClass {
51+
public myExplicitMethod(foo: string, bar: boolean): string {
52+
return 'test';
53+
}
54+
}
55+
`);
56+
57+
expect(parseClassJsDoc(ast)).toEqual('This is a JSDoc comment for MyTestClass\n@description A test class\n@deprecated Use NewTestClass instead\n@since 1.0.0');
58+
});
1259
});

0 commit comments

Comments
 (0)