hekireki 0.7.5 → 0.7.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.
@@ -1,14 +1,57 @@
1
1
  //#region src/cli/index.d.ts
2
- type Result<T> = {
2
+ declare const HELP_TEXT = "\u26A1\uFE0F hekireki - Prisma schema tools\n\nUsage:\n hekireki <command> [options]\n\nCommands:\n docs serve Start a local server to view the documentation\n\nOptions:\n -p, --port <port> Specify the port (default: 5858)\n -h, --help Show help\n\nExamples:\n hekireki docs serve\n hekireki docs serve -p 3000";
3
+ declare const DOCS_HELP_TEXT = "\u26A1\uFE0F hekireki docs - Documentation tools\n\nUsage:\n hekireki docs serve [options]\n\nCommands:\n serve Start a local server to view the documentation\n\nOptions:\n -p, --port <port> Specify the port (default: 5858)\n -h, --help Show help\n\nExamples:\n hekireki docs serve\n hekireki docs serve -p 3000";
4
+ /**
5
+ * Parse port from CLI arguments.
6
+ */
7
+ declare const parsePort: (args: readonly string[]) => {
8
+ readonly ok: true;
9
+ readonly value: number;
10
+ } | {
11
+ readonly ok: false;
12
+ readonly error: string;
13
+ };
14
+ /**
15
+ * Parse CLI arguments for docs serve command.
16
+ */
17
+ declare const parseDocsServeArgs: (args: readonly string[]) => {
18
+ readonly ok: true;
19
+ readonly value: {
20
+ readonly port: number;
21
+ };
22
+ } | {
23
+ readonly ok: false;
24
+ readonly error: string;
25
+ };
26
+ /**
27
+ * Handle docs subcommand.
28
+ */
29
+ declare const handleDocs: (args: readonly string[]) => {
30
+ readonly ok: true;
31
+ readonly value: string;
32
+ } | {
33
+ readonly ok: false;
34
+ readonly error: string;
35
+ };
36
+ /**
37
+ * Main CLI dispatcher (pure — takes args, returns Result).
38
+ */
39
+ declare const hekirekiCli: (args: readonly string[]) => {
3
40
  readonly ok: true;
4
- readonly value: T;
41
+ readonly value: string;
5
42
  } | {
6
43
  readonly ok: false;
7
44
  readonly error: string;
8
45
  };
9
46
  /**
10
- * Main CLI entry point for hekireki.
47
+ * Main CLI entry point for hekireki (reads process.argv).
11
48
  */
12
- declare const hekireki: () => Result<string>;
49
+ declare const hekireki: () => {
50
+ readonly ok: true;
51
+ readonly value: string;
52
+ } | {
53
+ readonly ok: false;
54
+ readonly error: string;
55
+ };
13
56
  //#endregion
14
- export { hekireki };
57
+ export { DOCS_HELP_TEXT, HELP_TEXT, handleDocs, hekireki, hekirekiCli, parseDocsServeArgs, parsePort };
package/dist/cli/index.js CHANGED
@@ -137,10 +137,9 @@ const handleDocs = (args) => {
137
137
  */
138
138
  const commands = { docs: handleDocs };
139
139
  /**
140
- * Main CLI entry point for hekireki.
140
+ * Main CLI dispatcher (pure takes args, returns Result).
141
141
  */
142
- const hekireki = () => {
143
- const args = process.argv.slice(2);
142
+ const hekirekiCli = (args) => {
144
143
  const command = args[0];
145
144
  if (!command || command === "-h" || command === "--help") return {
146
145
  ok: true,
@@ -153,6 +152,12 @@ const hekireki = () => {
153
152
  };
154
153
  return handler(args.slice(1));
155
154
  };
155
+ /**
156
+ * Main CLI entry point for hekireki (reads process.argv).
157
+ */
158
+ const hekireki = () => {
159
+ return hekirekiCli(process.argv.slice(2));
160
+ };
156
161
  const result = hekireki();
157
162
  if (result.ok) console.log(result.value);
158
163
  else {
@@ -161,4 +166,4 @@ else {
161
166
  }
162
167
 
163
168
  //#endregion
164
- export { hekireki };
169
+ export { DOCS_HELP_TEXT, HELP_TEXT, handleDocs, hekireki, hekirekiCli, parseDocsServeArgs, parsePort };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as fmt } from "../../format-DwiYldCm.js";
3
- import { a as makeCommentBlock, c as makeValidationExtractor, f as mkdir, l as parseDocumentWithoutAnnotations, p as writeFile, t as getBool } from "../../utils-BGe939v0.js";
4
- import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-CfcdmYJs.js";
3
+ import { l as makeValidationExtractor, m as writeFile, n as getBool, o as makeCommentBlock, p as mkdir, u as parseDocumentWithoutAnnotations } from "../../utils-3ot3YB3D.js";
4
+ import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-o4IvnEUh.js";
5
5
  import path from "node:path";
6
6
  import pkg from "@prisma/generator-helper";
7
7
 
@@ -37,13 +37,13 @@ const PRISMA_TO_AJV = {
37
37
  * @param modelFields - The fields of the model
38
38
  * @param comment - Whether to include JSDoc comments in the generated code
39
39
  */
40
- function makeAjvSchemas(modelFields, comment) {
40
+ function makeAjvSchemas(modelFields, comment, objectType) {
41
41
  const modelName = modelFields[0].modelName;
42
42
  const properties = modelFields.map((field) => {
43
43
  return `${comment ? makeCommentBlock(field.comment, 4) : ""} ${field.fieldName}: ${field.validation ?? "{ type: 'unknown' as const }"},`;
44
44
  }).join("\n");
45
45
  const requiredFields = modelFields.filter((f) => f.isRequired).map((f) => f.fieldName);
46
- return `export const ${modelName}Schema = {\n type: 'object' as const,\n properties: {\n${properties}\n },${requiredFields.length > 0 ? `\n required: [${requiredFields.map((f) => `'${f}'`).join(", ")}] as const,` : ""}\n additionalProperties: false,\n} as const`;
46
+ return `export const ${modelName}Schema = {\n type: 'object' as const,\n properties: {\n${properties}\n },${requiredFields.length > 0 ? `\n required: [${requiredFields.map((f) => `'${f}'`).join(", ")}] as const,` : ""}\n additionalProperties: ${objectType === "loose" ? "true" : "false"},\n} as const`;
47
47
  }
48
48
  /**
49
49
  * Generate JSON Schema relation object definition
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as fmt } from "../../format-DwiYldCm.js";
3
- import { a as makeCommentBlock, c as makeValidationExtractor, f as mkdir, l as parseDocumentWithoutAnnotations, p as writeFile, t as getBool, u as schemaFromFields } from "../../utils-BGe939v0.js";
4
- import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-CfcdmYJs.js";
3
+ import { d as schemaFromFields, l as makeValidationExtractor, m as writeFile, n as getBool, o as makeCommentBlock, p as mkdir, u as parseDocumentWithoutAnnotations } from "../../utils-3ot3YB3D.js";
4
+ import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-o4IvnEUh.js";
5
5
  import path from "node:path";
6
6
  import pkg from "@prisma/generator-helper";
7
7
 
@@ -18,8 +18,8 @@ function makeArktypeInfer(modelName) {
18
18
  * @param modelName - The model name for the schema
19
19
  * @param fields - The formatted field definitions string
20
20
  */
21
- function makeArktypeSchema(modelName, fields) {
22
- return `export const ${modelName}Schema = type({\n${fields}\n})`;
21
+ function makeArktypeSchema(modelName, fields, objectType) {
22
+ return `export const ${modelName}Schema = type({${objectType === "strict" ? "\n \"+\": \"reject\",\n" : objectType === "loose" ? "\n \"+\": \"ignore\",\n" : "\n"}${fields}\n})`;
23
23
  }
24
24
  /**
25
25
  * Generate ArkType property definitions
@@ -55,8 +55,8 @@ const PRISMA_TO_ARKTYPE = {
55
55
  * @param modelFields - The fields of the model
56
56
  * @param comment - Whether to include JSDoc comments in the generated code
57
57
  */
58
- function makeArktypeSchemas(modelFields, comment) {
59
- return schemaFromFields(modelFields, comment, makeArktypeSchema, makeArktypeProperties);
58
+ function makeArktypeSchemas(modelFields, comment, objectType) {
59
+ return schemaFromFields(modelFields, comment, makeArktypeSchema, makeArktypeProperties, objectType);
60
60
  }
61
61
  /**
62
62
  * Generate ArkType relation schema definition
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { d as stripAnnotations, f as mkdir, m as writeFileBinary, n as getString, p as writeFile } from "../../utils-BGe939v0.js";
2
+ import { f as stripAnnotations, h as writeFileBinary, m as writeFile, p as mkdir, r as getString } from "../../utils-3ot3YB3D.js";
3
3
  import path from "node:path";
4
4
  import pkg from "@prisma/generator-helper";
5
5
  import { Resvg } from "@resvg/resvg-js";
@@ -1,10 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as fmt } from "../../format-DwiYldCm.js";
3
- import { f as mkdir, p as writeFile, s as makeSnakeCase } from "../../utils-BGe939v0.js";
3
+ import { c as makeSnakeCase, m as writeFile, p as mkdir } from "../../utils-3ot3YB3D.js";
4
4
  import path from "node:path";
5
5
  import pkg from "@prisma/generator-helper";
6
6
 
7
7
  //#region src/helper/drizzle.ts
8
+ function resolveDbProvider(provider) {
9
+ switch (provider) {
10
+ case "postgresql":
11
+ case "cockroachdb": return "postgresql";
12
+ case "mysql": return "mysql";
13
+ case "sqlite": return "sqlite";
14
+ }
15
+ }
8
16
  const PG_SCALAR_MAP = {
9
17
  String: "text()",
10
18
  Int: "integer()",
@@ -97,34 +105,26 @@ function mysqlNativeType(name, args) {
97
105
  default: return null;
98
106
  }
99
107
  }
100
- var ImportTracker = class {
101
- coreFns = /* @__PURE__ */ new Set();
102
- ormFns = /* @__PURE__ */ new Set();
103
- extPkgs = /* @__PURE__ */ new Map();
104
- provider;
105
- constructor(provider) {
106
- this.provider = provider;
107
- }
108
- addCore(fn) {
109
- this.coreFns.add(fn);
110
- }
111
- addOrm(fn) {
112
- this.ormFns.add(fn);
113
- }
114
- addExternal(pkg, fn) {
115
- const fns = this.extPkgs.get(pkg) ?? /* @__PURE__ */ new Set();
116
- fns.add(fn);
117
- this.extPkgs.set(pkg, fns);
118
- }
119
- generate() {
120
- const mod = this.provider === "postgresql" ? "drizzle-orm/pg-core" : this.provider === "mysql" ? "drizzle-orm/mysql-core" : "drizzle-orm/sqlite-core";
121
- return [
122
- this.coreFns.size > 0 ? `import { ${[...this.coreFns].sort().join(", ")} } from '${mod}'` : "",
123
- this.ormFns.size > 0 ? `import { ${[...this.ormFns].sort().join(", ")} } from 'drizzle-orm'` : "",
124
- ...[...this.extPkgs.entries()].map(([pkg, fns]) => `import { ${[...fns].sort().join(", ")} } from '${pkg}'`)
125
- ].filter(Boolean).join("\n");
126
- }
127
- };
108
+ function createImports() {
109
+ return {
110
+ core: /* @__PURE__ */ new Set(),
111
+ orm: /* @__PURE__ */ new Set(),
112
+ ext: /* @__PURE__ */ new Map()
113
+ };
114
+ }
115
+ function addExternal(imports, pkg, fn) {
116
+ const fns = imports.ext.get(pkg) ?? /* @__PURE__ */ new Set();
117
+ fns.add(fn);
118
+ imports.ext.set(pkg, fns);
119
+ }
120
+ function generateImports(imports, provider) {
121
+ const mod = provider === "postgresql" ? "drizzle-orm/pg-core" : provider === "mysql" ? "drizzle-orm/mysql-core" : "drizzle-orm/sqlite-core";
122
+ return [
123
+ imports.core.size > 0 ? `import { ${[...imports.core].sort().join(", ")} } from '${mod}'` : "",
124
+ imports.orm.size > 0 ? `import { ${[...imports.orm].sort().join(", ")} } from 'drizzle-orm'` : "",
125
+ ...[...imports.ext.entries()].map(([pkg, fns]) => `import { ${[...fns].sort().join(", ")} } from '${pkg}'`)
126
+ ].filter(Boolean).join("\n");
127
+ }
128
128
  function toCamelCase(name) {
129
129
  return name.charAt(0).toLowerCase() + name.slice(1);
130
130
  }
@@ -146,23 +146,23 @@ function makeColumnExpr(field, provider, imports, enums) {
146
146
  const enumDef = enums.find((e) => e.name === field.type);
147
147
  const enumValues = enumDef ? enumDef.values.map((v) => `'${v.name}'`).join(", ") : "";
148
148
  if (provider === "postgresql") {
149
- imports.addCore("pgEnum");
149
+ imports.core.add("pgEnum");
150
150
  return `pgEnum('${enumDef?.dbName ?? field.type}', [${enumValues}])('${colName}')`;
151
151
  }
152
152
  if (provider === "mysql") {
153
- imports.addCore("mysqlEnum");
153
+ imports.core.add("mysqlEnum");
154
154
  return `mysqlEnum('${colName}', [${enumValues}])`;
155
155
  }
156
- imports.addCore("text");
156
+ imports.core.add("text");
157
157
  return `text('${colName}', { enum: [${enumValues}] })`;
158
158
  }
159
159
  if (isAutoincrement && provider === "postgresql") {
160
- imports.addCore("serial");
160
+ imports.core.add("serial");
161
161
  return `serial('${colName}')`;
162
162
  }
163
163
  const baseExpr = resolveScalarType(field, provider);
164
164
  const fnName = baseExpr.match(/^(\w+)/)?.[1];
165
- if (fnName) imports.addCore(fnName);
165
+ if (fnName) imports.core.add(fnName);
166
166
  const parenIdx = baseExpr.indexOf("(");
167
167
  if (parenIdx === -1) return baseExpr;
168
168
  const baseFnName = baseExpr.slice(0, parenIdx);
@@ -261,8 +261,8 @@ function resolveUpdatedAtDefault(provider) {
261
261
  }
262
262
  function makeDefaultChain(dflt, fieldType, provider, imports) {
263
263
  const result = resolveDefaultValue(dflt, fieldType, provider);
264
- if (result.needsSql) imports.addOrm("sql");
265
- if (result.needsCuid) imports.addExternal("@paralleldrive/cuid2", "createId");
264
+ if (result.needsSql) imports.orm.add("sql");
265
+ if (result.needsCuid) addExternal(imports, "@paralleldrive/cuid2", "createId");
266
266
  return result.chain;
267
267
  }
268
268
  const PRISMA_ACTION_MAP = {
@@ -275,6 +275,7 @@ const PRISMA_ACTION_MAP = {
275
275
  function makeFkReference(field, model) {
276
276
  const relField = model.fields.find((f) => f.kind === "object" && f.relationFromFields && f.relationFromFields.includes(field.name));
277
277
  if (!(relField?.relationFromFields && relField.relationToFields)) return "";
278
+ if (relField.type === model.name) return "";
278
279
  const targetVar = toCamelCase(relField.type);
279
280
  const toCol = relField.relationToFields[0] ?? "id";
280
281
  const onDelete = relField.relationOnDelete;
@@ -294,7 +295,7 @@ function makeColumn(field, model, provider, imports, enums) {
294
295
  makeFkReference(field, model),
295
296
  isAutoincrement ? provider === "mysql" ? ".autoincrement()" : "" : field.isUpdatedAt && (field.default === void 0 || field.default === null) ? (() => {
296
297
  const r = resolveUpdatedAtDefault(provider);
297
- if (r.needsSql) imports.addOrm("sql");
298
+ if (r.needsSql) imports.orm.add("sql");
298
299
  return r.chain;
299
300
  })() : makeDefaultChain(field.default, field.type, provider, imports),
300
301
  field.isUpdatedAt ? ".$onUpdate(() => new Date())" : "",
@@ -304,15 +305,15 @@ function makeColumn(field, model, provider, imports, enums) {
304
305
  }
305
306
  function makeCompositeConstraints(model, imports, indexes, tableName) {
306
307
  const pkLine = model.primaryKey ? (() => {
307
- imports.addCore("primaryKey");
308
+ imports.core.add("primaryKey");
308
309
  return `primaryKey({ columns: [${model.primaryKey.fields.map((f) => `table.${f}`).join(", ")}] })`;
309
310
  })() : null;
310
311
  const uniqueLines = model.uniqueFields.filter((fields) => fields.length > 1).map((fields) => {
311
- imports.addCore("unique");
312
+ imports.core.add("unique");
312
313
  return `unique().on(${fields.map((f) => `table.${f}`).join(", ")})`;
313
314
  });
314
315
  const indexLines = indexes.filter((idx) => idx.model === model.name && (idx.type === "normal" || idx.type === "fulltext")).map((idx) => {
315
- imports.addCore("index");
316
+ imports.core.add("index");
316
317
  return `index('${idx.dbName ?? idx.name ?? `idx_${tableName}_${idx.fields.map((f) => f.name).join("_")}`}').on(${idx.fields.map((f) => `table.${f.name}`).join(", ")})`;
317
318
  });
318
319
  const all = [
@@ -324,7 +325,7 @@ function makeCompositeConstraints(model, imports, indexes, tableName) {
324
325
  }
325
326
  function makeTable(model, provider, imports, enums, indexes) {
326
327
  const tableFunc = provider === "postgresql" ? "pgTable" : provider === "mysql" ? "mysqlTable" : "sqliteTable";
327
- imports.addCore(tableFunc);
328
+ imports.core.add(tableFunc);
328
329
  const varName = toCamelCase(model.name);
329
330
  const tableName = model.dbName ?? makeSnakeCase(model.name);
330
331
  const columns = model.fields.map((field) => makeColumn(field, model, provider, imports, enums)).filter((c) => c !== null).join(", ");
@@ -351,7 +352,7 @@ function makeRelationField(field, model, _models, relFields) {
351
352
  function makeRelations(models, imports) {
352
353
  const modelsWithRels = models.filter((model) => model.fields.some((f) => f.kind === "object"));
353
354
  if (modelsWithRels.length === 0) return [];
354
- imports.addOrm("relations");
355
+ imports.orm.add("relations");
355
356
  return modelsWithRels.map((model) => {
356
357
  const relFields = model.fields.filter((f) => f.kind === "object");
357
358
  const fieldLines = relFields.map((field) => makeRelationField(field, model, models, relFields)).join(", ");
@@ -362,22 +363,14 @@ function makeRelations(models, imports) {
362
363
  });
363
364
  }
364
365
  function drizzleSchema(datamodel, provider, indexes) {
365
- const db = (() => {
366
- switch (provider) {
367
- case "postgresql":
368
- case "cockroachdb": return "postgresql";
369
- case "mysql": return "mysql";
370
- case "sqlite": return "sqlite";
371
- default: throw new Error(`Unsupported provider: ${provider}`);
372
- }
373
- })();
374
- const imports = new ImportTracker(db);
366
+ const db = resolveDbProvider(provider);
367
+ const imports = createImports();
375
368
  const tableLines = datamodel.models.map((model) => makeTable(model, db, imports, datamodel.enums, indexes));
376
369
  const relationsLines = makeRelations(datamodel.models, imports);
377
370
  const tableLinesWithGap = tableLines.flatMap((line, i) => i < tableLines.length - 1 ? [line, ""] : [line]);
378
371
  const relationsLinesWithGap = relationsLines.flatMap((line, i) => i < relationsLines.length - 1 ? [line, ""] : [line]);
379
372
  return [
380
- imports.generate(),
373
+ generateImports(imports, db),
381
374
  "",
382
375
  ...tableLinesWithGap,
383
376
  ...relationsLinesWithGap.length > 0 ? ["", ...relationsLinesWithGap] : []
@@ -387,6 +380,10 @@ function drizzleSchema(datamodel, provider, indexes) {
387
380
  //#endregion
388
381
  //#region src/generator/drizzle/index.ts
389
382
  const { generatorHandler } = pkg;
383
+ function parsePrismaProvider(raw) {
384
+ if (raw === "postgresql" || raw === "cockroachdb" || raw === "mysql" || raw === "sqlite") return raw;
385
+ throw new Error(`Unsupported provider: ${raw}`);
386
+ }
390
387
  async function main(options) {
391
388
  if (!(options.generator.isCustomOutput && options.generator.output?.value)) throw new Error("output is required for Hekireki-Drizzle. Please specify output in your generator config.");
392
389
  const output = options.generator.output.value;
@@ -397,7 +394,7 @@ async function main(options) {
397
394
  dir: output,
398
395
  file: path.join(output, "schema.ts")
399
396
  };
400
- const provider = options.datasources[0]?.activeProvider ?? "postgresql";
397
+ const provider = parsePrismaProvider(options.datasources[0]?.activeProvider ?? "postgresql");
401
398
  const formatted = await fmt(drizzleSchema(options.dmmf.datamodel, provider, options.dmmf.datamodel.indexes));
402
399
  await mkdir(resolved.dir);
403
400
  await writeFile(resolved.file, formatted);
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { f as mkdir, p as writeFile, s as makeSnakeCase } from "../../utils-BGe939v0.js";
2
+ import { c as makeSnakeCase, m as writeFile, p as mkdir } from "../../utils-3ot3YB3D.js";
3
3
  import { join } from "node:path";
4
4
  import pkg from "@prisma/generator-helper";
5
5
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as fmt } from "../../format-DwiYldCm.js";
3
- import { a as makeCommentBlock, c as makeValidationExtractor, f as mkdir, l as parseDocumentWithoutAnnotations, p as writeFile, t as getBool, u as schemaFromFields } from "../../utils-BGe939v0.js";
4
- import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-CfcdmYJs.js";
3
+ import { d as schemaFromFields, l as makeValidationExtractor, m as writeFile, n as getBool, o as makeCommentBlock, p as mkdir, u as parseDocumentWithoutAnnotations } from "../../utils-3ot3YB3D.js";
4
+ import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-o4IvnEUh.js";
5
5
  import path from "node:path";
6
6
  import pkg from "@prisma/generator-helper";
7
7
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { f as mkdir, n as getString, p as writeFile, s as makeSnakeCase } from "../../utils-BGe939v0.js";
2
+ import { c as makeSnakeCase, m as writeFile, p as mkdir, r as getString } from "../../utils-3ot3YB3D.js";
3
3
  import path, { dirname } from "node:path";
4
4
  import pkg from "@prisma/generator-helper";
5
5
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { d as stripAnnotations, f as mkdir, p as writeFile } from "../../utils-BGe939v0.js";
2
+ import { f as stripAnnotations, m as writeFile, p as mkdir } from "../../utils-3ot3YB3D.js";
3
3
  import path from "node:path";
4
4
  import pkg from "@prisma/generator-helper";
5
5
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { f as mkdir, n as getString, p as writeFile, s as makeSnakeCase } from "../../utils-BGe939v0.js";
2
+ import { c as makeSnakeCase, m as writeFile, p as mkdir, r as getString } from "../../utils-3ot3YB3D.js";
3
3
  import { join } from "node:path";
4
4
  import pkg from "@prisma/generator-helper";
5
5
 
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { f as mkdir, p as writeFile, s as makeSnakeCase } from "../../utils-BGe939v0.js";
2
+ import { c as makeSnakeCase, m as writeFile, p as mkdir } from "../../utils-3ot3YB3D.js";
3
3
  import path, { dirname } from "node:path";
4
4
  import pkg from "@prisma/generator-helper";
5
5
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as fmt } from "../../format-DwiYldCm.js";
3
- import { a as makeCommentBlock, c as makeValidationExtractor, f as mkdir, l as parseDocumentWithoutAnnotations, p as writeFile, t as getBool, u as schemaFromFields } from "../../utils-BGe939v0.js";
4
- import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-CfcdmYJs.js";
3
+ import { d as schemaFromFields, l as makeValidationExtractor, m as writeFile, n as getBool, o as makeCommentBlock, p as mkdir, u as parseDocumentWithoutAnnotations } from "../../utils-3ot3YB3D.js";
4
+ import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-o4IvnEUh.js";
5
5
  import path from "node:path";
6
6
  import pkg from "@prisma/generator-helper";
7
7
 
@@ -18,8 +18,9 @@ function makeTypeBoxInfer(modelName) {
18
18
  * @param modelName - The model name for the schema
19
19
  * @param fields - The formatted field definitions string
20
20
  */
21
- function makeTypeBoxSchema(modelName, fields) {
22
- return `export const ${modelName}Schema = Type.Object({\n${fields}\n})`;
21
+ function makeTypeBoxSchema(modelName, fields, objectType) {
22
+ const obj = `Type.Object({\n${fields}\n})`;
23
+ return objectType === "strict" ? `export const ${modelName}Schema = Type.Strict(${obj})` : `export const ${modelName}Schema = ${obj}`;
23
24
  }
24
25
  /**
25
26
  * Generate TypeBox property definitions with optional wrapping
@@ -58,8 +59,8 @@ const PRISMA_TO_TYPEBOX = {
58
59
  * @param modelFields - The fields of the model
59
60
  * @param comment - Whether to include JSDoc comments in the generated code
60
61
  */
61
- function makeTypeBoxSchemas(modelFields, comment) {
62
- return schemaFromFields(modelFields, comment, makeTypeBoxSchema, makeTypeBoxProperties);
62
+ function makeTypeBoxSchemas(modelFields, comment, objectType) {
63
+ return schemaFromFields(modelFields, comment, makeTypeBoxSchema, makeTypeBoxProperties, objectType);
63
64
  }
64
65
  /**
65
66
  * Generate TypeBox relation schema definition
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as fmt } from "../../format-DwiYldCm.js";
3
- import { c as makeValidationExtractor, f as mkdir, l as parseDocumentWithoutAnnotations, o as makePropertiesGenerator, p as writeFile, t as getBool, u as schemaFromFields } from "../../utils-BGe939v0.js";
4
- import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-CfcdmYJs.js";
3
+ import { d as schemaFromFields, l as makeValidationExtractor, m as writeFile, n as getBool, p as mkdir, s as makePropertiesGenerator, u as parseDocumentWithoutAnnotations } from "../../utils-3ot3YB3D.js";
4
+ import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-o4IvnEUh.js";
5
5
  import path from "node:path";
6
6
  import pkg from "@prisma/generator-helper";
7
7
 
@@ -9,8 +9,8 @@ import pkg from "@prisma/generator-helper";
9
9
  function makeValibotInfer(modelName) {
10
10
  return `export type ${modelName} = v.InferOutput<typeof ${modelName}Schema>`;
11
11
  }
12
- function makeValibotSchema(modelName, fields) {
13
- return `export const ${modelName}Schema = v.object({\n${fields}\n})`;
12
+ function makeValibotSchema(modelName, fields, objectType) {
13
+ return `export const ${modelName}Schema = v.${objectType === "strict" ? "strictObject" : objectType === "loose" ? "looseObject" : "object"}({\n${fields}\n})`;
14
14
  }
15
15
  function makeValibotEnumExpression(values) {
16
16
  return `picklist([${values.map((v) => `'${v}'`).join(", ")}])`;
@@ -26,8 +26,8 @@ const PRISMA_TO_VALIBOT = {
26
26
  Json: "unknown()",
27
27
  Bytes: "any()"
28
28
  };
29
- function makeValibotSchemas(modelFields, comment) {
30
- return schemaFromFields(modelFields, comment, makeValibotSchema, makePropertiesGenerator("v", (expr, isRequired) => isRequired ? expr : `v.exactOptional(${expr})`));
29
+ function makeValibotSchemas(modelFields, comment, objectType) {
30
+ return schemaFromFields(modelFields, comment, makeValibotSchema, makePropertiesGenerator("v", (expr, isRequired) => isRequired ? expr : `v.exactOptional(${expr})`), objectType);
31
31
  }
32
32
  function makeValibotRelations(model, relProps, options) {
33
33
  if (relProps.length === 0) return null;
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as fmt } from "../../format-DwiYldCm.js";
3
- import { c as makeValidationExtractor, f as mkdir, l as parseDocumentWithoutAnnotations, n as getString, o as makePropertiesGenerator, p as writeFile, t as getBool, u as schemaFromFields } from "../../utils-BGe939v0.js";
4
- import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-CfcdmYJs.js";
3
+ import { d as schemaFromFields, l as makeValidationExtractor, m as writeFile, n as getBool, p as mkdir, r as getString, s as makePropertiesGenerator, u as parseDocumentWithoutAnnotations } from "../../utils-3ot3YB3D.js";
4
+ import { n as validationSchemas, t as makeRelationsOnly } from "../../prisma-o4IvnEUh.js";
5
5
  import path from "node:path";
6
6
  import pkg from "@prisma/generator-helper";
7
7
 
@@ -9,8 +9,8 @@ import pkg from "@prisma/generator-helper";
9
9
  function makeZodInfer(modelName) {
10
10
  return `export type ${modelName} = z.infer<typeof ${modelName}Schema>`;
11
11
  }
12
- function makeZodSchema(modelName, fields) {
13
- return `export const ${modelName}Schema = z.object({\n${fields}\n})`;
12
+ function makeZodSchema(modelName, fields, objectType) {
13
+ return `export const ${modelName}Schema = z.${objectType === "strict" ? "strictObject" : objectType === "loose" ? "looseObject" : "object"}({\n${fields}\n})`;
14
14
  }
15
15
  function makeZodEnumExpression(values) {
16
16
  return `enum([${values.map((v) => `'${v}'`).join(", ")}])`;
@@ -26,8 +26,8 @@ const PRISMA_TO_ZOD = {
26
26
  Json: "unknown()",
27
27
  Bytes: "any()"
28
28
  };
29
- function makeZodSchemas(modelFields, comment) {
30
- return schemaFromFields(modelFields, comment, makeZodSchema, makePropertiesGenerator("z", (expr, isRequired) => isRequired ? expr : `${expr}.exactOptional()`));
29
+ function makeZodSchemas(modelFields, comment, objectType) {
30
+ return schemaFromFields(modelFields, comment, makeZodSchema, makePropertiesGenerator("z", (expr, isRequired) => isRequired ? expr : `${expr}.exactOptional()`), objectType);
31
31
  }
32
32
  function makeZodRelations(model, relProps, options) {
33
33
  if (relProps.length === 0) return null;
@@ -1,4 +1,4 @@
1
- import { i as isFields, r as groupByModel } from "./utils-BGe939v0.js";
1
+ import { a as isFields, i as groupByModel, t as extractObjectType } from "./utils-3ot3YB3D.js";
2
2
 
3
3
  //#region src/helper/prisma.ts
4
4
  function collectRelationProps(models) {
@@ -61,10 +61,13 @@ function validationSchemas(models, type, comment, config) {
61
61
  fieldName: f.name
62
62
  })));
63
63
  if (config.onWarning) for (const { modelName, fieldName } of missing) config.onWarning(`Warning: Field "${modelName}.${fieldName}" has no ${config.annotationPrefix} annotation and will be omitted from the schema`);
64
- const schemas = Object.values(groupByModel(isFields(modelFields))).map((fields) => ({
65
- schema: config.schemas(fields, comment),
66
- inferType: type ? config.inferType(fields[0].modelName) : ""
67
- })).flatMap(({ schema, inferType }) => [schema, inferType].filter(Boolean)).join("\n\n");
64
+ const schemas = Object.values(groupByModel(isFields(modelFields))).map((fields) => {
65
+ const objectType = extractObjectType(fields[0].documentation, config.annotationPrefix);
66
+ return {
67
+ schema: config.schemas(fields, comment, objectType),
68
+ inferType: type ? config.inferType(fields[0].modelName) : ""
69
+ };
70
+ }).flatMap(({ schema, inferType }) => [schema, inferType].filter(Boolean)).join("\n\n");
68
71
  return config.importStatement ? [
69
72
  config.importStatement,
70
73
  "",
@@ -84,10 +84,22 @@ function groupByModel(validFields) {
84
84
  function isFields(modelFields) {
85
85
  return modelFields.flat().filter((field) => field.validation !== null);
86
86
  }
87
- function schemaFromFields(modelFields, comment, schemaBuilder, propertiesGenerator) {
87
+ /**
88
+ * Extract object type (strict/loose) from model documentation.
89
+ */
90
+ function extractObjectType(documentation, prefix) {
91
+ if (!documentation) return void 0;
92
+ const lines = documentation.split("\n").map((l) => l.trim());
93
+ const prefixWithoutAt = prefix.slice(1);
94
+ const match = lines.find((line) => line.includes(`${prefixWithoutAt}strictObject`) || line.includes(`${prefixWithoutAt}looseObject`));
95
+ if (!match) return void 0;
96
+ if (match.includes("strictObject")) return "strict";
97
+ if (match.includes("looseObject")) return "loose";
98
+ }
99
+ function schemaFromFields(modelFields, comment, schemaBuilder, propertiesGenerator, objectType) {
88
100
  const modelName = modelFields[0].modelName;
89
- return schemaBuilder(modelName, propertiesGenerator(modelFields, comment));
101
+ return schemaBuilder(modelName, propertiesGenerator(modelFields, comment), objectType);
90
102
  }
91
103
 
92
104
  //#endregion
93
- export { makeCommentBlock as a, makeValidationExtractor as c, stripAnnotations as d, mkdir as f, isFields as i, parseDocumentWithoutAnnotations as l, writeFileBinary as m, getString as n, makePropertiesGenerator as o, writeFile as p, groupByModel as r, makeSnakeCase as s, getBool as t, schemaFromFields as u };
105
+ export { isFields as a, makeSnakeCase as c, schemaFromFields as d, stripAnnotations as f, writeFileBinary as h, groupByModel as i, makeValidationExtractor as l, writeFile as m, getBool as n, makeCommentBlock as o, mkdir as p, getString as r, makePropertiesGenerator as s, extractObjectType as t, parseDocumentWithoutAnnotations as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hekireki",
3
- "version": "0.7.5",
3
+ "version": "0.7.7",
4
4
  "description": "Hekireki is a tool that generates validation schemas for Zod, Valibot, ArkType, and Effect Schema, as well as ER diagrams and DBML, from Prisma schemas annotated with comments.",
5
5
  "keywords": [
6
6
  "ajv",