@dbml/cli 7.1.1 → 8.0.0-alpha.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.
Files changed (88) hide show
  1. package/__tests__/db2dbml/mssql/dbml-error.log +330 -0
  2. package/__tests__/db2dbml/mysql/dbml-error.log +429 -0
  3. package/__tests__/db2dbml/oracle/dbml-error.log +462 -0
  4. package/__tests__/db2dbml/postgres/dbml-error.log +231 -0
  5. package/__tests__/dbml2sql/filename --mysql --out-file/dbml-error.log +0 -0
  6. package/__tests__/dbml2sql/filename --mysql --out-file/out-files/schema.sql +65 -0
  7. package/__tests__/dbml2sql/filename --mysql stdout/dbml-error.log +0 -0
  8. package/__tests__/dbml2sql/filename --oracle --out-file/dbml-error.log +0 -0
  9. package/__tests__/dbml2sql/filename --oracle --out-file/out-files/schema.sql +61 -0
  10. package/__tests__/dbml2sql/filename --oracle stdout/dbml-error.log +0 -0
  11. package/__tests__/dbml2sql/filename --out-file/dbml-error.log +0 -0
  12. package/__tests__/dbml2sql/filename --out-file/out-files/schema.sql +77 -0
  13. package/__tests__/dbml2sql/filename --postgres --out-file/dbml-error.log +0 -0
  14. package/__tests__/dbml2sql/filename --postgres --out-file/out-files/schema.sql +77 -0
  15. package/__tests__/dbml2sql/filename --postgres stdout/dbml-error.log +0 -0
  16. package/__tests__/dbml2sql/filename stdout/dbml-error.log +0 -0
  17. package/__tests__/dbml2sql/filenames --mysql --out-file/dbml-error.log +0 -0
  18. package/__tests__/dbml2sql/filenames --mysql --out-file/out-files/schema.sql +172 -0
  19. package/__tests__/dbml2sql/filenames --mysql stdout/dbml-error.log +0 -0
  20. package/__tests__/dbml2sql/filenames --oracle --out-file/dbml-error.log +0 -0
  21. package/__tests__/dbml2sql/filenames --oracle --out-file/out-files/schema.sql +172 -0
  22. package/__tests__/dbml2sql/filenames --oracle stdout/dbml-error.log +0 -0
  23. package/__tests__/dbml2sql/filenames --out-file/dbml-error.log +0 -0
  24. package/__tests__/dbml2sql/filenames --out-file/out-files/schema.sql +172 -0
  25. package/__tests__/dbml2sql/filenames --postgres --out-file/dbml-error.log +0 -0
  26. package/__tests__/dbml2sql/filenames --postgres --out-file/out-files/schema.sql +172 -0
  27. package/__tests__/dbml2sql/filenames --postgres stdout/dbml-error.log +0 -0
  28. package/__tests__/dbml2sql/filenames stdout/dbml-error.log +0 -0
  29. package/__tests__/dbml2sql/multifile complex stdout/dbml-error.log +0 -0
  30. package/__tests__/dbml2sql/multifile complex stdout/in-files/auth.dbml +4 -0
  31. package/__tests__/dbml2sql/multifile complex stdout/in-files/catalog.dbml +10 -0
  32. package/__tests__/dbml2sql/multifile complex stdout/in-files/enums.dbml +5 -0
  33. package/__tests__/dbml2sql/multifile complex stdout/in-files/main.dbml +15 -0
  34. package/__tests__/dbml2sql/multifile complex stdout/options.json +3 -0
  35. package/__tests__/dbml2sql/multifile complex stdout/stdout.txt +32 -0
  36. package/__tests__/dbml2sql/multiple_schema_mssql/dbml-error.log +30 -0
  37. package/__tests__/dbml2sql/multiple_schema_mssql/out-files/multiple_schema.out.sql +62 -0
  38. package/__tests__/dbml2sql/multiple_schema_mysql/dbml-error.log +30 -0
  39. package/__tests__/dbml2sql/multiple_schema_mysql/out-files/multiple_schema.out.sql +50 -0
  40. package/__tests__/dbml2sql/multiple_schema_oracle/dbml-error.log +0 -0
  41. package/__tests__/dbml2sql/multiple_schema_oracle/out-files/multiple_schema.out.sql +88 -0
  42. package/__tests__/dbml2sql/multiple_schema_pg/dbml-error.log +30 -0
  43. package/__tests__/dbml2sql/multiple_schema_pg/out-files/multiple_schema.out.sql +67 -0
  44. package/__tests__/dbml2sql/syntax-error/dbml-error.log +102 -0
  45. package/__tests__/sql2dbml/custom-error-alter-table-column-not-found --oracle/dbml-error.log +108 -0
  46. package/__tests__/sql2dbml/custom-error-alter-table-table-not-found --oracle/dbml-error.log +108 -0
  47. package/__tests__/sql2dbml/custom-error-column-comment-column-not-found --oracle/dbml-error.log +108 -0
  48. package/__tests__/sql2dbml/custom-error-column-comment-table-not-found --oracle/dbml-error.log +108 -0
  49. package/__tests__/sql2dbml/custom-error-create-index-table-not-found --oracle/dbml-error.log +108 -0
  50. package/__tests__/sql2dbml/custom-error-table-comment-table-not-found --oracle/dbml-error.log +108 -0
  51. package/__tests__/sql2dbml/filename --mssql --out-file/dbml-error.log +0 -0
  52. package/__tests__/sql2dbml/filename --mssql --out-file/out-files/schema.dbml +25 -0
  53. package/__tests__/sql2dbml/filename --mysql --out-file/dbml-error.log +0 -0
  54. package/__tests__/sql2dbml/filename --mysql --out-file/out-files/schema.dbml +74 -0
  55. package/__tests__/sql2dbml/filename --mysql stdout/dbml-error.log +0 -0
  56. package/__tests__/sql2dbml/filename --oracle --out-file/dbml-error.log +0 -0
  57. package/__tests__/sql2dbml/filename --oracle --out-file/out-files/schema.dbml +83 -0
  58. package/__tests__/sql2dbml/filename --out-file/dbml-error.log +0 -0
  59. package/__tests__/sql2dbml/filename --out-file/out-files/schema.dbml +74 -0
  60. package/__tests__/sql2dbml/filename --postgres --out-file/dbml-error.log +0 -0
  61. package/__tests__/sql2dbml/filename --postgres --out-file/out-files/schema.dbml +74 -0
  62. package/__tests__/sql2dbml/filename --postgres stdout/dbml-error.log +0 -0
  63. package/__tests__/sql2dbml/filename --snowflake stdout/dbml-error.log +0 -0
  64. package/__tests__/sql2dbml/filename stdout/dbml-error.log +0 -0
  65. package/__tests__/sql2dbml/filenames --mysql --out-file/dbml-error.log +0 -0
  66. package/__tests__/sql2dbml/filenames --mysql --out-file/out-files/schema.dbml +170 -0
  67. package/__tests__/sql2dbml/filenames --mysql stdout/dbml-error.log +0 -0
  68. package/__tests__/sql2dbml/filenames --out-file/dbml-error.log +0 -0
  69. package/__tests__/sql2dbml/filenames --out-file/out-files/schema.dbml +170 -0
  70. package/__tests__/sql2dbml/filenames --postgres --out-file/dbml-error.log +0 -0
  71. package/__tests__/sql2dbml/filenames --postgres --out-file/out-files/schema.dbml +170 -0
  72. package/__tests__/sql2dbml/filenames --postgres stdout/dbml-error.log +0 -0
  73. package/__tests__/sql2dbml/filenames stdout/dbml-error.log +0 -0
  74. package/__tests__/sql2dbml/multiple_schema_mssql/dbml-error.log +0 -0
  75. package/__tests__/sql2dbml/multiple_schema_mssql/out-files/multiple_schema.out.dbml +58 -0
  76. package/__tests__/sql2dbml/multiple_schema_mysql/dbml-error.log +0 -0
  77. package/__tests__/sql2dbml/multiple_schema_mysql/out-files/multiple_schema.out.dbml +136 -0
  78. package/__tests__/sql2dbml/multiple_schema_pg/dbml-error.log +0 -0
  79. package/__tests__/sql2dbml/multiple_schema_pg/out-files/multiple_schema.out.dbml +101 -0
  80. package/__tests__/sql2dbml/syntax-error/dbml-error.log +102 -0
  81. package/__tests__/sql2dbml/syntax-error-duplicate-endpoints --mssql/dbml-error.log +99 -0
  82. package/__tests__/sql2dbml/syntax-error-duplicate-endpoints --mysql/dbml-error.log +99 -0
  83. package/dbml-error.log +3 -0
  84. package/lib/index.js +129 -42
  85. package/package.json +5 -5
  86. package/src/NodeProjectLayout.ts +125 -0
  87. package/src/cli/export.ts +59 -35
  88. package/vite.config.ts +1 -0
