@ahoo-wang/wow-generator 9.2.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +177 -0
- package/README.zh-CN.md +149 -0
- package/dist/analysis/aggregates.d.cts +21 -0
- package/dist/analysis/aggregates.d.ts +21 -0
- package/dist/analysis/analyze.d.cts +18 -0
- package/dist/analysis/analyze.d.ts +18 -0
- package/dist/analysis/apiClients.d.cts +14 -0
- package/dist/analysis/apiClients.d.ts +14 -0
- package/dist/analysis/clientNames.d.cts +55 -0
- package/dist/analysis/clientNames.d.ts +55 -0
- package/dist/analysis/model.d.cts +212 -0
- package/dist/analysis/model.d.ts +212 -0
- package/dist/analysis/modelInfo.d.cts +23 -0
- package/dist/analysis/modelInfo.d.ts +23 -0
- package/dist/analysis/models.d.cts +17 -0
- package/dist/analysis/models.d.ts +17 -0
- package/dist/api/configuration.d.cts +30 -0
- package/dist/api/configuration.d.ts +30 -0
- package/dist/api/errors.d.cts +41 -0
- package/dist/api/errors.d.ts +41 -0
- package/dist/api/logger.d.cts +61 -0
- package/dist/api/logger.d.ts +61 -0
- package/dist/api/options.d.cts +47 -0
- package/dist/api/options.d.ts +47 -0
- package/dist/cli/program.d.cts +35 -0
- package/dist/cli/program.d.ts +35 -0
- package/dist/cli/runGenerate.d.cts +65 -0
- package/dist/cli/runGenerate.d.ts +65 -0
- package/dist/cli.cjs +3 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +6 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +98 -0
- package/dist/cli.js.map +1 -0
- package/dist/codeGenerator-DpDTDC4o.cjs +23 -0
- package/dist/codeGenerator-DpDTDC4o.cjs.map +1 -0
- package/dist/codeGenerator-kyY9eLML.js +2583 -0
- package/dist/codeGenerator-kyY9eLML.js.map +1 -0
- package/dist/emit/importRegistry.d.cts +50 -0
- package/dist/emit/importRegistry.d.ts +50 -0
- package/dist/emit/imports.d.cts +49 -0
- package/dist/emit/imports.d.ts +49 -0
- package/dist/emit/jsdoc.d.cts +38 -0
- package/dist/emit/jsdoc.d.ts +38 -0
- package/dist/emit/moduleBuilder.d.cts +80 -0
- package/dist/emit/moduleBuilder.d.ts +80 -0
- package/dist/emitters/apiClients.d.cts +10 -0
- package/dist/emitters/apiClients.d.ts +10 -0
- package/dist/emitters/commandClients.d.cts +14 -0
- package/dist/emitters/commandClients.d.ts +14 -0
- package/dist/emitters/decorators.d.cts +83 -0
- package/dist/emitters/decorators.d.ts +83 -0
- package/dist/emitters/emit.d.cts +15 -0
- package/dist/emitters/emit.d.ts +15 -0
- package/dist/emitters/indexFiles.d.cts +12 -0
- package/dist/emitters/indexFiles.d.ts +12 -0
- package/dist/emitters/models.d.cts +77 -0
- package/dist/emitters/models.d.ts +77 -0
- package/dist/emitters/queryClients.d.cts +11 -0
- package/dist/emitters/queryClients.d.ts +11 -0
- package/dist/emitters/target.d.cts +14 -0
- package/dist/emitters/target.d.ts +14 -0
- package/dist/finalize/finalize.d.cts +16 -0
- package/dist/finalize/finalize.d.ts +16 -0
- package/dist/finalize/typeOnlyImports.d.cts +13 -0
- package/dist/finalize/typeOnlyImports.d.ts +13 -0
- package/dist/finalize/verification.d.cts +14 -0
- package/dist/finalize/verification.d.ts +14 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +2 -0
- package/dist/input/configuration.d.cts +87 -0
- package/dist/input/configuration.d.ts +87 -0
- package/dist/input/parsers.d.cts +39 -0
- package/dist/input/parsers.d.ts +39 -0
- package/dist/input/resources.d.cts +36 -0
- package/dist/input/resources.d.ts +36 -0
- package/dist/naming/modelInfo.d.cts +10 -0
- package/dist/naming/modelInfo.d.ts +10 -0
- package/dist/naming/naming.d.cts +102 -0
- package/dist/naming/naming.d.ts +102 -0
- package/dist/naming/order.d.cts +2 -0
- package/dist/naming/order.d.ts +2 -0
- package/dist/naming/paths.d.cts +27 -0
- package/dist/naming/paths.d.ts +27 -0
- package/dist/openapi/components.d.cts +55 -0
- package/dist/openapi/components.d.ts +55 -0
- package/dist/openapi/document.d.cts +25 -0
- package/dist/openapi/document.d.ts +25 -0
- package/dist/openapi/operations.d.cts +78 -0
- package/dist/openapi/operations.d.ts +78 -0
- package/dist/openapi/references.d.cts +28 -0
- package/dist/openapi/references.d.ts +28 -0
- package/dist/openapi/responses.d.cts +44 -0
- package/dist/openapi/responses.d.ts +44 -0
- package/dist/openapi/schemas.d.cts +112 -0
- package/dist/openapi/schemas.d.ts +112 -0
- package/dist/output/outputStore.d.cts +92 -0
- package/dist/output/outputStore.d.ts +92 -0
- package/dist/pipeline/codeGenerator.d.cts +61 -0
- package/dist/pipeline/codeGenerator.d.ts +61 -0
- package/dist/pipeline/seams.d.cts +29 -0
- package/dist/pipeline/seams.d.ts +29 -0
- package/dist/types/typeResolver.d.cts +124 -0
- package/dist/types/typeResolver.d.ts +124 -0
- package/dist/version.d.cts +2 -0
- package/dist/version.d.ts +2 -0
- package/dist/wow/conventions.d.cts +154 -0
- package/dist/wow/conventions.d.ts +154 -0
- package/dist/wow/model.d.cts +116 -0
- package/dist/wow/model.d.ts +116 -0
- package/dist/wow/resolveWowModel.d.cts +21 -0
- package/dist/wow/resolveWowModel.d.ts +21 -0
- package/package.json +108 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { TagAliasAggregate } from '../wow/model.cjs';
|
|
2
|
+
import { Operation } from '@ahoo-wang/fetcher-openapi';
|
|
3
|
+
/**
|
|
4
|
+
* The path of a client module of an aggregate, relative to the output
|
|
5
|
+
* directory: `<contextAlias>/<aggregateName>/<fileName>.ts`.
|
|
6
|
+
*
|
|
7
|
+
* @param aggregate - The aggregate metadata containing context alias and aggregate name
|
|
8
|
+
* @param fileName - The name of the file, without extension
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* clientModulePath({ contextAlias: 'user', aggregateName: 'profile' }, 'queryClient');
|
|
13
|
+
* // 'user/profile/queryClient.ts'
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function clientModulePath(aggregate: Pick<TagAliasAggregate, 'contextAlias' | 'aggregateName'>, fileName: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* The name of a class or type of an aggregate: its name as a type, then the
|
|
19
|
+
* suffix (`order`, `CommandClient` → `OrderCommandClient`).
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveClassName(aggregate: Pick<TagAliasAggregate, 'aggregateName'>, suffix: string): string;
|
|
22
|
+
/** Operation extension naming the method an operation generates. */
|
|
23
|
+
export declare const OPERATION_METHOD_NAME_KEY = "x-fetcher-method";
|
|
24
|
+
/**
|
|
25
|
+
* Names the method an operation generates.
|
|
26
|
+
*
|
|
27
|
+
* The name depends on the operation alone, so adding an operation never
|
|
28
|
+
* renames an existing method:
|
|
29
|
+
*
|
|
30
|
+
* 1. a name configured for the operationId (`apiClients[tag].methodNames`);
|
|
31
|
+
* 2. else the operation's `x-fetcher-method` extension;
|
|
32
|
+
* 3. else the last dot-separated segment of the operationId, camel-cased:
|
|
33
|
+
* `getUserById` → `getUserById`, `delete_user_by_id` → `deleteUserById`,
|
|
34
|
+
* `getUser_1` → `getUser1`, `users.list` → `list`,
|
|
35
|
+
* `example.cart.add_cart_item` → `addCartItem`; a name starting with a
|
|
36
|
+
* digit is prefixed with `_`.
|
|
37
|
+
*
|
|
38
|
+
* Two operations of one client that arrive at the same name are an error the
|
|
39
|
+
* caller reports; the first two sources resolve it.
|
|
40
|
+
*
|
|
41
|
+
* @param operation - The OpenAPI operation
|
|
42
|
+
* @param configured - The name configured for its operationId, if any
|
|
43
|
+
* @returns The method name, or undefined for an operation without an operationId
|
|
44
|
+
* @throws GeneratorError when a configured or extension name is not a valid method name
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveMethodName(operation: Operation, configured?: string): string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Turns a parameter name from the document into a unique parameter
|
|
49
|
+
* identifier: `item-id` → `itemId`, and `id` twice → `id`, `id2`.
|
|
50
|
+
*
|
|
51
|
+
* @param name - The name the document uses
|
|
52
|
+
* @param used - The identifiers the method already uses; updated
|
|
53
|
+
* @returns The identifier
|
|
54
|
+
*/
|
|
55
|
+
export declare function uniqueParameterName(name: string, used: Set<string>): string;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { TagAliasAggregate } from '../wow/model.js';
|
|
2
|
+
import { Operation } from '@ahoo-wang/fetcher-openapi';
|
|
3
|
+
/**
|
|
4
|
+
* The path of a client module of an aggregate, relative to the output
|
|
5
|
+
* directory: `<contextAlias>/<aggregateName>/<fileName>.ts`.
|
|
6
|
+
*
|
|
7
|
+
* @param aggregate - The aggregate metadata containing context alias and aggregate name
|
|
8
|
+
* @param fileName - The name of the file, without extension
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* clientModulePath({ contextAlias: 'user', aggregateName: 'profile' }, 'queryClient');
|
|
13
|
+
* // 'user/profile/queryClient.ts'
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function clientModulePath(aggregate: Pick<TagAliasAggregate, 'contextAlias' | 'aggregateName'>, fileName: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* The name of a class or type of an aggregate: its name as a type, then the
|
|
19
|
+
* suffix (`order`, `CommandClient` → `OrderCommandClient`).
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveClassName(aggregate: Pick<TagAliasAggregate, 'aggregateName'>, suffix: string): string;
|
|
22
|
+
/** Operation extension naming the method an operation generates. */
|
|
23
|
+
export declare const OPERATION_METHOD_NAME_KEY = "x-fetcher-method";
|
|
24
|
+
/**
|
|
25
|
+
* Names the method an operation generates.
|
|
26
|
+
*
|
|
27
|
+
* The name depends on the operation alone, so adding an operation never
|
|
28
|
+
* renames an existing method:
|
|
29
|
+
*
|
|
30
|
+
* 1. a name configured for the operationId (`apiClients[tag].methodNames`);
|
|
31
|
+
* 2. else the operation's `x-fetcher-method` extension;
|
|
32
|
+
* 3. else the last dot-separated segment of the operationId, camel-cased:
|
|
33
|
+
* `getUserById` → `getUserById`, `delete_user_by_id` → `deleteUserById`,
|
|
34
|
+
* `getUser_1` → `getUser1`, `users.list` → `list`,
|
|
35
|
+
* `example.cart.add_cart_item` → `addCartItem`; a name starting with a
|
|
36
|
+
* digit is prefixed with `_`.
|
|
37
|
+
*
|
|
38
|
+
* Two operations of one client that arrive at the same name are an error the
|
|
39
|
+
* caller reports; the first two sources resolve it.
|
|
40
|
+
*
|
|
41
|
+
* @param operation - The OpenAPI operation
|
|
42
|
+
* @param configured - The name configured for its operationId, if any
|
|
43
|
+
* @returns The method name, or undefined for an operation without an operationId
|
|
44
|
+
* @throws GeneratorError when a configured or extension name is not a valid method name
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveMethodName(operation: Operation, configured?: string): string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Turns a parameter name from the document into a unique parameter
|
|
49
|
+
* identifier: `item-id` → `itemId`, and `id` twice → `id`, `id2`.
|
|
50
|
+
*
|
|
51
|
+
* @param name - The name the document uses
|
|
52
|
+
* @param used - The identifiers the method already uses; updated
|
|
53
|
+
* @returns The identifier
|
|
54
|
+
*/
|
|
55
|
+
export declare function uniqueParameterName(name: string, used: Set<string>): string;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { HTTPMethod, Reference, Schema } from '@ahoo-wang/fetcher-openapi';
|
|
2
|
+
import { ModelInfo } from '../naming/modelInfo.cjs';
|
|
3
|
+
/**
|
|
4
|
+
* What a document generates, decided before anything is written: every
|
|
5
|
+
* name, file, parameter and kind of body or response, as plain data. It
|
|
6
|
+
* holds no ts-morph node and no operation of the document; the emitters read
|
|
7
|
+
* it, and only they resolve schemas to types, in this order, so the imports
|
|
8
|
+
* of each module come out the way they always have.
|
|
9
|
+
*
|
|
10
|
+
* Files are relative to the output directory.
|
|
11
|
+
*/
|
|
12
|
+
export interface GenerationModel {
|
|
13
|
+
/** The bounded contexts, each a file declaring its alias constant; sorted. */
|
|
14
|
+
readonly contexts: readonly BoundedContextModel[];
|
|
15
|
+
/** The models, in the order of the document's components. */
|
|
16
|
+
readonly models: readonly ModelDeclaration[];
|
|
17
|
+
/** The aggregates with a command and a query client, by bounded context. */
|
|
18
|
+
readonly aggregates: readonly AggregateModel[];
|
|
19
|
+
/** The API clients, one per tag, sorted by tag name. */
|
|
20
|
+
readonly apiClients: readonly ApiClientModel[];
|
|
21
|
+
}
|
|
22
|
+
/** What a generation decided, and the warnings it gave on the way. */
|
|
23
|
+
export interface Analysis {
|
|
24
|
+
readonly model: GenerationModel;
|
|
25
|
+
/** One line each, in the order they arose. */
|
|
26
|
+
readonly warnings: readonly string[];
|
|
27
|
+
}
|
|
28
|
+
/** A bounded context's alias constant: `export const SHOP_BOUNDED_CONTEXT_ALIAS = 'shop';`. */
|
|
29
|
+
export interface BoundedContextModel {
|
|
30
|
+
readonly alias: string;
|
|
31
|
+
readonly constantName: string;
|
|
32
|
+
readonly file: string;
|
|
33
|
+
}
|
|
34
|
+
/** The constant a module imports to name its bounded context. */
|
|
35
|
+
export interface ContextReference {
|
|
36
|
+
readonly alias: string;
|
|
37
|
+
readonly constantName: string;
|
|
38
|
+
}
|
|
39
|
+
/** A model: one declaration (and its companions) of a component schema. */
|
|
40
|
+
export interface ModelDeclaration {
|
|
41
|
+
/** The component key. */
|
|
42
|
+
readonly key: string;
|
|
43
|
+
/** Its name, and the package path of its file. */
|
|
44
|
+
readonly info: ModelInfo;
|
|
45
|
+
readonly file: string;
|
|
46
|
+
/** The schema as the document has it; the types read this one. */
|
|
47
|
+
readonly schema: Schema | Reference;
|
|
48
|
+
/**
|
|
49
|
+
* The schema its doc comment reads: with the title and description the
|
|
50
|
+
* Wow metadata lends it over it, when it lends any.
|
|
51
|
+
*/
|
|
52
|
+
readonly docSchema: Schema | Reference;
|
|
53
|
+
/**
|
|
54
|
+
* A command or event body that declares nothing - a Kotlin `data object` -
|
|
55
|
+
* which generates `Record<string, never>` rather than any object.
|
|
56
|
+
*/
|
|
57
|
+
readonly emptyMessageBody: boolean;
|
|
58
|
+
}
|
|
59
|
+
/** An aggregate: its command client and its query client. */
|
|
60
|
+
export interface AggregateModel {
|
|
61
|
+
readonly contextAlias: string;
|
|
62
|
+
readonly aggregateName: string;
|
|
63
|
+
readonly context: ContextReference;
|
|
64
|
+
readonly commandClient: CommandClientModel;
|
|
65
|
+
readonly queryClient: QueryClientModel;
|
|
66
|
+
}
|
|
67
|
+
/** The command client of an aggregate, and its streaming twin. */
|
|
68
|
+
export interface CommandClientModel {
|
|
69
|
+
readonly file: string;
|
|
70
|
+
/** The enum of the command routes: `CartCommandEndpointPaths`. */
|
|
71
|
+
readonly endpointPathsName: string;
|
|
72
|
+
readonly className: string;
|
|
73
|
+
readonly streamClassName: string;
|
|
74
|
+
readonly commands: readonly CommandModel[];
|
|
75
|
+
}
|
|
76
|
+
/** A command of an aggregate. */
|
|
77
|
+
export interface CommandModel {
|
|
78
|
+
/** The command's route, and the member of the route enum that holds it. */
|
|
79
|
+
readonly path: string;
|
|
80
|
+
readonly endpointMember: string;
|
|
81
|
+
readonly httpMethod: HTTPMethod;
|
|
82
|
+
readonly methodName: string;
|
|
83
|
+
/**
|
|
84
|
+
* The alias of the command's body type: `AddCartItemCommand`. None when
|
|
85
|
+
* the body's name already ends in `Command`: its methods then take
|
|
86
|
+
* `CommandBody<MountedCommand>` itself, so no name repeats the suffix.
|
|
87
|
+
*/
|
|
88
|
+
readonly typeName?: string;
|
|
89
|
+
/** The body's model; one of Wow's own lives in wow-client, with its type. */
|
|
90
|
+
readonly body: ModelInfo;
|
|
91
|
+
/** The component key of the body's schema. */
|
|
92
|
+
readonly bodyKey: string;
|
|
93
|
+
/** The body's properties a caller may leave out. */
|
|
94
|
+
readonly optionalFields: readonly string[];
|
|
95
|
+
/** Whether a request may leave out the body: it has no properties. */
|
|
96
|
+
readonly requestOptional: boolean;
|
|
97
|
+
/** The path parameters the caller passes. */
|
|
98
|
+
readonly pathParameters: readonly PathParameterModel[];
|
|
99
|
+
readonly docs: readonly (string | undefined)[];
|
|
100
|
+
}
|
|
101
|
+
/** A path parameter of a command method, in the order the route holds them. */
|
|
102
|
+
export interface PathParameterModel {
|
|
103
|
+
/** The method's parameter: an identifier. */
|
|
104
|
+
readonly name: string;
|
|
105
|
+
/** The name in the route. */
|
|
106
|
+
readonly pathName: string;
|
|
107
|
+
readonly type: string;
|
|
108
|
+
}
|
|
109
|
+
/** The query client factory of an aggregate. */
|
|
110
|
+
export interface QueryClientModel {
|
|
111
|
+
readonly file: string;
|
|
112
|
+
/** The aggregate's route segment: its resource name. */
|
|
113
|
+
readonly resourceName: string;
|
|
114
|
+
/** A `ResourceAttributionPathSpec` member, as code. */
|
|
115
|
+
readonly resourceAttribution: string;
|
|
116
|
+
readonly state: ModelInfo;
|
|
117
|
+
readonly fields: ModelInfo;
|
|
118
|
+
/** The enum of the event titles: `CartDomainEventTypeMapTitle`. */
|
|
119
|
+
readonly eventTitlesName: string;
|
|
120
|
+
/** The union of the event types: `CartDomainEventType`. */
|
|
121
|
+
readonly eventTypeName: string;
|
|
122
|
+
readonly events: readonly EventModel[];
|
|
123
|
+
readonly factoryName: string;
|
|
124
|
+
}
|
|
125
|
+
/** A domain event of an aggregate. */
|
|
126
|
+
export interface EventModel {
|
|
127
|
+
/** Its member of the event title enum. */
|
|
128
|
+
readonly memberName: string;
|
|
129
|
+
readonly title: string;
|
|
130
|
+
readonly body: ModelInfo;
|
|
131
|
+
}
|
|
132
|
+
/** The API client of a tag. */
|
|
133
|
+
export interface ApiClientModel {
|
|
134
|
+
readonly tagName: string;
|
|
135
|
+
readonly className: string;
|
|
136
|
+
readonly file: string;
|
|
137
|
+
/** The tag's description, the class's doc comment. */
|
|
138
|
+
readonly description?: string;
|
|
139
|
+
/** The bounded context whose alias is the base path, in a Wow document. */
|
|
140
|
+
readonly basePath?: ContextReference;
|
|
141
|
+
/** In the order of the document's operations, by operation id. */
|
|
142
|
+
readonly methods: readonly ApiMethodModel[];
|
|
143
|
+
}
|
|
144
|
+
/** A method of an API client: one operation. */
|
|
145
|
+
export interface ApiMethodModel {
|
|
146
|
+
readonly name: string;
|
|
147
|
+
readonly httpMethod: HTTPMethod;
|
|
148
|
+
readonly path: string;
|
|
149
|
+
/**
|
|
150
|
+
* The path, query and header parameters, in the order the types resolve:
|
|
151
|
+
* path, then query, then header, each in document order. The method takes
|
|
152
|
+
* the required ones first, then the body if required, then the optional
|
|
153
|
+
* ones, then the body if optional.
|
|
154
|
+
*/
|
|
155
|
+
readonly parameters: readonly ParameterModel[];
|
|
156
|
+
readonly body?: BodyModel;
|
|
157
|
+
readonly returns: ReturnModel;
|
|
158
|
+
readonly docs: readonly (string | undefined)[];
|
|
159
|
+
}
|
|
160
|
+
/** A path, query or header parameter of an API method. */
|
|
161
|
+
export interface ParameterModel {
|
|
162
|
+
/** The method's parameter: an identifier. */
|
|
163
|
+
readonly name: string;
|
|
164
|
+
readonly location: 'path' | 'query' | 'header';
|
|
165
|
+
/** The name the request uses. */
|
|
166
|
+
readonly parameterName: string;
|
|
167
|
+
/** Its schema; a parameter without one is a string. */
|
|
168
|
+
readonly schema?: Schema | Reference;
|
|
169
|
+
readonly required: boolean;
|
|
170
|
+
}
|
|
171
|
+
/** The request body of an API method. */
|
|
172
|
+
export interface BodyModel {
|
|
173
|
+
/** The method's parameter: `body`, unless a parameter took the name. */
|
|
174
|
+
readonly name: string;
|
|
175
|
+
readonly required: boolean;
|
|
176
|
+
readonly content: BodyContent;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* What a body holds:
|
|
180
|
+
*
|
|
181
|
+
* - `json`: the schema's type, with the properties the schema does not
|
|
182
|
+
* require optional (`PartialBy<Item, 'id'>`);
|
|
183
|
+
* - `formData`: `FormData`; `urlEncoded`: `URLSearchParams`;
|
|
184
|
+
* - `text`: a string; `binary`: whatever a fetch request accepts.
|
|
185
|
+
*/
|
|
186
|
+
export type BodyContent = {
|
|
187
|
+
readonly kind: 'json';
|
|
188
|
+
readonly schema: Schema | Reference;
|
|
189
|
+
readonly optionalFields: readonly string[];
|
|
190
|
+
} | {
|
|
191
|
+
readonly kind: 'formData' | 'urlEncoded' | 'text' | 'binary';
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* What an API method returns, read from its success response:
|
|
195
|
+
*
|
|
196
|
+
* - `json`: the schema's type; a response of any media type (`wildcard`)
|
|
197
|
+
* whose schema resolves to `string` is text;
|
|
198
|
+
* - `eventStream`: a JSON server-sent event stream of the items' type, the
|
|
199
|
+
* `data` of a `ServerSentEvent` model, or of anything without one;
|
|
200
|
+
* - `text`: a string; `response`: the raw `Response`.
|
|
201
|
+
*/
|
|
202
|
+
export type ReturnModel = {
|
|
203
|
+
readonly kind: 'json';
|
|
204
|
+
readonly schema: Schema | Reference;
|
|
205
|
+
readonly wildcard: boolean;
|
|
206
|
+
} | {
|
|
207
|
+
readonly kind: 'eventStream';
|
|
208
|
+
readonly items?: Reference;
|
|
209
|
+
readonly serverSentEvent: boolean;
|
|
210
|
+
} | {
|
|
211
|
+
readonly kind: 'text' | 'response';
|
|
212
|
+
};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { HTTPMethod, Reference, Schema } from '@ahoo-wang/fetcher-openapi';
|
|
2
|
+
import { ModelInfo } from '../naming/modelInfo.js';
|
|
3
|
+
/**
|
|
4
|
+
* What a document generates, decided before anything is written: every
|
|
5
|
+
* name, file, parameter and kind of body or response, as plain data. It
|
|
6
|
+
* holds no ts-morph node and no operation of the document; the emitters read
|
|
7
|
+
* it, and only they resolve schemas to types, in this order, so the imports
|
|
8
|
+
* of each module come out the way they always have.
|
|
9
|
+
*
|
|
10
|
+
* Files are relative to the output directory.
|
|
11
|
+
*/
|
|
12
|
+
export interface GenerationModel {
|
|
13
|
+
/** The bounded contexts, each a file declaring its alias constant; sorted. */
|
|
14
|
+
readonly contexts: readonly BoundedContextModel[];
|
|
15
|
+
/** The models, in the order of the document's components. */
|
|
16
|
+
readonly models: readonly ModelDeclaration[];
|
|
17
|
+
/** The aggregates with a command and a query client, by bounded context. */
|
|
18
|
+
readonly aggregates: readonly AggregateModel[];
|
|
19
|
+
/** The API clients, one per tag, sorted by tag name. */
|
|
20
|
+
readonly apiClients: readonly ApiClientModel[];
|
|
21
|
+
}
|
|
22
|
+
/** What a generation decided, and the warnings it gave on the way. */
|
|
23
|
+
export interface Analysis {
|
|
24
|
+
readonly model: GenerationModel;
|
|
25
|
+
/** One line each, in the order they arose. */
|
|
26
|
+
readonly warnings: readonly string[];
|
|
27
|
+
}
|
|
28
|
+
/** A bounded context's alias constant: `export const SHOP_BOUNDED_CONTEXT_ALIAS = 'shop';`. */
|
|
29
|
+
export interface BoundedContextModel {
|
|
30
|
+
readonly alias: string;
|
|
31
|
+
readonly constantName: string;
|
|
32
|
+
readonly file: string;
|
|
33
|
+
}
|
|
34
|
+
/** The constant a module imports to name its bounded context. */
|
|
35
|
+
export interface ContextReference {
|
|
36
|
+
readonly alias: string;
|
|
37
|
+
readonly constantName: string;
|
|
38
|
+
}
|
|
39
|
+
/** A model: one declaration (and its companions) of a component schema. */
|
|
40
|
+
export interface ModelDeclaration {
|
|
41
|
+
/** The component key. */
|
|
42
|
+
readonly key: string;
|
|
43
|
+
/** Its name, and the package path of its file. */
|
|
44
|
+
readonly info: ModelInfo;
|
|
45
|
+
readonly file: string;
|
|
46
|
+
/** The schema as the document has it; the types read this one. */
|
|
47
|
+
readonly schema: Schema | Reference;
|
|
48
|
+
/**
|
|
49
|
+
* The schema its doc comment reads: with the title and description the
|
|
50
|
+
* Wow metadata lends it over it, when it lends any.
|
|
51
|
+
*/
|
|
52
|
+
readonly docSchema: Schema | Reference;
|
|
53
|
+
/**
|
|
54
|
+
* A command or event body that declares nothing - a Kotlin `data object` -
|
|
55
|
+
* which generates `Record<string, never>` rather than any object.
|
|
56
|
+
*/
|
|
57
|
+
readonly emptyMessageBody: boolean;
|
|
58
|
+
}
|
|
59
|
+
/** An aggregate: its command client and its query client. */
|
|
60
|
+
export interface AggregateModel {
|
|
61
|
+
readonly contextAlias: string;
|
|
62
|
+
readonly aggregateName: string;
|
|
63
|
+
readonly context: ContextReference;
|
|
64
|
+
readonly commandClient: CommandClientModel;
|
|
65
|
+
readonly queryClient: QueryClientModel;
|
|
66
|
+
}
|
|
67
|
+
/** The command client of an aggregate, and its streaming twin. */
|
|
68
|
+
export interface CommandClientModel {
|
|
69
|
+
readonly file: string;
|
|
70
|
+
/** The enum of the command routes: `CartCommandEndpointPaths`. */
|
|
71
|
+
readonly endpointPathsName: string;
|
|
72
|
+
readonly className: string;
|
|
73
|
+
readonly streamClassName: string;
|
|
74
|
+
readonly commands: readonly CommandModel[];
|
|
75
|
+
}
|
|
76
|
+
/** A command of an aggregate. */
|
|
77
|
+
export interface CommandModel {
|
|
78
|
+
/** The command's route, and the member of the route enum that holds it. */
|
|
79
|
+
readonly path: string;
|
|
80
|
+
readonly endpointMember: string;
|
|
81
|
+
readonly httpMethod: HTTPMethod;
|
|
82
|
+
readonly methodName: string;
|
|
83
|
+
/**
|
|
84
|
+
* The alias of the command's body type: `AddCartItemCommand`. None when
|
|
85
|
+
* the body's name already ends in `Command`: its methods then take
|
|
86
|
+
* `CommandBody<MountedCommand>` itself, so no name repeats the suffix.
|
|
87
|
+
*/
|
|
88
|
+
readonly typeName?: string;
|
|
89
|
+
/** The body's model; one of Wow's own lives in wow-client, with its type. */
|
|
90
|
+
readonly body: ModelInfo;
|
|
91
|
+
/** The component key of the body's schema. */
|
|
92
|
+
readonly bodyKey: string;
|
|
93
|
+
/** The body's properties a caller may leave out. */
|
|
94
|
+
readonly optionalFields: readonly string[];
|
|
95
|
+
/** Whether a request may leave out the body: it has no properties. */
|
|
96
|
+
readonly requestOptional: boolean;
|
|
97
|
+
/** The path parameters the caller passes. */
|
|
98
|
+
readonly pathParameters: readonly PathParameterModel[];
|
|
99
|
+
readonly docs: readonly (string | undefined)[];
|
|
100
|
+
}
|
|
101
|
+
/** A path parameter of a command method, in the order the route holds them. */
|
|
102
|
+
export interface PathParameterModel {
|
|
103
|
+
/** The method's parameter: an identifier. */
|
|
104
|
+
readonly name: string;
|
|
105
|
+
/** The name in the route. */
|
|
106
|
+
readonly pathName: string;
|
|
107
|
+
readonly type: string;
|
|
108
|
+
}
|
|
109
|
+
/** The query client factory of an aggregate. */
|
|
110
|
+
export interface QueryClientModel {
|
|
111
|
+
readonly file: string;
|
|
112
|
+
/** The aggregate's route segment: its resource name. */
|
|
113
|
+
readonly resourceName: string;
|
|
114
|
+
/** A `ResourceAttributionPathSpec` member, as code. */
|
|
115
|
+
readonly resourceAttribution: string;
|
|
116
|
+
readonly state: ModelInfo;
|
|
117
|
+
readonly fields: ModelInfo;
|
|
118
|
+
/** The enum of the event titles: `CartDomainEventTypeMapTitle`. */
|
|
119
|
+
readonly eventTitlesName: string;
|
|
120
|
+
/** The union of the event types: `CartDomainEventType`. */
|
|
121
|
+
readonly eventTypeName: string;
|
|
122
|
+
readonly events: readonly EventModel[];
|
|
123
|
+
readonly factoryName: string;
|
|
124
|
+
}
|
|
125
|
+
/** A domain event of an aggregate. */
|
|
126
|
+
export interface EventModel {
|
|
127
|
+
/** Its member of the event title enum. */
|
|
128
|
+
readonly memberName: string;
|
|
129
|
+
readonly title: string;
|
|
130
|
+
readonly body: ModelInfo;
|
|
131
|
+
}
|
|
132
|
+
/** The API client of a tag. */
|
|
133
|
+
export interface ApiClientModel {
|
|
134
|
+
readonly tagName: string;
|
|
135
|
+
readonly className: string;
|
|
136
|
+
readonly file: string;
|
|
137
|
+
/** The tag's description, the class's doc comment. */
|
|
138
|
+
readonly description?: string;
|
|
139
|
+
/** The bounded context whose alias is the base path, in a Wow document. */
|
|
140
|
+
readonly basePath?: ContextReference;
|
|
141
|
+
/** In the order of the document's operations, by operation id. */
|
|
142
|
+
readonly methods: readonly ApiMethodModel[];
|
|
143
|
+
}
|
|
144
|
+
/** A method of an API client: one operation. */
|
|
145
|
+
export interface ApiMethodModel {
|
|
146
|
+
readonly name: string;
|
|
147
|
+
readonly httpMethod: HTTPMethod;
|
|
148
|
+
readonly path: string;
|
|
149
|
+
/**
|
|
150
|
+
* The path, query and header parameters, in the order the types resolve:
|
|
151
|
+
* path, then query, then header, each in document order. The method takes
|
|
152
|
+
* the required ones first, then the body if required, then the optional
|
|
153
|
+
* ones, then the body if optional.
|
|
154
|
+
*/
|
|
155
|
+
readonly parameters: readonly ParameterModel[];
|
|
156
|
+
readonly body?: BodyModel;
|
|
157
|
+
readonly returns: ReturnModel;
|
|
158
|
+
readonly docs: readonly (string | undefined)[];
|
|
159
|
+
}
|
|
160
|
+
/** A path, query or header parameter of an API method. */
|
|
161
|
+
export interface ParameterModel {
|
|
162
|
+
/** The method's parameter: an identifier. */
|
|
163
|
+
readonly name: string;
|
|
164
|
+
readonly location: 'path' | 'query' | 'header';
|
|
165
|
+
/** The name the request uses. */
|
|
166
|
+
readonly parameterName: string;
|
|
167
|
+
/** Its schema; a parameter without one is a string. */
|
|
168
|
+
readonly schema?: Schema | Reference;
|
|
169
|
+
readonly required: boolean;
|
|
170
|
+
}
|
|
171
|
+
/** The request body of an API method. */
|
|
172
|
+
export interface BodyModel {
|
|
173
|
+
/** The method's parameter: `body`, unless a parameter took the name. */
|
|
174
|
+
readonly name: string;
|
|
175
|
+
readonly required: boolean;
|
|
176
|
+
readonly content: BodyContent;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* What a body holds:
|
|
180
|
+
*
|
|
181
|
+
* - `json`: the schema's type, with the properties the schema does not
|
|
182
|
+
* require optional (`PartialBy<Item, 'id'>`);
|
|
183
|
+
* - `formData`: `FormData`; `urlEncoded`: `URLSearchParams`;
|
|
184
|
+
* - `text`: a string; `binary`: whatever a fetch request accepts.
|
|
185
|
+
*/
|
|
186
|
+
export type BodyContent = {
|
|
187
|
+
readonly kind: 'json';
|
|
188
|
+
readonly schema: Schema | Reference;
|
|
189
|
+
readonly optionalFields: readonly string[];
|
|
190
|
+
} | {
|
|
191
|
+
readonly kind: 'formData' | 'urlEncoded' | 'text' | 'binary';
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* What an API method returns, read from its success response:
|
|
195
|
+
*
|
|
196
|
+
* - `json`: the schema's type; a response of any media type (`wildcard`)
|
|
197
|
+
* whose schema resolves to `string` is text;
|
|
198
|
+
* - `eventStream`: a JSON server-sent event stream of the items' type, the
|
|
199
|
+
* `data` of a `ServerSentEvent` model, or of anything without one;
|
|
200
|
+
* - `text`: a string; `response`: the raw `Response`.
|
|
201
|
+
*/
|
|
202
|
+
export type ReturnModel = {
|
|
203
|
+
readonly kind: 'json';
|
|
204
|
+
readonly schema: Schema | Reference;
|
|
205
|
+
readonly wildcard: boolean;
|
|
206
|
+
} | {
|
|
207
|
+
readonly kind: 'eventStream';
|
|
208
|
+
readonly items?: Reference;
|
|
209
|
+
readonly serverSentEvent: boolean;
|
|
210
|
+
} | {
|
|
211
|
+
readonly kind: 'text' | 'response';
|
|
212
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Components, Reference, Schema } from '@ahoo-wang/fetcher-openapi';
|
|
2
|
+
import { ModelInfo } from '../naming/modelInfo.cjs';
|
|
3
|
+
export type { ModelInfo } from '../naming/modelInfo.cjs';
|
|
4
|
+
/**
|
|
5
|
+
* Resolves model information from a schema key.
|
|
6
|
+
*
|
|
7
|
+
* This function parses a dot-separated schema key and extracts the model name and path.
|
|
8
|
+
* It assumes that the model name is the first part that starts with an uppercase letter.
|
|
9
|
+
* All parts before the model name are treated as the path.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
*
|
|
13
|
+
* - "wow.api.BindingError" -> {path:'/wow/api',name:'BindingError'}
|
|
14
|
+
* - "compensation.ApiVersion" -> {path:'/compensation',name:'ApiVersion'}
|
|
15
|
+
* - "ai.AiMessage.Assistant" -> {path:'/ai',name:'AiMessageAssistant'}
|
|
16
|
+
* - "Result" -> {path:'/',name:'Result'}
|
|
17
|
+
*
|
|
18
|
+
* @param schemaKey - The dot-separated schema key (e.g., "com.example.User")
|
|
19
|
+
* @returns ModelInfo object containing the parsed name and path
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveModelInfo(schemaKey: string, schema?: Schema): ModelInfo;
|
|
22
|
+
export declare function resolveReferenceModelInfo(reference: Reference, components?: Components): ModelInfo;
|
|
23
|
+
export declare function resolveContextDeclarationName(contextAlias: string): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Components, Reference, Schema } from '@ahoo-wang/fetcher-openapi';
|
|
2
|
+
import { ModelInfo } from '../naming/modelInfo.js';
|
|
3
|
+
export type { ModelInfo } from '../naming/modelInfo.js';
|
|
4
|
+
/**
|
|
5
|
+
* Resolves model information from a schema key.
|
|
6
|
+
*
|
|
7
|
+
* This function parses a dot-separated schema key and extracts the model name and path.
|
|
8
|
+
* It assumes that the model name is the first part that starts with an uppercase letter.
|
|
9
|
+
* All parts before the model name are treated as the path.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
*
|
|
13
|
+
* - "wow.api.BindingError" -> {path:'/wow/api',name:'BindingError'}
|
|
14
|
+
* - "compensation.ApiVersion" -> {path:'/compensation',name:'ApiVersion'}
|
|
15
|
+
* - "ai.AiMessage.Assistant" -> {path:'/ai',name:'AiMessageAssistant'}
|
|
16
|
+
* - "Result" -> {path:'/',name:'Result'}
|
|
17
|
+
*
|
|
18
|
+
* @param schemaKey - The dot-separated schema key (e.g., "com.example.User")
|
|
19
|
+
* @returns ModelInfo object containing the parsed name and path
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveModelInfo(schemaKey: string, schema?: Schema): ModelInfo;
|
|
22
|
+
export declare function resolveReferenceModelInfo(reference: Reference, components?: Components): ModelInfo;
|
|
23
|
+
export declare function resolveContextDeclarationName(contextAlias: string): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { OpenApiDocument } from '../openapi/document.cjs';
|
|
2
|
+
import { WowModel } from '../wow/model.cjs';
|
|
3
|
+
import { BoundedContextModel, ModelDeclaration } from './model.cjs';
|
|
4
|
+
/**
|
|
5
|
+
* The bounded contexts whose alias constant is generated: every context with
|
|
6
|
+
* aggregates, and the document's own, which API clients take their base path
|
|
7
|
+
* from. Sorted by alias.
|
|
8
|
+
*/
|
|
9
|
+
export declare function analyzeContexts(wow: WowModel): BoundedContextModel[];
|
|
10
|
+
/**
|
|
11
|
+
* The models of a document: one per component schema, in the document's
|
|
12
|
+
* order, but for Wow's own schemas, which wow-client declares (`wow.*`, and
|
|
13
|
+
* the types every aggregate derives from its state).
|
|
14
|
+
*
|
|
15
|
+
* @throws GeneratorError when two schemas generate the same model
|
|
16
|
+
*/
|
|
17
|
+
export declare function analyzeModels(document: OpenApiDocument, wow: WowModel): ModelDeclaration[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { OpenApiDocument } from '../openapi/document.js';
|
|
2
|
+
import { WowModel } from '../wow/model.js';
|
|
3
|
+
import { BoundedContextModel, ModelDeclaration } from './model.js';
|
|
4
|
+
/**
|
|
5
|
+
* The bounded contexts whose alias constant is generated: every context with
|
|
6
|
+
* aggregates, and the document's own, which API clients take their base path
|
|
7
|
+
* from. Sorted by alias.
|
|
8
|
+
*/
|
|
9
|
+
export declare function analyzeContexts(wow: WowModel): BoundedContextModel[];
|
|
10
|
+
/**
|
|
11
|
+
* The models of a document: one per component schema, in the document's
|
|
12
|
+
* order, but for Wow's own schemas, which wow-client declares (`wow.*`, and
|
|
13
|
+
* the types every aggregate derives from its state).
|
|
14
|
+
*
|
|
15
|
+
* @throws GeneratorError when two schemas generate the same model
|
|
16
|
+
*/
|
|
17
|
+
export declare function analyzeModels(document: OpenApiDocument, wow: WowModel): ModelDeclaration[];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the generator looks for its configuration when none is named.
|
|
3
|
+
*/
|
|
4
|
+
export declare const DEFAULT_CONFIG_PATH = "./wow-generator.config.json";
|
|
5
|
+
/**
|
|
6
|
+
* The generator configuration, read from {@link DEFAULT_CONFIG_PATH} or the
|
|
7
|
+
* path `GeneratorOptions.configPath` names.
|
|
8
|
+
*/
|
|
9
|
+
export interface GeneratorConfiguration {
|
|
10
|
+
/**
|
|
11
|
+
* tag name -> api client configuration
|
|
12
|
+
*/
|
|
13
|
+
apiClients?: Record<string, ApiClientConfiguration>;
|
|
14
|
+
}
|
|
15
|
+
export interface ApiClientConfiguration {
|
|
16
|
+
/**
|
|
17
|
+
* The path parameters the client leaves out, because an interceptor fills
|
|
18
|
+
* them.
|
|
19
|
+
*
|
|
20
|
+
* Default: `['tenantId', 'ownerId']` for a Wow document (one with
|
|
21
|
+
* `x-wow-context-alias` or aggregates), whose CoSec interceptor fills them;
|
|
22
|
+
* none for any other document.
|
|
23
|
+
*/
|
|
24
|
+
ignorePathParameters?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Method names by operationId, overriding the name derived from it. Use it
|
|
27
|
+
* when two operations of one tag derive the same name.
|
|
28
|
+
*/
|
|
29
|
+
methodNames?: Record<string, string>;
|
|
30
|
+
}
|