diff --git a/package-lock.json b/package-lock.json index 31e7aec..4086f3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,17 @@ { "name": "seam-pgm", - "version": "1.3.0", + "version": "1.3.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "seam-pgm", - "version": "1.3.0", + "version": "1.3.2", "license": "ISC", "dependencies": { "pg-schema-dump": "^2.0.1", + "prettier": "^3.5.1", + "ts-morph": "^25.0.1", "yargs": "^17.7.2" }, "bin": { @@ -488,7 +490,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "devOptional": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -501,7 +502,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "devOptional": true, "engines": { "node": ">= 8" } @@ -510,7 +510,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "devOptional": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -565,14 +564,13 @@ } }, "node_modules/@ts-morph/common": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.13.0.tgz", - "integrity": "sha512-fEJ6j7Cu8yiWjA4UmybOBH9Efgb/64ZTWuvCF4KysGu4xz8ettfyaqFt8WZ1btCxXsGZJjZ2/3svOF6rL+UFdQ==", - "optional": true, + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.26.1.tgz", + "integrity": "sha512-Sn28TGl/4cFpcM+jwsH1wLncYq3FtN/BIpem+HOygfBWPT5pAeS5dB4VFVzV8FbnOKHpDLZmvAl4AjPEev5idA==", + "license": "MIT", "dependencies": { - "fast-glob": "^3.2.11", - "minimatch": "^5.0.1", - "mkdirp": "^1.0.4", + "fast-glob": "^3.3.2", + "minimatch": "^9.0.4", "path-browserify": "^1.0.1" } }, @@ -580,33 +578,24 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "optional": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/@ts-morph/common/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "optional": true, + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" - } - }, - "node_modules/@ts-morph/common/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true, - "bin": { - "mkdirp": "bin/cmd.js" + "node": ">=16 || 14 >=14.17" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@types/debug": { @@ -1133,8 +1122,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "devOptional": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -1205,12 +1193,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "devOptional": true, + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1595,10 +1583,10 @@ } }, "node_modules/code-block-writer": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-11.0.3.tgz", - "integrity": "sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==", - "optional": true + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "license": "MIT" }, "node_modules/code-excerpt": { "version": "4.0.0", @@ -2290,16 +2278,16 @@ "peer": true }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "devOptional": true, + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -2309,7 +2297,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "devOptional": true, "dependencies": { "reusify": "^1.0.4" } @@ -2331,10 +2318,10 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "devOptional": true, + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2541,7 +2528,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "devOptional": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -2792,7 +2778,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -2813,7 +2798,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "devOptional": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -2831,7 +2815,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -3326,18 +3310,17 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "devOptional": true, "engines": { "node": ">= 8" } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "devOptional": true, + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -4050,7 +4033,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "optional": true + "license": "MIT" }, "node_modules/path-exists": { "version": "5.0.0", @@ -4355,6 +4338,49 @@ "pgtui": "dist/cli.js" } }, + "node_modules/pgtui/node_modules/@ts-morph/common": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.13.0.tgz", + "integrity": "sha512-fEJ6j7Cu8yiWjA4UmybOBH9Efgb/64ZTWuvCF4KysGu4xz8ettfyaqFt8WZ1btCxXsGZJjZ2/3svOF6rL+UFdQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "fast-glob": "^3.2.11", + "minimatch": "^5.0.1", + "mkdirp": "^1.0.4", + "path-browserify": "^1.0.1" + } + }, + "node_modules/pgtui/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/pgtui/node_modules/code-block-writer": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-11.0.3.tgz", + "integrity": "sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==", + "license": "MIT", + "optional": true + }, + "node_modules/pgtui/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "optional": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/pgtui/node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -4367,11 +4393,37 @@ "node": ">=10" } }, + "node_modules/pgtui/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "license": "MIT", + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pgtui/node_modules/ts-morph": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-14.0.0.tgz", + "integrity": "sha512-tO8YQ1dP41fw8GVmeQAdNsD8roZi1JMqB7YwZrqU856DvmG5/710e41q2XauzTYrygH9XmMryaFeLo+kdCziyA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@ts-morph/common": "~0.13.0", + "code-block-writer": "^11.0.0" + } + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "devOptional": true, "engines": { "node": ">=8.6" }, @@ -4494,15 +4546,15 @@ "dev": true }, "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "optional": true, + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz", + "integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==", + "license": "MIT", "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" @@ -4615,7 +4667,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "devOptional": true, "funding": [ { "type": "github", @@ -4799,7 +4850,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "devOptional": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -4840,7 +4890,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "devOptional": true, "funding": [ { "type": "github", @@ -5511,7 +5560,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -5541,13 +5590,13 @@ "dev": true }, "node_modules/ts-morph": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-14.0.0.tgz", - "integrity": "sha512-tO8YQ1dP41fw8GVmeQAdNsD8roZi1JMqB7YwZrqU856DvmG5/710e41q2XauzTYrygH9XmMryaFeLo+kdCziyA==", - "optional": true, + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-25.0.1.tgz", + "integrity": "sha512-QJEiTdnz1YjrB3JFhd626gX4rKHDLSjSVMvGGG4v7ONc3RBwa0Eei98G9AT9uNFDMtV54JyuXsFeC+OH0n6bXQ==", + "license": "MIT", "dependencies": { - "@ts-morph/common": "~0.13.0", - "code-block-writer": "^11.0.0" + "@ts-morph/common": "~0.26.0", + "code-block-writer": "^13.0.3" } }, "node_modules/tslib": { @@ -6348,7 +6397,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "devOptional": true, "requires": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -6357,14 +6405,12 @@ "@nodelib/fs.stat": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "devOptional": true + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" }, "@nodelib/fs.walk": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "devOptional": true, "requires": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -6405,14 +6451,12 @@ "optional": true }, "@ts-morph/common": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.13.0.tgz", - "integrity": "sha512-fEJ6j7Cu8yiWjA4UmybOBH9Efgb/64ZTWuvCF4KysGu4xz8ettfyaqFt8WZ1btCxXsGZJjZ2/3svOF6rL+UFdQ==", - "optional": true, + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.26.1.tgz", + "integrity": "sha512-Sn28TGl/4cFpcM+jwsH1wLncYq3FtN/BIpem+HOygfBWPT5pAeS5dB4VFVzV8FbnOKHpDLZmvAl4AjPEev5idA==", "requires": { - "fast-glob": "^3.2.11", - "minimatch": "^5.0.1", - "mkdirp": "^1.0.4", + "fast-glob": "^3.3.2", + "minimatch": "^9.0.4", "path-browserify": "^1.0.1" }, "dependencies": { @@ -6420,25 +6464,17 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "optional": true, "requires": { "balanced-match": "^1.0.0" } }, "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "optional": true, + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "requires": { "brace-expansion": "^2.0.1" } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true } } }, @@ -6866,8 +6902,7 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "devOptional": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base64-js": { "version": "1.5.1", @@ -6921,12 +6956,11 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "devOptional": true, + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "buffer": { @@ -7185,10 +7219,9 @@ } }, "code-block-writer": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-11.0.3.tgz", - "integrity": "sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==", - "optional": true + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==" }, "code-excerpt": { "version": "4.0.0", @@ -7723,23 +7756,21 @@ "peer": true }, "fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "devOptional": true, + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" } }, "fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "devOptional": true, "requires": { "reusify": "^1.0.4" } @@ -7755,10 +7786,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "devOptional": true, + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "requires": { "to-regex-range": "^5.0.1" } @@ -7906,7 +7936,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "devOptional": true, "requires": { "is-glob": "^4.0.1" } @@ -8091,8 +8120,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "devOptional": true + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, "is-fullwidth-code-point": { "version": "4.0.0", @@ -8104,7 +8132,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "devOptional": true, "requires": { "is-extglob": "^2.1.1" } @@ -8118,8 +8145,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-path-cwd": { "version": "2.2.0", @@ -8490,16 +8516,14 @@ "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "devOptional": true + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "devOptional": true, + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "requires": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" } }, @@ -9013,8 +9037,7 @@ "path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", - "optional": true + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" }, "path-exists": { "version": "5.0.0", @@ -9251,19 +9274,70 @@ "yargs": "^17.1.1" }, "dependencies": { + "@ts-morph/common": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.13.0.tgz", + "integrity": "sha512-fEJ6j7Cu8yiWjA4UmybOBH9Efgb/64ZTWuvCF4KysGu4xz8ettfyaqFt8WZ1btCxXsGZJjZ2/3svOF6rL+UFdQ==", + "optional": true, + "requires": { + "fast-glob": "^3.2.11", + "minimatch": "^5.0.1", + "mkdirp": "^1.0.4", + "path-browserify": "^1.0.1" + } + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "optional": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "code-block-writer": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-11.0.3.tgz", + "integrity": "sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==", + "optional": true + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "optional": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "optional": true + }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "optional": true + }, + "ts-morph": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-14.0.0.tgz", + "integrity": "sha512-tO8YQ1dP41fw8GVmeQAdNsD8roZi1JMqB7YwZrqU856DvmG5/710e41q2XauzTYrygH9XmMryaFeLo+kdCziyA==", + "optional": true, + "requires": { + "@ts-morph/common": "~0.13.0", + "code-block-writer": "^11.0.0" + } } } }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "devOptional": true + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pirates": { "version": "4.0.6", @@ -9334,10 +9408,9 @@ "dev": true }, "prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "optional": true + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz", + "integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==" }, "pretty-ms": { "version": "8.0.0", @@ -9422,8 +9495,7 @@ "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "devOptional": true + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, "queue-tick": { "version": "1.0.1", @@ -9558,8 +9630,7 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "devOptional": true + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" }, "rimraf": { "version": "3.0.2", @@ -9583,7 +9654,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "devOptional": true, "requires": { "queue-microtask": "^1.2.2" } @@ -10076,7 +10146,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, "requires": { "is-number": "^7.0.0" } @@ -10100,13 +10169,12 @@ "dev": true }, "ts-morph": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-14.0.0.tgz", - "integrity": "sha512-tO8YQ1dP41fw8GVmeQAdNsD8roZi1JMqB7YwZrqU856DvmG5/710e41q2XauzTYrygH9XmMryaFeLo+kdCziyA==", - "optional": true, + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-25.0.1.tgz", + "integrity": "sha512-QJEiTdnz1YjrB3JFhd626gX4rKHDLSjSVMvGGG4v7ONc3RBwa0Eei98G9AT9uNFDMtV54JyuXsFeC+OH0n6bXQ==", "requires": { - "@ts-morph/common": "~0.13.0", - "code-block-writer": "^11.0.0" + "@ts-morph/common": "~0.26.0", + "code-block-writer": "^13.0.3" } }, "tslib": { diff --git a/package.json b/package.json index 9de8025..daf4e44 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ "license": "ISC", "dependencies": { "pg-schema-dump": "^2.0.1", + "prettier": "^3.5.1", + "ts-morph": "^25.0.1", "yargs": "^17.7.2" }, "peerDependencies": { diff --git a/src/generate.ts b/src/generate.ts index 3996655..20e488c 100644 --- a/src/generate.ts +++ b/src/generate.ts @@ -2,6 +2,7 @@ import { getConnectionStringFromEnv } from "pg-connection-from-env" import { Context } from "./get-project-context" import { generateSchema } from "./lib/generate-schema" import { generateStructure } from "./lib/generate-structure" +import { generateTypes } from "./lib/generate-types" import { generateGetDbClient } from "./lib/generate-get-db-client" export const generate = async ( @@ -21,6 +22,11 @@ export const generate = async ( schemas, }) + await generateTypes({ + zapatos_dir: `${zapatosDir ?? dbDir}/zapatos`, + output_dir: `${dbDir}/types`, + }) + await generateStructure({ database_name: defaultDatabase, output_dir: dbDir, diff --git a/src/lib/generate-types/file-generators/custom/[schema_name]/[TableName]CustomTypes.ts b/src/lib/generate-types/file-generators/custom/[schema_name]/[TableName]CustomTypes.ts new file mode 100644 index 0000000..79da8b6 --- /dev/null +++ b/src/lib/generate-types/file-generators/custom/[schema_name]/[TableName]CustomTypes.ts @@ -0,0 +1,60 @@ +import type { Config, Schema, Table } from "../../../types" +import { pascalCase } from "../../../utils" +import { + StructureKind, + type Project, + type SourceFile, + type StatementedNodeStructure, +} from "ts-morph" + +export const createCustomTypesFile = ( + args: { + project: Project + schema: Schema + table: Table + }, + config: Config +): SourceFile => { + const { project, schema, table } = args + const { output_dir } = config + + const pascal_table_name = pascalCase(table.name) + + const statements: StatementedNodeStructure["statements"] = [ + { + kind: StructureKind.ImportDeclaration, + namedImports: ["SubsetOf"], + moduleSpecifier: "../../generated/utils", + isTypeOnly: true, + }, + { + kind: StructureKind.ImportDeclaration, + namedImports: [`Selectable${pascal_table_name}`], + moduleSpecifier: `../../generated/${schema.name}/${pascal_table_name}QueryTypes`, + isTypeOnly: true, + }, + (writer) => writer.blankLine(), + { + kind: StructureKind.TypeAlias, + name: `${pascal_table_name}CustomTypes`, + type: `SubsetOf`, + isExported: true, + }, + (writer) => writer.blankLine(), + { + kind: StructureKind.ExportAssignment, + isExportEquals: false, + expression: `${pascal_table_name}CustomTypes`, + }, + ] + + return project.createSourceFile( + `${output_dir}/custom/${schema.name}/${pascal_table_name}CustomTypes.ts`, + { + statements, + }, + { + overwrite: false, + } + ) +} diff --git a/src/lib/generate-types/file-generators/generated/[schema_name]/[TableName].ts b/src/lib/generate-types/file-generators/generated/[schema_name]/[TableName].ts new file mode 100644 index 0000000..2c26186 --- /dev/null +++ b/src/lib/generate-types/file-generators/generated/[schema_name]/[TableName].ts @@ -0,0 +1,95 @@ +import type { Config, Schema, Table } from "../../../types" +import { pascalCase } from "../../../utils" +import { + StructureKind, + type Project, + type SourceFile, + type StatementedNodeStructure, +} from "ts-morph" + +export const createResultingTypeFile = ( + args: { + project: Project + schema: Schema + table: Table + }, + config: Config +): SourceFile => { + const { project, schema, table } = args + const { output_dir } = config + + const pascal_table_name = pascalCase(table.name) + + const statements: StatementedNodeStructure["statements"] = [ + { + kind: StructureKind.ImportDeclaration, + moduleSpecifier: `./${pascal_table_name}QueryTypes`, + namedImports: [ + `Selectable${pascal_table_name}`, + `Insertable${pascal_table_name}`, + ], + isTypeOnly: true, + }, + ] + + if (table.is_affected_by_pgtui_bugs) { + statements.push({ + kind: StructureKind.ImportDeclaration, + moduleSpecifier: "../utils", + namedImports: ["ReproducePgtuiBugs"], + isTypeOnly: true, + }) + } + + if (table.is_customizable) { + statements.push( + { + kind: StructureKind.ImportDeclaration, + moduleSpecifier: "../utils", + namedImports: ["CustomizeDbType", "CustomizeDbTypeInitializer"], + isTypeOnly: true, + }, + { + kind: StructureKind.ImportDeclaration, + moduleSpecifier: `../../custom/${schema.name}/${pascal_table_name}CustomTypes`, + defaultImport: `${pascal_table_name}CustomTypes`, + isTypeOnly: true, + } + ) + } + + statements.push( + (writer) => writer.newLine(), + { + kind: StructureKind.TypeAlias, + isExported: true, + name: pascal_table_name, + type: table.is_customizable + ? `CustomizeDbType` + : `Selectable${pascal_table_name}`, + }, + { + kind: StructureKind.TypeAlias, + isExported: true, + name: `${pascal_table_name}Initializer`, + type: table.is_customizable + ? `CustomizeDbTypeInitializer` + : `Insertable${pascal_table_name}`, + } + ) + + if (table.is_affected_by_pgtui_bugs) { + statements.push({ + kind: StructureKind.TypeAlias, + isExported: true, + name: `${pascal_table_name}WithPgtuiBugs`, + type: `ReproducePgtuiBugs<${pascal_table_name}>`, + }) + } + + return project.createSourceFile( + `${output_dir}/generated/${schema.name}/${pascal_table_name}.ts`, + { statements }, + { overwrite: true } + ) +} diff --git a/src/lib/generate-types/file-generators/generated/[schema_name]/[TableName]QueryTypes.ts b/src/lib/generate-types/file-generators/generated/[schema_name]/[TableName]QueryTypes.ts new file mode 100644 index 0000000..9718c28 --- /dev/null +++ b/src/lib/generate-types/file-generators/generated/[schema_name]/[TableName]QueryTypes.ts @@ -0,0 +1,71 @@ +import type { Config, Schema, Table } from "../../../types" +import { pascalCase } from "../../../utils" +import { + type SourceFile, + StructureKind, + type Project, + type StatementedNodeStructure, +} from "ts-morph" + +export const createQueryTypesFile = ( + args: { + project: Project + schema: Schema + table: Table + }, + config: Config +): SourceFile => { + const { project, schema, table } = args + const { output_dir } = config + + const base_type_name = pascalCase(table.name) + + const statements: StatementedNodeStructure["statements"] = [] + + if (table.uses_zapatos_column_type) { + statements.push({ + kind: StructureKind.ImportDeclaration, + moduleSpecifier: "zapatos/db", + namespaceImport: "db", + isTypeOnly: true, + }) + } + + statements.push( + (writer) => writer.newLine(), + { + kind: StructureKind.TypeAlias, + isExported: true, + name: `Selectable${base_type_name}`, + type: (writer) => + writer.inlineBlock(() => { + for (const column of Object.values(table.selectable_columns)) { + writer.writeLine( + `${column.name}${column.is_optional ? "?" : ""}: ${column.type};` + ) + } + }), + }, + { + kind: StructureKind.TypeAlias, + isExported: true, + name: `Insertable${base_type_name}`, + type: (writer) => + writer.inlineBlock(() => { + for (const column of Object.values(table.insertable_columns)) { + writer.writeLine( + `${column.name}${column.is_optional ? "?" : ""}: ${column.type};` + ) + } + }), + } + ) + + return project.createSourceFile( + `${output_dir}/generated/${schema.name}/${base_type_name}QueryTypes.ts`, + { + statements, + }, + { overwrite: true } + ) +} diff --git a/src/lib/generate-types/file-generators/generated/[schema_name]/index.ts b/src/lib/generate-types/file-generators/generated/[schema_name]/index.ts new file mode 100644 index 0000000..ad3a3f1 --- /dev/null +++ b/src/lib/generate-types/file-generators/generated/[schema_name]/index.ts @@ -0,0 +1,125 @@ +import type { Config, Schema } from "../../../types" +import { pascalCase } from "../../../utils" +import { + StructureKind, + type Project, + type SourceFile, + type StatementedNodeStructure, +} from "ts-morph" + +export const createSchemaGeneratedTypeIndexFile = ( + args: { + project: Project + schema: Schema + }, + config: Config, +): SourceFile => { + const { project, schema } = args + const { output_dir } = config + + const pascale_schema_name = pascalCase(schema.name) + + const tables = Object.values(schema.tables) + const pascal_table_names = tables + .map((table) => table.name) + .reduce>((acc, table_name) => { + acc[table_name] = pascalCase(table_name) + return acc + }, {}) + + const statements: StatementedNodeStructure["statements"] = [ + { + kind: StructureKind.ImportDeclaration, + moduleSpecifier: "../utils", + namedImports: ["KyselyTable"], + isTypeOnly: true, + }, + ] + + for (const table of tables) { + statements.push({ + kind: StructureKind.ImportDeclaration, + isTypeOnly: true, + moduleSpecifier: `./${pascal_table_names[table.name]}`, + namedImports: [ + pascal_table_names[table.name], + ...(table.is_affected_by_pgtui_bugs + ? [`${pascal_table_names[table.name]}WithPgtuiBugs`] + : []), + `${pascal_table_names[table.name]}Initializer`, + ], + }) + } + + statements.push( + (writer) => writer.newLine(), + { + kind: StructureKind.TypeAlias, + isExported: true, + name: `${pascale_schema_name}Tables`, + type: `[ ${tables + .map((table) => `"${schema.name}.${table.name}"`) + .join(", ")} ]`, + }, + { + kind: StructureKind.TypeAlias, + isExported: true, + name: `${pascale_schema_name}Table`, + type: `${pascale_schema_name}Tables[number]`, + }, + (writer) => writer.newLine(), + ) + + if (config.generate_knex_types) { + statements.push({ + kind: StructureKind.Interface, + isExported: true, + name: "KnexSchemaTypeMap", + properties: tables.map((table) => ({ + name: + schema.name === "seam" + ? table.name + : `"${schema.name}.${table.name}"`, + type: table.is_affected_by_pgtui_bugs + ? `${pascal_table_names[table.name]}WithPgtuiBugs` + : pascal_table_names[table.name], + })), + }) + } + + statements.push( + { + kind: StructureKind.TypeAlias, + isExported: true, + name: "KyselySchemaTypeMap", + type: `{ ${tables + .map( + (table) => + `"${schema.name}.${table.name}": KyselyTable<${ + pascal_table_names[table.name] + }, ${pascal_table_names[table.name]}Initializer>;`, + ) + .join(" ")} }`, + }, + (writer) => writer.newLine(), + { + kind: StructureKind.ExportDeclaration, + isTypeOnly: true, + namedExports: tables.flatMap((table) => [ + pascal_table_names[table.name], + ...(table.is_affected_by_pgtui_bugs + ? [`${pascal_table_names[table.name]}WithPgtuiBugs`] + : []), + `${pascal_table_names[table.name]}Initializer`, + ]), + }, + ) + + return project.createSourceFile( + `${output_dir}/generated/${schema.name}/index.ts`, + { + statements, + }, + { overwrite: true }, + ) +} diff --git a/src/lib/generate-types/file-generators/generated/index.ts b/src/lib/generate-types/file-generators/generated/index.ts new file mode 100644 index 0000000..ff63d9d --- /dev/null +++ b/src/lib/generate-types/file-generators/generated/index.ts @@ -0,0 +1,96 @@ +import { pascalCase } from "../../utils" +import type { Config, Schema } from "../../types" +import { + type Project, + type StatementedNodeStructure, + type SourceFile, + StructureKind, +} from "ts-morph" + +export const createGeneratedIndexFile = ( + args: { + project: Project + schemas: Schema[] + }, + config: Config, +): SourceFile => { + const { project, schemas } = args + const { output_dir, main_schema = "public" } = config + + const schema_import_statements: StatementedNodeStructure["statements"] = [] + const schema_export_statements: StatementedNodeStructure["statements"] = [] + const schemas_tables: string[] = [] + + for (const schema of schemas) { + if (Object.values(schema.tables).length === 0) continue + const pascal_schema_name = pascalCase(schema.name) + + schema_import_statements.push({ + kind: StructureKind.ImportDeclaration, + moduleSpecifier: `./${schema.name}`, + namedImports: [`${pascal_schema_name}Tables`], + }) + schemas_tables.push(`${pascal_schema_name}Tables`) + schema_export_statements.push({ + kind: StructureKind.ExportDeclaration, + namespaceExport: schema.name === main_schema ? undefined : schema.name, + moduleSpecifier: `./${schema.name}`, + }) + } + + const statements: StatementedNodeStructure["statements"] = [ + ...schema_import_statements, + (writer) => writer.newLine(), + { + kind: StructureKind.TypeAlias, + isExported: true, + name: "DatabaseSchemas", + type: `[ ${schemas.map((schema) => `"${schema.name}"`).join(", ")} ]`, + }, + { + kind: StructureKind.TypeAlias, + isExported: true, + name: "DatabaseTables", + type: `[ ${schemas_tables + .map((schema_tables) => `...${schema_tables}`) + .join(", ")} ]`, + }, + (writer) => writer.newLine(), + { + kind: StructureKind.TypeAlias, + isExported: true, + name: "DatabaseSchema", + type: "DatabaseSchemas[number]", + }, + { + kind: StructureKind.TypeAlias, + isExported: true, + name: "DatabaseTable", + type: "DatabaseTables[number]", + }, + (writer) => writer.newLine(), + ...schema_export_statements, + (writer) => writer.newLine(), + { + kind: StructureKind.ExportDeclaration, + namespaceExport: "kysely", + moduleSpecifier: "./kysely", + }, + ] + + if (config.generate_knex_types) { + statements.push({ + kind: StructureKind.ExportDeclaration, + namespaceExport: "knex", + moduleSpecifier: "./knex", + }) + } + + return project.createSourceFile( + `${output_dir}/generated/index.ts`, + { + statements, + }, + { overwrite: true }, + ) +} diff --git a/src/lib/generate-types/file-generators/generated/knex.ts b/src/lib/generate-types/file-generators/generated/knex.ts new file mode 100644 index 0000000..3f40e3c --- /dev/null +++ b/src/lib/generate-types/file-generators/generated/knex.ts @@ -0,0 +1,61 @@ +import type { Config, Schema } from "../../types" +import { pascalCase } from "../../utils" +import { + StructureKind, + type SourceFile, + type Project, + type StatementedNodeStructure, +} from "ts-morph" + +export const createKnexIndexFile = ( + args: { + project: Project + schemas: Schema[] + }, + config: Config, +): SourceFile => { + const { project, schemas } = args + const { output_dir } = config + + const statements: StatementedNodeStructure["statements"] = [] + const module_interface_statements: StatementedNodeStructure["statements"] = [] + + for (const schema of schemas) { + if (Object.values(schema.tables).length === 0) continue + + statements.push({ + kind: StructureKind.ImportDeclaration, + moduleSpecifier: `./${schema.name}`, + namedImports: [ + { + name: "KnexSchemaTypeMap", + alias: `${pascalCase(schema.name)}TypeMap`, + }, + ], + }) + + module_interface_statements.push({ + kind: StructureKind.Interface, + name: "Tables", + extends: [`${pascalCase(schema.name)}TypeMap`], + properties: [], + }) + } + + // Create the module declaration + statements.push({ + kind: StructureKind.Module, + name: `"knex/types/tables"`, + hasDeclareKeyword: true, + statements: module_interface_statements, + }) + + // Create the source file + return project.createSourceFile( + `${output_dir}/generated/knex.ts`, + { + statements, + }, + { overwrite: true }, + ) +} diff --git a/src/lib/generate-types/file-generators/generated/kysely.ts b/src/lib/generate-types/file-generators/generated/kysely.ts new file mode 100644 index 0000000..940ae36 --- /dev/null +++ b/src/lib/generate-types/file-generators/generated/kysely.ts @@ -0,0 +1,79 @@ +import type { Config, Schema } from "../../types" +import { pascalCase } from "../../utils" +import { + StructureKind, + type SourceFile, + type Project, + type StatementedNodeStructure, +} from "ts-morph" + +export const createKyselyIndexFile = ( + args: { + project: Project + schemas: Schema[] + }, + config: Config +): SourceFile => { + const { project, schemas } = args + const { output_dir } = config + + const type_references: string[] = [] + + const statements: StatementedNodeStructure["statements"] = [ + { + kind: StructureKind.ImportDeclaration, + moduleSpecifier: "kysely", + namedImports: ["Kysely", "Transaction"], + isTypeOnly: true, + }, + ] + + for (const schema of schemas) { + if (Object.values(schema.tables).length === 0) continue + + statements.push({ + kind: StructureKind.ImportDeclaration, + moduleSpecifier: `./${schema.name}`, + namedImports: [ + { + name: "KyselySchemaTypeMap", + alias: `${pascalCase(schema.name)}TypeMap`, + }, + ], + isTypeOnly: true, + }) + + type_references.push(`${pascalCase(schema.name)}TypeMap`) + } + + statements.push( + (writer) => writer.newLine(), + { + kind: StructureKind.TypeAlias, + name: "KyselySchema", + isExported: true, + type: type_references.join(" & "), + }, + (writer) => writer.newLine(), + { + kind: StructureKind.TypeAlias, + name: "KyselyDatabase", + isExported: true, + type: `Kysely`, + }, + { + kind: StructureKind.TypeAlias, + name: "KyselyTransaction", + isExported: true, + type: `Transaction`, + } + ) + + return project.createSourceFile( + `${output_dir}/generated/kysely.ts`, + { + statements, + }, + { overwrite: true } + ) +} diff --git a/src/lib/generate-types/file-generators/generated/utils.ts b/src/lib/generate-types/file-generators/generated/utils.ts new file mode 100644 index 0000000..36fd3cf --- /dev/null +++ b/src/lib/generate-types/file-generators/generated/utils.ts @@ -0,0 +1,101 @@ +import { type Config } from "../../types" +import { type Project, type SourceFile } from "ts-morph" + +export const createGeneratedUtilsFile = ( + args: { + project: Project + }, + config: Config, +): SourceFile => { + const { project } = args + const { output_dir } = config + + const file_source = `import type { JSONValue } from "zapatos/db" +import { type ColumnType } from "kysely" + +type PartialWithNever = { + [P in keyof T as T[P] extends never ? never : P]?: T[P] +} & { + [P in keyof T as T[P] extends never ? P : never]: T[P] +} + +export type KyselyTable = { + [K in keyof Selectable]: ColumnType< + Selectable[K], + K extends keyof Initializer ? Initializer[K] : never, + K extends keyof PartialWithNever + ? PartialWithNever[K] + : never + > +} + +type KeysOfUnion = T extends T ? keyof T : never + +type NullableKeys = { + [K in keyof T]: null extends T[K] ? K : never +}[keyof T] + +/** + * Allows creating a type that is a subset of another type. + */ +export type SubsetOf< + Super, + Sub extends { + // The types of keys present in sub must be assignable to the types of the same keys in super + [K in keyof Super as K extends KeysOfUnion ? K : never]: Super[K] + } & { + // Keys that are nullable in super must stay nullable in sub + [K in keyof Sub as K extends NullableKeys + ? K + : never]: null extends Sub[K] ? any : null + } & { + // Keys in sub must exist in super + [K in keyof Sub as K extends keyof Super ? never : K]: never + } +> = Sub + +// Replaces the values of From with the values of To and ignores the rest of the properties of To +type ReplaceValueTypes = Omit & + Pick> + +// Works to make From properties optional but it would not work to make them mandatory as From[K] would include undefined +// TODO improve to keep unions (if possible) +type ReplaceKeyTypes = { + [K in keyof To as K extends keyof From ? K : never]: K extends keyof From + ? From[K] + : never +} & { + [K in keyof From as K extends keyof To ? never : K]: From[K] +} + +export type CustomizeDbType = ReplaceValueTypes< + DbType, + CustomProperties +> + +export type CustomizeDbTypeInitializer = + ReplaceValueTypes< + DbTypeInitializer, + ReplaceKeyTypes + > + +// TODO Migrating from pgtui to our custom types is a pain because of two bugs in pgtui. +// This type is a workaround to make the migration easier and should be removed later. +// To remove it, we need to fix a lot of type errors. It can be done per table thanks +// to a configuration option of generate-types. +export type ReproducePgtuiBugs = { + [K in keyof T]: K extends \`\${string}_id\` + ? string + : ReplaceJSONValueWithAny +} + +type ReplaceJSONValueWithAny = [JSONValue] extends [T] ? any : T` + + return project.createSourceFile( + `${output_dir}/generated/utils.ts`, + file_source, + { + overwrite: true, + }, + ) +} diff --git a/src/lib/generate-types/generate-types.ts b/src/lib/generate-types/generate-types.ts new file mode 100644 index 0000000..4e806ae --- /dev/null +++ b/src/lib/generate-types/generate-types.ts @@ -0,0 +1,109 @@ +import prettier from "prettier" +import { readDatabaseTree } from "./read-database-tree" +import type { Config, DatabaseTree } from "./types" +import { createQueryTypesFile } from "./file-generators/generated/[schema_name]/[TableName]QueryTypes" +import { createResultingTypeFile } from "./file-generators/generated/[schema_name]/[TableName]" +import { createSchemaGeneratedTypeIndexFile } from "./file-generators/generated/[schema_name]" +import { createCustomTypesFile } from "./file-generators/custom/[schema_name]/[TableName]CustomTypes" +import { createKnexIndexFile } from "./file-generators/generated/knex" +import { createKyselyIndexFile } from "./file-generators/generated/kysely" +import { createGeneratedIndexFile } from "./file-generators/generated" +import { createGeneratedUtilsFile } from "./file-generators/generated/utils" +import { Project, type SourceFile } from "ts-morph" + +/** + * Generate types based on a Zapatos database schema. + */ +export const generateTypes = async (config: Config) => { + const project = new Project() + const database_tree = readDatabaseTree(config) + + createGeneratedTypesFiles(project, database_tree, config) + createCustomTypesFiles(project, database_tree, config) + + await formatProjectFiles(project) + + project.saveSync() +} + +const createGeneratedTypesFiles = ( + project: Project, + database_tree: DatabaseTree, + config: Config, +) => { + const { + file_header = "// @generated\n// This file was automatically generated. DO NOT EDIT!\n\n", + } = config + + const schemas = Object.values(database_tree.schemas) + const generated_types_files: SourceFile[] = [ + createKyselyIndexFile({ project, schemas }, config), + createGeneratedIndexFile({ project, schemas }, config), + createGeneratedUtilsFile({ project }, config), + ] + + if (config.generate_knex_types) { + generated_types_files.push( + createKnexIndexFile({ project, schemas }, config), + ) + } + + for (const schema of schemas) { + for (const table of Object.values(schema.tables)) { + generated_types_files.push( + createQueryTypesFile({ project, schema, table }, config), + createResultingTypeFile({ project, schema, table }, config), + ) + } + if (Object.values(schema.tables).length > 0) { + generated_types_files.push( + createSchemaGeneratedTypeIndexFile({ project, schema }, config), + ) + } + } + + for (const source_file of generated_types_files) { + source_file.replaceWithText(`${file_header}${source_file.getFullText()}`) + } + + return generated_types_files +} + +const createCustomTypesFiles = ( + project: Project, + database_tree: DatabaseTree, + config: Config, +) => { + const custom_types_files: SourceFile[] = [] + for (const schema of Object.values(database_tree.schemas)) { + for (const table of Object.values(schema.tables)) { + if (!table.is_customizable) { + continue + } + try { + custom_types_files.push( + createCustomTypesFile({ project, schema, table }, config), + ) + } catch (error: any) { + if (error.message.includes("A source file already exists")) { + continue + } + throw error as Error + } + } + } + return custom_types_files +} + +const formatProjectFiles = async (project: Project) => { + for (const source_file of project.getSourceFiles()) { + const formatted_source = await prettier.format( + source_file.getFullText().replace(/;$/gm, ""), + { + semi: false, + parser: "typescript", + }, + ) + source_file.replaceWithText(formatted_source) + } +} diff --git a/src/lib/generate-types/index.ts b/src/lib/generate-types/index.ts new file mode 100644 index 0000000..0196b8f --- /dev/null +++ b/src/lib/generate-types/index.ts @@ -0,0 +1 @@ +export * from "./generate-types" diff --git a/src/lib/generate-types/read-database-tree.ts b/src/lib/generate-types/read-database-tree.ts new file mode 100644 index 0000000..7330352 --- /dev/null +++ b/src/lib/generate-types/read-database-tree.ts @@ -0,0 +1,229 @@ +import type { Column, Config, DatabaseTree, Schema, Table } from "./types" +import { + type InterfaceDeclaration, + Project, + type PropertySignature, + SyntaxKind, +} from "ts-morph" + +export const readDatabaseTree = (config: Config): DatabaseTree => { + const { zapatos_dir } = config + + const project = new Project() + + const zapatos_custom_types = readCustomZapatosTypes(config) + + const source_file = project.addSourceFileAtPath(`${zapatos_dir}/schema.d.ts`) + const zapatos_module = source_file.getModules()[0] + + if (!zapatos_module) { + throw new Error("Could not find the zapatos module in the schema file") + } + + const schemas: Record = {} + for (const schema_module of zapatos_module.getModules()) { + const schema_name = schema_module.getName() + const tables: Record = {} + + for (const table_module of schema_module.getModules()) { + const is_table = + table_module + .getStatementByKind(SyntaxKind.TypeAliasDeclaration) + ?.getName() === "Table" + + if (!is_table) { + continue + } + const table_name = table_module.getName() + const is_customizable = isTableCustomizable( + { + schema_name, + table_name, + }, + config + ) + const is_affected_by_pgtui_bugs = isTableAffectedByPgtuiBugs( + { + schema_name, + table_name, + }, + config + ) + + const table = { + name: table_name, + selectable_columns: {}, + insertable_columns: {}, + is_customizable, + is_affected_by_pgtui_bugs, + uses_zapatos_column_type: false, + } + + table.selectable_columns = getColumns( + table_module.getInterfaceOrThrow("Selectable"), + table, + zapatos_custom_types + ) + table.insertable_columns = getColumns( + table_module.getInterfaceOrThrow("Insertable"), + table, + zapatos_custom_types + ) + + tables[table_name] = table + } + + schemas[schema_name] = { + name: schema_name, + tables, + } + } + + return { + schemas, + } +} + +const isTableCustomizable = ( + args: { schema_name: string; table_name: string }, + config: Config +) => { + const { schema_name, table_name } = args + const { customizable_tables } = config + + const schema_customizable_tables = customizable_tables?.[schema_name] + return ( + schema_customizable_tables === "all" || + (schema_customizable_tables?.includes(table_name) ?? false) + ) +} + +const isTableAffectedByPgtuiBugs = ( + args: { schema_name: string; table_name: string }, + config: Config +) => { + const { schema_name, table_name } = args + const { reproduce_pgtui_bugs_for_tables } = config + + const pgtui_affected_tables = reproduce_pgtui_bugs_for_tables?.[schema_name] + return pgtui_affected_tables?.includes(table_name) ?? false +} + +const readCustomZapatosTypes = (config: Config) => { + const { zapatos_dir } = config + + const project = new Project() + const custom_zapatos_types: Record = {} + + const source_files = project.addSourceFilesAtPaths( + `${zapatos_dir}/custom/**/*.d.ts` + ) + + for (const source_file of source_files) { + const zapatos_module = source_file.getModules()[0] + + if (!zapatos_module) { + throw new Error("Could not find the zapatos module in the schema file") + } + + for (const type_alias of zapatos_module.getTypeAliases()) { + custom_zapatos_types[type_alias.getName()] = type_alias + .getTypeNodeOrThrow() + .getText() + } + } + return custom_zapatos_types +} + +const getColumns = ( + table_interface: InterfaceDeclaration, + table: Table, + zapatos_custom_types: Record +) => { + const columns: Record = {} + + for (const column of table_interface.getProperties()) { + const column_name = column.getName() + const column_type = customizeType(column, zapatos_custom_types) + + if (column_type.includes("db.")) { + table.uses_zapatos_column_type = true + } + + columns[column_name] = { + name: column_name, + type: column_type, + is_optional: column.hasQuestionToken(), + comments: [], + } + } + + return columns +} + +const customizeType = ( + column: PropertySignature, + zapatos_custom_types: Record +) => { + const type_node = column.getTypeNodeOrThrow() + const is_union = type_node.getKind() === SyntaxKind.UnionType + + const type_members = is_union + ? type_node + .asKindOrThrow(SyntaxKind.UnionType) + .getTypeNodes() + .map((node) => node.getText()) + : [type_node.getText()] + + let customized_type_members = type_members + customized_type_members = removeZapatosSpecificTypes(customized_type_members) + customized_type_members = replaceSvixMessageStatusEnum( + customized_type_members + ) + customized_type_members = replaceCustomZapatosTypesWithTheirDefinitions( + customized_type_members, + zapatos_custom_types + ) + customized_type_members = replaceJSONValueWithNonNullableVersion( + customized_type_members + ) + + return customized_type_members.join(" | ") +} + +const removeZapatosSpecificTypes = (type_members: string[]) => + type_members.filter( + (member) => + !( + member === "db.DefaultType" || + member.startsWith("db.Parameter") || + member.startsWith("db.SQLFragment") + ) + ) + +const replaceCustomZapatosTypesWithTheirDefinitions = ( + type_members: string[], + zapatos_custom_types: Record +) => + type_members.map((member) => + member.startsWith("c.Pg") + ? zapatos_custom_types[member.slice(2)] ?? member + : member + ) + +/** + * For some reason Zapatos generates a type `db.JSONValue` which is nullable. + * This is an issue as it means non-nullable jsonb columns are not correctly + * represented in the generated types. + */ +const replaceJSONValueWithNonNullableVersion = (type_members: string[]) => + type_members.map((member) => + member === "db.JSONValue" ? "NonNullable" : member + ) + +const replaceSvixMessageStatusEnum = (type_members: string[]) => + type_members.map((member) => + member === "svix_message_status_enum" + ? `"no_svix_app" | "sent" | "unsent"` + : member + ) diff --git a/src/lib/generate-types/types.ts b/src/lib/generate-types/types.ts new file mode 100644 index 0000000..686edad --- /dev/null +++ b/src/lib/generate-types/types.ts @@ -0,0 +1,34 @@ +export type Config = { + zapatos_dir: string + output_dir: string + customizable_tables?: Record + reproduce_pgtui_bugs_for_tables?: Record + generate_knex_types?: boolean + main_schema?: string + file_header?: string +} + +export type DatabaseTree = { + schemas: Record +} + +export type Schema = { + name: string + tables: Record +} + +export type Table = { + name: string + selectable_columns: Record + insertable_columns: Record + is_customizable: boolean + is_affected_by_pgtui_bugs: boolean + uses_zapatos_column_type: boolean +} + +export type Column = { + name: string + type: string + is_optional: boolean + comments: string[] +} diff --git a/src/lib/generate-types/utils.ts b/src/lib/generate-types/utils.ts new file mode 100644 index 0000000..67932a9 --- /dev/null +++ b/src/lib/generate-types/utils.ts @@ -0,0 +1,5 @@ +export const pascalCase = (str: string): string => { + return str.replace(/(_\w|^\w)/g, (match) => + match.replace("_", "").toUpperCase() + ) +} diff --git a/src/lib/index.ts b/src/lib/index.ts index d546f51..f1142df 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,2 +1,3 @@ +export * from "./generate-types" export * from "./generate-schema" export * from "./generate-structure"