@ddt-tools/cli 0.2.0 → 0.2.4

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 (203) hide show
  1. package/dist/advise-tests-YNMKVJCD.js +87 -0
  2. package/dist/advise-tests-YNMKVJCD.js.map +1 -0
  3. package/dist/ai-NTNPYEKZ.js +86 -0
  4. package/dist/ai-NTNPYEKZ.js.map +1 -0
  5. package/dist/anonymize-LERTWUQO.js +139 -0
  6. package/dist/anonymize-LERTWUQO.js.map +1 -0
  7. package/dist/approval-GGZGKIU4.js +73 -0
  8. package/dist/approval-GGZGKIU4.js.map +1 -0
  9. package/dist/approval-chain-GWJKZHVU.js +118 -0
  10. package/dist/approval-chain-GWJKZHVU.js.map +1 -0
  11. package/dist/audit-log-2PH55BU4.js +159 -0
  12. package/dist/audit-log-2PH55BU4.js.map +1 -0
  13. package/dist/backlog-QNXGOUF4.js +76 -0
  14. package/dist/backlog-QNXGOUF4.js.map +1 -0
  15. package/dist/bisect-W3XKKRWG.js +111 -0
  16. package/dist/bisect-W3XKKRWG.js.map +1 -0
  17. package/dist/bookmarks-XVOGXGMC.js +107 -0
  18. package/dist/bookmarks-XVOGXGMC.js.map +1 -0
  19. package/dist/branch-S3I2IJGQ.js +103 -0
  20. package/dist/branch-S3I2IJGQ.js.map +1 -0
  21. package/dist/build-MP3JQEFO.js +20 -0
  22. package/dist/build-MP3JQEFO.js.map +1 -0
  23. package/dist/catalog-3J3NFNXP.js +137 -0
  24. package/dist/catalog-3J3NFNXP.js.map +1 -0
  25. package/dist/changelog-ZQAH3ULB.js +216 -0
  26. package/dist/changelog-ZQAH3ULB.js.map +1 -0
  27. package/dist/chunk-2FT6HXKS.js +55 -0
  28. package/dist/chunk-2FT6HXKS.js.map +1 -0
  29. package/dist/chunk-DGUM43GV.js +11 -0
  30. package/dist/chunk-DGUM43GV.js.map +1 -0
  31. package/dist/chunk-DL3V7UJ2.js +25 -0
  32. package/dist/chunk-DL3V7UJ2.js.map +1 -0
  33. package/dist/chunk-VM2H4LAO.js +15 -0
  34. package/dist/chunk-VM2H4LAO.js.map +1 -0
  35. package/dist/chunk-XFXG347C.js +40 -0
  36. package/dist/chunk-XFXG347C.js.map +1 -0
  37. package/dist/cli.js +499 -19402
  38. package/dist/cli.js.map +1 -1
  39. package/dist/compare-P7JOV76O.js +379 -0
  40. package/dist/compare-P7JOV76O.js.map +1 -0
  41. package/dist/compare-profiles-H33CXZPD.js +219 -0
  42. package/dist/compare-profiles-H33CXZPD.js.map +1 -0
  43. package/dist/completion-ZSNCQKJ2.js +89 -0
  44. package/dist/completion-ZSNCQKJ2.js.map +1 -0
  45. package/dist/connection-CDGVEFUC.js +148 -0
  46. package/dist/connection-CDGVEFUC.js.map +1 -0
  47. package/dist/cost-estimate-S2MKHT2H.js +321 -0
  48. package/dist/cost-estimate-S2MKHT2H.js.map +1 -0
  49. package/dist/data-compare-46ZI7KHL.js +128 -0
  50. package/dist/data-compare-46ZI7KHL.js.map +1 -0
  51. package/dist/data-fit-WGEPLD5S.js +127 -0
  52. package/dist/data-fit-WGEPLD5S.js.map +1 -0
  53. package/dist/deploy-status-4H5KJFRC.js +58 -0
  54. package/dist/deploy-status-4H5KJFRC.js.map +1 -0
  55. package/dist/design-ILX3ZSWW.js +135 -0
  56. package/dist/design-ILX3ZSWW.js.map +1 -0
  57. package/dist/diagnose-WPUL67E4.js +150 -0
  58. package/dist/diagnose-WPUL67E4.js.map +1 -0
  59. package/dist/discover-DEO2R5T6.js +78 -0
  60. package/dist/discover-DEO2R5T6.js.map +1 -0
  61. package/dist/docs-QNY3MUVO.js +183 -0
  62. package/dist/docs-QNY3MUVO.js.map +1 -0
  63. package/dist/drift-FDRNPWQA.js +233 -0
  64. package/dist/drift-FDRNPWQA.js.map +1 -0
  65. package/dist/drift-gate-6BWWWMHW.js +103 -0
  66. package/dist/drift-gate-6BWWWMHW.js.map +1 -0
  67. package/dist/error-lookup-4R3Y4RBC.js +56 -0
  68. package/dist/error-lookup-4R3Y4RBC.js.map +1 -0
  69. package/dist/errorReporting-3LPE2IJY.js +109 -0
  70. package/dist/errorReporting-3LPE2IJY.js.map +1 -0
  71. package/dist/exec-JOLH5LPT.js +122 -0
  72. package/dist/exec-JOLH5LPT.js.map +1 -0
  73. package/dist/explain-NS26WE2Y.js +189 -0
  74. package/dist/explain-NS26WE2Y.js.map +1 -0
  75. package/dist/explorer-GSYYYOAL.js +58 -0
  76. package/dist/explorer-GSYYYOAL.js.map +1 -0
  77. package/dist/extract-4LWEZG4O.js +152 -0
  78. package/dist/extract-4LWEZG4O.js.map +1 -0
  79. package/dist/features-KQV4OFIZ.js +54 -0
  80. package/dist/features-KQV4OFIZ.js.map +1 -0
  81. package/dist/feedback-CBLGXUEG.js +158 -0
  82. package/dist/feedback-CBLGXUEG.js.map +1 -0
  83. package/dist/find-SMXRCZ76.js +176 -0
  84. package/dist/find-SMXRCZ76.js.map +1 -0
  85. package/dist/format-HMGG6MY3.js +277 -0
  86. package/dist/format-HMGG6MY3.js.map +1 -0
  87. package/dist/generate-W7VLBDLI.js +160 -0
  88. package/dist/generate-W7VLBDLI.js.map +1 -0
  89. package/dist/graph-YYL5UYCJ.js +168 -0
  90. package/dist/graph-YYL5UYCJ.js.map +1 -0
  91. package/dist/history-GDRFP4PG.js +184 -0
  92. package/dist/history-GDRFP4PG.js.map +1 -0
  93. package/dist/hosts-DRFZTMIJ.js +45 -0
  94. package/dist/hosts-DRFZTMIJ.js.map +1 -0
  95. package/dist/impact-A4NU6CB2.js +63 -0
  96. package/dist/impact-A4NU6CB2.js.map +1 -0
  97. package/dist/import-2RNYDL4E.js +79 -0
  98. package/dist/import-2RNYDL4E.js.map +1 -0
  99. package/dist/index.cjs +11 -5
  100. package/dist/index.cjs.map +1 -1
  101. package/dist/index.js +8 -2
  102. package/dist/index.js.map +1 -1
  103. package/dist/init-EAOGNGXI.js +54 -0
  104. package/dist/init-EAOGNGXI.js.map +1 -0
  105. package/dist/install-hooks-G3Y5LVXK.js +109 -0
  106. package/dist/install-hooks-G3Y5LVXK.js.map +1 -0
  107. package/dist/license-Z5YSC7XQ.js +43 -0
  108. package/dist/license-Z5YSC7XQ.js.map +1 -0
  109. package/dist/lineage-C5CGVP36.js +555 -0
  110. package/dist/lineage-C5CGVP36.js.map +1 -0
  111. package/dist/lint-AQFPZ3WG.js +144 -0
  112. package/dist/lint-AQFPZ3WG.js.map +1 -0
  113. package/dist/mcp-F7FND5X7.js +343 -0
  114. package/dist/mcp-F7FND5X7.js.map +1 -0
  115. package/dist/migrate-from-dbt-K4ELOWUD.js +156 -0
  116. package/dist/migrate-from-dbt-K4ELOWUD.js.map +1 -0
  117. package/dist/migrate-platform-E7VZFPO5.js +91 -0
  118. package/dist/migrate-platform-E7VZFPO5.js.map +1 -0
  119. package/dist/optimize-WUJ5ZN5Y.js +109 -0
  120. package/dist/optimize-WUJ5ZN5Y.js.map +1 -0
  121. package/dist/perf-UULZSREY.js +200 -0
  122. package/dist/perf-UULZSREY.js.map +1 -0
  123. package/dist/pii-QHU32VML.js +146 -0
  124. package/dist/pii-QHU32VML.js.map +1 -0
  125. package/dist/pilot-BR6GVK32.js +29 -0
  126. package/dist/pilot-BR6GVK32.js.map +1 -0
  127. package/dist/pr-comment-2FOA3EXG.js +81 -0
  128. package/dist/pr-comment-2FOA3EXG.js.map +1 -0
  129. package/dist/preview-XNY422OU.js +46 -0
  130. package/dist/preview-XNY422OU.js.map +1 -0
  131. package/dist/profile-SQTBNKYS.js +98 -0
  132. package/dist/profile-SQTBNKYS.js.map +1 -0
  133. package/dist/promote-FSGUPIPD.js +417 -0
  134. package/dist/promote-FSGUPIPD.js.map +1 -0
  135. package/dist/publish-AYCRMCE2.js +739 -0
  136. package/dist/publish-AYCRMCE2.js.map +1 -0
  137. package/dist/purge-Y5IOTXKA.js +56 -0
  138. package/dist/purge-Y5IOTXKA.js.map +1 -0
  139. package/dist/query-log-SDDGMJLJ.js +112 -0
  140. package/dist/query-log-SDDGMJLJ.js.map +1 -0
  141. package/dist/refactor-TC7S43F2.js +5809 -0
  142. package/dist/refactor-TC7S43F2.js.map +1 -0
  143. package/dist/refresh-MDJYOYV5.js +39 -0
  144. package/dist/refresh-MDJYOYV5.js.map +1 -0
  145. package/dist/replay-E4664A5K.js +118 -0
  146. package/dist/replay-E4664A5K.js.map +1 -0
  147. package/dist/revert-QWQWCJJB.js +111 -0
  148. package/dist/revert-QWQWCJJB.js.map +1 -0
  149. package/dist/review-7CAVLD67.js +164 -0
  150. package/dist/review-7CAVLD67.js.map +1 -0
  151. package/dist/rollback-suggest-C6D5YFCA.js +79 -0
  152. package/dist/rollback-suggest-C6D5YFCA.js.map +1 -0
  153. package/dist/safer-alternative-QR4QEFUV.js +84 -0
  154. package/dist/safer-alternative-QR4QEFUV.js.map +1 -0
  155. package/dist/safety-OFWUFLK4.js +165 -0
  156. package/dist/safety-OFWUFLK4.js.map +1 -0
  157. package/dist/savings-MEBE4TXI.js +95 -0
  158. package/dist/savings-MEBE4TXI.js.map +1 -0
  159. package/dist/scan-secrets-XCUBMLHL.js +54 -0
  160. package/dist/scan-secrets-XCUBMLHL.js.map +1 -0
  161. package/dist/schema-7JZIG6QR.js +447 -0
  162. package/dist/schema-7JZIG6QR.js.map +1 -0
  163. package/dist/script-BMYVBHFR.js +167 -0
  164. package/dist/script-BMYVBHFR.js.map +1 -0
  165. package/dist/search-TA3C3AZT.js +151 -0
  166. package/dist/search-TA3C3AZT.js.map +1 -0
  167. package/dist/seed-W4Q3L2IU.js +101 -0
  168. package/dist/seed-W4Q3L2IU.js.map +1 -0
  169. package/dist/sketch-6B2V6FJV.js +83 -0
  170. package/dist/sketch-6B2V6FJV.js.map +1 -0
  171. package/dist/snapshot-YMVS322L.js +171 -0
  172. package/dist/snapshot-YMVS322L.js.map +1 -0
  173. package/dist/snippets-EVTN63OU.js +74 -0
  174. package/dist/snippets-EVTN63OU.js.map +1 -0
  175. package/dist/standards-FGJW3CQL.js +238 -0
  176. package/dist/standards-FGJW3CQL.js.map +1 -0
  177. package/dist/suggest-V3LVIFZ5.js +44 -0
  178. package/dist/suggest-V3LVIFZ5.js.map +1 -0
  179. package/dist/suggest-constraints-EX2FCWOQ.js +154 -0
  180. package/dist/suggest-constraints-EX2FCWOQ.js.map +1 -0
  181. package/dist/suite-YTQ3CNX5.js +85 -0
  182. package/dist/suite-YTQ3CNX5.js.map +1 -0
  183. package/dist/telemetry-KOIY3NEQ.js +90 -0
  184. package/dist/telemetry-KOIY3NEQ.js.map +1 -0
  185. package/dist/template-MUJ6X6LN.js +396 -0
  186. package/dist/template-MUJ6X6LN.js.map +1 -0
  187. package/dist/test-XFSQHR2S.js +169 -0
  188. package/dist/test-XFSQHR2S.js.map +1 -0
  189. package/dist/trial-GFTGYCR3.js +31 -0
  190. package/dist/trial-GFTGYCR3.js.map +1 -0
  191. package/dist/validate-LFDEZFFH.js +107 -0
  192. package/dist/validate-LFDEZFFH.js.map +1 -0
  193. package/dist/verify-KRDYOJCR.js +76 -0
  194. package/dist/verify-KRDYOJCR.js.map +1 -0
  195. package/dist/watch-FSG23RR3.js +80 -0
  196. package/dist/watch-FSG23RR3.js.map +1 -0
  197. package/dist/xcompare-U4TXTTIR.js +87 -0
  198. package/dist/xcompare-U4TXTTIR.js.map +1 -0
  199. package/package.json +2 -2
  200. package/dist/cli.cjs +0 -19298
  201. package/dist/cli.cjs.map +0 -1
  202. package/dist/cli.d.cts +0 -1
  203. package/dist/cli.d.ts +0 -1