@@ -0,0 +1,99 @@
1
+ 2026-04-11T10:16:02.804Z
2
+ undefined
3
+
4
+ 2026-04-11T10:19:47.074Z
5
+ undefined
6
+
7
+ 2026-04-11T10:53:31.236Z
8
+ undefined
9
+
10
+ 2026-04-11T10:55:59.352Z
11
+ undefined
12
+
13
+ 2026-04-11T11:14:08.082Z
14
+ undefined
15
+
16
+ 2026-04-11T15:33:24.319Z
17
+ undefined
18
+
19
+ 2026-04-17T08:28:12.644Z
20
+ undefined
21
+
22
+ 2026-04-17T08:30:04.522Z
23
+ undefined
24
+
25
+ 2026-04-21T10:03:46.911Z
26
+ undefined
27
+
28
+ 2026-04-25T14:23:24.290Z
29
+ undefined
30
+
31
+ 2026-04-25T14:24:44.457Z
32
+ undefined
33
+
34
+ 2026-04-25T14:26:03.853Z
35
+ undefined
36
+
37
+ 2026-04-25T14:27:23.238Z
38
+ undefined
39
+
40
+ 2026-04-25T14:28:44.260Z
41
+ undefined
42
+
43
+ 2026-04-25T14:39:04.973Z
44
+ undefined
45
+
46
+ 2026-04-25T14:42:09.694Z
47
+ undefined
48
+
49
+ 2026-04-25T14:46:18.763Z
50
+ undefined
51
+
52
+ 2026-04-25T14:49:45.147Z
53
+ undefined
54
+
55
+ 2026-04-25T14:52:17.585Z
56
+ undefined
57
+
58
+ 2026-04-25T14:54:06.309Z
59
+ undefined
60
+
61
+ 2026-04-25T14:55:33.033Z
62
+ undefined
63
+
64
+ 2026-04-25T14:57:29.835Z
65
+ undefined
66
+
67
+ 2026-04-25T14:59:18.940Z
68
+ undefined
69
+
70
+ 2026-04-25T15:18:52.479Z
71
+ undefined
72
+
73
+ 2026-04-25T15:45:10.950Z
74
+ undefined
75
+
76
+ 2026-04-30T02:24:16.181Z
77
+ undefined
78
+
79
+ 2026-04-30T02:27:03.580Z
80
+ undefined
81
+
82
+ 2026-05-03T12:50:13.032Z
83
+ undefined
84
+
85
+ 2026-05-03T12:55:31.060Z
86
+ undefined
87
+
88
+ 2026-05-03T13:24:02.658Z
89
+ undefined
90
+
91
+ 2026-05-04T15:14:09.165Z
92
+ undefined
93
+
94
+ 2026-05-04T17:05:56.541Z
95
+ undefined
96
+
97
+ 2026-05-04T17:07:08.426Z
98
+ undefined
99
+
package/dbml-error.log ADDED
@@ -0,0 +1,3 @@
1
+ 2026-04-11T10:16:28.713Z
2
+ undefined
3
+
package/lib/index.js CHANGED
@@ -32,9 +32,11 @@ figures = __toESM(figures);
32
32
  let winston = require("winston");
