create-mock-api-from-types 1.0.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/README.md +220 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/router/routeBuilder.d.ts +4 -0
- package/dist/router/routeBuilder.d.ts.map +1 -0
- package/dist/router/routeBuilder.js +78 -0
- package/dist/router/routeBuilder.js.map +1 -0
- package/dist/schema.d.ts +2 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +2 -0
- package/dist/schema.js.map +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +87 -0
- package/dist/server.js.map +1 -0
- package/dist/store/dataStore.d.ts +16 -0
- package/dist/store/dataStore.d.ts.map +1 -0
- package/dist/store/dataStore.js +77 -0
- package/dist/store/dataStore.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/mockGenerator.d.ts +5 -0
- package/dist/utils/mockGenerator.d.ts.map +1 -0
- package/dist/utils/mockGenerator.js +84 -0
- package/dist/utils/mockGenerator.js.map +1 -0
- package/dist/utils/nameUtils.d.ts +5 -0
- package/dist/utils/nameUtils.d.ts.map +1 -0
- package/dist/utils/nameUtils.js +58 -0
- package/dist/utils/nameUtils.js.map +1 -0
- package/dist/utils/processArgs.d.ts +3 -0
- package/dist/utils/processArgs.d.ts.map +1 -0
- package/dist/utils/processArgs.js +31 -0
- package/dist/utils/processArgs.js.map +1 -0
- package/dist/utils/propGenerator.d.ts +2 -0
- package/dist/utils/propGenerator.d.ts.map +1 -0
- package/dist/utils/propGenerator.js +73 -0
- package/dist/utils/propGenerator.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Mock API
|
|
2
|
+
|
|
3
|
+
Generate a mock REST API server from TypeScript interfaces and object type aliases. Perfect for frontend development, testing, and prototyping—define your data shapes in TypeScript and get a fully functional API with realistic fake data powered by [Faker](https://fakerjs.dev/).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **TypeScript-first**: Define schemas as interfaces or object type aliases
|
|
8
|
+
- **Smart mock data**: Property names are matched to appropriate Faker generators (e.g. `email` → realistic emails, `price` → commerce prices)
|
|
9
|
+
- **Full REST API**: GET, POST, PUT, PATCH, DELETE with pagination support
|
|
10
|
+
- **Nested types**: References to other interfaces/types are resolved recursively
|
|
11
|
+
- **Multiple schemas**: Point to one or more schema files to build a complete API
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add mock-api
|
|
17
|
+
# or
|
|
18
|
+
npm install mock-api
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
1. Create a schema file (e.g. `schema.ts`):
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
interface User {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
email: string;
|
|
30
|
+
phone: string;
|
|
31
|
+
isActive: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type Product = {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
price: number;
|
|
38
|
+
inStock: boolean;
|
|
39
|
+
};
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
2. Start the mock API:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx mock-api schema.ts
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
3. Visit `http://localhost:3000` to see all available routes and collections.
|
|
49
|
+
|
|
50
|
+
## CLI Usage
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
mock-api <schemas...> [options]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Arguments
|
|
57
|
+
|
|
58
|
+
| Argument | Description |
|
|
59
|
+
| ---------- | ------------------------------------ |
|
|
60
|
+
| `<schemas...>` | One or more TypeScript schema file paths (required) |
|
|
61
|
+
|
|
62
|
+
### Options
|
|
63
|
+
|
|
64
|
+
| Option | Short | Default | Description |
|
|
65
|
+
| ------ | ----- | ------- | ------------------------------------ |
|
|
66
|
+
| `--port` | `-p` | `3000` | Port to run the server on |
|
|
67
|
+
| `--count` | `-c` | `10` | Number of mock items to generate per collection |
|
|
68
|
+
|
|
69
|
+
### Examples
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Basic usage
|
|
73
|
+
mock-api src/schema.ts
|
|
74
|
+
|
|
75
|
+
# Custom port and item count
|
|
76
|
+
mock-api schemas/*.ts -p 8080 -c 25
|
|
77
|
+
|
|
78
|
+
# Multiple schema files
|
|
79
|
+
mock-api src/models/user.ts src/models/product.ts
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Schema Definition
|
|
83
|
+
|
|
84
|
+
### Interfaces
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
interface User {
|
|
88
|
+
id: string;
|
|
89
|
+
name: string;
|
|
90
|
+
email: string;
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Object Type Aliases
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
type Product = {
|
|
98
|
+
id: string;
|
|
99
|
+
name: string;
|
|
100
|
+
price: number;
|
|
101
|
+
};
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Both interfaces and object type aliases (`type X = { ... }`) are supported. Only object-shaped types are used—primitives and union aliases (e.g. `type ID = string`) are ignored.
|
|
105
|
+
|
|
106
|
+
### Supported Types
|
|
107
|
+
|
|
108
|
+
- **Primitives**: `string`, `number`, `boolean`
|
|
109
|
+
- **Arrays**: `T[]` or `Array<T>`
|
|
110
|
+
- **Unions**: `'a' | 'b'` (picks a random option)
|
|
111
|
+
- **Nested types**: References to other interfaces or type aliases in the same project
|
|
112
|
+
- **Optional**: `| undefined` and `| null` are stripped when generating mocks
|
|
113
|
+
|
|
114
|
+
## API Endpoints
|
|
115
|
+
|
|
116
|
+
Each schema becomes a collection with the following REST endpoints:
|
|
117
|
+
|
|
118
|
+
| Method | Path | Description |
|
|
119
|
+
| ------ | ---- | ----------- |
|
|
120
|
+
| GET | `/` | List all collections and their endpoints |
|
|
121
|
+
| GET | `/:collection` | List items (supports `?page` and `?limit` for pagination) |
|
|
122
|
+
| GET | `/:collection/:id` | Get a single item by ID |
|
|
123
|
+
| POST | `/:collection` | Create a new item |
|
|
124
|
+
| PUT | `/:collection/:id` | Replace an item |
|
|
125
|
+
| PATCH | `/:collection/:id` | Partially update an item |
|
|
126
|
+
| DELETE | `/:collection/:id` | Delete an item |
|
|
127
|
+
|
|
128
|
+
### Route Naming
|
|
129
|
+
|
|
130
|
+
Interface/type names are converted to kebab-case and pluralized:
|
|
131
|
+
|
|
132
|
+
- `User` → `/users`
|
|
133
|
+
- `Product` → `/products`
|
|
134
|
+
- `OrderItem` → `/order-items`
|
|
135
|
+
|
|
136
|
+
### Response Format
|
|
137
|
+
|
|
138
|
+
**List (GET `/:collection`):**
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"data": [...],
|
|
143
|
+
"total": 10,
|
|
144
|
+
"page": 1,
|
|
145
|
+
"limit": 10
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Single item (GET `/:collection/:id`):**
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"id": "uuid-here",
|
|
154
|
+
"name": "John Doe",
|
|
155
|
+
"email": "john@example.com"
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Smart Property Generation
|
|
160
|
+
|
|
161
|
+
Property names are matched to Faker generators for realistic data:
|
|
162
|
+
|
|
163
|
+
| Pattern | Example |
|
|
164
|
+
| ------- | ------- |
|
|
165
|
+
| `id`, `*Id` | UUID |
|
|
166
|
+
| `email` | `user@example.com` |
|
|
167
|
+
| `name`, `firstName`, `lastName` | Person names |
|
|
168
|
+
| `phone`, `mobile` | Phone numbers |
|
|
169
|
+
| `password`, `secret` | Passwords |
|
|
170
|
+
| `address`, `city`, `state`, `zip`, `country` | Location data |
|
|
171
|
+
| `price`, `cost`, `amount` | Commerce prices |
|
|
172
|
+
| `createdAt`, `updatedAt`, `date` | ISO date strings |
|
|
173
|
+
| `description`, `content`, `body` | Lorem paragraphs |
|
|
174
|
+
| `url`, `image`, `avatar` | URLs |
|
|
175
|
+
| `isActive`, `isEnabled`, `verified` | Booleans |
|
|
176
|
+
| ...and more | See `propGenerator.ts` for full list |
|
|
177
|
+
|
|
178
|
+
Unmatched properties fall back to type-based generation (`string` → word, `number` → integer, etc.).
|
|
179
|
+
|
|
180
|
+
## Programmatic Usage
|
|
181
|
+
|
|
182
|
+
Use the library in your own Node.js application:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
import { createServer, startServer } from "mock-api";
|
|
186
|
+
import type { MockApiOptions } from "mock-api";
|
|
187
|
+
|
|
188
|
+
const options: MockApiOptions = {
|
|
189
|
+
schemaPaths: ["src/schema.ts"],
|
|
190
|
+
port: 3000,
|
|
191
|
+
count: 10,
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// Start a server (blocks)
|
|
195
|
+
startServer(options);
|
|
196
|
+
|
|
197
|
+
// Or create an Express app for custom use (e.g. testing)
|
|
198
|
+
const app = createServer(options);
|
|
199
|
+
// app is a standard Express application
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Development
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Install dependencies
|
|
206
|
+
pnpm install
|
|
207
|
+
|
|
208
|
+
# Build
|
|
209
|
+
pnpm run build
|
|
210
|
+
|
|
211
|
+
# Run with tsx (no build step)
|
|
212
|
+
pnpm run dev src/schema.ts
|
|
213
|
+
|
|
214
|
+
# Type check
|
|
215
|
+
pnpm run typecheck
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
ISC
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC1C,WAAW,CAAC,OAAO,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routeBuilder.d.ts","sourceRoot":"","sources":["../../src/router/routeBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAmBvD,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,CA4ExE"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
// parseQueryInt(value) parses the given value as an integer
|
|
3
|
+
// returns: value as an int if valid, undefined otherwise
|
|
4
|
+
function parseQueryInt(value) {
|
|
5
|
+
if (typeof value !== "string") {
|
|
6
|
+
return undefined;
|
|
7
|
+
}
|
|
8
|
+
const num = parseInt(value, 10);
|
|
9
|
+
return isNaN(num) ? undefined : num;
|
|
10
|
+
}
|
|
11
|
+
// buildRouter(collection, store) builds a router for the given collection and store
|
|
12
|
+
// returns: the router
|
|
13
|
+
// example: "users" -> "/users"
|
|
14
|
+
// "posts" -> "/posts"
|
|
15
|
+
// "comments" -> "/comments"
|
|
16
|
+
// "products" -> "/products"
|
|
17
|
+
// "orders" -> "/orders"
|
|
18
|
+
export function buildRouter(collection, store) {
|
|
19
|
+
const router = Router();
|
|
20
|
+
// GET /: paginated list of items
|
|
21
|
+
router.get("/", (req, res) => {
|
|
22
|
+
const page = parseQueryInt(req.query["page"]);
|
|
23
|
+
const limit = parseQueryInt(req.query["limit"]);
|
|
24
|
+
const data = store.getAll(collection, page, limit);
|
|
25
|
+
const total = store.count(collection);
|
|
26
|
+
res.json({ data, total, page: page ?? 1, limit: limit ?? total });
|
|
27
|
+
});
|
|
28
|
+
// GET /:id: get an item by id
|
|
29
|
+
router.get("/:id", (req, res) => {
|
|
30
|
+
const id = req.params["id"];
|
|
31
|
+
const item = store.getById(collection, id);
|
|
32
|
+
if (item === undefined) {
|
|
33
|
+
res.status(404).json({ error: "Not found" });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
res.json(item);
|
|
37
|
+
});
|
|
38
|
+
// POST /: create a new item
|
|
39
|
+
router.post("/", (req, res) => {
|
|
40
|
+
const body = req.body;
|
|
41
|
+
const item = store.create(collection, body);
|
|
42
|
+
res.status(201).json(item);
|
|
43
|
+
});
|
|
44
|
+
// PUT /:id: update an item by id
|
|
45
|
+
router.put("/:id", (req, res) => {
|
|
46
|
+
const id = req.params["id"];
|
|
47
|
+
const body = req.body;
|
|
48
|
+
const item = store.update(collection, id, body);
|
|
49
|
+
if (item === undefined) {
|
|
50
|
+
res.status(404).json({ error: "Not found" });
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
res.json(item);
|
|
54
|
+
});
|
|
55
|
+
// PATCH /:id: update an item by id
|
|
56
|
+
router.patch("/:id", (req, res) => {
|
|
57
|
+
const id = req.params["id"];
|
|
58
|
+
const body = req.body;
|
|
59
|
+
const item = store.patch(collection, id, body);
|
|
60
|
+
if (item === undefined) {
|
|
61
|
+
res.status(404).json({ error: "Not found" });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
res.json(item);
|
|
65
|
+
});
|
|
66
|
+
// DELETE /:id: delete an item by id
|
|
67
|
+
router.delete("/:id", (req, res) => {
|
|
68
|
+
const id = req.params["id"];
|
|
69
|
+
const deleted = store.delete(collection, id);
|
|
70
|
+
if (!deleted) {
|
|
71
|
+
res.status(404).json({ error: "Not found" });
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
res.status(204).send();
|
|
75
|
+
});
|
|
76
|
+
return router;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=routeBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routeBuilder.js","sourceRoot":"","sources":["../../src/router/routeBuilder.ts"],"names":[],"mappings":"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"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":""}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":""}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type Express } from "express";
|
|
2
|
+
import type { MockApiOptions } from "./types.js";
|
|
3
|
+
export declare function createServer(options: MockApiOptions): Express;
|
|
4
|
+
export declare function startServer(options: MockApiOptions): void;
|
|
5
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AACA,OAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAEhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAYjD,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CA2E7D;AAKD,wBAAgB,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAezD"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import express, {} from "express";
|
|
3
|
+
import { Node, Project } from "ts-morph";
|
|
4
|
+
import { DataStore } from "./store/dataStore.js";
|
|
5
|
+
import { buildRouter } from "./router/routeBuilder.js";
|
|
6
|
+
import { generateMockCollection, } from "./utils/mockGenerator.js";
|
|
7
|
+
import { toRoutePath, toCollectionKey } from "./utils/nameUtils.js";
|
|
8
|
+
// createServer(options) creates a new server with the given options
|
|
9
|
+
// options: the options for the server
|
|
10
|
+
// returns: the Express application (server)
|
|
11
|
+
export function createServer(options) {
|
|
12
|
+
const app = express();
|
|
13
|
+
const project = new Project({ skipAddingFilesFromTsConfig: true });
|
|
14
|
+
const store = new DataStore();
|
|
15
|
+
app.use(express.json());
|
|
16
|
+
// Add the source files to the project
|
|
17
|
+
for (const schemaPath of options.schemaPaths) {
|
|
18
|
+
project.addSourceFilesAtPaths(resolve(schemaPath));
|
|
19
|
+
}
|
|
20
|
+
const schemas = [];
|
|
21
|
+
for (const sf of project.getSourceFiles()) {
|
|
22
|
+
// Add all interfaces to the schemas
|
|
23
|
+
for (const iface of sf.getInterfaces()) {
|
|
24
|
+
schemas.push({ name: iface.getName(), schema: iface });
|
|
25
|
+
}
|
|
26
|
+
// Add all type aliases to the schemas
|
|
27
|
+
for (const typeAlias of sf.getTypeAliases()) {
|
|
28
|
+
const typeNode = typeAlias.getTypeNode();
|
|
29
|
+
if (typeNode !== undefined && Node.isTypeLiteral(typeNode)) {
|
|
30
|
+
schemas.push({ name: typeAlias.getName(), schema: typeNode });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (schemas.length === 0) {
|
|
35
|
+
console.warn("Warning: No interfaces or object type aliases found in the provided schema files");
|
|
36
|
+
}
|
|
37
|
+
const routes = [];
|
|
38
|
+
for (const { name, schema } of schemas) {
|
|
39
|
+
const routePath = toRoutePath(name);
|
|
40
|
+
const collectionKey = toCollectionKey(name);
|
|
41
|
+
const mockData = generateMockCollection(schema, project, options.count);
|
|
42
|
+
store.seed(collectionKey, mockData);
|
|
43
|
+
const router = buildRouter(collectionKey, store);
|
|
44
|
+
app.use(routePath, router);
|
|
45
|
+
routes.push({
|
|
46
|
+
path: routePath,
|
|
47
|
+
interface: name,
|
|
48
|
+
count: options.count,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// Root route lists all available collections
|
|
52
|
+
app.get("/", (_req, res) => {
|
|
53
|
+
res.json({
|
|
54
|
+
message: "Mock API is running",
|
|
55
|
+
routes: routes.map((r) => ({
|
|
56
|
+
collection: r.path,
|
|
57
|
+
interface: r.interface,
|
|
58
|
+
seeded: r.count,
|
|
59
|
+
endpoints: [
|
|
60
|
+
`GET ${r.path}`,
|
|
61
|
+
`GET ${r.path}/:id`,
|
|
62
|
+
`POST ${r.path}`,
|
|
63
|
+
`PUT ${r.path}/:id`,
|
|
64
|
+
`PATCH ${r.path}/:id`,
|
|
65
|
+
`DELETE ${r.path}/:id`,
|
|
66
|
+
],
|
|
67
|
+
})),
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
return app;
|
|
71
|
+
}
|
|
72
|
+
// startServer(options) starts the server with the given options
|
|
73
|
+
// options: the options for the server
|
|
74
|
+
// returns: void
|
|
75
|
+
export function startServer(options) {
|
|
76
|
+
const app = createServer(options);
|
|
77
|
+
console.log("\nRegistering routes:");
|
|
78
|
+
for (const schemaPath of options.schemaPaths) {
|
|
79
|
+
console.log(` Schema: ${schemaPath}`);
|
|
80
|
+
}
|
|
81
|
+
app.listen(options.port, () => {
|
|
82
|
+
console.log(`\nMock API running at http://localhost:${options.port}`);
|
|
83
|
+
console.log(`Visit http://localhost:${options.port}/ to see all routes`);
|
|
84
|
+
console.log("Press Ctrl+C to stop\n");
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type MockRecord = Record<string, unknown> & {
|
|
2
|
+
id: string;
|
|
3
|
+
};
|
|
4
|
+
export declare class DataStore {
|
|
5
|
+
private readonly collections;
|
|
6
|
+
seed(collection: string, items: Record<string, unknown>[]): void;
|
|
7
|
+
count(collection: string): number;
|
|
8
|
+
getAll(collection: string, page?: number, limit?: number): MockRecord[];
|
|
9
|
+
getById(collection: string, id: string): MockRecord | undefined;
|
|
10
|
+
create(collection: string, data: Record<string, unknown>): MockRecord;
|
|
11
|
+
update(collection: string, id: string, data: Record<string, unknown>): MockRecord | undefined;
|
|
12
|
+
patch(collection: string, id: string, data: Record<string, unknown>): MockRecord | undefined;
|
|
13
|
+
delete(collection: string, id: string): boolean;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=dataStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataStore.d.ts","sourceRoot":"","sources":["../../src/store/dataStore.ts"],"names":[],"mappings":"AAEA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,qBAAa,SAAS;IAClB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAwC;IAIpE,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI;IAShE,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAMjC,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE;IAWvE,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAM/D,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU;IASrE,MAAM,CACF,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,UAAU,GAAG,SAAS;IAiBzB,KAAK,CACD,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,UAAU,GAAG,SAAS;IAiBzB,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO;CAalD"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
export class DataStore {
|
|
3
|
+
collections = new Map();
|
|
4
|
+
// seed(collection, items) seeds the collection with the given items
|
|
5
|
+
// adds the items to the collection
|
|
6
|
+
seed(collection, items) {
|
|
7
|
+
const records = items.map((item) => ({ id: randomUUID(), ...item }));
|
|
8
|
+
this.collections.set(collection, records);
|
|
9
|
+
}
|
|
10
|
+
// count(collection) counts the number of items in the collection
|
|
11
|
+
// returns: the number of items in the collection
|
|
12
|
+
count(collection) {
|
|
13
|
+
return this.collections.get(collection)?.length ?? 0;
|
|
14
|
+
}
|
|
15
|
+
// getAll(collection, page, limit) gets all items from the collection
|
|
16
|
+
// returns: a slice of the collection based on the page and limit
|
|
17
|
+
getAll(collection, page, limit) {
|
|
18
|
+
const items = this.collections.get(collection) ?? [];
|
|
19
|
+
if (page !== undefined && limit !== undefined) {
|
|
20
|
+
const start = (page - 1) * limit;
|
|
21
|
+
return items.slice(start, start + limit);
|
|
22
|
+
}
|
|
23
|
+
return items;
|
|
24
|
+
}
|
|
25
|
+
// getById(collection, id) gets an item from the collection by id
|
|
26
|
+
// returns: the item if it exists, undefined otherwise
|
|
27
|
+
getById(collection, id) {
|
|
28
|
+
return this.collections.get(collection)?.find((item) => item.id === id);
|
|
29
|
+
}
|
|
30
|
+
// create(collection, data) creates a new item in the collection
|
|
31
|
+
// returns: the created item
|
|
32
|
+
create(collection, data) {
|
|
33
|
+
const record = { id: randomUUID(), ...data };
|
|
34
|
+
const existing = this.collections.get(collection) ?? [];
|
|
35
|
+
this.collections.set(collection, [...existing, record]);
|
|
36
|
+
return record;
|
|
37
|
+
}
|
|
38
|
+
// update(collection, id, data) updates an item in the collection
|
|
39
|
+
// returns: the updated item if it exists, undefined otherwise
|
|
40
|
+
update(collection, id, data) {
|
|
41
|
+
const items = this.collections.get(collection);
|
|
42
|
+
if (items === undefined)
|
|
43
|
+
return undefined;
|
|
44
|
+
const exists = items.some((item) => item.id === id);
|
|
45
|
+
if (!exists)
|
|
46
|
+
return undefined;
|
|
47
|
+
const updated = { id, ...data };
|
|
48
|
+
this.collections.set(collection, items.map((item) => (item.id === id ? updated : item)));
|
|
49
|
+
return updated;
|
|
50
|
+
}
|
|
51
|
+
// patch(collection, id, data) partially updates an item in the collection
|
|
52
|
+
// returns: the updated item if it exists, undefined otherwise
|
|
53
|
+
patch(collection, id, data) {
|
|
54
|
+
const items = this.collections.get(collection);
|
|
55
|
+
if (items === undefined)
|
|
56
|
+
return undefined;
|
|
57
|
+
const existing = items.find((item) => item.id === id);
|
|
58
|
+
if (existing === undefined)
|
|
59
|
+
return undefined;
|
|
60
|
+
const updated = { ...existing, ...data, id };
|
|
61
|
+
this.collections.set(collection, items.map((item) => (item.id === id ? updated : item)));
|
|
62
|
+
return updated;
|
|
63
|
+
}
|
|
64
|
+
// delete(collection, id) deletes an item from the collection
|
|
65
|
+
// returns: true if the item was deleted, false otherwise
|
|
66
|
+
delete(collection, id) {
|
|
67
|
+
const items = this.collections.get(collection);
|
|
68
|
+
if (items === undefined)
|
|
69
|
+
return false;
|
|
70
|
+
const exists = items.some((item) => item.id === id);
|
|
71
|
+
if (!exists)
|
|
72
|
+
return false;
|
|
73
|
+
this.collections.set(collection, items.filter((item) => item.id !== id));
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=dataStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataStore.js","sourceRoot":"","sources":["../../src/store/dataStore.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACjB,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type InterfaceDeclaration, type Project, type TypeLiteralNode } from "ts-morph";
|
|
2
|
+
export type ObjectSchema = InterfaceDeclaration | TypeLiteralNode;
|
|
3
|
+
export declare function generateMockObject(schema: ObjectSchema, project: Project, depth?: number): Record<string, unknown>;
|
|
4
|
+
export declare function generateMockCollection(schema: ObjectSchema, project: Project, count: number): Record<string, unknown>[];
|
|
5
|
+
//# sourceMappingURL=mockGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mockGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/mockGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,KAAK,oBAAoB,EACzB,KAAK,OAAO,EACZ,KAAK,eAAe,EACvB,MAAM,UAAU,CAAC;AAKlB,MAAM,MAAM,YAAY,GAAG,oBAAoB,GAAG,eAAe,CAAC;AA4FlE,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,OAAO,EAChB,KAAK,GAAE,MAAU,GAClB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYzB;AAID,wBAAgB,sBAAsB,CAClC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,GACd,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAI3B"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Node, } from "ts-morph";
|
|
2
|
+
import { generateProp } from "./propGenerator.js";
|
|
3
|
+
const MAX_DEPTH = 5;
|
|
4
|
+
// findSchema(typeName, project) finds the interface or type alias with the given name in the project
|
|
5
|
+
// returns: the schema if it exists (interface or type literal from object type alias), undefined otherwise
|
|
6
|
+
function findSchema(typeName, project) {
|
|
7
|
+
const iface = project
|
|
8
|
+
.getSourceFiles()
|
|
9
|
+
.flatMap((sf) => sf.getInterfaces())
|
|
10
|
+
.find((i) => i.getName() === typeName);
|
|
11
|
+
if (iface !== undefined) {
|
|
12
|
+
return iface;
|
|
13
|
+
}
|
|
14
|
+
const typeAlias = project
|
|
15
|
+
.getSourceFiles()
|
|
16
|
+
.flatMap((sf) => sf.getTypeAliases())
|
|
17
|
+
.find((t) => t.getName() === typeName);
|
|
18
|
+
if (typeAlias === undefined) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
const typeNode = typeAlias.getTypeNode();
|
|
22
|
+
if (typeNode === undefined || !Node.isTypeLiteral(typeNode)) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
return typeNode;
|
|
26
|
+
}
|
|
27
|
+
// resolveTypeText(propName, typeText, project, depth) resolves the type text for the given property name,
|
|
28
|
+
// type text, project, and depth.
|
|
29
|
+
// returns: the resolved type text
|
|
30
|
+
function resolveTypeText(propName, typeText, project, depth) {
|
|
31
|
+
if (depth > MAX_DEPTH) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
// Strip optional modifiers (| undefined, | null)
|
|
35
|
+
const cleaned = typeText
|
|
36
|
+
.replace(/\s*\|\s*undefined/g, "")
|
|
37
|
+
.replace(/\s*\|\s*null/g, "")
|
|
38
|
+
.trim();
|
|
39
|
+
// Array type: T[]
|
|
40
|
+
if (cleaned.endsWith("[]")) {
|
|
41
|
+
const inner = cleaned.slice(0, -2);
|
|
42
|
+
return Array.from({ length: 3 }, () => resolveTypeText(propName, inner, project, depth + 1));
|
|
43
|
+
}
|
|
44
|
+
// Generic array: Array<T>
|
|
45
|
+
const arrayMatch = cleaned.match(/^Array<(.+)>$/);
|
|
46
|
+
const arrayInner = arrayMatch?.[1];
|
|
47
|
+
if (arrayInner !== undefined) {
|
|
48
|
+
return Array.from({ length: 3 }, () => resolveTypeText(propName, arrayInner, project, depth + 1));
|
|
49
|
+
}
|
|
50
|
+
// String literal: 'value' or "value"
|
|
51
|
+
if (/^'[^']*'$/.test(cleaned) || /^"[^"]*"$/.test(cleaned)) {
|
|
52
|
+
return cleaned.slice(1, -1);
|
|
53
|
+
}
|
|
54
|
+
// Union type: pick a random option
|
|
55
|
+
if (cleaned.includes(" | ")) {
|
|
56
|
+
const options = cleaned.split(" | ").map((t) => t.trim());
|
|
57
|
+
const picked = options[Math.floor(Math.random() * options.length)] ?? "string";
|
|
58
|
+
return resolveTypeText(propName, picked, project, depth + 1);
|
|
59
|
+
}
|
|
60
|
+
// Nested interface or type alias
|
|
61
|
+
const nested = findSchema(cleaned, project);
|
|
62
|
+
if (nested !== undefined) {
|
|
63
|
+
return generateMockObject(nested, project, depth + 1);
|
|
64
|
+
}
|
|
65
|
+
return generateProp(propName, cleaned);
|
|
66
|
+
}
|
|
67
|
+
// generateMockObject(schema, project, depth) generates a mock object with the given schema, project, and depth
|
|
68
|
+
// returns: a mock object
|
|
69
|
+
export function generateMockObject(schema, project, depth = 0) {
|
|
70
|
+
const obj = {};
|
|
71
|
+
for (const prop of schema.getProperties()) {
|
|
72
|
+
const propName = prop.getName();
|
|
73
|
+
// Prefer the type node text (as written) for clean type names
|
|
74
|
+
const typeText = prop.getTypeNode()?.getText() ?? prop.getType().getText();
|
|
75
|
+
obj[propName] = resolveTypeText(propName, typeText, project, depth);
|
|
76
|
+
}
|
|
77
|
+
return obj;
|
|
78
|
+
}
|
|
79
|
+
// generateMockCollection(schema, project, count) generates a mock collection with the given schema, project, and count
|
|
80
|
+
// returns: an array of mock objects
|
|
81
|
+
export function generateMockCollection(schema, project, count) {
|
|
82
|
+
return Array.from({ length: count }, () => generateMockObject(schema, project));
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=mockGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mockGenerator.js","sourceRoot":"","sources":["../../src/utils/mockGenerator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function pluralize(word: string): string;
|
|
2
|
+
export declare function toKebabCase(str: string): string;
|
|
3
|
+
export declare function toRoutePath(interfaceName: string): string;
|
|
4
|
+
export declare function toCollectionKey(interfaceName: string): string;
|
|
5
|
+
//# sourceMappingURL=nameUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nameUtils.d.ts","sourceRoot":"","sources":["../../src/utils/nameUtils.ts"],"names":[],"mappings":"AAeA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiB9C;AAKD,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK/C;AAKD,wBAAgB,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAQzD;AAKD,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE7D"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const IRREGULAR_PLURALS = {
|
|
2
|
+
person: "people",
|
|
3
|
+
man: "men",
|
|
4
|
+
woman: "women",
|
|
5
|
+
child: "children",
|
|
6
|
+
mouse: "mice",
|
|
7
|
+
tooth: "teeth",
|
|
8
|
+
foot: "feet",
|
|
9
|
+
goose: "geese",
|
|
10
|
+
};
|
|
11
|
+
// pluralize(word) pluralizes the given word
|
|
12
|
+
// returns: the pluralized word
|
|
13
|
+
// example: "Person" -> "People"
|
|
14
|
+
// "User" -> "Users"
|
|
15
|
+
export function pluralize(word) {
|
|
16
|
+
const lower = word.toLowerCase();
|
|
17
|
+
const irregular = IRREGULAR_PLURALS[lower];
|
|
18
|
+
if (irregular !== undefined) {
|
|
19
|
+
return irregular;
|
|
20
|
+
}
|
|
21
|
+
// If the word ends in s, x, z, ch, or sh, add es
|
|
22
|
+
if (/(?:s|x|z|ch|sh)$/i.test(word)) {
|
|
23
|
+
return word + "es";
|
|
24
|
+
}
|
|
25
|
+
// If the word ends in y and is not preceded by a vowel, add ies
|
|
26
|
+
if (/[^aeiou]y$/i.test(word)) {
|
|
27
|
+
return word.slice(0, -1) + "ies";
|
|
28
|
+
}
|
|
29
|
+
return word + "s";
|
|
30
|
+
}
|
|
31
|
+
// toKebabCase(str) converts the given string to kebab case
|
|
32
|
+
// returns: the kebab case string
|
|
33
|
+
// example: "User" -> "user"
|
|
34
|
+
export function toKebabCase(str) {
|
|
35
|
+
return str
|
|
36
|
+
.replace(/([A-Z])/g, (_, char) => `-${char}`)
|
|
37
|
+
.toLowerCase()
|
|
38
|
+
.replace(/^-/, "");
|
|
39
|
+
}
|
|
40
|
+
// toRoutePath(interfaceName) converts the given interface name to a route path
|
|
41
|
+
// returns: route path
|
|
42
|
+
// example: "User" -> "/users"
|
|
43
|
+
export function toRoutePath(interfaceName) {
|
|
44
|
+
const kebab = toKebabCase(interfaceName);
|
|
45
|
+
const parts = kebab.split("-");
|
|
46
|
+
const lastPart = parts[parts.length - 1];
|
|
47
|
+
if (lastPart !== undefined) {
|
|
48
|
+
parts[parts.length - 1] = pluralize(lastPart);
|
|
49
|
+
}
|
|
50
|
+
return "/" + parts.join("-");
|
|
51
|
+
}
|
|
52
|
+
// toCollectionKey(interfaceName) converts the given interface name to a collection key
|
|
53
|
+
// returns: collection key
|
|
54
|
+
// example: "User" -> "users"
|
|
55
|
+
export function toCollectionKey(interfaceName) {
|
|
56
|
+
return toRoutePath(interfaceName).slice(1);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=nameUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nameUtils.js","sourceRoot":"","sources":["../../src/utils/nameUtils.ts"],"names":[],"mappings":"AAAA,MAAM,iBAAiB,GAAqC;IACxD,MAAM,EAAE,QAAQ;IAChB,GAAG,EAAE,KAAK;IACV,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,UAAU;IACjB,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;CACjB,CAAC;AAEF,4CAA4C;AAC5C,+BAA+B;AAC/B,gCAAgC;AAChC,6BAA6B;AAC7B,MAAM,UAAU,SAAS,CAAC,IAAY;IAClC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAEjC,MAAM,SAAS,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAC3C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,iDAAiD;IACjD,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,GAAG,IAAI,CAAC;IACvB,CAAC;IACD,gEAAgE;IAChE,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;IACrC,CAAC;IAED,OAAO,IAAI,GAAG,GAAG,CAAC;AACtB,CAAC;AAED,2DAA2D;AAC3D,iCAAiC;AACjC,4BAA4B;AAC5B,MAAM,UAAU,WAAW,CAAC,GAAW;IACnC,OAAO,GAAG;SACL,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;SACpD,WAAW,EAAE;SACb,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED,+EAA+E;AAC/E,sBAAsB;AACtB,8BAA8B;AAC9B,MAAM,UAAU,WAAW,CAAC,aAAqB;IAC7C,MAAM,KAAK,GAAG,WAAW,CAAC,aAAa,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QACzB,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACjC,CAAC;AAED,uFAAuF;AACvF,0BAA0B;AAC1B,6BAA6B;AAC7B,MAAM,UAAU,eAAe,CAAC,aAAqB;IACjD,OAAO,WAAW,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processArgs.d.ts","sourceRoot":"","sources":["../../src/utils/processArgs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,cAAc,CAuC1D"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
// processArgs(argv) processes the given arguments and returns the options
|
|
3
|
+
// retunrs: object with schema paths, port, and count
|
|
4
|
+
export function processArgs(argv) {
|
|
5
|
+
const program = new Command();
|
|
6
|
+
program
|
|
7
|
+
.name("mock-api")
|
|
8
|
+
.description("Generate a mock REST API from TypeScript interfaces and object type aliases")
|
|
9
|
+
.argument("<schemas...>", "TypeScript schema file path(s)")
|
|
10
|
+
.option("-p, --port <number>", "Port to run the server on", "3000")
|
|
11
|
+
.option("-c, --count <number>", "Number of mock items to generate per collection", "10")
|
|
12
|
+
.parse(argv);
|
|
13
|
+
const schemaPaths = program.args;
|
|
14
|
+
const opts = program.opts();
|
|
15
|
+
const port = parseInt(opts.port, 10);
|
|
16
|
+
const count = parseInt(opts.count, 10);
|
|
17
|
+
if (schemaPaths.length === 0) {
|
|
18
|
+
console.error("Error: At least one schema file is required");
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
22
|
+
console.error("Error: Port must be a number between 1 and 65535");
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
if (isNaN(count) || count < 1) {
|
|
26
|
+
console.error("Error: Count must be a positive integer");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
return { schemaPaths, port, count };
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=processArgs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processArgs.js","sourceRoot":"","sources":["../../src/utils/processArgs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,0EAA0E;AAC1E,qDAAqD;AACrD,MAAM,UAAU,WAAW,CAAC,IAAc;IACtC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACF,IAAI,CAAC,UAAU,CAAC;SAChB,WAAW,CACR,6EAA6E,CAChF;SACA,QAAQ,CAAC,cAAc,EAAE,gCAAgC,CAAC;SAC1D,MAAM,CAAC,qBAAqB,EAAE,2BAA2B,EAAE,MAAM,CAAC;SAClE,MAAM,CACH,sBAAsB,EACtB,iDAAiD,EACjD,IAAI,CACP;SACA,KAAK,CAAC,IAAI,CAAC,CAAC;IAEjB,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IACjC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAmC,CAAC;IAE7D,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAEvC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QAC1C,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;QAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/propGenerator.ts"],"names":[],"mappings":"AAiEA,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAaxE"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { faker } from "@faker-js/faker";
|
|
2
|
+
// Ordered by specificity — first match wins
|
|
3
|
+
const NAME_PATTERNS = [
|
|
4
|
+
[/^id$|Id$/, () => faker.string.uuid()],
|
|
5
|
+
[/email/i, () => faker.internet.email()],
|
|
6
|
+
[/username/i, () => faker.internet.username()],
|
|
7
|
+
[/password|secret/i, () => faker.internet.password()],
|
|
8
|
+
[/phone|mobile/i, () => faker.phone.number()],
|
|
9
|
+
[/firstName|first_name/i, () => faker.person.firstName()],
|
|
10
|
+
[/lastName|last_name/i, () => faker.person.lastName()],
|
|
11
|
+
[/fullName|full_name/i, () => faker.person.fullName()],
|
|
12
|
+
[/name/i, () => faker.person.fullName()],
|
|
13
|
+
[/address|street/i, () => faker.location.streetAddress()],
|
|
14
|
+
[/city/i, () => faker.location.city()],
|
|
15
|
+
[/state|province/i, () => faker.location.state()],
|
|
16
|
+
[/zip|postal/i, () => faker.location.zipCode()],
|
|
17
|
+
[/country/i, () => faker.location.country()],
|
|
18
|
+
[/latitude|lat$/i, () => faker.location.latitude()],
|
|
19
|
+
[/longitude|lng$|lon$/i, () => faker.location.longitude()],
|
|
20
|
+
[/createdAt|updatedAt|deletedAt/i, () => faker.date.recent().toISOString()],
|
|
21
|
+
[/date|time/i, () => faker.date.recent().toISOString()],
|
|
22
|
+
[/description|bio|summary|about/i, () => faker.lorem.paragraph()],
|
|
23
|
+
[/title|headline/i, () => faker.lorem.words(4)],
|
|
24
|
+
[/slug/i, () => faker.helpers.slugify(faker.lorem.words(3))],
|
|
25
|
+
[/image|avatar|photo|picture/i, () => faker.image.url()],
|
|
26
|
+
[/url|website|link|href/i, () => faker.internet.url()],
|
|
27
|
+
[/price|cost|amount|fee/i, () => faker.commerce.price()],
|
|
28
|
+
[/color|colour/i, () => faker.color.human()],
|
|
29
|
+
[/company|organization|org/i, () => faker.company.name()],
|
|
30
|
+
[/job|position|role|occupation/i, () => faker.person.jobTitle()],
|
|
31
|
+
[/age/i, () => faker.number.int({ min: 18, max: 80 })],
|
|
32
|
+
[
|
|
33
|
+
/rating|score/i,
|
|
34
|
+
() => faker.number.float({ min: 0, max: 5, fractionDigits: 1 }),
|
|
35
|
+
],
|
|
36
|
+
[/count|total|quantity|qty/i, () => faker.number.int({ min: 0, max: 100 })],
|
|
37
|
+
[/content|body|text/i, () => faker.lorem.paragraphs(2)],
|
|
38
|
+
[/token|key|hash/i, () => faker.string.alphanumeric(32)],
|
|
39
|
+
[/tag|label|category/i, () => faker.commerce.department()],
|
|
40
|
+
[
|
|
41
|
+
/isActive|isEnabled|isVerified|active|enabled|verified/i,
|
|
42
|
+
() => faker.datatype.boolean(),
|
|
43
|
+
],
|
|
44
|
+
];
|
|
45
|
+
// Record of type generic type fallbacks in case no pattern matches
|
|
46
|
+
const TYPE_FALLBACKS = {
|
|
47
|
+
string: () => faker.lorem.word(),
|
|
48
|
+
number: () => faker.number.int({ max: 1000 }),
|
|
49
|
+
boolean: () => faker.datatype.boolean(),
|
|
50
|
+
Date: () => faker.date.recent().toISOString(),
|
|
51
|
+
any: () => faker.lorem.word(),
|
|
52
|
+
unknown: () => faker.lorem.word(),
|
|
53
|
+
};
|
|
54
|
+
// generateProp(propName, propType) generates a mock property with the given name and type
|
|
55
|
+
// returns: mock property
|
|
56
|
+
// example: "name" -> "John Doe"
|
|
57
|
+
// "email" -> "john.doe@example.com"
|
|
58
|
+
// "password" -> "password123"
|
|
59
|
+
// "phone" -> "1234567890"
|
|
60
|
+
// "createdAt" -> "2021-01-01T00:00:00.000Z"
|
|
61
|
+
export function generateProp(propName, propType) {
|
|
62
|
+
for (const [pattern, generator] of NAME_PATTERNS) {
|
|
63
|
+
if (pattern.test(propName)) {
|
|
64
|
+
return generator();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const fallback = TYPE_FALLBACKS[propType];
|
|
68
|
+
if (fallback !== undefined) {
|
|
69
|
+
return fallback();
|
|
70
|
+
}
|
|
71
|
+
return faker.lorem.word();
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=propGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propGenerator.js","sourceRoot":"","sources":["../../src/utils/propGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAIxC,4CAA4C;AAC5C,MAAM,aAAa,GAAoD;IACnE,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACvC,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxC,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAC9C,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;IACrD,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IAC7C,CAAC,uBAAuB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;IACzD,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;IACtD,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;IACtD,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;IACxC,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IACzD,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACtC,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACjD,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC/C,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;IAC5C,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;IACnD,CAAC,sBAAsB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;IAC1D,CAAC,gCAAgC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3E,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC;IACvD,CAAC,gCAAgC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;IACjE,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,CAAC,6BAA6B,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;IACxD,CAAC,wBAAwB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;IACtD,CAAC,wBAAwB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxD,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAC5C,CAAC,2BAA2B,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACzD,CAAC,+BAA+B,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;IAChE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;IACtD;QACI,eAAe;QACf,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC;KAClE;IACD,CAAC,2BAA2B,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3E,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;IAC1D;QACI,wDAAwD;QACxD,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE;KACjC;CACK,CAAC;AAEX,mEAAmE;AACnE,MAAM,cAAc,GAA4C;IAC5D,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;IAChC,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IAC7C,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE;IACvC,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE;IAC7C,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;IAC7B,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;CACpC,CAAC;AAEF,0FAA0F;AAC1F,yBAAyB;AACzB,gCAAgC;AAChC,6CAA6C;AAC7C,uCAAuC;AACvC,mCAAmC;AACnC,qDAAqD;AACrD,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,QAAgB;IAC3D,KAAK,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,aAAa,EAAE,CAAC;QAC/C,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,SAAS,EAAE,CAAC;QACvB,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,QAAQ,EAAE,CAAC;IACtB,CAAC;IAED,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;AAC9B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-mock-api-from-types",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Generate a mock REST API server from TypeScript interfaces",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"mock-api": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mock",
|
|
22
|
+
"api",
|
|
23
|
+
"faker",
|
|
24
|
+
"typescript",
|
|
25
|
+
"rest",
|
|
26
|
+
"testing"
|
|
27
|
+
],
|
|
28
|
+
"author": "",
|
|
29
|
+
"license": "ISC",
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/express": "^5.0.6",
|
|
32
|
+
"@types/node": "^25.5.0",
|
|
33
|
+
"ts-node": "^10.9.2",
|
|
34
|
+
"tsx": "^4.21.0",
|
|
35
|
+
"typescript": "^5.9.3"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@faker-js/faker": "^10.3.0",
|
|
39
|
+
"commander": "^14.0.3",
|
|
40
|
+
"express": "^5.2.1",
|
|
41
|
+
"ts-morph": "^27.0.2"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc",
|
|
45
|
+
"postbuild": "chmod +x dist/cli.js",
|
|
46
|
+
"start": "node dist/cli.js",
|
|
47
|
+
"dev": "tsx src/cli.ts",
|
|
48
|
+
"typecheck": "tsc --noEmit"
|
|
49
|
+
}
|
|
50
|
+
}
|