@schema2sheet/dbml 1.0.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.
@@ -0,0 +1,54 @@
1
+ import { OnDeleteAction } from "@schema2sheet/core";
2
+
3
+ //#region src/converter.d.ts
4
+ type RefTarget = {
5
+ table: string;
6
+ field: string;
7
+ onDelete?: OnDeleteAction;
8
+ };
9
+ type ExportedField = {
10
+ name: string;
11
+ type: any;
12
+ pk: boolean;
13
+ not_null: boolean;
14
+ unique: boolean;
15
+ note: string;
16
+ dbdefault: any;
17
+ increment: boolean;
18
+ };
19
+ type ExportedEndpoint = {
20
+ schemaName: string;
21
+ tableName: string;
22
+ fieldNames: string[];
23
+ relation: string;
24
+ };
25
+ type ExportedRef = {
26
+ endpoints: ExportedEndpoint[];
27
+ name: string;
28
+ onDelete: string | null;
29
+ onUpdate: string | null;
30
+ };
31
+ type ExportedEnum = {
32
+ name: string;
33
+ values: {
34
+ name: string;
35
+ }[];
36
+ };
37
+ type ExportedTable = {
38
+ name: string;
39
+ fields: ExportedField[];
40
+ };
41
+ type ExportedSchema = {
42
+ tables: ExportedTable[];
43
+ enums: ExportedEnum[];
44
+ refs: ExportedRef[];
45
+ };
46
+ type ExportedDatabase = {
47
+ schemas: ExportedSchema[];
48
+ };
49
+ declare function buildRefMap(schemas: ExportedSchema[]): Map<string, RefTarget>;
50
+ declare function convertDbmlTableToHeaders(table: ExportedTable, refMap: Map<string, RefTarget>, enumNames: Set<string>): string[];
51
+ declare function collectEnumNames(schemas: ExportedSchema[]): Set<string>;
52
+ //#endregion
53
+ export { type ExportedDatabase, type RefTarget, buildRefMap, collectEnumNames, convertDbmlTableToHeaders };
54
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/converter.ts"],"mappings":";;;KAEY,SAAA;EACX,KAAA;EACA,KAAA;EACA,QAAA,GAAW,cAAA;AAAA;AAAA,KAGP,aAAA;EACJ,IAAA;EACA,IAAA;EACA,EAAA;EACA,QAAA;EACA,MAAA;EACA,IAAA;EACA,SAAA;EACA,SAAA;AAAA;AAAA,KAGI,gBAAA;EACJ,UAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA;AAAA;AAAA,KAGI,WAAA;EACJ,SAAA,EAAW,gBAAA;EACX,IAAA;EACA,QAAA;EACA,QAAA;AAAA;AAAA,KAGI,YAAA;EACJ,IAAA;EACA,MAAA;IAAU,IAAA;EAAA;AAAA;AAAA,KAGN,aAAA;EACJ,IAAA;EACA,MAAA,EAAQ,aAAA;AAAA;AAAA,KAGJ,cAAA;EACJ,MAAA,EAAQ,aAAA;EACR,KAAA,EAAO,YAAA;EACP,IAAA,EAAM,WAAA;AAAA;AAAA,KAGK,gBAAA;EACX,OAAA,EAAS,cAAA;AAAA;AAAA,iBAsDM,WAAA,CAAY,OAAA,EAAS,cAAA,KAAmB,GAAA,SAAY,SAAA;AAAA,iBAwCpD,yBAAA,CACf,KAAA,EAAO,aAAA,EACP,MAAA,EAAQ,GAAA,SAAY,SAAA,GACpB,SAAA,EAAW,GAAA;AAAA,iBA+EI,gBAAA,CAAiB,OAAA,EAAS,cAAA,KAAmB,GAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,118 @@
1
+ //#region src/converter.ts
2
+ const DBML_TYPE_MAP = {
3
+ uuid: "uuid",
4
+ varchar: "string",
5
+ text: "string",
6
+ string: "string",
7
+ char: "string",
8
+ nvarchar: "string",
9
+ ntext: "string",
10
+ nchar: "string",
11
+ int: "integer",
12
+ integer: "integer",
13
+ bigint: "integer",
14
+ smallint: "integer",
15
+ tinyint: "integer",
16
+ serial: "integer",
17
+ bigserial: "integer",
18
+ float: "float",
19
+ double: "double",
20
+ decimal: "number",
21
+ real: "float",
22
+ numeric: "number",
23
+ money: "currency",
24
+ boolean: "boolean",
25
+ bool: "boolean",
26
+ timestamp: "date-time",
27
+ timestamptz: "date-time",
28
+ datetime: "date-time",
29
+ date: "date",
30
+ time: "time",
31
+ timetz: "time",
32
+ json: "json",
33
+ jsonb: "json"
34
+ };
35
+ const ON_DELETE_MAP = {
36
+ cascade: "cascade",
37
+ restrict: "restrict",
38
+ set_null: "set_null",
39
+ "set null": "set_null",
40
+ set_default: void 0,
41
+ "set default": void 0,
42
+ no_action: void 0,
43
+ "no action": void 0
44
+ };
45
+ function buildRefMap(schemas) {
46
+ const refMap = /* @__PURE__ */ new Map();
47
+ for (const schema of schemas) for (const ref of schema.refs) {
48
+ if (ref.endpoints.length !== 2) continue;
49
+ const [ep0, ep1] = ref.endpoints;
50
+ let source;
51
+ let target;
52
+ if (ep0.relation === "*" || ep0.relation === ">") {
53
+ source = ep0;
54
+ target = ep1;
55
+ } else if (ep1.relation === "*" || ep1.relation === ">") {
56
+ source = ep1;
57
+ target = ep0;
58
+ } else {
59
+ source = ep0;
60
+ target = ep1;
61
+ }
62
+ const onDelete = ref.onDelete ? ON_DELETE_MAP[ref.onDelete.toLowerCase()] : void 0;
63
+ for (const fieldName of source.fieldNames) {
64
+ const key = `${source.tableName}.${fieldName}`;
65
+ refMap.set(key, {
66
+ table: target.tableName,
67
+ field: target.fieldNames[0] || "id",
68
+ onDelete
69
+ });
70
+ }
71
+ }
72
+ return refMap;
73
+ }
74
+ function convertDbmlTableToHeaders(table, refMap, enumNames) {
75
+ return table.fields.map((field) => convertDbmlFieldToHeader(field, refMap, table.name, enumNames));
76
+ }
77
+ function convertDbmlFieldToHeader(field, refMap, tableName, enumNames) {
78
+ const name = field.name;
79
+ const requiredMark = field.pk || field.not_null ? "*" : "";
80
+ const refKey = `${tableName}.${name}`;
81
+ const ref = refMap.get(refKey);
82
+ if (ref) {
83
+ const parts = [ref.table];
84
+ const expandKey = extractExpandKey(name);
85
+ if (expandKey) parts.push(expandKey);
86
+ if (ref.onDelete && ref.onDelete !== "restrict") parts.push(ref.onDelete);
87
+ return `${name}${requiredMark}:ref(${parts.join(",")})`;
88
+ }
89
+ const rawType = resolveFieldTypeName(field.type);
90
+ if (enumNames.has(rawType)) return `${name}${requiredMark}:enum`;
91
+ if (field.pk && name === "id") return `${name}${requiredMark}:uuid`;
92
+ const mappedType = DBML_TYPE_MAP[rawType.toLowerCase().replace(/\(.*\)/, "").trim()];
93
+ if (!mappedType) {
94
+ console.warn(`Unknown DBML type "${rawType}" for ${tableName}.${name}, defaulting to string`);
95
+ return `${name}${requiredMark}`;
96
+ }
97
+ if (mappedType === "string") return `${name}${requiredMark}`;
98
+ return `${name}${requiredMark}:${mappedType}`;
99
+ }
100
+ function resolveFieldTypeName(type) {
101
+ if (typeof type === "string") return type;
102
+ if (type?.type_name) return String(type.type_name);
103
+ if (type?.schemaName && type?.type_name) return `${type.schemaName}.${type.type_name}`;
104
+ return String(type || "string");
105
+ }
106
+ function extractExpandKey(fieldName) {
107
+ if (fieldName.endsWith("_id")) return fieldName.slice(0, -3);
108
+ if (fieldName.endsWith("Id") && fieldName.length > 2) return fieldName.slice(0, -2);
109
+ }
110
+ function collectEnumNames(schemas) {
111
+ const names = /* @__PURE__ */ new Set();
112
+ for (const schema of schemas) for (const enumDef of schema.enums) names.add(enumDef.name);
113
+ return names;
114
+ }
115
+
116
+ //#endregion
117
+ export { buildRefMap, collectEnumNames, convertDbmlTableToHeaders };
118
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/converter.ts"],"sourcesContent":["import type { OnDeleteAction } from \"@schema2sheet/core\";\n\nexport type RefTarget = {\n\ttable: string;\n\tfield: string;\n\tonDelete?: OnDeleteAction;\n};\n\ntype ExportedField = {\n\tname: string;\n\ttype: any;\n\tpk: boolean;\n\tnot_null: boolean;\n\tunique: boolean;\n\tnote: string;\n\tdbdefault: any;\n\tincrement: boolean;\n};\n\ntype ExportedEndpoint = {\n\tschemaName: string;\n\ttableName: string;\n\tfieldNames: string[];\n\trelation: string;\n};\n\ntype ExportedRef = {\n\tendpoints: ExportedEndpoint[];\n\tname: string;\n\tonDelete: string | null;\n\tonUpdate: string | null;\n};\n\ntype ExportedEnum = {\n\tname: string;\n\tvalues: { name: string }[];\n};\n\ntype ExportedTable = {\n\tname: string;\n\tfields: ExportedField[];\n};\n\ntype ExportedSchema = {\n\ttables: ExportedTable[];\n\tenums: ExportedEnum[];\n\trefs: ExportedRef[];\n};\n\nexport type ExportedDatabase = {\n\tschemas: ExportedSchema[];\n};\n\nconst DBML_TYPE_MAP: Record<string, string> = {\n\tuuid: \"uuid\",\n\n\tvarchar: \"string\",\n\ttext: \"string\",\n\tstring: \"string\",\n\tchar: \"string\",\n\tnvarchar: \"string\",\n\tntext: \"string\",\n\tnchar: \"string\",\n\n\tint: \"integer\",\n\tinteger: \"integer\",\n\tbigint: \"integer\",\n\tsmallint: \"integer\",\n\ttinyint: \"integer\",\n\tserial: \"integer\",\n\tbigserial: \"integer\",\n\n\tfloat: \"float\",\n\tdouble: \"double\",\n\tdecimal: \"number\",\n\treal: \"float\",\n\tnumeric: \"number\",\n\tmoney: \"currency\",\n\n\tboolean: \"boolean\",\n\tbool: \"boolean\",\n\n\ttimestamp: \"date-time\",\n\ttimestamptz: \"date-time\",\n\tdatetime: \"date-time\",\n\tdate: \"date\",\n\ttime: \"time\",\n\ttimetz: \"time\",\n\n\tjson: \"json\",\n\tjsonb: \"json\",\n};\n\nconst ON_DELETE_MAP: Record<string, OnDeleteAction | undefined> = {\n\tcascade: \"cascade\",\n\trestrict: \"restrict\",\n\tset_null: \"set_null\",\n\t\"set null\": \"set_null\",\n\tset_default: undefined,\n\t\"set default\": undefined,\n\tno_action: undefined,\n\t\"no action\": undefined,\n};\n\nexport function buildRefMap(schemas: ExportedSchema[]): Map<string, RefTarget> {\n\tconst refMap = new Map<string, RefTarget>();\n\n\tfor (const schema of schemas) {\n\t\tfor (const ref of schema.refs) {\n\t\t\tif (ref.endpoints.length !== 2) continue;\n\n\t\t\tconst [ep0, ep1] = ref.endpoints;\n\t\t\tlet source: ExportedEndpoint;\n\t\t\tlet target: ExportedEndpoint;\n\n\t\t\tif (ep0.relation === \"*\" || ep0.relation === \">\") {\n\t\t\t\tsource = ep0;\n\t\t\t\ttarget = ep1;\n\t\t\t} else if (ep1.relation === \"*\" || ep1.relation === \">\") {\n\t\t\t\tsource = ep1;\n\t\t\t\ttarget = ep0;\n\t\t\t} else {\n\t\t\t\tsource = ep0;\n\t\t\t\ttarget = ep1;\n\t\t\t}\n\n\t\t\tconst onDelete = ref.onDelete\n\t\t\t\t? ON_DELETE_MAP[ref.onDelete.toLowerCase()]\n\t\t\t\t: undefined;\n\n\t\t\tfor (const fieldName of source.fieldNames) {\n\t\t\t\tconst key = `${source.tableName}.${fieldName}`;\n\t\t\t\trefMap.set(key, {\n\t\t\t\t\ttable: target.tableName,\n\t\t\t\t\tfield: target.fieldNames[0] || \"id\",\n\t\t\t\t\tonDelete,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn refMap;\n}\n\nexport function convertDbmlTableToHeaders(\n\ttable: ExportedTable,\n\trefMap: Map<string, RefTarget>,\n\tenumNames: Set<string>,\n): string[] {\n\treturn table.fields.map((field) =>\n\t\tconvertDbmlFieldToHeader(field, refMap, table.name, enumNames),\n\t);\n}\n\nfunction convertDbmlFieldToHeader(\n\tfield: ExportedField,\n\trefMap: Map<string, RefTarget>,\n\ttableName: string,\n\tenumNames: Set<string>,\n): string {\n\tconst name = field.name;\n\tconst isRequired = field.pk || field.not_null;\n\tconst requiredMark = isRequired ? \"*\" : \"\";\n\n\tconst refKey = `${tableName}.${name}`;\n\tconst ref = refMap.get(refKey);\n\n\tif (ref) {\n\t\tconst parts: string[] = [ref.table];\n\t\tconst expandKey = extractExpandKey(name);\n\t\tif (expandKey) parts.push(expandKey);\n\t\tif (ref.onDelete && ref.onDelete !== \"restrict\") {\n\t\t\tparts.push(ref.onDelete);\n\t\t}\n\t\treturn `${name}${requiredMark}:ref(${parts.join(\",\")})`;\n\t}\n\n\tconst rawType = resolveFieldTypeName(field.type);\n\n\tif (enumNames.has(rawType)) {\n\t\treturn `${name}${requiredMark}:enum`;\n\t}\n\n\tif (field.pk && name === \"id\") {\n\t\treturn `${name}${requiredMark}:uuid`;\n\t}\n\n\tconst baseType = rawType\n\t\t.toLowerCase()\n\t\t.replace(/\\(.*\\)/, \"\")\n\t\t.trim();\n\tconst mappedType = DBML_TYPE_MAP[baseType];\n\n\tif (!mappedType) {\n\t\tconsole.warn(\n\t\t\t`Unknown DBML type \"${rawType}\" for ${tableName}.${name}, defaulting to string`,\n\t\t);\n\t\treturn `${name}${requiredMark}`;\n\t}\n\n\tif (mappedType === \"string\") {\n\t\treturn `${name}${requiredMark}`;\n\t}\n\n\treturn `${name}${requiredMark}:${mappedType}`;\n}\n\nfunction resolveFieldTypeName(type: any): string {\n\tif (typeof type === \"string\") return type;\n\tif (type?.type_name) return String(type.type_name);\n\tif (type?.schemaName && type?.type_name) {\n\t\treturn `${type.schemaName}.${type.type_name}`;\n\t}\n\treturn String(type || \"string\");\n}\n\nfunction extractExpandKey(fieldName: string): string | undefined {\n\tif (fieldName.endsWith(\"_id\")) {\n\t\treturn fieldName.slice(0, -3);\n\t}\n\tif (fieldName.endsWith(\"Id\") && fieldName.length > 2) {\n\t\treturn fieldName.slice(0, -2);\n\t}\n\treturn undefined;\n}\n\nexport function collectEnumNames(schemas: ExportedSchema[]): Set<string> {\n\tconst names = new Set<string>();\n\tfor (const schema of schemas) {\n\t\tfor (const enumDef of schema.enums) {\n\t\t\tnames.add(enumDef.name);\n\t\t}\n\t}\n\treturn names;\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@schema2sheet/dbml",
3
+ "version": "1.0.0",
4
+ "description": "DBML to schema converter for schema2sheet",
5
+ "type": "module",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "keywords": [
11
+ "dbml",
12
+ "schema",
13
+ "converter"
14
+ ],
15
+ "license": "MIT",
16
+ "dependencies": {
17
+ "@dbml/core": "^3.14.1",
18
+ "@schema2sheet/core": "1.0.0"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^22.10.2",
22
+ "typescript": "^5.7.2"
23
+ },
24
+ "exports": {
25
+ ".": "./dist/index.mjs",
26
+ "./package.json": "./package.json"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/froggy1014/schema2sheet.git"
31
+ },
32
+ "homepage": "https://github.com/froggy1014/schema2sheet#readme",
33
+ "bugs": {
34
+ "url": "https://github.com/froggy1014/schema2sheet/issues"
35
+ },
36
+ "author": "froggy1014",
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "scripts": {
41
+ "build": "tsdown",
42
+ "dev": "tsdown --watch",
43
+ "lint": "biome check --write .",
44
+ "clean": "rm -rf dist .turbo node_modules",
45
+ "typecheck": "tsc --noEmit"
46
+ }
47
+ }