drizzle-docs-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 +21 -0
- package/README.ja.md +89 -0
- package/README.md +89 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +69 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/generator/common.d.ts +393 -0
- package/dist/generator/common.d.ts.map +1 -0
- package/dist/generator/common.js +699 -0
- package/dist/generator/common.js.map +1 -0
- package/dist/generator/index.d.ts +15 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/mysql.d.ts +36 -0
- package/dist/generator/mysql.d.ts.map +1 -0
- package/dist/generator/mysql.js +16 -0
- package/dist/generator/mysql.js.map +1 -0
- package/dist/generator/pg.d.ts +48 -0
- package/dist/generator/pg.d.ts.map +1 -0
- package/dist/generator/pg.js +52 -0
- package/dist/generator/pg.js.map +1 -0
- package/dist/generator/sqlite.d.ts +36 -0
- package/dist/generator/sqlite.d.ts.map +1 -0
- package/dist/generator/sqlite.js +16 -0
- package/dist/generator/sqlite.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/comments.d.ts +31 -0
- package/dist/parser/comments.d.ts.map +1 -0
- package/dist/parser/comments.js +113 -0
- package/dist/parser/comments.js.map +1 -0
- package/dist/parser/index.d.ts +5 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/relations.d.ts +34 -0
- package/dist/parser/relations.d.ts.map +1 -0
- package/dist/parser/relations.js +111 -0
- package/dist/parser/relations.js.map +1 -0
- package/dist/test-utils/cli-runner.d.ts +35 -0
- package/dist/test-utils/cli-runner.d.ts.map +1 -0
- package/dist/test-utils/dbml-validator.d.ts +70 -0
- package/dist/test-utils/dbml-validator.d.ts.map +1 -0
- package/dist/test-utils/index.d.ts +7 -0
- package/dist/test-utils/index.d.ts.map +1 -0
- package/dist/types.d.ts +53 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { extractComments } from './comments';
|
|
2
|
+
export type { SchemaComments, TableComment, ColumnComment } from './comments';
|
|
3
|
+
export { extractRelations } from './relations';
|
|
4
|
+
export type { ParsedRelation, SchemaRelations } from './relations';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsed relation from relations() definition
|
|
3
|
+
*/
|
|
4
|
+
export interface ParsedRelation {
|
|
5
|
+
/** Name of the source table (the first argument of relations()) */
|
|
6
|
+
sourceTable: string;
|
|
7
|
+
/** Name of the target table (the first argument of one()/many()) */
|
|
8
|
+
targetTable: string;
|
|
9
|
+
/** Relation type: "one" or "many" */
|
|
10
|
+
type: "one" | "many";
|
|
11
|
+
/** Source column names (from fields array) */
|
|
12
|
+
fields: string[];
|
|
13
|
+
/** Target column names (from references array) */
|
|
14
|
+
references: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* All extracted relations from a schema file
|
|
18
|
+
*/
|
|
19
|
+
export interface SchemaRelations {
|
|
20
|
+
relations: ParsedRelation[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Extract relations from a Drizzle schema source file or directory using AST parsing
|
|
24
|
+
*
|
|
25
|
+
* Parses TypeScript source files and extracts:
|
|
26
|
+
* - relations() function calls
|
|
27
|
+
* - one() and many() relation definitions within them
|
|
28
|
+
* - fields and references arrays for generating DBML Refs
|
|
29
|
+
*
|
|
30
|
+
* @param sourcePath - Path to the TypeScript schema file or directory
|
|
31
|
+
* @returns Extracted relations
|
|
32
|
+
*/
|
|
33
|
+
export declare function extractRelations(sourcePath: string): SchemaRelations;
|
|
34
|
+
//# sourceMappingURL=relations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../../src/parser/relations.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB,qCAAqC;IACrC,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;IACrB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,kDAAkD;IAClD,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,cAAc,EAAE,CAAC;CAC7B;AA+BD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,CAapE"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import * as r from "typescript";
|
|
2
|
+
import { readFileSync as h, statSync as A, readdirSync as b } from "node:fs";
|
|
3
|
+
import { join as F } from "node:path";
|
|
4
|
+
function d(e) {
|
|
5
|
+
const s = A(e);
|
|
6
|
+
if (s.isFile())
|
|
7
|
+
return e.endsWith(".ts") ? [e] : [];
|
|
8
|
+
if (s.isDirectory()) {
|
|
9
|
+
const n = [], i = b(e, { withFileTypes: !0 });
|
|
10
|
+
for (const t of i) {
|
|
11
|
+
const o = F(e, t.name);
|
|
12
|
+
t.isDirectory() ? n.push(...d(o)) : t.isFile() && t.name.endsWith(".ts") && !t.name.endsWith(".test.ts") && n.push(o);
|
|
13
|
+
}
|
|
14
|
+
return n;
|
|
15
|
+
}
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
function S(e) {
|
|
19
|
+
const s = { relations: [] }, n = d(e);
|
|
20
|
+
for (const i of n) {
|
|
21
|
+
const t = h(i, "utf-8"), o = r.createSourceFile(i, t, r.ScriptTarget.Latest, !0);
|
|
22
|
+
x(o, o, s);
|
|
23
|
+
}
|
|
24
|
+
return s;
|
|
25
|
+
}
|
|
26
|
+
function x(e, s, n) {
|
|
27
|
+
if (r.isVariableStatement(e)) {
|
|
28
|
+
for (const i of e.declarationList.declarations)
|
|
29
|
+
if (i.initializer && r.isCallExpression(i.initializer)) {
|
|
30
|
+
const t = p(i.initializer);
|
|
31
|
+
t && n.relations.push(...t);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (r.isExportAssignment(e) && r.isCallExpression(e.expression)) {
|
|
35
|
+
const i = p(e.expression);
|
|
36
|
+
i && n.relations.push(...i);
|
|
37
|
+
}
|
|
38
|
+
r.forEachChild(e, (i) => x(i, s, n));
|
|
39
|
+
}
|
|
40
|
+
function p(e, s) {
|
|
41
|
+
if (y(e) !== "relations")
|
|
42
|
+
return;
|
|
43
|
+
const i = e.arguments[0];
|
|
44
|
+
if (!i)
|
|
45
|
+
return;
|
|
46
|
+
const t = g(i);
|
|
47
|
+
if (!t)
|
|
48
|
+
return;
|
|
49
|
+
const o = e.arguments[1];
|
|
50
|
+
if (!(!o || !r.isArrowFunction(o)))
|
|
51
|
+
return v(t, o);
|
|
52
|
+
}
|
|
53
|
+
function v(e, s, n) {
|
|
54
|
+
const i = [];
|
|
55
|
+
let t = s.body;
|
|
56
|
+
if (r.isParenthesizedExpression(t) && (t = t.expression), !r.isObjectLiteralExpression(t))
|
|
57
|
+
return i;
|
|
58
|
+
for (const o of t.properties)
|
|
59
|
+
if (r.isPropertyAssignment(o) && r.isCallExpression(o.initializer)) {
|
|
60
|
+
const f = z(e, o.initializer);
|
|
61
|
+
f && i.push(f);
|
|
62
|
+
}
|
|
63
|
+
return i;
|
|
64
|
+
}
|
|
65
|
+
function z(e, s, n) {
|
|
66
|
+
const i = y(s);
|
|
67
|
+
if (i !== "one" && i !== "many")
|
|
68
|
+
return;
|
|
69
|
+
const t = s.arguments[0];
|
|
70
|
+
if (!t)
|
|
71
|
+
return;
|
|
72
|
+
const o = g(t);
|
|
73
|
+
if (!o)
|
|
74
|
+
return;
|
|
75
|
+
const f = s.arguments[1];
|
|
76
|
+
let c = [], l = [];
|
|
77
|
+
if (f && r.isObjectLiteralExpression(f)) {
|
|
78
|
+
for (const a of f.properties)
|
|
79
|
+
if (r.isPropertyAssignment(a) && r.isIdentifier(a.name)) {
|
|
80
|
+
const u = a.name.text;
|
|
81
|
+
u === "fields" && r.isArrayLiteralExpression(a.initializer) ? c = m(a.initializer) : u === "references" && r.isArrayLiteralExpression(a.initializer) && (l = m(a.initializer));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
sourceTable: e,
|
|
86
|
+
targetTable: o,
|
|
87
|
+
type: i,
|
|
88
|
+
fields: c,
|
|
89
|
+
references: l
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function m(e) {
|
|
93
|
+
const s = [];
|
|
94
|
+
for (const n of e.elements)
|
|
95
|
+
r.isPropertyAccessExpression(n) ? s.push(n.name.text) : r.isIdentifier(n) && s.push(n.text);
|
|
96
|
+
return s;
|
|
97
|
+
}
|
|
98
|
+
function y(e) {
|
|
99
|
+
if (r.isIdentifier(e.expression))
|
|
100
|
+
return e.expression.text;
|
|
101
|
+
if (r.isPropertyAccessExpression(e.expression))
|
|
102
|
+
return e.expression.name.text;
|
|
103
|
+
}
|
|
104
|
+
function g(e) {
|
|
105
|
+
if (r.isIdentifier(e))
|
|
106
|
+
return e.text;
|
|
107
|
+
}
|
|
108
|
+
export {
|
|
109
|
+
S as extractRelations
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=relations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relations.js","sources":["../../src/parser/relations.ts"],"sourcesContent":["import * as ts from \"typescript\";\nimport { readFileSync, statSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/**\n * Parsed relation from relations() definition\n */\nexport interface ParsedRelation {\n /** Name of the source table (the first argument of relations()) */\n sourceTable: string;\n /** Name of the target table (the first argument of one()/many()) */\n targetTable: string;\n /** Relation type: \"one\" or \"many\" */\n type: \"one\" | \"many\";\n /** Source column names (from fields array) */\n fields: string[];\n /** Target column names (from references array) */\n references: string[];\n}\n\n/**\n * All extracted relations from a schema file\n */\nexport interface SchemaRelations {\n relations: ParsedRelation[];\n}\n\n/**\n * Get all TypeScript files from a path (file or directory)\n */\nfunction getTypeScriptFiles(sourcePath: string): string[] {\n const stat = statSync(sourcePath);\n\n if (stat.isFile()) {\n return sourcePath.endsWith(\".ts\") ? [sourcePath] : [];\n }\n\n if (stat.isDirectory()) {\n const files: string[] = [];\n const entries = readdirSync(sourcePath, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(sourcePath, entry.name);\n if (entry.isDirectory()) {\n files.push(...getTypeScriptFiles(fullPath));\n } else if (entry.isFile() && entry.name.endsWith(\".ts\") && !entry.name.endsWith(\".test.ts\")) {\n files.push(fullPath);\n }\n }\n\n return files;\n }\n\n return [];\n}\n\n/**\n * Extract relations from a Drizzle schema source file or directory using AST parsing\n *\n * Parses TypeScript source files and extracts:\n * - relations() function calls\n * - one() and many() relation definitions within them\n * - fields and references arrays for generating DBML Refs\n *\n * @param sourcePath - Path to the TypeScript schema file or directory\n * @returns Extracted relations\n */\nexport function extractRelations(sourcePath: string): SchemaRelations {\n const result: SchemaRelations = { relations: [] };\n const files = getTypeScriptFiles(sourcePath);\n\n for (const filePath of files) {\n const sourceCode = readFileSync(filePath, \"utf-8\");\n const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true);\n\n // Visit all nodes to find relations() calls\n visitNode(sourceFile, sourceFile, result);\n }\n\n return result;\n}\n\n/**\n * Recursively visit AST nodes to find relations() definitions\n */\nfunction visitNode(node: ts.Node, sourceFile: ts.SourceFile, result: SchemaRelations): void {\n // Look for variable declarations that define relations\n if (ts.isVariableStatement(node)) {\n for (const declaration of node.declarationList.declarations) {\n if (declaration.initializer && ts.isCallExpression(declaration.initializer)) {\n const parsedRelations = parseRelationsDefinition(declaration.initializer, sourceFile);\n if (parsedRelations) {\n result.relations.push(...parsedRelations);\n }\n }\n }\n }\n\n // Also check for direct call expressions (e.g., export const x = relations(...))\n if (ts.isExportAssignment(node) && ts.isCallExpression(node.expression)) {\n const parsedRelations = parseRelationsDefinition(node.expression, sourceFile);\n if (parsedRelations) {\n result.relations.push(...parsedRelations);\n }\n }\n\n ts.forEachChild(node, (child) => visitNode(child, sourceFile, result));\n}\n\n/**\n * Parse a relations() call expression\n *\n * Example:\n * relations(posts, ({ one }) => ({\n * author: one(users, {\n * fields: [posts.authorId],\n * references: [users.id],\n * }),\n * }))\n */\nfunction parseRelationsDefinition(\n callExpr: ts.CallExpression,\n sourceFile: ts.SourceFile,\n): ParsedRelation[] | undefined {\n const funcName = getCallExpressionName(callExpr);\n\n if (funcName !== \"relations\") {\n return undefined;\n }\n\n // Get source table from first argument\n const sourceTableArg = callExpr.arguments[0];\n if (!sourceTableArg) {\n return undefined;\n }\n const sourceTable = extractIdentifierName(sourceTableArg);\n if (!sourceTable) {\n return undefined;\n }\n\n // Get the callback function (second argument)\n const callbackArg = callExpr.arguments[1];\n if (!callbackArg || !ts.isArrowFunction(callbackArg)) {\n return undefined;\n }\n\n // Parse the callback body for one()/many() calls\n return parseRelationsCallback(sourceTable, callbackArg, sourceFile);\n}\n\n/**\n * Parse the callback function inside relations()\n */\nfunction parseRelationsCallback(\n sourceTable: string,\n callback: ts.ArrowFunction,\n sourceFile: ts.SourceFile,\n): ParsedRelation[] {\n const relations: ParsedRelation[] = [];\n\n // The callback body should be an object literal or parenthesized expression containing object literal\n let body = callback.body;\n\n // Unwrap parenthesized expression: ({ ... })\n if (ts.isParenthesizedExpression(body)) {\n body = body.expression;\n }\n\n if (!ts.isObjectLiteralExpression(body)) {\n return relations;\n }\n\n // Iterate over object properties to find one()/many() calls\n for (const property of body.properties) {\n if (ts.isPropertyAssignment(property) && ts.isCallExpression(property.initializer)) {\n const relation = parseRelationCall(sourceTable, property.initializer, sourceFile);\n if (relation) {\n relations.push(relation);\n }\n }\n }\n\n return relations;\n}\n\n/**\n * Parse a one() or many() call expression\n */\nfunction parseRelationCall(\n sourceTable: string,\n callExpr: ts.CallExpression,\n _sourceFile: ts.SourceFile,\n): ParsedRelation | undefined {\n const funcName = getCallExpressionName(callExpr);\n\n if (funcName !== \"one\" && funcName !== \"many\") {\n return undefined;\n }\n\n // Get target table from first argument\n const targetTableArg = callExpr.arguments[0];\n if (!targetTableArg) {\n return undefined;\n }\n const targetTable = extractIdentifierName(targetTableArg);\n if (!targetTable) {\n return undefined;\n }\n\n // For many(), there might not be a config object (no fields/references)\n // In that case, the relation is only useful if there's a corresponding one() on the other side\n const configArg = callExpr.arguments[1];\n\n let fields: string[] = [];\n let references: string[] = [];\n\n if (configArg && ts.isObjectLiteralExpression(configArg)) {\n // Parse fields and references from config object\n for (const property of configArg.properties) {\n if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name)) {\n const propName = property.name.text;\n\n if (propName === \"fields\" && ts.isArrayLiteralExpression(property.initializer)) {\n fields = extractColumnNames(property.initializer);\n } else if (propName === \"references\" && ts.isArrayLiteralExpression(property.initializer)) {\n references = extractColumnNames(property.initializer);\n }\n }\n }\n }\n\n return {\n sourceTable,\n targetTable,\n type: funcName,\n fields,\n references,\n };\n}\n\n/**\n * Extract column names from an array literal like [posts.authorId, posts.title]\n */\nfunction extractColumnNames(arrayLiteral: ts.ArrayLiteralExpression): string[] {\n const names: string[] = [];\n\n for (const element of arrayLiteral.elements) {\n // Handle property access like: posts.authorId\n if (ts.isPropertyAccessExpression(element)) {\n names.push(element.name.text);\n }\n // Handle identifier (less common)\n else if (ts.isIdentifier(element)) {\n names.push(element.text);\n }\n }\n\n return names;\n}\n\n/**\n * Get the function name from a call expression\n */\nfunction getCallExpressionName(callExpr: ts.CallExpression): string | undefined {\n if (ts.isIdentifier(callExpr.expression)) {\n return callExpr.expression.text;\n }\n if (ts.isPropertyAccessExpression(callExpr.expression)) {\n return callExpr.expression.name.text;\n }\n return undefined;\n}\n\n/**\n * Extract identifier name from an expression\n */\nfunction extractIdentifierName(expr: ts.Expression): string | undefined {\n if (ts.isIdentifier(expr)) {\n return expr.text;\n }\n return undefined;\n}\n"],"names":["getTypeScriptFiles","sourcePath","stat","statSync","files","entries","readdirSync","entry","fullPath","join","extractRelations","result","filePath","sourceCode","readFileSync","sourceFile","ts","visitNode","node","declaration","parsedRelations","parseRelationsDefinition","child","callExpr","getCallExpressionName","sourceTableArg","sourceTable","extractIdentifierName","callbackArg","parseRelationsCallback","callback","relations","body","property","relation","parseRelationCall","_sourceFile","funcName","targetTableArg","targetTable","configArg","fields","references","propName","extractColumnNames","arrayLiteral","names","element","expr"],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI runner utility for integration tests
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to execute the CLI and capture output
|
|
5
|
+
*/
|
|
6
|
+
export interface CliResult {
|
|
7
|
+
stdout: string;
|
|
8
|
+
stderr: string;
|
|
9
|
+
exitCode: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Run the CLI with the given arguments
|
|
13
|
+
*
|
|
14
|
+
* @param args - CLI arguments (e.g., ["generate", "schema.ts", "-d", "postgresql"])
|
|
15
|
+
* @param options - Optional configuration
|
|
16
|
+
* @returns Promise resolving to CLI output and exit code
|
|
17
|
+
*/
|
|
18
|
+
export declare function runCli(args: string[], options?: {
|
|
19
|
+
cwd?: string;
|
|
20
|
+
timeout?: number;
|
|
21
|
+
}): Promise<CliResult>;
|
|
22
|
+
/**
|
|
23
|
+
* Run the CLI generate command with common options
|
|
24
|
+
*
|
|
25
|
+
* @param schemaPath - Path to the schema file
|
|
26
|
+
* @param dialect - Database dialect
|
|
27
|
+
* @param options - Additional CLI options
|
|
28
|
+
* @returns Promise resolving to CLI output and exit code
|
|
29
|
+
*/
|
|
30
|
+
export declare function runGenerate(schemaPath: string, dialect: "postgresql" | "mysql" | "sqlite", options?: {
|
|
31
|
+
output?: string;
|
|
32
|
+
relational?: boolean;
|
|
33
|
+
cwd?: string;
|
|
34
|
+
}): Promise<CliResult>;
|
|
35
|
+
//# sourceMappingURL=cli-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-runner.d.ts","sourceRoot":"","sources":["../../src/test-utils/cli-runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAC1B,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/C,OAAO,CAAC,SAAS,CAAC,CA0CpB;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,YAAY,GAAG,OAAO,GAAG,QAAQ,EAC1C,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;CACT,GACL,OAAO,CAAC,SAAS,CAAC,CAYpB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DBML validation utilities for integration tests
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to validate DBML output structure
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Validate that the DBML output contains expected table definitions
|
|
8
|
+
*
|
|
9
|
+
* @param dbml - DBML output string
|
|
10
|
+
* @param tableNames - Expected table names
|
|
11
|
+
* @param quoteChar - Quote character used for identifiers (" for PG/SQLite, ` for MySQL)
|
|
12
|
+
* @returns true if all tables are present
|
|
13
|
+
*/
|
|
14
|
+
export declare function hasAllTables(dbml: string, tableNames: string[], quoteChar?: '"' | "`"): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Validate that the DBML output contains expected columns in a table
|
|
17
|
+
*
|
|
18
|
+
* @param dbml - DBML output string
|
|
19
|
+
* @param tableName - Table name to check
|
|
20
|
+
* @param columnNames - Expected column names
|
|
21
|
+
* @param quoteChar - Quote character used for identifiers
|
|
22
|
+
* @returns true if all columns are present
|
|
23
|
+
*/
|
|
24
|
+
export declare function hasAllColumns(dbml: string, tableName: string, columnNames: string[], quoteChar?: '"' | "`"): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Check if DBML contains a reference (foreign key relationship)
|
|
27
|
+
*
|
|
28
|
+
* @param dbml - DBML output string
|
|
29
|
+
* @param fromTable - Source table name
|
|
30
|
+
* @param fromColumn - Source column name
|
|
31
|
+
* @param toTable - Target table name
|
|
32
|
+
* @param toColumn - Target column name
|
|
33
|
+
* @param quoteChar - Quote character used for identifiers
|
|
34
|
+
* @returns true if the reference exists
|
|
35
|
+
*/
|
|
36
|
+
export declare function hasReference(dbml: string, fromTable: string, fromColumn: string, toTable: string, toColumn: string, quoteChar?: '"' | "`"): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Check if DBML contains indexes section for a table
|
|
39
|
+
*
|
|
40
|
+
* @param dbml - DBML output string
|
|
41
|
+
* @param tableName - Table name to check
|
|
42
|
+
* @param quoteChar - Quote character used for identifiers
|
|
43
|
+
* @returns true if indexes section exists
|
|
44
|
+
*/
|
|
45
|
+
export declare function hasIndexes(dbml: string, tableName: string, quoteChar?: '"' | "`"): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Check if DBML contains a Note clause for a table
|
|
48
|
+
*
|
|
49
|
+
* @param dbml - DBML output string
|
|
50
|
+
* @param tableName - Table name to check
|
|
51
|
+
* @param noteText - Expected note text (partial match)
|
|
52
|
+
* @param quoteChar - Quote character used for identifiers
|
|
53
|
+
* @returns true if the note exists
|
|
54
|
+
*/
|
|
55
|
+
export declare function hasTableNote(dbml: string, tableName: string, noteText: string, quoteChar?: '"' | "`"): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Count the number of tables in DBML output
|
|
58
|
+
*
|
|
59
|
+
* @param dbml - DBML output string
|
|
60
|
+
* @returns Number of tables
|
|
61
|
+
*/
|
|
62
|
+
export declare function countTables(dbml: string): number;
|
|
63
|
+
/**
|
|
64
|
+
* Count the number of Ref statements in DBML output
|
|
65
|
+
*
|
|
66
|
+
* @param dbml - DBML output string
|
|
67
|
+
* @returns Number of references
|
|
68
|
+
*/
|
|
69
|
+
export declare function countRefs(dbml: string): number;
|
|
70
|
+
//# sourceMappingURL=dbml-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dbml-validator.d.ts","sourceRoot":"","sources":["../../src/test-utils/dbml-validator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAAE,EACpB,SAAS,GAAE,GAAG,GAAG,GAAS,GACzB,OAAO,CAET;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EAAE,EACrB,SAAS,GAAE,GAAG,GAAG,GAAS,GACzB,OAAO,CAqBT;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,GAAG,GAAG,GAAS,GACzB,OAAO,CAOT;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,GAAG,GAAG,GAAS,GAAG,OAAO,CAqB/F;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,GAAG,GAAG,GAAS,GACzB,OAAO,CAqBT;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG9C"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test utilities for integration testing
|
|
3
|
+
*/
|
|
4
|
+
export { runCli, runGenerate } from './cli-runner.js';
|
|
5
|
+
export type { CliResult } from './cli-runner.js';
|
|
6
|
+
export { hasAllTables, hasAllColumns, hasReference, hasIndexes, hasTableNote, countTables, countRefs, } from './dbml-validator.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test-utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACtD,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,SAAS,GACV,MAAM,qBAAqB,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { AnyColumn, Table } from 'drizzle-orm';
|
|
2
|
+
import { SchemaComments } from './parser/comments';
|
|
3
|
+
export type { AnyColumn, Table };
|
|
4
|
+
/**
|
|
5
|
+
* Options for DBML generation
|
|
6
|
+
*/
|
|
7
|
+
export interface GenerateOptions<TSchema extends Record<string, unknown>> {
|
|
8
|
+
/** The Drizzle schema object containing tables and optionally relations */
|
|
9
|
+
schema: TSchema;
|
|
10
|
+
/** Output file path. If provided, DBML will be written to this file */
|
|
11
|
+
out?: string;
|
|
12
|
+
/** If true, uses relations() definitions instead of foreign keys for references */
|
|
13
|
+
relational?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Path to the source schema file or directory for extracting JSDoc comments and relations.
|
|
16
|
+
* If a directory is provided, all .ts files will be processed recursively.
|
|
17
|
+
* Comments will be extracted and included as DBML Note clauses.
|
|
18
|
+
*/
|
|
19
|
+
source?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Pre-extracted comments to use for DBML Note clauses.
|
|
22
|
+
* Alternative to source - use this if you've already extracted comments.
|
|
23
|
+
*/
|
|
24
|
+
comments?: SchemaComments;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Supported relation types in DBML
|
|
28
|
+
*/
|
|
29
|
+
export type RelationType = "one-to-one" | "one-to-many" | "many-to-one";
|
|
30
|
+
/**
|
|
31
|
+
* Internal representation of a reference/relationship
|
|
32
|
+
*/
|
|
33
|
+
export interface GeneratedRef {
|
|
34
|
+
fromTable: string;
|
|
35
|
+
fromColumns: string[];
|
|
36
|
+
toTable: string;
|
|
37
|
+
toColumns: string[];
|
|
38
|
+
type: "<" | ">" | "-";
|
|
39
|
+
onDelete?: string;
|
|
40
|
+
onUpdate?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Column constraint attributes for DBML output
|
|
44
|
+
*/
|
|
45
|
+
export interface ColumnAttributes {
|
|
46
|
+
primaryKey?: boolean;
|
|
47
|
+
notNull?: boolean;
|
|
48
|
+
unique?: boolean;
|
|
49
|
+
increment?: boolean;
|
|
50
|
+
default?: string;
|
|
51
|
+
note?: string;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAEjC;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtE,2EAA2E;IAC3E,MAAM,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,aAAa,GAAG,aAAa,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "drizzle-docs-generator",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A CLI tool that generates DBML files from Drizzle ORM schema definitions.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cli",
|
|
7
|
+
"database",
|
|
8
|
+
"dbml",
|
|
9
|
+
"documentation",
|
|
10
|
+
"drizzle",
|
|
11
|
+
"drizzle-orm",
|
|
12
|
+
"schema",
|
|
13
|
+
"typescript"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/rikeda71/drizzle-docs-generator#readme",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/rikeda71/drizzle-docs-generator/issues"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "rikeda71",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/rikeda71/drizzle-docs-generator.git"
|
|
24
|
+
},
|
|
25
|
+
"bin": {
|
|
26
|
+
"drizzle-docs": "dist/cli/index.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"LICENSE",
|
|
31
|
+
"README.md"
|
|
32
|
+
],
|
|
33
|
+
"type": "module",
|
|
34
|
+
"main": "dist/index.js",
|
|
35
|
+
"types": "dist/index.d.ts",
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"commander": "^14.0.2",
|
|
41
|
+
"drizzle-orm": "1.0.0-beta.10-42c284e"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^24.10.7",
|
|
45
|
+
"oxfmt": "^0.23.0",
|
|
46
|
+
"oxlint": "^1.38.0",
|
|
47
|
+
"typescript": "^5.9.3",
|
|
48
|
+
"vite": "^7.3.1",
|
|
49
|
+
"vite-plugin-dts": "^4.5.4",
|
|
50
|
+
"vitest": "^4.0.16"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"drizzle-orm": ">=0.44.0 || >=1.0.0-beta.0"
|
|
54
|
+
},
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=24"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "vite build",
|
|
60
|
+
"dev": "vite build --watch",
|
|
61
|
+
"test": "vitest",
|
|
62
|
+
"test:run": "vitest run",
|
|
63
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
64
|
+
"lint": "oxlint",
|
|
65
|
+
"format": "oxfmt --write",
|
|
66
|
+
"format:check": "oxfmt --check",
|
|
67
|
+
"typecheck": "tsc --noEmit"
|
|
68
|
+
}
|
|
69
|
+
}
|