@masaori/zod-to-entity-definitions 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,413 @@
1
+ # zod-to-entity-definitions
2
+
3
+ A TypeScript library that allows you to define data models using Zod with extended metadata (Primary Key, Foreign Key, Unique) and convert them into framework-agnostic Entity Definitions (ER models).
4
+
5
+ ## Features
6
+
7
+ - 🔧 **Zod Extensions**: Add `.pk()`, `.unique()`, and `.ref()` methods to Zod schemas
8
+ - 🏗️ **Entity & Struct Factories**: Define entities and reusable struct types
9
+ - 🔄 **Automatic Generation**: Convert Zod schemas to entity definitions and relations
10
+ - 🔒 **Type-Safe**: Full TypeScript support with strict typing
11
+ - 📦 **Framework Agnostic**: Generate generic entity definitions usable by any framework
12
+ - ✅ **Validation**: Built-in validation for entity nesting and reference integrity
13
+
14
+ ## Installation
15
+
16
+ ### Installation
17
+
18
+ Install the package from npm:
19
+
20
+ ```bash
21
+ npm install @masaori/zod-to-entity-definitions zod
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ```typescript
27
+ import { z } from 'zod';
28
+ import {
29
+ entity,
30
+ struct,
31
+ generateEntities,
32
+ generateRelations,
33
+ } from '@masaori/zod-to-entity-definitions';
34
+
35
+ // 1. Define a Struct (reusable component)
36
+ const Address = struct({
37
+ name: 'AddressStruct',
38
+ description: 'Common address',
39
+ columns: {
40
+ city: z.string(),
41
+ street: z.string(),
42
+ },
43
+ });
44
+
45
+ // 2. Define Entities
46
+ const Company = entity({
47
+ name: 'Company',
48
+ columns: {
49
+ id: z.string().pk(),
50
+ name: z.string(),
51
+ address: Address, // Using struct is OK
52
+ },
53
+ });
54
+
55
+ const User = entity({
56
+ name: 'User',
57
+ columns: {
58
+ id: z.string().pk(),
59
+ email: z.string().email().unique(),
60
+ companyId: z.string().ref(Company), // Reference to Company entity
61
+ },
62
+ });
63
+
64
+ // 3. Generate Entity Definitions
65
+ const definitions = generateEntities([Company, User]);
66
+
67
+ // 4. Generate Relations
68
+ const relations = generateRelations(definitions);
69
+
70
+ console.log(JSON.stringify(definitions, null, 2));
71
+ console.log(JSON.stringify(relations, null, 2));
72
+ ```
73
+
74
+ > 📝 **See the [examples](./examples) directory for complete working examples with generated JSON output.**
75
+
76
+ ## API Reference
77
+
78
+ ### Zod Extensions
79
+
80
+ The library extends Zod schemas with the following methods:
81
+
82
+ #### `.pk()`
83
+
84
+ Marks a field as the Primary Key.
85
+
86
+ ```typescript
87
+ id: z.string().pk();
88
+ ```
89
+
90
+ #### `.unique()`
91
+
92
+ Marks a field as Unique.
93
+
94
+ ```typescript
95
+ email: z.string().email().unique();
96
+ ```
97
+
98
+ #### `.ref(targetEntity, targetColumn?)`
99
+
100
+ Marks a field as a Foreign Key reference to another entity.
101
+
102
+ - `targetEntity`: Must be a schema created with `entity()`
103
+ - `targetColumn`: Optional, defaults to "id"
104
+
105
+ ```typescript
106
+ companyId: z.string().ref(Company);
107
+ managerId: z.string().ref(User, 'userId');
108
+ ```
109
+
110
+ ### Factory Functions
111
+
112
+ #### `entity(config)`
113
+
114
+ Creates an entity schema with metadata.
115
+
116
+ ```typescript
117
+ type EntityConfig<T extends z.ZodRawShape> = {
118
+ name: string;
119
+ description?: string;
120
+ columns: T;
121
+ };
122
+ ```
123
+
124
+ #### `struct(config)`
125
+
126
+ Creates a struct schema for reusable components.
127
+
128
+ ```typescript
129
+ type StructConfig<T extends z.ZodRawShape> = {
130
+ name: string;
131
+ description?: string;
132
+ columns: T;
133
+ };
134
+ ```
135
+
136
+ ### Generator Functions
137
+
138
+ #### `generateEntities(schemas)`
139
+
140
+ Parses Zod schemas and returns an array of `EntityDefinition`.
141
+
142
+ **Validation Rules:**
143
+
144
+ 1. Entities cannot directly embed other entities (must use `.ref()`)
145
+ 2. `.ref()` must point to valid entity schemas
146
+
147
+ ```typescript
148
+ const definitions = generateEntities([Company, User]);
149
+ ```
150
+
151
+ #### `generateRelations(definitions)`
152
+
153
+ Analyzes entity definitions to construct relation maps.
154
+
155
+ ```typescript
156
+ const relations = generateRelations(definitions);
157
+ ```
158
+
159
+ ## Type Definitions
160
+
161
+ ### EntityDefinition
162
+
163
+ ```typescript
164
+ type EntityDefinition = {
165
+ name: string;
166
+ description?: string;
167
+ properties: EntityPropertyDefinition[];
168
+ };
169
+ ```
170
+
171
+ ### EntityPropertyDefinition
172
+
173
+ Union type representing different property types:
174
+
175
+ - `EntityPropertyDefinitionPrimaryKey`: Primary key field
176
+ - `EntityPropertyDefinitionPrimitive`: boolean, number, string, Date
177
+ - `EntityPropertyDefinitionTypedStruct`: Reference to a struct type
178
+ - `EntityPropertyDefinitionReferencedObject`: Foreign key reference
179
+
180
+ ### EntityRelation
181
+
182
+ ```typescript
183
+ type EntityRelation = {
184
+ entityName: string;
185
+ referTos: EntityRelationReferTo[];
186
+ referredBys: EntityRelationReferredBy[];
187
+ };
188
+ ```
189
+
190
+ ## Advanced Usage
191
+
192
+ ### Nullable and Optional Fields
193
+
194
+ ```typescript
195
+ const User = entity({
196
+ name: 'User',
197
+ columns: {
198
+ id: z.string().pk(),
199
+ nickname: z.string().optional(), // Optional field
200
+ bio: z.string().nullable(), // Nullable field
201
+ },
202
+ });
203
+ ```
204
+
205
+ ### Array Fields
206
+
207
+ ```typescript
208
+ const User = entity({
209
+ name: 'User',
210
+ columns: {
211
+ id: z.string().pk(),
212
+ tags: z.array(z.string()),
213
+ scores: z.array(z.number()).optional(),
214
+ },
215
+ });
216
+ ```
217
+
218
+ ### Enum Fields
219
+
220
+ ```typescript
221
+ const User = entity({
222
+ name: 'User',
223
+ columns: {
224
+ id: z.string().pk(),
225
+ role: z.enum(['admin', 'user', 'guest']),
226
+ },
227
+ });
228
+ ```
229
+
230
+ ### Complex Relations
231
+
232
+ ```typescript
233
+ const Department = entity({
234
+ name: 'Department',
235
+ columns: {
236
+ id: z.string().pk(),
237
+ name: z.string(),
238
+ },
239
+ });
240
+
241
+ const Employee = entity({
242
+ name: 'Employee',
243
+ columns: {
244
+ id: z.string().pk(),
245
+ name: z.string(),
246
+ departmentId: z.string().ref(Department),
247
+ },
248
+ });
249
+
250
+ const Project = entity({
251
+ name: 'Project',
252
+ columns: {
253
+ id: z.string().pk(),
254
+ name: z.string(),
255
+ leadId: z.string().ref(Employee),
256
+ departmentId: z.string().ref(Department),
257
+ },
258
+ });
259
+ ```
260
+
261
+ ## Validation Rules
262
+
263
+ ### ❌ Entity Nesting (Not Allowed)
264
+
265
+ ```typescript
266
+ const User = entity({
267
+ name: 'User',
268
+ columns: {
269
+ id: z.string().pk(),
270
+ company: Company, // ❌ Error: Direct entity embedding not allowed
271
+ },
272
+ });
273
+ ```
274
+
275
+ ### ✅ Use References Instead
276
+
277
+ ```typescript
278
+ const User = entity({
279
+ name: 'User',
280
+ columns: {
281
+ id: z.string().pk(),
282
+ companyId: z.string().ref(Company), // ✅ Correct: Use .ref()
283
+ },
284
+ });
285
+ ```
286
+
287
+ ### ❌ Invalid References
288
+
289
+ ```typescript
290
+ const Address = struct({
291
+ name: 'Address',
292
+ columns: { city: z.string() },
293
+ });
294
+
295
+ const User = entity({
296
+ name: 'User',
297
+ columns: {
298
+ id: z.string().pk(),
299
+ addressId: z.string().ref(Address), // ❌ Error: Can't reference struct
300
+ },
301
+ });
302
+ ```
303
+
304
+ ## Development
305
+
306
+ ```bash
307
+ # Install dependencies
308
+ pnpm install
309
+
310
+ # Run tests
311
+ pnpm test
312
+
313
+ # Run tests in watch mode
314
+ pnpm test:watch
315
+
316
+ # Type checking
317
+ pnpm check-types
318
+
319
+ # Linting
320
+ pnpm lint
321
+
322
+ # Auto-fix lint issues
323
+ pnpm lint:fix
324
+
325
+ # Format code
326
+ pnpm format
327
+
328
+ # Build
329
+ pnpm build
330
+ ```
331
+
332
+ ## CI/CD
333
+
334
+ This project uses GitHub Actions for continuous integration and deployment.
335
+
336
+ ### Workflows
337
+
338
+ 1. **Commit Message Validation** (`.github/workflows/commit-check.yml`)
339
+ - Runs on all PRs
340
+ - Validates commit messages using [Conventional Commits](https://www.conventionalcommits.org/)
341
+ - Ensures all commits are linear (no merge commits)
342
+
343
+ 2. **Lint and Test** (`.github/workflows/lint-test.yml`)
344
+ - Runs on all PRs and pushes to main
345
+ - Executes linting, type checking, and tests
346
+ - Must pass before merging
347
+
348
+ 3. **Publish to GitHub Packages** (`.github/workflows/publish.yml`)
349
+ - Manual workflow trigger only (workflow_dispatch)
350
+ - Automatically determines version bump using semantic versioning
351
+ - Publishes to GitHub Packages with automatic changelog generation
352
+ - Version bumps follow Conventional Commits:
353
+ - `feat:` → minor version bump
354
+ - `fix:`, `docs:`, `style:`, `refactor:`, `test:`, `build:`, `ci:`, `chore:` → patch version bump
355
+ - `BREAKING CHANGE:` → major version bump
356
+
357
+ ### Publishing to GitHub Packages
358
+
359
+ Publishing is automated via GitHub Actions. To publish a new version:
360
+
361
+ 1. **Required tokens**: No additional tokens needed!
362
+ - The workflow uses the built-in `GITHUB_TOKEN` which is automatically provided by GitHub Actions
363
+ - The `GITHUB_TOKEN` has the necessary permissions to:
364
+ - Write to the repository (create tags, update files)
365
+ - Publish to GitHub Packages
366
+ - Create GitHub releases
367
+ - **No manual token configuration required** - it works out of the box
368
+
369
+ 2. **Trigger the publish workflow**:
370
+ - Go to the Actions tab in GitHub
371
+ - Select "Publish to GitHub Packages" workflow
372
+ - Click "Run workflow" on the main branch
373
+
374
+ 3. **Automated process**:
375
+ - The workflow will analyze commit messages since the last release
376
+ - Automatically determine the version bump (major/minor/patch)
377
+ - Update `package.json` and `CHANGELOG.md`
378
+ - Create a git tag and GitHub release
379
+ - Publish to GitHub Packages
380
+
381
+ ### Commit Message Format
382
+
383
+ All commits must follow the [Conventional Commits](https://www.conventionalcommits.org/) specification:
384
+
385
+ ```
386
+ <type>[optional scope]: <description>
387
+
388
+ [optional body]
389
+
390
+ [optional footer(s)]
391
+ ```
392
+
393
+ Examples:
394
+
395
+ - `feat: add new entity validation`
396
+ - `fix: correct reference resolution`
397
+ - `docs: update README with examples`
398
+ - `feat!: remove deprecated API` (breaking change)
399
+
400
+ ### Pre-publish Checklist
401
+
402
+ The package includes a `prepublishOnly` script that automatically runs before publishing:
403
+
404
+ - Type checking (`pnpm check-types`)
405
+ - Linting (`pnpm lint`)
406
+ - Tests (`pnpm test`)
407
+ - Build (`pnpm build`)
408
+
409
+ All these checks must pass before the package can be published.
410
+
411
+ ## License
412
+
413
+ MIT
@@ -0,0 +1,101 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const PK_SYMBOL: unique symbol;
4
+ declare const UNIQUE_SYMBOL: unique symbol;
5
+ declare const REF_SYMBOL: unique symbol;
6
+ type RefMetadata = {
7
+ targetEntity: z.ZodTypeAny;
8
+ targetColumn: string;
9
+ };
10
+ declare module 'zod' {
11
+ interface ZodType {
12
+ [PK_SYMBOL]?: boolean;
13
+ [UNIQUE_SYMBOL]?: boolean;
14
+ [REF_SYMBOL]?: RefMetadata;
15
+ pk(): this;
16
+ unique(): this;
17
+ ref(targetEntity: z.ZodTypeAny, targetColumn?: string): this;
18
+ }
19
+ }
20
+
21
+ type EntityConfig<T extends z.ZodRawShape> = {
22
+ name: string;
23
+ description?: string;
24
+ columns: T;
25
+ };
26
+ type StructConfig<T extends z.ZodRawShape> = {
27
+ name: string;
28
+ description?: string;
29
+ columns: T;
30
+ };
31
+ declare const ENTITY_NAME_BRAND: unique symbol;
32
+ type EntitySchema<TName extends string, TShape extends z.ZodRawShape> = z.ZodObject<TShape> & {
33
+ readonly [ENTITY_NAME_BRAND]: TName;
34
+ };
35
+ declare function entity<const TConfig extends EntityConfig<z.ZodRawShape>>(config: TConfig): EntitySchema<TConfig['name'], TConfig['columns']>;
36
+ declare function struct<T extends z.ZodRawShape>(config: StructConfig<T>): z.ZodObject<T>;
37
+
38
+ type EntityDefinition<TEntityNames = string> = {
39
+ name: TEntityNames;
40
+ description?: string;
41
+ properties: EntityPropertyDefinition[];
42
+ };
43
+ type EntityPropertyDefinition = EntityPropertyDefinitionPrimaryKey | EntityPropertyDefinitionPrimitive | EntityPropertyDefinitionTypedStruct | EntityPropertyDefinitionReferencedObject;
44
+ type EntityPropertyDefinitionPrimaryKey = {
45
+ isReference: false;
46
+ propertyType: 'PrimaryKey';
47
+ name: string;
48
+ description?: string;
49
+ };
50
+ type EntityPropertyDefinitionPrimitive = {
51
+ isReference: false;
52
+ propertyType: 'boolean' | 'number' | 'string' | 'Date' | 'struct';
53
+ name: string;
54
+ isUnique: boolean;
55
+ isNullable: boolean;
56
+ isArray: boolean;
57
+ acceptableValues: string[] | null;
58
+ description?: string;
59
+ };
60
+ type EntityPropertyDefinitionTypedStruct = {
61
+ isReference: false;
62
+ propertyType: 'typedStruct';
63
+ name: string;
64
+ structTypeName: string;
65
+ isUnique: boolean;
66
+ isNullable: boolean;
67
+ isArray: boolean;
68
+ description?: string;
69
+ };
70
+ type EntityPropertyDefinitionReferencedObject = {
71
+ isReference: true;
72
+ name: string;
73
+ targetEntityDefinitionName: string;
74
+ isUnique: boolean;
75
+ isNullable: boolean;
76
+ description?: string;
77
+ };
78
+ type EntityRelationReferTo<T = string> = {
79
+ entityName: T;
80
+ propertyName: string;
81
+ isUnique: boolean;
82
+ };
83
+ type EntityRelationReferredBy<T = string> = {
84
+ entityName: T;
85
+ propertyName: string;
86
+ isUnique: boolean;
87
+ };
88
+ type EntityRelation<T = string> = {
89
+ entityName: T;
90
+ referTos: EntityRelationReferTo<T>[];
91
+ referredBys: EntityRelationReferredBy<T>[];
92
+ };
93
+
94
+ type ExtractEntityName<T> = T extends EntitySchema<infer TName, z.ZodRawShape> ? TName : never;
95
+ type ExtractEntityNames<T extends readonly z.ZodTypeAny[]> = {
96
+ [K in keyof T]: ExtractEntityName<T[K]>;
97
+ }[number];
98
+ declare function generateEntities<const T extends readonly z.ZodTypeAny[]>(schemas: T): EntityDefinition<ExtractEntityNames<T>>[];
99
+ declare function generateRelations(definitions: EntityDefinition[]): EntityRelation[];
100
+
101
+ export { type EntityConfig, type EntityDefinition, type EntityPropertyDefinition, type EntityPropertyDefinitionPrimaryKey, type EntityPropertyDefinitionPrimitive, type EntityPropertyDefinitionReferencedObject, type EntityPropertyDefinitionTypedStruct, type EntityRelation, type EntityRelationReferTo, type EntityRelationReferredBy, type EntitySchema, type StructConfig, entity, generateEntities, generateRelations, struct };
@@ -0,0 +1,101 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const PK_SYMBOL: unique symbol;
4
+ declare const UNIQUE_SYMBOL: unique symbol;
5
+ declare const REF_SYMBOL: unique symbol;
6
+ type RefMetadata = {
7
+ targetEntity: z.ZodTypeAny;
8
+ targetColumn: string;
9
+ };
10
+ declare module 'zod' {
11
+ interface ZodType {
12
+ [PK_SYMBOL]?: boolean;
13
+ [UNIQUE_SYMBOL]?: boolean;
14
+ [REF_SYMBOL]?: RefMetadata;
15
+ pk(): this;
16
+ unique(): this;
17
+ ref(targetEntity: z.ZodTypeAny, targetColumn?: string): this;
18
+ }
19
+ }
20
+
21
+ type EntityConfig<T extends z.ZodRawShape> = {
22
+ name: string;
23
+ description?: string;
24
+ columns: T;
25
+ };
26
+ type StructConfig<T extends z.ZodRawShape> = {
27
+ name: string;
28
+ description?: string;
29
+ columns: T;
30
+ };
31
+ declare const ENTITY_NAME_BRAND: unique symbol;
32
+ type EntitySchema<TName extends string, TShape extends z.ZodRawShape> = z.ZodObject<TShape> & {
33
+ readonly [ENTITY_NAME_BRAND]: TName;
34
+ };
35
+ declare function entity<const TConfig extends EntityConfig<z.ZodRawShape>>(config: TConfig): EntitySchema<TConfig['name'], TConfig['columns']>;
36
+ declare function struct<T extends z.ZodRawShape>(config: StructConfig<T>): z.ZodObject<T>;
37
+
38
+ type EntityDefinition<TEntityNames = string> = {
39
+ name: TEntityNames;
40
+ description?: string;
41
+ properties: EntityPropertyDefinition[];
42
+ };
43
+ type EntityPropertyDefinition = EntityPropertyDefinitionPrimaryKey | EntityPropertyDefinitionPrimitive | EntityPropertyDefinitionTypedStruct | EntityPropertyDefinitionReferencedObject;
44
+ type EntityPropertyDefinitionPrimaryKey = {
45
+ isReference: false;
46
+ propertyType: 'PrimaryKey';
47
+ name: string;
48
+ description?: string;
49
+ };
50
+ type EntityPropertyDefinitionPrimitive = {
51
+ isReference: false;
52
+ propertyType: 'boolean' | 'number' | 'string' | 'Date' | 'struct';
53
+ name: string;
54
+ isUnique: boolean;
55
+ isNullable: boolean;
56
+ isArray: boolean;
57
+ acceptableValues: string[] | null;
58
+ description?: string;
59
+ };
60
+ type EntityPropertyDefinitionTypedStruct = {
61
+ isReference: false;
62
+ propertyType: 'typedStruct';
63
+ name: string;
64
+ structTypeName: string;
65
+ isUnique: boolean;
66
+ isNullable: boolean;
67
+ isArray: boolean;
68
+ description?: string;
69
+ };
70
+ type EntityPropertyDefinitionReferencedObject = {
71
+ isReference: true;
72
+ name: string;
73
+ targetEntityDefinitionName: string;
74
+ isUnique: boolean;
75
+ isNullable: boolean;
76
+ description?: string;
77
+ };
78
+ type EntityRelationReferTo<T = string> = {
79
+ entityName: T;
80
+ propertyName: string;
81
+ isUnique: boolean;
82
+ };
83
+ type EntityRelationReferredBy<T = string> = {
84
+ entityName: T;
85
+ propertyName: string;
86
+ isUnique: boolean;
87
+ };
88
+ type EntityRelation<T = string> = {
89
+ entityName: T;
90
+ referTos: EntityRelationReferTo<T>[];
91
+ referredBys: EntityRelationReferredBy<T>[];
92
+ };
93
+
94
+ type ExtractEntityName<T> = T extends EntitySchema<infer TName, z.ZodRawShape> ? TName : never;
95
+ type ExtractEntityNames<T extends readonly z.ZodTypeAny[]> = {
96
+ [K in keyof T]: ExtractEntityName<T[K]>;
97
+ }[number];
98
+ declare function generateEntities<const T extends readonly z.ZodTypeAny[]>(schemas: T): EntityDefinition<ExtractEntityNames<T>>[];
99
+ declare function generateRelations(definitions: EntityDefinition[]): EntityRelation[];
100
+
101
+ export { type EntityConfig, type EntityDefinition, type EntityPropertyDefinition, type EntityPropertyDefinitionPrimaryKey, type EntityPropertyDefinitionPrimitive, type EntityPropertyDefinitionReferencedObject, type EntityPropertyDefinitionTypedStruct, type EntityRelation, type EntityRelationReferTo, type EntityRelationReferredBy, type EntitySchema, type StructConfig, entity, generateEntities, generateRelations, struct };
package/dist/index.js ADDED
@@ -0,0 +1,267 @@
1
+ 'use strict';
2
+
3
+ var zod = require('zod');
4
+
5
+ // src/setupZod.ts
6
+ var PK_SYMBOL = Symbol("zod-entity-pk");
7
+ var UNIQUE_SYMBOL = Symbol("zod-entity-unique");
8
+ var REF_SYMBOL = Symbol("zod-entity-ref");
9
+ zod.z.ZodType.prototype.pk = function() {
10
+ this[PK_SYMBOL] = true;
11
+ return this;
12
+ };
13
+ zod.z.ZodType.prototype.unique = function() {
14
+ this[UNIQUE_SYMBOL] = true;
15
+ return this;
16
+ };
17
+ zod.z.ZodType.prototype.ref = function(targetEntity, targetColumn = "id") {
18
+ this[REF_SYMBOL] = { targetEntity, targetColumn };
19
+ return this;
20
+ };
21
+ function isPrimaryKey(schema) {
22
+ return schema[PK_SYMBOL] === true;
23
+ }
24
+ function isUnique(schema) {
25
+ return schema[UNIQUE_SYMBOL] === true;
26
+ }
27
+ function getRefMetadata(schema) {
28
+ return schema[REF_SYMBOL];
29
+ }
30
+ var SCHEMA_TYPE_SYMBOL = Symbol("zod-schema-type");
31
+ var SCHEMA_NAME_SYMBOL = Symbol("zod-schema-name");
32
+ var SCHEMA_DESCRIPTION_SYMBOL = Symbol("zod-schema-description");
33
+ function entity(config) {
34
+ const schema = zod.z.object(config.columns);
35
+ schema[SCHEMA_TYPE_SYMBOL] = "entity";
36
+ schema[SCHEMA_NAME_SYMBOL] = config.name;
37
+ if (config.description !== void 0) {
38
+ schema[SCHEMA_DESCRIPTION_SYMBOL] = config.description;
39
+ }
40
+ return schema;
41
+ }
42
+ function struct(config) {
43
+ const schema = zod.z.object(config.columns);
44
+ schema[SCHEMA_TYPE_SYMBOL] = "struct";
45
+ schema[SCHEMA_NAME_SYMBOL] = config.name;
46
+ if (config.description !== void 0) {
47
+ schema[SCHEMA_DESCRIPTION_SYMBOL] = config.description;
48
+ }
49
+ return schema;
50
+ }
51
+ function getSchemaType(schema) {
52
+ if (schema instanceof zod.z.ZodObject) {
53
+ return schema[SCHEMA_TYPE_SYMBOL];
54
+ }
55
+ return void 0;
56
+ }
57
+ function getSchemaName(schema) {
58
+ if (schema instanceof zod.z.ZodObject) {
59
+ return schema[SCHEMA_NAME_SYMBOL];
60
+ }
61
+ return void 0;
62
+ }
63
+ function getSchemaDescription(schema) {
64
+ if (schema instanceof zod.z.ZodObject) {
65
+ return schema[SCHEMA_DESCRIPTION_SYMBOL];
66
+ }
67
+ return void 0;
68
+ }
69
+ function unwrapSchema(schema) {
70
+ let current = schema;
71
+ let isNullable = false;
72
+ let isArray = false;
73
+ while (true) {
74
+ if (current instanceof zod.z.ZodOptional) {
75
+ isNullable = true;
76
+ current = current.unwrap();
77
+ } else if (current instanceof zod.z.ZodNullable) {
78
+ isNullable = true;
79
+ current = current.unwrap();
80
+ } else if (current instanceof zod.z.ZodArray) {
81
+ isArray = true;
82
+ current = current.element;
83
+ } else {
84
+ break;
85
+ }
86
+ }
87
+ return { innerSchema: current, isNullable, isArray };
88
+ }
89
+ function generateEntities(schemas) {
90
+ const definitions = [];
91
+ for (const schema of schemas) {
92
+ const schemaType = getSchemaType(schema);
93
+ if (schemaType !== "entity") {
94
+ continue;
95
+ }
96
+ const name = getSchemaName(schema);
97
+ if (name === void 0) {
98
+ throw new Error("Entity schema must have a name");
99
+ }
100
+ const description = getSchemaDescription(schema);
101
+ if (!(schema instanceof zod.z.ZodObject)) {
102
+ throw new Error(`Entity "${name}" must be a ZodObject`);
103
+ }
104
+ const properties = [];
105
+ const shape = schema.shape;
106
+ for (const [fieldName, fieldSchema] of Object.entries(shape)) {
107
+ if (!(fieldSchema instanceof zod.z.ZodType)) {
108
+ continue;
109
+ }
110
+ const property = parseProperty(fieldName, fieldSchema);
111
+ properties.push(property);
112
+ }
113
+ const entityDefinition = {
114
+ name,
115
+ properties
116
+ };
117
+ if (description !== void 0) {
118
+ entityDefinition.description = description;
119
+ }
120
+ definitions.push(entityDefinition);
121
+ }
122
+ return definitions;
123
+ }
124
+ function parseProperty(fieldName, fieldSchema) {
125
+ const isPk = isPrimaryKey(fieldSchema);
126
+ const isUniqueField = isUnique(fieldSchema);
127
+ const refMetadata = getRefMetadata(fieldSchema);
128
+ if (isPk) {
129
+ const property = {
130
+ isReference: false,
131
+ propertyType: "PrimaryKey",
132
+ name: fieldName
133
+ };
134
+ return property;
135
+ }
136
+ if (refMetadata !== void 0) {
137
+ const { targetEntity } = refMetadata;
138
+ const targetSchemaType = getSchemaType(targetEntity);
139
+ if (targetSchemaType !== "entity") {
140
+ throw new Error(
141
+ `Field "${fieldName}" has .ref() pointing to a non-entity schema. Only entity schemas created with entity() can be referenced.`
142
+ );
143
+ }
144
+ const targetEntityName = getSchemaName(targetEntity);
145
+ if (targetEntityName === void 0) {
146
+ throw new Error(`Referenced entity for field "${fieldName}" must have a name`);
147
+ }
148
+ const { isNullable: isNullable2 } = unwrapSchema(fieldSchema);
149
+ const property = {
150
+ isReference: true,
151
+ name: fieldName,
152
+ targetEntityDefinitionName: targetEntityName,
153
+ isUnique: isUniqueField,
154
+ isNullable: isNullable2
155
+ };
156
+ return property;
157
+ }
158
+ const { innerSchema, isNullable, isArray } = unwrapSchema(fieldSchema);
159
+ const innerSchemaType = getSchemaType(innerSchema);
160
+ if (innerSchemaType === "entity") {
161
+ throw new Error(
162
+ `Field "${fieldName}" contains a direct entity embedding. Entities cannot be directly nested. Use .ref() instead.`
163
+ );
164
+ }
165
+ if (innerSchemaType === "struct") {
166
+ const structName = getSchemaName(innerSchema);
167
+ if (structName === void 0) {
168
+ throw new Error(`Struct schema for field "${fieldName}" must have a name`);
169
+ }
170
+ const property = {
171
+ isReference: false,
172
+ propertyType: "typedStruct",
173
+ name: fieldName,
174
+ structTypeName: structName,
175
+ isUnique: isUniqueField,
176
+ isNullable,
177
+ isArray
178
+ };
179
+ return property;
180
+ }
181
+ const primitiveType = getPrimitiveType(innerSchema);
182
+ if (primitiveType !== null) {
183
+ const acceptableValues = getAcceptableValues(innerSchema);
184
+ const property = {
185
+ isReference: false,
186
+ propertyType: primitiveType,
187
+ name: fieldName,
188
+ isUnique: isUniqueField,
189
+ isNullable,
190
+ isArray,
191
+ acceptableValues
192
+ };
193
+ return property;
194
+ }
195
+ throw new Error(`Unsupported schema type for field "${fieldName}"`);
196
+ }
197
+ function getPrimitiveType(schema) {
198
+ if (schema instanceof zod.z.ZodString) {
199
+ return "string";
200
+ }
201
+ if (schema instanceof zod.z.ZodNumber) {
202
+ return "number";
203
+ }
204
+ if (schema instanceof zod.z.ZodBoolean) {
205
+ return "boolean";
206
+ }
207
+ if (schema instanceof zod.z.ZodDate) {
208
+ return "Date";
209
+ }
210
+ if (schema instanceof zod.z.ZodEnum) {
211
+ return "string";
212
+ }
213
+ return null;
214
+ }
215
+ function getAcceptableValues(schema) {
216
+ if (schema instanceof zod.z.ZodEnum) {
217
+ return [...schema.options];
218
+ }
219
+ return null;
220
+ }
221
+ function generateRelations(definitions) {
222
+ const relations = [];
223
+ const entityMap = /* @__PURE__ */ new Map();
224
+ for (const def of definitions) {
225
+ entityMap.set(def.name, def);
226
+ }
227
+ for (const def of definitions) {
228
+ const referTos = [];
229
+ const referredBys = [];
230
+ for (const prop of def.properties) {
231
+ if (prop.isReference) {
232
+ referTos.push({
233
+ entityName: prop.targetEntityDefinitionName,
234
+ propertyName: prop.name,
235
+ isUnique: prop.isUnique
236
+ });
237
+ }
238
+ }
239
+ for (const otherDef of definitions) {
240
+ if (otherDef.name === def.name) {
241
+ continue;
242
+ }
243
+ for (const prop of otherDef.properties) {
244
+ if (prop.isReference && prop.targetEntityDefinitionName === def.name) {
245
+ referredBys.push({
246
+ entityName: otherDef.name,
247
+ propertyName: prop.name,
248
+ isUnique: prop.isUnique
249
+ });
250
+ }
251
+ }
252
+ }
253
+ relations.push({
254
+ entityName: def.name,
255
+ referTos,
256
+ referredBys
257
+ });
258
+ }
259
+ return relations;
260
+ }
261
+
262
+ exports.entity = entity;
263
+ exports.generateEntities = generateEntities;
264
+ exports.generateRelations = generateRelations;
265
+ exports.struct = struct;
266
+ //# sourceMappingURL=index.js.map
267
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/setupZod.ts","../src/factories.ts","../src/generator.ts"],"names":["z","isNullable"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Extends Zod schemas with metadata methods using declaration merging\n */\nimport { z } from 'zod';\n\n// Symbols for metadata storage to avoid property name conflicts\nconst PK_SYMBOL = Symbol('zod-entity-pk');\nconst UNIQUE_SYMBOL = Symbol('zod-entity-unique');\nconst REF_SYMBOL = Symbol('zod-entity-ref');\n\nexport const METADATA_SYMBOLS = {\n PK: PK_SYMBOL,\n UNIQUE: UNIQUE_SYMBOL,\n REF: REF_SYMBOL,\n} as const;\n\nexport type RefMetadata = {\n targetEntity: z.ZodTypeAny;\n targetColumn: string;\n};\n\n// Declare module augmentation for Zod types\ndeclare module 'zod' {\n interface ZodType {\n [PK_SYMBOL]?: boolean;\n [UNIQUE_SYMBOL]?: boolean;\n [REF_SYMBOL]?: RefMetadata;\n\n pk(): this;\n unique(): this;\n ref(targetEntity: z.ZodTypeAny, targetColumn?: string): this;\n }\n}\n\n// Implement the methods on ZodType prototype\nz.ZodType.prototype.pk = function () {\n this[PK_SYMBOL] = true;\n return this;\n};\n\nz.ZodType.prototype.unique = function () {\n this[UNIQUE_SYMBOL] = true;\n return this;\n};\n\nz.ZodType.prototype.ref = function (targetEntity: z.ZodTypeAny, targetColumn = 'id') {\n this[REF_SYMBOL] = { targetEntity, targetColumn };\n return this;\n};\n\n/**\n * Helper functions to check metadata\n */\nexport function isPrimaryKey(schema: z.ZodTypeAny): boolean {\n return schema[PK_SYMBOL] === true;\n}\n\nexport function isUnique(schema: z.ZodTypeAny): boolean {\n return schema[UNIQUE_SYMBOL] === true;\n}\n\nexport function getRefMetadata(schema: z.ZodTypeAny): RefMetadata | undefined {\n return schema[REF_SYMBOL];\n}\n","/**\n * Factory functions for creating entity and struct schemas\n */\nimport { z } from 'zod';\n\n// Symbols for schema metadata\nconst SCHEMA_TYPE_SYMBOL = Symbol('zod-schema-type');\nconst SCHEMA_NAME_SYMBOL = Symbol('zod-schema-name');\nconst SCHEMA_DESCRIPTION_SYMBOL = Symbol('zod-schema-description');\n\nexport const SCHEMA_METADATA_SYMBOLS = {\n TYPE: SCHEMA_TYPE_SYMBOL,\n NAME: SCHEMA_NAME_SYMBOL,\n DESCRIPTION: SCHEMA_DESCRIPTION_SYMBOL,\n} as const;\n\nexport type EntityConfig<T extends z.ZodRawShape> = {\n name: string;\n description?: string;\n columns: T;\n};\n\nexport type StructConfig<T extends z.ZodRawShape> = {\n name: string;\n description?: string;\n columns: T;\n};\n\n// Augment ZodObject to store metadata\n// Note: Using bracket notation to add properties at runtime, avoiding type parameter conflicts\ntype ZodObjectWithMetadata = z.ZodObject<z.ZodRawShape> & {\n [SCHEMA_TYPE_SYMBOL]?: 'entity' | 'struct';\n [SCHEMA_NAME_SYMBOL]?: string;\n [SCHEMA_DESCRIPTION_SYMBOL]?: string;\n};\n\n// Branded type to carry entity name at type level\ndeclare const ENTITY_NAME_BRAND: unique symbol;\nexport type EntitySchema<\n TName extends string,\n TShape extends z.ZodRawShape,\n> = z.ZodObject<TShape> & {\n readonly [ENTITY_NAME_BRAND]: TName;\n};\n\n/**\n * Creates an entity schema with metadata\n */\nexport function entity<const TConfig extends EntityConfig<z.ZodRawShape>>(\n config: TConfig\n): EntitySchema<TConfig['name'], TConfig['columns']> {\n const schema = z.object(config.columns) as ZodObjectWithMetadata;\n schema[SCHEMA_TYPE_SYMBOL] = 'entity';\n schema[SCHEMA_NAME_SYMBOL] = config.name;\n if (config.description !== undefined) {\n schema[SCHEMA_DESCRIPTION_SYMBOL] = config.description;\n }\n return schema as EntitySchema<TConfig['name'], TConfig['columns']>;\n}\n\n/**\n * Creates a struct schema with metadata\n */\nexport function struct<T extends z.ZodRawShape>(config: StructConfig<T>): z.ZodObject<T> {\n const schema = z.object(config.columns) as ZodObjectWithMetadata;\n schema[SCHEMA_TYPE_SYMBOL] = 'struct';\n schema[SCHEMA_NAME_SYMBOL] = config.name;\n if (config.description !== undefined) {\n schema[SCHEMA_DESCRIPTION_SYMBOL] = config.description;\n }\n return schema as z.ZodObject<T>;\n}\n\n/**\n * Helper functions to check schema metadata\n */\nexport function getSchemaType(schema: z.ZodTypeAny): 'entity' | 'struct' | undefined {\n if (schema instanceof z.ZodObject) {\n return (schema as ZodObjectWithMetadata)[SCHEMA_TYPE_SYMBOL];\n }\n return undefined;\n}\n\nexport function getSchemaName(schema: z.ZodTypeAny): string | undefined {\n if (schema instanceof z.ZodObject) {\n return (schema as ZodObjectWithMetadata)[SCHEMA_NAME_SYMBOL];\n }\n return undefined;\n}\n\nexport function getSchemaDescription(schema: z.ZodTypeAny): string | undefined {\n if (schema instanceof z.ZodObject) {\n return (schema as ZodObjectWithMetadata)[SCHEMA_DESCRIPTION_SYMBOL];\n }\n return undefined;\n}\n","/**\n * Core generation logic for entity definitions and relations\n */\nimport { z } from 'zod';\nimport type { EntitySchema } from './factories';\nimport { getSchemaDescription, getSchemaName, getSchemaType } from './factories';\nimport { getRefMetadata, isPrimaryKey, isUnique } from './setupZod';\nimport type {\n EntityDefinition,\n EntityPropertyDefinition,\n EntityPropertyDefinitionPrimaryKey,\n EntityPropertyDefinitionPrimitive,\n EntityPropertyDefinitionReferencedObject,\n EntityPropertyDefinitionTypedStruct,\n EntityRelation,\n EntityRelationReferTo,\n EntityRelationReferredBy,\n} from './types';\n\n/**\n * Helper type to extract entity name from a single EntitySchema\n *\n * For example: EntitySchema<'User', {...}> => 'User'\n * For non-EntitySchema types, returns never\n */\ntype ExtractEntityName<T> = T extends EntitySchema<infer TName, z.ZodRawShape> ? TName : never;\n\n/**\n * Helper type to extract entity names from an array of schemas\n *\n * This transforms an array of EntitySchema types into a union of their names.\n * For example: [EntitySchema<'User', ...>, EntitySchema<'Company', ...>] => 'User' | 'Company'\n *\n * The pattern works by:\n * 1. Mapping over the array type to extract each entity name\n * 2. Using [number] to create a union of all extracted names\n */\ntype ExtractEntityNames<T extends readonly z.ZodTypeAny[]> = {\n [K in keyof T]: ExtractEntityName<T[K]>;\n}[number];\n\n/**\n * Unwraps a Zod schema to get the innermost type\n * Handles z.optional, z.nullable, z.array\n */\ntype UnwrapResult = {\n innerSchema: z.ZodTypeAny;\n isNullable: boolean;\n isArray: boolean;\n};\n\nfunction unwrapSchema(schema: z.ZodTypeAny): UnwrapResult {\n let current = schema;\n let isNullable = false;\n let isArray = false;\n\n // Unwrap layers\n while (true) {\n if (current instanceof z.ZodOptional) {\n isNullable = true;\n current = current.unwrap() as z.ZodTypeAny;\n } else if (current instanceof z.ZodNullable) {\n isNullable = true;\n current = current.unwrap() as z.ZodTypeAny;\n } else if (current instanceof z.ZodArray) {\n isArray = true;\n current = current.element as z.ZodTypeAny;\n } else {\n break;\n }\n }\n\n return { innerSchema: current, isNullable, isArray };\n}\n\n/**\n * Generates entity definitions from Zod schemas\n */\nexport function generateEntities<const T extends readonly z.ZodTypeAny[]>(\n schemas: T\n): EntityDefinition<ExtractEntityNames<T>>[] {\n const definitions: EntityDefinition[] = [];\n\n for (const schema of schemas) {\n const schemaType = getSchemaType(schema);\n\n // Only process entity schemas\n if (schemaType !== 'entity') {\n continue;\n }\n\n const name = getSchemaName(schema);\n if (name === undefined) {\n throw new Error('Entity schema must have a name');\n }\n\n const description = getSchemaDescription(schema);\n\n if (!(schema instanceof z.ZodObject)) {\n throw new Error(`Entity \"${name}\" must be a ZodObject`);\n }\n\n const properties: EntityPropertyDefinition[] = [];\n const shape = schema.shape;\n\n for (const [fieldName, fieldSchema] of Object.entries(shape)) {\n if (!(fieldSchema instanceof z.ZodType)) {\n continue;\n }\n\n const property = parseProperty(fieldName, fieldSchema);\n properties.push(property);\n }\n\n const entityDefinition: EntityDefinition = {\n name,\n properties,\n };\n if (description !== undefined) {\n entityDefinition.description = description;\n }\n definitions.push(entityDefinition);\n }\n\n return definitions as EntityDefinition<ExtractEntityNames<T>>[];\n}\n\n/**\n * Parses a single property from a Zod schema\n */\nfunction parseProperty(fieldName: string, fieldSchema: z.ZodTypeAny): EntityPropertyDefinition {\n const isPk = isPrimaryKey(fieldSchema);\n const isUniqueField = isUnique(fieldSchema);\n const refMetadata = getRefMetadata(fieldSchema);\n\n // Handle Primary Key\n if (isPk) {\n const property: EntityPropertyDefinitionPrimaryKey = {\n isReference: false,\n propertyType: 'PrimaryKey',\n name: fieldName,\n };\n return property;\n }\n\n // Handle Foreign Key Reference\n if (refMetadata !== undefined) {\n const { targetEntity } = refMetadata;\n\n // Validate that targetEntity is an entity\n const targetSchemaType = getSchemaType(targetEntity);\n if (targetSchemaType !== 'entity') {\n throw new Error(\n `Field \"${fieldName}\" has .ref() pointing to a non-entity schema. Only entity schemas created with entity() can be referenced.`\n );\n }\n\n const targetEntityName = getSchemaName(targetEntity);\n if (targetEntityName === undefined) {\n throw new Error(`Referenced entity for field \"${fieldName}\" must have a name`);\n }\n\n const { isNullable } = unwrapSchema(fieldSchema);\n\n const property: EntityPropertyDefinitionReferencedObject = {\n isReference: true,\n name: fieldName,\n targetEntityDefinitionName: targetEntityName,\n isUnique: isUniqueField,\n isNullable,\n };\n return property;\n }\n\n // Unwrap the schema\n const { innerSchema, isNullable, isArray } = unwrapSchema(fieldSchema);\n\n // Check if inner schema is an entity (not allowed)\n const innerSchemaType = getSchemaType(innerSchema);\n if (innerSchemaType === 'entity') {\n throw new Error(\n `Field \"${fieldName}\" contains a direct entity embedding. Entities cannot be directly nested. Use .ref() instead.`\n );\n }\n\n // Handle struct\n if (innerSchemaType === 'struct') {\n const structName = getSchemaName(innerSchema);\n if (structName === undefined) {\n throw new Error(`Struct schema for field \"${fieldName}\" must have a name`);\n }\n\n const property: EntityPropertyDefinitionTypedStruct = {\n isReference: false,\n propertyType: 'typedStruct',\n name: fieldName,\n structTypeName: structName,\n isUnique: isUniqueField,\n isNullable,\n isArray,\n };\n return property;\n }\n\n // Handle primitives\n const primitiveType = getPrimitiveType(innerSchema);\n if (primitiveType !== null) {\n const acceptableValues = getAcceptableValues(innerSchema);\n\n const property: EntityPropertyDefinitionPrimitive = {\n isReference: false,\n propertyType: primitiveType,\n name: fieldName,\n isUnique: isUniqueField,\n isNullable,\n isArray,\n acceptableValues,\n };\n return property;\n }\n\n throw new Error(`Unsupported schema type for field \"${fieldName}\"`);\n}\n\n/**\n * Determines the primitive type from a Zod schema\n */\nfunction getPrimitiveType(schema: z.ZodTypeAny): 'boolean' | 'number' | 'string' | 'Date' | null {\n if (schema instanceof z.ZodString) {\n return 'string';\n }\n if (schema instanceof z.ZodNumber) {\n return 'number';\n }\n if (schema instanceof z.ZodBoolean) {\n return 'boolean';\n }\n if (schema instanceof z.ZodDate) {\n return 'Date';\n }\n if (schema instanceof z.ZodEnum) {\n return 'string';\n }\n return null;\n}\n\n/**\n * Extracts acceptable values from z.enum\n */\nfunction getAcceptableValues(schema: z.ZodTypeAny): string[] | null {\n if (schema instanceof z.ZodEnum) {\n return [...schema.options] as string[];\n }\n return null;\n}\n\n/**\n * Generates relations from entity definitions\n */\nexport function generateRelations(definitions: EntityDefinition[]): EntityRelation[] {\n const relations: EntityRelation[] = [];\n\n // Build a map for quick lookup\n const entityMap = new Map<string, EntityDefinition>();\n for (const def of definitions) {\n entityMap.set(def.name, def);\n }\n\n // Initialize relations for each entity\n for (const def of definitions) {\n const referTos: EntityRelationReferTo[] = [];\n const referredBys: EntityRelationReferredBy[] = [];\n\n // Find referTos (outgoing references)\n for (const prop of def.properties) {\n if (prop.isReference) {\n referTos.push({\n entityName: prop.targetEntityDefinitionName,\n propertyName: prop.name,\n isUnique: prop.isUnique,\n });\n }\n }\n\n // Find referredBys (incoming references)\n for (const otherDef of definitions) {\n if (otherDef.name === def.name) {\n continue;\n }\n\n for (const prop of otherDef.properties) {\n if (prop.isReference && prop.targetEntityDefinitionName === def.name) {\n referredBys.push({\n entityName: otherDef.name,\n propertyName: prop.name,\n isUnique: prop.isUnique,\n });\n }\n }\n }\n\n relations.push({\n entityName: def.name,\n referTos,\n referredBys,\n });\n }\n\n return relations;\n}\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,262 @@
1
+ import { z } from 'zod';
2
+
3
+ // src/setupZod.ts
4
+ var PK_SYMBOL = Symbol("zod-entity-pk");
5
+ var UNIQUE_SYMBOL = Symbol("zod-entity-unique");
6
+ var REF_SYMBOL = Symbol("zod-entity-ref");
7
+ z.ZodType.prototype.pk = function() {
8
+ this[PK_SYMBOL] = true;
9
+ return this;
10
+ };
11
+ z.ZodType.prototype.unique = function() {
12
+ this[UNIQUE_SYMBOL] = true;
13
+ return this;
14
+ };
15
+ z.ZodType.prototype.ref = function(targetEntity, targetColumn = "id") {
16
+ this[REF_SYMBOL] = { targetEntity, targetColumn };
17
+ return this;
18
+ };
19
+ function isPrimaryKey(schema) {
20
+ return schema[PK_SYMBOL] === true;
21
+ }
22
+ function isUnique(schema) {
23
+ return schema[UNIQUE_SYMBOL] === true;
24
+ }
25
+ function getRefMetadata(schema) {
26
+ return schema[REF_SYMBOL];
27
+ }
28
+ var SCHEMA_TYPE_SYMBOL = Symbol("zod-schema-type");
29
+ var SCHEMA_NAME_SYMBOL = Symbol("zod-schema-name");
30
+ var SCHEMA_DESCRIPTION_SYMBOL = Symbol("zod-schema-description");
31
+ function entity(config) {
32
+ const schema = z.object(config.columns);
33
+ schema[SCHEMA_TYPE_SYMBOL] = "entity";
34
+ schema[SCHEMA_NAME_SYMBOL] = config.name;
35
+ if (config.description !== void 0) {
36
+ schema[SCHEMA_DESCRIPTION_SYMBOL] = config.description;
37
+ }
38
+ return schema;
39
+ }
40
+ function struct(config) {
41
+ const schema = z.object(config.columns);
42
+ schema[SCHEMA_TYPE_SYMBOL] = "struct";
43
+ schema[SCHEMA_NAME_SYMBOL] = config.name;
44
+ if (config.description !== void 0) {
45
+ schema[SCHEMA_DESCRIPTION_SYMBOL] = config.description;
46
+ }
47
+ return schema;
48
+ }
49
+ function getSchemaType(schema) {
50
+ if (schema instanceof z.ZodObject) {
51
+ return schema[SCHEMA_TYPE_SYMBOL];
52
+ }
53
+ return void 0;
54
+ }
55
+ function getSchemaName(schema) {
56
+ if (schema instanceof z.ZodObject) {
57
+ return schema[SCHEMA_NAME_SYMBOL];
58
+ }
59
+ return void 0;
60
+ }
61
+ function getSchemaDescription(schema) {
62
+ if (schema instanceof z.ZodObject) {
63
+ return schema[SCHEMA_DESCRIPTION_SYMBOL];
64
+ }
65
+ return void 0;
66
+ }
67
+ function unwrapSchema(schema) {
68
+ let current = schema;
69
+ let isNullable = false;
70
+ let isArray = false;
71
+ while (true) {
72
+ if (current instanceof z.ZodOptional) {
73
+ isNullable = true;
74
+ current = current.unwrap();
75
+ } else if (current instanceof z.ZodNullable) {
76
+ isNullable = true;
77
+ current = current.unwrap();
78
+ } else if (current instanceof z.ZodArray) {
79
+ isArray = true;
80
+ current = current.element;
81
+ } else {
82
+ break;
83
+ }
84
+ }
85
+ return { innerSchema: current, isNullable, isArray };
86
+ }
87
+ function generateEntities(schemas) {
88
+ const definitions = [];
89
+ for (const schema of schemas) {
90
+ const schemaType = getSchemaType(schema);
91
+ if (schemaType !== "entity") {
92
+ continue;
93
+ }
94
+ const name = getSchemaName(schema);
95
+ if (name === void 0) {
96
+ throw new Error("Entity schema must have a name");
97
+ }
98
+ const description = getSchemaDescription(schema);
99
+ if (!(schema instanceof z.ZodObject)) {
100
+ throw new Error(`Entity "${name}" must be a ZodObject`);
101
+ }
102
+ const properties = [];
103
+ const shape = schema.shape;
104
+ for (const [fieldName, fieldSchema] of Object.entries(shape)) {
105
+ if (!(fieldSchema instanceof z.ZodType)) {
106
+ continue;
107
+ }
108
+ const property = parseProperty(fieldName, fieldSchema);
109
+ properties.push(property);
110
+ }
111
+ const entityDefinition = {
112
+ name,
113
+ properties
114
+ };
115
+ if (description !== void 0) {
116
+ entityDefinition.description = description;
117
+ }
118
+ definitions.push(entityDefinition);
119
+ }
120
+ return definitions;
121
+ }
122
+ function parseProperty(fieldName, fieldSchema) {
123
+ const isPk = isPrimaryKey(fieldSchema);
124
+ const isUniqueField = isUnique(fieldSchema);
125
+ const refMetadata = getRefMetadata(fieldSchema);
126
+ if (isPk) {
127
+ const property = {
128
+ isReference: false,
129
+ propertyType: "PrimaryKey",
130
+ name: fieldName
131
+ };
132
+ return property;
133
+ }
134
+ if (refMetadata !== void 0) {
135
+ const { targetEntity } = refMetadata;
136
+ const targetSchemaType = getSchemaType(targetEntity);
137
+ if (targetSchemaType !== "entity") {
138
+ throw new Error(
139
+ `Field "${fieldName}" has .ref() pointing to a non-entity schema. Only entity schemas created with entity() can be referenced.`
140
+ );
141
+ }
142
+ const targetEntityName = getSchemaName(targetEntity);
143
+ if (targetEntityName === void 0) {
144
+ throw new Error(`Referenced entity for field "${fieldName}" must have a name`);
145
+ }
146
+ const { isNullable: isNullable2 } = unwrapSchema(fieldSchema);
147
+ const property = {
148
+ isReference: true,
149
+ name: fieldName,
150
+ targetEntityDefinitionName: targetEntityName,
151
+ isUnique: isUniqueField,
152
+ isNullable: isNullable2
153
+ };
154
+ return property;
155
+ }
156
+ const { innerSchema, isNullable, isArray } = unwrapSchema(fieldSchema);
157
+ const innerSchemaType = getSchemaType(innerSchema);
158
+ if (innerSchemaType === "entity") {
159
+ throw new Error(
160
+ `Field "${fieldName}" contains a direct entity embedding. Entities cannot be directly nested. Use .ref() instead.`
161
+ );
162
+ }
163
+ if (innerSchemaType === "struct") {
164
+ const structName = getSchemaName(innerSchema);
165
+ if (structName === void 0) {
166
+ throw new Error(`Struct schema for field "${fieldName}" must have a name`);
167
+ }
168
+ const property = {
169
+ isReference: false,
170
+ propertyType: "typedStruct",
171
+ name: fieldName,
172
+ structTypeName: structName,
173
+ isUnique: isUniqueField,
174
+ isNullable,
175
+ isArray
176
+ };
177
+ return property;
178
+ }
179
+ const primitiveType = getPrimitiveType(innerSchema);
180
+ if (primitiveType !== null) {
181
+ const acceptableValues = getAcceptableValues(innerSchema);
182
+ const property = {
183
+ isReference: false,
184
+ propertyType: primitiveType,
185
+ name: fieldName,
186
+ isUnique: isUniqueField,
187
+ isNullable,
188
+ isArray,
189
+ acceptableValues
190
+ };
191
+ return property;
192
+ }
193
+ throw new Error(`Unsupported schema type for field "${fieldName}"`);
194
+ }
195
+ function getPrimitiveType(schema) {
196
+ if (schema instanceof z.ZodString) {
197
+ return "string";
198
+ }
199
+ if (schema instanceof z.ZodNumber) {
200
+ return "number";
201
+ }
202
+ if (schema instanceof z.ZodBoolean) {
203
+ return "boolean";
204
+ }
205
+ if (schema instanceof z.ZodDate) {
206
+ return "Date";
207
+ }
208
+ if (schema instanceof z.ZodEnum) {
209
+ return "string";
210
+ }
211
+ return null;
212
+ }
213
+ function getAcceptableValues(schema) {
214
+ if (schema instanceof z.ZodEnum) {
215
+ return [...schema.options];
216
+ }
217
+ return null;
218
+ }
219
+ function generateRelations(definitions) {
220
+ const relations = [];
221
+ const entityMap = /* @__PURE__ */ new Map();
222
+ for (const def of definitions) {
223
+ entityMap.set(def.name, def);
224
+ }
225
+ for (const def of definitions) {
226
+ const referTos = [];
227
+ const referredBys = [];
228
+ for (const prop of def.properties) {
229
+ if (prop.isReference) {
230
+ referTos.push({
231
+ entityName: prop.targetEntityDefinitionName,
232
+ propertyName: prop.name,
233
+ isUnique: prop.isUnique
234
+ });
235
+ }
236
+ }
237
+ for (const otherDef of definitions) {
238
+ if (otherDef.name === def.name) {
239
+ continue;
240
+ }
241
+ for (const prop of otherDef.properties) {
242
+ if (prop.isReference && prop.targetEntityDefinitionName === def.name) {
243
+ referredBys.push({
244
+ entityName: otherDef.name,
245
+ propertyName: prop.name,
246
+ isUnique: prop.isUnique
247
+ });
248
+ }
249
+ }
250
+ }
251
+ relations.push({
252
+ entityName: def.name,
253
+ referTos,
254
+ referredBys
255
+ });
256
+ }
257
+ return relations;
258
+ }
259
+
260
+ export { entity, generateEntities, generateRelations, struct };
261
+ //# sourceMappingURL=index.mjs.map
262
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/setupZod.ts","../src/factories.ts","../src/generator.ts"],"names":["z","isNullable"],"mappings":";;;AAMA,IAAM,SAAA,GAAY,OAAO,eAAe,CAAA;AACxC,IAAM,aAAA,GAAgB,OAAO,mBAAmB,CAAA;AAChD,IAAM,UAAA,GAAa,OAAO,gBAAgB,CAAA;AA2B1C,CAAA,CAAE,OAAA,CAAQ,SAAA,CAAU,EAAA,GAAK,WAAY;AACnC,EAAA,IAAA,CAAK,SAAS,CAAA,GAAI,IAAA;AAClB,EAAA,OAAO,IAAA;AACT,CAAA;AAEA,CAAA,CAAE,OAAA,CAAQ,SAAA,CAAU,MAAA,GAAS,WAAY;AACvC,EAAA,IAAA,CAAK,aAAa,CAAA,GAAI,IAAA;AACtB,EAAA,OAAO,IAAA;AACT,CAAA;AAEA,CAAA,CAAE,QAAQ,SAAA,CAAU,GAAA,GAAM,SAAU,YAAA,EAA4B,eAAe,IAAA,EAAM;AACnF,EAAA,IAAA,CAAK,UAAU,CAAA,GAAI,EAAE,YAAA,EAAc,YAAA,EAAa;AAChD,EAAA,OAAO,IAAA;AACT,CAAA;AAKO,SAAS,aAAa,MAAA,EAA+B;AAC1D,EAAA,OAAO,MAAA,CAAO,SAAS,CAAA,KAAM,IAAA;AAC/B;AAEO,SAAS,SAAS,MAAA,EAA+B;AACtD,EAAA,OAAO,MAAA,CAAO,aAAa,CAAA,KAAM,IAAA;AACnC;AAEO,SAAS,eAAe,MAAA,EAA+C;AAC5E,EAAA,OAAO,OAAO,UAAU,CAAA;AAC1B;ACzDA,IAAM,kBAAA,GAAqB,OAAO,iBAAiB,CAAA;AACnD,IAAM,kBAAA,GAAqB,OAAO,iBAAiB,CAAA;AACnD,IAAM,yBAAA,GAA4B,OAAO,wBAAwB,CAAA;AAwC1D,SAAS,OACd,MAAA,EACmD;AACnD,EAAA,MAAM,MAAA,GAASA,CAAAA,CAAE,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA;AACtC,EAAA,MAAA,CAAO,kBAAkB,CAAA,GAAI,QAAA;AAC7B,EAAA,MAAA,CAAO,kBAAkB,IAAI,MAAA,CAAO,IAAA;AACpC,EAAA,IAAI,MAAA,CAAO,gBAAgB,MAAA,EAAW;AACpC,IAAA,MAAA,CAAO,yBAAyB,IAAI,MAAA,CAAO,WAAA;AAAA,EAC7C;AACA,EAAA,OAAO,MAAA;AACT;AAKO,SAAS,OAAgC,MAAA,EAAyC;AACvF,EAAA,MAAM,MAAA,GAASA,CAAAA,CAAE,MAAA,CAAO,MAAA,CAAO,OAAO,CAAA;AACtC,EAAA,MAAA,CAAO,kBAAkB,CAAA,GAAI,QAAA;AAC7B,EAAA,MAAA,CAAO,kBAAkB,IAAI,MAAA,CAAO,IAAA;AACpC,EAAA,IAAI,MAAA,CAAO,gBAAgB,MAAA,EAAW;AACpC,IAAA,MAAA,CAAO,yBAAyB,IAAI,MAAA,CAAO,WAAA;AAAA,EAC7C;AACA,EAAA,OAAO,MAAA;AACT;AAKO,SAAS,cAAc,MAAA,EAAuD;AACnF,EAAA,IAAI,MAAA,YAAkBA,EAAE,SAAA,EAAW;AACjC,IAAA,OAAQ,OAAiC,kBAAkB,CAAA;AAAA,EAC7D;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,cAAc,MAAA,EAA0C;AACtE,EAAA,IAAI,MAAA,YAAkBA,EAAE,SAAA,EAAW;AACjC,IAAA,OAAQ,OAAiC,kBAAkB,CAAA;AAAA,EAC7D;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,qBAAqB,MAAA,EAA0C;AAC7E,EAAA,IAAI,MAAA,YAAkBA,EAAE,SAAA,EAAW;AACjC,IAAA,OAAQ,OAAiC,yBAAyB,CAAA;AAAA,EACpE;AACA,EAAA,OAAO,MAAA;AACT;AC5CA,SAAS,aAAa,MAAA,EAAoC;AACxD,EAAA,IAAI,OAAA,GAAU,MAAA;AACd,EAAA,IAAI,UAAA,GAAa,KAAA;AACjB,EAAA,IAAI,OAAA,GAAU,KAAA;AAGd,EAAA,OAAO,IAAA,EAAM;AACX,IAAA,IAAI,OAAA,YAAmBA,EAAE,WAAA,EAAa;AACpC,MAAA,UAAA,GAAa,IAAA;AACb,MAAA,OAAA,GAAU,QAAQ,MAAA,EAAO;AAAA,IAC3B,CAAA,MAAA,IAAW,OAAA,YAAmBA,CAAAA,CAAE,WAAA,EAAa;AAC3C,MAAA,UAAA,GAAa,IAAA;AACb,MAAA,OAAA,GAAU,QAAQ,MAAA,EAAO;AAAA,IAC3B,CAAA,MAAA,IAAW,OAAA,YAAmBA,CAAAA,CAAE,QAAA,EAAU;AACxC,MAAA,OAAA,GAAU,IAAA;AACV,MAAA,OAAA,GAAU,OAAA,CAAQ,OAAA;AAAA,IACpB,CAAA,MAAO;AACL,MAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,WAAA,EAAa,OAAA,EAAS,UAAA,EAAY,OAAA,EAAQ;AACrD;AAKO,SAAS,iBACd,OAAA,EAC2C;AAC3C,EAAA,MAAM,cAAkC,EAAC;AAEzC,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,MAAM,UAAA,GAAa,cAAc,MAAM,CAAA;AAGvC,IAAA,IAAI,eAAe,QAAA,EAAU;AAC3B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,GAAO,cAAc,MAAM,CAAA;AACjC,IAAA,IAAI,SAAS,MAAA,EAAW;AACtB,MAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,IAClD;AAEA,IAAA,MAAM,WAAA,GAAc,qBAAqB,MAAM,CAAA;AAE/C,IAAA,IAAI,EAAE,MAAA,YAAkBA,CAAAA,CAAE,SAAA,CAAA,EAAY;AACpC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,QAAA,EAAW,IAAI,CAAA,qBAAA,CAAuB,CAAA;AAAA,IACxD;AAEA,IAAA,MAAM,aAAyC,EAAC;AAChD,IAAA,MAAM,QAAQ,MAAA,CAAO,KAAA;AAErB,IAAA,KAAA,MAAW,CAAC,SAAA,EAAW,WAAW,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC5D,MAAA,IAAI,EAAE,WAAA,YAAuBA,CAAAA,CAAE,OAAA,CAAA,EAAU;AACvC,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,QAAA,GAAW,aAAA,CAAc,SAAA,EAAW,WAAW,CAAA;AACrD,MAAA,UAAA,CAAW,KAAK,QAAQ,CAAA;AAAA,IAC1B;AAEA,IAAA,MAAM,gBAAA,GAAqC;AAAA,MACzC,IAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,IAAI,gBAAgB,MAAA,EAAW;AAC7B,MAAA,gBAAA,CAAiB,WAAA,GAAc,WAAA;AAAA,IACjC;AACA,IAAA,WAAA,CAAY,KAAK,gBAAgB,CAAA;AAAA,EACnC;AAEA,EAAA,OAAO,WAAA;AACT;AAKA,SAAS,aAAA,CAAc,WAAmB,WAAA,EAAqD;AAC7F,EAAA,MAAM,IAAA,GAAO,aAAa,WAAW,CAAA;AACrC,EAAA,MAAM,aAAA,GAAgB,SAAS,WAAW,CAAA;AAC1C,EAAA,MAAM,WAAA,GAAc,eAAe,WAAW,CAAA;AAG9C,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,MAAM,QAAA,GAA+C;AAAA,MACnD,WAAA,EAAa,KAAA;AAAA,MACb,YAAA,EAAc,YAAA;AAAA,MACd,IAAA,EAAM;AAAA,KACR;AACA,IAAA,OAAO,QAAA;AAAA,EACT;AAGA,EAAA,IAAI,gBAAgB,MAAA,EAAW;AAC7B,IAAA,MAAM,EAAE,cAAa,GAAI,WAAA;AAGzB,IAAA,MAAM,gBAAA,GAAmB,cAAc,YAAY,CAAA;AACnD,IAAA,IAAI,qBAAqB,QAAA,EAAU;AACjC,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,UAAU,SAAS,CAAA,0GAAA;AAAA,OACrB;AAAA,IACF;AAEA,IAAA,MAAM,gBAAA,GAAmB,cAAc,YAAY,CAAA;AACnD,IAAA,IAAI,qBAAqB,MAAA,EAAW;AAClC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,6BAAA,EAAgC,SAAS,CAAA,kBAAA,CAAoB,CAAA;AAAA,IAC/E;AAEA,IAAA,MAAM,EAAE,UAAA,EAAAC,WAAAA,EAAW,GAAI,aAAa,WAAW,CAAA;AAE/C,IAAA,MAAM,QAAA,GAAqD;AAAA,MACzD,WAAA,EAAa,IAAA;AAAA,MACb,IAAA,EAAM,SAAA;AAAA,MACN,0BAAA,EAA4B,gBAAA;AAAA,MAC5B,QAAA,EAAU,aAAA;AAAA,MACV,UAAA,EAAAA;AAAA,KACF;AACA,IAAA,OAAO,QAAA;AAAA,EACT;AAGA,EAAA,MAAM,EAAE,WAAA,EAAa,UAAA,EAAY,OAAA,EAAQ,GAAI,aAAa,WAAW,CAAA;AAGrE,EAAA,MAAM,eAAA,GAAkB,cAAc,WAAW,CAAA;AACjD,EAAA,IAAI,oBAAoB,QAAA,EAAU;AAChC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,UAAU,SAAS,CAAA,6FAAA;AAAA,KACrB;AAAA,EACF;AAGA,EAAA,IAAI,oBAAoB,QAAA,EAAU;AAChC,IAAA,MAAM,UAAA,GAAa,cAAc,WAAW,CAAA;AAC5C,IAAA,IAAI,eAAe,MAAA,EAAW;AAC5B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,SAAS,CAAA,kBAAA,CAAoB,CAAA;AAAA,IAC3E;AAEA,IAAA,MAAM,QAAA,GAAgD;AAAA,MACpD,WAAA,EAAa,KAAA;AAAA,MACb,YAAA,EAAc,aAAA;AAAA,MACd,IAAA,EAAM,SAAA;AAAA,MACN,cAAA,EAAgB,UAAA;AAAA,MAChB,QAAA,EAAU,aAAA;AAAA,MACV,UAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,OAAO,QAAA;AAAA,EACT;AAGA,EAAA,MAAM,aAAA,GAAgB,iBAAiB,WAAW,CAAA;AAClD,EAAA,IAAI,kBAAkB,IAAA,EAAM;AAC1B,IAAA,MAAM,gBAAA,GAAmB,oBAAoB,WAAW,CAAA;AAExD,IAAA,MAAM,QAAA,GAA8C;AAAA,MAClD,WAAA,EAAa,KAAA;AAAA,MACb,YAAA,EAAc,aAAA;AAAA,MACd,IAAA,EAAM,SAAA;AAAA,MACN,QAAA,EAAU,aAAA;AAAA,MACV,UAAA;AAAA,MACA,OAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,SAAS,CAAA,CAAA,CAAG,CAAA;AACpE;AAKA,SAAS,iBAAiB,MAAA,EAAuE;AAC/F,EAAA,IAAI,MAAA,YAAkBD,EAAE,SAAA,EAAW;AACjC,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,IAAI,MAAA,YAAkBA,EAAE,SAAA,EAAW;AACjC,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,IAAI,MAAA,YAAkBA,EAAE,UAAA,EAAY;AAClC,IAAA,OAAO,SAAA;AAAA,EACT;AACA,EAAA,IAAI,MAAA,YAAkBA,EAAE,OAAA,EAAS;AAC/B,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,IAAI,MAAA,YAAkBA,EAAE,OAAA,EAAS;AAC/B,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAA;AACT;AAKA,SAAS,oBAAoB,MAAA,EAAuC;AAClE,EAAA,IAAI,MAAA,YAAkBA,EAAE,OAAA,EAAS;AAC/B,IAAA,OAAO,CAAC,GAAG,MAAA,CAAO,OAAO,CAAA;AAAA,EAC3B;AACA,EAAA,OAAO,IAAA;AACT;AAKO,SAAS,kBAAkB,WAAA,EAAmD;AACnF,EAAA,MAAM,YAA8B,EAAC;AAGrC,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAA8B;AACpD,EAAA,KAAA,MAAW,OAAO,WAAA,EAAa;AAC7B,IAAA,SAAA,CAAU,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,GAAG,CAAA;AAAA,EAC7B;AAGA,EAAA,KAAA,MAAW,OAAO,WAAA,EAAa;AAC7B,IAAA,MAAM,WAAoC,EAAC;AAC3C,IAAA,MAAM,cAA0C,EAAC;AAGjD,IAAA,KAAA,MAAW,IAAA,IAAQ,IAAI,UAAA,EAAY;AACjC,MAAA,IAAI,KAAK,WAAA,EAAa;AACpB,QAAA,QAAA,CAAS,IAAA,CAAK;AAAA,UACZ,YAAY,IAAA,CAAK,0BAAA;AAAA,UACjB,cAAc,IAAA,CAAK,IAAA;AAAA,UACnB,UAAU,IAAA,CAAK;AAAA,SAChB,CAAA;AAAA,MACH;AAAA,IACF;AAGA,IAAA,KAAA,MAAW,YAAY,WAAA,EAAa;AAClC,MAAA,IAAI,QAAA,CAAS,IAAA,KAAS,GAAA,CAAI,IAAA,EAAM;AAC9B,QAAA;AAAA,MACF;AAEA,MAAA,KAAA,MAAW,IAAA,IAAQ,SAAS,UAAA,EAAY;AACtC,QAAA,IAAI,IAAA,CAAK,WAAA,IAAe,IAAA,CAAK,0BAAA,KAA+B,IAAI,IAAA,EAAM;AACpE,UAAA,WAAA,CAAY,IAAA,CAAK;AAAA,YACf,YAAY,QAAA,CAAS,IAAA;AAAA,YACrB,cAAc,IAAA,CAAK,IAAA;AAAA,YACnB,UAAU,IAAA,CAAK;AAAA,WAChB,CAAA;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,IAAA,SAAA,CAAU,IAAA,CAAK;AAAA,MACb,YAAY,GAAA,CAAI,IAAA;AAAA,MAChB,QAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,SAAA;AACT","file":"index.mjs","sourcesContent":["/**\n * Extends Zod schemas with metadata methods using declaration merging\n */\nimport { z } from 'zod';\n\n// Symbols for metadata storage to avoid property name conflicts\nconst PK_SYMBOL = Symbol('zod-entity-pk');\nconst UNIQUE_SYMBOL = Symbol('zod-entity-unique');\nconst REF_SYMBOL = Symbol('zod-entity-ref');\n\nexport const METADATA_SYMBOLS = {\n PK: PK_SYMBOL,\n UNIQUE: UNIQUE_SYMBOL,\n REF: REF_SYMBOL,\n} as const;\n\nexport type RefMetadata = {\n targetEntity: z.ZodTypeAny;\n targetColumn: string;\n};\n\n// Declare module augmentation for Zod types\ndeclare module 'zod' {\n interface ZodType {\n [PK_SYMBOL]?: boolean;\n [UNIQUE_SYMBOL]?: boolean;\n [REF_SYMBOL]?: RefMetadata;\n\n pk(): this;\n unique(): this;\n ref(targetEntity: z.ZodTypeAny, targetColumn?: string): this;\n }\n}\n\n// Implement the methods on ZodType prototype\nz.ZodType.prototype.pk = function () {\n this[PK_SYMBOL] = true;\n return this;\n};\n\nz.ZodType.prototype.unique = function () {\n this[UNIQUE_SYMBOL] = true;\n return this;\n};\n\nz.ZodType.prototype.ref = function (targetEntity: z.ZodTypeAny, targetColumn = 'id') {\n this[REF_SYMBOL] = { targetEntity, targetColumn };\n return this;\n};\n\n/**\n * Helper functions to check metadata\n */\nexport function isPrimaryKey(schema: z.ZodTypeAny): boolean {\n return schema[PK_SYMBOL] === true;\n}\n\nexport function isUnique(schema: z.ZodTypeAny): boolean {\n return schema[UNIQUE_SYMBOL] === true;\n}\n\nexport function getRefMetadata(schema: z.ZodTypeAny): RefMetadata | undefined {\n return schema[REF_SYMBOL];\n}\n","/**\n * Factory functions for creating entity and struct schemas\n */\nimport { z } from 'zod';\n\n// Symbols for schema metadata\nconst SCHEMA_TYPE_SYMBOL = Symbol('zod-schema-type');\nconst SCHEMA_NAME_SYMBOL = Symbol('zod-schema-name');\nconst SCHEMA_DESCRIPTION_SYMBOL = Symbol('zod-schema-description');\n\nexport const SCHEMA_METADATA_SYMBOLS = {\n TYPE: SCHEMA_TYPE_SYMBOL,\n NAME: SCHEMA_NAME_SYMBOL,\n DESCRIPTION: SCHEMA_DESCRIPTION_SYMBOL,\n} as const;\n\nexport type EntityConfig<T extends z.ZodRawShape> = {\n name: string;\n description?: string;\n columns: T;\n};\n\nexport type StructConfig<T extends z.ZodRawShape> = {\n name: string;\n description?: string;\n columns: T;\n};\n\n// Augment ZodObject to store metadata\n// Note: Using bracket notation to add properties at runtime, avoiding type parameter conflicts\ntype ZodObjectWithMetadata = z.ZodObject<z.ZodRawShape> & {\n [SCHEMA_TYPE_SYMBOL]?: 'entity' | 'struct';\n [SCHEMA_NAME_SYMBOL]?: string;\n [SCHEMA_DESCRIPTION_SYMBOL]?: string;\n};\n\n// Branded type to carry entity name at type level\ndeclare const ENTITY_NAME_BRAND: unique symbol;\nexport type EntitySchema<\n TName extends string,\n TShape extends z.ZodRawShape,\n> = z.ZodObject<TShape> & {\n readonly [ENTITY_NAME_BRAND]: TName;\n};\n\n/**\n * Creates an entity schema with metadata\n */\nexport function entity<const TConfig extends EntityConfig<z.ZodRawShape>>(\n config: TConfig\n): EntitySchema<TConfig['name'], TConfig['columns']> {\n const schema = z.object(config.columns) as ZodObjectWithMetadata;\n schema[SCHEMA_TYPE_SYMBOL] = 'entity';\n schema[SCHEMA_NAME_SYMBOL] = config.name;\n if (config.description !== undefined) {\n schema[SCHEMA_DESCRIPTION_SYMBOL] = config.description;\n }\n return schema as EntitySchema<TConfig['name'], TConfig['columns']>;\n}\n\n/**\n * Creates a struct schema with metadata\n */\nexport function struct<T extends z.ZodRawShape>(config: StructConfig<T>): z.ZodObject<T> {\n const schema = z.object(config.columns) as ZodObjectWithMetadata;\n schema[SCHEMA_TYPE_SYMBOL] = 'struct';\n schema[SCHEMA_NAME_SYMBOL] = config.name;\n if (config.description !== undefined) {\n schema[SCHEMA_DESCRIPTION_SYMBOL] = config.description;\n }\n return schema as z.ZodObject<T>;\n}\n\n/**\n * Helper functions to check schema metadata\n */\nexport function getSchemaType(schema: z.ZodTypeAny): 'entity' | 'struct' | undefined {\n if (schema instanceof z.ZodObject) {\n return (schema as ZodObjectWithMetadata)[SCHEMA_TYPE_SYMBOL];\n }\n return undefined;\n}\n\nexport function getSchemaName(schema: z.ZodTypeAny): string | undefined {\n if (schema instanceof z.ZodObject) {\n return (schema as ZodObjectWithMetadata)[SCHEMA_NAME_SYMBOL];\n }\n return undefined;\n}\n\nexport function getSchemaDescription(schema: z.ZodTypeAny): string | undefined {\n if (schema instanceof z.ZodObject) {\n return (schema as ZodObjectWithMetadata)[SCHEMA_DESCRIPTION_SYMBOL];\n }\n return undefined;\n}\n","/**\n * Core generation logic for entity definitions and relations\n */\nimport { z } from 'zod';\nimport type { EntitySchema } from './factories';\nimport { getSchemaDescription, getSchemaName, getSchemaType } from './factories';\nimport { getRefMetadata, isPrimaryKey, isUnique } from './setupZod';\nimport type {\n EntityDefinition,\n EntityPropertyDefinition,\n EntityPropertyDefinitionPrimaryKey,\n EntityPropertyDefinitionPrimitive,\n EntityPropertyDefinitionReferencedObject,\n EntityPropertyDefinitionTypedStruct,\n EntityRelation,\n EntityRelationReferTo,\n EntityRelationReferredBy,\n} from './types';\n\n/**\n * Helper type to extract entity name from a single EntitySchema\n *\n * For example: EntitySchema<'User', {...}> => 'User'\n * For non-EntitySchema types, returns never\n */\ntype ExtractEntityName<T> = T extends EntitySchema<infer TName, z.ZodRawShape> ? TName : never;\n\n/**\n * Helper type to extract entity names from an array of schemas\n *\n * This transforms an array of EntitySchema types into a union of their names.\n * For example: [EntitySchema<'User', ...>, EntitySchema<'Company', ...>] => 'User' | 'Company'\n *\n * The pattern works by:\n * 1. Mapping over the array type to extract each entity name\n * 2. Using [number] to create a union of all extracted names\n */\ntype ExtractEntityNames<T extends readonly z.ZodTypeAny[]> = {\n [K in keyof T]: ExtractEntityName<T[K]>;\n}[number];\n\n/**\n * Unwraps a Zod schema to get the innermost type\n * Handles z.optional, z.nullable, z.array\n */\ntype UnwrapResult = {\n innerSchema: z.ZodTypeAny;\n isNullable: boolean;\n isArray: boolean;\n};\n\nfunction unwrapSchema(schema: z.ZodTypeAny): UnwrapResult {\n let current = schema;\n let isNullable = false;\n let isArray = false;\n\n // Unwrap layers\n while (true) {\n if (current instanceof z.ZodOptional) {\n isNullable = true;\n current = current.unwrap() as z.ZodTypeAny;\n } else if (current instanceof z.ZodNullable) {\n isNullable = true;\n current = current.unwrap() as z.ZodTypeAny;\n } else if (current instanceof z.ZodArray) {\n isArray = true;\n current = current.element as z.ZodTypeAny;\n } else {\n break;\n }\n }\n\n return { innerSchema: current, isNullable, isArray };\n}\n\n/**\n * Generates entity definitions from Zod schemas\n */\nexport function generateEntities<const T extends readonly z.ZodTypeAny[]>(\n schemas: T\n): EntityDefinition<ExtractEntityNames<T>>[] {\n const definitions: EntityDefinition[] = [];\n\n for (const schema of schemas) {\n const schemaType = getSchemaType(schema);\n\n // Only process entity schemas\n if (schemaType !== 'entity') {\n continue;\n }\n\n const name = getSchemaName(schema);\n if (name === undefined) {\n throw new Error('Entity schema must have a name');\n }\n\n const description = getSchemaDescription(schema);\n\n if (!(schema instanceof z.ZodObject)) {\n throw new Error(`Entity \"${name}\" must be a ZodObject`);\n }\n\n const properties: EntityPropertyDefinition[] = [];\n const shape = schema.shape;\n\n for (const [fieldName, fieldSchema] of Object.entries(shape)) {\n if (!(fieldSchema instanceof z.ZodType)) {\n continue;\n }\n\n const property = parseProperty(fieldName, fieldSchema);\n properties.push(property);\n }\n\n const entityDefinition: EntityDefinition = {\n name,\n properties,\n };\n if (description !== undefined) {\n entityDefinition.description = description;\n }\n definitions.push(entityDefinition);\n }\n\n return definitions as EntityDefinition<ExtractEntityNames<T>>[];\n}\n\n/**\n * Parses a single property from a Zod schema\n */\nfunction parseProperty(fieldName: string, fieldSchema: z.ZodTypeAny): EntityPropertyDefinition {\n const isPk = isPrimaryKey(fieldSchema);\n const isUniqueField = isUnique(fieldSchema);\n const refMetadata = getRefMetadata(fieldSchema);\n\n // Handle Primary Key\n if (isPk) {\n const property: EntityPropertyDefinitionPrimaryKey = {\n isReference: false,\n propertyType: 'PrimaryKey',\n name: fieldName,\n };\n return property;\n }\n\n // Handle Foreign Key Reference\n if (refMetadata !== undefined) {\n const { targetEntity } = refMetadata;\n\n // Validate that targetEntity is an entity\n const targetSchemaType = getSchemaType(targetEntity);\n if (targetSchemaType !== 'entity') {\n throw new Error(\n `Field \"${fieldName}\" has .ref() pointing to a non-entity schema. Only entity schemas created with entity() can be referenced.`\n );\n }\n\n const targetEntityName = getSchemaName(targetEntity);\n if (targetEntityName === undefined) {\n throw new Error(`Referenced entity for field \"${fieldName}\" must have a name`);\n }\n\n const { isNullable } = unwrapSchema(fieldSchema);\n\n const property: EntityPropertyDefinitionReferencedObject = {\n isReference: true,\n name: fieldName,\n targetEntityDefinitionName: targetEntityName,\n isUnique: isUniqueField,\n isNullable,\n };\n return property;\n }\n\n // Unwrap the schema\n const { innerSchema, isNullable, isArray } = unwrapSchema(fieldSchema);\n\n // Check if inner schema is an entity (not allowed)\n const innerSchemaType = getSchemaType(innerSchema);\n if (innerSchemaType === 'entity') {\n throw new Error(\n `Field \"${fieldName}\" contains a direct entity embedding. Entities cannot be directly nested. Use .ref() instead.`\n );\n }\n\n // Handle struct\n if (innerSchemaType === 'struct') {\n const structName = getSchemaName(innerSchema);\n if (structName === undefined) {\n throw new Error(`Struct schema for field \"${fieldName}\" must have a name`);\n }\n\n const property: EntityPropertyDefinitionTypedStruct = {\n isReference: false,\n propertyType: 'typedStruct',\n name: fieldName,\n structTypeName: structName,\n isUnique: isUniqueField,\n isNullable,\n isArray,\n };\n return property;\n }\n\n // Handle primitives\n const primitiveType = getPrimitiveType(innerSchema);\n if (primitiveType !== null) {\n const acceptableValues = getAcceptableValues(innerSchema);\n\n const property: EntityPropertyDefinitionPrimitive = {\n isReference: false,\n propertyType: primitiveType,\n name: fieldName,\n isUnique: isUniqueField,\n isNullable,\n isArray,\n acceptableValues,\n };\n return property;\n }\n\n throw new Error(`Unsupported schema type for field \"${fieldName}\"`);\n}\n\n/**\n * Determines the primitive type from a Zod schema\n */\nfunction getPrimitiveType(schema: z.ZodTypeAny): 'boolean' | 'number' | 'string' | 'Date' | null {\n if (schema instanceof z.ZodString) {\n return 'string';\n }\n if (schema instanceof z.ZodNumber) {\n return 'number';\n }\n if (schema instanceof z.ZodBoolean) {\n return 'boolean';\n }\n if (schema instanceof z.ZodDate) {\n return 'Date';\n }\n if (schema instanceof z.ZodEnum) {\n return 'string';\n }\n return null;\n}\n\n/**\n * Extracts acceptable values from z.enum\n */\nfunction getAcceptableValues(schema: z.ZodTypeAny): string[] | null {\n if (schema instanceof z.ZodEnum) {\n return [...schema.options] as string[];\n }\n return null;\n}\n\n/**\n * Generates relations from entity definitions\n */\nexport function generateRelations(definitions: EntityDefinition[]): EntityRelation[] {\n const relations: EntityRelation[] = [];\n\n // Build a map for quick lookup\n const entityMap = new Map<string, EntityDefinition>();\n for (const def of definitions) {\n entityMap.set(def.name, def);\n }\n\n // Initialize relations for each entity\n for (const def of definitions) {\n const referTos: EntityRelationReferTo[] = [];\n const referredBys: EntityRelationReferredBy[] = [];\n\n // Find referTos (outgoing references)\n for (const prop of def.properties) {\n if (prop.isReference) {\n referTos.push({\n entityName: prop.targetEntityDefinitionName,\n propertyName: prop.name,\n isUnique: prop.isUnique,\n });\n }\n }\n\n // Find referredBys (incoming references)\n for (const otherDef of definitions) {\n if (otherDef.name === def.name) {\n continue;\n }\n\n for (const prop of otherDef.properties) {\n if (prop.isReference && prop.targetEntityDefinitionName === def.name) {\n referredBys.push({\n entityName: otherDef.name,\n propertyName: prop.name,\n isUnique: prop.isUnique,\n });\n }\n }\n }\n\n relations.push({\n entityName: def.name,\n referTos,\n referredBys,\n });\n }\n\n return relations;\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@masaori/zod-to-entity-definitions",
3
+ "version": "1.1.7",
4
+ "description": "A library to define data models using Zod with extended metadata and convert them into framework-agnostic Entity Definitions",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "dev": "tsup --watch",
21
+ "test": "vitest run",
22
+ "test:watch": "vitest",
23
+ "lint": "biome check .",
24
+ "fix": "biome check --write .",
25
+ "format": "biome format --write .",
26
+ "check-types": "tsc --noEmit",
27
+ "prepublishOnly": "npm run check-types && npm run lint && npm run test && npm run build"
28
+ },
29
+ "keywords": [
30
+ "zod",
31
+ "entity",
32
+ "orm",
33
+ "schema",
34
+ "typescript",
35
+ "entity-definition",
36
+ "er-model"
37
+ ],
38
+ "author": "",
39
+ "license": "MIT",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "git+https://github.com/masaori/zod-to-entity-definitions.git"
43
+ },
44
+ "publishConfig": {
45
+ "registry": "https://registry.npmjs.org",
46
+ "access": "public"
47
+ },
48
+ "peerDependencies": {
49
+ "zod": "4.1.13"
50
+ },
51
+ "devDependencies": {
52
+ "@biomejs/biome": "^1.9.4",
53
+ "@commitlint/cli": "^19.0.0",
54
+ "@commitlint/config-conventional": "^19.0.0",
55
+ "@semantic-release/changelog": "^6.0.3",
56
+ "@semantic-release/git": "^10.0.1",
57
+ "@semantic-release/npm": "^12.0.0",
58
+ "@types/node": "^22.10.1",
59
+ "conventional-changelog-conventionalcommits": "^8.0.0",
60
+ "semantic-release": "^24.0.0",
61
+ "tsup": "^8.3.5",
62
+ "tsx": "^4.20.6",
63
+ "typescript": "^5.7.2",
64
+ "vitest": "^2.1.8",
65
+ "zod": "4.1.13"
66
+ }
67
+ }