33
33
  let fs = require("fs");
34
34
  fs = __toESM(fs);
35
+ let __dbml_parse = require("@dbml/parse");
36
+ let node_fs = require("node:fs");
35
37
  const $schema = "https://json.schemastore.org/package";
36
38
  const name = "@dbml/cli";
37
- const version = "7.1.1";
39
+ const version = "8.0.0-alpha.0";
38
40
  const description = "";
39
41
  const main = "lib/index.js";
40
42
  const license = "Apache-2.0";
@@ -60,9 +62,9 @@ const repository = "https://github.com/holistics/dbml/tree/master/packages/dbml-
60
62
  const keywords = ["dbml", "dbml-cli"];
61
63
  const dependencies = {
62
64
  "@babel/cli": "^7.21.0",
63
- "@dbml/connector": "^7.1.1",
64
- "@dbml/core": "^7.1.1",
65
- "@dbml/parse": "^7.1.1",
65
+ "@dbml/connector": "^8.0.0-alpha.0",
66
+ "@dbml/core": "^8.0.0-alpha.0",
67
+ "@dbml/parse": "^8.0.0-alpha.0",
66
68
  "bluebird": "^3.5.5",
67
69
  "chalk": "^2.4.2",
68
70
  "commander": "^2.20.0",
@@ -73,7 +75,7 @@ const dependencies = {
73
75
  "strip-ansi": "^5.2.0",
74
76
  "winston": "^3.2.1"
75
77
  };
76
- const gitHead = "db3691bdada0e754afb76ed4c24c519a80fcddf9";
78
+ const gitHead = "4b99e7eab601b7d53e268d5d80048ee035614a79";
77
79
  const engines = { "node": ">=18" };
78
80
  var package_default = {
79
81
  $schema,
@@ -510,8 +512,8 @@ ListCache.prototype.get = _listCacheGet_default;
510
512
  ListCache.prototype.has = _listCacheHas_default;
511
513
  ListCache.prototype.set = _listCacheSet_default;
512
514
  var _ListCache_default = ListCache;
513
- var Map = _getNative_default(_root_default, "Map");
514
- var _Map_default = Map;
515
+ var Map$1 = _getNative_default(_root_default, "Map");
516
+ var _Map_default = Map$1;
515
517
  function mapCacheClear() {
516
518
  this.size = 0;
517
519
  this.__data__ = {
@@ -724,8 +726,8 @@ var DataView = _getNative_default(_root_default, "DataView");
724
726
  var _DataView_default = DataView;
725
727
  var Promise$1 = _getNative_default(_root_default, "Promise");
726
728
  var _Promise_default = Promise$1;
727
- var Set = _getNative_default(_root_default, "Set");
728
- var _Set_default = Set;
729
+ var Set$1 = _getNative_default(_root_default, "Set");
730
+ var _Set_default = Set$1;
729
731
  var mapTag$2 = "[object Map]", objectTag$1 = "[object Object]", promiseTag = "[object Promise]", setTag$2 = "[object Set]", weakMapTag = "[object WeakMap]";
730
732
  var dataViewTag$1 = "[object DataView]";
731
733
  var dataViewCtorString = _toSource_default(_DataView_default), mapCtorString = _toSource_default(_Map_default), promiseCtorString = _toSource_default(_Promise_default), setCtorString = _toSource_default(_Set_default), weakMapCtorString = _toSource_default(_WeakMap_default);
@@ -1176,25 +1178,76 @@ async function connectionHandler(program$1) {
1176
1178
  logger_default.error(error);
1177
1179
  }
1178
1180
  }
1179
- var DomainError = class extends Error {
1180
- constructor(message, rootError = {}) {
1181
- super(message);
1182
- this.name = this.constructor.name;
1183
- this.rootError = rootError;
1184
- Error.captureStackTrace(this, this.constructor);
1181
+ var NodeProjectLayout = class NodeProjectLayout {
1182
+ constructor(entryPoints) {
1183
+ this.overlay = /* @__PURE__ */ new Map();
1184
+ this.entryPoints = [...entryPoints];
1185
1185
  }
1186
- };
1187
- var domainError_default = DomainError;
1188
- var SyntaxError = class extends domainError_default {
1189
- constructor(fileName, rootError = {}) {
1190
- let message = `You have a syntax error at "${fileName}"`;
1191
- if (rootError.location) message += ` line ${rootError.location.start.line} column ${rootError.location.start.column}`;
1192
- message += ".";
1193
- if (!isEmpty_default(rootError)) message += ` ${rootError.message}`;
1194
- super(message, rootError);
1186
+ setSource(filePath, content) {
1187
+ this.overlay.set(filePath.absolute, content);
1188
+ }
1189
+ getSource(filePath) {
1190
+ const absolutePath = filePath.absolute;
1191
+ if (this.overlay.has(absolutePath)) return this.overlay.get(absolutePath) ?? void 0;
1192
+ try {
1193
+ return (0, node_fs.readFileSync)(absolutePath, "utf-8");
1194
+ } catch {
1195
+ return;
1196
+ }
1197
+ }
1198
+ deleteSource(filePath) {
1199
+ this.overlay.set(filePath.absolute, null);
1200
+ }
1201
+ clearSource() {
1202
+ this.overlay.clear();
1203
+ this.entryPoints = [];
1204
+ }
1205
+ exists(filePath) {
1206
+ return this.isFile(filePath) || this.isDirectory(filePath);
1207
+ }
1208
+ isFile(filePath) {
1209
+ const absolutePath = filePath.absolute;
1210
+ if (this.overlay.has(absolutePath)) return this.overlay.get(absolutePath) !== null;
1211
+ try {
1212
+ return (0, node_fs.statSync)(absolutePath).isFile();
1213
+ } catch {
1214
+ return false;
1215
+ }
1216
+ }
1217
+ isDirectory(filePath) {
1218
+ const absolutePath = filePath.absolute;
1219
+ try {
1220
+ if ((0, node_fs.statSync)(absolutePath).isDirectory()) return true;
1221
+ } catch {}
1222
+ for (const [overlayPath, content] of this.overlay) {
1223
+ if (content === null) continue;
1224
+ if (overlayPath.startsWith(absolutePath)) return true;
1225
+ }
1226
+ return false;
1227
+ }
1228
+ listDirectory(dirPath) {
1229
+ const basePath = dirPath?.absolute ?? "/";
1230
+ const results = /* @__PURE__ */ new Set();
1231
+ try {
1232
+ for (const entry of (0, node_fs.readdirSync)(basePath)) results.add(basePath + entry);
1233
+ } catch {}
1234
+ for (const [abs, content] of this.overlay) {
1235
+ if (content === null) continue;
1236
+ if (!abs.startsWith(basePath)) continue;
1237
+ if (!abs.slice(basePath.length).includes("/")) results.add(abs);
1238
+ }
1239
+ for (const [overlayPath, content] of this.overlay) if (content === null) results.delete(overlayPath);
1240
+ return [...results].sort().map(__dbml_parse.Filepath.from);
1241
+ }
1242
+ getEntryPoints() {
1243
+ return this.entryPoints.filter((fp) => this.exists(fp));
1244
+ }
1245
+ clone() {
1246
+ const copy = new NodeProjectLayout([...this.entryPoints]);
1247
+ for (const [overlayPath, content] of this.overlay) copy.overlay.set(overlayPath, content);
1248
+ return copy;
1195
1249
  }
1196
1250
  };
1197
- var syntaxError_default = SyntaxError;
1198
1251
  var config = {
1199
1252
  mysql: { name: "MySQL" },
1200
1253
  mysqlLegacy: { name: "MySQL" },
@@ -1209,26 +1262,60 @@ function validateFilePlugin(_path) {
1209
1262
  if (fs.default.statSync(_path).isDirectory()) throw new Error("Expect input to be files");
1210
1263
  }
1211
1264
  async function exportHandler(program$1) {
1212
- try {
1213
- const inputPaths = resolvePaths(program$1.args);
1214
- validateInputFilePaths(inputPaths, validateFilePlugin);
1215
- const opts = program$1.opts();
1216
- const format$1 = getFormatOpt(opts);
1217
- if (!opts.outFile && !opts.outDir) generate(inputPaths, (dbml) => __dbml_core.exporter.export(dbml, format$1), outputConsolePlugin_default);
1218
- else if (opts.outFile) {
1219
- const header = [
1220
- "-- SQL dump generated using DBML (dbml.dbdiagram.io)\n",
1221
- `-- Database: ${config_default[format$1].name}\n`,
1222
- `-- Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}\n\n`
1223
- ].join("");
1224
- generate(inputPaths, (dbml) => __dbml_core.exporter.export(dbml, format$1), new outputFilePlugin_default(resolvePaths(opts.outFile), header));
1225
- console.log(` ${chalk.default.green(figures.default.main.tick)} Generated SQL dump file (${config_default[format$1].name}): ${path.default.basename(opts.outFile)}`);
1265
+ const inputPaths = resolvePaths(program$1.args);
1266
+ validateInputFilePaths(inputPaths, validateFilePlugin);
1267
+ const opts = program$1.opts();
1268
+ const format$1 = getFormatOpt(opts);
1269
+ const entryPoints = inputPaths.map((p) => new __dbml_parse.Filepath(p));
1270
+ const compiler = new __dbml_parse.Compiler();
1271
+ compiler.layout = new NodeProjectLayout(entryPoints);
1272
+ const outputPlugin = opts.outFile ? new outputFilePlugin_default(resolvePaths(opts.outFile), [
1273
+ "-- SQL dump generated using DBML (dbml.dbdiagram.io)\n",
1274
+ `-- Database: ${config_default[format$1].name}\n`,
1275
+ `-- Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}\n\n`
1276
+ ].join("")) : outputConsolePlugin_default;
1277
+ let hasErrors = false;
1278
+ for (const filepath of entryPoints) {
1279
+ const result = compiler.interpretFile(filepath);
1280
+ const errors = result.getErrors();
1281
+ if (errors.length > 0) {
1282
+ hasErrors = true;
1283
+ const isMultifile = compiler.reachableFiles(filepath).length > 1;
1284
+ logger_default.error(`\n ${errors.map((e) => {
1285
+ const pos = e.nodeOrToken.startPos;
1286
+ const line = pos.line + 1;
1287
+ const col = pos.column + 1;
1288
+ if (isMultifile) return `${e.filepath.basename}(${line},${col}): ${e.message}`;
1289
+ return `You have a syntax error at "${e.filepath.basename}" line ${line} column ${col}. ${e.message}`;
1290
+ }).join("\n ")}`);
1291
+ continue;
1226
1292
  }
1227
- } catch (error) {
1228
- const e = error;
1229
- logger_default.error(`\n ${e.diags.map((diag) => new syntaxError_default(diag.filepath ?? "", diag)).map(({ message }) => message).join("\n ")}`);
1293
+ const db = result.getValue();
1294
+ if (!db) continue;
1295
+ const sql = __dbml_core.ModelExporter.export(__dbml_core.Parser.parseJSONToDatabase(db), format$1);
1296
+ outputPlugin.write(sql);
1230
1297
  }
1298
+ if (!hasErrors && opts.outFile) console.log(` ${chalk.default.green(figures.default.main.tick)} Generated SQL dump file (${config_default[format$1].name}): ${path.default.basename(opts.outFile)}`);
1231
1299
  }
1300
+ var DomainError = class extends Error {
1301
+ constructor(message, rootError = {}) {
1302
+ super(message);
1303
+ this.name = this.constructor.name;
1304
+ this.rootError = rootError;
1305
+ Error.captureStackTrace(this, this.constructor);
1306
+ }
1307
+ };
1308
+ var domainError_default = DomainError;
1309
+ var SyntaxError = class extends domainError_default {
1310
+ constructor(fileName, rootError = {}) {
1311
+ let message = `You have a syntax error at "${fileName}"`;
1312
+ if (rootError.location) message += ` line ${rootError.location.start.line} column ${rootError.location.start.column}`;
1313
+ message += ".";
1314
+ if (!isEmpty_default(rootError)) message += ` ${rootError.message}`;
1315
+ super(message, rootError);
1316
+ }
1317
+ };
1318
+ var syntaxError_default = SyntaxError;
1232
1319
  async function importHandler(program$1) {
1233
1320
  try {
1234
1321
  const inputPaths = resolvePaths(program$1.args);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@dbml/cli",
4
- "version": "7.1.1",
4
+ "version": "8.0.0-alpha.0",
5
5
  "description": "",
6
6
  "main": "lib/index.js",
7
7
  "license": "Apache-2.0",
@@ -32,9 +32,9 @@
32
32
  ],
33
33
  "dependencies": {
34
34
  "@babel/cli": "^7.21.0",
35
- "@dbml/connector": "^7.1.1",
36
- "@dbml/core": "^7.1.1",
37
- "@dbml/parse": "^7.1.1",
35
+ "@dbml/connector": "^8.0.0-alpha.0",
36
+ "@dbml/core": "^8.0.0-alpha.0",
37
+ "@dbml/parse": "^8.0.0-alpha.0",
38
38
  "bluebird": "^3.5.5",
39
39
  "chalk": "^2.4.2",
40
40
  "commander": "^2.20.0",
@@ -45,7 +45,7 @@
45
45
  "strip-ansi": "^5.2.0",
46
46
  "winston": "^3.2.1"
47
47
  },
48
- "gitHead": "db3691bdada0e754afb76ed4c24c519a80fcddf9",
48
+ "gitHead": "4b99e7eab601b7d53e268d5d80048ee035614a79",
49
49
  "engines": {
50
50
  "node": ">=18"
51
51
  }
@@ -0,0 +1,125 @@
1
+ import {
2
+ existsSync, readFileSync, readdirSync, statSync,
3
+ } from 'node:fs';
4
+ import {
5
+ type DbmlProjectLayout, Filepath,
6
+ } from '@dbml/parse';
7
+
8
+ /**
9
+ * A DbmlProjectLayout backed by the Node.js filesystem.
10
+ * Reads source files on demand from disk; setSource/deleteSource maintain an
11
+ * in-memory overlay (e.g. for unsaved edits) without touching the real FS.
12
+ */
13
+ export class NodeProjectLayout implements DbmlProjectLayout {
14
+ // Overlay is an overriding map of file absolute paths to file content
15
+ // `null`: The file is deleted
16
+ private overlay = new Map<string, string | null>();
17
+ private entryPoints: Filepath[];
18
+
19
+ constructor (entryPoints: Filepath[]) {
20
+ this.entryPoints = [...entryPoints];
21
+ }
22
+
23
+ setSource (filePath: Filepath, content: string): void {
24
+ this.overlay.set(filePath.absolute, content);
25
+ }
26
+
27
+ getSource (filePath: Filepath): string | undefined {
28
+ const absolutePath = filePath.absolute;
29
+
30
+ // If overlay already has the file,
31
+ // return its content
32
+ if (this.overlay.has(absolutePath)) {
33
+ const value = this.overlay.get(absolutePath);
34
+ return value ?? undefined; // null (deleted) -> undefined
35
+ }
36
+ try {
37
+ return readFileSync(absolutePath, 'utf-8');
38
+ } catch {
39
+ return undefined;
40
+ }
41
+ }
42
+
43
+ deleteSource (filePath: Filepath): void {
44
+ this.overlay.set(filePath.absolute, null);
45
+ }
46
+
47
+ clearSource (): void {
48
+ this.overlay.clear();
49
+ this.entryPoints = [];
50
+ }
51
+
52
+ exists (filePath: Filepath): boolean {
53
+ return this.isFile(filePath) || this.isDirectory(filePath);
54
+ }
55
+
56
+ isFile (filePath: Filepath): boolean {
57
+ const absolutePath = filePath.absolute;
58
+
59
+ if (this.overlay.has(absolutePath)) return this.overlay.get(absolutePath) !== null;
60
+
61
+ try {
62
+ // `statSync` (not lstatSync) so symlinks resolve to their target, matching
63
+ // how node reads the file on disk.
64
+ return statSync(absolutePath).isFile();
65
+ } catch {
66
+ return false;
67
+ }
68
+ }
69
+
70
+ isDirectory (filePath: Filepath): boolean {
71
+ const absolutePath = filePath.absolute;
72
+
73
+ try {
74
+ // Exist in filesystem
75
+ if (statSync(absolutePath).isDirectory()) return true;
76
+ } catch {
77
+ // fall through: the path may exist only in the overlay
78
+ }
79
+ for (const [overlayPath, content] of this.overlay) {
80
+ if (content === null) continue;
81
+ if (overlayPath.startsWith(absolutePath)) return true;
82
+ }
83
+ return false;
84
+ }
85
+
86
+ listDirectory (dirPath?: Filepath): Filepath[] {
87
+ const basePath = dirPath?.absolute ?? '/';
88
+ const results = new Set<string>();
89
+
90
+ try {
91
+ // Filesystem entries
92
+ for (const entry of readdirSync(basePath)) {
93
+ results.add(basePath + entry);
94
+ }
95
+ } catch {
96
+ // Not a readable directory - ignore
97
+ }
98
+
99
+ // Overlay additions: non-deleted files directly under base
100
+ for (const [abs, content] of this.overlay) {
101
+ if (content === null) continue;
102
+ if (!abs.startsWith(basePath)) continue;
103
+ if (!abs.slice(basePath.length).includes('/')) results.add(abs);
104
+ }
105
+
106
+ // Remove overlay-deleted paths
107
+ for (const [overlayPath, content] of this.overlay) {
108
+ if (content === null) results.delete(overlayPath);
109
+ }
110
+
111
+ return [...results].sort().map(Filepath.from);
112
+ }
113
+
114
+ getEntryPoints (): Filepath[] {
115
+ return this.entryPoints.filter((fp) => this.exists(fp));
116
+ }
117
+
118
+ clone (): NodeProjectLayout {
119
+ const copy = new NodeProjectLayout([...this.entryPoints]);
120
+ for (const [overlayPath, content] of this.overlay) {
121
+ copy.overlay.set(overlayPath, content);
122
+ }
123
+ return copy;
124
+ }
125
+ }
package/src/cli/export.ts CHANGED
@@ -1,24 +1,23 @@
1
1
  import path from 'path';
2
2
  import {
3
- CompilerError, exporter,
4
- } from '@dbml/core';
5
- import type {
6
- ExportFormat,
3
+ ModelExporter, Parser,
7
4
  } from '@dbml/core';
5
+ import {
6
+ Compiler, Filepath,
7
+ } from '@dbml/parse';
8
8
  import chalk from 'chalk';
9
9
  import type {
10
10
  Command,
11
11
  } from 'commander';
12
12
  import figures from 'figures';
13
13
  import {
14
- SyntaxError,
15
- } from '../errors';
14
+ NodeProjectLayout,
15
+ } from '../NodeProjectLayout';
16
16
  import logger from '../helpers/logger';
17
17
  import config from './config';
18
18
  import OutputConsolePlugin from './outputPlugins/outputConsolePlugin';
19
19
  import OutputFilePlugin from './outputPlugins/outputFilePlugin';
20
20
  import {
21
- generate,
22
21
  getFormatOpt,
23
22
  resolvePaths,
24
23
  validateInputFilePaths,
@@ -27,35 +26,60 @@ import {
27
26
  validateFilePlugin,
28
27
  } from './validatePlugins/validatePlugins';
29
28
 
30
- export default async function exportHandler (program: Command) {
31
- try {
32
- const inputPaths = resolvePaths(program.args);
33
- validateInputFilePaths(inputPaths, validateFilePlugin);
34
- const opts = program.opts();
35
-
36
- const format = getFormatOpt(opts) as ExportFormat;
37
-
38
- if (!opts.outFile && !opts.outDir) {
39
- generate(inputPaths, (dbml) => exporter.export(dbml, format), OutputConsolePlugin);
40
- } else if (opts.outFile) {
41
- const header = [
42
- '-- SQL dump generated using DBML (dbml.dbdiagram.io)\n',
43
- `-- Database: ${config[format].name}\n`,
44
- `-- Generated at: ${new Date().toISOString()}\n\n`,
45
- ].join('');
46
-
47
- generate(
48
- inputPaths,
49
- (dbml) => exporter.export(dbml, format),
50
- new OutputFilePlugin(resolvePaths(opts.outFile), header),
51
- );
29
+ export default async function exportHandler (program: Command): Promise<void> {
30
+ const inputPaths = resolvePaths(program.args);
31
+ validateInputFilePaths(inputPaths, validateFilePlugin);
32
+ const opts = program.opts();
33
+ const format = getFormatOpt(opts);
34
+
35
+ const entryPoints = inputPaths.map((p: string) => new Filepath(p));
36
+ const compiler = new Compiler();
37
+ compiler.layout = new NodeProjectLayout(entryPoints);
38
+
39
+ const outputPlugin = opts.outFile
40
+ ? new OutputFilePlugin(
41
+ resolvePaths(opts.outFile as string),
42
+ [
43
+ '-- SQL dump generated using DBML (dbml.dbdiagram.io)\n',
44
+ `-- Database: ${(config as any)[format].name}\n`,
45
+ `-- Generated at: ${new Date().toISOString()}\n\n`,
46
+ ].join(''),
47
+ )
48
+ : OutputConsolePlugin;
49
+
50
+ let hasErrors = false;
52
51
 
53
- console.log(` ${chalk.green(figures.main.tick)} Generated SQL dump file (${config[format].name}): ${path.basename(opts.outFile)}`);
52
+ for (const filepath of entryPoints) {
53
+ const result = compiler.interpretFile(filepath);
54
+ const errors = result.getErrors();
55
+
56
+ if (errors.length > 0) {
57
+ hasErrors = true;
58
+ const isMultifile = compiler.reachableFiles(filepath).length > 1;
59
+ logger.error(
60
+ `\n ${errors
61
+ .map((e) => {
62
+ const pos = e.nodeOrToken.startPos;
63
+ const line = pos.line + 1;
64
+ const col = pos.column + 1;
65
+ if (isMultifile) {
66
+ return `${e.filepath.basename}(${line},${col}): ${e.message}`;
67
+ }
68
+ return `You have a syntax error at "${e.filepath.basename}" line ${line} column ${col}. ${e.message}`;
69
+ })
70
+ .join('\n ')}`,
71
+ );
72
+ continue;
54
73
  }
55
- } catch (error) {
56
- const e = error as CompilerError;
57
- logger.error(`\n ${e.diags.map((diag) => new SyntaxError(diag.filepath ?? '', diag)).map(({
58
- message,
59
- }) => message).join('\n ')}`);
74
+
75
+ const db = result.getValue();
76
+ if (!db) continue;
77
+
78
+ const sql = ModelExporter.export(Parser.parseJSONToDatabase(db as any), format);
79
+ outputPlugin.write(sql);
80
+ }
81
+
82
+ if (!hasErrors && opts.outFile) {
83
+ console.log(` ${chalk.green(figures.main.tick)} Generated SQL dump file (${(config as any)[format].name}): ${path.basename(opts.outFile)}`);
60
84
  }
61
85
  }
package/vite.config.ts CHANGED
@@ -25,6 +25,7 @@ export default defineConfig({
25
25
  external: [
26
26
  '@dbml/connector',
27
27
  '@dbml/core',
28
+ '@dbml/parse',
28
29
  'bluebird',
29
30
  'chalk',
30
31
  'commander',