next-openapi-gen 0.10.5 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +407 -1047
  2. package/dist/cli.d.ts +4 -0
  3. package/dist/cli.js +8599 -0
  4. package/dist/index.d.ts +18 -0
  5. package/dist/index.js +8645 -26
  6. package/dist/next/index.d.ts +1 -0
  7. package/dist/next/index.js +7965 -0
  8. package/dist/react-router/index.d.ts +1 -0
  9. package/dist/react-router/index.js +7134 -0
  10. package/dist/vite/index.d.ts +1 -0
  11. package/dist/vite/index.js +7134 -0
  12. package/package.json +103 -79
  13. package/{dist/components/rapidoc.js → templates/init/ui/nextjs/rapidoc.tsx} +16 -20
  14. package/templates/init/ui/nextjs/redoc.tsx +11 -0
  15. package/{dist/components/scalar.js → templates/init/ui/nextjs/scalar.tsx} +15 -21
  16. package/{dist/components/stoplight.js → templates/init/ui/nextjs/stoplight.tsx} +11 -17
  17. package/templates/init/ui/nextjs/swagger.tsx +17 -0
  18. package/templates/init/ui/reactrouter/rapidoc.tsx +15 -0
  19. package/templates/init/ui/reactrouter/redoc.tsx +9 -0
  20. package/templates/init/ui/reactrouter/scalar.tsx +14 -0
  21. package/templates/init/ui/reactrouter/stoplight.tsx +10 -0
  22. package/templates/init/ui/reactrouter/swagger.tsx +11 -0
  23. package/templates/init/ui/tanstack/rapidoc.tsx +21 -0
  24. package/templates/init/ui/tanstack/redoc.tsx +14 -0
  25. package/templates/init/ui/tanstack/scalar.tsx +19 -0
  26. package/templates/init/ui/tanstack/stoplight.tsx +15 -0
  27. package/templates/init/ui/tanstack/swagger.tsx +16 -0
  28. package/templates/init/ui/template-types.d.ts +9 -0
  29. package/dist/commands/generate.js +0 -24
  30. package/dist/commands/init.js +0 -194
  31. package/dist/components/redoc.js +0 -17
  32. package/dist/components/swagger.js +0 -21
  33. package/dist/lib/app-router-strategy.js +0 -66
  34. package/dist/lib/drizzle-zod-processor.js +0 -329
  35. package/dist/lib/logger.js +0 -39
  36. package/dist/lib/openapi-generator.js +0 -171
  37. package/dist/lib/pages-router-strategy.js +0 -198
  38. package/dist/lib/route-processor.js +0 -349
  39. package/dist/lib/router-strategy.js +0 -1
  40. package/dist/lib/schema-processor.js +0 -1612
  41. package/dist/lib/utils.js +0 -283
  42. package/dist/lib/zod-converter.js +0 -2133
  43. package/dist/openapi-template.js +0 -99
  44. package/dist/types.js +0 -1