@@ -0,0 +1,447 @@
1
+ import "./chunk-DGUM43GV.js";
2
+
3
+ // src/commands/schema.ts
4
+ import { promises as fs } from "fs";
5
+ import path from "path";
6
+ import { Command } from "commander";
7
+ import {
8
+ interop,
9
+ loadProject,
10
+ pac,
11
+ parseProjectModel,
12
+ schema,
13
+ validate as validateNs
14
+ } from "@ddt-tools/core";
15
+ function schemaCommand() {
16
+ const cmd = new Command("schema").description(
17
+ "Interop with third-party schema formats (DBML import/export; draw.io export). NOT a separate data modeler \u2014 DDT remains the canonical model."
18
+ );
19
+ cmd.command("import-dbml <file>").description("Import a DBML file and emit Databricks CREATE TABLE files.").option("-o, --out <path>", "Output directory. Default ./imported/.").action(async (filePath, opts) => {
20
+ const text = await fs.readFile(path.resolve(String(filePath)), "utf8");
21
+ const doc = schema.parseDbml(text);
22
+ const out = opts.out ? path.resolve(String(opts.out)) : path.resolve("imported");
23
+ await fs.mkdir(out, { recursive: true });
24
+ let written = 0;
25
+ for (const t of doc.tables) {
26
+ const ddl = renderTableDdl(t, doc.refs);
27
+ const dir = path.join(out, "main", t.schema, "tables");
28
+ await fs.mkdir(dir, { recursive: true });
29
+ const file = path.join(dir, `${t.name}.sql`);
30
+ await fs.writeFile(file, ddl, "utf8");
31
+ written++;
32
+ }
33
+ console.error(`Imported ${written} table(s) from ${filePath} into ${out}.`);
34
+ console.error(`Catalog defaulted to main; rename the top-level folder if needed.`);
35
+ });
36
+ cmd.command("export-dbml").description(
37
+ "Emit DBML text from a project model. Lossy projection \u2014 UC-specific features become comments."
38
+ ).requiredOption("--source <path>", ".ddtproj or .ddtpac to export.").option("-o, --out <path>", "Output file. Defaults to stdout.").action(async (opts) => {
39
+ const model = await loadModel(String(opts.source));
40
+ const text = schema.emitDbml(model);
41
+ await emit(text, opts.out);
42
+ });
43
+ cmd.command("export-drawio").description(
44
+ "Emit a draw.io / diagrams.net XML file from a project model. Open in any diagrams.net editor."
45
+ ).requiredOption("--source <path>", ".ddtproj or .ddtpac to export.").option("-o, --out <path>", "Output file. Defaults to ./schema.drawio.").option(
46
+ "--columns <n>",
47
+ "Grid columns (used when --auto-layout is off). Default 4.",
48
+ (v) => parseInt(v, 10)
49
+ ).option(
50
+ "--auto-layout",
51
+ "Apply force-directed layout \u2014 connected tables cluster together. Default: alphabetical grid."
52
+ ).option(
53
+ "--print",
54
+ "Print-friendly mode: monochrome palette, US Letter landscape page settings."
55
+ ).action(async (opts) => {
56
+ const model = await loadModel(String(opts.source));
57
+ const text = schema.emitDrawio(model, {
58
+ ...typeof opts.columns === "number" ? { columns: opts.columns } : {},
59
+ ...opts.autoLayout ? { autoLayout: true } : {},
60
+ ...opts.print ? { print: true } : {}
61
+ });
62
+ const outPath = opts.out ? path.resolve(String(opts.out)) : path.resolve("schema.drawio");
63
+ await fs.mkdir(path.dirname(outPath), { recursive: true });
64
+ await fs.writeFile(outPath, text, "utf8");
65
+ const flags = [opts.autoLayout && "auto-layout", opts.print && "print-mode"].filter(Boolean).join(", ") || "default";
66
+ console.error(
67
+ `Wrote ${outPath} (${text.length} bytes). Flags: ${flags}. Open in any draw.io / diagrams.net editor.`
68
+ );
69
+ });
70
+ for (const fmt of [
71
+ {
72
+ name: "jsonschema",
73
+ emit: interop.emitJsonSchema,
74
+ ext: "json",
75
+ why: "API contracts, NoSQL, payload validation."
76
+ },
77
+ {
78
+ name: "avro",
79
+ emit: interop.emitAvro,
80
+ ext: "avsc",
81
+ why: "Kafka / streaming pipelines with schema-registry."
82
+ },
83
+ {
84
+ name: "protobuf",
85
+ emit: interop.emitProtobuf,
86
+ ext: "proto",
87
+ why: "gRPC services, cross-language data contracts."
88
+ },
89
+ {
90
+ name: "graphql",
91
+ emit: interop.emitGraphqlSdl,
92
+ ext: "graphql",
93
+ why: "GraphQL APIs that expose the schema."
94
+ },
95
+ {
96
+ name: "plantuml",
97
+ emit: interop.emitPlantumlEr,
98
+ ext: "puml",
99
+ why: "Text-based ER diagrams (alternative to Mermaid)."
100
+ },
101
+ {
102
+ name: "typescript",
103
+ emit: interop.emitTypescript,
104
+ ext: "ts",
105
+ why: "Generate TypeScript interfaces for app code."
106
+ },
107
+ {
108
+ name: "pydantic",
109
+ emit: interop.emitPydantic,
110
+ ext: "py",
111
+ why: "Generate Pydantic models for Python apps."
112
+ },
113
+ { name: "java", emit: interop.emitJavaDto, ext: "java", why: "Generate Java record DTOs." },
114
+ {
115
+ name: "markdown",
116
+ emit: interop.emitMarkdownDocs,
117
+ ext: "md",
118
+ why: "Schema docs rendered by GitHub / GitLab."
119
+ },
120
+ {
121
+ name: "html",
122
+ emit: interop.emitHtmlDocs,
123
+ ext: "html",
124
+ why: "Self-contained schema-docs page for distribution."
125
+ }
126
+ ]) {
127
+ cmd.command(`export-${fmt.name}`).description(`Emit ${fmt.name.toUpperCase()} from the project model. Use: ${fmt.why}`).requiredOption("--source <path>", ".ddtproj or .ddtpac to export.").option("-o, --out <path>", `Output file. Defaults to ./schema.${fmt.ext}.`).action(async (opts) => {
128
+ const model = await loadModel(String(opts.source));
129
+ const text = fmt.emit(model);
130
+ const outPath = opts.out ? path.resolve(String(opts.out)) : path.resolve(`schema.${fmt.ext}`);
131
+ await fs.mkdir(path.dirname(outPath), { recursive: true });
132
+ await fs.writeFile(outPath, text, "utf8");
133
+ console.error(`Wrote ${outPath} (${text.length} bytes).`);
134
+ });
135
+ }
136
+ cmd.command("validate-star").description(
137
+ "Validate a star schema rooted at a fact table. Classifies each connected dim by SCD type, reports FK coverage + naming issues."
138
+ ).requiredOption("--source <path>", ".ddtproj or .ddtpac containing the star.").requiredOption("--root <fqn>", "Fully-qualified fact-table FQN (catalog.schema.fact_name).").option("--format <fmt>", "table | json | markdown. Default table.", "table").option("-o, --out <path>", "Output file. Defaults to stdout.").action(async (opts) => {
139
+ const model = await loadModel(String(opts.source));
140
+ const report = validateNs.validateStar(model, String(opts.root), {
141
+ source: String(opts.source)
142
+ });
143
+ const fmt = String(opts.format ?? "table").toLowerCase();
144
+ let payload;
145
+ if (fmt === "json") {
146
+ payload = JSON.stringify(report, null, 2);
147
+ } else if (fmt === "markdown") {
148
+ payload = renderStarMarkdown(report);
149
+ } else if (fmt === "table") {
150
+ payload = validateNs.formatStarReport(report);
151
+ } else {
152
+ throw new Error(`Unknown --format: ${fmt}. Use table | json | markdown.`);
153
+ }
154
+ await emit(payload, opts.out);
155
+ if (!report.factExists || report.issues.length > 0) {
156
+ process.exitCode = 1;
157
+ }
158
+ });
159
+ cmd.command("suggest-snowflake-schema").description(
160
+ "Propose snowflake-schema refactors: detect column groups on star dims that look like candidates for extraction (geography, category, org)."
161
+ ).requiredOption("--source <path>", ".ddtproj or .ddtpac containing the star.").requiredOption("--root <fqn>", "Fully-qualified fact-table FQN (catalog.schema.fact_name).").option("--format <fmt>", "table | json | markdown. Default table.", "table").option("-o, --out <path>", "Output file. Defaults to stdout.").action(async (opts) => {
162
+ const model = await loadModel(String(opts.source));
163
+ const proposal = validateNs.proposeSnowflakeSchema(model, String(opts.root), {
164
+ source: String(opts.source)
165
+ });
166
+ const fmt = String(opts.format ?? "table").toLowerCase();
167
+ let payload;
168
+ if (fmt === "json") {
169
+ payload = JSON.stringify(proposal, null, 2);
170
+ } else if (fmt === "markdown") {
171
+ payload = renderSnowflakeSchemaMarkdown(proposal);
172
+ } else if (fmt === "table") {
173
+ payload = validateNs.formatSnowflakeSchemaProposal(proposal);
174
+ } else {
175
+ throw new Error(`Unknown --format: ${fmt}. Use table | json | markdown.`);
176
+ }
177
+ await emit(payload, opts.out);
178
+ });
179
+ cmd.command("infer-csv <file>").description(
180
+ "Read a CSV sample and emit a Databricks CREATE TABLE with heuristic type inference. Review before deploy."
181
+ ).requiredOption(
182
+ "--name <fqn>",
183
+ "Fully-qualified table name (catalog.schema.table or schema.table)."
184
+ ).option("--delimiter <char>", "CSV delimiter. Default: comma.", ",").option(
185
+ "--no-header",
186
+ "Treat the first row as data, not header. Generated column names: column_1, column_2, \u2026"
187
+ ).option("--max-sample-rows <n>", "Cap on rows sampled. Default 1000.", (v) => parseInt(v, 10)).option(
188
+ "--or-replace",
189
+ "Emit CREATE OR REPLACE TABLE instead of CREATE TABLE IF NOT EXISTS.",
190
+ false
191
+ ).option(
192
+ "--using <format>",
193
+ "Storage format (DELTA / PARQUET / CSV / JSON / ICEBERG). Default DELTA.",
194
+ "DELTA"
195
+ ).option("-o, --out <path>", "Output file. Defaults to stdout.").action(async (filePath, opts) => {
196
+ const text = await fs.readFile(path.resolve(String(filePath)), "utf8");
197
+ const inferred = schema.inferSchemaFromCsv(
198
+ text,
199
+ {
200
+ delimiter: String(opts.delimiter),
201
+ hasHeader: opts.header !== false,
202
+ ...typeof opts.maxSampleRows === "number" ? { maxSampleRows: opts.maxSampleRows } : {}
203
+ },
204
+ path.basename(String(filePath))
205
+ );
206
+ const parts = String(opts.name).split(".").filter(Boolean);
207
+ const fqn = parts.length === 3 ? { database: parts[0], schema: parts[1], name: parts[2] } : parts.length === 2 ? { schema: parts[0], name: parts[1] } : { name: parts[0] ?? "inferred_table" };
208
+ const ddl = schema.renderCreateTable(inferred, {
209
+ fqn,
210
+ orReplace: !!opts.orReplace,
211
+ using: String(opts.using)
212
+ });
213
+ await emit(ddl, opts.out);
214
+ console.error(
215
+ `Sampled ${inferred.sampleRowCount} row(s); inferred ${inferred.columns.length} column(s).`
216
+ );
217
+ const allNull = inferred.columns.filter((c) => c.allNull);
218
+ if (allNull.length > 0) {
219
+ console.error(
220
+ `Warning: ${allNull.length} column(s) had no values in the sample \u2014 types defaulted to STRING. Review the generated DDL.`
221
+ );
222
+ }
223
+ });
224
+ cmd.command("infer-parquet <file>").description(
225
+ "Read a Parquet file's metadata footer and emit a Databricks CREATE TABLE. No data is read \u2014 only the schema header."
226
+ ).requiredOption(
227
+ "--name <fqn>",
228
+ "Fully-qualified table name (catalog.schema.table or schema.table)."
229
+ ).option(
230
+ "--or-replace",
231
+ "Emit CREATE OR REPLACE TABLE instead of CREATE TABLE IF NOT EXISTS.",
232
+ false
233
+ ).option(
234
+ "--using <format>",
235
+ "Storage format (DELTA / PARQUET / ICEBERG / ...). Default DELTA.",
236
+ "DELTA"
237
+ ).option("-o, --out <path>", "Output file. Defaults to stdout.").action(async (filePath, opts) => {
238
+ const buf = await fs.readFile(path.resolve(String(filePath)));
239
+ const inferred = await schema.inferSchemaFromParquet(buf, path.basename(String(filePath)));
240
+ const parts = String(opts.name).split(".").filter(Boolean);
241
+ const fqn = parts.length === 3 ? { database: parts[0], schema: parts[1], name: parts[2] } : parts.length === 2 ? { schema: parts[0], name: parts[1] } : { name: parts[0] ?? "inferred_table" };
242
+ const ddl = schema.renderCreateTable(inferred, {
243
+ fqn,
244
+ orReplace: !!opts.orReplace,
245
+ using: String(opts.using)
246
+ });
247
+ await emit(ddl, opts.out);
248
+ console.error(
249
+ `Parquet schema: ${inferred.columns.length} column(s); reported ${inferred.sampleRowCount} row(s) in metadata.`
250
+ );
251
+ });
252
+ cmd.command("import-ddl <file>").description(
253
+ 'Universal DDL importer \u2014 parse any CREATE TABLE statements (erwin / ER/Studio / PowerDesigner / DbSchema / Hackolade / Visio / DataGrip all "Forward Engineer to Script"; we read it).'
254
+ ).option("-o, --out <path>", "Output directory. Default ./imported/.").action(async (filePath, opts) => {
255
+ const text = await fs.readFile(path.resolve(String(filePath)), "utf8");
256
+ const result = interop.parseUniversalDdl(text);
257
+ await writeImportedTables(
258
+ result,
259
+ opts.out ? path.resolve(String(opts.out)) : path.resolve("imported")
260
+ );
261
+ });
262
+ cmd.command("import-jsonschema <file>").description("Import a JSON Schema document; each top-level object schema becomes a table.").option("-o, --out <path>", "Output directory. Default ./imported/.").action(async (filePath, opts) => {
263
+ const text = await fs.readFile(path.resolve(String(filePath)), "utf8");
264
+ const result = interop.parseJsonSchema(text);
265
+ await writeImportedTables(
266
+ result,
267
+ opts.out ? path.resolve(String(opts.out)) : path.resolve("imported")
268
+ );
269
+ });
270
+ cmd.command("import-dbt <file>").description("Import a dbt-generated manifest.json; each model/seed/source becomes a table.").option("-o, --out <path>", "Output directory. Default ./imported/.").action(async (filePath, opts) => {
271
+ const text = await fs.readFile(path.resolve(String(filePath)), "utf8");
272
+ const result = interop.parseDbtManifest(text);
273
+ await writeImportedTables(
274
+ result,
275
+ opts.out ? path.resolve(String(opts.out)) : path.resolve("imported")
276
+ );
277
+ });
278
+ return cmd;
279
+ }
280
+ async function writeImportedTables(result, outDir) {
281
+ await fs.mkdir(outDir, { recursive: true });
282
+ let written = 0;
283
+ for (const t of result.tables) {
284
+ const catalog = t.database ?? "main";
285
+ const sch = t.schema ?? "default";
286
+ const dir = path.join(outDir, catalog, sch, "tables");
287
+ await fs.mkdir(dir, { recursive: true });
288
+ const file = path.join(dir, `${t.name}.sql`);
289
+ const colDdl = t.columns.map((c) => {
290
+ const mods = [];
291
+ if (c.nullable === false) mods.push("NOT NULL");
292
+ if (c.default) mods.push(`DEFAULT ${c.default}`);
293
+ return ` ${c.name.padEnd(28)} ${databricksType(c.dataType)}${mods.length > 0 ? " " + mods.join(" ") : ""}${c.comment ? ` COMMENT '${c.comment.replace(/'/g, "''")}'` : ""}`;
294
+ }).join(",\n");
295
+ const ddl = `-- Imported by \`ddt schema import-*\` from source: ${result.source}.
296
+ -- Review and refine; DDT is the canonical model from here on.
297
+
298
+ CREATE OR REPLACE TABLE ${catalog}.${sch}.${t.name} (
299
+ ${colDdl}
300
+ )
301
+ USING DELTA
302
+ TBLPROPERTIES ('delta.enableDeletionVectors' = 'true')${t.comment ? `
303
+ COMMENT '${t.comment.replace(/'/g, "''")}'` : ""};
304
+ `;
305
+ await fs.writeFile(file, ddl, "utf8");
306
+ written++;
307
+ }
308
+ console.error(`Imported ${written} table(s) into ${outDir}.`);
309
+ if (result.warnings.length > 0) {
310
+ console.error("Warnings (review before deploy):");
311
+ for (const w of result.warnings) console.error(` - ${w}`);
312
+ }
313
+ }
314
+ function databricksType(dbmlType) {
315
+ const t = dbmlType.toLowerCase().trim();
316
+ if (t === "int" || t === "integer" || t === "serial") return "INT";
317
+ if (t === "bigint" || t.startsWith("number")) return "BIGINT";
318
+ if (t === "smallint") return "SMALLINT";
319
+ if (t === "decimal" || t === "numeric") return "DECIMAL(38,9)";
320
+ if (t === "float" || t === "double") return "DOUBLE";
321
+ if (t === "boolean" || t === "bool") return "BOOLEAN";
322
+ if (t === "date") return "DATE";
323
+ if (t === "datetime" || t === "timestamp" || t === "timestamp_ntz") return "TIMESTAMP";
324
+ if (t === "text" || t === "string" || t.startsWith("varchar")) return "STRING";
325
+ if (t === "variant" || t === "json" || t === "jsonb") return "MAP<STRING, STRING>";
326
+ if (t === "array") return "ARRAY<STRING>";
327
+ if (t === "uuid") return "STRING";
328
+ return dbmlType.toUpperCase();
329
+ }
330
+ function renderTableDdl(t, refs) {
331
+ const lines = [];
332
+ lines.push(`-- Imported from DBML by \`ddt schema import-dbml\`.`);
333
+ lines.push(`-- Review and refine; DDT is the canonical model from here on.`);
334
+ if (t.note) lines.push(`-- ${t.note}`);
335
+ lines.push("");
336
+ const colDdl = t.columns.map((c) => {
337
+ const mods = [];
338
+ if (c.notNull) mods.push("NOT NULL");
339
+ if (c.default) mods.push(`DEFAULT ${c.default}`);
340
+ return ` ${c.name.padEnd(28)} ${databricksType(c.type)}${mods.length > 0 ? " " + mods.join(" ") : ""}${c.note ? ` COMMENT '${c.note.replace(/'/g, "''")}'` : ""}`;
341
+ });
342
+ const tableRefs = refs.filter(
343
+ (r) => r.from.toLowerCase().startsWith(`${t.schema.toLowerCase()}.${t.name.toLowerCase()}.`)
344
+ );
345
+ if (tableRefs.length > 0) {
346
+ lines.push(`-- Inferred references (UC doesn't enforce FKs; this is metadata only):`);
347
+ for (const r of tableRefs) lines.push(`-- ${r.from} ${r.cardinality} ${r.to}`);
348
+ lines.push("");
349
+ }
350
+ lines.push(`CREATE OR REPLACE TABLE main.${t.schema}.${t.name} (`);
351
+ lines.push(colDdl.join(",\n"));
352
+ lines.push(")");
353
+ lines.push(`USING DELTA`);
354
+ lines.push(`TBLPROPERTIES ('delta.enableDeletionVectors' = 'true')`);
355
+ if (t.note) lines.push(`COMMENT '${t.note.replace(/'/g, "''")}'`);
356
+ lines.push(";\n");
357
+ return lines.join("\n");
358
+ }
359
+ function renderSnowflakeSchemaMarkdown(p) {
360
+ const lines = [];
361
+ lines.push(`# Snowflake-schema refactor proposal \u2014 \`${p.fact}\``);
362
+ lines.push("");
363
+ lines.push(`Generated: ${p.generatedAt}`);
364
+ if (p.source) lines.push(`Source: \`${p.source}\``);
365
+ lines.push("");
366
+ if (!p.factExists) {
367
+ lines.push(`**Fact not found in the project.**`);
368
+ return lines.join("\n");
369
+ }
370
+ if (p.dims.length === 0) {
371
+ lines.push("_No refactor candidates detected._");
372
+ return lines.join("\n");
373
+ }
374
+ for (const d of p.dims) {
375
+ lines.push(`## \`${d.dim}\` (${d.scdType})`);
376
+ lines.push("");
377
+ for (const g of d.groups) {
378
+ lines.push(`### ${g.kind} \u2014 columns: \`${g.columns.join("`, `")}\``);
379
+ lines.push("");
380
+ if (g.proposedDim) {
381
+ lines.push(`**Proposal:** extract to \`${g.proposedDim}\`.`);
382
+ } else {
383
+ lines.push(`**Proposal:** keep on parent dim (audit metadata).`);
384
+ }
385
+ lines.push("");
386
+ lines.push(`*Why:* ${g.reasoning}`);
387
+ lines.push("");
388
+ }
389
+ }
390
+ return lines.join("\n");
391
+ }
392
+ function renderStarMarkdown(report) {
393
+ const lines = [];
394
+ lines.push(`# Star validation \u2014 \`${report.fact}\``);
395
+ lines.push("");
396
+ lines.push(`Generated: ${report.generatedAt}`);
397
+ if (report.source) lines.push(`Source: \`${report.source}\``);
398
+ lines.push("");
399
+ if (!report.factExists) {
400
+ lines.push(`**${report.issues[0]}**`);
401
+ return lines.join("\n");
402
+ }
403
+ lines.push(
404
+ `**Fan-out:** ${report.fanOut} \xB7 **CLUSTER BY:** ${report.clusterBy.length > 0 ? report.clusterBy.join(", ") : "_none_"}`
405
+ );
406
+ lines.push("");
407
+ if (report.dimensions.length > 0) {
408
+ lines.push("## Dimensions");
409
+ lines.push("");
410
+ lines.push("| Dim | SCD Type | Business Key | Notes |");
411
+ lines.push("| --- | --- | --- | --- |");
412
+ for (const d of report.dimensions) {
413
+ lines.push(
414
+ `| \`${d.fqn}\` | ${d.scdType} | ${d.bk ? `\`${d.bk}\`` : "_none_"} | ${d.reasons.join("; ")} |`
415
+ );
416
+ }
417
+ lines.push("");
418
+ }
419
+ if (report.issues.length > 0) {
420
+ lines.push("## Issues");
421
+ lines.push("");
422
+ for (const i of report.issues) lines.push(`- \u26A0\uFE0F ${i}`);
423
+ }
424
+ return lines.join("\n");
425
+ }
426
+ async function loadModel(sourcePath) {
427
+ if (sourcePath.endsWith(".ddtpac")) {
428
+ const c = await pac.readPac(sourcePath);
429
+ return c.model;
430
+ }
431
+ const loaded = await loadProject(sourcePath);
432
+ return await parseProjectModel(loaded);
433
+ }
434
+ async function emit(text, out) {
435
+ if (out) {
436
+ const p = path.resolve(String(out));
437
+ await fs.mkdir(path.dirname(p), { recursive: true });
438
+ await fs.writeFile(p, text + (text.endsWith("\n") ? "" : "\n"), "utf8");
439
+ console.error(`Wrote ${p}.`);
440
+ } else {
441
+ process.stdout.write(text + (text.endsWith("\n") ? "" : "\n"));
442
+ }
443
+ }
444
+ export {
445
+ schemaCommand
446
+ };
447
+ //# sourceMappingURL=schema-7JZIG6QR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/schema.ts"],"sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { Command } from 'commander';\nimport {\n interop,\n loadProject,\n pac,\n parseProjectModel,\n schema,\n validate as validateNs,\n type DatabricksObject,\n} from '@ddt-tools/core';\n\n/**\n * `ddt schema` — interop with third-party schema-modeling formats.\n * Mirrors `sdt schema`. See root NOTICE for the interop attribution\n * and the \"what this product is NOT\" statement.\n */\nexport function schemaCommand(): Command {\n const cmd = new Command('schema').description(\n 'Interop with third-party schema formats (DBML import/export; draw.io export). NOT a separate data modeler — DDT remains the canonical model.',\n );\n\n cmd\n .command('import-dbml <file>')\n .description('Import a DBML file and emit Databricks CREATE TABLE files.')\n .option('-o, --out <path>', 'Output directory. Default ./imported/.')\n .action(async (filePath, opts) => {\n const text = await fs.readFile(path.resolve(String(filePath)), 'utf8');\n const doc = schema.parseDbml(text);\n const out = opts.out ? path.resolve(String(opts.out)) : path.resolve('imported');\n await fs.mkdir(out, { recursive: true });\n let written = 0;\n for (const t of doc.tables) {\n const ddl = renderTableDdl(t, doc.refs);\n const dir = path.join(out, 'main', t.schema, 'tables');\n await fs.mkdir(dir, { recursive: true });\n const file = path.join(dir, `${t.name}.sql`);\n await fs.writeFile(file, ddl, 'utf8');\n written++;\n }\n console.error(`Imported ${written} table(s) from ${filePath} into ${out}.`);\n console.error(`Catalog defaulted to main; rename the top-level folder if needed.`);\n });\n\n cmd\n .command('export-dbml')\n .description(\n 'Emit DBML text from a project model. Lossy projection — UC-specific features become comments.',\n )\n .requiredOption('--source <path>', '.ddtproj or .ddtpac to export.')\n .option('-o, --out <path>', 'Output file. Defaults to stdout.')\n .action(async (opts) => {\n const model = await loadModel(String(opts.source));\n const text = schema.emitDbml(model);\n await emit(text, opts.out);\n });\n\n cmd\n .command('export-drawio')\n .description(\n 'Emit a draw.io / diagrams.net XML file from a project model. Open in any diagrams.net editor.',\n )\n .requiredOption('--source <path>', '.ddtproj or .ddtpac to export.')\n .option('-o, --out <path>', 'Output file. Defaults to ./schema.drawio.')\n .option('--columns <n>', 'Grid columns (used when --auto-layout is off). Default 4.', (v) =>\n parseInt(v, 10),\n )\n .option(\n '--auto-layout',\n 'Apply force-directed layout — connected tables cluster together. Default: alphabetical grid.',\n )\n .option(\n '--print',\n 'Print-friendly mode: monochrome palette, US Letter landscape page settings.',\n )\n .action(async (opts) => {\n const model = await loadModel(String(opts.source));\n const text = schema.emitDrawio(model, {\n ...(typeof opts.columns === 'number' ? { columns: opts.columns } : {}),\n ...(opts.autoLayout ? { autoLayout: true } : {}),\n ...(opts.print ? { print: true } : {}),\n });\n const outPath = opts.out ? path.resolve(String(opts.out)) : path.resolve('schema.drawio');\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, text, 'utf8');\n const flags =\n [opts.autoLayout && 'auto-layout', opts.print && 'print-mode'].filter(Boolean).join(', ') ||\n 'default';\n console.error(\n `Wrote ${outPath} (${text.length} bytes). Flags: ${flags}. Open in any draw.io / diagrams.net editor.`,\n );\n });\n\n // ─── Multi-format emitters ───\n for (const fmt of [\n {\n name: 'jsonschema',\n emit: interop.emitJsonSchema,\n ext: 'json',\n why: 'API contracts, NoSQL, payload validation.',\n },\n {\n name: 'avro',\n emit: interop.emitAvro,\n ext: 'avsc',\n why: 'Kafka / streaming pipelines with schema-registry.',\n },\n {\n name: 'protobuf',\n emit: interop.emitProtobuf,\n ext: 'proto',\n why: 'gRPC services, cross-language data contracts.',\n },\n {\n name: 'graphql',\n emit: interop.emitGraphqlSdl,\n ext: 'graphql',\n why: 'GraphQL APIs that expose the schema.',\n },\n {\n name: 'plantuml',\n emit: interop.emitPlantumlEr,\n ext: 'puml',\n why: 'Text-based ER diagrams (alternative to Mermaid).',\n },\n {\n name: 'typescript',\n emit: interop.emitTypescript,\n ext: 'ts',\n why: 'Generate TypeScript interfaces for app code.',\n },\n {\n name: 'pydantic',\n emit: interop.emitPydantic,\n ext: 'py',\n why: 'Generate Pydantic models for Python apps.',\n },\n { name: 'java', emit: interop.emitJavaDto, ext: 'java', why: 'Generate Java record DTOs.' },\n {\n name: 'markdown',\n emit: interop.emitMarkdownDocs,\n ext: 'md',\n why: 'Schema docs rendered by GitHub / GitLab.',\n },\n {\n name: 'html',\n emit: interop.emitHtmlDocs,\n ext: 'html',\n why: 'Self-contained schema-docs page for distribution.',\n },\n ]) {\n cmd\n .command(`export-${fmt.name}`)\n .description(`Emit ${fmt.name.toUpperCase()} from the project model. Use: ${fmt.why}`)\n .requiredOption('--source <path>', '.ddtproj or .ddtpac to export.')\n .option('-o, --out <path>', `Output file. Defaults to ./schema.${fmt.ext}.`)\n .action(async (opts) => {\n const model = await loadModel(String(opts.source));\n const text = fmt.emit(model);\n const outPath = opts.out\n ? path.resolve(String(opts.out))\n : path.resolve(`schema.${fmt.ext}`);\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, text, 'utf8');\n console.error(`Wrote ${outPath} (${text.length} bytes).`);\n });\n }\n\n // ─── Star-schema validator ───\n cmd\n .command('validate-star')\n .description(\n 'Validate a star schema rooted at a fact table. Classifies each connected dim by SCD type, reports FK coverage + naming issues.',\n )\n .requiredOption('--source <path>', '.ddtproj or .ddtpac containing the star.')\n .requiredOption('--root <fqn>', 'Fully-qualified fact-table FQN (catalog.schema.fact_name).')\n .option('--format <fmt>', 'table | json | markdown. Default table.', 'table')\n .option('-o, --out <path>', 'Output file. Defaults to stdout.')\n .action(async (opts) => {\n const model = await loadModel(String(opts.source));\n const report = validateNs.validateStar(model, String(opts.root), {\n source: String(opts.source),\n });\n\n const fmt = String(opts.format ?? 'table').toLowerCase();\n let payload: string;\n if (fmt === 'json') {\n payload = JSON.stringify(report, null, 2);\n } else if (fmt === 'markdown') {\n payload = renderStarMarkdown(report);\n } else if (fmt === 'table') {\n payload = validateNs.formatStarReport(report);\n } else {\n throw new Error(`Unknown --format: ${fmt}. Use table | json | markdown.`);\n }\n await emit(payload, opts.out);\n\n if (!report.factExists || report.issues.length > 0) {\n process.exitCode = 1;\n }\n });\n\n // ─── Snowflake-schema refactor proposer ───\n cmd\n .command('suggest-snowflake-schema')\n .description(\n 'Propose snowflake-schema refactors: detect column groups on star dims that look like candidates for extraction (geography, category, org).',\n )\n .requiredOption('--source <path>', '.ddtproj or .ddtpac containing the star.')\n .requiredOption('--root <fqn>', 'Fully-qualified fact-table FQN (catalog.schema.fact_name).')\n .option('--format <fmt>', 'table | json | markdown. Default table.', 'table')\n .option('-o, --out <path>', 'Output file. Defaults to stdout.')\n .action(async (opts) => {\n const model = await loadModel(String(opts.source));\n const proposal = validateNs.proposeSnowflakeSchema(model, String(opts.root), {\n source: String(opts.source),\n });\n\n const fmt = String(opts.format ?? 'table').toLowerCase();\n let payload: string;\n if (fmt === 'json') {\n payload = JSON.stringify(proposal, null, 2);\n } else if (fmt === 'markdown') {\n payload = renderSnowflakeSchemaMarkdown(proposal);\n } else if (fmt === 'table') {\n payload = validateNs.formatSnowflakeSchemaProposal(proposal);\n } else {\n throw new Error(`Unknown --format: ${fmt}. Use table | json | markdown.`);\n }\n await emit(payload, opts.out);\n });\n\n // ─── Sample-data → CREATE TABLE inference ───\n cmd\n .command('infer-csv <file>')\n .description(\n 'Read a CSV sample and emit a Databricks CREATE TABLE with heuristic type inference. Review before deploy.',\n )\n .requiredOption(\n '--name <fqn>',\n 'Fully-qualified table name (catalog.schema.table or schema.table).',\n )\n .option('--delimiter <char>', 'CSV delimiter. Default: comma.', ',')\n .option(\n '--no-header',\n 'Treat the first row as data, not header. Generated column names: column_1, column_2, …',\n )\n .option('--max-sample-rows <n>', 'Cap on rows sampled. Default 1000.', (v) => parseInt(v, 10))\n .option(\n '--or-replace',\n 'Emit CREATE OR REPLACE TABLE instead of CREATE TABLE IF NOT EXISTS.',\n false,\n )\n .option(\n '--using <format>',\n 'Storage format (DELTA / PARQUET / CSV / JSON / ICEBERG). Default DELTA.',\n 'DELTA',\n )\n .option('-o, --out <path>', 'Output file. Defaults to stdout.')\n .action(async (filePath, opts) => {\n const text = await fs.readFile(path.resolve(String(filePath)), 'utf8');\n const inferred = schema.inferSchemaFromCsv(\n text,\n {\n delimiter: String(opts.delimiter),\n hasHeader: opts.header !== false,\n ...(typeof opts.maxSampleRows === 'number' ? { maxSampleRows: opts.maxSampleRows } : {}),\n },\n path.basename(String(filePath)),\n );\n const parts = String(opts.name).split('.').filter(Boolean);\n const fqn =\n parts.length === 3\n ? { database: parts[0]!, schema: parts[1]!, name: parts[2]! }\n : parts.length === 2\n ? { schema: parts[0]!, name: parts[1]! }\n : { name: parts[0] ?? 'inferred_table' };\n const ddl = schema.renderCreateTable(inferred, {\n fqn,\n orReplace: !!opts.orReplace,\n using: String(opts.using),\n });\n await emit(ddl, opts.out);\n console.error(\n `Sampled ${inferred.sampleRowCount} row(s); inferred ${inferred.columns.length} column(s).`,\n );\n const allNull = inferred.columns.filter((c) => c.allNull);\n if (allNull.length > 0) {\n console.error(\n `Warning: ${allNull.length} column(s) had no values in the sample — types defaulted to STRING. Review the generated DDL.`,\n );\n }\n });\n\n cmd\n .command('infer-parquet <file>')\n .description(\n \"Read a Parquet file's metadata footer and emit a Databricks CREATE TABLE. No data is read — only the schema header.\",\n )\n .requiredOption(\n '--name <fqn>',\n 'Fully-qualified table name (catalog.schema.table or schema.table).',\n )\n .option(\n '--or-replace',\n 'Emit CREATE OR REPLACE TABLE instead of CREATE TABLE IF NOT EXISTS.',\n false,\n )\n .option(\n '--using <format>',\n 'Storage format (DELTA / PARQUET / ICEBERG / ...). Default DELTA.',\n 'DELTA',\n )\n .option('-o, --out <path>', 'Output file. Defaults to stdout.')\n .action(async (filePath, opts) => {\n const buf = await fs.readFile(path.resolve(String(filePath)));\n const inferred = await schema.inferSchemaFromParquet(buf, path.basename(String(filePath)));\n const parts = String(opts.name).split('.').filter(Boolean);\n const fqn =\n parts.length === 3\n ? { database: parts[0]!, schema: parts[1]!, name: parts[2]! }\n : parts.length === 2\n ? { schema: parts[0]!, name: parts[1]! }\n : { name: parts[0] ?? 'inferred_table' };\n const ddl = schema.renderCreateTable(inferred, {\n fqn,\n orReplace: !!opts.orReplace,\n using: String(opts.using),\n });\n await emit(ddl, opts.out);\n console.error(\n `Parquet schema: ${inferred.columns.length} column(s); reported ${inferred.sampleRowCount} row(s) in metadata.`,\n );\n });\n\n // ─── Multi-format importers ───\n cmd\n .command('import-ddl <file>')\n .description(\n 'Universal DDL importer — parse any CREATE TABLE statements (erwin / ER/Studio / PowerDesigner / DbSchema / Hackolade / Visio / DataGrip all \"Forward Engineer to Script\"; we read it).',\n )\n .option('-o, --out <path>', 'Output directory. Default ./imported/.')\n .action(async (filePath, opts) => {\n const text = await fs.readFile(path.resolve(String(filePath)), 'utf8');\n const result = interop.parseUniversalDdl(text);\n await writeImportedTables(\n result,\n opts.out ? path.resolve(String(opts.out)) : path.resolve('imported'),\n );\n });\n\n cmd\n .command('import-jsonschema <file>')\n .description('Import a JSON Schema document; each top-level object schema becomes a table.')\n .option('-o, --out <path>', 'Output directory. Default ./imported/.')\n .action(async (filePath, opts) => {\n const text = await fs.readFile(path.resolve(String(filePath)), 'utf8');\n const result = interop.parseJsonSchema(text);\n await writeImportedTables(\n result,\n opts.out ? path.resolve(String(opts.out)) : path.resolve('imported'),\n );\n });\n\n cmd\n .command('import-dbt <file>')\n .description('Import a dbt-generated manifest.json; each model/seed/source becomes a table.')\n .option('-o, --out <path>', 'Output directory. Default ./imported/.')\n .action(async (filePath, opts) => {\n const text = await fs.readFile(path.resolve(String(filePath)), 'utf8');\n const result = interop.parseDbtManifest(text);\n await writeImportedTables(\n result,\n opts.out ? path.resolve(String(opts.out)) : path.resolve('imported'),\n );\n });\n\n return cmd;\n}\n\nasync function writeImportedTables(result: interop.ImportResult, outDir: string): Promise<void> {\n await fs.mkdir(outDir, { recursive: true });\n let written = 0;\n for (const t of result.tables) {\n const catalog = t.database ?? 'main';\n const sch = t.schema ?? 'default';\n const dir = path.join(outDir, catalog, sch, 'tables');\n await fs.mkdir(dir, { recursive: true });\n const file = path.join(dir, `${t.name}.sql`);\n const colDdl = t.columns\n .map((c) => {\n const mods: string[] = [];\n if (c.nullable === false) mods.push('NOT NULL');\n if (c.default) mods.push(`DEFAULT ${c.default}`);\n return ` ${c.name.padEnd(28)} ${databricksType(c.dataType)}${mods.length > 0 ? ' ' + mods.join(' ') : ''}${c.comment ? ` COMMENT '${c.comment.replace(/'/g, \"''\")}'` : ''}`;\n })\n .join(',\\n');\n const ddl = `-- Imported by \\`ddt schema import-*\\` from source: ${result.source}.\\n-- Review and refine; DDT is the canonical model from here on.\\n\\nCREATE OR REPLACE TABLE ${catalog}.${sch}.${t.name} (\\n${colDdl}\\n)\\nUSING DELTA\\nTBLPROPERTIES ('delta.enableDeletionVectors' = 'true')${t.comment ? `\\nCOMMENT '${t.comment.replace(/'/g, \"''\")}'` : ''};\\n`;\n await fs.writeFile(file, ddl, 'utf8');\n written++;\n }\n console.error(`Imported ${written} table(s) into ${outDir}.`);\n if (result.warnings.length > 0) {\n console.error('Warnings (review before deploy):');\n for (const w of result.warnings) console.error(` - ${w}`);\n }\n}\n\nfunction databricksType(dbmlType: string): string {\n const t = dbmlType.toLowerCase().trim();\n if (t === 'int' || t === 'integer' || t === 'serial') return 'INT';\n if (t === 'bigint' || t.startsWith('number')) return 'BIGINT';\n if (t === 'smallint') return 'SMALLINT';\n if (t === 'decimal' || t === 'numeric') return 'DECIMAL(38,9)';\n if (t === 'float' || t === 'double') return 'DOUBLE';\n if (t === 'boolean' || t === 'bool') return 'BOOLEAN';\n if (t === 'date') return 'DATE';\n if (t === 'datetime' || t === 'timestamp' || t === 'timestamp_ntz') return 'TIMESTAMP';\n if (t === 'text' || t === 'string' || t.startsWith('varchar')) return 'STRING';\n if (t === 'variant' || t === 'json' || t === 'jsonb') return 'MAP<STRING, STRING>';\n if (t === 'array') return 'ARRAY<STRING>';\n if (t === 'uuid') return 'STRING';\n return dbmlType.toUpperCase();\n}\n\nfunction renderTableDdl(t: schema.DbmlTable, refs: readonly schema.DbmlRef[]): string {\n const lines: string[] = [];\n lines.push(`-- Imported from DBML by \\`ddt schema import-dbml\\`.`);\n lines.push(`-- Review and refine; DDT is the canonical model from here on.`);\n if (t.note) lines.push(`-- ${t.note}`);\n lines.push('');\n const colDdl = t.columns.map((c) => {\n const mods: string[] = [];\n if (c.notNull) mods.push('NOT NULL');\n if (c.default) mods.push(`DEFAULT ${c.default}`);\n return ` ${c.name.padEnd(28)} ${databricksType(c.type)}${mods.length > 0 ? ' ' + mods.join(' ') : ''}${c.note ? ` COMMENT '${c.note.replace(/'/g, \"''\")}'` : ''}`;\n });\n const tableRefs = refs.filter((r) =>\n r.from.toLowerCase().startsWith(`${t.schema.toLowerCase()}.${t.name.toLowerCase()}.`),\n );\n if (tableRefs.length > 0) {\n lines.push(`-- Inferred references (UC doesn't enforce FKs; this is metadata only):`);\n for (const r of tableRefs) lines.push(`-- ${r.from} ${r.cardinality} ${r.to}`);\n lines.push('');\n }\n lines.push(`CREATE OR REPLACE TABLE main.${t.schema}.${t.name} (`);\n lines.push(colDdl.join(',\\n'));\n lines.push(')');\n lines.push(`USING DELTA`);\n lines.push(`TBLPROPERTIES ('delta.enableDeletionVectors' = 'true')`);\n if (t.note) lines.push(`COMMENT '${t.note.replace(/'/g, \"''\")}'`);\n lines.push(';\\n');\n return lines.join('\\n');\n}\n\nfunction renderSnowflakeSchemaMarkdown(p: validateNs.SnowflakeSchemaProposal): string {\n const lines: string[] = [];\n lines.push(`# Snowflake-schema refactor proposal — \\`${p.fact}\\``);\n lines.push('');\n lines.push(`Generated: ${p.generatedAt}`);\n if (p.source) lines.push(`Source: \\`${p.source}\\``);\n lines.push('');\n if (!p.factExists) {\n lines.push(`**Fact not found in the project.**`);\n return lines.join('\\n');\n }\n if (p.dims.length === 0) {\n lines.push('_No refactor candidates detected._');\n return lines.join('\\n');\n }\n for (const d of p.dims) {\n lines.push(`## \\`${d.dim}\\` (${d.scdType})`);\n lines.push('');\n for (const g of d.groups) {\n lines.push(`### ${g.kind} — columns: \\`${g.columns.join('`, `')}\\``);\n lines.push('');\n if (g.proposedDim) {\n lines.push(`**Proposal:** extract to \\`${g.proposedDim}\\`.`);\n } else {\n lines.push(`**Proposal:** keep on parent dim (audit metadata).`);\n }\n lines.push('');\n lines.push(`*Why:* ${g.reasoning}`);\n lines.push('');\n }\n }\n return lines.join('\\n');\n}\n\nfunction renderStarMarkdown(report: validateNs.StarValidationReport): string {\n const lines: string[] = [];\n lines.push(`# Star validation — \\`${report.fact}\\``);\n lines.push('');\n lines.push(`Generated: ${report.generatedAt}`);\n if (report.source) lines.push(`Source: \\`${report.source}\\``);\n lines.push('');\n if (!report.factExists) {\n lines.push(`**${report.issues[0]}**`);\n return lines.join('\\n');\n }\n lines.push(\n `**Fan-out:** ${report.fanOut} · **CLUSTER BY:** ${report.clusterBy.length > 0 ? report.clusterBy.join(', ') : '_none_'}`,\n );\n lines.push('');\n if (report.dimensions.length > 0) {\n lines.push('## Dimensions');\n lines.push('');\n lines.push('| Dim | SCD Type | Business Key | Notes |');\n lines.push('| --- | --- | --- | --- |');\n for (const d of report.dimensions) {\n lines.push(\n `| \\`${d.fqn}\\` | ${d.scdType} | ${d.bk ? `\\`${d.bk}\\`` : '_none_'} | ${d.reasons.join('; ')} |`,\n );\n }\n lines.push('');\n }\n if (report.issues.length > 0) {\n lines.push('## Issues');\n lines.push('');\n for (const i of report.issues) lines.push(`- ⚠️ ${i}`);\n }\n return lines.join('\\n');\n}\n\nasync function loadModel(sourcePath: string): Promise<DatabricksObject[]> {\n if (sourcePath.endsWith('.ddtpac')) {\n const c = await pac.readPac(sourcePath);\n return c.model;\n }\n const loaded = await loadProject(sourcePath);\n return await parseProjectModel(loaded);\n}\n\nasync function emit(text: string, out: unknown): Promise<void> {\n if (out) {\n const p = path.resolve(String(out));\n await fs.mkdir(path.dirname(p), { recursive: true });\n await fs.writeFile(p, text + (text.endsWith('\\n') ? '' : '\\n'), 'utf8');\n console.error(`Wrote ${p}.`);\n } else {\n process.stdout.write(text + (text.endsWith('\\n') ? '' : '\\n'));\n }\n}\n"],"mappings":"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","names":[]}