prisma-effect-schema-generator 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cyberistic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # prisma-effect-schema-generator
2
+
3
+ A standalone [Prisma](https://www.prisma.io) generator that emits
4
+ [Effect Schema](https://effect.website/docs/schema) values for every
5
+ model in your `schema.prisma`. Drop-in runtime validation for your
6
+ database rows — perfect for sync engines, RPC layers, or anywhere you
7
+ need to assert that what you read from the DB actually matches what
8
+ your code expects.
9
+
10
+ A real-world example: the generator powers the schemas in
11
+ [`Cyberistic/livestore-tanstackdb`](https://github.com/Cyberistic/livestore-tanstackdb)
12
+ where a single `schema.prisma` drives both the Prisma/D1 DDL and the
13
+ LiveStore client-side validation.
14
+
15
+ ```prisma
16
+ generator effect_client {
17
+ provider = "prisma-effect-schema-generator"
18
+ }
19
+
20
+ model User {
21
+ id String @id
22
+ email String
23
+ role Role
24
+ }
25
+
26
+ enum Role {
27
+ ADMIN
28
+ USER
29
+ }
30
+ ```
31
+
32
+ ```ts
33
+ // generated/effect-schemas/index.ts (auto-generated)
34
+ import { Schema } from "effect"
35
+
36
+ export const UserSchema = Schema.Struct({
37
+ id: Schema.String,
38
+ email: Schema.String,
39
+ role: Schema.Union(Schema.Literal("ADMIN"), Schema.Literal("USER")),
40
+ })
41
+
42
+ export type ModelName = | "User"
43
+ export const ALL_MODEL_NAMES = ["User"] as const
44
+ ```
45
+
46
+ ```ts
47
+ // your code
48
+ import { Schema } from "effect"
49
+ import { UserSchema } from "./generated/effect-schemas"
50
+
51
+ const user = Schema.decodeUnknownSync(UserSchema)(rowFromDatabase)
52
+ // user is fully typed as { id: string; email: string; role: "ADMIN" | "USER" }
53
+ ```
54
+
55
+ ## Install
56
+
57
+ ```bash
58
+ npm install --save-dev prisma-effect-schema-generator
59
+ npm install effect # the generator emits `Schema.X` from `effect`
60
+ ```
61
+
62
+ ## Configure
63
+
64
+ Add the generator to your `schema.prisma`:
65
+
66
+ ```prisma
67
+ generator effect_client {
68
+ provider = "prisma-effect-schema-generator"
69
+ output = "./generated/effect-schemas/index.ts" // optional
70
+ }
71
+ ```
72
+
73
+ Run `npx prisma generate` and the file at `output` is created (or
74
+ updated) on every regeneration.
75
+
76
+ ### All options
77
+
78
+ | Option | Default | Description |
79
+ |-----------------------|----------------------|-------------------------------------------------------------------------------------------------------------------|
80
+ | `output` | `./generated/effect-schemas/index.ts` | Where to write the generated module. Relative to the schema file's directory. |
81
+ | `effectImport` | `"effect"` | Module specifier to import `Schema` from. Use `"@livestore/utils/effect"` if you live inside that ecosystem. |
82
+ | `effectImportName` | `"Schema"` | Local binding name. Set to e.g. `"S"` to import as `Schema as S`. |
83
+ | `bigIntAs` | `"BigIntFromSelf"` | `"BigInt"` (string-encoded) or `"BigIntFromSelf"` (accepts native bigint). |
84
+ | `decimalAs` | `"String"` | `"String"` (precision-safe) or `"Number"` (lossy but ergonomic). |
85
+ | `dateAs` | `"DateFromSelf"` | `"Date"` (ISO-string codec) or `"DateFromSelf"` (accepts native `Date`). |
86
+ | `exportModelNames` | `"true"` | Emit `export const ALL_MODEL_NAMES = [...] as const`. |
87
+ | `exportModelNameType` | `"true"` | Emit `export type ModelName = "X" | "Y"`. |
88
+
89
+ ```prisma
90
+ generator effect_client {
91
+ provider = "prisma-effect-schema-generator"
92
+ output = "./generated/effect-schemas/index.ts"
93
+ effectImport = "effect"
94
+ effectImportName = "Schema"
95
+ bigIntAs = "BigIntFromSelf"
96
+ decimalAs = "String"
97
+ dateAs = "DateFromSelf"
98
+ exportModelNames = "true"
99
+ exportModelNameType = "true"
100
+ }
101
+ ```
102
+
103
+ ## Type mapping
104
+
105
+ | Prisma field | Effect Schema (default) | Encoded → Decoded |
106
+ |--------------------|--------------------------------|------------------------------------|
107
+ | `String` | `Schema.String` | string → string |
108
+ | `Int` | `Schema.Number` | number → number |
109
+ | `Float` | `Schema.Number` | number → number |
110
+ | `BigInt` | `Schema.BigIntFromSelf` | bigint → bigint |
111
+ | `Decimal` | `Schema.String` | string → string (precision-safe) |
112
+ | `Boolean` | `Schema.Boolean` | boolean → boolean |
113
+ | `DateTime` | `Schema.DateFromSelf` | Date → Date |
114
+ | `Json` | `Schema.Unknown` | unknown → unknown |
115
+ | `Bytes` | `Schema.Uint8Array` | number[] → Uint8Array |
116
+ | enum `<E>` | `Schema.Union(Schema.Literal(...)...)` | string → string (literal type) |
117
+
118
+ Wrappers:
119
+
120
+ | Prisma modifier | Wrapper |
121
+ |-----------------|-----------------------------------|
122
+ | `field?` | `Schema.NullOr(...)` |
123
+ | `field[]` | `Schema.Array(...)` |
124
+ | `field[]?` | `Schema.NullOr(Schema.Array(...))` |
125
+
126
+ Relations (object-typed fields) are skipped — the model itself is the
127
+ representation, so re-emitting it as a nested schema would be redundant.
128
+ If you need to validate the related entity, just compose the related
129
+ schema yourself.
130
+
131
+ ## Programmatic use
132
+
133
+ The generator can be driven without Prisma, e.g. for build scripts or
134
+ custom tooling:
135
+
136
+ ```ts
137
+ import { runGenerator, resolveOptions } from "prisma-effect-schema-generator"
138
+
139
+ runGenerator({
140
+ output: "./out.ts",
141
+ schemaDir: process.cwd(),
142
+ datamodel: {
143
+ models: [
144
+ {
145
+ name: "User",
146
+ dbName: null,
147
+ fields: [
148
+ { kind: "scalar", name: "id", type: "String", isRequired: true, isList: false },
149
+ { kind: "scalar", name: "email", type: "String", isRequired: true, isList: false },
150
+ ],
151
+ },
152
+ ],
153
+ enums: [],
154
+ },
155
+ rawConfig: resolveOptions({ bigIntAs: "BigInt" }),
156
+ })
157
+ ```
158
+
159
+ Lower-level building blocks (`renderModule`, `prismaFieldToEffectSchema`,
160
+ `enumToSchema`, `shouldQuoteName`, ...) are also exported.
161
+
162
+ ## Requirements
163
+
164
+ - Node.js >= 18
165
+ - Prisma 7+ (the `@prisma/generator-helper@7` API)
166
+ - `effect` 3.x or 4.x (peer dependency)
167
+
168
+ ## Development
169
+
170
+ ```bash
171
+ npm install
172
+ npm run build # tsc -> dist/
173
+ npm test # vitest
174
+ npm run typecheck # tsc --noEmit
175
+ ```
176
+
177
+ ## License
178
+
179
+ MIT
@@ -0,0 +1,26 @@
1
+ import type { ResolvedOptions } from "./types.js";
2
+ /**
3
+ * The defaults applied when the user doesn't supply a config key.
4
+ *
5
+ * Kept here (not in `types.ts`) so they live next to the code that
6
+ * consumes them and the surface area is easy to skim.
7
+ */
8
+ export declare const DEFAULTS: {
9
+ readonly effectImport: "effect";
10
+ readonly effectImportName: "Schema";
11
+ readonly bigIntAs: "BigIntFromSelf";
12
+ readonly decimalAs: "String";
13
+ readonly dateAs: "DateFromSelf";
14
+ readonly exportModelNames: true;
15
+ readonly exportModelNameType: true;
16
+ };
17
+ type RawConfig = Record<string, string | string[] | boolean | undefined>;
18
+ /**
19
+ * Resolve user-supplied options against {@link DEFAULTS}.
20
+ *
21
+ * Unknown keys are dropped silently — Prisma forwards arbitrary strings
22
+ * and we don't want to fail on a typo we don't even use.
23
+ */
24
+ export declare function resolveOptions(raw: RawConfig | undefined | null): ResolvedOptions;
25
+ export {};
26
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ;;;;;;;;CAQe,CAAC;AAErC,KAAK,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;AAkBzE;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,GAAG,eAAe,CAWjF"}
package/dist/config.js ADDED
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULTS = void 0;
4
+ exports.resolveOptions = resolveOptions;
5
+ /**
6
+ * The defaults applied when the user doesn't supply a config key.
7
+ *
8
+ * Kept here (not in `types.ts`) so they live next to the code that
9
+ * consumes them and the surface area is easy to skim.
10
+ */
11
+ exports.DEFAULTS = {
12
+ effectImport: "effect",
13
+ effectImportName: "Schema",
14
+ bigIntAs: "BigIntFromSelf",
15
+ decimalAs: "String",
16
+ dateAs: "DateFromSelf",
17
+ exportModelNames: true,
18
+ exportModelNameType: true,
19
+ };
20
+ /**
21
+ * Normalise a string-or-boolean into a real boolean.
22
+ *
23
+ * Prisma passes all generator options as strings, so users write
24
+ * `exportModelNames = "false"` to turn the feature off. We accept a real
25
+ * `boolean` too for direct programmatic use (tests, programmatic APIs).
26
+ */
27
+ function toBool(v, fallback) {
28
+ if (typeof v === "boolean")
29
+ return v;
30
+ if (typeof v === "string") {
31
+ if (v === "true")
32
+ return true;
33
+ if (v === "false")
34
+ return false;
35
+ }
36
+ return fallback;
37
+ }
38
+ /**
39
+ * Resolve user-supplied options against {@link DEFAULTS}.
40
+ *
41
+ * Unknown keys are dropped silently — Prisma forwards arbitrary strings
42
+ * and we don't want to fail on a typo we don't even use.
43
+ */
44
+ function resolveOptions(raw) {
45
+ const cfg = raw ?? {};
46
+ return {
47
+ effectImport: stringOr(cfg.effectImport, exports.DEFAULTS.effectImport),
48
+ effectImportName: stringOr(cfg.effectImportName, exports.DEFAULTS.effectImportName),
49
+ bigIntAs: enumOr(cfg.bigIntAs, exports.DEFAULTS.bigIntAs, ["BigInt", "BigIntFromSelf"]),
50
+ decimalAs: enumOr(cfg.decimalAs, exports.DEFAULTS.decimalAs, ["String", "Number"]),
51
+ dateAs: enumOr(cfg.dateAs, exports.DEFAULTS.dateAs, ["Date", "DateFromSelf"]),
52
+ exportModelNames: toBool(cfg.exportModelNames, exports.DEFAULTS.exportModelNames),
53
+ exportModelNameType: toBool(cfg.exportModelNameType, exports.DEFAULTS.exportModelNameType),
54
+ };
55
+ }
56
+ function stringOr(v, fallback) {
57
+ return typeof v === "string" && v.length > 0 ? v : fallback;
58
+ }
59
+ function enumOr(v, fallback, allowed) {
60
+ if (typeof v === "string" && allowed.includes(v)) {
61
+ return v;
62
+ }
63
+ return fallback;
64
+ }
65
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;AA0CA,wCAWC;AAnDD;;;;;GAKG;AACU,QAAA,QAAQ,GAAG;IACtB,YAAY,EAAE,QAAQ;IACtB,gBAAgB,EAAE,QAAQ;IAC1B,QAAQ,EAAE,gBAAgB;IAC1B,SAAS,EAAE,QAAQ;IACnB,MAAM,EAAE,cAAc;IACtB,gBAAgB,EAAE,IAAI;IACtB,mBAAmB,EAAE,IAAI;CACS,CAAC;AAIrC;;;;;;GAMG;AACH,SAAS,MAAM,CAAC,CAAU,EAAE,QAAiB;IAC3C,IAAI,OAAO,CAAC,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC;IACrC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC;QAC9B,IAAI,CAAC,KAAK,OAAO;YAAE,OAAO,KAAK,CAAC;IAClC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,GAAiC;IAC9D,MAAM,GAAG,GAAG,GAAG,IAAI,EAAE,CAAC;IACtB,OAAO;QACL,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAQ,CAAC,YAAY,CAAC;QAC/D,gBAAgB,EAAE,QAAQ,CAAC,GAAG,CAAC,gBAAgB,EAAE,gBAAQ,CAAC,gBAAgB,CAAC;QAC3E,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,gBAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;QAC/E,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,gBAAQ,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC1E,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;QACrE,gBAAgB,EAAE,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,gBAAQ,CAAC,gBAAgB,CAAC;QACzE,mBAAmB,EAAE,MAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,gBAAQ,CAAC,mBAAmB,CAAC;KACnF,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,CAAU,EAAE,QAAgB;IAC5C,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC9D,CAAC;AAED,SAAS,MAAM,CACb,CAAU,EACV,QAAW,EACX,OAAqB;IAErB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAK,OAA6B,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,OAAO,CAAM,CAAC;IAChB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,61 @@
1
+ import type { DMMFDatamodelLike } from "./types.js";
2
+ /**
3
+ * Resolve the output file path the user asked for, against the schema
4
+ * directory Prisma tells us about.
5
+ *
6
+ * - `output` may be an absolute path or relative.
7
+ * - When relative, it's pinned to the schema file's directory so the
8
+ * generator behaves the same way no matter where Prisma invokes us
9
+ * from.
10
+ * - When the user didn't set `output`, we use `defaultOutput` from the
11
+ * manifest (relative to the schema directory).
12
+ */
13
+ export declare function resolveOutputPath(outputRaw: string | undefined, schemaDir: string, fallback: string): string;
14
+ /**
15
+ * The actual generator. Pure of side effects beyond writing the file
16
+ * and talking to Prisma -- easy to unit-test by calling
17
+ * {@link runGenerator} with a fake `GeneratorOptions`.
18
+ */
19
+ export declare function runGenerator(opts: {
20
+ output: string;
21
+ schemaDir: string;
22
+ datamodel: DMMFDatamodelLike;
23
+ rawConfig: Record<string, string | string[] | boolean | undefined> | undefined;
24
+ }): {
25
+ outputPath: string;
26
+ code: string;
27
+ };
28
+ /**
29
+ * Adapter that wraps {@link runGenerator} with the shape Prisma's
30
+ * generator-helper expects.
31
+ *
32
+ * Exposed so tests can drive the same code path that Prisma calls.
33
+ */
34
+ export declare function onGenerate(prismaOptions: {
35
+ generator: {
36
+ output?: {
37
+ value: string | null;
38
+ } | null;
39
+ config: Record<string, string | string[] | boolean | undefined>;
40
+ };
41
+ dmmf: {
42
+ datamodel: DMMFDatamodelLike;
43
+ };
44
+ schemaPath: string;
45
+ }): Promise<void>;
46
+ /**
47
+ * Register the generator with Prisma. The `prisma generate` command
48
+ * spawns the generator binary, which calls `generatorHandler(...)`,
49
+ * which in turn fires `onManifest` and `onGenerate`.
50
+ *
51
+ * Calling this at the top of the CJS entry is what wires everything up.
52
+ */
53
+ export declare function register(): void;
54
+ export { resolveOptions } from "./config.js";
55
+ export { renderModule } from "./render.js";
56
+ export type { DMMFDatamodelLike, DMMFEnumLike, DMMFFieldLike, DMMFModelLike, GeneratorOptionsConfig, ResolvedOptions, } from "./types.js";
57
+ export declare const _internal: {
58
+ PKG_NAME: string;
59
+ PKG_VERSION: string;
60
+ };
61
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAKpD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,MAAM,CAGR;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;CAChF,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAOvC;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,aAAa,EAAE;IAC9C,SAAS,EAAE;QACT,MAAM,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,GAAG,IAAI,CAAC;QACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;KACjE,CAAC;IACF,IAAI,EAAE;QAAE,SAAS,EAAE,iBAAiB,CAAA;KAAE,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhB;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,IAAI,IAAI,CAa/B;AAKD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,sBAAsB,EACtB,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,SAAS;;;CAA4B,CAAC"}
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports._internal = exports.renderModule = exports.resolveOptions = void 0;
4
+ exports.resolveOutputPath = resolveOutputPath;
5
+ exports.runGenerator = runGenerator;
6
+ exports.onGenerate = onGenerate;
7
+ exports.register = register;
8
+ const node_fs_1 = require("node:fs");
9
+ const node_path_1 = require("node:path");
10
+ const generator_helper_1 = require("@prisma/generator-helper");
11
+ const config_js_1 = require("./config.js");
12
+ const render_js_1 = require("./render.js");
13
+ const PKG_NAME = "prisma-effect-schema-generator";
14
+ const PKG_VERSION = "0.1.0";
15
+ /**
16
+ * Resolve the output file path the user asked for, against the schema
17
+ * directory Prisma tells us about.
18
+ *
19
+ * - `output` may be an absolute path or relative.
20
+ * - When relative, it's pinned to the schema file's directory so the
21
+ * generator behaves the same way no matter where Prisma invokes us
22
+ * from.
23
+ * - When the user didn't set `output`, we use `defaultOutput` from the
24
+ * manifest (relative to the schema directory).
25
+ */
26
+ function resolveOutputPath(outputRaw, schemaDir, fallback) {
27
+ const out = outputRaw && outputRaw.length > 0 ? outputRaw : fallback;
28
+ return (0, node_path_1.isAbsolute)(out) ? out : (0, node_path_1.resolve)(schemaDir, out);
29
+ }
30
+ /**
31
+ * The actual generator. Pure of side effects beyond writing the file
32
+ * and talking to Prisma -- easy to unit-test by calling
33
+ * {@link runGenerator} with a fake `GeneratorOptions`.
34
+ */
35
+ function runGenerator(opts) {
36
+ const options = (0, config_js_1.resolveOptions)(opts.rawConfig);
37
+ const code = (0, render_js_1.renderModule)(opts.datamodel, options);
38
+ const outputPath = resolveOutputPath(opts.output, opts.schemaDir, "./generated/effect-schemas/index.ts");
39
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(outputPath), { recursive: true });
40
+ (0, node_fs_1.writeFileSync)(outputPath, code, "utf8");
41
+ return { outputPath, code };
42
+ }
43
+ /**
44
+ * Adapter that wraps {@link runGenerator} with the shape Prisma's
45
+ * generator-helper expects.
46
+ *
47
+ * Exposed so tests can drive the same code path that Prisma calls.
48
+ */
49
+ async function onGenerate(prismaOptions) {
50
+ runGenerator({
51
+ output: prismaOptions.generator.output?.value ?? "",
52
+ schemaDir: (0, node_path_1.dirname)(prismaOptions.schemaPath),
53
+ datamodel: prismaOptions.dmmf.datamodel,
54
+ rawConfig: prismaOptions.generator.config,
55
+ });
56
+ }
57
+ /**
58
+ * Register the generator with Prisma. The `prisma generate` command
59
+ * spawns the generator binary, which calls `generatorHandler(...)`,
60
+ * which in turn fires `onManifest` and `onGenerate`.
61
+ *
62
+ * Calling this at the top of the CJS entry is what wires everything up.
63
+ */
64
+ function register() {
65
+ (0, generator_helper_1.generatorHandler)({
66
+ onManifest() {
67
+ return {
68
+ defaultOutput: "./generated/effect-schemas/index.ts",
69
+ prettyName: "Effect Schema Generator",
70
+ version: PKG_VERSION,
71
+ };
72
+ },
73
+ async onGenerate(options) {
74
+ await onGenerate(options);
75
+ },
76
+ });
77
+ }
78
+ // Re-export the building blocks so programmatic consumers can drive
79
+ // the generator without going through Prisma at all (handy for
80
+ // snapshot tests, embedding in build scripts, etc.).
81
+ var config_js_2 = require("./config.js");
82
+ Object.defineProperty(exports, "resolveOptions", { enumerable: true, get: function () { return config_js_2.resolveOptions; } });
83
+ var render_js_2 = require("./render.js");
84
+ Object.defineProperty(exports, "renderModule", { enumerable: true, get: function () { return render_js_2.renderModule; } });
85
+ exports._internal = { PKG_NAME, PKG_VERSION };
86
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":";;;AAqBA,8CAOC;AAOD,oCAYC;AAQD,gCAcC;AASD,4BAaC;AA3FD,qCAAmD;AACnD,yCAAyD;AACzD,+DAA4D;AAC5D,2CAA6C;AAC7C,2CAA2C;AAG3C,MAAM,QAAQ,GAAG,gCAAgC,CAAC;AAClD,MAAM,WAAW,GAAG,OAAO,CAAC;AAE5B;;;;;;;;;;GAUG;AACH,SAAgB,iBAAiB,CAC/B,SAA6B,EAC7B,SAAiB,EACjB,QAAgB;IAEhB,MAAM,GAAG,GAAG,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IACrE,OAAO,IAAA,sBAAU,EAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAA,mBAAO,EAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,SAAgB,YAAY,CAAC,IAK5B;IACC,MAAM,OAAO,GAAG,IAAA,0BAAc,EAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,IAAA,wBAAY,EAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,qCAAqC,CAAC,CAAC;IACzG,IAAA,mBAAS,EAAC,IAAA,mBAAO,EAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,IAAA,uBAAa,EAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAC9B,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,UAAU,CAAC,aAOhC;IACC,YAAY,CAAC;QACX,MAAM,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;QACnD,SAAS,EAAE,IAAA,mBAAO,EAAC,aAAa,CAAC,UAAU,CAAC;QAC5C,SAAS,EAAE,aAAa,CAAC,IAAI,CAAC,SAAS;QACvC,SAAS,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM;KAC1C,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,QAAQ;IACtB,IAAA,mCAAgB,EAAC;QACf,UAAU;YACR,OAAO;gBACL,aAAa,EAAE,qCAAqC;gBACpD,UAAU,EAAE,yBAAyB;gBACrC,OAAO,EAAE,WAAW;aACrB,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,OAAO;YACtB,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,oEAAoE;AACpE,+DAA+D;AAC/D,qDAAqD;AACrD,yCAA6C;AAApC,2GAAA,cAAc,OAAA;AACvB,yCAA2C;AAAlC,yGAAA,YAAY,OAAA;AAUR,QAAA,SAAS,GAAG,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * prisma-effect-schema-generator
3
+ *
4
+ * Standalone Prisma generator that emits Effect Schema values for every
5
+ * model in your `schema.prisma`.
6
+ *
7
+ * Public API:
8
+ * - {@link register} -- wire up the generator with `@prisma/generator-helper`.
9
+ * - {@link runGenerator} -- programmatic entry (no Prisma required).
10
+ * - {@link renderModule} -- render the TS source for a given DMMF.
11
+ * - {@link resolveOptions} -- normalise user config.
12
+ *
13
+ * Most users will never touch this file directly. Add the generator to
14
+ * `schema.prisma` and run `prisma generate`.
15
+ */
16
+ export { register, runGenerator, onGenerate, resolveOutputPath, } from "./generator.js";
17
+ export { renderModule } from "./render.js";
18
+ export { prismaFieldToBaseSchema, prismaFieldToEffectSchema, enumToSchema, isIncludeField, sortModels, } from "./mapper.js";
19
+ export { resolveOptions, DEFAULTS } from "./config.js";
20
+ export { shouldQuoteName, renderKey } from "./render.js";
21
+ export type { DMMFDatamodelLike, DMMFEnumLike, DMMFFieldLike, DMMFModelLike, GeneratorOptionsConfig, ResolvedOptions, } from "./types.js";
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,YAAY,EACZ,cAAc,EACd,UAAU,GACX,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,sBAAsB,EACtB,eAAe,GAChB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ /**
3
+ * prisma-effect-schema-generator
4
+ *
5
+ * Standalone Prisma generator that emits Effect Schema values for every
6
+ * model in your `schema.prisma`.
7
+ *
8
+ * Public API:
9
+ * - {@link register} -- wire up the generator with `@prisma/generator-helper`.
10
+ * - {@link runGenerator} -- programmatic entry (no Prisma required).
11
+ * - {@link renderModule} -- render the TS source for a given DMMF.
12
+ * - {@link resolveOptions} -- normalise user config.
13
+ *
14
+ * Most users will never touch this file directly. Add the generator to
15
+ * `schema.prisma` and run `prisma generate`.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.renderKey = exports.shouldQuoteName = exports.DEFAULTS = exports.resolveOptions = exports.sortModels = exports.isIncludeField = exports.enumToSchema = exports.prismaFieldToEffectSchema = exports.prismaFieldToBaseSchema = exports.renderModule = exports.resolveOutputPath = exports.onGenerate = exports.runGenerator = exports.register = void 0;
19
+ const generator_js_1 = require("./generator.js");
20
+ var generator_js_2 = require("./generator.js");
21
+ Object.defineProperty(exports, "register", { enumerable: true, get: function () { return generator_js_2.register; } });
22
+ Object.defineProperty(exports, "runGenerator", { enumerable: true, get: function () { return generator_js_2.runGenerator; } });
23
+ Object.defineProperty(exports, "onGenerate", { enumerable: true, get: function () { return generator_js_2.onGenerate; } });
24
+ Object.defineProperty(exports, "resolveOutputPath", { enumerable: true, get: function () { return generator_js_2.resolveOutputPath; } });
25
+ var render_js_1 = require("./render.js");
26
+ Object.defineProperty(exports, "renderModule", { enumerable: true, get: function () { return render_js_1.renderModule; } });
27
+ var mapper_js_1 = require("./mapper.js");
28
+ Object.defineProperty(exports, "prismaFieldToBaseSchema", { enumerable: true, get: function () { return mapper_js_1.prismaFieldToBaseSchema; } });
29
+ Object.defineProperty(exports, "prismaFieldToEffectSchema", { enumerable: true, get: function () { return mapper_js_1.prismaFieldToEffectSchema; } });
30
+ Object.defineProperty(exports, "enumToSchema", { enumerable: true, get: function () { return mapper_js_1.enumToSchema; } });
31
+ Object.defineProperty(exports, "isIncludeField", { enumerable: true, get: function () { return mapper_js_1.isIncludeField; } });
32
+ Object.defineProperty(exports, "sortModels", { enumerable: true, get: function () { return mapper_js_1.sortModels; } });
33
+ var config_js_1 = require("./config.js");
34
+ Object.defineProperty(exports, "resolveOptions", { enumerable: true, get: function () { return config_js_1.resolveOptions; } });
35
+ Object.defineProperty(exports, "DEFAULTS", { enumerable: true, get: function () { return config_js_1.DEFAULTS; } });
36
+ var render_js_2 = require("./render.js");
37
+ Object.defineProperty(exports, "shouldQuoteName", { enumerable: true, get: function () { return render_js_2.shouldQuoteName; } });
38
+ Object.defineProperty(exports, "renderKey", { enumerable: true, get: function () { return render_js_2.renderKey; } });
39
+ // Auto-register when imported as the generator entry point.
40
+ // We guard with a feature-detection on `process` so importing the
41
+ // module from tests / Node doesn't crash on environments that lack it.
42
+ if (typeof process !== "undefined" && process.env.PRISMA_GENERATOR_AUTO_REGISTER !== "0") {
43
+ try {
44
+ (0, generator_js_1.register)();
45
+ }
46
+ catch {
47
+ // No-op: registering requires `@prisma/generator-helper`'s
48
+ // `generatorHandler`, which only works under Prisma's spawn. When
49
+ // imported from a test / a build script we skip registration.
50
+ }
51
+ }
52
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH,iDAA0C;AAE1C,+CAKwB;AAJtB,wGAAA,QAAQ,OAAA;AACR,4GAAA,YAAY,OAAA;AACZ,0GAAA,UAAU,OAAA;AACV,iHAAA,iBAAiB,OAAA;AAEnB,yCAA2C;AAAlC,yGAAA,YAAY,OAAA;AACrB,yCAMqB;AALnB,oHAAA,uBAAuB,OAAA;AACvB,sHAAA,yBAAyB,OAAA;AACzB,yGAAA,YAAY,OAAA;AACZ,2GAAA,cAAc,OAAA;AACd,uGAAA,UAAU,OAAA;AAEZ,yCAAuD;AAA9C,2GAAA,cAAc,OAAA;AAAE,qGAAA,QAAQ,OAAA;AACjC,yCAAyD;AAAhD,4GAAA,eAAe,OAAA;AAAE,sGAAA,SAAS,OAAA;AAUnC,4DAA4D;AAC5D,kEAAkE;AAClE,uEAAuE;AACvE,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,8BAA8B,KAAK,GAAG,EAAE,CAAC;IACzF,IAAI,CAAC;QACH,IAAA,uBAAQ,GAAE,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,2DAA2D;QAC3D,kEAAkE;QAClE,8DAA8D;IAChE,CAAC;AACH,CAAC"}
@@ -0,0 +1,55 @@
1
+ import type { DMMFDatamodelLike, DMMFFieldLike, DMMFModelLike, ResolvedOptions } from "./types.js";
2
+ /**
3
+ * Return the local binding for the Effect Schema namespace.
4
+ *
5
+ * Default is `Schema` -- which is what `effect` exports. If the user
6
+ * has chosen to import it under a different name we honour that
7
+ * throughout the file.
8
+ */
9
+ export declare function localBinding(options: ResolvedOptions): string;
10
+ /**
11
+ * Map a single Prisma scalar field to its Effect Schema expression,
12
+ * without list/optional wrappers.
13
+ *
14
+ * Returns the raw `Schema.<X>` identifier or a literal enum expression.
15
+ * Wrapping (lists + NullOr) is applied by {@link prismaFieldToEffectSchema}.
16
+ *
17
+ * For unknown / unsupported kinds we fall back to `Schema.Unknown` and
18
+ * emit a `// TODO` comment in the rendered output via
19
+ * {@link prismaFieldToEffectSchema}.
20
+ */
21
+ export declare function prismaFieldToBaseSchema(field: DMMFFieldLike, datamodel: DMMFDatamodelLike, options: ResolvedOptions): {
22
+ expr: string;
23
+ unsupported: boolean;
24
+ };
25
+ /**
26
+ * Apply list + optional wrappers to a base schema expression and return
27
+ * the final Effect Schema expression for the field.
28
+ */
29
+ export declare function prismaFieldToEffectSchema(field: DMMFFieldLike, datamodel: DMMFDatamodelLike, options: ResolvedOptions): {
30
+ expr: string;
31
+ unsupported: boolean;
32
+ };
33
+ /**
34
+ * Render an enum field as `Schema.Union(Schema.Literal("A"), Schema.Literal("B"))`.
35
+ *
36
+ * If the enum can't be found in the datamodel we emit
37
+ * `Schema.Literal("UNKNOWN")` as a sentinel so the generated file is still
38
+ * parseable; the user will get a clear runtime error.
39
+ */
40
+ export declare function enumToSchema(enumName: string, datamodel: DMMFDatamodelLike, options?: ResolvedOptions): string;
41
+ /**
42
+ * Decide whether a field is "safe" to include in the generated Struct.
43
+ *
44
+ * - Scalars: yes
45
+ * - Enums: yes
46
+ * - Object (relation) fields: skipped (Prisma gives you the model directly)
47
+ * - Unsupported fields: included as `Schema.Unknown` so nothing breaks
48
+ */
49
+ export declare function isIncludeField(field: DMMFFieldLike): boolean;
50
+ /**
51
+ * Sort models so that the output is deterministic regardless of the order
52
+ * DMMF hands them to us in. Field order inside a model is preserved.
53
+ */
54
+ export declare function sortModels(models: readonly DMMFModelLike[]): DMMFModelLike[];
55
+ //# sourceMappingURL=mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["../src/mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAI7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,aAAa,EACpB,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,eAAe,GACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAyCxC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,aAAa,EACpB,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,eAAe,GACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAOxC;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,iBAAiB,EAC5B,OAAO,CAAC,EAAE,eAAe,GACxB,MAAM,CAiBR;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAE5D;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,GAAG,aAAa,EAAE,CAE5E"}
package/dist/mapper.js ADDED
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.localBinding = localBinding;
4
+ exports.prismaFieldToBaseSchema = prismaFieldToBaseSchema;
5
+ exports.prismaFieldToEffectSchema = prismaFieldToEffectSchema;
6
+ exports.enumToSchema = enumToSchema;
7
+ exports.isIncludeField = isIncludeField;
8
+ exports.sortModels = sortModels;
9
+ /**
10
+ * Return the local binding for the Effect Schema namespace.
11
+ *
12
+ * Default is `Schema` -- which is what `effect` exports. If the user
13
+ * has chosen to import it under a different name we honour that
14
+ * throughout the file.
15
+ */
16
+ function localBinding(options) {
17
+ return options.effectImportName === "Schema"
18
+ ? "Schema"
19
+ : options.effectImportName;
20
+ }
21
+ /**
22
+ * Map a single Prisma scalar field to its Effect Schema expression,
23
+ * without list/optional wrappers.
24
+ *
25
+ * Returns the raw `Schema.<X>` identifier or a literal enum expression.
26
+ * Wrapping (lists + NullOr) is applied by {@link prismaFieldToEffectSchema}.
27
+ *
28
+ * For unknown / unsupported kinds we fall back to `Schema.Unknown` and
29
+ * emit a `// TODO` comment in the rendered output via
30
+ * {@link prismaFieldToEffectSchema}.
31
+ */
32
+ function prismaFieldToBaseSchema(field, datamodel, options) {
33
+ const b = localBinding(options);
34
+ // Enums first -- they don't have a fixed `type` like scalars do.
35
+ if (field.kind === "enum") {
36
+ return {
37
+ expr: enumToSchema(field.type, datamodel, options),
38
+ unsupported: false,
39
+ };
40
+ }
41
+ // "Unsupported" fields (e.g. Mongo `Unsupported("...")`) carry a
42
+ // declared `type` but the underlying DB can't represent it. We must
43
+ // short-circuit here, otherwise the type-switch below would resolve
44
+ // them to whatever their declared type maps to (often misleading).
45
+ if (field.kind === "unsupported") {
46
+ return { expr: `${b}.Unknown`, unsupported: true };
47
+ }
48
+ switch (field.type) {
49
+ case "String":
50
+ return { expr: `${b}.String`, unsupported: false };
51
+ case "Int":
52
+ case "Float":
53
+ return { expr: `${b}.Number`, unsupported: false };
54
+ case "BigInt":
55
+ return { expr: `${b}.${options.bigIntAs}`, unsupported: false };
56
+ case "Decimal":
57
+ return { expr: `${b}.${options.decimalAs}`, unsupported: false };
58
+ case "Boolean":
59
+ return { expr: `${b}.Boolean`, unsupported: false };
60
+ case "DateTime":
61
+ return { expr: `${b}.${options.dateAs}`, unsupported: false };
62
+ case "Json":
63
+ return { expr: `${b}.Unknown`, unsupported: false };
64
+ case "Bytes":
65
+ return { expr: `${b}.Uint8Array`, unsupported: false };
66
+ default:
67
+ // Unknown / future Prisma types land here.
68
+ return { expr: `${b}.Unknown`, unsupported: true };
69
+ }
70
+ }
71
+ /**
72
+ * Apply list + optional wrappers to a base schema expression and return
73
+ * the final Effect Schema expression for the field.
74
+ */
75
+ function prismaFieldToEffectSchema(field, datamodel, options) {
76
+ const b = localBinding(options);
77
+ const base = prismaFieldToBaseSchema(field, datamodel, options);
78
+ let expr = base.expr;
79
+ if (field.isList)
80
+ expr = `${b}.Array(${expr})`;
81
+ if (!field.isRequired)
82
+ expr = `${b}.NullOr(${expr})`;
83
+ return { expr, unsupported: base.unsupported };
84
+ }
85
+ /**
86
+ * Render an enum field as `Schema.Union(Schema.Literal("A"), Schema.Literal("B"))`.
87
+ *
88
+ * If the enum can't be found in the datamodel we emit
89
+ * `Schema.Literal("UNKNOWN")` as a sentinel so the generated file is still
90
+ * parseable; the user will get a clear runtime error.
91
+ */
92
+ function enumToSchema(enumName, datamodel, options) {
93
+ const b = localBinding(options ?? {
94
+ effectImport: "effect",
95
+ effectImportName: "Schema",
96
+ bigIntAs: "BigIntFromSelf",
97
+ decimalAs: "String",
98
+ dateAs: "DateFromSelf",
99
+ exportModelNames: true,
100
+ exportModelNameType: true,
101
+ });
102
+ const en = datamodel.enums.find((e) => e.name === enumName);
103
+ if (!en || en.values.length === 0) {
104
+ return `${b}.Literal("UNKNOWN")`;
105
+ }
106
+ const literals = en.values.map((v) => `${b}.Literal(${JSON.stringify(v.name)})`);
107
+ if (literals.length === 1)
108
+ return literals[0];
109
+ return `${b}.Union(${literals.join(", ")})`;
110
+ }
111
+ /**
112
+ * Decide whether a field is "safe" to include in the generated Struct.
113
+ *
114
+ * - Scalars: yes
115
+ * - Enums: yes
116
+ * - Object (relation) fields: skipped (Prisma gives you the model directly)
117
+ * - Unsupported fields: included as `Schema.Unknown` so nothing breaks
118
+ */
119
+ function isIncludeField(field) {
120
+ return field.kind === "scalar" || field.kind === "enum" || field.kind === "unsupported";
121
+ }
122
+ /**
123
+ * Sort models so that the output is deterministic regardless of the order
124
+ * DMMF hands them to us in. Field order inside a model is preserved.
125
+ */
126
+ function sortModels(models) {
127
+ return [...models].sort((a, b) => a.name.localeCompare(b.name));
128
+ }
129
+ //# sourceMappingURL=mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.js","sourceRoot":"","sources":["../src/mapper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { DMMFDatamodelLike, DMMFModelLike, ResolvedOptions } from "./types.js";
2
+ /**
3
+ * Decide whether a property key needs to be quoted.
4
+ *
5
+ * The bare minimum is "valid identifier that is not a reserved word".
6
+ * Anything else -- names with hyphens, spaces, leading digits -- must be
7
+ * quoted, otherwise the generated TypeScript won't parse.
8
+ *
9
+ * We accept Unicode letters/digits (per the ECMAScript spec for
10
+ * IdentifierStart/IdentifierPart) so non-ASCII names like `caf\u00e9`
11
+ * don't get quoted needlessly.
12
+ */
13
+ export declare function shouldQuoteName(name: string): boolean;
14
+ /**
15
+ * Render a property key, smart-quoting it only when necessary.
16
+ *
17
+ * Always emits a quoted string if the name isn't a valid identifier or
18
+ * collides with a reserved word; otherwise emits the bare identifier.
19
+ * This is the only sane default -- we don't expose a "force quote" knob
20
+ * because quoting bare identifiers actively hurts readability and
21
+ * prevents destructuring in user code.
22
+ */
23
+ export declare function renderKey(name: string): string;
24
+ /**
25
+ * Render a single model as a `Schema.Struct({ ... })` expression.
26
+ *
27
+ * Relation fields (kind === "object") are skipped entirely. Scalar
28
+ * fields are emitted in the order they appear in the DMMF.
29
+ */
30
+ export declare function renderModel(model: DMMFModelLike, datamodel: DMMFDatamodelLike, options: ResolvedOptions): string;
31
+ /**
32
+ * Render the entire generated module.
33
+ *
34
+ * The output is byte-stable for the same input: model order is sorted
35
+ * alphabetically, field order is preserved, and we always emit a
36
+ * trailing newline.
37
+ */
38
+ export declare function renderModule(datamodel: DMMFDatamodelLike, options: ResolvedOptions): string;
39
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EAChB,MAAM,YAAY,CAAC;AAmBpB;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAeD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,aAAa,EACpB,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,eAAe,GACvB,MAAM,CAiCR;AAgCD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,eAAe,GACvB,MAAM,CAoCR"}
package/dist/render.js ADDED
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shouldQuoteName = shouldQuoteName;
4
+ exports.renderKey = renderKey;
5
+ exports.renderModel = renderModel;
6
+ exports.renderModule = renderModule;
7
+ const mapper_js_1 = require("./mapper.js");
8
+ const RESERVED_IDENTIFIERS = new Set([
9
+ // ECMAScript reserved words -- these are illegal as object property
10
+ // keys when unquoted, period.
11
+ "break", "case", "catch", "class", "const", "continue", "debugger",
12
+ "default", "delete", "do", "else", "enum", "export", "extends", "false",
13
+ "finally", "for", "function", "if", "import", "in", "instanceof", "new",
14
+ "null", "return", "super", "switch", "this", "throw", "true", "try",
15
+ "typeof", "var", "void", "while", "with", "yield",
16
+ // Strict-mode reserved.
17
+ "implements", "interface", "let", "package", "private", "protected",
18
+ "public", "static", "await",
19
+ // NOTE: TypeScript type-level keywords (`string`, `number`, `boolean`,
20
+ // `any`, `unknown`, `never`, `void`, `undefined`, `null`, ...) are NOT
21
+ // reserved as object property keys. `{ string: "hi" }` parses fine in
22
+ // TS 5+. Only the value-level reserved words above need quoting.
23
+ ]);
24
+ /**
25
+ * Decide whether a property key needs to be quoted.
26
+ *
27
+ * The bare minimum is "valid identifier that is not a reserved word".
28
+ * Anything else -- names with hyphens, spaces, leading digits -- must be
29
+ * quoted, otherwise the generated TypeScript won't parse.
30
+ *
31
+ * We accept Unicode letters/digits (per the ECMAScript spec for
32
+ * IdentifierStart/IdentifierPart) so non-ASCII names like `caf\u00e9`
33
+ * don't get quoted needlessly.
34
+ */
35
+ function shouldQuoteName(name) {
36
+ if (RESERVED_IDENTIFIERS.has(name))
37
+ return true;
38
+ return !/^[\p{L}_$][\p{L}\p{N}_$]*$/u.test(name);
39
+ }
40
+ /**
41
+ * Render a property key, smart-quoting it only when necessary.
42
+ *
43
+ * Always emits a quoted string if the name isn't a valid identifier or
44
+ * collides with a reserved word; otherwise emits the bare identifier.
45
+ * This is the only sane default -- we don't expose a "force quote" knob
46
+ * because quoting bare identifiers actively hurts readability and
47
+ * prevents destructuring in user code.
48
+ */
49
+ function renderKey(name) {
50
+ return shouldQuoteName(name) ? JSON.stringify(name) : name;
51
+ }
52
+ /**
53
+ * The local binding for the Effect Schema namespace.
54
+ *
55
+ * Default is `Schema` -- which is what `effect` exports. If the user
56
+ * has chosen to import it under a different name we honour that
57
+ * throughout the file.
58
+ */
59
+ function localBinding(options) {
60
+ return options.effectImportName === "Schema"
61
+ ? "Schema"
62
+ : options.effectImportName;
63
+ }
64
+ /**
65
+ * Render a single model as a `Schema.Struct({ ... })` expression.
66
+ *
67
+ * Relation fields (kind === "object") are skipped entirely. Scalar
68
+ * fields are emitted in the order they appear in the DMMF.
69
+ */
70
+ function renderModel(model, datamodel, options) {
71
+ const lines = [];
72
+ const binding = localBinding(options);
73
+ const unsupportedComments = [];
74
+ lines.push(`export const ${model.name}Schema = ${binding}.Struct({`);
75
+ for (const field of model.fields) {
76
+ if (!(0, mapper_js_1.isIncludeField)(field))
77
+ continue;
78
+ const { expr, unsupported } = (0, mapper_js_1.prismaFieldToEffectSchema)(field, datamodel, options);
79
+ const key = renderKey(field.name);
80
+ lines.push(` ${key}: ${expr},`);
81
+ if (unsupported && field.kind === "unsupported") {
82
+ unsupportedComments.push(`// - ${field.name}: Prisma marks this field as "unsupported" -- typed as Schema.Unknown.`);
83
+ }
84
+ }
85
+ lines.push("})");
86
+ if (unsupportedComments.length > 0) {
87
+ lines.unshift(`// WARNING: ${model.name} contains unsupported fields:`);
88
+ for (const c of unsupportedComments)
89
+ lines.unshift(c);
90
+ lines.unshift("");
91
+ }
92
+ lines.push("");
93
+ return lines.join("\n");
94
+ }
95
+ /**
96
+ * Render the helper exports at the bottom of the file:
97
+ *
98
+ * export type ModelName = "Todo" | "Event";
99
+ * export const ALL_MODEL_NAMES = ["Todo", "Event"] as const;
100
+ *
101
+ * These are guarded by `options.exportModelNames` /
102
+ * `options.exportModelNameType` so users can disable either piece.
103
+ */
104
+ function renderModelHelpers(models, options) {
105
+ const lines = [];
106
+ if (options.exportModelNameType && models.length > 0) {
107
+ lines.push("export type ModelName =");
108
+ for (const m of models) {
109
+ lines.push(` | ${JSON.stringify(m.name)}`);
110
+ }
111
+ lines.push("");
112
+ }
113
+ if (options.exportModelNames && models.length > 0) {
114
+ lines.push(`export const ALL_MODEL_NAMES = ${JSON.stringify(models.map((m) => m.name))} as const`, "");
115
+ }
116
+ return lines;
117
+ }
118
+ /**
119
+ * Render the entire generated module.
120
+ *
121
+ * The output is byte-stable for the same input: model order is sorted
122
+ * alphabetically, field order is preserved, and we always emit a
123
+ * trailing newline.
124
+ */
125
+ function renderModule(datamodel, options) {
126
+ const lines = [];
127
+ lines.push(`// AUTO-GENERATED by prisma-effect-schema-generator -- do not edit.`, `// Regenerate via \`prisma generate\`.`, "");
128
+ if (datamodel.models.length === 0) {
129
+ lines.push(`// No models in your schema.prisma -- nothing to generate.`, `export const ALL_MODEL_NAMES = [] as const`, `export type ModelName = never`, "");
130
+ return lines.join("\n");
131
+ }
132
+ if (options.effectImportName === "Schema") {
133
+ lines.push(`import { Schema } from "${options.effectImport}"`, "");
134
+ }
135
+ else {
136
+ lines.push(`import { Schema as ${options.effectImportName} } from "${options.effectImport}"`, "");
137
+ }
138
+ const models = (0, mapper_js_1.sortModels)(datamodel.models);
139
+ for (const m of models) {
140
+ lines.push(renderModel(m, datamodel, options));
141
+ }
142
+ lines.push(...renderModelHelpers(models, options));
143
+ return lines.join("\n");
144
+ }
145
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Public configuration for the generator.
3
+ *
4
+ * Each option is read from the `generator` block in `schema.prisma`,
5
+ * e.g. `effectImport = "effect"` becomes `effectImport` here.
6
+ *
7
+ * Unknown options are ignored (Prisma only forwards strings).
8
+ */
9
+ export interface GeneratorOptionsConfig {
10
+ /** Path the generated module is written to. */
11
+ readonly output?: string;
12
+ /** Module specifier for `Schema`. Defaults to `"effect"`. */
13
+ readonly effectImport?: string;
14
+ /** Local name to import `Schema` under. Defaults to `"Schema"`. */
15
+ readonly effectImportName?: string;
16
+ /** How `BigInt` Prisma fields map to Effect. Default `"BigIntFromSelf"`. */
17
+ readonly bigIntAs?: "BigInt" | "BigIntFromSelf";
18
+ /** How `Decimal` Prisma fields map to Effect. Default `"String"`. */
19
+ readonly decimalAs?: "String" | "Number";
20
+ /** How `DateTime` Prisma fields map to Effect. Default `"Date"`. */
21
+ readonly dateAs?: "Date" | "DateFromSelf";
22
+ /**
23
+ * Emit `ALL_MODEL_NAMES` and `ModelName` helpers. Default `true`.
24
+ * Set to `"false"` to disable.
25
+ */
26
+ readonly exportModelNames?: boolean | string;
27
+ /**
28
+ * Emit the `ModelName` TypeScript union type. Default `true`.
29
+ * Set to `"false"` to disable.
30
+ */
31
+ readonly exportModelNameType?: boolean | string;
32
+ }
33
+ /**
34
+ * Fully-resolved options (defaults applied) used internally by the renderer.
35
+ */
36
+ export interface ResolvedOptions {
37
+ readonly effectImport: string;
38
+ readonly effectImportName: string;
39
+ readonly bigIntAs: "BigInt" | "BigIntFromSelf";
40
+ readonly decimalAs: "String" | "Number";
41
+ readonly dateAs: "Date" | "DateFromSelf";
42
+ readonly exportModelNames: boolean;
43
+ readonly exportModelNameType: boolean;
44
+ }
45
+ /**
46
+ * The shape of an `@prisma/dmmf` field that we care about.
47
+ *
48
+ * We type it minimally here so the renderer can be exercised against
49
+ * partial fixtures in tests without needing the full DMMF type.
50
+ */
51
+ export interface DMMFFieldLike {
52
+ readonly kind: "scalar" | "object" | "enum" | "unsupported";
53
+ readonly name: string;
54
+ readonly type: string;
55
+ readonly isRequired: boolean;
56
+ readonly isList: boolean;
57
+ readonly isUnique?: boolean;
58
+ readonly isId?: boolean;
59
+ readonly hasDefaultValue?: boolean;
60
+ readonly dbName?: string | null;
61
+ }
62
+ export interface DMMFModelLike {
63
+ readonly name: string;
64
+ readonly dbName?: string | null;
65
+ readonly fields: readonly DMMFFieldLike[];
66
+ }
67
+ export interface DMMFEnumLike {
68
+ readonly name: string;
69
+ readonly values: readonly {
70
+ readonly name: string;
71
+ }[];
72
+ }
73
+ export interface DMMFDatamodelLike {
74
+ readonly models: readonly DMMFModelLike[];
75
+ readonly enums: readonly DMMFEnumLike[];
76
+ }
77
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,mEAAmE;IACnE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,gBAAgB,CAAC;IAChD,qEAAqE;IACrE,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACzC,oEAAoE;IACpE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC7C;;;OAGG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACjD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,gBAAgB,CAAC;IAC/C,QAAQ,CAAC,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC;IACzC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;CACvC;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,aAAa,CAAC;IAC5D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;CAC3C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACvD;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;CACzC"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "prisma-effect-schema-generator",
3
+ "version": "0.1.0",
4
+ "description": "Prisma generator that emits Effect Schema values for every model — drop-in validation for your database rows.",
5
+ "keywords": [
6
+ "prisma",
7
+ "prisma-generator",
8
+ "effect",
9
+ "effect-schema",
10
+ "schema",
11
+ "validation",
12
+ "orm",
13
+ "typescript",
14
+ "dmmf"
15
+ ],
16
+ "license": "MIT",
17
+ "author": "Cyberistic",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/Cyberistic/Prisma-Effect-Schema-Generator.git"
21
+ },
22
+ "homepage": "https://github.com/Cyberistic/Prisma-Effect-Schema-Generator#readme",
23
+ "bugs": {
24
+ "url": "https://github.com/Cyberistic/Prisma-Effect-Schema-Generator/issues"
25
+ },
26
+ "main": "./dist/index.js",
27
+ "module": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "require": "./dist/index.js",
33
+ "default": "./dist/index.js"
34
+ },
35
+ "./package.json": "./package.json"
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "README.md",
40
+ "LICENSE"
41
+ ],
42
+ "scripts": {
43
+ "build": "tsc -p tsconfig.build.json",
44
+ "clean": "rm -rf dist",
45
+ "prepublishOnly": "npm run clean && npm run build && npm test",
46
+ "test": "vitest run",
47
+ "test:watch": "vitest",
48
+ "typecheck": "tsc --noEmit",
49
+ "lint": "echo 'no linter configured'"
50
+ },
51
+ "dependencies": {
52
+ "@prisma/generator-helper": "^7.0.0"
53
+ },
54
+ "peerDependencies": {
55
+ "@prisma/generator-helper": "^7.0.0",
56
+ "effect": "^3.0.0 || ^4.0.0"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "effect": {
60
+ "optional": true
61
+ }
62
+ },
63
+ "devDependencies": {
64
+ "@prisma/generator-helper": "^7.8.0",
65
+ "@types/node": "^22.10.0",
66
+ "effect": "^3.21.0",
67
+ "prisma": "^7.8.0",
68
+ "typescript": "^5.4.5",
69
+ "vitest": "^2.1.0"
70
+ },
71
+ "engines": {
72
+ "node": ">=18.0.0"
73
+ },
74
+ "sideEffects": false,
75
+ "publishConfig": {
76
+ "access": "public"
77
+ }
78
+ }