@rexeus/typeweaver-aws-cdk 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 +264 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +238 -0
- package/dist/lib/AwsHttpApiGatewayRouter.ts +10 -0
- package/dist/lib/index.ts +1 -0
- package/dist/templates/HttpApiRouter.ejs +24 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# @rexeus/typeweaver-aws-cdk
|
|
2
|
+
|
|
3
|
+
AWS CDK constructs and deployment utilities for TypeWeaver APIs.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This plugin generates AWS CDK constructs and HTTP API Gateway routers from your TypeWeaver API
|
|
8
|
+
definitions, making it easy to deploy type-safe APIs to AWS.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @rexeus/typeweaver-aws-cdk
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Peer Dependencies:**
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @rexeus/typeweaver-core @rexeus/typeweaver-gen
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### CLI
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx typeweaver generate --input ./api/definitions --output ./api/generated --plugins aws-cdk
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Configuration File
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
// typeweaver.config.js
|
|
34
|
+
export default {
|
|
35
|
+
input: "./api/definitions",
|
|
36
|
+
output: "./api/generated",
|
|
37
|
+
plugins: ["aws-cdk"],
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Generated Output
|
|
42
|
+
|
|
43
|
+
This plugin generates HTTP API Gateway routers for each entity in your API definitions.
|
|
44
|
+
|
|
45
|
+
### Example Generated Router
|
|
46
|
+
|
|
47
|
+
For an API definition with a `users` entity, the plugin generates:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// UsersHttpApiRouter.ts
|
|
51
|
+
import { HttpMethod } from "@rexeus/typeweaver-core";
|
|
52
|
+
|
|
53
|
+
export const UsersHttpApiRouter = {
|
|
54
|
+
"/users": [HttpMethod.POST],
|
|
55
|
+
"/users/{userId}": [HttpMethod.GET, HttpMethod.PUT, HttpMethod.DELETE],
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Router Structure
|
|
60
|
+
|
|
61
|
+
The generated routers provide:
|
|
62
|
+
|
|
63
|
+
- **Route Definitions** - Express-style paths converted to API Gateway format
|
|
64
|
+
- **HTTP Methods** - Supported methods for each route
|
|
65
|
+
- **Parameter Mapping** - Path parameters (`:param` → `{param}`)
|
|
66
|
+
|
|
67
|
+
### Path Conversion
|
|
68
|
+
|
|
69
|
+
The plugin automatically converts Express-style paths to API Gateway format:
|
|
70
|
+
|
|
71
|
+
- `/users/:userId` → `/users/{userId}`
|
|
72
|
+
- `/users/:userId/posts/:postId` → `/users/{userId}/posts/{postId}`
|
|
73
|
+
|
|
74
|
+
## AWS CDK Integration
|
|
75
|
+
|
|
76
|
+
Use the generated routers in your CDK stacks:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { HttpApi, HttpMethod } from "@aws-cdk/aws-apigatewayv2-alpha";
|
|
80
|
+
import { UsersHttpApiRouter, PostsHttpApiRouter } from "./api/generated";
|
|
81
|
+
|
|
82
|
+
export class ApiStack extends Stack {
|
|
83
|
+
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
84
|
+
super(scope, id, props);
|
|
85
|
+
|
|
86
|
+
const api = new HttpApi(this, "TypeWeaverApi");
|
|
87
|
+
|
|
88
|
+
// Add routes from generated routers
|
|
89
|
+
Object.entries(UsersHttpApiRouter).forEach(([path, methods]) => {
|
|
90
|
+
methods.forEach(method => {
|
|
91
|
+
api.addRoutes({
|
|
92
|
+
path,
|
|
93
|
+
methods: [method],
|
|
94
|
+
integration: new HttpLambdaIntegration("UsersIntegration", usersHandler),
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
Object.entries(PostsHttpApiRouter).forEach(([path, methods]) => {
|
|
100
|
+
methods.forEach(method => {
|
|
101
|
+
api.addRoutes({
|
|
102
|
+
path,
|
|
103
|
+
methods: [method],
|
|
104
|
+
integration: new HttpLambdaIntegration("PostsIntegration", postsHandler),
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Complete AWS Deployment Example
|
|
113
|
+
|
|
114
|
+
### 1. Define Your API
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// api/definitions/users/GetUserDefinition.ts
|
|
118
|
+
import { HttpOperationDefinition, HttpMethod, HttpStatusCode } from "@rexeus/typeweaver-core";
|
|
119
|
+
import { z } from "zod/v4";
|
|
120
|
+
|
|
121
|
+
export default new HttpOperationDefinition({
|
|
122
|
+
operationId: "GetUser",
|
|
123
|
+
method: HttpMethod.GET,
|
|
124
|
+
path: "/users/:userId",
|
|
125
|
+
request: {
|
|
126
|
+
param: z.object({
|
|
127
|
+
userId: z.string(),
|
|
128
|
+
}),
|
|
129
|
+
},
|
|
130
|
+
responses: [
|
|
131
|
+
{
|
|
132
|
+
statusCode: HttpStatusCode.OK,
|
|
133
|
+
body: z.object({
|
|
134
|
+
id: z.string(),
|
|
135
|
+
name: z.string(),
|
|
136
|
+
email: z.email(),
|
|
137
|
+
}),
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 2. Generate Code
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npx typeweaver generate --input ./api/definitions --output ./api/generated --plugins aws-cdk,types,clients
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 3. Create CDK Stack
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// lib/api-stack.ts
|
|
153
|
+
import { Stack, StackProps } from "aws-cdk-lib";
|
|
154
|
+
import { Construct } from "constructs";
|
|
155
|
+
import { HttpApi } from "@aws-cdk/aws-apigatewayv2-alpha";
|
|
156
|
+
import { HttpLambdaIntegration } from "@aws-cdk/aws-apigatewayv2-integrations-alpha";
|
|
157
|
+
import { UsersHttpApiRouter } from "../api/generated/users/UsersHttpApiRouter";
|
|
158
|
+
|
|
159
|
+
export class ApiStack extends Stack {
|
|
160
|
+
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
161
|
+
super(scope, id, props);
|
|
162
|
+
|
|
163
|
+
const api = new HttpApi(this, "TypeWeaverApi");
|
|
164
|
+
|
|
165
|
+
// Create Lambda handler (your implementation)
|
|
166
|
+
const usersHandler = new Function(this, "UsersHandler", {
|
|
167
|
+
// Lambda configuration
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Add routes using generated router
|
|
171
|
+
Object.entries(UsersHttpApiRouter).forEach(([path, methods]) => {
|
|
172
|
+
methods.forEach(method => {
|
|
173
|
+
api.addRoutes({
|
|
174
|
+
path,
|
|
175
|
+
methods: [method],
|
|
176
|
+
integration: new HttpLambdaIntegration("UsersIntegration", usersHandler),
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 4. Deploy
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
cdk deploy
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Features
|
|
191
|
+
|
|
192
|
+
### Route Organization
|
|
193
|
+
|
|
194
|
+
- **Entity-based routing** - Each entity gets its own router file
|
|
195
|
+
- **Method grouping** - Routes grouped by HTTP method support
|
|
196
|
+
- **Parameter extraction** - Path parameters automatically identified
|
|
197
|
+
|
|
198
|
+
### Type Safety
|
|
199
|
+
|
|
200
|
+
- **Generated types** - Work seamlessly with other TypeWeaver plugins
|
|
201
|
+
- **CDK integration** - Type-safe AWS CDK constructs
|
|
202
|
+
- **Validation** - Runtime validation via TypeWeaver Core
|
|
203
|
+
|
|
204
|
+
### Development Workflow
|
|
205
|
+
|
|
206
|
+
- **Hot reload** - Regenerate routes when API definitions change
|
|
207
|
+
- **Version control** - Generated files can be committed for review
|
|
208
|
+
- **Testing** - Generated routes can be unit tested
|
|
209
|
+
|
|
210
|
+
## Plugin Architecture
|
|
211
|
+
|
|
212
|
+
This plugin extends the TypeWeaver plugin system:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { BasePlugin, type GeneratorContext } from "@rexeus/typeweaver-gen";
|
|
216
|
+
|
|
217
|
+
export default class AwsCdkPlugin extends BasePlugin {
|
|
218
|
+
public name = "aws-cdk";
|
|
219
|
+
|
|
220
|
+
public override generate(context: GeneratorContext): void {
|
|
221
|
+
// Generates HTTP API routers for each entity
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Best Practices
|
|
227
|
+
|
|
228
|
+
### CDK Integration
|
|
229
|
+
|
|
230
|
+
- Use the generated routers as single source of truth for API routes
|
|
231
|
+
- Combine with other TypeWeaver plugins for complete type safety
|
|
232
|
+
- Version generated files in source control
|
|
233
|
+
|
|
234
|
+
### Deployment
|
|
235
|
+
|
|
236
|
+
- Generate code before CDK synthesis
|
|
237
|
+
- Use CDK context for environment-specific configuration
|
|
238
|
+
- Implement proper error handling in Lambda functions
|
|
239
|
+
|
|
240
|
+
### Monitoring
|
|
241
|
+
|
|
242
|
+
- Add CloudWatch metrics for generated routes
|
|
243
|
+
- Implement distributed tracing
|
|
244
|
+
- Monitor API Gateway throttling and errors
|
|
245
|
+
|
|
246
|
+
## Troubleshooting
|
|
247
|
+
|
|
248
|
+
### Common Issues
|
|
249
|
+
|
|
250
|
+
**Route conflicts**: Ensure API definitions don't have conflicting paths **Method mismatches**:
|
|
251
|
+
Verify HTTP methods in definitions match usage **Parameter mapping**: Check path parameter names are
|
|
252
|
+
consistent
|
|
253
|
+
|
|
254
|
+
### Debug Mode
|
|
255
|
+
|
|
256
|
+
Enable verbose logging during generation:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
DEBUG=typeweaver:* npx typeweaver generate --plugins aws-cdk
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## License
|
|
263
|
+
|
|
264
|
+
ISC © Dennis Wentzien 2025
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { BasePlugin } from '@rexeus/typeweaver-gen';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
function getDefaultExportFromCjs (x) {
|
|
6
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
var Case$2 = {exports: {}};
|
|
10
|
+
|
|
11
|
+
var Case$1 = Case$2.exports;
|
|
12
|
+
|
|
13
|
+
var hasRequiredCase;
|
|
14
|
+
|
|
15
|
+
function requireCase () {
|
|
16
|
+
if (hasRequiredCase) return Case$2.exports;
|
|
17
|
+
hasRequiredCase = 1;
|
|
18
|
+
(function (module) {
|
|
19
|
+
/*! Case - v1.6.2 - 2020-03-24
|
|
20
|
+
* Copyright (c) 2020 Nathan Bubna; Licensed MIT, GPL */
|
|
21
|
+
(function() {
|
|
22
|
+
var unicodes = function(s, prefix) {
|
|
23
|
+
prefix = prefix || "";
|
|
24
|
+
return s.replace(/(^|-)/g, "$1\\u" + prefix).replace(/,/g, "\\u" + prefix);
|
|
25
|
+
}, basicSymbols = unicodes("20-26,28-2F,3A-40,5B-60,7B-7E,A0-BF,D7,F7", "00"), baseLowerCase = "a-z" + unicodes("DF-F6,F8-FF", "00"), baseUpperCase = "A-Z" + unicodes("C0-D6,D8-DE", "00"), improperInTitle = "A|An|And|As|At|But|By|En|For|If|In|Of|On|Or|The|To|Vs?\\.?|Via", regexps = function(symbols, lowers, uppers, impropers) {
|
|
26
|
+
symbols = symbols || basicSymbols;
|
|
27
|
+
lowers = lowers || baseLowerCase;
|
|
28
|
+
uppers = uppers || baseUpperCase;
|
|
29
|
+
impropers = impropers || improperInTitle;
|
|
30
|
+
return {
|
|
31
|
+
capitalize: new RegExp("(^|[" + symbols + "])([" + lowers + "])", "g"),
|
|
32
|
+
pascal: new RegExp("(^|[" + symbols + "])+([" + lowers + uppers + "])", "g"),
|
|
33
|
+
fill: new RegExp("[" + symbols + "]+(.|$)", "g"),
|
|
34
|
+
sentence: new RegExp('(^\\s*|[\\?\\!\\.]+"?\\s+"?|,\\s+")([' + lowers + "])", "g"),
|
|
35
|
+
improper: new RegExp("\\b(" + impropers + ")\\b", "g"),
|
|
36
|
+
relax: new RegExp("([^" + uppers + "])([" + uppers + "]*)([" + uppers + "])(?=[^" + uppers + "]|$)", "g"),
|
|
37
|
+
upper: new RegExp("^[^" + lowers + "]+$"),
|
|
38
|
+
hole: /[^\s]\s[^\s]/,
|
|
39
|
+
apostrophe: /'/g,
|
|
40
|
+
room: new RegExp("[" + symbols + "]")
|
|
41
|
+
};
|
|
42
|
+
}, re = regexps(), _ = {
|
|
43
|
+
re,
|
|
44
|
+
unicodes,
|
|
45
|
+
regexps,
|
|
46
|
+
types: [],
|
|
47
|
+
up: String.prototype.toUpperCase,
|
|
48
|
+
low: String.prototype.toLowerCase,
|
|
49
|
+
cap: function(s) {
|
|
50
|
+
return _.up.call(s.charAt(0)) + s.slice(1);
|
|
51
|
+
},
|
|
52
|
+
decap: function(s) {
|
|
53
|
+
return _.low.call(s.charAt(0)) + s.slice(1);
|
|
54
|
+
},
|
|
55
|
+
deapostrophe: function(s) {
|
|
56
|
+
return s.replace(re.apostrophe, "");
|
|
57
|
+
},
|
|
58
|
+
fill: function(s, fill, deapostrophe) {
|
|
59
|
+
if (fill != null) {
|
|
60
|
+
s = s.replace(re.fill, function(m, next) {
|
|
61
|
+
return next ? fill + next : "";
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (deapostrophe) {
|
|
65
|
+
s = _.deapostrophe(s);
|
|
66
|
+
}
|
|
67
|
+
return s;
|
|
68
|
+
},
|
|
69
|
+
prep: function(s, fill, pascal, upper) {
|
|
70
|
+
s = s == null ? "" : s + "";
|
|
71
|
+
if (!upper && re.upper.test(s)) {
|
|
72
|
+
s = _.low.call(s);
|
|
73
|
+
}
|
|
74
|
+
if (!fill && !re.hole.test(s)) {
|
|
75
|
+
var holey = _.fill(s, " ");
|
|
76
|
+
if (re.hole.test(holey)) {
|
|
77
|
+
s = holey;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (!pascal && !re.room.test(s)) {
|
|
81
|
+
s = s.replace(re.relax, _.relax);
|
|
82
|
+
}
|
|
83
|
+
return s;
|
|
84
|
+
},
|
|
85
|
+
relax: function(m, before, acronym, caps) {
|
|
86
|
+
return before + " " + (acronym ? acronym + " " : "") + caps;
|
|
87
|
+
}
|
|
88
|
+
}, Case = {
|
|
89
|
+
_,
|
|
90
|
+
of: function(s) {
|
|
91
|
+
for (var i = 0, m = _.types.length; i < m; i++) {
|
|
92
|
+
if (Case[_.types[i]].apply(Case, arguments) === s) {
|
|
93
|
+
return _.types[i];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
flip: function(s) {
|
|
98
|
+
return s.replace(/\w/g, function(l) {
|
|
99
|
+
return (l == _.up.call(l) ? _.low : _.up).call(l);
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
random: function(s) {
|
|
103
|
+
return s.replace(/\w/g, function(l) {
|
|
104
|
+
return (Math.round(Math.random()) ? _.up : _.low).call(l);
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
type: function(type2, fn) {
|
|
108
|
+
Case[type2] = fn;
|
|
109
|
+
_.types.push(type2);
|
|
110
|
+
}
|
|
111
|
+
}, types = {
|
|
112
|
+
lower: function(s, fill, deapostrophe) {
|
|
113
|
+
return _.fill(_.low.call(_.prep(s, fill)), fill, deapostrophe);
|
|
114
|
+
},
|
|
115
|
+
snake: function(s) {
|
|
116
|
+
return Case.lower(s, "_", true);
|
|
117
|
+
},
|
|
118
|
+
constant: function(s) {
|
|
119
|
+
return Case.upper(s, "_", true);
|
|
120
|
+
},
|
|
121
|
+
camel: function(s) {
|
|
122
|
+
return _.decap(Case.pascal(s));
|
|
123
|
+
},
|
|
124
|
+
kebab: function(s) {
|
|
125
|
+
return Case.lower(s, "-", true);
|
|
126
|
+
},
|
|
127
|
+
upper: function(s, fill, deapostrophe) {
|
|
128
|
+
return _.fill(_.up.call(_.prep(s, fill, false, true)), fill, deapostrophe);
|
|
129
|
+
},
|
|
130
|
+
capital: function(s, fill, deapostrophe) {
|
|
131
|
+
return _.fill(_.prep(s).replace(re.capitalize, function(m, border, letter) {
|
|
132
|
+
return border + _.up.call(letter);
|
|
133
|
+
}), fill, deapostrophe);
|
|
134
|
+
},
|
|
135
|
+
header: function(s) {
|
|
136
|
+
return Case.capital(s, "-", true);
|
|
137
|
+
},
|
|
138
|
+
pascal: function(s) {
|
|
139
|
+
return _.fill(_.prep(s, false, true).replace(re.pascal, function(m, border, letter) {
|
|
140
|
+
return _.up.call(letter);
|
|
141
|
+
}), "", true);
|
|
142
|
+
},
|
|
143
|
+
title: function(s) {
|
|
144
|
+
return Case.capital(s).replace(re.improper, function(small, p, i, s2) {
|
|
145
|
+
return i > 0 && i < s2.lastIndexOf(" ") ? _.low.call(small) : small;
|
|
146
|
+
});
|
|
147
|
+
},
|
|
148
|
+
sentence: function(s, names, abbreviations) {
|
|
149
|
+
s = Case.lower(s).replace(re.sentence, function(m, prelude, letter) {
|
|
150
|
+
return prelude + _.up.call(letter);
|
|
151
|
+
});
|
|
152
|
+
if (names) {
|
|
153
|
+
names.forEach(function(name) {
|
|
154
|
+
s = s.replace(new RegExp("\\b" + Case.lower(name) + "\\b", "g"), _.cap);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
if (abbreviations) {
|
|
158
|
+
abbreviations.forEach(function(abbr) {
|
|
159
|
+
s = s.replace(new RegExp("(\\b" + Case.lower(abbr) + "\\. +)(\\w)"), function(m, abbrAndSpace, letter) {
|
|
160
|
+
return abbrAndSpace + _.low.call(letter);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return s;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
types.squish = types.pascal;
|
|
168
|
+
Case.default = Case;
|
|
169
|
+
for (var type in types) {
|
|
170
|
+
Case.type(type, types[type]);
|
|
171
|
+
}
|
|
172
|
+
var define = typeof define === "function" ? define : function() {
|
|
173
|
+
};
|
|
174
|
+
define(module.exports ? module.exports = Case : this.Case = Case);
|
|
175
|
+
}).call(Case$1);
|
|
176
|
+
} (Case$2));
|
|
177
|
+
return Case$2.exports;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
var CaseExports = requireCase();
|
|
181
|
+
var Case = /*@__PURE__*/getDefaultExportFromCjs(CaseExports);
|
|
182
|
+
|
|
183
|
+
const __dirname$1 = path.dirname(fileURLToPath(import.meta.url));
|
|
184
|
+
class HttpApiRouterGenerator {
|
|
185
|
+
static generate(context) {
|
|
186
|
+
const templateFile = path.join(__dirname$1, "templates", "HttpApiRouter.ejs");
|
|
187
|
+
for (const [entityName, operationResources] of Object.entries(
|
|
188
|
+
context.resources.entityResources
|
|
189
|
+
)) {
|
|
190
|
+
this.writeHttpApiRoutes(entityName, templateFile, operationResources, context);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
static writeHttpApiRoutes(entityName, templateFile, operationResources, context) {
|
|
194
|
+
const routes = {};
|
|
195
|
+
const pascalCaseEntityName = Case.pascal(entityName);
|
|
196
|
+
const outputDir = operationResources[0].outputDir;
|
|
197
|
+
const outputFile = path.join(
|
|
198
|
+
outputDir,
|
|
199
|
+
`${pascalCaseEntityName}HttpApiRouter.ts`
|
|
200
|
+
);
|
|
201
|
+
for (const operation of operationResources) {
|
|
202
|
+
const path2 = this.createRoutePath(operation.definition.path);
|
|
203
|
+
if (!routes[path2]) {
|
|
204
|
+
routes[path2] = [];
|
|
205
|
+
}
|
|
206
|
+
routes[path2].push(operation.definition.method);
|
|
207
|
+
}
|
|
208
|
+
const content = context.renderTemplate(templateFile, {
|
|
209
|
+
entityName,
|
|
210
|
+
pascalCaseEntityName,
|
|
211
|
+
routes,
|
|
212
|
+
coreDir: context.coreDir
|
|
213
|
+
});
|
|
214
|
+
const relativePath = path.relative(context.outputDir, outputFile);
|
|
215
|
+
context.writeFile(relativePath, content);
|
|
216
|
+
}
|
|
217
|
+
static createRoutePath(path2) {
|
|
218
|
+
const parts = path2.split("/").map((part) => {
|
|
219
|
+
if (part.startsWith(":")) {
|
|
220
|
+
return `{${part.slice(1)}}`;
|
|
221
|
+
}
|
|
222
|
+
return part;
|
|
223
|
+
});
|
|
224
|
+
return parts.join("/");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
229
|
+
class AwsCdkPlugin extends BasePlugin {
|
|
230
|
+
name = "aws-cdk";
|
|
231
|
+
generate(context) {
|
|
232
|
+
const libDir = path.join(__dirname, "lib");
|
|
233
|
+
this.copyLibFiles(context, libDir, "aws-cdk");
|
|
234
|
+
HttpApiRouterGenerator.generate(context);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export { AwsCdkPlugin as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./AwsHttpApiGatewayRouter";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { HttpMethod } from "<%= coreDir %>";
|
|
2
|
+
import {
|
|
3
|
+
type AwsHttpApiGatewayRoute,
|
|
4
|
+
AwsHttpApiGatewayRouter,
|
|
5
|
+
} from "../lib/aws-cdk";
|
|
6
|
+
|
|
7
|
+
export class <%= pascalCaseEntityName %>HttpApiRouter extends AwsHttpApiGatewayRouter {
|
|
8
|
+
private routes: AwsHttpApiGatewayRoute[] = [
|
|
9
|
+
<% for(const [path, methods] of Object.entries(routes)) { %>
|
|
10
|
+
{
|
|
11
|
+
path: "<%= path %>",
|
|
12
|
+
methods: [<% for(const method of methods) { %>HttpMethod.<%= method %>,<% } %>],
|
|
13
|
+
},
|
|
14
|
+
<% } %>
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
public constructor() {
|
|
18
|
+
super();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public getRoutes(): AwsHttpApiGatewayRoute[] {
|
|
22
|
+
return this.routes;
|
|
23
|
+
}
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rexeus/typeweaver-aws-cdk",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "AWS CDK constructs and deployment utilities for TypeWeaver APIs",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"package.json",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"api",
|
|
15
|
+
"spec",
|
|
16
|
+
"definition",
|
|
17
|
+
"typescript",
|
|
18
|
+
"zod",
|
|
19
|
+
"generator",
|
|
20
|
+
"typeweaver"
|
|
21
|
+
],
|
|
22
|
+
"author": "Dennis Wentzien <dw@rexeus.com>",
|
|
23
|
+
"license": "ISC",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/rexeus/typeweaver.git",
|
|
27
|
+
"directory": "packages/aws-cdk"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/rexeus/typeweaver/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/rexeus/typeweaver#readme",
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@rexeus/typeweaver-core": "*",
|
|
35
|
+
"@rexeus/typeweaver-gen": "*"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@rexeus/typeweaver-core": "0.0.1",
|
|
39
|
+
"@rexeus/typeweaver-gen": "0.0.1"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"typecheck": "tsc --noEmit",
|
|
43
|
+
"format": "prettier --write .",
|
|
44
|
+
"build": "pkgroll --clean-dist && cp -r ./src/templates ./dist/templates && cp -r ./src/lib ./dist/lib",
|
|
45
|
+
"preversion": "npm run build"
|
|
46
|
+
}
|
|
47
|
+
}
|