diff --git a/.eslintrc.json b/.eslintrc.json index 91850cd..5e5db42 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -170,7 +170,6 @@ } ], "space-before-function-paren": "off", - "@typescript-eslint/no-var-requires": "warn", "@typescript-eslint/space-before-function-paren": [ "error", "always" diff --git a/README.md b/README.md index 026214e..c04b84c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ npm install prisma-models-graph **2. Add the generator to the schema** ```prisma -generator modelsGraph { +generator jsonSchema { provider = "prisma-models-graph" } ``` @@ -24,7 +24,7 @@ generator modelsGraph { Additional options ```prisma -generator modelsGraph { +generator jsonSchema { provider = "prisma-models-graph" output = "./customOutputs" fileName = "custom.json" @@ -34,61 +34,8 @@ generator modelsGraph { ## Usage - Add custom relation annotation next to the field you want annotate relationship. -- Format: `/// [[.]]` (The triple slash is important.) - -```prisma -userId Int @map("user_id) /// [[User.id]] -``` +- Format: `/// [[.]]` + - With the above annotation, the generated models graph will be like this: - -```js -{ - "users": { - "attributes": [ - "id", - "email", - "name", - "user_type_id" - ], - "relations": [ - { - "modelName": "posts", - "condition": "users.id = posts.user_id" - } - ] - }, - "posts": { - "attributes": [ - "id", - "subject", - "body", - "user_id" - ], - "relations": [ - { - "modelName": "users", - "condition": "posts.user_id = users.id" - } - ] - } -} -``` - -- To access the generated models graph, import it from `@generated/models-graph`. The generated models graph will be a _typesafe_ object matching the models declared in `schema.prisma` - -```js -import { ModelsGraph } from '@generated/models-graph' -``` - -- There are a few helper types available: - -```js -import { - ModelsGraph, // Generated models graph object - ParsedModel, // Type definition of a singular generated model graph - ParsedModels, // Type definition of all generated models graph - ParsedModelRelation, // Type definition of the relation between two models - ModelNames, // List of all generated models name -} from '@generated/models-graph' -``` + diff --git a/assets/annotation.png b/assets/annotation.png new file mode 100644 index 0000000..fbc2520 Binary files /dev/null and b/assets/annotation.png differ diff --git a/assets/output.png b/assets/output.png new file mode 100644 index 0000000..d18460b Binary files /dev/null and b/assets/output.png differ diff --git a/package.json b/package.json index 8629cca..fca79d4 100644 --- a/package.json +++ b/package.json @@ -16,34 +16,31 @@ "prepack": "yarn build", "test": "jest", "lint": "eslint --fix .", - "prepare": "husky install", - "usage": "ts-node usage/index.ts" + "prepare": "husky install" }, "dependencies": { "@prisma/client": "^5.2.0", "@prisma/generator-helper": "^5.2.0", "@prisma/internals": "^5.2.0", - "prettier": "3.0.3", "prisma": "^5.2.0", - "ts-node": "^10.9.1" + "prettier": "3.0.3" }, "devDependencies": { - "@semantic-release/changelog": "^6.0.1", - "@semantic-release/git": "^10.0.1", "@types/jest": "^29.5.2", "@types/node": "^20.4.0", + "jest": "^29.6.1", + "ts-jest": "^29.1.1", + "typescript": "^5.1.6", + "@semantic-release/changelog": "^6.0.1", + "@semantic-release/git": "^10.0.1", + "semantic-release": "^18.0.1", "@typescript-eslint/eslint-plugin": "^5.61.0", "@typescript-eslint/parser": "^5.61.0", "@typescript-eslint/typescript-estree": "^5.61.0", "eslint": "^8.44.0", "eslint-plugin-jest": "^27.2.2", "eslint-plugin-jest-formatting": "^3.1.0", - "husky": "7.0.4", - "jest": "^29.6.1", - "semantic-release": "^18.0.1", - "ts-jest": "^29.1.1", - "ts-morph": "20.0.0", - "typescript": "^5.1.6" + "husky": "7.0.4" }, "homepage": "https://github.com/dangchinh25/prisma-models-graph", "repository": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b198bd..ef09c02 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,9 +23,6 @@ importers: prisma: specifier: ^5.2.0 version: 5.2.0 - ts-node: - specifier: ^10.9.1 - version: 10.9.1(@types/node@20.4.0)(typescript@5.1.6) devDependencies: '@semantic-release/changelog': specifier: ^6.0.1 @@ -62,16 +59,13 @@ importers: version: 7.0.4 jest: specifier: ^29.6.1 - version: 29.6.1(@types/node@20.4.0)(ts-node@10.9.1) + version: 29.6.1(@types/node@20.4.0) semantic-release: specifier: ^18.0.1 version: 18.0.1 ts-jest: specifier: ^29.1.1 version: 29.1.1(@babel/core@7.23.2)(jest@29.6.1)(typescript@5.1.6) - ts-morph: - specifier: 20.0.0 - version: 20.0.0 typescript: specifier: ^5.1.6 version: 5.1.6 @@ -429,12 +423,6 @@ packages: dev: true optional: true - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/trace-mapping': 0.3.9 - /@eslint-community/eslint-utils@4.4.0(eslint@8.44.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -520,7 +508,7 @@ packages: slash: 3.0.0 dev: true - /@jest/core@29.7.0(ts-node@10.9.1): + /@jest/core@29.7.0: resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -541,7 +529,7 @@ packages: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.4.0)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@20.4.0) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -734,6 +722,7 @@ packages: /@jridgewell/resolve-uri@3.1.1: resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} + dev: true /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} @@ -742,6 +731,7 @@ packages: /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true /@jridgewell/trace-mapping@0.3.20: resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} @@ -750,12 +740,6 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 - /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1172,27 +1156,6 @@ packages: '@sinonjs/commons': 3.0.0 dev: true - /@ts-morph/common@0.21.0: - resolution: {integrity: sha512-ES110Mmne5Vi4ypUKrtVQfXFDtCsDXiUiGxF6ILVlE90dDD4fdpC1LSjydl/ml7xJWKSDZwUYD2zkOePMSrPBA==} - dependencies: - fast-glob: 3.3.1 - minimatch: 7.4.6 - mkdirp: 2.1.6 - path-browserify: 1.0.1 - dev: true - - /@tsconfig/node10@1.0.9: - resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} - - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - - /@tsconfig/node16@1.0.4: - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - /@types/babel__core@7.20.3: resolution: {integrity: sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==} dependencies: @@ -1515,14 +1478,11 @@ packages: acorn: 8.11.2 dev: true - /acorn-walk@8.3.0: - resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==} - engines: {node: '>=0.4.0'} - /acorn@8.11.2: resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} engines: {node: '>=0.4.0'} hasBin: true + dev: true /agent-base@7.1.0: resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} @@ -1632,9 +1592,6 @@ packages: zip-stream: 4.1.1 dev: false - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - /arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} dev: false @@ -1785,6 +1742,7 @@ packages: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 + dev: false /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} @@ -1958,10 +1916,6 @@ packages: engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} dev: true - /code-block-writer@12.0.0: - resolution: {integrity: sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==} - dev: true - /collect-v8-coverage@1.0.2: resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} dev: true @@ -2084,7 +2038,7 @@ packages: readable-stream: 3.6.2 dev: false - /create-jest@29.7.0(@types/node@20.4.0)(ts-node@10.9.1): + /create-jest@29.7.0(@types/node@20.4.0): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -2093,7 +2047,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.4.0)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@20.4.0) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -2103,9 +2057,6 @@ packages: - ts-node dev: true - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -2196,10 +2147,6 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2311,7 +2258,7 @@ packages: '@typescript-eslint/eslint-plugin': 5.61.0(@typescript-eslint/parser@5.61.0)(eslint@8.44.0)(typescript@5.1.6) '@typescript-eslint/utils': 5.62.0(eslint@8.44.0)(typescript@5.1.6) eslint: 8.44.0 - jest: 29.6.1(@types/node@20.4.0)(ts-node@10.9.1) + jest: 29.6.1(@types/node@20.4.0) transitivePeerDependencies: - supports-color - typescript @@ -3109,7 +3056,7 @@ packages: - supports-color dev: true - /jest-cli@29.7.0(@types/node@20.4.0)(ts-node@10.9.1): + /jest-cli@29.7.0(@types/node@20.4.0): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -3119,14 +3066,14 @@ packages: node-notifier: optional: true dependencies: - '@jest/core': 29.7.0(ts-node@10.9.1) + '@jest/core': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.4.0)(ts-node@10.9.1) + create-jest: 29.7.0(@types/node@20.4.0) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.4.0)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@20.4.0) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -3137,7 +3084,7 @@ packages: - ts-node dev: true - /jest-config@29.7.0(@types/node@20.4.0)(ts-node@10.9.1): + /jest-config@29.7.0(@types/node@20.4.0): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -3172,7 +3119,6 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.1(@types/node@20.4.0)(typescript@5.1.6) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -3461,7 +3407,7 @@ packages: supports-color: 8.1.1 dev: true - /jest@29.6.1(@types/node@20.4.0)(ts-node@10.9.1): + /jest@29.6.1(@types/node@20.4.0): resolution: {integrity: sha512-Nirw5B4nn69rVUZtemCQhwxOBhm0nsp3hmtF4rzCeWD7BkjAXRIji7xWQfnTNbz9g0aVsBX6aZK3n+23LM6uDw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -3471,10 +3417,10 @@ packages: node-notifier: optional: true dependencies: - '@jest/core': 29.7.0(ts-node@10.9.1) + '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.4.0)(ts-node@10.9.1) + jest-cli: 29.7.0(@types/node@20.4.0) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -3698,6 +3644,7 @@ packages: /make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true /makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -3792,13 +3739,6 @@ packages: brace-expansion: 2.0.1 dev: false - /minimatch@7.4.6: - resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} - engines: {node: '>=10'} - dependencies: - brace-expansion: 2.0.1 - dev: true - /minimist-options@4.1.0: resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} engines: {node: '>= 6'} @@ -3812,12 +3752,6 @@ packages: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} dev: true - /mkdirp@2.1.6: - resolution: {integrity: sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==} - engines: {node: '>=10'} - hasBin: true - dev: true - /modify-values@1.0.1: resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} engines: {node: '>=0.10.0'} @@ -4163,10 +4097,6 @@ packages: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - /path-browserify@1.0.1: - resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - dev: true - /path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} @@ -4832,7 +4762,7 @@ packages: '@babel/core': 7.23.2 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 29.6.1(@types/node@20.4.0)(ts-node@10.9.1) + jest: 29.6.1(@types/node@20.4.0) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -4842,43 +4772,6 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-morph@20.0.0: - resolution: {integrity: sha512-JVmEJy2Wow5n/84I3igthL9sudQ8qzjh/6i4tmYCm6IqYyKFlNbJZi7oBdjyqcWSWYRu3CtL0xbT6fS03ESZIg==} - dependencies: - '@ts-morph/common': 0.21.0 - code-block-writer: 12.0.0 - dev: true - - /ts-node@10.9.1(@types/node@20.4.0)(typescript@5.1.6): - resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.9 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 20.4.0 - acorn: 8.11.2 - acorn-walk: 8.3.0 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.1.6 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - /ts-pattern@4.3.0: resolution: {integrity: sha512-pefrkcd4lmIVR0LA49Imjf9DYLK8vtWhqBPA3Ya1ir8xCW0O2yjL9dsCVvI7pCodLC5q7smNpEtDR2yVulQxOg==} dev: false @@ -4939,6 +4832,7 @@ packages: resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} engines: {node: '>=14.17'} hasBin: true + dev: true /uglify-js@3.17.4: resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} @@ -4991,9 +4885,6 @@ packages: hasBin: true dev: false - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - /v8-to-istanbul@9.1.3: resolution: {integrity: sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==} engines: {node: '>=10.12.0'} @@ -5113,10 +5004,6 @@ packages: yargs-parser: 21.1.1 dev: true - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} diff --git a/prisma/test/custom.json b/prisma/test/custom.json new file mode 100644 index 0000000..ec6a2c3 --- /dev/null +++ b/prisma/test/custom.json @@ -0,0 +1,78 @@ +{ + "users": { + "attributes": [ + "id", + "email", + "name", + "user_type_id" + ], + "relations": [ + { + "modelName": "user_types", + "condition": "users.user_type_id = user_types.id" + }, + { + "modelName": "posts", + "condition": "users.id = posts.user_id" + }, + { + "modelName": "users_user_groups", + "condition": "users.id = users_user_groups.user_id" + } + ] + }, + "posts": { + "attributes": [ + "id", + "subject", + "body", + "user_id" + ], + "relations": [ + { + "modelName": "users", + "condition": "posts.user_id = users.id" + } + ] + }, + "user_types": { + "attributes": [ + "id", + "name" + ], + "relations": [ + { + "modelName": "users", + "condition": "user_types.id = users.user_type_id" + } + ] + }, + "user_groups": { + "attributes": [ + "id", + "name" + ], + "relations": [ + { + "modelName": "users_user_groups", + "condition": "user_groups.id = users_user_groups.user_group_id" + } + ] + }, + "users_user_groups": { + "attributes": [ + "user_id", + "user_group_id" + ], + "relations": [ + { + "modelName": "users", + "condition": "users_user_groups.user_id = users.id" + }, + { + "modelName": "user_groups", + "condition": "users_user_groups.user_group_id = user_groups.id" + } + ] + } +} diff --git a/src/bin.ts b/src/bin.ts new file mode 100644 index 0000000..d0e369c --- /dev/null +++ b/src/bin.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env node +import './generator'; diff --git a/src/cli/generator.ts b/src/cli/generator.ts deleted file mode 100644 index 96eeaed..0000000 --- a/src/cli/generator.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { GeneratorManifest, generatorHandler } from '@prisma/generator-helper'; -import { generate } from './prisma-generator'; -import { logger } from '@prisma/internals'; -import { GENERATOR_NAME, DEFAULT_OUTPUT_FOLDER } from './constants'; - -const { version } = require( '../../package.json' ); - -generatorHandler( { - onManifest (): GeneratorManifest { - logger.info( `${ GENERATOR_NAME }:Registered` ); - - return { - version, - defaultOutput: DEFAULT_OUTPUT_FOLDER, - prettyName: GENERATOR_NAME - }; - }, - onGenerate: generate -} ); diff --git a/src/cli/prisma-generator.ts b/src/cli/prisma-generator.ts deleted file mode 100644 index d133b1d..0000000 --- a/src/cli/prisma-generator.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { GeneratorOptions } from '@prisma/generator-helper'; -import { generateCode } from '../generator/generateCode'; - -export const generate = async ( options: GeneratorOptions ): Promise => { - await generateCode( options.dmmf ); -}; \ No newline at end of file diff --git a/src/cli/constants.ts b/src/constants.ts similarity index 100% rename from src/cli/constants.ts rename to src/constants.ts diff --git a/src/generator.ts b/src/generator.ts index 1df8391..98b3aa4 100644 --- a/src/generator.ts +++ b/src/generator.ts @@ -1,3 +1,47 @@ #!/usr/bin/env node -import './cli/generator'; \ No newline at end of file +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ +/* eslint-disable @typescript-eslint/no-var-requires */ +import { + generatorHandler, GeneratorManifest, GeneratorOptions +} from '@prisma/generator-helper'; +import { logger } from '@prisma/internals'; +import path from 'path'; +import { + DEFAULT_FILE_NAME, DEFAULT_OUTPUT_FOLDER, GENERATOR_NAME +} from './constants'; +import { formatFileName, parseDMMFModels } from './helpers'; +import { writeFileSafely } from './utils/writeFileSafely'; + +const { version } = require( '../package.json' ); + +generatorHandler( { + onManifest (): GeneratorManifest { + logger.info( `${ GENERATOR_NAME }:Registered` ); + + return { + version, + defaultOutput: DEFAULT_OUTPUT_FOLDER, + prettyName: GENERATOR_NAME + }; + }, + onGenerate: async ( options: GeneratorOptions ): Promise => { + const modelsGraph = parseDMMFModels( options.dmmf.datamodel.models ); + + let writeFileName = DEFAULT_FILE_NAME; + const { fileName } = options.generator.config; + + if ( fileName ) { + // This is to handle generator config can be an array of string + writeFileName = typeof fileName === 'string' ? formatFileName( fileName ) : formatFileName( fileName[ 0 ] ); + } + + const writeLocation1 = path.join( + options.generator.output?.value!, + writeFileName + ); + + await writeFileSafely( writeLocation1, JSON.stringify( modelsGraph ) ); + } +} ); diff --git a/src/generator/config.ts b/src/generator/config.ts deleted file mode 100644 index 1f4802e..0000000 --- a/src/generator/config.ts +++ /dev/null @@ -1,17 +0,0 @@ -export const TYPE_DIRECTORY_NAME = 'types'; - -export const MODELS_GRAPH_FILE_NAME = 'modelsGraph.ts'; - -export const MODELS_GRAPH_VARIABLE_NAME = 'ModelsGraph'; - -export const INDEX_FILE_NAME = 'index.ts'; - -export const PARSED_MODELS_TYPE_NAME = 'ParsedModels'; - -export const PARSED_MODEL_TYPE_NAME = 'ParsedModel'; - -export const PARSED_MODEL_RELATION_TYPE_NAME = 'ParsedModelRelation'; - -export const MODEL_NAMES_VARIABLE_NAME = 'modelNames'; - -export const MODEL_NAMES_TYPE_NAME = 'ModelNames'; \ No newline at end of file diff --git a/src/generator/generateCode.ts b/src/generator/generateCode.ts deleted file mode 100644 index b9a83a3..0000000 --- a/src/generator/generateCode.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { DMMF } from '@prisma/generator-helper'; -import path from 'path'; -import { - CompilerOptions, - Directory, - ModuleKind, - Project, - ScriptTarget, - SourceFile, - VariableDeclarationKind -} from 'ts-morph'; -import { - INDEX_FILE_NAME, - MODELS_GRAPH_FILE_NAME, - MODELS_GRAPH_VARIABLE_NAME, - MODEL_NAMES_TYPE_NAME, - MODEL_NAMES_VARIABLE_NAME, - PARSED_MODELS_TYPE_NAME, - PARSED_MODEL_RELATION_TYPE_NAME, - PARSED_MODEL_TYPE_NAME, - TYPE_DIRECTORY_NAME -} from './config'; -import { parseDMMFModels } from './helpers'; -import { ParsedModels } from './types'; - -const baseCompilerOptions: CompilerOptions = { - target: ScriptTarget.ES2022, - module: ModuleKind.CommonJS, - emitDecoratorMetadata: true, - experimentalDecorators: true, - esModuleInterop: true, - declaration: true -}; - -const baseDirPath = 'node_modules/@generated/models-graph'; - -export const generateCode = async ( - dmmf: DMMF.Document -): Promise => { - const modelsGraph = parseDMMFModels( dmmf.datamodel.models ); - - const project = new Project( { compilerOptions: { ...baseCompilerOptions } } ); - - const generatedTypesDirectory = await generateTypeDirectory( - project, - baseDirPath - ); - - const generatedModelsGraphFile = await generateModelsGraphFile( - project, - baseDirPath, - generatedTypesDirectory.getPath(), - modelsGraph - ); - - await generateIndexFile( project, baseDirPath, [ - generatedTypesDirectory, - generatedModelsGraphFile - ] ); - - await project.emit(); -}; - -// TODO figure out how to dynamically export type -const generateTypeDirectory = async ( - project: Project, - baseGeneratedDirPath: string -): Promise => { - const generatedTypeDirectory = project.createDirectory( - path.resolve( baseGeneratedDirPath, TYPE_DIRECTORY_NAME ) - ); - - const modelsTypeSourceFile = generatedTypeDirectory.createSourceFile( - path.resolve( generatedTypeDirectory.getPath(), 'models.ts' ), - `export type ${ PARSED_MODEL_RELATION_TYPE_NAME } = { - modelName: string; - condition: string; - }; - - export type ${ PARSED_MODEL_TYPE_NAME } = { - attributes: string[]; - relations: ${ PARSED_MODEL_RELATION_TYPE_NAME }[]; - }; - - export type ${ PARSED_MODELS_TYPE_NAME } = { - [modelName: string]: ${ PARSED_MODEL_TYPE_NAME }; - };`, - { overwrite: true } - ); - - await generateIndexFile( - project, - generatedTypeDirectory.getPath(), - [ modelsTypeSourceFile ] - ); - - await generatedTypeDirectory.save(); - - return generatedTypeDirectory; -}; - -const generateModelsGraphFile = async ( - project: Project, - baseGeneratedDirPath: string, - generatedTypesDirectoryPath: string, - modelsGraph: ParsedModels -): Promise => { - const modelsGraphSourceFile = project.createSourceFile( - path.resolve( baseGeneratedDirPath, MODELS_GRAPH_FILE_NAME ), - undefined, - { overwrite: true } - ); - - // Add import statements - const relativePathToTypesDirectory = `./${ modelsGraphSourceFile.getRelativePathTo( generatedTypesDirectoryPath ) }`; - - modelsGraphSourceFile.addImportDeclarations( [ - { - moduleSpecifier: relativePathToTypesDirectory, - namedImports: [ PARSED_MODEL_TYPE_NAME ] - } - ] ); - - // Generate dynamic types and export them - const modelNames = Object.keys( modelsGraph ); - - modelsGraphSourceFile.addVariableStatement( { - declarationKind: VariableDeclarationKind.Const, - declarations: [ - { - name: MODEL_NAMES_VARIABLE_NAME, - initializer: `${ JSON.stringify( modelNames ) } as const` - } - ] - } ); - - modelsGraphSourceFile.addStatements( [ `export type ${ MODEL_NAMES_TYPE_NAME } = typeof ${ MODEL_NAMES_VARIABLE_NAME }[number];` ] ); - - // Add export statement for the main ModelsGraph - modelsGraphSourceFile.addVariableStatement( { - declarationKind: VariableDeclarationKind.Const, - declarations: [ - { - name: MODELS_GRAPH_VARIABLE_NAME, - type: `{[modelName in ${ MODEL_NAMES_TYPE_NAME }]: ${ PARSED_MODEL_TYPE_NAME }}`, - initializer: JSON.stringify( modelsGraph ) - } - ], - isExported: true - } ); - - return modelsGraphSourceFile; -}; - -const generateIndexFile = async ( - project: Project, - baseGeneratedDirPath: string, - modules: ( SourceFile | Directory )[] -): Promise => { - const indexSourceFile = project.createSourceFile( - path.resolve( baseGeneratedDirPath, INDEX_FILE_NAME ), - undefined, - { overwrite: true } - ); - - modules.forEach( module => { - const moduleName = module.getBaseName() - .split( '.' )[ 0 ]; - - indexSourceFile.addExportDeclaration( { moduleSpecifier: `./${ moduleName }` } ); - } ); - - return indexSourceFile; -}; \ No newline at end of file diff --git a/src/generator/index.ts b/src/generator/index.ts deleted file mode 100644 index da403bf..0000000 --- a/src/generator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './generateCode'; \ No newline at end of file diff --git a/src/generator/helpers/fileName.ts b/src/helpers/fileName.ts similarity index 100% rename from src/generator/helpers/fileName.ts rename to src/helpers/fileName.ts diff --git a/src/generator/helpers/index.ts b/src/helpers/index.ts similarity index 100% rename from src/generator/helpers/index.ts rename to src/helpers/index.ts diff --git a/src/generator/helpers/parser.ts b/src/helpers/parser.ts similarity index 100% rename from src/generator/helpers/parser.ts rename to src/helpers/parser.ts diff --git a/src/generator/types/index.ts b/src/types/index.ts similarity index 100% rename from src/generator/types/index.ts rename to src/types/index.ts diff --git a/src/generator/types/models.ts b/src/types/models.ts similarity index 70% rename from src/generator/types/models.ts rename to src/types/models.ts index 4f9f743..8e85681 100644 --- a/src/generator/types/models.ts +++ b/src/types/models.ts @@ -1,11 +1,11 @@ -export type ParsedModelRelation = { +export type ParseModelRelation = { modelName: string; condition: string; }; export type ParsedModel = { attributes: string[]; - relations: ParsedModelRelation[]; + relations: ParseModelRelation[]; }; export type ParsedModels = { diff --git a/tests/helpers/parser.test.ts b/tests/helpers/parser.test.ts index 738e673..da8770b 100644 --- a/tests/helpers/parser.test.ts +++ b/tests/helpers/parser.test.ts @@ -1,6 +1,6 @@ -import { parseDMMFModels } from '../../src/generator/helpers'; +import { parseDMMFModels } from '../../src/helpers'; import { getSampleDMMF } from '../__fixtures__/getSampleDMMF'; -import { ParsedModels } from '../../src/generator/types'; +import { ParsedModels } from '../../src/types'; import { DMMF } from '@prisma/generator-helper'; describe( 'parseDMMFModels', () => { diff --git a/tsconfig.json b/tsconfig.json index 9bf26d2..6bfff05 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,7 +26,6 @@ "exclude": [ "**/node_modules", "**/dist", - "./tests", - "./usage" + "./tests" ] } \ No newline at end of file diff --git a/usage/index.ts b/usage/index.ts deleted file mode 100644 index cb137d6..0000000 --- a/usage/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { ModelsGraph } from '@generated/models-graph'; - -console.log( ModelsGraph ); \ No newline at end of file