Skip to content

Commit 4acb43e

Browse files
committed
chore: wip
1 parent a3fba2a commit 4acb43e

File tree

7 files changed

+186
-11
lines changed

7 files changed

+186
-11
lines changed

packages/dtsx/src/extractor/builders.ts

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ export function buildClassDeclaration(node: ClassDeclaration, isExported: boolea
277277

278278
/**
279279
* Helper to build member modifiers string efficiently
280+
* TypeScript modifier order: private/protected/public, static, abstract, readonly
280281
*/
281282
function buildMemberModifiers(
282283
isStatic: boolean,
@@ -286,16 +287,20 @@ function buildMemberModifiers(
286287
isProtected: boolean,
287288
): string {
288289
const parts: string[] = [' ']
290+
// Access modifiers come first
291+
if (isPrivate)
292+
parts.push('private ')
293+
else if (isProtected)
294+
parts.push('protected ')
295+
// Then static
289296
if (isStatic)
290297
parts.push('static ')
298+
// Then abstract
291299
if (isAbstract)
292300
parts.push('abstract ')
301+
// Then readonly
293302
if (isReadonly)
294303
parts.push('readonly ')
295-
if (isPrivate)
296-
parts.push('private ')
297-
else if (isProtected)
298-
parts.push('protected ')
299304
return parts.join('')
300305
}
301306

@@ -346,6 +351,12 @@ export function buildClassBody(node: ClassDeclaration): string {
346351
// First, add property declarations for parameter properties
347352
for (const param of member.parameters) {
348353
if (param.modifiers && param.modifiers.length > 0) {
354+
// Skip private parameter properties - they're not part of the public API
355+
const isPrivateParam = param.modifiers.some(mod => mod.kind === SyntaxKind.PrivateKeyword)
356+
if (isPrivateParam) {
357+
continue
358+
}
359+
349360
// This is a parameter property, add it as a separate property declaration
350361
const name = getParameterName(param)
351362
const type = param.type?.getText() || 'any'
@@ -372,14 +383,20 @@ export function buildClassBody(node: ClassDeclaration): string {
372383
continue
373384
}
374385

386+
// Skip private keyword methods - they're not part of the public API
387+
const isPrivateMethod = member.modifiers?.some(mod => mod.kind === SyntaxKind.PrivateKeyword)
388+
if (isPrivateMethod) {
389+
continue
390+
}
391+
375392
// Method signature without implementation
376393
const name = getMemberNameText(member)
377394
const isGenerator = !!member.asteriskToken
378395
const mods = buildMemberModifiers(
379396
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.StaticKeyword),
380397
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.AbstractKeyword),
381398
false,
382-
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.PrivateKeyword),
399+
false, // Already filtered out private
383400
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.ProtectedKeyword),
384401
)
385402

@@ -434,13 +451,19 @@ export function buildClassBody(node: ClassDeclaration): string {
434451
continue
435452
}
436453

454+
// Skip private keyword properties - they're not part of the public API
455+
const isPrivateProperty = member.modifiers?.some(mod => mod.kind === SyntaxKind.PrivateKeyword)
456+
if (isPrivateProperty) {
457+
continue
458+
}
459+
437460
// Property declaration
438461
const name = getMemberNameText(member)
439462
const mods = buildMemberModifiers(
440463
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.StaticKeyword),
441464
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.AbstractKeyword),
442465
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.ReadonlyKeyword),
443-
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.PrivateKeyword),
466+
false, // Already filtered out private
444467
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.ProtectedKeyword),
445468
)
446469

@@ -455,13 +478,19 @@ export function buildClassBody(node: ClassDeclaration): string {
455478
continue
456479
}
457480

481+
// Skip private keyword accessors - they're not part of the public API
482+
const isPrivateAccessor = member.modifiers?.some(mod => mod.kind === SyntaxKind.PrivateKeyword)
483+
if (isPrivateAccessor) {
484+
continue
485+
}
486+
458487
// Get accessor declaration
459488
const name = getMemberNameText(member)
460489
const mods = buildMemberModifiers(
461490
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.StaticKeyword),
462491
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.AbstractKeyword),
463492
false,
464-
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.PrivateKeyword),
493+
false, // Already filtered out private
465494
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.ProtectedKeyword),
466495
)
467496

@@ -474,13 +503,19 @@ export function buildClassBody(node: ClassDeclaration): string {
474503
continue
475504
}
476505

506+
// Skip private keyword accessors - they're not part of the public API
507+
const isPrivateAccessor = member.modifiers?.some(mod => mod.kind === SyntaxKind.PrivateKeyword)
508+
if (isPrivateAccessor) {
509+
continue
510+
}
511+
477512
// Set accessor declaration
478513
const name = getMemberNameText(member)
479514
const mods = buildMemberModifiers(
480515
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.StaticKeyword),
481516
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.AbstractKeyword),
482517
false,
483-
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.PrivateKeyword),
518+
false, // Already filtered out private
484519
!!member.modifiers?.some(mod => mod.kind === SyntaxKind.ProtectedKeyword),
485520
)
486521

