@rexeus/typeweaver-gen 0.0.1

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/README.md ADDED
@@ -0,0 +1,267 @@
1
+ # @rexeus/typeweaver-gen
2
+
3
+ Code generation engine and utilities for TypeWeaver plugins.
4
+
5
+ ## Overview
6
+
7
+ This package provides the plugin architecture and utilities that power TypeWeaver's extensible code
8
+ generation system. It includes base classes, context utilities, and the plugin registry system.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install @rexeus/typeweaver-gen
14
+ ```
15
+
16
+ **Peer Dependencies:**
17
+
18
+ ```bash
19
+ npm install @rexeus/typeweaver-core
20
+ ```
21
+
22
+ ## Plugin Architecture
23
+
24
+ ### Creating a Plugin
25
+
26
+ ```typescript
27
+ import { BasePlugin, type GeneratorContext } from "@rexeus/typeweaver-gen";
28
+
29
+ export default class MyPlugin extends BasePlugin {
30
+ public name = "my-plugin";
31
+
32
+ public override generate(context: GeneratorContext): Promise<void> | void {
33
+ // Your generation logic here
34
+ const content = context.renderTemplate(templatePath, templateData);
35
+ context.writeFile("relative/path/to/output.ts", content);
36
+ context.addGeneratedFile("relative/path/to/output.ts");
37
+ }
38
+ }
39
+ ```
40
+
41
+ ### Plugin Context
42
+
43
+ The `GeneratorContext` provides utilities for code generation:
44
+
45
+ ```typescript
46
+ interface GeneratorContext {
47
+ // Input/output directories
48
+ outputDir: string;
49
+ inputDir: string;
50
+ templateDir: string;
51
+ coreDir: string;
52
+
53
+ // Resource data
54
+ resources: GetResourcesResult;
55
+
56
+ // Configuration
57
+ config: PluginConfig;
58
+
59
+ // Utility functions
60
+ writeFile: (relativePath: string, content: string) => void;
61
+ renderTemplate: (templatePath: string, data: unknown) => string;
62
+ addGeneratedFile: (relativePath: string) => void;
63
+ getGeneratedFiles: () => string[];
64
+ }
65
+ ```
66
+
67
+ ### Utility Functions
68
+
69
+ #### `writeFile(relativePath, content)`
70
+
71
+ Writes files relative to the output directory with automatic directory creation:
72
+
73
+ ```typescript
74
+ context.writeFile("users/UserClient.ts", generatedClientCode);
75
+ ```
76
+
77
+ #### `renderTemplate(templatePath, data)`
78
+
79
+ Renders EJS templates with provided data:
80
+
81
+ ```typescript
82
+ const content = context.renderTemplate(path.join(__dirname, "templates", "Client.ejs"), {
83
+ entityName,
84
+ operations,
85
+ coreDir: context.coreDir,
86
+ });
87
+ ```
88
+
89
+ #### `addGeneratedFile(relativePath)`
90
+
91
+ Tracks generated files (automatically called by `writeFile`):
92
+
93
+ ```typescript
94
+ context.addGeneratedFile("users/UserClient.ts");
95
+ ```
96
+
97
+ ## Resource System
98
+
99
+ The resource system provides structured access to API definitions:
100
+
101
+ ### Resource Types
102
+
103
+ ```typescript
104
+ interface GetResourcesResult {
105
+ entityResources: Record<string, OperationResource[]>;
106
+ sharedResponseResources: SharedResponseResource[];
107
+ }
108
+
109
+ interface OperationResource {
110
+ entityName: string;
111
+ definition: HttpOperationDefinition;
112
+ outputDir: string;
113
+ outputRequestFile: string;
114
+ outputResponseFile: string;
115
+ outputRequestValidationFile: string;
116
+ outputResponseValidationFile: string;
117
+ // ... more output file paths
118
+ }
119
+
120
+ interface SharedResponseResource {
121
+ name: string;
122
+ definition: HttpResponseDefinition;
123
+ outputDir: string;
124
+ outputFileName: string;
125
+ outputFile: string;
126
+ }
127
+ ```
128
+
129
+ ### Using Resources
130
+
131
+ ```typescript
132
+ export default class MyPlugin extends BasePlugin {
133
+ public name = "my-plugin";
134
+
135
+ public override generate(context: GeneratorContext): void {
136
+ // Iterate through entities
137
+ for (const [entityName, operations] of Object.entries(context.resources.entityResources)) {
138
+ // Generate entity-level code
139
+ this.generateEntityCode(entityName, operations, context);
140
+
141
+ // Generate operation-level code
142
+ for (const operation of operations) {
143
+ this.generateOperationCode(operation, context);
144
+ }
145
+ }
146
+
147
+ // Use shared responses
148
+ for (const sharedResponse of context.resources.sharedResponseResources) {
149
+ this.generateSharedResponse(sharedResponse, context);
150
+ }
151
+ }
152
+ }
153
+ ```
154
+
155
+ ## Template System
156
+
157
+ ### Template Structure
158
+
159
+ Templates should be placed in a `templates/` directory within your plugin:
160
+
161
+ ```
162
+ my-plugin/
163
+ ├── src/
164
+ │ ├── index.ts
165
+ │ ├── MyGenerator.ts
166
+ │ └── templates/
167
+ │ ├── Client.ejs
168
+ │ └── Router.ejs
169
+ └── package.json
170
+ ```
171
+
172
+ ### Template Usage
173
+
174
+ Templates receive context data and can use EJS syntax:
175
+
176
+ ```ejs
177
+ <%# templates/Client.ejs %>
178
+ import { ApiClient } from "<%= coreDir %>";
179
+
180
+ export class <%= pascalCaseEntityName %>Client extends ApiClient {
181
+ <% for (const operation of operations) { %>
182
+ public <%= operation.operationId %>() {
183
+ // Generated method
184
+ }
185
+ <% } %>
186
+ }
187
+ ```
188
+
189
+ ## Plugin Lifecycle
190
+
191
+ ### Lifecycle Hooks
192
+
193
+ ```typescript
194
+ interface TypeWeaverPlugin {
195
+ /**
196
+ * Initialize the plugin
197
+ * Called before any generation happens
198
+ */
199
+ initialize?(context: PluginContext): Promise<void> | void;
200
+
201
+ /**
202
+ * Collect and transform resources
203
+ * Allows plugins to modify the resource collection
204
+ */
205
+ collectResources?(
206
+ resources: GetResourcesResult
207
+ ): Promise<GetResourcesResult> | GetResourcesResult;
208
+
209
+ /**
210
+ * Main generation logic
211
+ * Called with all resources and utilities
212
+ */
213
+ generate?(context: GeneratorContext): Promise<void> | void;
214
+
215
+ /**
216
+ * Finalize the plugin
217
+ * Called after all generation is complete
218
+ */
219
+ finalize?(context: PluginContext): Promise<void> | void;
220
+ }
221
+ ```
222
+
223
+ ## Built-in Plugins
224
+
225
+ TypeWeaver includes several built-in plugins:
226
+
227
+ - **@rexeus/typeweaver-types** - TypeScript types and Zod validators
228
+ - **@rexeus/typeweaver-clients** - HTTP API clients
229
+ - **@rexeus/typeweaver-aws-cdk** - AWS CDK constructs and HTTP API routers
230
+
231
+ ## Best Practices
232
+
233
+ ### File Organization
234
+
235
+ - Use consistent naming patterns for generated files
236
+ - Organize output by entity or feature
237
+ - Include proper imports and exports
238
+
239
+ ### Template Design
240
+
241
+ - Keep templates focused and modular
242
+ - Use consistent variable naming
243
+ - Include proper TypeScript types in generated code
244
+
245
+ ### Error Handling
246
+
247
+ - Validate input data before generation
248
+ - Provide clear error messages
249
+ - Handle edge cases gracefully
250
+
251
+ ```typescript
252
+ export default class MyPlugin extends BasePlugin {
253
+ public name = "my-plugin";
254
+
255
+ public override generate(context: GeneratorContext): void {
256
+ try {
257
+ // Generation logic
258
+ } catch (error) {
259
+ throw new Error(`Plugin ${this.name} failed: ${error.message}`);
260
+ }
261
+ }
262
+ }
263
+ ```
264
+
265
+ ## License
266
+
267
+ ISC © Dennis Wentzien 2025
@@ -0,0 +1,263 @@
1
+ import { IHttpOperationDefinition, IHttpResponseDefinition } from '@rexeus/typeweaver-core';
2
+
3
+ type GetResourcesResult = {
4
+ entityResources: EntityResources;
5
+ sharedResponseResources: SharedResponseResource[];
6
+ };
7
+ type ExtendedResponseDefinition = IHttpResponseDefinition & {
8
+ statusCodeName: string;
9
+ };
10
+ type EntityName = string;
11
+ type OperationResource = {
12
+ sourceDir: string;
13
+ sourceFile: string;
14
+ sourceFileName: string;
15
+ definition: Omit<IHttpOperationDefinition, "responses"> & {
16
+ responses: ExtendedResponseDefinition[];
17
+ };
18
+ outputDir: string;
19
+ entityName: EntityName;
20
+ outputRequestFile: string;
21
+ outputRequestFileName: string;
22
+ outputResponseFile: string;
23
+ outputResponseFileName: string;
24
+ outputRequestValidationFile: string;
25
+ outputRequestValidationFileName: string;
26
+ outputResponseValidationFile: string;
27
+ outputResponseValidationFileName: string;
28
+ outputClientFile: string;
29
+ outputClientFileName: string;
30
+ };
31
+ type EntityResources = Record<EntityName, OperationResource[]>;
32
+ type SharedResponseResource = IHttpResponseDefinition & {
33
+ isShared: true;
34
+ sourceDir: string;
35
+ sourceFile: string;
36
+ sourceFileName: string;
37
+ outputFile: string;
38
+ outputFileName: string;
39
+ outputDir: string;
40
+ };
41
+
42
+ /**
43
+ * Configuration for a TypeWeaver plugin
44
+ */
45
+ type PluginConfig = Record<string, unknown>;
46
+ /**
47
+ * Context provided to plugins during initialization and finalization
48
+ */
49
+ interface PluginContext {
50
+ outputDir: string;
51
+ inputDir: string;
52
+ config: PluginConfig;
53
+ }
54
+ /**
55
+ * Context provided to plugins during generation
56
+ */
57
+ interface GeneratorContext extends PluginContext {
58
+ resources: GetResourcesResult;
59
+ templateDir: string;
60
+ coreDir: string;
61
+ writeFile: (relativePath: string, content: string) => void;
62
+ renderTemplate: (templatePath: string, data: unknown) => string;
63
+ addGeneratedFile: (relativePath: string) => void;
64
+ getGeneratedFiles: () => string[];
65
+ }
66
+ /**
67
+ * Plugin metadata
68
+ */
69
+ interface PluginMetadata {
70
+ name: string;
71
+ }
72
+ /**
73
+ * TypeWeaver plugin interface
74
+ */
75
+ interface TypeWeaverPlugin extends PluginMetadata {
76
+ /**
77
+ * Initialize the plugin
78
+ * Called before any generation happens
79
+ */
80
+ initialize?(context: PluginContext): Promise<void> | void;
81
+ /**
82
+ * Collect and transform resources
83
+ * Allows plugins to modify the resource collection
84
+ */
85
+ collectResources?(resources: GetResourcesResult): Promise<GetResourcesResult> | GetResourcesResult;
86
+ /**
87
+ * Main generation logic
88
+ * Called with all resources and utilities
89
+ */
90
+ generate?(context: GeneratorContext): Promise<void> | void;
91
+ /**
92
+ * Finalize the plugin
93
+ * Called after all generation is complete
94
+ */
95
+ finalize?(context: PluginContext): Promise<void> | void;
96
+ }
97
+ /**
98
+ * Plugin constructor type
99
+ */
100
+ type PluginConstructor = new (config?: PluginConfig) => TypeWeaverPlugin;
101
+ /**
102
+ * Plugin module export
103
+ */
104
+ interface PluginModule {
105
+ default: PluginConstructor;
106
+ }
107
+ /**
108
+ * Plugin registration entry
109
+ */
110
+ interface PluginRegistration {
111
+ name: string;
112
+ plugin: TypeWeaverPlugin;
113
+ config?: PluginConfig;
114
+ }
115
+ /**
116
+ * TypeWeaver configuration
117
+ */
118
+ interface TypeWeaverConfig {
119
+ input: string;
120
+ output: string;
121
+ plugins?: Array<string | [string, PluginConfig]>;
122
+ prettier?: boolean;
123
+ clean?: boolean;
124
+ }
125
+ /**
126
+ * Plugin loading error
127
+ */
128
+ declare class PluginLoadError extends Error {
129
+ pluginName: string;
130
+ constructor(pluginName: string, message: string);
131
+ }
132
+ /**
133
+ * Plugin dependency error
134
+ */
135
+ declare class PluginDependencyError extends Error {
136
+ pluginName: string;
137
+ missingDependency: string;
138
+ constructor(pluginName: string, missingDependency: string);
139
+ }
140
+
141
+ /**
142
+ * Base class for TypeWeaver plugins
143
+ * Provides default implementations and common utilities
144
+ */
145
+ declare abstract class BasePlugin implements TypeWeaverPlugin {
146
+ abstract name: string;
147
+ description?: string;
148
+ author?: string;
149
+ depends?: string[];
150
+ protected config: PluginConfig;
151
+ constructor(config?: PluginConfig);
152
+ /**
153
+ * Default implementation - override in subclasses if needed
154
+ */
155
+ initialize(context: PluginContext): Promise<void>;
156
+ /**
157
+ * Default implementation - override in subclasses if needed
158
+ */
159
+ collectResources(resources: GetResourcesResult): GetResourcesResult;
160
+ /**
161
+ * Main generation logic - must be implemented by subclasses
162
+ */
163
+ abstract generate(context: GeneratorContext): Promise<void> | void;
164
+ /**
165
+ * Default implementation - override in subclasses if needed
166
+ */
167
+ finalize(context: PluginContext): Promise<void>;
168
+ /**
169
+ * Copy lib files from plugin package to generated lib folder
170
+ */
171
+ protected copyLibFiles(context: GeneratorContext, libSourceDir: string, libNamespace: string): void;
172
+ }
173
+
174
+ /**
175
+ * Base class for template-based generator plugins
176
+ * Provides utilities for working with EJS templates
177
+ */
178
+ declare abstract class BaseTemplatePlugin extends BasePlugin {
179
+ /**
180
+ * Render an EJS template with the given data
181
+ */
182
+ protected renderTemplate(templatePath: string, data: unknown): string;
183
+ /**
184
+ * Write a file relative to the output directory
185
+ */
186
+ protected writeFile(context: GeneratorContext, relativePath: string, content: string): void;
187
+ /**
188
+ * Ensure a directory exists
189
+ */
190
+ protected ensureDir(context: GeneratorContext, relativePath: string): void;
191
+ /**
192
+ * Get the template path for this plugin
193
+ */
194
+ protected getTemplatePath(context: GeneratorContext, templateName: string): string;
195
+ }
196
+
197
+ /**
198
+ * Registry for managing TypeWeaver plugins
199
+ */
200
+ declare class PluginRegistry {
201
+ private plugins;
202
+ constructor();
203
+ /**
204
+ * Register a plugin
205
+ */
206
+ register(plugin: TypeWeaverPlugin, config?: unknown): void;
207
+ /**
208
+ * Get a registered plugin
209
+ */
210
+ get(name: string): PluginRegistration | undefined;
211
+ /**
212
+ * Get all registered plugins
213
+ */
214
+ getAll(): PluginRegistration[];
215
+ /**
216
+ * Check if a plugin is registered
217
+ */
218
+ has(name: string): boolean;
219
+ /**
220
+ * Clear all registered plugins (except required ones)
221
+ */
222
+ clear(): void;
223
+ }
224
+
225
+ /**
226
+ * Builder for plugin contexts
227
+ */
228
+ declare class PluginContextBuilder {
229
+ private generatedFiles;
230
+ /**
231
+ * Create a basic plugin context
232
+ */
233
+ createPluginContext(params: {
234
+ outputDir: string;
235
+ inputDir: string;
236
+ config: PluginConfig;
237
+ }): PluginContext;
238
+ /**
239
+ * Create a generator context with utilities
240
+ */
241
+ createGeneratorContext(params: {
242
+ outputDir: string;
243
+ inputDir: string;
244
+ config: PluginConfig;
245
+ resources: GetResourcesResult;
246
+ templateDir: string;
247
+ coreDir: string;
248
+ }): GeneratorContext;
249
+ /**
250
+ * Get all generated files
251
+ */
252
+ getGeneratedFiles(): string[];
253
+ /**
254
+ * Clear generated files tracking
255
+ */
256
+ clearGeneratedFiles(): void;
257
+ }
258
+
259
+ declare class Path {
260
+ static relative(from: string, to: string): string;
261
+ }
262
+
263
+ export { BasePlugin, BaseTemplatePlugin, type EntityName, type EntityResources, type ExtendedResponseDefinition, type GeneratorContext, type GetResourcesResult, type OperationResource, Path, type PluginConfig, type PluginConstructor, type PluginContext, PluginContextBuilder, PluginDependencyError, PluginLoadError, type PluginMetadata, type PluginModule, type PluginRegistration, PluginRegistry, type SharedResponseResource, type TypeWeaverConfig, type TypeWeaverPlugin };