@jaypie/mcp 0.1.7 → 0.1.8
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/package.json +2 -3
- package/prompts/Jaypie_Fabricator.md +222 -25
- package/LICENSE.txt +0 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaypie/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Jaypie MCP",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -45,6 +45,5 @@
|
|
|
45
45
|
},
|
|
46
46
|
"publishConfig": {
|
|
47
47
|
"access": "public"
|
|
48
|
-
}
|
|
49
|
-
"gitHead": "14683b303359f95dc63e58998959fddae3c90e97"
|
|
48
|
+
}
|
|
50
49
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: coding style resource, helpful when stuck on lint errors
|
|
3
3
|
globs: packages/fabricator/**
|
|
4
|
+
version: 0.3.0
|
|
4
5
|
---
|
|
5
6
|
# Brief Guide to @jaypie/fabricator
|
|
6
7
|
|
|
@@ -17,6 +18,8 @@ The `Fabricator` class wraps faker.js and provides:
|
|
|
17
18
|
- **Direct faker access**: All faker modules are proxied for convenience
|
|
18
19
|
- **Enhanced random number generation**: Built-in `random()` function with advanced options
|
|
19
20
|
- **Custom generators**: Specialized methods like `words()` and `generate.person()`
|
|
21
|
+
- **Unique identifiers**: Each fabricator has an `id` (UUID) and `name` property
|
|
22
|
+
- **Nested fabricators**: Support for hierarchical data generation with child fabricators
|
|
20
23
|
|
|
21
24
|
```typescript
|
|
22
25
|
import { fabricator } from "@jaypie/fabricator";
|
|
@@ -27,6 +30,20 @@ const fab = fabricator();
|
|
|
27
30
|
// Create seeded (deterministic) fabricator
|
|
28
31
|
const seededFab = fabricator("my-seed");
|
|
29
32
|
const uuidFab = fabricator("550e8400-e29b-41d4-a716-446655440000");
|
|
33
|
+
|
|
34
|
+
// Access built-in properties
|
|
35
|
+
console.log(fab.id); // UUID
|
|
36
|
+
console.log(fab.name); // Generated name like "Happy Mountain"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Options**:
|
|
40
|
+
```typescript
|
|
41
|
+
const fab = fabricator("my-seed", {
|
|
42
|
+
name: "Custom Name", // String or function
|
|
43
|
+
generator: {
|
|
44
|
+
name: ({ fabricator }) => fabricator.faker.person.firstName()
|
|
45
|
+
}
|
|
46
|
+
});
|
|
30
47
|
```
|
|
31
48
|
|
|
32
49
|
### 2. Deterministic Seeding
|
|
@@ -43,30 +60,54 @@ fab2.faker.person.firstName(); // "Jordan" (same!)
|
|
|
43
60
|
|
|
44
61
|
**UUID Seeding**: UUIDs are converted to numeric arrays using `uuidToBytes` for efficient seeding.
|
|
45
62
|
|
|
63
|
+
**Environment Variable**: Set `PROJECT_SEED` environment variable to provide a default seed for all unseeded fabricators:
|
|
64
|
+
```typescript
|
|
65
|
+
process.env.PROJECT_SEED = "my-project-seed";
|
|
66
|
+
const fab = fabricator(); // Uses PROJECT_SEED
|
|
67
|
+
```
|
|
68
|
+
|
|
46
69
|
### 3. Random Number Generation
|
|
47
70
|
|
|
48
71
|
The `random()` function provides advanced randomness with multiple distribution types:
|
|
49
72
|
|
|
50
73
|
**Basic Usage:**
|
|
51
74
|
```typescript
|
|
52
|
-
fab.random();
|
|
53
|
-
fab.random({ min: 1, max: 10 });
|
|
54
|
-
fab.random({ min: 1, max: 10, integer: true });
|
|
75
|
+
fab.random(); // 0-1 float
|
|
76
|
+
fab.random({ min: 1, max: 10 }); // 1-10 float
|
|
77
|
+
fab.random({ min: 1, max: 10, integer: true }); // 1-10 integer
|
|
55
78
|
```
|
|
56
79
|
|
|
57
|
-
**
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
80
|
+
**All Options:**
|
|
81
|
+
```typescript
|
|
82
|
+
fab.random({
|
|
83
|
+
min: 1, // Minimum value (default: 0)
|
|
84
|
+
max: 10, // Maximum value (default: 1)
|
|
85
|
+
integer: true, // Return integer instead of float (default: false)
|
|
86
|
+
mean: 5, // For normal distribution
|
|
87
|
+
stddev: 2, // For normal distribution
|
|
88
|
+
precision: 2, // Decimal places
|
|
89
|
+
currency: true, // Shorthand for precision: 2
|
|
90
|
+
start: 100, // Add offset to result
|
|
91
|
+
seed: "override" // Override fabricator's seed for this call only
|
|
92
|
+
});
|
|
93
|
+
```
|
|
65
94
|
|
|
66
95
|
**Smart Defaults:**
|
|
67
96
|
- If only `min` is set, `max` defaults to `min * 2`
|
|
68
97
|
- Normal distribution with `mean/stddev` can optionally be clamped by `min/max`
|
|
69
98
|
|
|
99
|
+
**Common Patterns:**
|
|
100
|
+
```typescript
|
|
101
|
+
// Currency values
|
|
102
|
+
fab.random({ min: 10, max: 1000, currency: true }); // e.g., 542.73
|
|
103
|
+
|
|
104
|
+
// Percentages
|
|
105
|
+
fab.random({ min: 0, max: 100, integer: true }); // e.g., 42
|
|
106
|
+
|
|
107
|
+
// Weighted random with normal distribution
|
|
108
|
+
fab.random({ mean: 50, stddev: 15, min: 0, max: 100 }); // Clusters around 50
|
|
109
|
+
```
|
|
110
|
+
|
|
70
111
|
### 4. Faker Integration
|
|
71
112
|
|
|
72
113
|
All faker modules are directly accessible through getters:
|
|
@@ -81,14 +122,14 @@ fab.company.name();
|
|
|
81
122
|
|
|
82
123
|
### 5. Custom Methods
|
|
83
124
|
|
|
84
|
-
#### `words()`: Two-Word Combinations
|
|
125
|
+
#### `generate.words()`: Two-Word Combinations
|
|
85
126
|
Generates one of three patterns randomly:
|
|
86
127
|
- adjective + noun
|
|
87
128
|
- adjective + verb
|
|
88
129
|
- noun + verb
|
|
89
130
|
|
|
90
131
|
```typescript
|
|
91
|
-
fab.words(); // "happy dog" or "quick run" or "mountain climb"
|
|
132
|
+
fab.generate.words(); // "happy dog" or "quick run" or "mountain climb"
|
|
92
133
|
```
|
|
93
134
|
|
|
94
135
|
#### `generate.person(id?)`: Complex Person Generator
|
|
@@ -135,6 +176,47 @@ export const CHANCE = {
|
|
|
135
176
|
|
|
136
177
|
Use these for consistent probability calculations across your test data.
|
|
137
178
|
|
|
179
|
+
### 7. Nested Fabricators
|
|
180
|
+
|
|
181
|
+
Create hierarchical data structures with `Fabricator.new()` and nested configurations:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import { Fabricator } from "@jaypie/fabricator";
|
|
185
|
+
|
|
186
|
+
// Define a nested structure
|
|
187
|
+
const world = Fabricator.new({
|
|
188
|
+
seed: "my-world",
|
|
189
|
+
name: ({ fabricator }) => fabricator.location.city(),
|
|
190
|
+
fabricators: {
|
|
191
|
+
cities: {
|
|
192
|
+
name: ({ fabricator }) => fabricator.location.city(),
|
|
193
|
+
fabricators: {
|
|
194
|
+
streets: {
|
|
195
|
+
name: ({ fabricator }) => fabricator.location.street()
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
exports: {
|
|
200
|
+
name: ({ fabricator }) => fabricator.commerce.product()
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Access nested fabricators
|
|
206
|
+
const cities = world.cities(5); // Array of 5 city fabricators
|
|
207
|
+
const cityGen = world.cities(); // Generator for infinite cities
|
|
208
|
+
|
|
209
|
+
// Access nested child fabricators
|
|
210
|
+
const city = cities[0];
|
|
211
|
+
const streets = city.streets(10); // 10 streets for this city
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Deterministic Child Seeding**: Child fabricators are seeded deterministically based on their parent's ID and their index, ensuring reproducible hierarchies.
|
|
215
|
+
|
|
216
|
+
**Generator vs Array**:
|
|
217
|
+
- `world.cities()` - Returns a generator for unlimited fabricators
|
|
218
|
+
- `world.cities(n)` - Returns an array of exactly n fabricators
|
|
219
|
+
|
|
138
220
|
## Architecture
|
|
139
221
|
|
|
140
222
|
### Internal Utilities
|
|
@@ -143,6 +225,131 @@ Use these for consistent probability calculations across your test data.
|
|
|
143
225
|
- **`uuidToBytes()`**: Converts UUIDs to byte arrays for seeding
|
|
144
226
|
- **`uuidToNumber()`**: Converts UUIDs to single numbers (fallback)
|
|
145
227
|
- **`numericSeedArray()`**: Smart converter that detects UUIDs and uses appropriate conversion
|
|
228
|
+
- **`uuidFrom()`**: Generates deterministic UUID v5 from string or number using `JAYPIE_FABRICATOR_UUID` as namespace
|
|
229
|
+
- **`isUuid()`**: Validates if a string is a properly formatted UUID
|
|
230
|
+
|
|
231
|
+
## Best Practices & Patterns
|
|
232
|
+
|
|
233
|
+
### Seeding Strategy
|
|
234
|
+
|
|
235
|
+
Always tie seeds to fabricator instance ID for determinism with variety:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// In parent fabricator method
|
|
239
|
+
for (let i = 0; i < count; i++) {
|
|
240
|
+
const seed = `${this.id}-tenant-${i}`;
|
|
241
|
+
tenants.push(new TenantFabricator({ seed, name }));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// In child fabricator method
|
|
245
|
+
for (let i = 0; i < count; i++) {
|
|
246
|
+
const seed = `${this.id}-merchant-${i}`;
|
|
247
|
+
merchants.push(new MerchantFabricator({ seed, name }));
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**Result:**
|
|
252
|
+
- Same fabricator instance → same data (deterministic)
|
|
253
|
+
- Different fabricator instance → different data (variety)
|
|
254
|
+
- Each entity gets unique seed: `parentId-entityType-index`
|
|
255
|
+
|
|
256
|
+
### Name Handling Pattern
|
|
257
|
+
|
|
258
|
+
When passing name functions to child fabricators, pass the function itself (don't call it):
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
// ✅ Correct - parent will invoke function
|
|
262
|
+
const name = config?.name ? () => config.name : undefined;
|
|
263
|
+
new TenantFabricator({ name, seed });
|
|
264
|
+
|
|
265
|
+
// ❌ Wrong - calling function too early
|
|
266
|
+
const name = config?.name ? config.name : generateName({ fabricator: this });
|
|
267
|
+
new TenantFabricator({ name: () => name, seed });
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
The parent Fabricator class invokes name functions lazily when `get name()` is accessed and caches the result.
|
|
271
|
+
|
|
272
|
+
### Generator Functions
|
|
273
|
+
|
|
274
|
+
Export generator functions separately for reusability and testability:
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
// Export the generator function
|
|
278
|
+
export const generateTenantName = ({ fabricator }: FabricatorNameParams) => {
|
|
279
|
+
const city = fabricator.faker.location.city();
|
|
280
|
+
const suffixes = ["Financial", "Payments", "Commerce"];
|
|
281
|
+
const suffixIndex = Math.floor(fabricator.random() * suffixes.length);
|
|
282
|
+
return `${city} ${suffixes[suffixIndex]}`;
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
// Use in fabricator via generator option
|
|
286
|
+
const fab = new Fabricator({
|
|
287
|
+
seed: "my-seed",
|
|
288
|
+
generator: {
|
|
289
|
+
name: generateTenantName
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Extending Fabricator
|
|
295
|
+
|
|
296
|
+
Create domain-specific fabricators by extending the base class:
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
import { Fabricator as JaypieFabricator } from "@jaypie/fabricator";
|
|
300
|
+
|
|
301
|
+
export class TenantFabricator extends JaypieFabricator {
|
|
302
|
+
constructor({
|
|
303
|
+
name,
|
|
304
|
+
seed,
|
|
305
|
+
}: {
|
|
306
|
+
name?: string | ((params: FabricatorNameParams) => string);
|
|
307
|
+
seed?: string | number;
|
|
308
|
+
} = {}) {
|
|
309
|
+
super({
|
|
310
|
+
name,
|
|
311
|
+
seed,
|
|
312
|
+
generator: {
|
|
313
|
+
name: generateTenantName,
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Add domain-specific methods
|
|
319
|
+
merchants(count: number): MerchantFabricator[] {
|
|
320
|
+
const merchants: MerchantFabricator[] = [];
|
|
321
|
+
for (let i = 0; i < count; i++) {
|
|
322
|
+
merchants.push(new MerchantFabricator({
|
|
323
|
+
seed: `${this.id}-merchant-${i}`
|
|
324
|
+
}));
|
|
325
|
+
}
|
|
326
|
+
return merchants;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Common Anti-Patterns
|
|
332
|
+
|
|
333
|
+
**❌ Don't manage name storage yourself**
|
|
334
|
+
```typescript
|
|
335
|
+
// Wrong - parent already handles this
|
|
336
|
+
private readonly _name: string;
|
|
337
|
+
get name(): string {
|
|
338
|
+
return this._name;
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
**✅ Right:** Use parent's `get name()` accessor via `generator` option.
|
|
342
|
+
|
|
343
|
+
**❌ Don't pass index parameters**
|
|
344
|
+
```typescript
|
|
345
|
+
// Wrong - couples fabricator to sequence position
|
|
346
|
+
class TenantFabricator {
|
|
347
|
+
constructor({ index, seed }) {
|
|
348
|
+
this._name = this.generateName(index);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
**✅ Right:** Use constructor config or generator functions.
|
|
146
353
|
|
|
147
354
|
## Key Design Patterns
|
|
148
355
|
|
|
@@ -150,15 +357,5 @@ Use these for consistent probability calculations across your test data.
|
|
|
150
357
|
2. **Probabilistic Variations**: Use float rolls with CHANCE constants for realistic data variety
|
|
151
358
|
3. **Proxy Access**: All faker modules exposed through getters for ergonomic API
|
|
152
359
|
4. **Seed Flexibility**: Accepts strings, numbers, or UUIDs as seeds
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
Your wrapper package should:
|
|
157
|
-
- Extend or compose `Fabricator` from `@jaypie/fabricator`
|
|
158
|
-
- Add domain-specific generators (payments, accounts, transactions, etc.)
|
|
159
|
-
- Follow the same patterns: seeding, probabilistic variations, subfaker for complex objects
|
|
160
|
-
- Maintain the same function signature standards (single param, config object, or optional config)
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
Ready to build domain-specific test data generators on this foundation!
|
|
360
|
+
5. **Hierarchical Generation**: Nested fabricators enable deterministic tree structures for complex data models
|
|
361
|
+
6. **Identity & Naming**: Every fabricator has a unique ID and name for tracking and debugging
|
package/LICENSE.txt
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Finlayson Studio, LLC
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|