Skip to content

Commit d58bfa2

Browse files
committed
Emit typed memberFields instead of memberKeys
1 parent 823deb9 commit d58bfa2

13 files changed

Lines changed: 696 additions & 157 deletions

lib/generate/Generator.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { ClassLoader } from '../parse/ClassLoader';
99
import { CommentLoader } from '../parse/CommentLoader';
1010
import { ConstructorLoader } from '../parse/ConstructorLoader';
1111
import { GenericsLoader } from '../parse/GenericsLoader';
12+
import { MemberLoader } from '../parse/MemberLoader';
1213
import type { PackageMetadata } from '../parse/PackageMetadataLoader';
1314
import { PackageMetadataLoader } from '../parse/PackageMetadataLoader';
1415
import { ParameterLoader } from '../parse/ParameterLoader';
@@ -97,6 +98,10 @@ export class Generator {
9798
const extensionsUnresolved = parameterLoader.loadAllExtensionData(classAndInterfaceIndex);
9899
const extensions = await parameterResolver.resolveAllExtensionData(extensionsUnresolved, classAndInterfaceIndex);
99100

101+
// Load members data
102+
const membersUnresolved = new MemberLoader({ parameterLoader }).getMembers(classAndInterfaceIndex);
103+
const members = await parameterResolver.resolveAllMemberParameterData(membersUnresolved);
104+
100105
// Load external components
101106
const externalModulesLoader = new ExternalModulesLoader({
102107
pathDestination,
@@ -120,6 +125,7 @@ export class Generator {
120125
classConstructors: constructors,
121126
classGenerics: generics,
122127
classExtensions: extensions,
128+
classMembers: members,
123129
externalComponents,
124130
contextParser: new ContextParser({
125131
documentLoader: new PrefetchedDocumentLoader({

lib/parse/ClassIndex.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ export interface ClassLoaded extends ClassReference {
6161
comment?: string;
6262
// The generic types of this class
6363
generics: GenericTypes;
64-
// The keys of all members
65-
memberKeys: string[];
6664
}
6765

6866
/**
@@ -99,8 +97,14 @@ export interface InterfaceLoaded extends ClassReference {
9997
comment?: string;
10098
// The generic types of this class
10199
generics: GenericTypes;
102-
// The keys of all members
103-
memberKeys: string[];
100+
}
101+
102+
/**
103+
* A member field of a class or interface.
104+
*/
105+
export interface MemberField {
106+
name: string;
107+
range: TypeNode | undefined;
104108
}
105109

106110
/**

lib/parse/ClassLoader.ts

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,21 @@ import type {
66
TSModuleBlock,
77
TSModuleDeclaration,
88
TSTypeAliasDeclaration,
9-
ClassBody,
10-
TSInterfaceBody,
119
} from '@typescript-eslint/types/dist/ts-estree';
1210
import type { AST, TSESTreeOptions } from '@typescript-eslint/typescript-estree';
1311
import { AST_NODE_TYPES } from '@typescript-eslint/typescript-estree';
1412
import type { Logger } from 'winston';
1513
import type { ResolutionContext } from '../resolution/ResolutionContext';
16-
import type { ClassLoaded,
14+
import type {
15+
ClassLoaded,
1716
ClassReference,
1817
ClassReferenceLoaded,
1918
EnumLoaded,
2019
GenericTypes,
2120
InterfaceLoaded,
2221
TypeLoaded,
23-
GenericallyTyped } from './ClassIndex';
22+
GenericallyTyped,
23+
} from './ClassIndex';
2424
import type { CommentLoader } from './CommentLoader';
2525

2626
/**
@@ -202,7 +202,6 @@ export class ClassLoader {
202202
ast,
203203
abstract: declaration.abstract,
204204
generics: this.collectGenericTypes(declaration),
205-
memberKeys: this.collectClassMembers(declaration.body),
206205
});
207206
}
208207

@@ -216,7 +215,6 @@ export class ClassLoader {
216215
ast,
217216
abstract: declaration.abstract,
218217
generics: this.collectGenericTypes(declaration),
219-
memberKeys: this.collectClassMembers(declaration.body),
220218
});
221219
}
222220

@@ -231,7 +229,6 @@ export class ClassLoader {
231229
declaration,
232230
ast,
233231
generics: this.collectGenericTypes(declaration),
234-
memberKeys: this.collectClassMembers(declaration.body),
235232
});
236233
}
237234

@@ -244,7 +241,6 @@ export class ClassLoader {
244241
declaration,
245242
ast,
246243
generics: this.collectGenericTypes(declaration),
247-
memberKeys: this.collectClassMembers(declaration.body),
248244
});
249245
}
250246
}
@@ -676,31 +672,6 @@ export class ClassLoader {
676672
exportAssignment,
677673
};
678674
}
679-
680-
/**
681-
* Obtain the class member keys.
682-
* This should correspond to the keys that are available within the `keyof` range of this class
683-
* @param body A class or interface body
684-
*/
685-
public collectClassMembers(body: ClassBody | TSInterfaceBody): string[] {
686-
const members: string[] = [];
687-
for (const element of body.body) {
688-
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
689-
switch (element.type) {
690-
case AST_NODE_TYPES.ClassProperty:
691-
case AST_NODE_TYPES.TSAbstractClassProperty:
692-
case AST_NODE_TYPES.MethodDefinition:
693-
case AST_NODE_TYPES.TSAbstractMethodDefinition:
694-
case AST_NODE_TYPES.TSPropertySignature:
695-
case AST_NODE_TYPES.TSMethodSignature:
696-
if (element.key.type === 'Identifier') {
697-
members.push(element.key.name);
698-
}
699-
break;
700-
}
701-
}
702-
return members;
703-
}
704675
}
705676

706677
export interface ClassLoaderArgs {

lib/parse/MemberLoader.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { AST_NODE_TYPES } from '@typescript-eslint/typescript-estree';
2+
import type { ClassReferenceLoaded, ClassReferenceLoadedClassOrInterface, ClassIndex } from './ClassIndex';
3+
4+
import type { MemberParameterData, ParameterLoader, ParameterRangeUnresolved } from './ParameterLoader';
5+
6+
/**
7+
* Loads the member data of classes.
8+
*/
9+
export class MemberLoader {
10+
private readonly parameterLoader: ParameterLoader;
11+
12+
public constructor(args: MemberLoaderArgs) {
13+
this.parameterLoader = args.parameterLoader;
14+
}
15+
16+
/**
17+
* Create a class index containing all member data from the classes in the given index.
18+
* @param classIndex An index of loaded classes.
19+
*/
20+
public getMembers(
21+
classIndex: ClassIndex<ClassReferenceLoaded>,
22+
): ClassIndex<MemberData<ParameterRangeUnresolved>> {
23+
const membersIndex: ClassIndex<MemberData<ParameterRangeUnresolved>> = {};
24+
for (const [ className, classLoadedRoot ] of Object.entries(classIndex)) {
25+
if (classLoadedRoot.type === 'class' || classLoadedRoot.type === 'interface') {
26+
membersIndex[className] = {
27+
members: this.collectClassFields(classLoadedRoot),
28+
classLoaded: classLoadedRoot,
29+
};
30+
}
31+
}
32+
return membersIndex;
33+
}
34+
35+
/**
36+
* Obtain the class member fields.
37+
* This should correspond to the keys that are available within the `keyof` range of this class
38+
* @param classLoaded A class or interface
39+
*/
40+
public collectClassFields(
41+
classLoaded: ClassReferenceLoadedClassOrInterface,
42+
): MemberParameterData<ParameterRangeUnresolved>[] {
43+
const members: MemberParameterData<ParameterRangeUnresolved>[] = [];
44+
for (const element of classLoaded.declaration.body.body) {
45+
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
46+
switch (element.type) {
47+
case AST_NODE_TYPES.ClassProperty:
48+
case AST_NODE_TYPES.TSAbstractClassProperty:
49+
case AST_NODE_TYPES.MethodDefinition:
50+
case AST_NODE_TYPES.TSAbstractMethodDefinition:
51+
case AST_NODE_TYPES.TSPropertySignature:
52+
case AST_NODE_TYPES.TSMethodSignature:
53+
if (element.key.type === 'Identifier') {
54+
const typeNode = 'typeAnnotation' in element ? element.typeAnnotation!.typeAnnotation : undefined;
55+
members.push({
56+
name: element.key.name,
57+
range: typeNode ?
58+
this.parameterLoader.getRangeFromTypeNode(classLoaded, typeNode, `field ${element.key.name}`) :
59+
undefined,
60+
});
61+
}
62+
break;
63+
}
64+
}
65+
return members;
66+
}
67+
}
68+
69+
/**
70+
* Member parameter information
71+
*/
72+
export interface MemberData<R> {
73+
members: MemberParameterData<R>[];
74+
classLoaded: ClassReferenceLoaded;
75+
}
76+
77+
export interface MemberLoaderArgs {
78+
parameterLoader: ParameterLoader;
79+
}

lib/parse/ParameterLoader.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,21 @@ export interface GenericTypeParameterData<R> {
742742
comment?: string;
743743
}
744744

745+
export interface MemberParameterData<R> {
746+
/**
747+
* The member name.
748+
*/
749+
name: string;
750+
/**
751+
* The range of the member parameter.
752+
*/
753+
range?: R;
754+
/**
755+
* The human-readable description of this member.
756+
*/
757+
comment?: string;
758+
}
759+
745760
/**
746761
* Extension information
747762
*/

lib/parse/ParameterResolver.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ import type {
1111
import type { ClassLoader } from './ClassLoader';
1212
import type { ConstructorData } from './ConstructorLoader';
1313
import type { GenericsData } from './GenericsLoader';
14+
import type { MemberData } from './MemberLoader';
1415
import type { ExtensionData,
1516
GenericTypeParameterData,
1617
ParameterData,
1718
ParameterDataField,
1819
ParameterRangeResolved,
1920
ParameterRangeUnresolved,
20-
ParameterLoader } from './ParameterLoader';
21+
ParameterLoader, MemberParameterData } from './ParameterLoader';
2122

2223
export class ParameterResolver {
2324
private readonly classLoader: ClassLoader;
@@ -115,6 +116,47 @@ export class ParameterResolver {
115116
})));
116117
}
117118

119+
/**
120+
* Resolve all member parameters of a given constructor index.
121+
* @param unresolvedParametersIndex An index of unresolved constructor data.
122+
*/
123+
public async resolveAllMemberParameterData(
124+
unresolvedParametersIndex: ClassIndex<MemberData<ParameterRangeUnresolved>>,
125+
): Promise<ClassIndex<MemberData<ParameterRangeResolved>>> {
126+
const resolvedIndex: ClassIndex<MemberData<ParameterRangeResolved>> = {};
127+
128+
// Resolve parameters for the different constructors in parallel
129+
await Promise.all(Object.entries(unresolvedParametersIndex)
130+
.map(async([ className, unresolvedData ]) => {
131+
resolvedIndex[className] = {
132+
members: await this.resolveMemberParameterData(unresolvedData.members, unresolvedData.classLoaded, {}),
133+
classLoaded: unresolvedData.classLoaded,
134+
};
135+
}));
136+
137+
return resolvedIndex;
138+
}
139+
140+
/**
141+
* Resolve the given array of member parameter data in parallel.
142+
* @param members An array of unresolved members.
143+
* @param owningClass The class in which the given generic type parameters are declared.
144+
* @param genericTypeRemappings A remapping of generic type names.
145+
*/
146+
public async resolveMemberParameterData(
147+
members: MemberParameterData<ParameterRangeUnresolved>[],
148+
owningClass: ClassReferenceLoaded,
149+
genericTypeRemappings: Record<string, ParameterRangeUnresolved>,
150+
): Promise<GenericTypeParameterData<ParameterRangeResolved>[]> {
151+
return await Promise.all(members
152+
.map(async member => ({
153+
...member,
154+
range: member.range ?
155+
await this.resolveRange(member.range, owningClass, genericTypeRemappings, false, new Set()) :
156+
undefined,
157+
})));
158+
}
159+
118160
/**
119161
* Resolve the given array of parameter data in parallel.
120162
* @param parameters An array of unresolved parameters.

0 commit comments

Comments
 (0)