katanakit-js 5.1.0 → 5.1.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 +139 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/services/faker.service.d.ts +160 -0
- package/dist/core/services/faker.service.d.ts.map +1 -0
- package/dist/core/services/faker.service.js +235 -0
- package/dist/core/services/faker.service.js.map +1 -0
- package/dist/infrastructure/filesystem/filesystem.service.d.ts +238 -0
- package/dist/infrastructure/filesystem/filesystem.service.d.ts.map +1 -0
- package/dist/infrastructure/filesystem/filesystem.service.js +403 -0
- package/dist/infrastructure/filesystem/filesystem.service.js.map +1 -0
- package/dist/infrastructure/filesystem/path.service.d.ts +115 -0
- package/dist/infrastructure/filesystem/path.service.d.ts.map +1 -0
- package/dist/infrastructure/filesystem/path.service.js +154 -0
- package/dist/infrastructure/filesystem/path.service.js.map +1 -0
- package/dist/infrastructure/index.d.ts +2 -0
- package/dist/infrastructure/index.d.ts.map +1 -1
- package/dist/infrastructure/index.js +2 -0
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/schemas/faker.schema.d.ts +12 -0
- package/dist/schemas/faker.schema.d.ts.map +1 -0
- package/dist/schemas/faker.schema.js +12 -0
- package/dist/schemas/faker.schema.js.map +1 -0
- package/dist/schemas/filesystem.schema.d.ts +64 -0
- package/dist/schemas/filesystem.schema.d.ts.map +1 -0
- package/dist/schemas/filesystem.schema.js +54 -0
- package/dist/schemas/filesystem.schema.js.map +1 -0
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +2 -0
- package/dist/schemas/index.js.map +1 -1
- package/dist/types/index.d.ts +26 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -329,6 +329,145 @@ const stop = useKatanaWatch(newProduct, () => checkValidations(), { deep: true }
|
|
|
329
329
|
- **Hexagonal architecture** — pure core, infrastructure adapters, framework adapters
|
|
330
330
|
- **Tree-shakeable** — destructured re-exports from Singleton facades
|
|
331
331
|
- **SSR-safe** — all infrastructure adapters guard or fall back gracefully in server environments
|
|
332
|
+
- **Filesystem (Node/Bun)** — `useReadFile`, `useWriteFile`, `useReadJsonFile`, `useReadModuleJson` and friends return Safe Results with native errno codes, loaded lazily through dynamic `import()` and guarded by `useIsNode()`
|
|
333
|
+
- **Fake data (optional)** — `useFakeVehicle`, `useFakeEmail`, `useFakeList`, … via an optional, lazy-loaded `@faker-js/faker` peer
|
|
334
|
+
|
|
335
|
+
## Filesystem (Node/Bun)
|
|
336
|
+
|
|
337
|
+
Node-only helpers that wrap `node:fs/promises` and `node:path` with the Safe
|
|
338
|
+
Result contract. Built-ins load through dynamic `import()`, so importing them is
|
|
339
|
+
browser-safe; outside Node/Bun every fallible call returns `ERR_FS_UNAVAILABLE`
|
|
340
|
+
instead of throwing.
|
|
341
|
+
|
|
342
|
+
```ts
|
|
343
|
+
import {
|
|
344
|
+
useEnsureDir,
|
|
345
|
+
useReadDir,
|
|
346
|
+
useReadJsonFile,
|
|
347
|
+
useReadModuleJson,
|
|
348
|
+
useWriteJsonFile,
|
|
349
|
+
} from "katanakit-js";
|
|
350
|
+
import { z } from "zod";
|
|
351
|
+
|
|
352
|
+
const BooksSchema = z.array(z.object({ title: z.string() }));
|
|
353
|
+
|
|
354
|
+
// Read relative to the current module (the __dirname pattern, without __dirname)
|
|
355
|
+
const result = await useReadModuleJson(import.meta.url, "../data/books.json", BooksSchema);
|
|
356
|
+
|
|
357
|
+
if (result.ok) {
|
|
358
|
+
console.log(result.data);
|
|
359
|
+
} else {
|
|
360
|
+
console.error(result.error.code, result.error.message); // ENOENT | ERR_VALIDATION | ...
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Or with an explicit path (relative paths resolve against process.cwd())
|
|
364
|
+
await useEnsureDir("data/cache");
|
|
365
|
+
await useWriteJsonFile("data/cache/books.json", [{ title: "Kata" }]);
|
|
366
|
+
const books = await useReadJsonFile("data/cache/books.json", BooksSchema);
|
|
367
|
+
const files = await useReadDir("data/cache", { recursive: true });
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
| Group | Helpers |
|
|
371
|
+
| ----- | ------- |
|
|
372
|
+
| Read | `useReadFile`, `useReadFileBuffer`, `useReadJsonFile`, `useReadModuleFile`, `useReadModuleJson` |
|
|
373
|
+
| Write | `useWriteFile`, `useAppendFile`, `useWriteJsonFile`, `useEnsureDir` |
|
|
374
|
+
| Inspect | `useFileExists`, `useGetFileStats`, `useReadDir` |
|
|
375
|
+
| Move / delete | `useCopyFile`, `useMoveFile`, `useRemoveFile`, `useRemoveDir` |
|
|
376
|
+
| Paths | `useGetDirname`, `useResolvePath`, `useJoinPath`, `useGetRelativePath`, `useGetBasename`, `useGetFileExtension`, `useGetCwd`, `useIsNode` |
|
|
377
|
+
|
|
378
|
+
## Fake data (optional)
|
|
379
|
+
|
|
380
|
+
`@faker-js/faker` is an **optional peer dependency**: these helpers load it
|
|
381
|
+
through dynamic `import()` on first call, so install it only if you use them
|
|
382
|
+
(`bun add @faker-js/faker` / `npm install @faker-js/faker`).
|
|
383
|
+
|
|
384
|
+
| Group | Helpers |
|
|
385
|
+
| ----------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
386
|
+
| People / internet | `useFakeFullName`, `useFakeFirstName`, `useFakeLastName`, `useFakeEmail`, `useFakePhone`, `useFakeCompanyName`, `useFakeUrl` |
|
|
387
|
+
| Values | `useFakeUuid`, `useFakeText`, `useFakeNumber`, `useFakeBoolean`, `useFakeDate`, `useFakeVehicle` |
|
|
388
|
+
| Collections | `useFakeList(factory, count)` — the factory receives the zero-based index |
|
|
389
|
+
| Reproducibility | `useFakeSeed(seed?)`, `useFakeSetDefaultRefDate(refDate?)` |
|
|
390
|
+
|
|
391
|
+
### Reproducible seeds
|
|
392
|
+
|
|
393
|
+
`useFakeSeed(42)` sets the seed **and returns it**. Call it with no arguments to
|
|
394
|
+
roll a fresh random seed (also returned) — log it in CI and pass it back later
|
|
395
|
+
to replay the exact run. `useFakeSetDefaultRefDate("2026-01-01")` pins the
|
|
396
|
+
reference date used by date helpers. Same seed + same reference date + same
|
|
397
|
+
call order + same faker major = identical output.
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
import { useFakeSeed, useFakeSetDefaultRefDate, useFakeUuid } from "katanakit-js";
|
|
401
|
+
|
|
402
|
+
const seed = await useFakeSeed(); // e.g. 1696121567592875 — log it in CI
|
|
403
|
+
await useFakeSetDefaultRefDate("2026-01-01");
|
|
404
|
+
|
|
405
|
+
await useFakeSeed(seed); // replay the exact same sequence
|
|
406
|
+
const id = await useFakeUuid();
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Seed data (users, products, orders)
|
|
410
|
+
|
|
411
|
+
Compose the helpers with `useFakeList` to build realistic fixtures, then write
|
|
412
|
+
them anywhere with the [filesystem helpers](#filesystem-nodebun):
|
|
413
|
+
|
|
414
|
+
```ts
|
|
415
|
+
import {
|
|
416
|
+
useEnsureDir,
|
|
417
|
+
useFakeDate,
|
|
418
|
+
useFakeEmail,
|
|
419
|
+
useFakeFullName,
|
|
420
|
+
useFakeList,
|
|
421
|
+
useFakeNumber,
|
|
422
|
+
useFakeSeed,
|
|
423
|
+
useFakeSetDefaultRefDate,
|
|
424
|
+
useFakeText,
|
|
425
|
+
useFakeUuid,
|
|
426
|
+
useWriteJsonFile,
|
|
427
|
+
} from "katanakit-js";
|
|
428
|
+
|
|
429
|
+
await useFakeSeed(42);
|
|
430
|
+
await useFakeSetDefaultRefDate("2026-01-01");
|
|
431
|
+
|
|
432
|
+
const users = await useFakeList(
|
|
433
|
+
async () => ({
|
|
434
|
+
id: await useFakeUuid(),
|
|
435
|
+
fullName: await useFakeFullName(),
|
|
436
|
+
email: await useFakeEmail(),
|
|
437
|
+
createdAt: (await useFakeDate("2024-01-01")).toISOString(),
|
|
438
|
+
}),
|
|
439
|
+
5,
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
const products = await useFakeList(
|
|
443
|
+
async () => ({
|
|
444
|
+
id: await useFakeUuid(),
|
|
445
|
+
name: await useFakeText(3),
|
|
446
|
+
price: await useFakeNumber(5, 250),
|
|
447
|
+
stock: await useFakeNumber(0, 120),
|
|
448
|
+
}),
|
|
449
|
+
8,
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
// Relations: the factory receives the index
|
|
453
|
+
const orders = await useFakeList(
|
|
454
|
+
async (index) => ({
|
|
455
|
+
id: await useFakeUuid(),
|
|
456
|
+
userId: users[index % users.length].id,
|
|
457
|
+
productId: products[index % products.length].id,
|
|
458
|
+
quantity: await useFakeNumber(1, 6),
|
|
459
|
+
placedAt: (await useFakeDate("2025-01-01")).toISOString(),
|
|
460
|
+
}),
|
|
461
|
+
12,
|
|
462
|
+
);
|
|
463
|
+
|
|
464
|
+
await useEnsureDir("data/seed");
|
|
465
|
+
await useWriteJsonFile("data/seed/users.json", users);
|
|
466
|
+
// feed the arrays to your seeder: prisma.user.createMany({ data: users }), ...
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
A runnable version (users, products and orders with relations, written as JSON)
|
|
470
|
+
lives in [`examples/seed/`](./examples/seed/README.md).
|
|
332
471
|
|
|
333
472
|
## AI assistant (Kitt)
|
|
334
473
|
|
package/dist/core/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from "./services/agent.service.js";
|
|
|
3
3
|
export * from "./services/assistant.service.js";
|
|
4
4
|
export * from "./services/dates.service.js";
|
|
5
5
|
export * from "./services/error.service.js";
|
|
6
|
+
export * from "./services/faker.service.js";
|
|
6
7
|
export * from "./services/formatter.service.js";
|
|
7
8
|
export * from "./services/generator.service.js";
|
|
8
9
|
export * from "./services/geometry.service.js";
|
package/dist/core/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC"}
|
package/dist/core/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export * from "./services/agent.service.js";
|
|
|
3
3
|
export * from "./services/assistant.service.js";
|
|
4
4
|
export * from "./services/dates.service.js";
|
|
5
5
|
export * from "./services/error.service.js";
|
|
6
|
+
export * from "./services/faker.service.js";
|
|
6
7
|
export * from "./services/formatter.service.js";
|
|
7
8
|
export * from "./services/generator.service.js";
|
|
8
9
|
export * from "./services/geometry.service.js";
|
package/dist/core/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { FakeVehicle } from "../../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Seeds the faker instance for reproducible output, or rolls a new random seed.
|
|
4
|
+
*
|
|
5
|
+
* The sequence depends on the seed, the number of calls made since it was set
|
|
6
|
+
* and the faker major version — keep the call order stable for stable output.
|
|
7
|
+
*
|
|
8
|
+
* @param seed - Optional numeric seed. Omit it to generate a fresh random seed
|
|
9
|
+
* (log the returned value and pass it back later to replay the exact run).
|
|
10
|
+
* @returns The seed that was set.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { useFakeSeed, useFakeUuid } from "katanakit-js";
|
|
15
|
+
*
|
|
16
|
+
* const seed = await useFakeSeed(); // random, but loggable/replayable
|
|
17
|
+
* await useFakeSeed(seed); // replays the same sequence
|
|
18
|
+
* await useFakeUuid();
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function useFakeSeed(seed?: number): Promise<number>;
|
|
22
|
+
/**
|
|
23
|
+
* Pins the reference date faker uses for relative date helpers, so
|
|
24
|
+
* date-dependent output stays reproducible next to {@link useFakeSeed}.
|
|
25
|
+
*
|
|
26
|
+
* @param refDate - Static date (`Date`, ISO string or epoch ms) or a factory
|
|
27
|
+
* returning a fresh `Date` on every call. Omit it to reset to the current time.
|
|
28
|
+
* @returns The reference date now in effect.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* import { useFakeSeed, useFakeSetDefaultRefDate, useFakeDate } from "katanakit-js";
|
|
33
|
+
*
|
|
34
|
+
* await useFakeSeed(42);
|
|
35
|
+
* await useFakeSetDefaultRefDate("2026-01-01");
|
|
36
|
+
* await useFakeDate(); // reproducible between 1970-01-01 and 2026-01-01
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function useFakeSetDefaultRefDate(refDate?: Date | number | string | (() => Date)): Promise<Date>;
|
|
40
|
+
/**
|
|
41
|
+
* Generates a v4 UUID.
|
|
42
|
+
*
|
|
43
|
+
* @returns A random UUID string.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const id = await useFakeUuid();
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function useFakeUuid(): Promise<string>;
|
|
51
|
+
/**
|
|
52
|
+
* Generates a fake email address.
|
|
53
|
+
*
|
|
54
|
+
* @returns An email address.
|
|
55
|
+
*/
|
|
56
|
+
export declare function useFakeEmail(): Promise<string>;
|
|
57
|
+
/**
|
|
58
|
+
* Generates a fake full name.
|
|
59
|
+
*
|
|
60
|
+
* @returns A full name, e.g. `"Ada Lovelace"`.
|
|
61
|
+
*/
|
|
62
|
+
export declare function useFakeFullName(): Promise<string>;
|
|
63
|
+
/**
|
|
64
|
+
* Generates a fake first name.
|
|
65
|
+
*
|
|
66
|
+
* @returns A first name.
|
|
67
|
+
*/
|
|
68
|
+
export declare function useFakeFirstName(): Promise<string>;
|
|
69
|
+
/**
|
|
70
|
+
* Generates a fake last name.
|
|
71
|
+
*
|
|
72
|
+
* @returns A last name.
|
|
73
|
+
*/
|
|
74
|
+
export declare function useFakeLastName(): Promise<string>;
|
|
75
|
+
/**
|
|
76
|
+
* Generates a fake phone number.
|
|
77
|
+
*
|
|
78
|
+
* @returns A phone number string.
|
|
79
|
+
*/
|
|
80
|
+
export declare function useFakePhone(): Promise<string>;
|
|
81
|
+
/**
|
|
82
|
+
* Generates a fake company name.
|
|
83
|
+
*
|
|
84
|
+
* @returns A company name.
|
|
85
|
+
*/
|
|
86
|
+
export declare function useFakeCompanyName(): Promise<string>;
|
|
87
|
+
/**
|
|
88
|
+
* Generates a fake URL.
|
|
89
|
+
*
|
|
90
|
+
* @returns An absolute URL.
|
|
91
|
+
*/
|
|
92
|
+
export declare function useFakeUrl(): Promise<string>;
|
|
93
|
+
/**
|
|
94
|
+
* Generates lorem-ipsum text.
|
|
95
|
+
*
|
|
96
|
+
* @param words - Number of words (default: `12`).
|
|
97
|
+
* @returns A space-separated string of words.
|
|
98
|
+
*/
|
|
99
|
+
export declare function useFakeText(words?: number): Promise<string>;
|
|
100
|
+
/**
|
|
101
|
+
* Generates an integer within an inclusive range.
|
|
102
|
+
*
|
|
103
|
+
* @param min - Lower bound (default: `0`).
|
|
104
|
+
* @param max - Upper bound (default: `100`).
|
|
105
|
+
* @returns A random integer between `min` and `max`.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* const age = await useFakeNumber(18, 65);
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export declare function useFakeNumber(min?: number, max?: number): Promise<number>;
|
|
113
|
+
/**
|
|
114
|
+
* Generates a random boolean.
|
|
115
|
+
*
|
|
116
|
+
* @returns `true` or `false`.
|
|
117
|
+
*/
|
|
118
|
+
export declare function useFakeBoolean(): Promise<boolean>;
|
|
119
|
+
/**
|
|
120
|
+
* Generates a random date within an optional range.
|
|
121
|
+
*
|
|
122
|
+
* @param from - Lower bound (default: `1970-01-01`).
|
|
123
|
+
* @param to - Upper bound (default: faker's reference date, see
|
|
124
|
+
* {@link useFakeSetDefaultRefDate} — the current time when unset).
|
|
125
|
+
* @returns A `Date` instance.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* const hiredAt = await useFakeDate(new Date("2020-01-01"), new Date("2025-12-31"));
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export declare function useFakeDate(from?: Date | number | string, to?: Date | number | string): Promise<Date>;
|
|
133
|
+
/**
|
|
134
|
+
* Generates a generic fake vehicle (brand, model, type, fuel, color, vin, plate).
|
|
135
|
+
*
|
|
136
|
+
* @returns A {@link FakeVehicle} object.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* const vehicle = await useFakeVehicle();
|
|
141
|
+
* // { brand: "Jeep", model: "Wrangler", plate: "HJ47FNP", ... }
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export declare function useFakeVehicle(): Promise<FakeVehicle>;
|
|
145
|
+
/**
|
|
146
|
+
* Builds an array of fake items from a factory (sync or async).
|
|
147
|
+
*
|
|
148
|
+
* @typeParam T - Item type produced by the factory.
|
|
149
|
+
* @param factory - Called once per item; receives the zero-based index.
|
|
150
|
+
* @param count - Number of items to generate (non-negative integer).
|
|
151
|
+
* @returns A promise resolving to the generated array.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```ts
|
|
155
|
+
* const vehicles = await useFakeList(() => useFakeVehicle(), 5);
|
|
156
|
+
* const relations = await useFakeList((index) => ({ user: users[index % users.length] }), 10);
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export declare function useFakeList<T>(factory: (index: number) => T | Promise<T>, count: number): Promise<T[]>;
|
|
160
|
+
//# sourceMappingURL=faker.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"faker.service.d.ts","sourceRoot":"","sources":["../../../src/core/services/faker.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA+BxD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,GAC7C,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAGnD;AAED;;;;GAIG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAGpD;AAED;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAGvD;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAGxD;AAED;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAGvD;AAED;;;;GAIG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAGpD;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAG1D;AAED;;;;GAIG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAGlD;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,KAAK,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAG7D;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,GAAG,SAAI,EAAE,GAAG,SAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGvE;AAED;;;;GAIG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAGvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,WAAW,CAChC,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,EAC7B,EAAE,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,GACzB,OAAO,CAAC,IAAI,CAAC,CAMf;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC,CAW3D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAClC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC1C,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,CAAC,EAAE,CAAC,CAKd"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/** Cached lazy faker instance (reset on failure so a later call can retry). */
|
|
2
|
+
let fakerPromise = null;
|
|
3
|
+
/** Loads faker on first use, or rejects with an actionable install error. */
|
|
4
|
+
async function loadFaker() {
|
|
5
|
+
if (!fakerPromise) {
|
|
6
|
+
fakerPromise = import("@faker-js/faker")
|
|
7
|
+
.then((module) => module.faker)
|
|
8
|
+
.catch((error) => {
|
|
9
|
+
fakerPromise = null;
|
|
10
|
+
throw new Error('[Faker] The optional peer dependency "@faker-js/faker" is not installed. Run "bun add @faker-js/faker" (or "npm install @faker-js/faker").', { cause: error });
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
return fakerPromise;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Seeds the faker instance for reproducible output, or rolls a new random seed.
|
|
17
|
+
*
|
|
18
|
+
* The sequence depends on the seed, the number of calls made since it was set
|
|
19
|
+
* and the faker major version — keep the call order stable for stable output.
|
|
20
|
+
*
|
|
21
|
+
* @param seed - Optional numeric seed. Omit it to generate a fresh random seed
|
|
22
|
+
* (log the returned value and pass it back later to replay the exact run).
|
|
23
|
+
* @returns The seed that was set.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { useFakeSeed, useFakeUuid } from "katanakit-js";
|
|
28
|
+
*
|
|
29
|
+
* const seed = await useFakeSeed(); // random, but loggable/replayable
|
|
30
|
+
* await useFakeSeed(seed); // replays the same sequence
|
|
31
|
+
* await useFakeUuid();
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export async function useFakeSeed(seed) {
|
|
35
|
+
const faker = await loadFaker();
|
|
36
|
+
return seed === undefined ? faker.seed() : faker.seed(seed);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Pins the reference date faker uses for relative date helpers, so
|
|
40
|
+
* date-dependent output stays reproducible next to {@link useFakeSeed}.
|
|
41
|
+
*
|
|
42
|
+
* @param refDate - Static date (`Date`, ISO string or epoch ms) or a factory
|
|
43
|
+
* returning a fresh `Date` on every call. Omit it to reset to the current time.
|
|
44
|
+
* @returns The reference date now in effect.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { useFakeSeed, useFakeSetDefaultRefDate, useFakeDate } from "katanakit-js";
|
|
49
|
+
*
|
|
50
|
+
* await useFakeSeed(42);
|
|
51
|
+
* await useFakeSetDefaultRefDate("2026-01-01");
|
|
52
|
+
* await useFakeDate(); // reproducible between 1970-01-01 and 2026-01-01
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export async function useFakeSetDefaultRefDate(refDate) {
|
|
56
|
+
const faker = await loadFaker();
|
|
57
|
+
faker.setDefaultRefDate(refDate);
|
|
58
|
+
return faker.defaultRefDate();
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Generates a v4 UUID.
|
|
62
|
+
*
|
|
63
|
+
* @returns A random UUID string.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* const id = await useFakeUuid();
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export async function useFakeUuid() {
|
|
71
|
+
const faker = await loadFaker();
|
|
72
|
+
return faker.string.uuid();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Generates a fake email address.
|
|
76
|
+
*
|
|
77
|
+
* @returns An email address.
|
|
78
|
+
*/
|
|
79
|
+
export async function useFakeEmail() {
|
|
80
|
+
const faker = await loadFaker();
|
|
81
|
+
return faker.internet.email();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Generates a fake full name.
|
|
85
|
+
*
|
|
86
|
+
* @returns A full name, e.g. `"Ada Lovelace"`.
|
|
87
|
+
*/
|
|
88
|
+
export async function useFakeFullName() {
|
|
89
|
+
const faker = await loadFaker();
|
|
90
|
+
return faker.person.fullName();
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Generates a fake first name.
|
|
94
|
+
*
|
|
95
|
+
* @returns A first name.
|
|
96
|
+
*/
|
|
97
|
+
export async function useFakeFirstName() {
|
|
98
|
+
const faker = await loadFaker();
|
|
99
|
+
return faker.person.firstName();
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Generates a fake last name.
|
|
103
|
+
*
|
|
104
|
+
* @returns A last name.
|
|
105
|
+
*/
|
|
106
|
+
export async function useFakeLastName() {
|
|
107
|
+
const faker = await loadFaker();
|
|
108
|
+
return faker.person.lastName();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Generates a fake phone number.
|
|
112
|
+
*
|
|
113
|
+
* @returns A phone number string.
|
|
114
|
+
*/
|
|
115
|
+
export async function useFakePhone() {
|
|
116
|
+
const faker = await loadFaker();
|
|
117
|
+
return faker.phone.number();
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Generates a fake company name.
|
|
121
|
+
*
|
|
122
|
+
* @returns A company name.
|
|
123
|
+
*/
|
|
124
|
+
export async function useFakeCompanyName() {
|
|
125
|
+
const faker = await loadFaker();
|
|
126
|
+
return faker.company.name();
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Generates a fake URL.
|
|
130
|
+
*
|
|
131
|
+
* @returns An absolute URL.
|
|
132
|
+
*/
|
|
133
|
+
export async function useFakeUrl() {
|
|
134
|
+
const faker = await loadFaker();
|
|
135
|
+
return faker.internet.url();
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Generates lorem-ipsum text.
|
|
139
|
+
*
|
|
140
|
+
* @param words - Number of words (default: `12`).
|
|
141
|
+
* @returns A space-separated string of words.
|
|
142
|
+
*/
|
|
143
|
+
export async function useFakeText(words = 12) {
|
|
144
|
+
const faker = await loadFaker();
|
|
145
|
+
return faker.lorem.words(words);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Generates an integer within an inclusive range.
|
|
149
|
+
*
|
|
150
|
+
* @param min - Lower bound (default: `0`).
|
|
151
|
+
* @param max - Upper bound (default: `100`).
|
|
152
|
+
* @returns A random integer between `min` and `max`.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
156
|
+
* const age = await useFakeNumber(18, 65);
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export async function useFakeNumber(min = 0, max = 100) {
|
|
160
|
+
const faker = await loadFaker();
|
|
161
|
+
return faker.number.int({ max, min });
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Generates a random boolean.
|
|
165
|
+
*
|
|
166
|
+
* @returns `true` or `false`.
|
|
167
|
+
*/
|
|
168
|
+
export async function useFakeBoolean() {
|
|
169
|
+
const faker = await loadFaker();
|
|
170
|
+
return faker.datatype.boolean();
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Generates a random date within an optional range.
|
|
174
|
+
*
|
|
175
|
+
* @param from - Lower bound (default: `1970-01-01`).
|
|
176
|
+
* @param to - Upper bound (default: faker's reference date, see
|
|
177
|
+
* {@link useFakeSetDefaultRefDate} — the current time when unset).
|
|
178
|
+
* @returns A `Date` instance.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* const hiredAt = await useFakeDate(new Date("2020-01-01"), new Date("2025-12-31"));
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
export async function useFakeDate(from, to) {
|
|
186
|
+
const faker = await loadFaker();
|
|
187
|
+
return faker.date.between({
|
|
188
|
+
from: from ?? "1970-01-01",
|
|
189
|
+
to: to ?? faker.defaultRefDate(),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Generates a generic fake vehicle (brand, model, type, fuel, color, vin, plate).
|
|
194
|
+
*
|
|
195
|
+
* @returns A {@link FakeVehicle} object.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```ts
|
|
199
|
+
* const vehicle = await useFakeVehicle();
|
|
200
|
+
* // { brand: "Jeep", model: "Wrangler", plate: "HJ47FNP", ... }
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
export async function useFakeVehicle() {
|
|
204
|
+
const faker = await loadFaker();
|
|
205
|
+
return {
|
|
206
|
+
brand: faker.vehicle.manufacturer(),
|
|
207
|
+
color: faker.vehicle.color(),
|
|
208
|
+
fuel: faker.vehicle.fuel(),
|
|
209
|
+
model: faker.vehicle.model(),
|
|
210
|
+
plate: faker.vehicle.vrm(),
|
|
211
|
+
type: faker.vehicle.type(),
|
|
212
|
+
vin: faker.vehicle.vin(),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Builds an array of fake items from a factory (sync or async).
|
|
217
|
+
*
|
|
218
|
+
* @typeParam T - Item type produced by the factory.
|
|
219
|
+
* @param factory - Called once per item; receives the zero-based index.
|
|
220
|
+
* @param count - Number of items to generate (non-negative integer).
|
|
221
|
+
* @returns A promise resolving to the generated array.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```ts
|
|
225
|
+
* const vehicles = await useFakeList(() => useFakeVehicle(), 5);
|
|
226
|
+
* const relations = await useFakeList((index) => ({ user: users[index % users.length] }), 10);
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
export async function useFakeList(factory, count) {
|
|
230
|
+
if (!Number.isInteger(count) || count < 0) {
|
|
231
|
+
throw new Error("[Faker] count must be a non-negative integer.");
|
|
232
|
+
}
|
|
233
|
+
return Promise.all(Array.from({ length: count }, (_, index) => factory(index)));
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=faker.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"faker.service.js","sourceRoot":"","sources":["../../../src/core/services/faker.service.ts"],"names":[],"mappings":"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"}
|