drizzle-erd
Version:
Entity-relationship diagram (ERD) generator for Drizzle.
1 lines • 8.17 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/utils/logger.ts","../src/infer.ts","../src/utils/assert.ts","../src/dbml.ts","../src/svg.ts","../src/generate.ts"],"sourcesContent":["export * from \"./generate.js\";\n","export type LogStyle = \"Verbose\" | \"Silent\" | \"Default\";\n\ntype LogData = Record<string, unknown> | Array<Record<string, unknown>> | Error;\n\nclass Logger {\n private logStyle: LogStyle;\n\n constructor(logStyle?: LogStyle) {\n this.logStyle = logStyle ?? \"Default\";\n }\n\n setLogStyle(logStyle: LogStyle) {\n this.logStyle = logStyle;\n }\n\n createOutput(message: string, data?: LogData) {\n const output: [string, LogData?] = [`[drizzle-erd]: ${message}`];\n if (!data) return output;\n\n if (data instanceof Error) {\n output.push(data);\n }\n try {\n output.push(JSON.stringify(data, null, 2));\n } catch (_) {\n output.push(data);\n }\n\n return output;\n }\n\n debug(message: string, data?: LogData): void {\n if (this.logStyle === \"Verbose\") {\n const output = this.createOutput(message, data);\n console.debug(...output);\n }\n }\n\n log(message: string, data?: LogData): void {\n if (this.logStyle !== \"Silent\") {\n const output = this.createOutput(message, data);\n console.debug(...output);\n }\n }\n\n error(message: string, data?: LogData): void {\n if (this.logStyle !== \"Silent\") {\n const output = this.createOutput(message, data);\n console.error(...output);\n }\n }\n}\n\nexport const logger = new Logger(\"Default\");\n","import util from \"util\";\nimport { ProvidedSchema, SchemaVariant } from \"./types.js\";\nimport { assert } from \"./utils/assert.js\";\n\nconst onlyOne = (value: unknown, array: unknown[]) =>\n array.filter((v) => v === value).length === 1;\n\nexport const inferSchemaVariant = (schema: ProvidedSchema): SchemaVariant => {\n const objectDump = util.inspect(schema, { depth: Infinity, getters: true });\n\n const containsPgTable = objectDump.includes(\"PgTable\");\n const containsMySqlTable = objectDump.includes(\"MySqlTable\");\n const containsSQLiteTable = objectDump.includes(\"SQLiteTable\");\n\n const containsResults = [\n containsPgTable,\n containsMySqlTable,\n containsSQLiteTable,\n ];\n\n assert(\n containsResults.some((v) => !!v),\n \"Could not find any tables with a supported type (PG / MySQL / SQLite)\"\n );\n assert(\n onlyOne(true, containsResults),\n \"Seems to contain multiple table types (PG / MySQL / SQLite)\"\n );\n\n if (containsPgTable) return \"Postgres\";\n if (containsMySqlTable) return \"MySQL\";\n if (containsSQLiteTable) return \"SQLite\";\n\n throw new Error(\"Unable to determine schema type (PG / MySQL / SQLite)\");\n};\n","class AssertionError extends Error {\n constructor(message: string) {\n super(message);\n // Add stack info to error.\n // Inspired by: https://blog.dennisokeeffe.com/blog/2020-08-07-error-tracing-with-sentry-and-es6-classes\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, AssertionError);\n } else {\n this.stack = new Error(message).stack;\n }\n this.name = \"AssertionError\";\n }\n}\n\nexport function assert(condition: boolean, message: string): asserts condition {\n if (!condition) {\n throw new AssertionError(message);\n }\n}\n","import {\n mysqlGenerate,\n pgGenerate,\n sqliteGenerate,\n} from \"@rorz/drizzle-dbml-generator\";\nimport { ProvidedSchema, RelationMethod, SchemaVariant } from \"./types.js\";\n\nexport const generateDbml = (\n schema: ProvidedSchema,\n variant: SchemaVariant,\n relationMethod: RelationMethod\n): string => {\n let relational = false; // All other methods default to false\n if (relationMethod === \"Explicit\") relational = true;\n\n switch (variant) {\n case \"Postgres\":\n return pgGenerate({ schema, relational });\n case \"MySQL\":\n return mysqlGenerate({ schema, relational });\n case \"SQLite\":\n return sqliteGenerate({ schema, relational });\n }\n};\n","import { run } from \"@rorz/dbml-renderer\";\n\nexport const generateSvg = (dbml: string): string => {\n const svg = run(dbml, \"svg\");\n return svg;\n};\n","import { logger, LogStyle } from \"./utils/logger.js\";\nimport { ProvidedSchema, RelationMethod } from \"./types.js\";\nimport { inferSchemaVariant } from \"./infer.js\";\nimport { generateDbml } from \"./dbml.js\";\nimport { generateSvg } from \"./svg.js\";\n\ninterface DrizzleErdOpts {\n logStyle?: LogStyle;\n schema: ProvidedSchema;\n relationMethod?: RelationMethod;\n}\n\ninterface DrizzleErdResult {\n dbml: string;\n svg: string;\n}\n\nexport const generateErd = async ({\n schema,\n relationMethod = \"ForeignKey\",\n logStyle = \"Default\",\n}: DrizzleErdOpts): Promise<DrizzleErdResult> => {\n logger.setLogStyle(logStyle);\n\n try {\n const schemaVariant = inferSchemaVariant(schema);\n\n logger.debug(\"⚪️ Generating DBML\");\n const dbml = generateDbml(schema, schemaVariant, relationMethod);\n logger.debug(\"🟢 Generated DBML\");\n\n logger.debug(\"⚪️ Generating SVG\");\n const svg = generateSvg(dbml);\n logger.debug(\"🟢 Generated SVG\");\n\n logger.debug(\"✅ ERD generated successfully\");\n return { dbml, svg };\n } catch (error) {\n logger.error(\n \"🔴 Generating ERD failed with error:\",\n error instanceof Error ? error : { error: \"UNKNOWN\" }\n );\n throw error;\n }\n};\n"],"mappings":"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","names":["util"]}