packages/dtsx/test/dts.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ describe('dts-generation', () => {
3939
'interface',
4040
'module',
4141
'namespace',
42+
'private-members',
4243
'type',
4344
'type-interface-imports',
4445
'variable',
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* Test fixture for private member handling in class declarations
3+
* Private members should be excluded from .d.ts output
4+
* Modifier order should be: private/protected, static, abstract, readonly
5+
*/
6+
7+
// Class with private static members - should be excluded from d.ts
8+
export class CacheManager {
9+
private static cache: Map<string, unknown> = new Map()
10+
private static loading: Map<string, Promise<unknown>> = new Map()
11+
12+
static readonly MAX_SIZE = 1000
13+
14+
static get(key: string): unknown {
15+
return this.cache.get(key)
16+
}
17+
18+
static set(key: string, value: unknown): void {
19+
this.cache.set(key, value)
20+
}
21+
22+
private static cleanup(): void {
23+
this.cache.clear()
24+
}
25+
26+
static clear(): void {
27+
this.cleanup()
28+
this.loading.clear()
29+
}
30+
}
31+
32+
// Class with mixed visibility modifiers
33+
export class MixedVisibility {
34+
private privateField: string = 'private'
35+
protected protectedField: string = 'protected'
36+
public publicField: string = 'public'
37+
readonly readonlyField: string = 'readonly'
38+
39+
private static privateStaticField: number = 0
40+
protected static protectedStaticField: number = 0
41+
public static publicStaticField: number = 0
42+
static readonly staticReadonlyField: number = 0
43+
44+
private privateMethod(): void {}
45+
protected protectedMethod(): void {}
46+
public publicMethod(): void {}
47+
48+
private static privateStaticMethod(): void {}
49+
protected static protectedStaticMethod(): void {}
50+
public static publicStaticMethod(): void {}
51+
}
52+
53+
// Class with private accessors
54+
export class PrivateAccessors {
55+
private _value: number = 0
56+
57+
private get privateGetter(): number {
58+
return this._value
59+
}
60+
61+
private set privateSetter(val: number) {
62+
this._value = val
63+
}
64+
65+
protected get protectedGetter(): number {
66+
return this._value
67+
}
68+
69+
protected set protectedSetter(val: number) {
70+
this._value = val
71+
}
72+
73+
public get publicGetter(): number {
74+
return this._value
75+
}
76+
77+
public set publicSetter(val: number) {
78+
this._value = val
79+
}
80+
}
81+
82+
// Class with private constructor parameter properties
83+
export class ParameterProperties {
84+
constructor(
85+
private privateParam: string,
86+
protected protectedParam: string,
87+
public publicParam: string,
88+
readonly readonlyParam: string
89+
) {}
90+
}
91+
92+
// Abstract class with private members
93+
export abstract class AbstractWithPrivate {
94+
private privateField: string = ''
95+
protected abstract protectedAbstractMethod(): void
96+
private privateMethod(): void {}
97+
abstract publicAbstractMethod(): void
98+
}

packages/dtsx/test/fixtures/output/checker.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ declare class SymbolTrackerImpl implements SymbolTracker {
5656
reportTruncationError(): void;
5757
reportNonlocalAugmentation(containingFile: SourceFile, parentSymbol: Symbol, augmentingSymbol: Symbol): void;
5858
reportNonSerializableProperty(propertyName: string): void;
59-
private onDiagnosticReported(): void;
6059
reportInferenceFallback(node: Node): void;
6160
}
6261
declare const enum ReferenceHint {

packages/dtsx/test/fixtures/output/class.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ export declare class CustomErrorWithMethodAndType extends CustomError {
1111
getError(): Error;
1212
}
1313
export declare class CustomErrorWithMethodAndTypeAndReturn {
14-
private message: string;
1514
public readonly code: number;
1615
public readonly metadata: Record<string, unknown>;
1716
constructor(message: string, code: number, metadata: Record<string, unknown>);

packages/dtsx/test/fixtures/output/example/0012.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
7272
* ```
7373
*/
7474
export declare class Logger {
75-
private name: string;
7675
constructor(name: string);
7776
info(message: string, data?: any): void;
7877
error(message: string, error?: Error): void;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Test fixture for private member handling in class declarations
3+
* Private members should be excluded from .d.ts output
4+
* Modifier order should be: private/protected, static, abstract, readonly
5+
*/
6+
// Class with private static members - should be excluded from d.ts
7+
export declare class CacheManager {
8+
static readonly MAX_SIZE: any;
9+
static get(key: string): unknown;
10+
static set(key: string, value: unknown): void;
11+
static clear(): void;
12+
}
13+
// Class with mixed visibility modifiers
14+
export declare class MixedVisibility {
15+
protected protectedField: string;
16+
publicField: string;
17+
readonly readonlyField: string;
18+
protected static protectedStaticField: number;
19+
static publicStaticField: number;
20+
static readonly staticReadonlyField: number;
21+
protected protectedMethod(): void;
22+
publicMethod(): void;
23+
protected static protectedStaticMethod(): void;
24+
static publicStaticMethod(): void;
25+
}
26+
// Class with private accessors
27+
export declare class PrivateAccessors {
28+
protected get protectedGetter(): number;
29+
protected set protectedSetter(val: number);
30+
get publicGetter(): number;
31+
set publicSetter(val: number);
32+
}
33+
// Class with private constructor parameter properties
34+
export declare class ParameterProperties {
35+
protected protectedParam: string;
36+
public publicParam: string;
37+
readonly readonlyParam: string;
38+
constructor(privateParam: string, protectedParam: string, publicParam: string, readonlyParam: string);
39+
}
40+
// Abstract class with private members
41+
export declare abstract class AbstractWithPrivate {
42+
protected abstract protectedAbstractMethod(): void;
43+
abstract publicAbstractMethod(): void;
44+
}

0 commit comments

Comments
 (0)