@@ -1,194 +0,0 @@
1
- import path from "path";
2
- import fse from "fs-extra";
3
- import fs from "fs";
4
- import ora from "ora";
5
- import { exec } from "child_process";
6
- import util from "util";
7
- import openapiTemplate from "../openapi-template.js";
8
- import { scalarDeps, scalarDevDeps, ScalarUI } from "../components/scalar.js";
9
- import { swaggerDeps, swaggerDevDeps, SwaggerUI } from "../components/swagger.js";
10
- import { redocDeps, redocDevDeps, RedocUI } from "../components/redoc.js";
11
- import { stoplightDeps, stoplightDevDeps, StoplightUI } from "../components/stoplight.js";
12
- import { rapidocDeps, rapidocDevDeps, RapidocUI } from "../components/rapidoc.js";
13
- const execPromise = util.promisify(exec);
14
- const spinner = ora("Initializing project with OpenAPI template...\n");
15
- async function hasDependency(packageName) {
16
- try {
17
- const packageJsonPath = path.join(process.cwd(), "package.json");
18
- const packageJson = await fse.readJson(packageJsonPath);
19
- return !!(packageJson.dependencies?.[packageName] || packageJson.devDependencies?.[packageName]);
20
- }
21
- catch {
22
- return false;
23
- }
24
- }
25
- const getPackageManager = async () => {
26
- let currentDir = process.cwd();
27
- while (true) {
28
- // Check for Yarn lock file
29
- if (fs.existsSync(path.join(currentDir, "yarn.lock"))) {
30
- return "yarn";
31
- }
32
- // Check for PNPM lock file
33
- if (fs.existsSync(path.join(currentDir, "pnpm-lock.yaml"))) {
34
- return "pnpm";
35
- }
36
- // If we're at the root directory, break the loop
37
- const parentDir = path.dirname(currentDir);
38
- if (parentDir === currentDir) {
39
- break; // We've reached the root
40
- }
41
- currentDir = parentDir; // Move up one directory
42
- }
43
- // Default to npm if no lock files are found
44
- return "npm";
45
- };
46
- function getDocsPage(ui, outputFile) {
47
- let DocsComponent = ScalarUI;
48
- if (ui === "swagger") {
49
- DocsComponent = SwaggerUI;
50
- }
51
- else if (ui === "redoc") {
52
- DocsComponent = RedocUI;
53
- }
54
- else if (ui === "stoplight") {
55
- DocsComponent = StoplightUI;
56
- }
57
- else if (ui === "rapidoc") {
58
- DocsComponent = RapidocUI;
59
- }
60
- return DocsComponent(outputFile);
61
- }
62
- function getDocsPageInstallFlags(ui, packageManager) {
63
- let installFlags = "";
64
- if (ui === "swagger") {
65
- // @temp: swagger-ui-react does not support React 19 now.
66
- if (packageManager === "pnpm") {
67
- installFlags = "--no-strict-peer-dependencies";
68
- }
69
- else if (packageManager === "yarn") {
70
- installFlags = ""; // flag for legacy peer deps is not needed for yarn
71
- }
72
- else {
73
- installFlags = "--legacy-peer-deps";
74
- }
75
- }
76
- return installFlags;
77
- }
78
- function getDocsPageDependencies(ui) {
79
- let deps = [];
80
- if (ui === "scalar") {
81
- deps = scalarDeps;
82
- }
83
- else if (ui === "swagger") {
84
- deps = swaggerDeps;
85
- }
86
- else if (ui === "redoc") {
87
- deps = redocDeps;
88
- }
89
- else if (ui === "stoplight") {
90
- deps = stoplightDeps;
91
- }
92
- else if (ui === "rapidoc") {
93
- deps = rapidocDeps;
94
- }
95
- return deps.join(" ");
96
- }
97
- function getDocsPageDevDependencies(ui) {
98
- let devDeps = [];
99
- if (ui === "scalar") {
100
- devDeps = scalarDevDeps;
101
- }
102
- else if (ui === "swagger") {
103
- devDeps = swaggerDevDeps;
104
- }
105
- else if (ui === "redoc") {
106
- devDeps = redocDevDeps;
107
- }
108
- else if (ui === "stoplight") {
109
- devDeps = stoplightDevDeps;
110
- }
111
- else if (ui === "rapidoc") {
112
- devDeps = rapidocDevDeps;
113
- }
114
- return devDeps.join(" ");
115
- }
116
- async function createDocsPage(ui, outputFile) {
117
- if (ui === "none") {
118
- return;
119
- }
120
- const paths = ["app", "api-docs"];
121
- const srcPath = path.join(process.cwd(), "src");
122
- if (fs.existsSync(srcPath)) {
123
- paths.unshift("src");
124
- }
125
- const docsDir = path.join(process.cwd(), ...paths);
126
- await fs.promises.mkdir(docsDir, { recursive: true });
127
- const docsPage = getDocsPage(ui, outputFile);
128
- const componentPath = path.join(docsDir, "page.tsx");
129
- await fs.promises.writeFile(componentPath, docsPage.trim());
130
- spinner.succeed(`Created ${paths.join("/")}/page.tsx for ${ui}.`);
131
- }
132
- async function installDependencies(ui, schema) {
133
- const packageManager = await getPackageManager();
134
- const installCmd = `${packageManager} ${packageManager === "npm" ? "install" : "add"}`;
135
- // Install UI dependencies
136
- if (ui !== "none") {
137
- const deps = getDocsPageDependencies(ui);
138
- const devDeps = getDocsPageDevDependencies(ui);
139
- const flags = getDocsPageInstallFlags(ui, packageManager);
140
- if (deps) {
141
- spinner.succeed(`Installing ${deps} dependencies...`);
142
- await execPromise(`${installCmd} ${deps} ${flags}`);
143
- spinner.succeed(`Successfully installed ${deps}.`);
144
- }
145
- if (devDeps) {
146
- const devFlag = packageManager === "npm" ? "--save-dev" : "-D";
147
- spinner.succeed(`Installing ${devDeps} dev dependencies...`);
148
- await execPromise(`${installCmd} ${devFlag} ${devDeps} ${flags}`);
149
- spinner.succeed(`Successfully installed ${devDeps}.`);
150
- }
151
- }
152
- // Install schema dependencies
153
- const schemaTypes = Array.isArray(schema) ? schema : [schema];
154
- for (const schemaType of schemaTypes) {
155
- if (schemaType === "zod" && !(await hasDependency("zod"))) {
156
- spinner.succeed(`Installing zod...`);
157
- await execPromise(`${installCmd} zod`);
158
- spinner.succeed(`Successfully installed zod.`);
159
- }
160
- else if (schemaType === "typescript" && !(await hasDependency("typescript"))) {
161
- const devFlag = packageManager === "npm" ? "--save-dev" : "-D";
162
- spinner.succeed(`Installing typescript...`);
163
- await execPromise(`${installCmd} ${devFlag} typescript`);
164
- spinner.succeed(`Successfully installed typescript.`);
165
- }
166
- }
167
- }
168
- function extendOpenApiTemplate(spec, options) {
169
- spec.ui = options.ui ?? spec.ui;
170
- spec.docsUrl = options.docsUrl ?? spec.docsUrl;
171
- spec.schemaType = options.schema ?? spec.schemaType;
172
- }
173
- function getOutputPath(output) {
174
- if (output) {
175
- return path.isAbsolute(output) ? output : path.join(process.cwd(), output);
176
- }
177
- return path.join(process.cwd(), "next.openapi.json");
178
- }
179
- export async function init(options) {
180
- const { ui, output, schema } = options;
181
- spinner.start();
182
- try {
183
- const outputPath = getOutputPath(output);
184
- const template = { ...openapiTemplate };
185
- extendOpenApiTemplate(template, options);
186
- await fse.writeJson(outputPath, template, { spaces: 2 });
187
- spinner.succeed(`Created OpenAPI template in ${outputPath}`);
188
- createDocsPage(ui, template.outputFile);
189
- installDependencies(ui, schema);
190
- }
191
- catch (error) {
192
- spinner.fail(`Failed to initialize project: ${error.message}`);
193
- }
194
- }
@@ -1,17 +0,0 @@
1
- export const redocDeps = ["redoc"];
2
- export const redocDevDeps = [];
3
- export function RedocUI(outputFile) {
4
- return `
5
- "use client";
6
-
7
- import { RedocStandalone } from "redoc";
8
-
9
- export default async function ApiDocsPage() {
10
- return (
11
- <section>
12
- <RedocStandalone specUrl="/${outputFile}" />
13
- </section>
14
- );
15
- }
16
- `;
17
- }
@@ -1,21 +0,0 @@
1
- export const swaggerDeps = ["swagger-ui", "swagger-ui-react"];
2
- export const swaggerDevDeps = ["@types/swagger-ui-react"];
3
- export function SwaggerUI(outputFile) {
4
- return `
5
- import "swagger-ui-react/swagger-ui.css";
6
-
7
- import dynamic from "next/dynamic";
8
-
9
- const SwaggerUI = dynamic(() => import("swagger-ui-react"), {
10
- loading: () => <p>Loading Component...</p>,
11
- });
12
-
13
- export default async function ApiDocsPage() {
14
- return (
15
- <section>
16
- <SwaggerUI url="/${outputFile}" />
17
- </section>
18
- );
19
- }
20
- `;
21
- }
@@ -1,66 +0,0 @@
1
- import * as t from "@babel/types";
2
- import fs from "fs";
3
- import traverseModule from "@babel/traverse";
4
- const traverse = traverseModule.default || traverseModule;
5
- import { HTTP_METHODS } from "./router-strategy.js";
6
- import { extractJSDocComments, parseTypeScriptFile } from "./utils.js";
7
- export class AppRouterStrategy {
8
- config;
9
- constructor(config) {
10
- this.config = config;
11
- }
12
- shouldProcessFile(fileName) {
13
- return fileName === "route.ts" || fileName === "route.tsx";
14
- }
15
- processFile(filePath, addRoute) {
16
- const content = fs.readFileSync(filePath, "utf-8");
17
- const ast = parseTypeScriptFile(content);
18
- traverse(ast, {
19
- ExportNamedDeclaration: (path) => {
20
- const declaration = path.node.declaration;
21
- if (t.isFunctionDeclaration(declaration) &&
22
- t.isIdentifier(declaration.id)) {
23
- if (HTTP_METHODS.includes(declaration.id.name)) {
24
- const dataTypes = extractJSDocComments(path);
25
- addRoute(declaration.id.name, filePath, dataTypes);
26
- }
27
- }
28
- if (t.isVariableDeclaration(declaration)) {
29
- declaration.declarations.forEach((decl) => {
30
- if (t.isVariableDeclarator(decl) && t.isIdentifier(decl.id)) {
31
- if (HTTP_METHODS.includes(decl.id.name)) {
32
- const dataTypes = extractJSDocComments(path);
33
- addRoute(decl.id.name, filePath, dataTypes);
34
- }
35
- }
36
- });
37
- }
38
- },
39
- });
40
- }
41
- getRoutePath(filePath) {
42
- const normalizedPath = filePath.replaceAll("\\", "/");
43
- const normalizedApiDir = this.config.apiDir
44
- .replaceAll("\\", "/")
45
- .replace(/^\.\//, "")
46
- .replace(/\/$/, "");
47
- const apiDirIndex = normalizedPath.indexOf(normalizedApiDir);
48
- if (apiDirIndex === -1) {
49
- throw new Error(`Could not find apiDir "${this.config.apiDir}" in file path "${filePath}"`);
50
- }
51
- let relativePath = normalizedPath.substring(apiDirIndex + normalizedApiDir.length);
52
- // Remove the /route.ts or /route.tsx suffix
53
- relativePath = relativePath.replace(/\/route\.tsx?$/, "");
54
- if (!relativePath.startsWith("/")) {
55
- relativePath = "/" + relativePath;
56
- }
57
- relativePath = relativePath.replace(/\/$/, "");
58
- // Remove Next.js route groups (folders in parentheses like (authenticated))
59
- relativePath = relativePath.replace(/\/\([^)]+\)/g, "");
60
- // Handle catch-all routes before dynamic routes
61
- relativePath = relativePath.replace(/\/\[\.\.\.(.*?)\]/g, "/{$1}");
62
- // Convert Next.js dynamic route syntax to OpenAPI parameter syntax
63
- relativePath = relativePath.replace(/\/\[([^\]]+)\]/g, "/{$1}");
64
- return relativePath || "/";
65
- }
66
- }
@@ -1,329 +0,0 @@
1
- import * as t from "@babel/types";
2
- import { logger } from "./logger.js";
3
- /**
4
- * Processor for drizzle-zod schemas
5
- *
6
- * Drizzle-zod is a library that generates Zod schemas from Drizzle ORM table definitions.
7
- * It provides helper functions like:
8
- * - createInsertSchema(tableDefinition, refinements)
9
- * - createSelectSchema(tableDefinition, refinements)
10
- *
11
- * This processor extracts field definitions and refinements to generate OpenAPI schemas.
12
- */
13
- export class DrizzleZodProcessor {
14
- /**
15
- * Known drizzle-zod helper function names
16
- */
17
- static DRIZZLE_ZOD_HELPERS = [
18
- "createInsertSchema",
19
- "createSelectSchema",
20
- "createUpdateSchema",
21
- ];
22
- /**
23
- * Process a drizzle-zod schema node
24
- *
25
- * @param node - The CallExpression node representing a drizzle-zod function call
26
- * @returns OpenAPI schema object
27
- */
28
- static processSchema(node) {
29
- const functionName = t.isIdentifier(node.callee)
30
- ? node.callee.name
31
- : "unknown";
32
- logger.debug(`Processing drizzle-zod schema: ${functionName}`);
33
- const schema = {
34
- type: "object",
35
- properties: {},
36
- required: [],
37
- };
38
- // Check if there's a refinements object (second argument)
39
- if (node.arguments.length > 1 && t.isObjectExpression(node.arguments[1])) {
40
- const refinements = node.arguments[1];
41
- // Process each property in the refinements object
42
- refinements.properties.forEach((prop) => {
43
- if (t.isObjectProperty(prop) || t.isObjectMethod(prop)) {
44
- const key = this.extractPropertyKey(prop);
45
- if (!key)
46
- return;
47
- // The value is typically an arrow function: (schema) => schema.field.method()
48
- if (t.isObjectProperty(prop) &&
49
- t.isArrowFunctionExpression(prop.value)) {
50
- const arrowFunc = prop.value;
51
- const fieldSchema = this.extractFieldSchema(arrowFunc.body);
52
- if (fieldSchema) {
53
- schema.properties[key] = fieldSchema;
54
- // Determine if field is required based on schema modifiers
55
- if (!this.isFieldOptional(arrowFunc.body)) {
56
- schema.required.push(key);
57
- }
58
- }
59
- }
60
- }
61
- });
62
- }
63
- // If no properties were extracted, return a generic object schema
64
- if (Object.keys(schema.properties).length === 0) {
65
- logger.debug("No properties extracted from drizzle-zod schema, returning generic object");
66
- return { type: "object" };
67
- }
68
- return schema;
69
- }
70
- /**
71
- * Extract property key from object property or method
72
- */
73
- static extractPropertyKey(prop) {
74
- if (t.isIdentifier(prop.key)) {
75
- return prop.key.name;
76
- }
77
- if (t.isStringLiteral(prop.key)) {
78
- return prop.key.value;
79
- }
80
- return null;
81
- }
82
- /**
83
- * Extract OpenAPI schema from a drizzle-zod field refinement
84
- *
85
- * Handles patterns like:
86
- * - schema.field
87
- * - schema.field.min(1)
88
- * - schema.field.min(1).max(100).email()
89
- */
90
- static extractFieldSchema(node) {
91
- // Handle member expressions like: schema.field
92
- if (t.isMemberExpression(node)) {
93
- if (t.isIdentifier(node.property)) {
94
- const fieldType = node.property.name;
95
- return this.mapFieldTypeToOpenApi(fieldType);
96
- }
97
- }
98
- // Handle call expressions (chained methods like schema.field.min(1).max(100))
99
- if (t.isCallExpression(node)) {
100
- const baseSchema = this.extractFieldSchema(t.isMemberExpression(node.callee) ? node.callee.object : node);
101
- if (baseSchema && t.isMemberExpression(node.callee)) {
102
- const methodName = t.isIdentifier(node.callee.property)
103
- ? node.callee.property.name
104
- : null;
105
- if (methodName) {
106
- return this.applyZodMethod(baseSchema, methodName, node.arguments);
107
- }
108
- }
109
- return baseSchema;
110
- }
111
- return null;
112
- }
113
- /**
114
- * Check if a drizzle-zod field is optional
115
- */
116
- static isFieldOptional(node) {
117
- if (t.isCallExpression(node) && t.isMemberExpression(node.callee)) {
118
- const methodName = t.isIdentifier(node.callee.property)
119
- ? node.callee.property.name
120
- : null;
121
- if (methodName === "optional" ||
122
- methodName === "nullish") {
123
- return true;
124
- }
125
- // Check parent chain recursively
126
- return this.isFieldOptional(node.callee.object);
127
- }
128
- return false;
129
- }
130
- /**
131
- * Map Drizzle field types to OpenAPI types
132
- *
133
- * This provides intelligent mapping based on common field naming patterns.
134
- * For more accurate type detection, the drizzle table schema would need to be analyzed.
135
- */
136
- static mapFieldTypeToOpenApi(fieldType) {
137
- // Common mappings based on field naming conventions
138
- const lowercaseField = fieldType.toLowerCase();
139
- // String types
140
- if (lowercaseField.includes("title") ||
141
- lowercaseField.includes("name") ||
142
- lowercaseField.includes("description") ||
143
- lowercaseField.includes("content") ||
144
- lowercaseField.includes("text") ||
145
- lowercaseField.includes("slug") ||
146
- lowercaseField.includes("email") ||
147
- lowercaseField.includes("url") ||
148
- lowercaseField.includes("phone")) {
149
- const schema = { type: "string" };
150
- // Add format hints
151
- if (lowercaseField.includes("email")) {
152
- schema.format = "email";
153
- }
154
- else if (lowercaseField.includes("url") ||
155
- lowercaseField.includes("uri")) {
156
- schema.format = "uri";
157
- }
158
- else if (lowercaseField.includes("uuid")) {
159
- schema.format = "uuid";
160
- }
161
- return schema;
162
- }
163
- // Integer types
164
- if (lowercaseField.includes("id") ||
165
- lowercaseField.includes("count") ||
166
- lowercaseField.includes("stock") ||
167
- lowercaseField.includes("quantity") ||
168
- lowercaseField.includes("age") ||
169
- lowercaseField.includes("year")) {
170
- return { type: "integer" };
171
- }
172
- // Number types
173
- if (lowercaseField.includes("price") ||
174
- lowercaseField.includes("amount") ||
175
- lowercaseField.includes("rate") ||
176
- lowercaseField.includes("percent")) {
177
- return { type: "number" };
178
- }
179
- // Boolean types
180
- if (lowercaseField.startsWith("is") ||
181
- lowercaseField.startsWith("has") ||
182
- lowercaseField.includes("active") ||
183
- lowercaseField.includes("enabled") ||
184
- lowercaseField.includes("published")) {
185
- return { type: "boolean" };
186
- }
187
- // Date/time types
188
- if (lowercaseField.includes("date") ||
189
- lowercaseField.includes("time") ||
190
- lowercaseField.includes("createdat") ||
191
- lowercaseField.includes("updatedat") ||
192
- lowercaseField.includes("deletedat")) {
193
- return { type: "string", format: "date-time" };
194
- }
195
- // Default to string for unknown types
196
- return { type: "string" };
197
- }
198
- /**
199
- * Apply a Zod validation method to a schema
200
- *
201
- * Translates Zod validation methods to OpenAPI constraints:
202
- * - min/max for strings become minLength/maxLength
203
- * - min/max for numbers become minimum/maximum
204
- * - email/url/uuid become format constraints
205
- */
206
- static applyZodMethod(schema, methodName, args) {
207
- const result = { ...schema };
208
- switch (methodName) {
209
- case "min":
210
- if (args.length > 0 && t.isNumericLiteral(args[0])) {
211
- if (schema.type === "string") {
212
- result.minLength = args[0].value;
213
- }
214
- else if (schema.type === "number" || schema.type === "integer") {
215
- result.minimum = args[0].value;
216
- }
217
- else if (schema.type === "array") {
218
- result.minItems = args[0].value;
219
- }
220
- }
221
- break;
222
- case "max":
223
- if (args.length > 0 && t.isNumericLiteral(args[0])) {
224
- if (schema.type === "string") {
225
- result.maxLength = args[0].value;
226
- }
227
- else if (schema.type === "number" || schema.type === "integer") {
228
- result.maximum = args[0].value;
229
- }
230
- else if (schema.type === "array") {
231
- result.maxItems = args[0].value;
232
- }
233
- }
234
- break;
235
- case "length":
236
- if (args.length > 0 && t.isNumericLiteral(args[0])) {
237
- if (schema.type === "string") {
238
- result.minLength = args[0].value;
239
- result.maxLength = args[0].value;
240
- }
241
- else if (schema.type === "array") {
242
- result.minItems = args[0].value;
243
- result.maxItems = args[0].value;
244
- }
245
- }
246
- break;
247
- case "email":
248
- result.format = "email";
249
- break;
250
- case "url":
251
- result.format = "uri";
252
- break;
253
- case "uuid":
254
- result.format = "uuid";
255
- break;
256
- case "datetime":
257
- result.format = "date-time";
258
- break;
259
- case "regex":
260
- if (args.length > 0) {
261
- // Try to extract pattern from regex literal
262
- if (t.isRegExpLiteral(args[0])) {
263
- result.pattern = args[0].pattern;
264
- }
265
- }
266
- break;
267
- case "positive":
268
- if (schema.type === "number" || schema.type === "integer") {
269
- result.minimum = 0;
270
- result.exclusiveMinimum = true;
271
- }
272
- break;
273
- case "nonnegative":
274
- if (schema.type === "number" || schema.type === "integer") {
275
- result.minimum = 0;
276
- }
277
- break;
278
- case "negative":
279
- if (schema.type === "number" || schema.type === "integer") {
280
- result.maximum = 0;
281
- result.exclusiveMaximum = true;
282
- }
283
- break;
284
- case "nonpositive":
285
- if (schema.type === "number" || schema.type === "integer") {
286
- result.maximum = 0;
287
- }
288
- break;
289
- case "int":
290
- result.type = "integer";
291
- break;
292
- case "optional":
293
- // Handled by isFieldOptional check, no schema modification needed
294
- break;
295
- case "nullable":
296
- result.nullable = true;
297
- break;
298
- case "nullish":
299
- result.nullable = true;
300
- break;
301
- case "describe":
302
- if (args.length > 0 && t.isStringLiteral(args[0])) {
303
- result.description = args[0].value;
304
- }
305
- break;
306
- case "default":
307
- if (args.length > 0) {
308
- // Extract default value
309
- if (t.isStringLiteral(args[0])) {
310
- result.default = args[0].value;
311
- }
312
- else if (t.isNumericLiteral(args[0])) {
313
- result.default = args[0].value;
314
- }
315
- else if (t.isBooleanLiteral(args[0])) {
316
- result.default = args[0].value;
317
- }
318
- }
319
- break;
320
- }
321
- return result;
322
- }
323
- /**
324
- * Check if a function name is a drizzle-zod helper
325
- */
326
- static isDrizzleZodHelper(name) {
327
- return this.DRIZZLE_ZOD_HELPERS.includes(name);
328
- }
329
- }
@@ -1,39 +0,0 @@
1
- class Logger {
2
- config = null;
3
- init(config) {
4
- this.config = config;
5
- }
6
- getCallerInfo() {
7
- const stack = new Error().stack;
8
- if (!stack)
9
- return 'Unknown';
10
- const lines = stack.split('\n');
11
- // Skip: Error, getCallerInfo, log/warn/error
12
- const callerLine = lines[3] || lines[2];
13
- // Extract class/function name
14
- const match = callerLine.match(/at (\w+)\.(\w+)|at (\w+)/);
15
- if (match) {
16
- return match[1] || match[3] || 'Unknown';
17
- }
18
- return 'Unknown';
19
- }
20
- log(message, ...args) {
21
- const source = this.getCallerInfo();
22
- console.log(`[${source}] ${message}`, ...args);
23
- }
24
- warn(message, ...args) {
25
- const source = this.getCallerInfo();
26
- console.warn(`[${source}] ${message}`, ...args);
27
- }
28
- error(message, ...args) {
29
- const source = this.getCallerInfo();
30
- console.error(`[${source}] ${message}`, ...args);
31
- }
32
- debug(message, ...args) {
33
- if (this.config?.debug) {
34
- const source = this.getCallerInfo();
35
- console.log(`[${source}] ${message}`, ...args);
36
- }
37
- }
38
- }
39
- export const logger = new Logger();