chore(): start moving some packages to the core directory (#7215)
This commit is contained in:
1 parent
fdee748eed
commit
bbccd6481d
1436 files changed
+275
-756
No files matched your search
@@ -0,0 +1,6 @@
|
||||
/dist
|
||||
node_modules
|
||||
.DS_store
|
||||
.env*
|
||||
.env
|
||||
*.sql
|
||||
@@ -0,0 +1,335 @@
|
||||
# @medusajs/oas-cli
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6812](https://github.com/medusajs/medusa/pull/6812) [`e005987adf`](https://github.com/medusajs/medusa/commit/e005987adf2a2dd8c2748e7abc360cc93e7c05ad) Thanks [@shahednasser](https://github.com/shahednasser)! - fix(medusa-oas-cli): fix tool not working in Medusa backends
|
||||
|
||||
- Updated dependencies [[`0168c819da`](https://github.com/medusajs/medusa/commit/0168c819da2bcdf2391c5fb5501342ea140882df), [`70859397c0`](https://github.com/medusajs/medusa/commit/70859397c00ad0b45a517547e2792ed4f6882d73), [`deab12e27e`](https://github.com/medusajs/medusa/commit/deab12e27e8249e26d24d7bc904c18195679ff24), [`56481e683d`](https://github.com/medusajs/medusa/commit/56481e683d33ff98f0d4c4e144873bb23f993c9c), [`9073d7aba3`](https://github.com/medusajs/medusa/commit/9073d7aba3419e4dc0a206473291a46ebd79b8c1), [`7bc7adeeb4`](https://github.com/medusajs/medusa/commit/7bc7adeeb4568ad85a81df08e3d6d3b5023cee13), [`509ddf9a56`](https://github.com/medusajs/medusa/commit/509ddf9a5631b4c8a4c2641595c40d7f9261e563), [`68b9812aa1`](https://github.com/medusajs/medusa/commit/68b9812aa1fe8a9e368112e721cd868919369980), [`4974f5e455`](https://github.com/medusajs/medusa/commit/4974f5e4557bd64a328a881ec02b91e15485bd23), [`205573f5e3`](https://github.com/medusajs/medusa/commit/205573f5e3bb826abe1cc1bc16855f079aa490e4), [`26531c5a38`](https://github.com/medusajs/medusa/commit/26531c5a38bf09ab3e77a1444cefd65a073ae713), [`05e857d256`](https://github.com/medusajs/medusa/commit/05e857d25657b5576a891c9b48c19c1759c70701), [`1ef9c78cea`](https://github.com/medusajs/medusa/commit/1ef9c78cea080c3b7c136f909c6cddec9d8f0c62), [`20132d7cea`](https://github.com/medusajs/medusa/commit/20132d7cea13b7c7ae77b33684d01a9ab40f7ed3)]:
|
||||
- @medusajs/medusa@1.20.4
|
||||
- @medusajs/types@1.11.15
|
||||
- @medusajs/utils@1.11.8
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6338](https://github.com/medusajs/medusa/pull/6338) [`374a3f4dab`](https://github.com/medusajs/medusa/commit/374a3f4dab7bf893ba3c579fa7f9c346fa30ad64) Thanks [@shahednasser](https://github.com/shahednasser)! - feat(@medusajs/medusa-oas-cli): added v2 flag
|
||||
feat(@medusajs/oas-github-ci): added v2 flag
|
||||
- Updated dependencies [[`1fd0457c15`](https://github.com/medusajs/medusa/commit/1fd0457c153b2ef7657c052878d8e5364e1b324a), [`9288f53327`](https://github.com/medusajs/medusa/commit/9288f53327b8ce617af92ed8d14d9459cbfeb13c), [`e124762873`](https://github.com/medusajs/medusa/commit/e124762873cd43af8eefa9fee4698450fdf8c30f), [`d4b921f3db`](https://github.com/medusajs/medusa/commit/d4b921f3dbe0a38f1565a8de759996c70798d58e), [`557d86afbf`](https://github.com/medusajs/medusa/commit/557d86afbfef707d2998e4e5d1ce3559ec22f9f8), [`ac86362e81`](https://github.com/medusajs/medusa/commit/ac86362e81d8523cb8e3dfad026fc94658513018), [`e4acde1aa2`](https://github.com/medusajs/medusa/commit/e4acde1aa2eb57f07e6692fe8b61f728948b9a96), [`1a661adf3e`](https://github.com/medusajs/medusa/commit/1a661adf3ef4991aa6e237dd894b6a5c47cd4aca), [`0c705d7bd4`](https://github.com/medusajs/medusa/commit/0c705d7bd41a768c48017ae95b3c8414d96c6acb), [`56504c99f0`](https://github.com/medusajs/medusa/commit/56504c99f0df7a375b303084c43ee4f15db828a3), [`56cbf88115`](https://github.com/medusajs/medusa/commit/56cbf88115994adea7037c3f2814f0c96af3cfc0), [`36a61658f9`](https://github.com/medusajs/medusa/commit/36a61658f969a7b19c84a1e621ad1464927cafb1), [`c3f26a6826`](https://github.com/medusajs/medusa/commit/c3f26a68266ce2b4427c04b03120e4a441f29eec), [`04a532e5ef`](https://github.com/medusajs/medusa/commit/04a532e5efabbf75b1e4155520b1da175b686ffc), [`f0ef0a8784`](https://github.com/medusajs/medusa/commit/f0ef0a87845764bae7610ee854592bb9800210f5), [`296d7faad4`](https://github.com/medusajs/medusa/commit/296d7faad45d77fffb39de13457f996dce5256ed), [`0c2a460751`](https://github.com/medusajs/medusa/commit/0c2a460751644021056d0f99d9b1fffe509fb7ab), [`25d176b851`](https://github.com/medusajs/medusa/commit/25d176b851c041ecc7901163b704b36b7e585076), [`1ba35b02dd`](https://github.com/medusajs/medusa/commit/1ba35b02dd52eeca9f3e1bee073c5e7a17edbc33), [`c319edb8e0`](https://github.com/medusajs/medusa/commit/c319edb8e0ecd13d086652147667916e5abab2d8), [`7c46b0f88b`](https://github.com/medusajs/medusa/commit/7c46b0f88b65467a9fb734061a7cc8e7bdb3c85c), [`0b9fcb6324`](https://github.com/medusajs/medusa/commit/0b9fcb6324eee9f2556c7e6317775fae93b12a47), [`586df9da25`](https://github.com/medusajs/medusa/commit/586df9da250e492442769f5bac2f8b3de1d46f05), [`b3d826497b`](https://github.com/medusajs/medusa/commit/b3d826497b3dae5e1b26b7924706c24fd5e87ca5), [`a86c87fe14`](https://github.com/medusajs/medusa/commit/a86c87fe1442afce9285e39255914e01012b4449), [`640eccd5dd`](https://github.com/medusajs/medusa/commit/640eccd5ddbb163e0f987ce6c772f1129c2e2632), [`8ea37d03c9`](https://github.com/medusajs/medusa/commit/8ea37d03c914a5004a3e42770668b2d1f7f8f564), [`339a946f38`](https://github.com/medusajs/medusa/commit/339a946f389033c21e05338f9dbf07d88e140533), [`fb25471e92`](https://github.com/medusajs/medusa/commit/fb25471e927c0cc91525f5e0134b935cd36596b5), [`ac829fc67f`](https://github.com/medusajs/medusa/commit/ac829fc67f7495b08f28e55923c59f0fd6320311), [`d9d5afc3cf`](https://github.com/medusajs/medusa/commit/d9d5afc3cfc29221d0e65bff7b78474a8fb8f31f), [`c3c4f49fc2`](https://github.com/medusajs/medusa/commit/c3c4f49fc2126f950e69e291ca939ca88a15afd3), [`c2d56ca12b`](https://github.com/medusajs/medusa/commit/c2d56ca12b89af078b885a0acced20e29bf6f8f5), [`9288f53327`](https://github.com/medusajs/medusa/commit/9288f53327b8ce617af92ed8d14d9459cbfeb13c), [`0d46abf0ff`](https://github.com/medusajs/medusa/commit/0d46abf0ffa4c5e03bf7d2a9cdf1db828a76bea8), [`fafde4f54d`](https://github.com/medusajs/medusa/commit/fafde4f54d3ef75a7d382e6cbf94e38b3deae99b), [`b78f863d80`](https://github.com/medusajs/medusa/commit/b78f863d80cad0e7075585cd400dc47ac05f4bf1), [`8dad2b51a2`](https://github.com/medusajs/medusa/commit/8dad2b51a26c4c3c14a6c95f70424c8bef2ad63e), [`2d00625729`](https://github.com/medusajs/medusa/commit/2d00625729e7dab02149751327239992dea3a8e1), [`873c21355c`](https://github.com/medusajs/medusa/commit/873c21355c94c7c38c6f5575ca807c5aa4adcadb), [`608c10383a`](https://github.com/medusajs/medusa/commit/608c10383a1a86068f0648d5aa641cbf11ffd323), [`0c705d7bd4`](https://github.com/medusajs/medusa/commit/0c705d7bd41a768c48017ae95b3c8414d96c6acb), [`78e5ec459a`](https://github.com/medusajs/medusa/commit/78e5ec459a637946482a3ee9f8b437656686988f), [`d37ff8024d`](https://github.com/medusajs/medusa/commit/d37ff8024d8affbe84db3c0b6d79cd41016bfac4), [`7be0a2cf6d`](https://github.com/medusajs/medusa/commit/7be0a2cf6dc753247dff9fea6891fe64f58b9812), [`a6d7070dd6`](https://github.com/medusajs/medusa/commit/a6d7070dd669c21ea19d70434d42c2f8167dc309), [`1d91b7429b`](https://github.com/medusajs/medusa/commit/1d91b7429beebd6f09d5027f7f7e1fe74ce3a8ff), [`168f02f138`](https://github.com/medusajs/medusa/commit/168f02f138ad101e1013f2c8c3f8dc19de12accf), [`1ed5f918c3`](https://github.com/medusajs/medusa/commit/1ed5f918c31794a70aca4a4e4cd83cf456593baa), [`e076590ff2`](https://github.com/medusajs/medusa/commit/e076590ff2a9587d66Line truncated
|
||||
- @medusajs/types@1.11.14
|
||||
- @medusajs/medusa@1.20.3
|
||||
- @medusajs/utils@1.11.7
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#6211](https://github.com/medusajs/medusa/pull/6211) [`e84847be3`](https://github.com/medusajs/medusa/commit/e84847be36c88c5bd8e49e1e8aca734ce941a7c2) Thanks [@shahednasser](https://github.com/shahednasser)! - feat(medusa-oas-cli): updated redocly-cli to v1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`68ddd866a5`](https://github.com/medusajs/medusa/commit/68ddd866a5ff9414e2db5b80d75acc5e81948540), [`72bc52231c`](https://github.com/medusajs/medusa/commit/72bc52231ca3a72fa6d197a248fe07a938ed0d85), [`489b7effb`](https://github.com/medusajs/medusa/commit/489b7effb013b2ffb38693ace14fb8cce2dd7ab4), [`99045848f`](https://github.com/medusajs/medusa/commit/99045848fd3e863359c7878d9bc05271ed083a0e), [`af7af7374`](https://github.com/medusajs/medusa/commit/af7af737455daa0f330840a9678e6339e519dfe6), [`db4da5602`](https://github.com/medusajs/medusa/commit/db4da56023c1c0563a545bffb2bec9cf0e1c4c4a), [`fc6b1772a7`](https://github.com/medusajs/medusa/commit/fc6b1772a71582bb48602c5cac7b2297e9d267a9), [`a9b4214503`](https://github.com/medusajs/medusa/commit/a9b42145032ee88aa922a11fe03e777b140c68f4), [`d85fee42e`](https://github.com/medusajs/medusa/commit/d85fee42ee7f661310584dfee5741d6c53b989bb), [`5e655dd59`](https://github.com/medusajs/medusa/commit/5e655dd59bda4ffface28db38021ba71cae6de10), [`134af7766`](https://github.com/medusajs/medusa/commit/134af77667c278622e3731ba41602d297852fedb), [`b132ff7669`](https://github.com/medusajs/medusa/commit/b132ff76693148b3a06373c168e8dd5e02970757), [`e28fa7fbdf`](https://github.com/medusajs/medusa/commit/e28fa7fbdf45c5b1fa19848db731132a0bf1757d), [`a12c28b7d5`](https://github.com/medusajs/medusa/commit/a12c28b7d5faed733bebbb4963dff50b9c8a33bc), [`b782d3bcb7`](https://github.com/medusajs/medusa/commit/b782d3bcb7e8088a962584b9a55200dd29c2161c), [`d68089b2a`](https://github.com/medusajs/medusa/commit/d68089b2aa2fb4ab52640424ed1a378cd649364f), [`7f7cb2a263`](https://github.com/medusajs/medusa/commit/7f7cb2a263c26baf540b05a40ab3732ffeb0c73c), [`6404b9abd`](https://github.com/medusajs/medusa/commit/6404b9abd12000ca00873d9d7a7f8273b77e0db4), [`302323916`](https://github.com/medusajs/medusa/commit/302323916b6d8eaf571cd59b5fc92a913af207de), [`da5cc4cf7`](https://github.com/medusajs/medusa/commit/da5cc4cf7f7f0ef40d409704a95b025ce95477f4), [`daecd82a7`](https://github.com/medusajs/medusa/commit/daecd82a7cdf7315599f464999690414c20d6748), [`ce81cade88`](https://github.com/medusajs/medusa/commit/ce81cade887659cefe9638e3c1c2807378191c62), [`fd78f5e24`](https://github.com/medusajs/medusa/commit/fd78f5e24263f5e158c3b7d11fbf0a4436e9c17a), [`192bc336cc`](https://github.com/medusajs/medusa/commit/192bc336cc2b6ec3820d94524c046dcd3c4ac7d9), [`06b33a9b4`](https://github.com/medusajs/medusa/commit/06b33a9b4525b77b1b14b35b973209700945654e), [`b6ac768698`](https://github.com/medusajs/medusa/commit/b6ac768698a3b49d0162cb49e628386f3352d034), [`4792c5522`](https://github.com/medusajs/medusa/commit/4792c552269c147d3c07da49a175e9038f9260a8), [`8ad7539eb`](https://github.com/medusajs/medusa/commit/8ad7539ebc3172fe2c724cf41ec1db5829819446), [`130c641e5c`](https://github.com/medusajs/medusa/commit/130c641e5c91cf831de64fb87aebbfdc4d23530d), [`fade8ea7bf`](https://github.com/medusajs/medusa/commit/fade8ea7bf560343ecbde116d226ac44053cdb8e), [`8472460f53`](https://github.com/medusajs/medusa/commit/8472460f533322cc4535199aa768ac163021bc79), [`68d8daccd`](https://github.com/medusajs/medusa/commit/68d8daccd2a8508a13e211130e49017198b51fab)]:
|
||||
- @medusajs/types@1.11.11
|
||||
- @medusajs/utils@1.11.4
|
||||
- @medusajs/medusa@1.20.1
|
||||
|
||||
## 0.2.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4ad66c179`](https://github.com/medusajs/medusa/commit/4ad66c1795af2b5e9f0a0e958447b688e525651a), [`91615f9c4`](https://github.com/medusajs/medusa/commit/91615f9c459a2d8cb842561c5edb335680d30298), [`c39bf69a5`](https://github.com/medusajs/medusa/commit/c39bf69a5e5cae75d7fa12aa6022b10903557a32), [`203e1fccb`](https://github.com/medusajs/medusa/commit/203e1fccb404a7408b53767456eee52ea719356c), [`154c9b43b`](https://github.com/medusajs/medusa/commit/154c9b43bde1fdff562aba9da8a79af2660b29b3), [`f90ba0208`](https://github.com/medusajs/medusa/commit/f90ba02087778d8131aed3a59a6dc9c8ca3c95f4)]:
|
||||
- @medusajs/medusa@1.17.4
|
||||
- @medusajs/types@1.11.6
|
||||
- @medusajs/utils@1.10.5
|
||||
|
||||
## 0.2.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5453](https://github.com/medusajs/medusa/pull/5453) [`c1b97050a`](https://github.com/medusajs/medusa/commit/c1b97050ab801c6b5702311f777ebd7f98080a97) Thanks [@shahednasser](https://github.com/shahednasser)! - feat(medusa-oas-cli): Added `--main-file-name` option to specify output file name
|
||||
feat(oas-github-ci): Added `--with-full-file"` option to output both split and full files
|
||||
- Updated dependencies [[`148f537b4`](https://github.com/medusajs/medusa/commit/148f537b47635e8b73ebaa27bbfbe58624bfe641), [`e64823d1b`](https://github.com/medusajs/medusa/commit/e64823d1b9e7556d8bc12c553accefa0b2a8b714), [`9ff22110a`](https://github.com/medusajs/medusa/commit/9ff22110a60da6d91ca49e93de509512382a46a3), [`a45da9215`](https://github.com/medusajs/medusa/commit/a45da9215d2a7834c368037726aaa3961caadaf9), [`2548ea8e5`](https://github.com/medusajs/medusa/commit/2548ea8e5ed3374143500baa37e2accf0fa367a0), [`ebba93e03`](https://github.com/medusajs/medusa/commit/ebba93e03d223fb3a79276090f7cfad612d70243), [`148f537b4`](https://github.com/medusajs/medusa/commit/148f537b47635e8b73ebaa27bbfbe58624bfe641), [`4d52082bf`](https://github.com/medusajs/medusa/commit/4d52082bf05fce18b55dae7f982c0c2cf4c65194), [`a780b92b8`](https://github.com/medusajs/medusa/commit/a780b92b8d590baa0e86682d1154f9e5b0869ea1)]:
|
||||
- @medusajs/medusa@1.17.3
|
||||
- @medusajs/types@1.11.5
|
||||
|
||||
## 0.2.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`c1cabac72`](https://github.com/medusajs/medusa/commit/c1cabac721d80f631875e00b26247b32e3f6e4da), [`378ca1b36`](https://github.com/medusajs/medusa/commit/378ca1b36e909a67e39c69ea5ca94ec58a345878), [`69cf7215f`](https://github.com/medusajs/medusa/commit/69cf7215f1f730ffb332129e65211470be1f88f1), [`0d7c5543d`](https://github.com/medusajs/medusa/commit/0d7c5543dd200a3545fac6b8601c0542ddd20c82), [`ec27d02d9`](https://github.com/medusajs/medusa/commit/ec27d02d9951558f024fc154a03e9d4db56f0354), [`453297f52`](https://github.com/medusajs/medusa/commit/453297f525bd9f3aaa95bf0b28ff6cd31e6696b4), [`ddff91965`](https://github.com/medusajs/medusa/commit/ddff9196557c662cbdfb463dc5c76bf7bee6c087), [`e47461d95`](https://github.com/medusajs/medusa/commit/e47461d95caecf3a447ee9fa0b0950340b93f282), [`66413d094`](https://github.com/medusajs/medusa/commit/66413d094e916debbdb74b68800c96ca2c9302c9), [`a0963f0ed`](https://github.com/medusajs/medusa/commit/a0963f0edf909f6cfea17bd7a0c7899707808057)]:
|
||||
- @medusajs/medusa@1.17.2
|
||||
- @medusajs/utils@1.10.4
|
||||
- @medusajs/types@1.11.4
|
||||
|
||||
## 0.2.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`eeceec791`](https://github.com/medusajs/medusa/commit/eeceec791c141996cf7fd06555afb6e738b52840), [`90e24c593`](https://github.com/medusajs/medusa/commit/90e24c593f66276e8e93734e067f4e8c877f6001), [`130cbc1f4`](https://github.com/medusajs/medusa/commit/130cbc1f437af211b6d05f80128d90138abcd38d), [`f9264c479`](https://github.com/medusajs/medusa/commit/f9264c479e2628911bd3d753c99c141f97335fba), [`cb569c2df`](https://github.com/medusajs/medusa/commit/cb569c2dfe2d83e1ff72a49f2331450a83b73325), [`0f34e0f38`](https://github.com/medusajs/medusa/commit/0f34e0f381833a4790ee590a9cbf93b7660634f3), [`c5703a476`](https://github.com/medusajs/medusa/commit/c5703a4765a55da697885438cf3089d923669f21)]:
|
||||
- @medusajs/utils@1.10.3
|
||||
- @medusajs/medusa@1.17.1
|
||||
- @medusajs/types@1.11.3
|
||||
|
||||
## 0.2.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`240c439be`](https://github.com/medusajs/medusa/commit/240c439beb76626e58006ceb86a1cd425f14d4fa), [`2caff2efc`](https://github.com/medusajs/medusa/commit/2caff2efc757a3738ae8b7ee6fde77ee7100f995), [`2b91049f5`](https://github.com/medusajs/medusa/commit/2b91049f58b2bd70cbee53e1ace7d36f59da6fa4), [`f1512605d`](https://github.com/medusajs/medusa/commit/f1512605d2d8b758be21f21d0b118e14b914d7d2), [`cc4169a94`](https://github.com/medusajs/medusa/commit/cc4169a94c7c5f5bf4d04f7b6e815b409a0a8192), [`dfa5d041c`](https://github.com/medusajs/medusa/commit/dfa5d041c90b849b288f8ae9f5a0a1aa3ee1b32e), [`202049f8a`](https://github.com/medusajs/medusa/commit/202049f8aa3682df7e545b1c42ab0bdab1c52639), [`5f76b967d`](https://github.com/medusajs/medusa/commit/5f76b967d9c6ae3a3f554c2d854299f5e22ee83e), [`f285a6712`](https://github.com/medusajs/medusa/commit/f285a671232f34a35d9cd9c9a0e6faa8a899a674), [`a9972d7d6`](https://github.com/medusajs/medusa/commit/a9972d7d6fa5c9698318a55173440f635ebf0a11), [`c68ba63c1`](https://github.com/medusajs/medusa/commit/c68ba63c1b4ac551cb53bfb494bf7046e652e083), [`c1b8f089e`](https://github.com/medusajs/medusa/commit/c1b8f089e3277f2aa4b7188bf914253e4ad0fe95), [`1e7db5a5c`](https://github.com/medusajs/medusa/commit/1e7db5a5cb7c955e72c52e64df8a16b1607eef70)]:
|
||||
- @medusajs/medusa@1.17.0
|
||||
- @medusajs/utils@1.10.2
|
||||
- @medusajs/types@1.11.2
|
||||
|
||||
## 0.2.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7231f6583`](https://github.com/medusajs/medusa/commit/7231f658331485640aeac2b6109c824fd05ce19b), [`4fa675ec2`](https://github.com/medusajs/medusa/commit/4fa675ec25b3d6fccd881c4f5a5b91f0e9e13e82), [`77c85fc6c`](https://github.com/medusajs/medusa/commit/77c85fc6c6c940244b7714aee3a458ee4f86aad0), [`dc94f053d`](https://github.com/medusajs/medusa/commit/dc94f053d31d3544c313b23ac1d6d1465e8336db), [`6273b4b16`](https://github.com/medusajs/medusa/commit/6273b4b160493463e1199e5db4e9cfa4cff6fbe4), [`2b078f06d`](https://github.com/medusajs/medusa/commit/2b078f06d930e6219b46720f4a916b20015329e5), [`30863fee5`](https://github.com/medusajs/medusa/commit/30863fee529ed035f161c749fda3cd64fa48efb1), [`5362bfc34`](https://github.com/medusajs/medusa/commit/5362bfc348cad3aecb4fb93b21920355ad9d9ffc), [`60360d2fd`](https://github.com/medusajs/medusa/commit/60360d2fd26528e08c9ac93d316738c397b51169), [`3d68be2b6`](https://github.com/medusajs/medusa/commit/3d68be2b6b93ae928f5c955e102ebdf2c34fb364), [`a87d07655`](https://github.com/medusajs/medusa/commit/a87d07655bd8a1da8b90feb739daddd09295f724), [`05a32683a`](https://github.com/medusajs/medusa/commit/05a32683a341451fc4d3526687ec775926e1ba68), [`05fcfd803`](https://github.com/medusajs/medusa/commit/05fcfd803e5f06bf29354b20eb57bbc9c2c72d8e), [`edf90eecb`](https://github.com/medusajs/medusa/commit/edf90eecb487f6e031f2e2d0899de5ca2504cb12), [`107aaa371`](https://github.com/medusajs/medusa/commit/107aaa371c444843874d125bf8bd493ef89f5756), [`834da5c41`](https://github.com/medusajs/medusa/commit/834da5c41a7c043373f72239b6fdbf7815d9b4aa)]:
|
||||
- @medusajs/medusa@1.16.0
|
||||
- @medusajs/types@1.11.1
|
||||
- @medusajs/utils@1.10.1
|
||||
|
||||
## 0.2.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`bb5ea9d5c`](https://github.com/medusajs/medusa/commit/bb5ea9d5ca92d96a64652cbb679284c817b68bff), [`4bf8acbdd`](https://github.com/medusajs/medusa/commit/4bf8acbdd4244aed0425fae4bb1f2f26e79d5640), [`046b0dcfa`](https://github.com/medusajs/medusa/commit/046b0dcfa5acfdbf98f5a5593b42673c7567430d), [`4d439bed3`](https://github.com/medusajs/medusa/commit/4d439bed3812e4d4c45bd5c0a872c9b0fd111af8), [`460161a69`](https://github.com/medusajs/medusa/commit/460161a69f22cf6d561952e92e7d9b56912113e6), [`17d91c276`](https://github.com/medusajs/medusa/commit/17d91c276a68de4d2b360335f32fcce48a16c9ec), [`fcb6b4f51`](https://github.com/medusajs/medusa/commit/fcb6b4f510dba2757570625acb5da9476b7544fd), [`66bd9a835`](https://github.com/medusajs/medusa/commit/66bd9a835c61b139af7051e5faf6c9de3c7134bb), [`b71776738`](https://github.com/medusajs/medusa/commit/b71776738cce2add34306f23838ca576daa9d946), [`c7b149a7b`](https://github.com/medusajs/medusa/commit/c7b149a7bc87dc4df1c78edccb36b45f19ee8e36), [`4d16acf5f`](https://github.com/medusajs/medusa/commit/4d16acf5f096b5656b645f510f9c971e7c2dc9ef), [`4d16acf5f`](https://github.com/medusajs/medusa/commit/4d16acf5f096b5656b645f510f9c971e7c2dc9ef), [`87bade096`](https://github.com/medusajs/medusa/commit/87bade096e3d536f29ddc57dbc4c04e5d7a46e4b), [`9781089ca`](https://github.com/medusajs/medusa/commit/9781089ca301221011c58423add3bf81b74b068b), [`470379e63`](https://github.com/medusajs/medusa/commit/470379e631ca17ee486a28c50ec828344c61d727), [`a1110b343`](https://github.com/medusajs/medusa/commit/a1110b34383e4626197e572eac05b1a6164cabcb), [`4d16acf5f`](https://github.com/medusajs/medusa/commit/4d16acf5f096b5656b645f510f9c971e7c2dc9ef), [`a4906d0ac`](https://github.com/medusajs/medusa/commit/a4906d0ac0af36b1382d3befe64281b404387bd7)]:
|
||||
- @medusajs/medusa@1.15.1
|
||||
- @medusajs/types@1.11.0
|
||||
- @medusajs/utils@1.10.0
|
||||
|
||||
## 0.2.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d8a6e3e0d`](https://github.com/medusajs/medusa/commit/d8a6e3e0d8a86aba7209f4a767cd08ebe3e49c26), [`edf9ed4e5`](https://github.com/medusajs/medusa/commit/edf9ed4e593063622aa39cdbebef4810bf2a5fb1), [`8b860416d`](https://github.com/medusajs/medusa/commit/8b860416d26ce77eb13a643eb616ed6e221d3d66)]:
|
||||
- @medusajs/medusa@1.15.0
|
||||
- @medusajs/types@1.10.3
|
||||
|
||||
## 0.2.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`c53fa6cd3`](https://github.com/medusajs/medusa/commit/c53fa6cd3be8b1af5625fc2db7871f9f69e761ad)]:
|
||||
- @medusajs/utils@1.9.7
|
||||
|
||||
## 0.2.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d1e298f5d`](https://github.com/medusajs/medusa/commit/d1e298f5dcd3eb23c6172cf76025660aac50500f), [`5cf59a5b9`](https://github.com/medusajs/medusa/commit/5cf59a5b9c0ab6323927f14782f03fc1b91547f7), [`ac866ebb5`](https://github.com/medusajs/medusa/commit/ac866ebb5197ee694dda91824b501109012a3dd1), [`d8a908bd8`](https://github.com/medusajs/medusa/commit/d8a908bd8ee83cd5ca61b1a8078603eacbab65a9), [`3f3a84262`](https://github.com/medusajs/medusa/commit/3f3a84262ce9cbd911923278a54e301fbe9a4634), [`f1a05f472`](https://github.com/medusajs/medusa/commit/f1a05f4725dcc45150f014769562bd3dfbc0f1f8), [`30ce35b16`](https://github.com/medusajs/medusa/commit/30ce35b163afa25f4e1d8d1bd392f401a3b413df), [`a2d7540e4`](https://github.com/medusajs/medusa/commit/a2d7540e40461c138f953865e5374c42842928ac), [`9d8f87b03`](https://github.com/medusajs/medusa/commit/9d8f87b03b62b9145b95aa902f209d49c939bb6a), [`281b0746c`](https://github.com/medusajs/medusa/commit/281b0746cfbe80b83c6a67d1ea120b47a0ea7121)]:
|
||||
- @medusajs/medusa@1.14.0
|
||||
- @medusajs/types@1.10.2
|
||||
- @medusajs/utils@1.9.6
|
||||
|
||||
## 0.2.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`fc6c9df03`](https://github.com/medusajs/medusa/commit/fc6c9df03561dd262d00dda2a8426200745eebdb), [`dae34297e`](https://github.com/medusajs/medusa/commit/dae34297ebd405766dcea921dfc290e49aa17713), [`03fb0479c`](https://github.com/medusajs/medusa/commit/03fb0479c0c5389d2569d622b6bec188fcee0ad6), [`8af55aed8`](https://github.com/medusajs/medusa/commit/8af55aed87da7252c7c261175bc98331466a0da8), [`5c60aad17`](https://github.com/medusajs/medusa/commit/5c60aad177a99574ffff5ebdc02ce9dc86ef9af9), [`9c682ce28`](https://github.com/medusajs/medusa/commit/9c682ce288072592dad3824a64789f94d7c41dee), [`4073b7313`](https://github.com/medusajs/medusa/commit/4073b73130c874dc7d2240726224a01b7b19b1a1)]:
|
||||
- @medusajs/medusa@1.13.1
|
||||
- @medusajs/types@1.10.1
|
||||
- @medusajs/utils@1.9.5
|
||||
|
||||
## 0.2.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`107ae23a3`](https://github.com/medusajs/medusa/commit/107ae23a3f41ef0d676e9d03f53dafc7c1af6118), [`ce3f914e0`](https://github.com/medusajs/medusa/commit/ce3f914e01b0e2881182be230cf29d51ce711913)]:
|
||||
- @medusajs/utils@1.9.4
|
||||
- @medusajs/types@1.10.0
|
||||
|
||||
## 0.2.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`585ebf245`](https://github.com/medusajs/medusa/commit/585ebf2454719ed36957ba798a189a45a5274c5a), [`9129ca08a`](https://github.com/medusajs/medusa/commit/9129ca08a724f4e0c9e6a69b8bea9c0fb7b0f1b9), [`ae33f4825`](https://github.com/medusajs/medusa/commit/ae33f4825fc1a388813cde72de03a26c41b8b387), [`131477faf`](https://github.com/medusajs/medusa/commit/131477faf0409c49d4aacf26ea591e33b2fa22fd), [`c9989529e`](https://github.com/medusajs/medusa/commit/c9989529ed8c347fefe10d57b3d23fa60aa35fe7), [`caea44ebf`](https://github.com/medusajs/medusa/commit/caea44ebfdf7393ace931ce2a9884105dadc4f8d), [`30e8bb275`](https://github.com/medusajs/medusa/commit/30e8bb2757e07ccb997c508c730a8d8ef8bcc5d1), [`f18f1b9bf`](https://github.com/medusajs/medusa/commit/f18f1b9bfef897974ba034ce41cd64aa833e4767), [`f12299deb`](https://github.com/medusajs/medusa/commit/f12299deb10baadab1505cd4ac353dd5d1c8fa7c)]:
|
||||
- @medusajs/types@1.9.0
|
||||
- @medusajs/medusa@1.13.0
|
||||
- @medusajs/utils@1.9.3
|
||||
|
||||
## 0.2.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`befc2f1c8`](https://github.com/medusajs/medusa/commit/befc2f1c80b6aaeb3a5153f7fdeaa96cf832e46f), [`d184d23c6`](https://github.com/medusajs/medusa/commit/d184d23c6384d5f8bf52827826b62c6bef37f884), [`befc2f1c8`](https://github.com/medusajs/medusa/commit/befc2f1c80b6aaeb3a5153f7fdeaa96cf832e46f), [`56d1d326d`](https://github.com/medusajs/medusa/commit/56d1d326d4492626e9297e4cac9b4cb44ae0f165), [`43427b889`](https://github.com/medusajs/medusa/commit/43427b8893baedd7abe7b38cf5360aa2d245293d), [`2f283996f`](https://github.com/medusajs/medusa/commit/2f283996f80313b074b96c690bcd953c67665c1b)]:
|
||||
- @medusajs/medusa@1.12.3
|
||||
- @medusajs/types@1.8.11
|
||||
|
||||
## 0.2.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`499c3478c`](https://github.com/medusajs/medusa/commit/499c3478c910c8b922a15cc6f4d9fbad122a347f), [`85eb12883`](https://github.com/medusajs/medusa/commit/85eb12883e0571d494687e7a7e2f310c878f721d), [`9dcdc0041`](https://github.com/medusajs/medusa/commit/9dcdc0041a2b08cc0723343dd8d9127d9977b086), [`01245ac89`](https://github.com/medusajs/medusa/commit/01245ac89e13b687ac346c35168f9f28014e613d), [`6f1fa244f`](https://github.com/medusajs/medusa/commit/6f1fa244fa47d4ecdaa7363483bd7da555dbbf32), [`bdd9c5a7e`](https://github.com/medusajs/medusa/commit/bdd9c5a7e9a9b1a6b4d1e2dcf22f67540494fedc), [`9760d4a96`](https://github.com/medusajs/medusa/commit/9760d4a96c27f6f89a8c3f3b6e73b17547f97f2a), [`4264302f2`](https://github.com/medusajs/medusa/commit/4264302f214f0717e8b3218a15d43def9122879c), [`7bf7d2ade`](https://github.com/medusajs/medusa/commit/7bf7d2adef53b80230a36c22e639b471e501e52e)]:
|
||||
- @medusajs/types@1.8.10
|
||||
- @medusajs/utils@1.9.2
|
||||
- @medusajs/medusa@1.12.2
|
||||
|
||||
## 0.2.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`dc120121c`](https://github.com/medusajs/medusa/commit/dc120121c12bd2722d97c65e242888bb552ef78a)]:
|
||||
- @medusajs/types@1.8.9
|
||||
|
||||
## 0.2.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`f98ba5bde`](https://github.com/medusajs/medusa/commit/f98ba5bde83ba785eead31b0c9eb9f135d664178), [`2c0074031`](https://github.com/medusajs/medusa/commit/2c0074031be2576e59c8f545b786b4a61a35b802), [`13294fff3`](https://github.com/medusajs/medusa/commit/13294fff3ff334c83a34e054c34204fdd30c4dce), [`ca477c86a`](https://github.com/medusajs/medusa/commit/ca477c86af38f08c3b9a34147e9145f6a4e84677), [`79cca2ab8`](https://github.com/medusajs/medusa/commit/79cca2ab809b77606e65706c19f9fce37b174365), [`d76ba0cd2`](https://github.com/medusajs/medusa/commit/d76ba0cd29694c2e31f9f89992a9fbc14659c1ae), [`8e708aadd`](https://github.com/medusajs/medusa/commit/8e708aaddf85a78b73d81844812dd8d60fcf99b1), [`02b1bd07c`](https://github.com/medusajs/medusa/commit/02b1bd07cd4e6be6348c936431d5e3952cac0f3b), [`eadf13cb2`](https://github.com/medusajs/medusa/commit/eadf13cb2101b2b12753428df0fb775f828cd9ac), [`2db6a1d40`](https://github.com/medusajs/medusa/commit/2db6a1d4076fb84248149d9e1388d3e6ca81ab70), [`109096465`](https://github.com/medusajs/medusa/commit/109096465dacdc5879a816a56ef4f2d7a9927e1a), [`81dfeb43e`](https://github.com/medusajs/medusa/commit/81dfeb43ea5aee92771a84c4dbf8d73bc3166522), [`14c0f62f8`](https://github.com/medusajs/medusa/commit/14c0f62f84704a4c87beff3daaff60a52f5c88b8), [`af2dc4f75`](https://github.com/medusajs/medusa/commit/af2dc4f75a2ed109495ca83b1bc6ae6941c2f716), [`8676ee7a2`](https://github.com/medusajs/medusa/commit/8676ee7a2e3da9fecc2e81db3ab12693d02f63f4), [`260dc55b6`](https://github.com/medusajs/medusa/commit/260dc55b6f122351f8e1d75a4b5ca797745735be), [`f8643361c`](https://github.com/medusajs/medusa/commit/f8643361cdcb549c61e645d4ee275f20883e00d9), [`afd1b67f1`](https://github.com/medusajs/medusa/commit/afd1b67f1c7de8cf07fd9fcbdde599a37914e9b5)]:
|
||||
- @medusajs/utils@1.9.1
|
||||
- @medusajs/medusa@1.12.1
|
||||
- @medusajs/types@1.8.8
|
||||
|
||||
## 0.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`0a35f21af`](https://github.com/medusajs/medusa/commit/0a35f21af7ac8b6cdc1af12a403e95f9bf6142fe), [`4fb443c0e`](https://github.com/medusajs/medusa/commit/4fb443c0ea38bde3148bce059c0ee3b91dfff3d4), [`0476f5251`](https://github.com/medusajs/medusa/commit/0476f52519237c622b37d29de0718f9774b6add7), [`0f87d3d64`](https://github.com/medusajs/medusa/commit/0f87d3d642b56bf19de8136e1f5bfedf364c5193), [`ed382f2ee`](https://github.com/medusajs/medusa/commit/ed382f2ee510cbf96164991efa7ff75e3ce659ff), [`92f01cefb`](https://github.com/medusajs/medusa/commit/92f01cefbc4a190defce425fb237d2d68728fa9a), [`e3cfbcd4a`](https://github.com/medusajs/medusa/commit/e3cfbcd4a78073c63ecd9829bc531e50d3944f07), [`6998666c6`](https://github.com/medusajs/medusa/commit/6998666c6edd6617ca61a8d39c26435bad1273e3), [`81eeaa329`](https://github.com/medusajs/medusa/commit/81eeaa32942b1a7148126a7218ceb168ce8d6cac), [`e2d29d35c`](https://github.com/medusajs/medusa/commit/e2d29d35c4c477bc9b4a3ddce1279276fd072875), [`3a38c84f8`](https://github.com/medusajs/medusa/commit/3a38c84f88b05f74ee0a172af3e3f78b2ec8c2d2), [`4f3c8f5d7`](https://github.com/medusajs/medusa/commit/4f3c8f5d70b5ae4a11e9d4a2fea4a8410b2daf47), [`a91987fab`](https://github.com/medusajs/medusa/commit/a91987fab33745f9864eab21bd1c27e8e3e24571), [`bf18bd0c8`](https://github.com/medusajs/medusa/commit/bf18bd0c8a284dd0042d4c54d84acb2e7c10edd3), [`db4199530`](https://github.com/medusajs/medusa/commit/db419953075e0907b8c4d27ab5188e9bd3e3d72b)]:
|
||||
- @medusajs/medusa@1.12.0
|
||||
|
||||
## 0.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3924](https://github.com/medusajs/medusa/pull/3924) [`cfcd2d54f`](https://github.com/medusajs/medusa/commit/cfcd2d54fd281fd98de881fc6dfbcc6b1b47c855) Thanks [@pevey](https://github.com/pevey)! - Add separator after tmpdir base
|
||||
|
||||
- Updated dependencies [[`a66646233`](https://github.com/medusajs/medusa/commit/a666462333d20821a3e50e3fbc65bc8a511c726f), [`9518efcca`](https://github.com/medusajs/medusa/commit/9518efccae1961d9b3cd1e85148e293a3744eedb), [`a86f0e815`](https://github.com/medusajs/medusa/commit/a86f0e815a9e75d7d562fbe516c5bb7e0ab1f6ee), [`cdbac2c84`](https://github.com/medusajs/medusa/commit/cdbac2c8403a3c15c0e11993f6b7dab268fa5c08), [`26963acc0`](https://github.com/medusajs/medusa/commit/26963acc0a5caa1bca97cfe4cbcee113a8d75b84)]:
|
||||
- @medusajs/medusa@1.11.0
|
||||
|
||||
## 0.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3d6bcaaf6`](https://github.com/medusajs/medusa/commit/3d6bcaaf65b3a43dfb251460d73e448870b5105f), [`7fd22ecb4`](https://github.com/medusajs/medusa/commit/7fd22ecb4d5190e92c6750a9fbf2d8534bb9f4ab), [`bd53adb23`](https://github.com/medusajs/medusa/commit/bd53adb238a64640533698fbccb98a39a0346590), [`1ea57c3a6`](https://github.com/medusajs/medusa/commit/1ea57c3a69a5377a8dd0821df819743ded4a222b), [`0c58ead6d`](https://github.com/medusajs/medusa/commit/0c58ead6d869f5605cbd2b8aca129984b7493bcf), [`cff54d732`](https://github.com/medusajs/medusa/commit/cff54d73253a4c2d16a174a28f0f5d31c94bcebd), [`a8e73942e`](https://github.com/medusajs/medusa/commit/a8e73942e69662ca673ccc4300e270ff6ab523d1), [`ff37cd190`](https://github.com/medusajs/medusa/commit/ff37cd190fa455f4ba4f76cfb4d641b1611cc32e)]:
|
||||
- @medusajs/medusa@1.10.1
|
||||
|
||||
## 0.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`0e488e71b`](https://github.com/medusajs/medusa/commit/0e488e71b186f7d08b18c4c6ba409ef3cadb8152), [`538c9874b`](https://github.com/medusajs/medusa/commit/538c9874ba18c1352284089a789d4a90652bc795), [`d539c6fee`](https://github.com/medusajs/medusa/commit/d539c6feeba8ee431f9a655b6cd4e9102cba2b25), [`b7a782639`](https://github.com/medusajs/medusa/commit/b7a7826394ecd621ca80e6d4ce445ea1c26804ac), [`983872319`](https://github.com/medusajs/medusa/commit/98387231927e9872f54c9e72597576f3273de506), [`284f1eed9`](https://github.com/medusajs/medusa/commit/284f1eed9a9fc7272df3fccdb162ea93750999de), [`4e8045a0a`](https://github.com/medusajs/medusa/commit/4e8045a0ac44b1541ee3cd846079f55d3e0dc957), [`d2443d83e`](https://github.com/medusajs/medusa/commit/d2443d83e60fee3c3f28b762d66378c3f07f1b5f), [`8b93bae8f`](https://github.com/medusajs/medusa/commit/8b93bae8f8ad1f6eb43931a7ba03bfa691475eca)]:
|
||||
- @medusajs/medusa@1.10.0
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`440f900af`](https://github.com/medusajs/medusa/commit/440f900af03dd0af29c9b16f01576d3eff45cd04), [`366b12fce`](https://github.com/medusajs/medusa/commit/366b12fcea679551c55baaeeaaf41bbddf04b972), [`7e213f210`](https://github.com/medusajs/medusa/commit/7e213f2106ed76449fbdfa6eda5594b59522443a), [`d2826872f`](https://github.com/medusajs/medusa/commit/d2826872fe487a027b677aeb43704f761a6b4e80), [`0d0e9bf20`](https://github.com/medusajs/medusa/commit/0d0e9bf2069718ac54684efbe4d449942bb2ef32), [`2be144ff0`](https://github.com/medusajs/medusa/commit/2be144ff05e852a3541a9a972942cfc15ef3bd38), [`935abeae6`](https://github.com/medusajs/medusa/commit/935abeae68012a93d820789c743941c3c1a1b802), [`3a77e8a88`](https://github.com/medusajs/medusa/commit/3a77e8a88fd327aca579bcd09d767d9315a04d7f), [`af710f1b4`](https://github.com/medusajs/medusa/commit/af710f1b48a4545a5064029a557013af34c4c100), [`491566df6`](https://github.com/medusajs/medusa/commit/491566df6b7ced35f655f810961422945e10ecd0), [`966ddd2f1`](https://github.com/medusajs/medusa/commit/966ddd2f1648d5d3c1c68094f488f307e3186d92), [`3b3236cc0`](https://github.com/medusajs/medusa/commit/3b3236cc01fc8b7448c1bdbad066a19c2c3de2c3), [`4a8562743`](https://github.com/medusajs/medusa/commit/4a8562743569f5bbb7bd0894b025a74725726529)]:
|
||||
- @medusajs/medusa@1.9.0
|
||||
|
||||
## 0.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3745](https://github.com/medusajs/medusa/pull/3745) [`1456056e8`](https://github.com/medusajs/medusa/commit/1456056e8f9d48cc1cb64c1836a6de5d5b263b05) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(oas): new medusa-oas docs for Redocly and circular references
|
||||
|
||||
- Updated dependencies [[`6bb1654b6`](https://github.com/medusajs/medusa/commit/6bb1654b61880f8658bf1395e4ccef860780aac4), [`95d338262`](https://github.com/medusajs/medusa/commit/95d338262b63e3daa6697bb23806980a8b5e5cdc), [`4f58ddee0`](https://github.com/medusajs/medusa/commit/4f58ddee03509a4c46af160e5824cba80d4c950a)]:
|
||||
- @medusajs/medusa@1.8.2
|
||||
|
||||
## 0.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`78ff64e78`](https://github.com/medusajs/medusa/commit/78ff64e7837f6506c641a3c97ffdfa6ee17419ee), [`1a60c6f58`](https://github.com/medusajs/medusa/commit/1a60c6f58dd80d2d8cb8ee10c186975b39325d13), [`713d85a92`](https://github.com/medusajs/medusa/commit/713d85a92cf5249e3b75b96f8bf2c25e4f9b0c90), [`0b3c6fde3`](https://github.com/medusajs/medusa/commit/0b3c6fde30c9bac052a8e1aa641ef925b6937c0e), [`914d57336`](https://github.com/medusajs/medusa/commit/914d57336bc8355533d743745989f793ffd4d513), [`60abb91b7`](https://github.com/medusajs/medusa/commit/60abb91b7c568c6c4cce3b2da7cfb8d54b078299), [`089f1eb19`](https://github.com/medusajs/medusa/commit/089f1eb19e2bb43659c5b300fccb8163c1d60b5c), [`08f85fa33`](https://github.com/medusajs/medusa/commit/08f85fa33b35e15f944a833e1401c7ba2081d3ec), [`282e239df`](https://github.com/medusajs/medusa/commit/282e239dfc0a74f0eb72b17426c8c8bffd86064a), [`abdb74d99`](https://github.com/medusajs/medusa/commit/abdb74d997f49f994bff49787a396179982843b0), [`eab2d22f7`](https://github.com/medusajs/medusa/commit/eab2d22f7d22ec53c68398558ffda32d2a734983), [`08f85fa33`](https://github.com/medusajs/medusa/commit/08f85fa33b35e15f944a833e1401c7ba2081d3ec), [`085fedb1f`](https://github.com/medusajs/medusa/commit/085fedb1f7e982859cff3ef3f1d870dce3bcc8b6), [`4d69d8ef6`](https://github.com/medusajs/medusa/commit/4d69d8ef6aef0a05d0bbb00eed045c2de511be56), [`7f6dc44be`](https://github.com/medusajs/medusa/commit/7f6dc44beb9789088f6d6b796f7545beb3653094), [`d533caa4c`](https://github.com/medusajs/medusa/commit/d533caa4c2986c1c9e320cce97423b0cdc213b6c)]:
|
||||
- @medusajs/medusa@1.8.1
|
||||
- @medusajs/openapi-typescript-codegen@0.2.1
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#3411](https://github.com/medusajs/medusa/pull/3411) [`966aea65c`](https://github.com/medusajs/medusa/commit/966aea65c221403bf316ae7665cc8f73bccd9c38) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(oas-cli): combine admin + store + custom OAS
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3213](https://github.com/medusajs/medusa/pull/3213) [`813706190`](https://github.com/medusajs/medusa/commit/8137061908d20314314b95d049b966a624e7123d) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(oas): medusa-oas-cli as OAS build tool
|
||||
|
||||
- [#3631](https://github.com/medusajs/medusa/pull/3631) [`377b9ce8c`](https://github.com/medusajs/medusa/commit/377b9ce8c27cb2c4d10d154c005c7553c173c0e8) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix(oas:test): fix beforeAll timeout silent failure
|
||||
|
||||
- [#3272](https://github.com/medusajs/medusa/pull/3272) [`1c40346e9`](https://github.com/medusajs/medusa/commit/1c40346e9e56718de4a6e2d5c2d52abd388343e3) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(codegen): openapi-typescript-codegen fork
|
||||
|
||||
- [#3559](https://github.com/medusajs/medusa/pull/3559) [`53c4a43ca`](https://github.com/medusajs/medusa/commit/53c4a43ca2b2c04920dc6f38e07348e7dfc23195) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(oas:cli): output better error when no command is provided
|
||||
|
||||
- Updated dependencies [[`d6b1ad1cc`](https://github.com/medusajs/medusa/commit/d6b1ad1ccd9a8f91b169f30ff99492cf3adcccac), [`e143a8697`](https://github.com/medusajs/medusa/commit/e143a86976a5cc6a53b7a795e8486df4db1d1c09), [`121b42acf`](https://github.com/medusajs/medusa/commit/121b42acfe98c12dd593f9b1f2072ff0f3b61724), [`84e448968`](https://github.com/medusajs/medusa/commit/84e44896836b2c44017572ac5192ab1cd937048c), [`33c6ccf05`](https://github.com/medusajs/medusa/commit/33c6ccf0591b8ef527f3b10a70b51e29751b4998), [`788ddc0f4`](https://github.com/medusajs/medusa/commit/788ddc0f43696df607f07133af15a04b29d5447d), [`5fd74b38a`](https://github.com/medusajs/medusa/commit/5fd74b38ae1b4f7dced191983b78db83f7b1f71b), [`30a320364`](https://github.com/medusajs/medusa/commit/30a3203640be9993ba2f8447abfdecc0d3e2f9b6), [`240d0ea7b`](https://github.com/medusajs/medusa/commit/240d0ea7b88ff494d0fe28c7c5348e958c14571f), [`6c0462472`](https://github.com/medusajs/medusa/commit/6c046247275c46d934f03d53471bdd555a19a9ad), [`589d1c09b`](https://github.com/medusajs/medusa/commit/589d1c09b085dcaf9667061201ac9deff3047466), [`0695ff642`](https://github.com/medusajs/medusa/commit/0695ff642b5836e7c28d40118aafe7a769023d5a), [`530740889`](https://github.com/medusajs/medusa/commit/53074088941719ac7ca435e76e3e64ba23fac200), [`13f40d721`](https://github.com/medusajs/medusa/commit/13f40d721702fbcdf6c131354ec9a81322d4a662), [`4342ac884`](https://github.com/medusajs/medusa/commit/4342ac884bc3fe473576ef10d291f3547e0ffc62), [`fe9eea4c1`](https://github.com/medusajs/medusa/commit/fe9eea4c18b7e04ba91660716c92b11a49840a3c), [`a5ad6c054`](https://github.com/medusajs/medusa/commit/a5ad6c05428e1bb090bbc5a51345a00821781c06), [`748833383`](https://github.com/medusajs/medusa/commit/748833383f4bafd05109dac7afa1286fe851cba3), [`7f87c4f2c`](https://github.com/medusajs/medusa/commit/7f87c4f2c8abb876213a595005e67d770be9cbe4), [`e5a2e9c8d`](https://github.com/medusajs/medusa/commit/e5a2e9c8d237bbe4e3563f5a7a892ca41f01ba24), [`0a02b70e5`](https://github.com/medusajs/medusa/commit/0a02b70e59cfbd8888fb58c29ee9aaf96eb8099a), [`8ddb3952c`](https://github.com/medusajs/medusa/commit/8ddb3952c045e6c05c8d0f6922f0d4ba30cf3bd4), [`fe4b8feb7`](https://github.com/medusajs/medusa/commit/fe4b8feb7e0af2ffc436ca77a769ecb37e16e652), [`aa690beed`](https://github.com/medusajs/medusa/commit/aa690beed775646cbc86b445fb5dc90dcac087d5), [`5eb61fa0e`](https://github.com/medusajs/medusa/commit/5eb61fa0ef991b8a9fabb16c2c159e51b9541867), [`f033711ad`](https://github.com/medusajs/medusa/commit/f033711ad649466d72dd9f673d75848c97c0861f), [`eed784d7d`](https://github.com/medusajs/medusa/commit/eed784d7d0b58aeddc9f6f5ea56fe80c608b22f5), [`3171b0e51`](https://github.com/medusajs/medusa/commit/3171b0e518aebcaa31bbe5c6e914d65282873cda), [`a0c919a8d`](https://github.com/medusajs/medusa/commit/a0c919a8d01ca5edf62336de48e9a112e3822f38), [`522e306e2`](https://github.com/medusajs/medusa/commit/522e306e2e9abf4afce63f30714389eba32bef7f), [`80b95a230`](https://github.com/medusajs/medusa/commit/80b95a230056d9ed15f7302f248094f879516faf), [`a1e59313c`](https://github.com/medusajs/medusa/commit/a1e59313c964a944a287b54f6654d1d19ac8a59b), [`10bf05c14`](https://github.com/medusajs/medusa/commit/10bf05c147cb65a263465129790edd44a6d8948b), [`cbbf3ca05`](https://github.com/medusajs/medusa/commit/cbbf3ca054387a900c5777c2eb0218df2c72bae6), [`9ba09ba4d`](https://github.com/medusajs/medusa/commit/9ba09ba4d753f132537f0447097fe9f54922c074), [`12d304307`](https://github.com/medusajs/medusa/commit/12d304307af87ea9287a41869eb33ef09f273d85), [`693015fde`](https://github.com/medusajs/medusa/commit/693015fde3218d67fb9c07eebeaea9950bf3f1f1), [`287c829c9`](https://github.com/medusajs/medusa/commit/287c829c9c5a9797fb8cd118b7a6066ad1935898), [`74bc4b16a`](https://github.com/medusajs/medusa/commit/74bc4b16a07f78668003ca930bf2a0d928897ceb), [`0cca13779`](https://github.com/medusajs/medusa/commit/0cca13779d0e84683193ad82ab163a10a807e903), [`aed7805c0`](https://github.com/medusajs/medusa/commit/aed7805c0e64b884007148bde90cfce7bee8aad4), [`e359d3f85`](https://github.com/medusajs/medusa/commit/e359d3f85bc12fd3868fc4b563cd994366e899dd), [`0d1b63d77`](https://github.com/medusajs/medusa/commit/0d1b63d773ad91846757a6f0b81b78b0b97b3f2b), [`4042beb10`](https://github.com/medusajs/medusa/commit/4042beb1026b9ad8b381aaa6e1a5214cd92db00f), [`809ab2e0e`](https://github.com/medusajs/medusa/commit/809ab2e0eb2d62054481fa6491d3f7cafbadab4f), [`f43e9f0f2`](https://github.com/medusajs/medusa/commit/f43e9f0f20a8b0637252951b2bdfed4d42fb9f5e), [`842423679`](https://github.com/medusajs/medusa/commit/8424236799c3789f884285cd3c8a491e91aef2ca), [`935870e01`](https://github.com/medusajs/medusa/commit/935870e010af1ec884259b1f1328421e99acc3af), [`826d4bedf`](https://github.com/medusajs/medusa/commit/826d4bedfe1b6459163711d5173eb8eadfdea26e), [`57d7728dd`](https://github.com/medusajs/medusa/commit/57d7728dd9d00df712e1a872899b8397955dfe46), [`15f47baf5`](https://gitLine truncated
|
||||
- @medusajs/medusa@1.8.0
|
||||
- @medusajs/openapi-typescript-codegen@0.2.0
|
||||
|
||||
## 0.2.0-rc.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4488ec685`](https://github.com/medusajs/medusa/commit/4488ec68524f95f367cbd352e9e5eb1957d1d0d6)]:
|
||||
- @medusajs/medusa@1.8.0-rc.8
|
||||
|
||||
## 0.2.0-rc.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`748833383`](https://github.com/medusajs/medusa/commit/748833383f4bafd05109dac7afa1286fe851cba3), [`e5a2e9c8d`](https://github.com/medusajs/medusa/commit/e5a2e9c8d237bbe4e3563f5a7a892ca41f01ba24)]:
|
||||
- @medusajs/medusa@1.8.0-rc.7
|
||||
|
||||
## 0.2.0-rc.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`788ddc0f4`](https://github.com/medusajs/medusa/commit/788ddc0f43696df607f07133af15a04b29d5447d), [`a5ad6c054`](https://github.com/medusajs/medusa/commit/a5ad6c05428e1bb090bbc5a51345a00821781c06), [`7f87c4f2c`](https://github.com/medusajs/medusa/commit/7f87c4f2c8abb876213a595005e67d770be9cbe4), [`eed784d7d`](https://github.com/medusajs/medusa/commit/eed784d7d0b58aeddc9f6f5ea56fe80c608b22f5), [`a0c919a8d`](https://github.com/medusajs/medusa/commit/a0c919a8d01ca5edf62336de48e9a112e3822f38), [`0cca13779`](https://github.com/medusajs/medusa/commit/0cca13779d0e84683193ad82ab163a10a807e903)]:
|
||||
- @medusajs/medusa@1.8.0-rc.6
|
||||
|
||||
## 0.2.0-rc.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4342ac884`](https://github.com/medusajs/medusa/commit/4342ac884bc3fe473576ef10d291f3547e0ffc62), [`809ab2e0e`](https://github.com/medusajs/medusa/commit/809ab2e0eb2d62054481fa6491d3f7cafbadab4f)]:
|
||||
- @medusajs/medusa@1.8.0-rc.5
|
||||
|
||||
## 0.2.0-rc.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3631](https://github.com/medusajs/medusa/pull/3631) [`377b9ce8c`](https://github.com/medusajs/medusa/commit/377b9ce8c27cb2c4d10d154c005c7553c173c0e8) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - fix(oas:test): fix beforeAll timeout silent failure
|
||||
|
||||
- Updated dependencies [[`5fd74b38a`](https://github.com/medusajs/medusa/commit/5fd74b38ae1b4f7dced191983b78db83f7b1f71b), [`999aeb116`](https://github.com/medusajs/medusa/commit/999aeb116c4742e5b5e0d80793af23f7727276f0), [`5e405be02`](https://github.com/medusajs/medusa/commit/5e405be02cc94779222dc3d930e747027496d918), [`a7e3f2d34`](https://github.com/medusajs/medusa/commit/a7e3f2d343c4059ba83022ec5c09f8101b251297)]:
|
||||
- @medusajs/medusa@1.8.0-rc.4
|
||||
|
||||
## 0.2.0-rc.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`0695ff642`](https://github.com/medusajs/medusa/commit/0695ff642b5836e7c28d40118aafe7a769023d5a), [`693015fde`](https://github.com/medusajs/medusa/commit/693015fde3218d67fb9c07eebeaea9950bf3f1f1)]:
|
||||
- @medusajs/medusa@1.8.0-rc.3
|
||||
|
||||
## 0.2.0-rc.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa@1.8.0-rc.2
|
||||
|
||||
## 0.2.0-rc.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3559](https://github.com/medusajs/medusa/pull/3559) [`53c4a43ca`](https://github.com/medusajs/medusa/commit/53c4a43ca2b2c04920dc6f38e07348e7dfc23195) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(oas:cli): output better error when no command is provided
|
||||
|
||||
- Updated dependencies [[`530740889`](https://github.com/medusajs/medusa/commit/53074088941719ac7ca435e76e3e64ba23fac200), [`e359d3f85`](https://github.com/medusajs/medusa/commit/e359d3f85bc12fd3868fc4b563cd994366e899dd), [`bca1f80dd`](https://github.com/medusajs/medusa/commit/bca1f80dd501d878455e1ad4f5091cf20ef900ea), [`5f41cd9a6`](https://github.com/medusajs/medusa/commit/5f41cd9a67eb0962f999291594c0aac5e38eb916), [`1ce3cc5ae`](https://github.com/medusajs/medusa/commit/1ce3cc5ae4e4cb16eb03be49c9287503f759fc60), [`332a9b686`](https://github.com/medusajs/medusa/commit/332a9b686bd0d224855215213dd11b4704283f62), [`feaf8d2e1`](https://github.com/medusajs/medusa/commit/feaf8d2e19715585d154464d003759c3a1f4f322)]:
|
||||
- @medusajs/medusa@1.8.0-rc.1
|
||||
|
||||
## 0.2.0-rc.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#3411](https://github.com/medusajs/medusa/pull/3411) [`966aea65c`](https://github.com/medusajs/medusa/commit/966aea65c221403bf316ae7665cc8f73bccd9c38) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(oas-cli): combine admin + store + custom OAS
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3213](https://github.com/medusajs/medusa/pull/3213) [`813706190`](https://github.com/medusajs/medusa/commit/8137061908d20314314b95d049b966a624e7123d) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(oas): medusa-oas-cli as OAS build tool
|
||||
|
||||
- [#3272](https://github.com/medusajs/medusa/pull/3272) [`1c40346e9`](https://github.com/medusajs/medusa/commit/1c40346e9e56718de4a6e2d5c2d52abd388343e3) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(codegen): openapi-typescript-codegen fork
|
||||
|
||||
- Updated dependencies [[`d6b1ad1cc`](https://github.com/medusajs/medusa/commit/d6b1ad1ccd9a8f91b169f30ff99492cf3adcccac), [`e143a8697`](https://github.com/medusajs/medusa/commit/e143a86976a5cc6a53b7a795e8486df4db1d1c09), [`121b42acf`](https://github.com/medusajs/medusa/commit/121b42acfe98c12dd593f9b1f2072ff0f3b61724), [`84e448968`](https://github.com/medusajs/medusa/commit/84e44896836b2c44017572ac5192ab1cd937048c), [`33c6ccf05`](https://github.com/medusajs/medusa/commit/33c6ccf0591b8ef527f3b10a70b51e29751b4998), [`30a320364`](https://github.com/medusajs/medusa/commit/30a3203640be9993ba2f8447abfdecc0d3e2f9b6), [`240d0ea7b`](https://github.com/medusajs/medusa/commit/240d0ea7b88ff494d0fe28c7c5348e958c14571f), [`6c0462472`](https://github.com/medusajs/medusa/commit/6c046247275c46d934f03d53471bdd555a19a9ad), [`589d1c09b`](https://github.com/medusajs/medusa/commit/589d1c09b085dcaf9667061201ac9deff3047466), [`13f40d721`](https://github.com/medusajs/medusa/commit/13f40d721702fbcdf6c131354ec9a81322d4a662), [`fe9eea4c1`](https://github.com/medusajs/medusa/commit/fe9eea4c18b7e04ba91660716c92b11a49840a3c), [`0a02b70e5`](https://github.com/medusajs/medusa/commit/0a02b70e59cfbd8888fb58c29ee9aaf96eb8099a), [`fe4b8feb7`](https://github.com/medusajs/medusa/commit/fe4b8feb7e0af2ffc436ca77a769ecb37e16e652), [`aa690beed`](https://github.com/medusajs/medusa/commit/aa690beed775646cbc86b445fb5dc90dcac087d5), [`5eb61fa0e`](https://github.com/medusajs/medusa/commit/5eb61fa0ef991b8a9fabb16c2c159e51b9541867), [`f033711ad`](https://github.com/medusajs/medusa/commit/f033711ad649466d72dd9f673d75848c97c0861f), [`3171b0e51`](https://github.com/medusajs/medusa/commit/3171b0e518aebcaa31bbe5c6e914d65282873cda), [`522e306e2`](https://github.com/medusajs/medusa/commit/522e306e2e9abf4afce63f30714389eba32bef7f), [`80b95a230`](https://github.com/medusajs/medusa/commit/80b95a230056d9ed15f7302f248094f879516faf), [`a1e59313c`](https://github.com/medusajs/medusa/commit/a1e59313c964a944a287b54f6654d1d19ac8a59b), [`10bf05c14`](https://github.com/medusajs/medusa/commit/10bf05c147cb65a263465129790edd44a6d8948b), [`cbbf3ca05`](https://github.com/medusajs/medusa/commit/cbbf3ca054387a900c5777c2eb0218df2c72bae6), [`9ba09ba4d`](https://github.com/medusajs/medusa/commit/9ba09ba4d753f132537f0447097fe9f54922c074), [`12d304307`](https://github.com/medusajs/medusa/commit/12d304307af87ea9287a41869eb33ef09f273d85), [`287c829c9`](https://github.com/medusajs/medusa/commit/287c829c9c5a9797fb8cd118b7a6066ad1935898), [`74bc4b16a`](https://github.com/medusajs/medusa/commit/74bc4b16a07f78668003ca930bf2a0d928897ceb), [`aed7805c0`](https://github.com/medusajs/medusa/commit/aed7805c0e64b884007148bde90cfce7bee8aad4), [`0d1b63d77`](https://github.com/medusajs/medusa/commit/0d1b63d773ad91846757a6f0b81b78b0b97b3f2b), [`4042beb10`](https://github.com/medusajs/medusa/commit/4042beb1026b9ad8b381aaa6e1a5214cd92db00f), [`f43e9f0f2`](https://github.com/medusajs/medusa/commit/f43e9f0f20a8b0637252951b2bdfed4d42fb9f5e), [`842423679`](https://github.com/medusajs/medusa/commit/8424236799c3789f884285cd3c8a491e91aef2ca), [`935870e01`](https://github.com/medusajs/medusa/commit/935870e010af1ec884259b1f1328421e99acc3af), [`826d4bedf`](https://github.com/medusajs/medusa/commit/826d4bedfe1b6459163711d5173eb8eadfdea26e), [`57d7728dd`](https://github.com/medusajs/medusa/commit/57d7728dd9d00df712e1a872899b8397955dfe46), [`15f47baf5`](https://github.com/medusajs/medusa/commit/15f47baf56e6722b7821cfaa2fb468e582dfa2c1), [`1c40346e9`](https://github.com/medusajs/medusa/commit/1c40346e9e56718de4a6e2d5c2d52abd388343e3), [`55c5fba0d`](https://github.com/medusajs/medusa/commit/55c5fba0d3dbd015c3ffd74d645a8057892d0f52), [`38503fff5`](https://github.com/medusajs/medusa/commit/38503fff56bbceb092e396ac11432a56967b53e9), [`40de54b01`](https://github.com/medusajs/medusa/commit/40de54b0101bdfd37f577d18c10ec9f1ab1ce8fe), [`54dcc1871`](https://github.com/medusajs/medusa/commit/54dcc1871c8f28bea962dbb9df6e79b038d56449), [`478d1af8d`](https://github.com/medusajs/medusa/commit/478d1af8d0df0af16baf4f130e19b0be34f5f295), [`77d46220c`](https://github.com/medusajs/medusa/commit/77d46220c23bfe19e575cbc445874eb6c22f3c73), [`6748877c6`](https://github.com/medusajs/medusa/commit/6748877c694c1433f666c6987f20af76b201b495), [`7e17e0ddc`](https://github.com/medusajs/medusa/commit/7e17e0ddc2e6b2891e9ee1420b04a541899d2a9d), [`7f2223b65`](https://github.com/medusajs/medusa/commit/7f2223b6507b0a3c452977bfcdee92af2086fa29), [`7b57695e0`](https://github.com/medusajs/medusa/commit/7b57695e00433e1d54f8cdc912ef7e5f28fc1071), [`7d585f5f8`](https://github.com/medusajs/medusa/commit/7d585f5f84a910c02d274df7a489dc3ff1ea273a), [`4e9d257d3`](https://github.com/medusajs/medusa/commit/4e9d257d3bf76703ef5be8ca054cc9f0f7339def), [`ef5ef9f5a`](https://github.com/medusajs/medusa/commit/ef5ef9f5a26febf0b64d9981606c1e59999ca76e), [`46547f29c`](https://github.com/medusajs/medusa/commit/46547f29c755719e22d2977c5e5f8ab8a4a7fcae), [`f97b3d7cc`](https://gitLine truncated
|
||||
- @medusajs/medusa@1.8.0-rc.0
|
||||
- @medusajs/openapi-typescript-codegen@0.2.0-rc.0
|
||||
|
||||
## 0.1.0
|
||||
@@ -0,0 +1,219 @@
|
||||
# medusa-oas-cli - 0.1.0 - experimental
|
||||
|
||||
A command-line tool for all OpenAPI Specifications (OAS) related tooling.
|
||||
|
||||
## Install
|
||||
|
||||
`yarn add --dev @medusajs/medusa-oas-cli`
|
||||
|
||||
Install in the global namespace is not yet supported.
|
||||
~~`npm install -g @medusajs/medusa-oas-cli`~~
|
||||
|
||||
## Configuration / First time setup
|
||||
|
||||
N/A
|
||||
|
||||
## How to use
|
||||
|
||||
```bash
|
||||
yarn medusa-oas <command>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Command - `oas`
|
||||
|
||||
This command will scan the `@medusajs/medusa` package in order to extract JSDoc OAS into a json file.
|
||||
|
||||
The command will output one of three the files `admin.oas.json`, `store.oas.json` or `combined.oas.json` in the same
|
||||
directory that the command was run.
|
||||
|
||||
Invalid OAS with throw an error and will prevent the files from being outputted.
|
||||
|
||||
#### `--type <string>`
|
||||
|
||||
Specify which API OAS to create. Accepts `admin`, `store`, `combined`.
|
||||
|
||||
The `combined` option will merge both the admin and the store APIs into a single OAS file.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas oas --type admin
|
||||
```
|
||||
|
||||
#### `--out-dir <path>`
|
||||
|
||||
Specify in which directory should the files be outputted. It accepts a relative or absolute path.
|
||||
If the directory doesn't exist, it will be created. Defaults to `./`.
|
||||
|
||||
```bash
|
||||
yarm medusa-oas oas --out-dir
|
||||
```
|
||||
|
||||
#### `--paths <paths...>`
|
||||
|
||||
Allows passing additional directory paths to crawl for JSDoc OAS and include in the generated OAS.
|
||||
It accepts multiple entries.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas oas --paths ~/medusa-server/src
|
||||
```
|
||||
|
||||
#### `--base <path>`
|
||||
|
||||
Allows overwriting the content the API's base.yaml OAS that is fed to swagger-inline.
|
||||
Paths, tags, and components will be merged together. Other OAS properties will be overwritten.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas oas --base ~/medusa-server/oas/custom.oas.base.yaml
|
||||
```
|
||||
|
||||
#### `--dry-run`
|
||||
|
||||
Will package the OAS but will not output file. Useful for validating OAS.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas oas --dry-run
|
||||
```
|
||||
|
||||
#### `--force`
|
||||
|
||||
Ignore OAS errors and attempt to output generated OAS files.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas oas --force
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Command - `client`
|
||||
|
||||
Will generate API client files from a given OAS file.
|
||||
|
||||
#### `--src-file <path>`
|
||||
|
||||
Specify the path to the OAS JSON file.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas client --src-file ./store.oas.json`
|
||||
```
|
||||
|
||||
#### `--name <name>`
|
||||
|
||||
Namespace for the generated client. Usually `admin` or `store`.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas client --name admin`
|
||||
```
|
||||
|
||||
#### `--out-dir <path>`
|
||||
|
||||
Specify in which directory should the files be outputted. Accepts relative and absolute path.
|
||||
If the directory doesn't exist, it will be created. Defaults to `./`.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas client --out-dir ./client`
|
||||
```
|
||||
|
||||
#### `--type <type>`
|
||||
|
||||
Client component types to generate. Accepts `all`, `types`, `client`, `hooks`.
|
||||
Defaults to `all`.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas client --type types`
|
||||
```
|
||||
|
||||
#### `--types-packages <name>`
|
||||
|
||||
Replace relative import statements by types package name. Mandatory when using `--type client` or `--type hooks`.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas client --types-packages @medusajs/client-types`
|
||||
```
|
||||
|
||||
#### `--client-packages <name>`
|
||||
|
||||
Replace relative import statements by client package name. Mandatory when using `--type hooks`.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas client --client-packages @medusajs/medusa-js`
|
||||
```
|
||||
|
||||
#### `--clean`
|
||||
|
||||
Delete destination directory content before generating client.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas client --clean
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Command - `docs`
|
||||
|
||||
Will sanitize OAS for use with Redocly's API documentation viewer.
|
||||
|
||||
#### `--src-file <path>`
|
||||
|
||||
Specify the path to the OAS JSON file.
|
||||
|
||||
```bash
|
||||
yarm medusa-oas docs --src-file ./store.oas.json
|
||||
```
|
||||
|
||||
#### `--out-dir <path>`
|
||||
|
||||
Specify in which directory should the files be outputted. Accepts relative and absolute path.
|
||||
If the directory doesn't exist, it will be created. Defaults to `./`.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas docs --src-file ./store.oas.json --out-dir ./docs`
|
||||
```
|
||||
|
||||
#### `--config <path>`
|
||||
|
||||
Specify the path to a Redocly config file.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas --src-file ./store.oas.json --config ./redocly-config.yaml
|
||||
```
|
||||
|
||||
#### `--dry-run`
|
||||
|
||||
Will sanitize the OAS but will not output file. Useful for troubleshooting circular reference issues.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas docs --src-file ./store.oas.json --dry-run
|
||||
```
|
||||
|
||||
#### `--clean`
|
||||
|
||||
Delete destination directory content before generating client.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas docs --src-file ./store.oas.json --clean
|
||||
```
|
||||
|
||||
#### `--split`
|
||||
|
||||
Creates a multi-file structure output. Uses `redocly split` internally.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas docs --src-file ./store.oas.json --split
|
||||
```
|
||||
|
||||
#### `--preview`
|
||||
|
||||
Generate a preview of the API documentation in a browser. Does not output files. Uses `redocly preview-docs` internally.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas docs --src-file ../../../www/apps/api-reference/specs/store.oas.json --preview
|
||||
```
|
||||
|
||||
#### `--html`
|
||||
|
||||
Generate a zero-dependency static HTML file. Uses `redocly build-docs` internally.
|
||||
|
||||
```bash
|
||||
yarn medusa-oas docs --src-file ./store.oas.json --html
|
||||
```
|
||||
@@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
transform: {
|
||||
"^.+\\.[jt]s?$": [
|
||||
"ts-jest",
|
||||
{
|
||||
tsconfig: "tsconfig.json",
|
||||
isolatedModules: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
testEnvironment: `node`,
|
||||
moduleFileExtensions: [`js`, `ts`],
|
||||
testTimeout: 100000,
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
version: 1.0.0
|
||||
title: Medusa API
|
||||
paths: { }
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "@medusajs/medusa-oas-cli",
|
||||
"version": "0.3.2",
|
||||
"description": "OAS CLI",
|
||||
"main": "dist/index.js",
|
||||
"bin": {
|
||||
"medusa-oas": "./dist/index.js"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"oas"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/medusajs/medusa",
|
||||
"directory": "packages/oas/medusa-oas-cli"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"author": "Medusa",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"jest": "^29.1.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "4.9.5",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "cross-env NODE_ENV=production tsc --build",
|
||||
"build": "tsc --build",
|
||||
"medusa-oas": "ts-node src/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@medusajs/medusa": "^1.20.4",
|
||||
"@medusajs/openapi-typescript-codegen": "^0.2.1",
|
||||
"@medusajs/types": "^1.11.15",
|
||||
"@medusajs/utils": "^1.11.8",
|
||||
"@readme/json-schema-ref-parser": "^1.2.0",
|
||||
"@readme/openapi-parser": "^2.4.0",
|
||||
"@redocly/cli": "^1.7.0",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"commander": "^10.0.0",
|
||||
"execa": "1.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"openapi3-ts": "^3.1.2",
|
||||
"swagger-inline": "^6.1.0",
|
||||
"yargs": "^17.7.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
module.exports = CircularPatch
|
||||
|
||||
/**
|
||||
* Since ref() is triggered upon reaching a $ref OAS line (leaf),
|
||||
* we want to inverse `schemas` instructions in order to optimize iterators.
|
||||
*/
|
||||
function preparePatches(schemas) {
|
||||
const patches = []
|
||||
const patchesObj = {}
|
||||
for (const schemaToPatch in schemas) {
|
||||
for (const schemaName of schemas[schemaToPatch]) {
|
||||
if (!patchesObj[schemaName]) {
|
||||
patchesObj[schemaName] = {
|
||||
schemaName,
|
||||
schemaPointer: `#/components/schemas/${schemaName}`,
|
||||
schemaToPatchPointers: [],
|
||||
}
|
||||
}
|
||||
const schemaToPatchPointer = `#/components/schemas/${schemaToPatch}`
|
||||
if (
|
||||
!patchesObj[schemaName].schemaToPatchPointers.includes(
|
||||
schemaToPatchPointer
|
||||
)
|
||||
) {
|
||||
patchesObj[schemaName].schemaToPatchPointers.push(schemaToPatchPointer)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const key in patchesObj) {
|
||||
patches.push(patchesObj[key])
|
||||
}
|
||||
return patches
|
||||
}
|
||||
|
||||
function applyPatch(node, schemaName) {
|
||||
delete node["$ref"]
|
||||
node.type = "object"
|
||||
if (!node.description && schemaName) {
|
||||
node.description = `${schemaName} object.`
|
||||
}
|
||||
}
|
||||
|
||||
function CircularPatch({ schemas = {}, verbose = false }) {
|
||||
const logs = []
|
||||
const patches = preparePatches(schemas)
|
||||
const refPathPrefix = "#/components/schemas/"
|
||||
const refPathPrefixLength = refPathPrefix.length
|
||||
const refPathPrefixRegex = /#\/components\/schemas\/\w+/
|
||||
return {
|
||||
ref(ref, ctx, resolved) {
|
||||
if (
|
||||
ctx.type.name.toLowerCase() !== "schema" ||
|
||||
!resolved?.location?.pointer
|
||||
) {
|
||||
return
|
||||
}
|
||||
for (const patch of patches) {
|
||||
if (resolved.location.pointer !== patch.schemaPointer) {
|
||||
continue
|
||||
}
|
||||
const ctxSchemaPointer =
|
||||
ctx.location.pointer.match(refPathPrefixRegex)[0]
|
||||
if (!patch.schemaToPatchPointers.includes(ctxSchemaPointer)) {
|
||||
continue
|
||||
}
|
||||
applyPatch(ref)
|
||||
if (verbose) {
|
||||
logs.push(
|
||||
`${ctxSchemaPointer.substring(refPathPrefixLength)} patch $ref to ${
|
||||
patch.schemaName
|
||||
}`
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
Root: {
|
||||
leave() {
|
||||
if (verbose) {
|
||||
logs.sort()
|
||||
for (const log of logs) {
|
||||
console.debug(log)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
const CircularPatch = require("./decorators/circular-patch")
|
||||
|
||||
const id = "medusa"
|
||||
|
||||
const decorators = {
|
||||
oas3: {
|
||||
"circular-patch": CircularPatch,
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
id,
|
||||
decorators,
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
plugins:
|
||||
- "./plugins/medusa/index.js"
|
||||
|
||||
# Allows to replace a $ref with `type: object` in order to avoid infinite loops
|
||||
# when Redocly attempts to render circular references.
|
||||
decorators:
|
||||
medusa/circular-patch:
|
||||
schemas:
|
||||
Address:
|
||||
- Customer
|
||||
Cart:
|
||||
- Customer
|
||||
- Order
|
||||
- Payment
|
||||
- PaymentSession
|
||||
ClaimImage:
|
||||
- ClaimItem
|
||||
ClaimItem:
|
||||
- ClaimOrder
|
||||
ClaimOrder:
|
||||
- Fulfillment
|
||||
- Order
|
||||
- Return
|
||||
Country:
|
||||
- Region
|
||||
Customer:
|
||||
- Order
|
||||
CustomerGroup:
|
||||
- Customer
|
||||
- PriceList
|
||||
Discount:
|
||||
- Discount
|
||||
DiscountRule:
|
||||
- DiscountCondition
|
||||
DraftOrder:
|
||||
- Cart
|
||||
- Order
|
||||
Fulfillment:
|
||||
- ClaimOrder
|
||||
- Order
|
||||
- Swap
|
||||
FulfillmentItem:
|
||||
- Fulfillment
|
||||
GiftCard:
|
||||
- Order
|
||||
GiftCardTransaction:
|
||||
- GiftCard
|
||||
- Order
|
||||
LineItem:
|
||||
- Cart
|
||||
- ClaimOrder
|
||||
- Order
|
||||
- OrderEdit
|
||||
- Swap
|
||||
LineItemAdjustment:
|
||||
- LineItem
|
||||
LineItemTaxLine:
|
||||
- LineItem
|
||||
MoneyAmount:
|
||||
- PriceList
|
||||
- ProductVariant
|
||||
- Region
|
||||
Notification:
|
||||
- Notification
|
||||
Order:
|
||||
- Cart
|
||||
- ClaimOrder
|
||||
- Customer
|
||||
- DraftOrder
|
||||
- Fulfillment
|
||||
- OrderEdit
|
||||
- Payment
|
||||
- Refund
|
||||
- Return
|
||||
- Swap
|
||||
OrderEdit:
|
||||
- Order
|
||||
OrderItemChange:
|
||||
- OrderEdit
|
||||
Payment:
|
||||
- Cart
|
||||
- Order
|
||||
- Swap
|
||||
ProductCategory:
|
||||
- ProductCategory
|
||||
- Product
|
||||
ProductCollection:
|
||||
- Product
|
||||
ProductOption:
|
||||
- Product
|
||||
ProductOptionValue:
|
||||
- ProductOption
|
||||
- ProductVariant
|
||||
ProductVariant:
|
||||
- Product
|
||||
ProductVariantInventoryItem:
|
||||
- ProductVariant
|
||||
Refund:
|
||||
- Order
|
||||
- Payment
|
||||
Return:
|
||||
- ClaimOrder
|
||||
- Order
|
||||
- Swap
|
||||
ReturnItem:
|
||||
- Return
|
||||
ReturnReason:
|
||||
- ReturnReason
|
||||
SalesChannelLocation:
|
||||
- SalesChannel
|
||||
ShippingMethod:
|
||||
- Cart
|
||||
- ClaimOrder
|
||||
- Order
|
||||
- Payment
|
||||
- Return
|
||||
- Swap
|
||||
ShippingMethodTaxLine:
|
||||
- ShippingMethod
|
||||
ShippingOption:
|
||||
- Region
|
||||
ShippingOptionRequirement:
|
||||
- ShippingOption
|
||||
ShippingProfile:
|
||||
- Product
|
||||
- ShippingOption
|
||||
Swap:
|
||||
- Cart
|
||||
- Fulfillment
|
||||
- Order
|
||||
- Payment
|
||||
- Return
|
||||
TaxRate:
|
||||
- Region
|
||||
TrackingLink:
|
||||
- Fulfillment
|
||||
SalesChannel:
|
||||
- Order
|
||||
- Cart
|
||||
- PublishableApiKey
|
||||
CustomerGroupResponse:
|
||||
- CustomerResponse
|
||||
ProductCategoryResponse:
|
||||
- ProductCategoryResponse
|
||||
|
||||
# Similar config to /www/docs/docusaurus.config.js > redocusaurus
|
||||
# Allows to emulate rendering of API public documentation when using `yarn redocly preview-docs openapi.yaml`
|
||||
theme:
|
||||
openapi:
|
||||
theme:
|
||||
colors:
|
||||
primary:
|
||||
dark: "#242526"
|
||||
sidebar:
|
||||
width: "250px"
|
||||
disableSearch: true
|
||||
expandResponses: "200,204"
|
||||
generatedPayloadSamplesMaxDepth: 4
|
||||
hideDownloadButton: true
|
||||
hideRequestPayloadSample: true
|
||||
nativeScrollbars: true
|
||||
requiredPropsFirst: true
|
||||
showObjectSchemaExamples: true
|
||||
sortTagsAlphabetically: true
|
||||
@@ -0,0 +1,376 @@
|
||||
import { exists, getTmpDirectory } from "../utils/fs-utils"
|
||||
import { writeJson } from "../utils/json-utils"
|
||||
import { OpenAPIObject } from "openapi3-ts"
|
||||
import path from "path"
|
||||
import { v4 as uid } from "uuid"
|
||||
import { readYaml, writeYaml } from "../utils/yaml-utils"
|
||||
import { mkdir, readdir } from "fs/promises"
|
||||
import {
|
||||
formatHintRecommendation,
|
||||
getCircularPatchRecommendation,
|
||||
getCircularReferences,
|
||||
} from "../utils/circular-patch-utils"
|
||||
import execa from "execa"
|
||||
|
||||
const basePath = path.resolve(__dirname, `../../../`)
|
||||
|
||||
export const runCLI = async (command: string, options: string[] = []) => {
|
||||
const params = ["run", "medusa-oas", command, ...options]
|
||||
try {
|
||||
const { all: logs } = await execa("yarn", params, {
|
||||
cwd: basePath,
|
||||
all: true,
|
||||
})
|
||||
} catch (err) {
|
||||
throw new Error(err.message + err.all)
|
||||
}
|
||||
}
|
||||
|
||||
export const getBaseOpenApi = (): OpenAPIObject => {
|
||||
return {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
title: "Test",
|
||||
version: "1.0.0",
|
||||
},
|
||||
paths: {},
|
||||
components: {},
|
||||
}
|
||||
}
|
||||
|
||||
describe("command docs", () => {
|
||||
let tmpDir: string
|
||||
let openApi: OpenAPIObject
|
||||
|
||||
beforeAll(async () => {
|
||||
tmpDir = await getTmpDirectory()
|
||||
})
|
||||
|
||||
beforeEach(async () => {
|
||||
openApi = getBaseOpenApi()
|
||||
})
|
||||
|
||||
describe("basic usage", () => {
|
||||
let srcFile: string
|
||||
|
||||
beforeAll(async () => {
|
||||
openApi = getBaseOpenApi()
|
||||
openApi.components = {
|
||||
schemas: {
|
||||
Order: {
|
||||
type: "object",
|
||||
},
|
||||
},
|
||||
}
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await mkdir(outDir, { recursive: true })
|
||||
srcFile = path.resolve(outDir, "store.oas.json")
|
||||
await writeJson(srcFile, openApi)
|
||||
})
|
||||
|
||||
it("should generate docs", async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await runCLI("docs", ["--src-file", srcFile, "--out-dir", outDir])
|
||||
const generatedFilePath = path.resolve(outDir, "openapi.yaml")
|
||||
const oas = (await readYaml(generatedFilePath)) as OpenAPIObject
|
||||
const files = await readdir(outDir)
|
||||
expect(oas.components?.schemas?.Order).toBeDefined()
|
||||
expect(files.length).toBe(1)
|
||||
})
|
||||
|
||||
it("should clean output directory", async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await mkdir(outDir, { recursive: true })
|
||||
await writeJson(path.resolve(outDir, "test.json"), { foo: "bar" })
|
||||
await runCLI("docs", [
|
||||
"--src-file",
|
||||
srcFile,
|
||||
"--out-dir",
|
||||
outDir,
|
||||
"--clean",
|
||||
])
|
||||
const files = await readdir(outDir)
|
||||
expect(files.includes("test.json")).toBeFalsy()
|
||||
expect(files.length).toBe(1)
|
||||
})
|
||||
|
||||
it("should not output any files", async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await runCLI("docs", [
|
||||
"--src-file",
|
||||
srcFile,
|
||||
"--out-dir",
|
||||
outDir,
|
||||
"--dry-run",
|
||||
])
|
||||
const outDirExists = await exists(outDir)
|
||||
expect(outDirExists).toBeFalsy()
|
||||
})
|
||||
|
||||
it("should split output into multiple files and directories", async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
/**
|
||||
* For split to output files, we need to not be in test mode
|
||||
* See https://github.com/Redocly/redocly-cli/blob/v1.0.0-beta.125/packages/cli/src/utils.ts#L206-L215
|
||||
*/
|
||||
const previousEnv = process.env.NODE_ENV
|
||||
process.env.NODE_ENV = "development"
|
||||
await runCLI("docs", [
|
||||
"--src-file",
|
||||
srcFile,
|
||||
"--out-dir",
|
||||
outDir,
|
||||
"--split",
|
||||
"--clean",
|
||||
])
|
||||
process.env.NODE_ENV = previousEnv
|
||||
const oasFileExists = await exists(path.resolve(outDir, "openapi.yaml"))
|
||||
const outFileExists = await exists(
|
||||
path.resolve(outDir, "components/schemas/Order.yaml")
|
||||
)
|
||||
expect(oasFileExists).toBeTruthy()
|
||||
expect(outFileExists).toBeTruthy()
|
||||
})
|
||||
|
||||
it("should generate static HTML docs", async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await runCLI("docs", [
|
||||
"--src-file",
|
||||
srcFile,
|
||||
"--out-dir",
|
||||
outDir,
|
||||
"--html",
|
||||
])
|
||||
const generatedFilePath = path.resolve(outDir, "index.html")
|
||||
const htmlFileExists = await exists(generatedFilePath)
|
||||
expect(htmlFileExists).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
describe("--config", () => {
|
||||
let srcFile: string
|
||||
let configFile: string
|
||||
let configYamlFile: string
|
||||
|
||||
beforeAll(async () => {
|
||||
openApi = getBaseOpenApi()
|
||||
openApi.components = {
|
||||
schemas: {
|
||||
Customer: {
|
||||
type: "object",
|
||||
properties: {
|
||||
address: {
|
||||
$ref: "#/components/schemas/Address",
|
||||
},
|
||||
},
|
||||
},
|
||||
TestOrder: {
|
||||
type: "object",
|
||||
properties: {
|
||||
address: {
|
||||
$ref: "#/components/schemas/Address",
|
||||
},
|
||||
},
|
||||
},
|
||||
Address: {
|
||||
type: "object",
|
||||
properties: {
|
||||
/**
|
||||
* We expect this circular reference to already be handled by
|
||||
* our CLI's default redocly-config.yaml
|
||||
*/
|
||||
customer: {
|
||||
$ref: "#/components/schemas/Customer",
|
||||
},
|
||||
/**
|
||||
* We expect this circular reference to not be handled.
|
||||
*/
|
||||
test_order: {
|
||||
$ref: "#/components/schemas/TestOrder",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
const config = {
|
||||
decorators: {
|
||||
"medusa/circular-patch": {
|
||||
schemas: {
|
||||
Address: ["TestOrder"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await mkdir(outDir, { recursive: true })
|
||||
srcFile = path.resolve(outDir, "store.oas.json")
|
||||
await writeJson(srcFile, openApi)
|
||||
configFile = path.resolve(outDir, "redocly-config.json")
|
||||
await writeJson(configFile, config)
|
||||
configYamlFile = path.resolve(outDir, "redocly-config.yaml")
|
||||
await writeYaml(configYamlFile, config)
|
||||
})
|
||||
|
||||
it("should fail with unhandled circular reference", async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await expect(
|
||||
runCLI("docs", [
|
||||
"--src-file",
|
||||
srcFile,
|
||||
"--out-dir",
|
||||
outDir,
|
||||
"--dry-run",
|
||||
])
|
||||
).rejects.toThrow("Unhandled circular references")
|
||||
})
|
||||
|
||||
it("should succeed with patched circular reference", async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await expect(
|
||||
runCLI("docs", [
|
||||
"--src-file",
|
||||
srcFile,
|
||||
"--out-dir",
|
||||
outDir,
|
||||
"--config",
|
||||
configFile,
|
||||
"--dry-run",
|
||||
])
|
||||
).resolves.not.toThrow()
|
||||
})
|
||||
|
||||
it("should succeed when config is of type yaml", async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await expect(
|
||||
runCLI("docs", [
|
||||
"--src-file",
|
||||
srcFile,
|
||||
"--out-dir",
|
||||
outDir,
|
||||
"--config",
|
||||
configYamlFile,
|
||||
"--dry-run",
|
||||
])
|
||||
).resolves.not.toThrow()
|
||||
})
|
||||
|
||||
it("should fail when config is not a file", async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await expect(
|
||||
runCLI("docs", [
|
||||
"--src-file",
|
||||
srcFile,
|
||||
"--out-dir",
|
||||
outDir,
|
||||
"--dry-run",
|
||||
"--config",
|
||||
outDir,
|
||||
])
|
||||
).rejects.toThrow("--config must be a file")
|
||||
})
|
||||
|
||||
it("should fail when config is not of supported file type", async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await mkdir(outDir, { recursive: true })
|
||||
const tmpFile = path.resolve(outDir, "tmp.txt")
|
||||
await writeJson(tmpFile, { foo: "bar" })
|
||||
await expect(
|
||||
runCLI("docs", [
|
||||
"--src-file",
|
||||
srcFile,
|
||||
"--out-dir",
|
||||
outDir,
|
||||
"--dry-run",
|
||||
"--config",
|
||||
tmpFile,
|
||||
])
|
||||
).rejects.toThrow("--config file must be of type .json or .yaml")
|
||||
})
|
||||
})
|
||||
|
||||
describe("circular references", () => {
|
||||
let srcFile: string
|
||||
|
||||
beforeAll(async () => {
|
||||
openApi = getBaseOpenApi()
|
||||
openApi.components = {
|
||||
schemas: {
|
||||
Customer: {
|
||||
type: "object",
|
||||
properties: {
|
||||
address: {
|
||||
$ref: "#/components/schemas/Address",
|
||||
},
|
||||
},
|
||||
},
|
||||
TestOrder: {
|
||||
type: "object",
|
||||
properties: {
|
||||
address: {
|
||||
$ref: "#/components/schemas/Address",
|
||||
},
|
||||
},
|
||||
},
|
||||
Address: {
|
||||
type: "object",
|
||||
properties: {
|
||||
customer: {
|
||||
$ref: "#/components/schemas/Customer",
|
||||
},
|
||||
test_order: {
|
||||
$ref: "#/components/schemas/TestOrder",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await mkdir(outDir, { recursive: true })
|
||||
srcFile = path.resolve(outDir, "store.oas.json")
|
||||
await writeJson(srcFile, openApi)
|
||||
})
|
||||
|
||||
it("should find circular references", async () => {
|
||||
const { circularRefs, oas } = await getCircularReferences(srcFile)
|
||||
expect(circularRefs.length).toBe(2)
|
||||
expect(circularRefs).toEqual(
|
||||
expect.arrayContaining([
|
||||
"#/components/schemas/Address/properties/customer",
|
||||
"#/components/schemas/TestOrder/properties/address",
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("should recommend which schemas to patch to resolve circular references", async () => {
|
||||
/**
|
||||
* The recommendation is heavily influenced but the dereference operation
|
||||
* from @readme/json-schema-ref-parser. It's not an exact science and the
|
||||
* results may vary between versions.
|
||||
*/
|
||||
const { circularRefs, oas } = await getCircularReferences(srcFile)
|
||||
const recommendation = getCircularPatchRecommendation(circularRefs, oas)
|
||||
expect(recommendation).toEqual(
|
||||
expect.objectContaining({
|
||||
Address: expect.arrayContaining(["Customer"]),
|
||||
TestOrder: expect.arrayContaining(["Address"]),
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should format hint", async () => {
|
||||
const { circularRefs, oas } = await getCircularReferences(srcFile)
|
||||
const recommendation = getCircularPatchRecommendation(circularRefs, oas)
|
||||
const hint = formatHintRecommendation(recommendation)
|
||||
expect(hint).toEqual(
|
||||
expect.stringContaining(`decorators:
|
||||
medusa/circular-patch:
|
||||
schemas:
|
||||
Address:
|
||||
- Customer
|
||||
TestOrder:
|
||||
- Address
|
||||
`)
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,669 @@
|
||||
import fs from "fs/promises"
|
||||
import { OpenAPIObject, SchemaObject } from "openapi3-ts"
|
||||
import { OperationObject } from "openapi3-ts/src/model/OpenApi"
|
||||
import path from "path"
|
||||
import { v4 as uid } from "uuid"
|
||||
import { getTmpDirectory } from "../utils/fs-utils"
|
||||
import { readYaml } from "../utils/yaml-utils"
|
||||
import { readJson } from "../utils/json-utils"
|
||||
import execa from "execa"
|
||||
|
||||
/**
|
||||
* OAS output directory
|
||||
*
|
||||
* @privateRemark
|
||||
* This should be the only directory OAS is loaded from for Medusa V2.
|
||||
* For now, we only use it if the --v2 flag it passed to the CLI tool.
|
||||
*/
|
||||
const oasOutputPath = path.resolve(
|
||||
__dirname, "..", "..", "..", "..", "docs-util", "oas-output"
|
||||
)
|
||||
const basePath = path.resolve(__dirname, `../../`)
|
||||
|
||||
export const runCLI = async (command: string, options: string[] = []) => {
|
||||
const params = ["run", "medusa-oas", command, ...options]
|
||||
try {
|
||||
const { all: logs } = await execa("yarn", params, {
|
||||
cwd: basePath,
|
||||
all: true,
|
||||
})
|
||||
} catch (err) {
|
||||
throw new Error(err.message + err.all)
|
||||
}
|
||||
}
|
||||
|
||||
const listOperations = (oas: OpenAPIObject): OperationObject[] => {
|
||||
const operations: OperationObject[] = []
|
||||
for (const url in oas.paths) {
|
||||
if (oas.paths.hasOwnProperty(url)) {
|
||||
const path = oas.paths[url]
|
||||
for (const method in path) {
|
||||
if (path.hasOwnProperty(method)) {
|
||||
switch (method) {
|
||||
case "get":
|
||||
case "put":
|
||||
case "post":
|
||||
case "delete":
|
||||
case "options":
|
||||
case "head":
|
||||
case "patch":
|
||||
operations.push(path[method])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return operations
|
||||
}
|
||||
|
||||
describe("command oas", () => {
|
||||
let tmpDir: string
|
||||
|
||||
beforeAll(async () => {
|
||||
tmpDir = await getTmpDirectory()
|
||||
})
|
||||
|
||||
describe("--type admin", () => {
|
||||
let oas: OpenAPIObject
|
||||
|
||||
/**
|
||||
* In a CI context, beforeAll might exceed the configured jest timeout.
|
||||
* Until we upgrade our jest version, the timeout error will be swallowed
|
||||
* and the test will fail in unexpected ways.
|
||||
*/
|
||||
beforeAll(async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await runCLI("oas", ["--type", "admin", "--out-dir", outDir, "--local"])
|
||||
const generatedFilePath = path.resolve(outDir, "admin.oas.json")
|
||||
oas = (await readJson(generatedFilePath)) as OpenAPIObject
|
||||
})
|
||||
|
||||
it("generates oas with admin routes only", async () => {
|
||||
const routes = Object.keys(oas.paths)
|
||||
expect(routes.includes("/admin/products")).toBeTruthy()
|
||||
expect(routes.includes("/store/products")).toBeFalsy()
|
||||
})
|
||||
|
||||
it("generates oas using admin.oas.base.yaml", async () => {
|
||||
const yamlFilePath = path.resolve(
|
||||
oasOutputPath,
|
||||
"base",
|
||||
"admin.oas.base.yaml"
|
||||
)
|
||||
const oasBase = (await readYaml(yamlFilePath)) as OpenAPIObject
|
||||
expect(oas.info.title).toEqual(oasBase.info.title)
|
||||
})
|
||||
})
|
||||
|
||||
describe("--type store", () => {
|
||||
let oas: OpenAPIObject
|
||||
|
||||
beforeAll(async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await runCLI("oas", ["--type", "store", "--out-dir", outDir, "--local"])
|
||||
const generatedFilePath = path.resolve(outDir, "store.oas.json")
|
||||
oas = (await readJson(generatedFilePath)) as OpenAPIObject
|
||||
})
|
||||
|
||||
it("generates oas with store routes only", async () => {
|
||||
const routes = Object.keys(oas.paths)
|
||||
expect(routes.includes("/admin/products")).toBeFalsy()
|
||||
expect(routes.includes("/store/products")).toBeTruthy()
|
||||
})
|
||||
|
||||
it("generates oas using store.oas.base.yaml", async () => {
|
||||
const yamlFilePath = path.resolve(
|
||||
oasOutputPath,
|
||||
"base",
|
||||
"store.oas.base.yaml"
|
||||
)
|
||||
const oasBase = (await readYaml(yamlFilePath)) as OpenAPIObject
|
||||
expect(oas.info.title).toEqual(oasBase.info.title)
|
||||
})
|
||||
})
|
||||
|
||||
describe("--type combined", () => {
|
||||
let oas: OpenAPIObject
|
||||
|
||||
beforeAll(async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await runCLI("oas", ["--type", "combined", "--out-dir", outDir, "--local"])
|
||||
const generatedFilePath = path.resolve(outDir, "combined.oas.json")
|
||||
oas = (await readJson(generatedFilePath)) as OpenAPIObject
|
||||
})
|
||||
|
||||
it("generates oas with admin and store routes", async () => {
|
||||
const routes = Object.keys(oas.paths)
|
||||
expect(routes.includes("/admin/products")).toBeTruthy()
|
||||
expect(routes.includes("/store/products")).toBeTruthy()
|
||||
})
|
||||
|
||||
it("generates oas using default.oas.base.yaml", async () => {
|
||||
const yamlFilePath = path.resolve(
|
||||
basePath,
|
||||
"oas",
|
||||
"default.oas.base.yaml"
|
||||
)
|
||||
const oasBase = (await readYaml(yamlFilePath)) as OpenAPIObject
|
||||
expect(oas.info.title).toEqual(oasBase.info.title)
|
||||
})
|
||||
|
||||
it("prefixes tags with api type", async () => {
|
||||
const found = (oas.tags ?? []).filter((tag) => {
|
||||
return !(tag.name.startsWith("Admin") || tag.name.startsWith("Store"))
|
||||
})
|
||||
expect(found).toEqual([])
|
||||
})
|
||||
|
||||
it("prefixes route's tags with api type", async () => {
|
||||
const tags: string[] = listOperations(oas)
|
||||
.map((operation) => {
|
||||
return operation.tags ?? []
|
||||
})
|
||||
.flat()
|
||||
const found = tags.filter((tag) => {
|
||||
return !(tag.startsWith("Admin") || tag.startsWith("Store"))
|
||||
})
|
||||
expect(found).toEqual([])
|
||||
})
|
||||
|
||||
it("prefixes route's operationId with api type", async () => {
|
||||
const operationIds: string[] = listOperations(oas)
|
||||
.map((operation) => operation.operationId)
|
||||
.filter((operationId): operationId is string => !!operationId)
|
||||
const found = operationIds.filter((tag) => {
|
||||
return !(tag.startsWith("Admin") || tag.startsWith("Store"))
|
||||
})
|
||||
expect(found).toEqual([])
|
||||
})
|
||||
|
||||
it("combines components.schemas from admin and store", async () => {
|
||||
const schemas = Object.keys(oas.components?.schemas ?? {})
|
||||
expect(schemas.includes("AdminProductsListRes")).toBeTruthy()
|
||||
expect(schemas.includes("StoreProductsListRes")).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* to optimize test suite time, we only test --paths with the store api
|
||||
*/
|
||||
describe("--paths", () => {
|
||||
let oas: OpenAPIObject
|
||||
|
||||
beforeAll(async () => {
|
||||
const fileContent = `
|
||||
/** @oas [get] /foobar/tests
|
||||
* operationId: GetFoobarTests
|
||||
*/
|
||||
/** @oas [get] /store/regions
|
||||
* operationId: OverwrittenOperation
|
||||
*/
|
||||
/**
|
||||
* @schema FoobarTestSchema
|
||||
* type: object
|
||||
* properties:
|
||||
* foo:
|
||||
* type: string
|
||||
*/
|
||||
/**
|
||||
* @schema StoreRegionsListRes
|
||||
* type: object
|
||||
* properties:
|
||||
* foo:
|
||||
* type: string
|
||||
*/
|
||||
`
|
||||
const additionalPath = path.resolve(tmpDir, uid())
|
||||
const filePath = path.resolve(additionalPath, "foobar.ts")
|
||||
await fs.mkdir(additionalPath, { recursive: true })
|
||||
await fs.writeFile(filePath, fileContent, "utf8")
|
||||
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await runCLI("oas", [
|
||||
"--type",
|
||||
"store",
|
||||
"--out-dir",
|
||||
outDir,
|
||||
"--paths",
|
||||
additionalPath,
|
||||
"--local"
|
||||
])
|
||||
const generatedFilePath = path.resolve(outDir, "store.oas.json")
|
||||
oas = (await readJson(generatedFilePath)) as OpenAPIObject
|
||||
})
|
||||
|
||||
it("should add new path to existing paths", async () => {
|
||||
const routes = Object.keys(oas.paths)
|
||||
expect(routes.includes("/store/products")).toBeTruthy()
|
||||
expect(routes.includes("/foobar/tests")).toBeTruthy()
|
||||
})
|
||||
|
||||
it("should overwrite existing path", async () => {
|
||||
expect(oas.paths["/store/regions"]["get"].operationId).toBe(
|
||||
"OverwrittenOperation"
|
||||
)
|
||||
})
|
||||
|
||||
it("should add new schema to existing schemas", async () => {
|
||||
const schemas = Object.keys(oas.components?.schemas ?? {})
|
||||
expect(schemas.includes("StoreProductsListRes")).toBeTruthy()
|
||||
expect(schemas.includes("FoobarTestSchema")).toBeTruthy()
|
||||
})
|
||||
|
||||
it("should overwrite existing schema", async () => {
|
||||
const schema = oas.components?.schemas?.StoreRegionsListRes as
|
||||
| SchemaObject
|
||||
| undefined
|
||||
expect(schema?.properties?.foo).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* to optimize test suite time, we only test --base with the store api
|
||||
*/
|
||||
describe("--base", () => {
|
||||
let oas: OpenAPIObject
|
||||
|
||||
beforeAll(async () => {
|
||||
const fileContent = `
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
version: 1.0.1
|
||||
title: Custom API
|
||||
servers:
|
||||
- url: https://foobar.com
|
||||
security:
|
||||
- api_key: []
|
||||
externalDocs:
|
||||
url: https://docs.com
|
||||
webhooks:
|
||||
"foo-hook":
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
tags:
|
||||
- name: Products
|
||||
description: Overwritten tag
|
||||
- name: FoobarTag
|
||||
description: Foobar tag description
|
||||
paths:
|
||||
"/foobar/tests":
|
||||
get:
|
||||
operationId: GetFoobarTests
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
"/store/regions":
|
||||
get:
|
||||
operationId: OverwrittenOperation
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
components:
|
||||
schemas:
|
||||
FoobarTestSchema:
|
||||
type: object
|
||||
properties:
|
||||
foo:
|
||||
type: string
|
||||
StoreRegionsListRes:
|
||||
type: object
|
||||
properties:
|
||||
foo:
|
||||
type: string
|
||||
callbacks:
|
||||
fooCallback:
|
||||
get:
|
||||
description: foo callback
|
||||
examples:
|
||||
fooExample:
|
||||
description: foo example
|
||||
headers:
|
||||
fooHeader:
|
||||
description: foo header
|
||||
links:
|
||||
fooLink:
|
||||
description: foo link
|
||||
operationRef: GetFoobarTests
|
||||
parameters:
|
||||
fooParameter:
|
||||
description: foo parameter
|
||||
name: foobar
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBodies:
|
||||
fooRequestBody:
|
||||
description: foo requestBody
|
||||
content:
|
||||
"application/octet-stream": { }
|
||||
responses:
|
||||
fooResponse:
|
||||
description: foo response
|
||||
securitySchemes:
|
||||
fooSecurity:
|
||||
description: foo security
|
||||
type: apiKey
|
||||
name: foo-api-key
|
||||
in: header
|
||||
`
|
||||
const targetDir = path.resolve(tmpDir, uid())
|
||||
const filePath = path.resolve(targetDir, "custom.oas.base.yaml")
|
||||
await fs.mkdir(targetDir, { recursive: true })
|
||||
await fs.writeFile(filePath, fileContent, "utf8")
|
||||
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await runCLI("oas", [
|
||||
"--type",
|
||||
"store",
|
||||
"--out-dir",
|
||||
outDir,
|
||||
"--base",
|
||||
filePath,
|
||||
"--local"
|
||||
])
|
||||
const generatedFilePath = path.resolve(outDir, "store.oas.json")
|
||||
oas = (await readJson(generatedFilePath)) as OpenAPIObject
|
||||
})
|
||||
|
||||
it("should add new path to existing paths", async () => {
|
||||
const routes = Object.keys(oas.paths)
|
||||
expect(routes.includes("/store/products")).toBeTruthy()
|
||||
expect(routes.includes("/foobar/tests")).toBeTruthy()
|
||||
})
|
||||
|
||||
it("should overwrite existing path", async () => {
|
||||
expect(oas.paths["/store/regions"]["get"].operationId).toBe(
|
||||
"OverwrittenOperation"
|
||||
)
|
||||
})
|
||||
|
||||
it("should add new schema to existing schemas", async () => {
|
||||
const schemas = Object.keys(oas.components?.schemas ?? {})
|
||||
expect(schemas.includes("StoreProductsListRes")).toBeTruthy()
|
||||
expect(schemas.includes("FoobarTestSchema")).toBeTruthy()
|
||||
})
|
||||
|
||||
it("should overwrite existing schema", async () => {
|
||||
const schema = oas.components?.schemas?.StoreRegionsListRes as
|
||||
| SchemaObject
|
||||
| undefined
|
||||
expect(schema?.properties?.foo).toBeDefined()
|
||||
})
|
||||
|
||||
it("should replace base properties", async () => {
|
||||
expect(oas.openapi).toBe("3.1.0")
|
||||
expect(oas.info).toEqual({ version: "1.0.1", title: "Custom API" })
|
||||
expect(oas.servers).toEqual([{ url: "https://foobar.com" }])
|
||||
expect(oas.security).toEqual([{ api_key: [] }])
|
||||
expect(oas.externalDocs).toEqual({ url: "https://docs.com" })
|
||||
expect(oas.webhooks).toEqual({
|
||||
"foo-hook": { get: { responses: { "200": { description: "OK" } } } },
|
||||
})
|
||||
})
|
||||
|
||||
it("should add new tag", async () => {
|
||||
expect(oas.tags).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: "FoobarTag",
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("should overwrite existing tag", async () => {
|
||||
expect(oas.tags).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: "Products",
|
||||
description: "Overwritten tag",
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("should add new components", async () => {
|
||||
const components = oas.components ?? {}
|
||||
expect(
|
||||
Object.keys(components.callbacks ?? {}).includes("fooCallback")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.examples ?? {}).includes("fooExample")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.headers ?? {}).includes("fooHeader")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.links ?? {}).includes("fooLink")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.parameters ?? {}).includes("fooParameter")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.requestBodies ?? {}).includes("fooRequestBody")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.responses ?? {}).includes("fooResponse")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.securitySchemes ?? {}).includes("fooSecurity")
|
||||
).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
describe("public OAS", () => {
|
||||
let oas: OpenAPIObject
|
||||
/**
|
||||
* In a CI context, beforeAll might exceed the configured jest timeout.
|
||||
* Until we upgrade our jest version, the timeout error will be swallowed
|
||||
* and the test will fail in unexpected ways.
|
||||
*/
|
||||
beforeAll(async () => {
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await runCLI("oas", ["--type", "admin", "--out-dir", outDir])
|
||||
const generatedFilePath = path.resolve(outDir, "admin.oas.json")
|
||||
oas = (await readJson(generatedFilePath)) as OpenAPIObject
|
||||
})
|
||||
|
||||
it("generates oas with admin routes only", async () => {
|
||||
const routes = Object.keys(oas.paths)
|
||||
expect(routes.includes("/admin/products")).toBeTruthy()
|
||||
expect(routes.includes("/store/products")).toBeFalsy()
|
||||
})
|
||||
})
|
||||
|
||||
describe("public OAS with base", () => {
|
||||
let oas: OpenAPIObject
|
||||
beforeAll(async () => {
|
||||
const fileContent = `
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
version: 1.0.1
|
||||
title: Custom API
|
||||
servers:
|
||||
- url: https://foobar.com
|
||||
security:
|
||||
- api_key: []
|
||||
externalDocs:
|
||||
url: https://docs.com
|
||||
webhooks:
|
||||
"foo-hook":
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
tags:
|
||||
- name: Products
|
||||
description: Overwritten tag
|
||||
- name: FoobarTag
|
||||
description: Foobar tag description
|
||||
paths:
|
||||
"/foobar/tests":
|
||||
get:
|
||||
operationId: GetFoobarTests
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
"/store/regions":
|
||||
get:
|
||||
operationId: OverwrittenOperation
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
components:
|
||||
schemas:
|
||||
FoobarTestSchema:
|
||||
type: object
|
||||
properties:
|
||||
foo:
|
||||
type: string
|
||||
StoreRegionsListRes:
|
||||
type: object
|
||||
properties:
|
||||
foo:
|
||||
type: string
|
||||
callbacks:
|
||||
fooCallback:
|
||||
get:
|
||||
description: foo callback
|
||||
examples:
|
||||
fooExample:
|
||||
description: foo example
|
||||
headers:
|
||||
fooHeader:
|
||||
description: foo header
|
||||
links:
|
||||
fooLink:
|
||||
description: foo link
|
||||
operationRef: GetFoobarTests
|
||||
parameters:
|
||||
fooParameter:
|
||||
description: foo parameter
|
||||
name: foobar
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBodies:
|
||||
fooRequestBody:
|
||||
description: foo requestBody
|
||||
content:
|
||||
"application/octet-stream": { }
|
||||
responses:
|
||||
fooResponse:
|
||||
description: foo response
|
||||
securitySchemes:
|
||||
fooSecurity:
|
||||
description: foo security
|
||||
type: apiKey
|
||||
name: foo-api-key
|
||||
in: header
|
||||
`
|
||||
const targetDir = path.resolve(tmpDir, uid())
|
||||
const filePath = path.resolve(targetDir, "custom.oas.base.yaml")
|
||||
await fs.mkdir(targetDir, { recursive: true })
|
||||
await fs.writeFile(filePath, fileContent, "utf8")
|
||||
|
||||
const outDir = path.resolve(tmpDir, uid())
|
||||
await runCLI("oas", [
|
||||
"--type",
|
||||
"store",
|
||||
"--out-dir",
|
||||
outDir,
|
||||
"--base",
|
||||
filePath,
|
||||
])
|
||||
const generatedFilePath = path.resolve(outDir, "store.oas.json")
|
||||
oas = (await readJson(generatedFilePath)) as OpenAPIObject
|
||||
})
|
||||
|
||||
it("should add new path to existing paths", async () => {
|
||||
const routes = Object.keys(oas.paths)
|
||||
expect(routes.includes("/store/products")).toBeTruthy()
|
||||
expect(routes.includes("/foobar/tests")).toBeTruthy()
|
||||
})
|
||||
|
||||
it("should overwrite existing path", async () => {
|
||||
expect(oas.paths["/store/regions"]["get"].operationId).toBe(
|
||||
"OverwrittenOperation"
|
||||
)
|
||||
})
|
||||
|
||||
it("should add new schema to existing schemas", async () => {
|
||||
const schemas = Object.keys(oas.components?.schemas ?? {})
|
||||
expect(schemas.includes("StoreProductsListRes")).toBeTruthy()
|
||||
expect(schemas.includes("FoobarTestSchema")).toBeTruthy()
|
||||
})
|
||||
|
||||
it("should overwrite existing schema", async () => {
|
||||
const schema = oas.components?.schemas?.StoreRegionsListRes as
|
||||
| SchemaObject
|
||||
| undefined
|
||||
expect(schema?.properties?.foo).toBeDefined()
|
||||
})
|
||||
|
||||
it("should replace base properties", async () => {
|
||||
expect(oas.openapi).toBe("3.1.0")
|
||||
expect(oas.info).toEqual({ version: "1.0.1", title: "Custom API" })
|
||||
expect(oas.servers).toEqual([{ url: "https://foobar.com" }])
|
||||
expect(oas.security).toEqual([{ api_key: [] }])
|
||||
expect(oas.externalDocs).toEqual({ url: "https://docs.com" })
|
||||
expect(oas.webhooks).toEqual({
|
||||
"foo-hook": { get: { responses: { "200": { description: "OK" } } } },
|
||||
})
|
||||
})
|
||||
|
||||
it("should add new tag", async () => {
|
||||
expect(oas.tags).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: "FoobarTag",
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("should overwrite existing tag", async () => {
|
||||
expect(oas.tags).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: "Products",
|
||||
description: "Overwritten tag",
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("should add new components", async () => {
|
||||
const components = oas.components ?? {}
|
||||
expect(
|
||||
Object.keys(components.callbacks ?? {}).includes("fooCallback")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.examples ?? {}).includes("fooExample")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.headers ?? {}).includes("fooHeader")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.links ?? {}).includes("fooLink")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.parameters ?? {}).includes("fooParameter")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.requestBodies ?? {}).includes("fooRequestBody")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.responses ?? {}).includes("fooResponse")
|
||||
).toBeTruthy()
|
||||
expect(
|
||||
Object.keys(components.securitySchemes ?? {}).includes("fooSecurity")
|
||||
).toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,176 @@
|
||||
import path from "path"
|
||||
import {
|
||||
generate,
|
||||
HttpClient,
|
||||
Indent,
|
||||
PackageNames,
|
||||
} from "@medusajs/openapi-typescript-codegen"
|
||||
import { upperFirst } from "lodash"
|
||||
import fs, { mkdir, readFile } from "fs/promises"
|
||||
import { OpenAPIObject } from "openapi3-ts"
|
||||
import { Command, Option, OptionValues } from "commander"
|
||||
|
||||
/**
|
||||
* CLI Command declaration
|
||||
*/
|
||||
export const commandName = "client"
|
||||
export const commandDescription = "Generate API clients from OAS."
|
||||
export const commandOptions: Option[] = [
|
||||
new Option(
|
||||
"-t, --type <type>",
|
||||
"Namespace for the generated client. Usually `admin` or `store`."
|
||||
).makeOptionMandatory(),
|
||||
|
||||
new Option(
|
||||
"-s, --src-file <srcFile>",
|
||||
"Path to source OAS JSON file."
|
||||
).makeOptionMandatory(),
|
||||
|
||||
new Option(
|
||||
"-o, --out-dir <outDir>",
|
||||
"Output directory for generated client files."
|
||||
).default(path.resolve(process.cwd(), "client")),
|
||||
|
||||
new Option(
|
||||
"-c, --component <component>",
|
||||
"Client component types to generate."
|
||||
)
|
||||
.choices(["all", "types", "client", "hooks"])
|
||||
.default("all"),
|
||||
|
||||
new Option(
|
||||
"--types-package <name>",
|
||||
"Replace relative import statements by types package name."
|
||||
),
|
||||
|
||||
new Option(
|
||||
"--client-package <name>",
|
||||
"Replace relative import statements by client package name."
|
||||
),
|
||||
|
||||
new Option(
|
||||
"--clean",
|
||||
"Delete destination directory content before generating client."
|
||||
),
|
||||
]
|
||||
|
||||
export function getCommand() {
|
||||
const command = new Command(commandName)
|
||||
command.description(commandDescription)
|
||||
for (const opt of commandOptions) {
|
||||
command.addOption(opt)
|
||||
}
|
||||
command.action(async (options) => await execute(options))
|
||||
command.showHelpAfterError(true)
|
||||
return command
|
||||
}
|
||||
|
||||
/**
|
||||
* Main
|
||||
*/
|
||||
export async function execute(cliParams: OptionValues) {
|
||||
/**
|
||||
* Process CLI options
|
||||
*/
|
||||
if (
|
||||
["client", "hooks"].includes(cliParams.component) &&
|
||||
!cliParams.typesPackage
|
||||
) {
|
||||
throw new Error(
|
||||
`--types-package must be declared when using --component=${cliParams.component}`
|
||||
)
|
||||
}
|
||||
if (cliParams.component === "hooks" && !cliParams.clientPackage) {
|
||||
throw new Error(
|
||||
`--client-package must be declared when using --component=${cliParams.component}`
|
||||
)
|
||||
}
|
||||
|
||||
const shouldClean = !!cliParams.clean
|
||||
const srcFile = path.resolve(cliParams.srcFile)
|
||||
const outDir = path.resolve(cliParams.outDir)
|
||||
const apiName = cliParams.type
|
||||
const packageNames: PackageNames = {
|
||||
models: cliParams.typesPackage,
|
||||
client: cliParams.clientPackage,
|
||||
}
|
||||
const exportComponent = cliParams.component
|
||||
|
||||
/**
|
||||
* Command execution
|
||||
*/
|
||||
console.log(`🟣 Generating client - ${apiName} - ${exportComponent}`)
|
||||
|
||||
if (shouldClean) {
|
||||
console.log(`🟠 Cleaning output directory`)
|
||||
await fs.rm(outDir, { recursive: true, force: true })
|
||||
}
|
||||
await mkdir(outDir, { recursive: true })
|
||||
|
||||
const oas = await getOASFromFile(srcFile)
|
||||
await generateClientSDK(oas, outDir, apiName, exportComponent, packageNames)
|
||||
|
||||
console.log(
|
||||
`⚫️ Client generated - ${apiName} - ${exportComponent} - ${outDir}`
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
const getOASFromFile = async (jsonFile: string): Promise<OpenAPIObject> => {
|
||||
const jsonString = await readFile(jsonFile, "utf8")
|
||||
return JSON.parse(jsonString)
|
||||
}
|
||||
|
||||
const generateClientSDK = async (
|
||||
oas: OpenAPIObject,
|
||||
targetDir: string,
|
||||
apiName: string,
|
||||
exportComponent: "all" | "types" | "client" | "hooks",
|
||||
packageNames: PackageNames = {}
|
||||
) => {
|
||||
const exports = {
|
||||
exportCore: false,
|
||||
exportServices: false,
|
||||
exportModels: false,
|
||||
exportHooks: false,
|
||||
}
|
||||
|
||||
switch (exportComponent) {
|
||||
case "types":
|
||||
exports.exportModels = true
|
||||
break
|
||||
case "client":
|
||||
exports.exportCore = true
|
||||
exports.exportServices = true
|
||||
break
|
||||
case "hooks":
|
||||
exports.exportHooks = true
|
||||
break
|
||||
default:
|
||||
exports.exportCore = true
|
||||
exports.exportServices = true
|
||||
exports.exportModels = true
|
||||
exports.exportHooks = true
|
||||
}
|
||||
|
||||
await generate({
|
||||
input: oas,
|
||||
output: targetDir,
|
||||
httpClient: HttpClient.AXIOS,
|
||||
useOptions: true,
|
||||
useUnionTypes: true,
|
||||
exportCore: exports.exportCore,
|
||||
exportServices: exports.exportServices,
|
||||
exportModels: exports.exportModels,
|
||||
exportHooks: exports.exportHooks,
|
||||
exportSchemas: false,
|
||||
indent: Indent.SPACE_2,
|
||||
postfixServices: "Service",
|
||||
postfixModels: "",
|
||||
clientName: `Medusa${upperFirst(apiName)}`,
|
||||
request: undefined,
|
||||
packageNames,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
import { PreviewDocsOptions, previewDocs } from "@redocly/cli/lib/commands/preview-docs"
|
||||
import { commandWrapper } from "@redocly/cli/lib/wrapper"
|
||||
import { Command, Option, OptionValues } from "commander"
|
||||
import execa from "execa"
|
||||
import fs, { mkdir } from "fs/promises"
|
||||
import { isArray, mergeWith } from "lodash"
|
||||
import * as path from "path"
|
||||
import {
|
||||
formatHintRecommendation,
|
||||
getCircularPatchRecommendation,
|
||||
getCircularReferences,
|
||||
} from "./utils/circular-patch-utils"
|
||||
import { getTmpDirectory, isFile } from "./utils/fs-utils"
|
||||
import { readJson } from "./utils/json-utils"
|
||||
import { jsonFileToYamlFile, readYaml, writeYaml, writeYamlFromJson } from "./utils/yaml-utils"
|
||||
import yargs from "yargs"
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
const basePath = path.resolve(__dirname, "../")
|
||||
|
||||
const medusaPluginRelativePath = "./plugins/medusa/index.js"
|
||||
const medusaPluginAbsolutePath = path.resolve(
|
||||
basePath,
|
||||
"redocly/plugins/medusa/index.js"
|
||||
)
|
||||
const configFileDefault = path.resolve(basePath, "redocly/redocly-config.yaml")
|
||||
|
||||
/**
|
||||
* CLI Command declaration
|
||||
*/
|
||||
export const commandName = "docs"
|
||||
export const commandDescription =
|
||||
"Sanitize OAS for use with Redocly's API documentation viewer."
|
||||
|
||||
export const commandOptions: Option[] = [
|
||||
new Option(
|
||||
"-s, --src-file <srcFile>",
|
||||
"Path to source OAS JSON file."
|
||||
).makeOptionMandatory(),
|
||||
new Option(
|
||||
"-o, --out-dir <outDir>",
|
||||
"Destination directory to output the sanitized OAS files."
|
||||
).default(process.cwd()),
|
||||
new Option(
|
||||
"--config <config>",
|
||||
"Configuration file to merge with default configuration before passing to Redocly's CLI."
|
||||
),
|
||||
new Option("-D, --dry-run", "Do not output files."),
|
||||
new Option(
|
||||
"--clean",
|
||||
"Delete destination directory content before generating documentation."
|
||||
),
|
||||
new Option("--split", "Creates a multi-file structure output."),
|
||||
new Option(
|
||||
"--preview",
|
||||
"Open a preview of the documentation. Does not output files."
|
||||
),
|
||||
new Option(
|
||||
"--html",
|
||||
"Generate a static HTML using Redocly's build-docs command."
|
||||
),
|
||||
new Option(
|
||||
"--main-file-name <mainFileName>",
|
||||
"The name of the main YAML file."
|
||||
).default("openapi.yaml")
|
||||
]
|
||||
|
||||
export function getCommand(): Command {
|
||||
const command = new Command(commandName)
|
||||
command.description(commandDescription)
|
||||
for (const opt of commandOptions) {
|
||||
command.addOption(opt)
|
||||
}
|
||||
command.action(async (options) => await execute(options))
|
||||
command.showHelpAfterError(true)
|
||||
return command
|
||||
}
|
||||
|
||||
/**
|
||||
* Main
|
||||
*/
|
||||
export async function execute(cliParams: OptionValues): Promise<void> {
|
||||
/**
|
||||
* Process CLI options
|
||||
*/
|
||||
const shouldClean = !!cliParams.clean
|
||||
const shouldSplit = !!cliParams.split
|
||||
const shouldPreview = !!cliParams.preview
|
||||
const shouldBuildHTML = !!cliParams.html
|
||||
const dryRun = !!cliParams.dryRun
|
||||
const srcFile = path.resolve(cliParams.srcFile)
|
||||
const outDir = path.resolve(cliParams.outDir)
|
||||
|
||||
const configFileCustom = cliParams.config
|
||||
? path.resolve(cliParams.config)
|
||||
: undefined
|
||||
if (configFileCustom) {
|
||||
if (!(await isFile(configFileCustom))) {
|
||||
throw new Error(`--config must be a file - ${configFileCustom}`)
|
||||
}
|
||||
if (![".json", ".yaml"].includes(path.extname(configFileCustom))) {
|
||||
throw new Error(
|
||||
`--config file must be of type .json or .yaml - ${configFileCustom}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command execution
|
||||
*/
|
||||
console.log(`🟣 Generating API documentation`)
|
||||
|
||||
const tmpDir = await getTmpDirectory()
|
||||
const configTmpFile = path.resolve(tmpDir, "redocly-config.yaml")
|
||||
/** matches naming convention from `redocly split` */
|
||||
const finalOASFile = cliParams.mainFileName
|
||||
|
||||
await createTmpConfig(configFileDefault, configTmpFile)
|
||||
if (configFileCustom) {
|
||||
console.log(
|
||||
`🔵 Merging configuration file - ${configFileCustom} > ${configTmpFile}`
|
||||
)
|
||||
await mergeConfig(configTmpFile, configFileCustom, configTmpFile)
|
||||
}
|
||||
|
||||
if (!dryRun) {
|
||||
if (shouldClean) {
|
||||
console.log(`🟠 Cleaning output directory`)
|
||||
await fs.rm(outDir, { recursive: true, force: true })
|
||||
}
|
||||
await mkdir(outDir, { recursive: true })
|
||||
}
|
||||
|
||||
const srcFileSanitized = path.resolve(tmpDir, "tmp.oas.yaml")
|
||||
await sanitizeOAS(srcFile, srcFileSanitized, configTmpFile)
|
||||
await circularReferenceCheck(srcFileSanitized)
|
||||
|
||||
if (dryRun) {
|
||||
console.log(`⚫️ Dry run - no files generated`)
|
||||
return
|
||||
}
|
||||
if (shouldPreview) {
|
||||
await preview(srcFileSanitized, configTmpFile)
|
||||
return
|
||||
}
|
||||
if (shouldSplit) {
|
||||
await generateReference(srcFileSanitized, outDir)
|
||||
} else {
|
||||
await writeYaml(path.join(outDir, finalOASFile), await fs.readFile(srcFileSanitized, "utf8"))
|
||||
}
|
||||
if (shouldBuildHTML) {
|
||||
const outHTMLFile = path.resolve(outDir, "index.html")
|
||||
await buildHTML(finalOASFile, outHTMLFile, configTmpFile)
|
||||
}
|
||||
console.log(`⚫️ API documentation generated - ${outDir}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
type RedoclyConfig = {
|
||||
apis?: Record<string, unknown>
|
||||
decorators?: Record<string, unknown>
|
||||
extends?: string[]
|
||||
organization?: string
|
||||
plugins?: string[]
|
||||
preprocessors?: Record<string, unknown>
|
||||
region?: string
|
||||
resolve?: Record<string, unknown>
|
||||
rules?: Record<string, unknown>
|
||||
theme?: Record<string, unknown>
|
||||
}
|
||||
|
||||
const mergeConfig = async (
|
||||
configFileDefault: string,
|
||||
configFileCustom: string,
|
||||
configFileOut: string
|
||||
): Promise<void> => {
|
||||
const configDefault = await readYaml(configFileDefault)
|
||||
const configCustom =
|
||||
path.extname(configFileCustom) === ".yaml"
|
||||
? await readYaml(configFileCustom)
|
||||
: await readJson(configFileCustom)
|
||||
|
||||
const config = mergeWith(configDefault, configCustom, (objValue, srcValue) =>
|
||||
isArray(objValue) ? objValue.concat(srcValue) : undefined
|
||||
) as RedoclyConfig
|
||||
|
||||
await writeYamlFromJson(configFileOut, config)
|
||||
}
|
||||
|
||||
const createTmpConfig = async (
|
||||
configFileDefault: string,
|
||||
configFileOut: string
|
||||
): Promise<void> => {
|
||||
const config = (await readYaml(configFileDefault)) as RedoclyConfig
|
||||
config.plugins = (config.plugins ?? []).filter(
|
||||
(plugin) => plugin !== medusaPluginRelativePath
|
||||
)
|
||||
config.plugins.push(medusaPluginAbsolutePath)
|
||||
|
||||
await writeYamlFromJson(configFileOut, config)
|
||||
}
|
||||
|
||||
const sanitizeOAS = async (
|
||||
srcFile: string,
|
||||
outFile: string,
|
||||
configFile: string
|
||||
): Promise<void> => {
|
||||
const { all: logs } = await execa(
|
||||
"yarn",
|
||||
[
|
||||
"redocly",
|
||||
"bundle",
|
||||
srcFile,
|
||||
`--output=${outFile}`,
|
||||
`--config=${configFile}`,
|
||||
],
|
||||
{ cwd: basePath, all: true }
|
||||
)
|
||||
console.log(logs)
|
||||
}
|
||||
|
||||
const circularReferenceCheck = async (srcFile: string): Promise<void> => {
|
||||
const { circularRefs, oas } = await getCircularReferences(srcFile)
|
||||
if (circularRefs.length) {
|
||||
console.log(circularRefs)
|
||||
let errorMessage = `🔴 Unhandled circular references - Please manually patch using --config ./redocly-config.yaml`
|
||||
const recommendation = getCircularPatchRecommendation(circularRefs, oas)
|
||||
if (Object.keys(recommendation).length) {
|
||||
const hint = formatHintRecommendation(recommendation)
|
||||
errorMessage += `
|
||||
Within redocly-config.yaml, try adding the following:
|
||||
###
|
||||
${hint}
|
||||
###
|
||||
`
|
||||
}
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
console.log(`🟢 All circular references are handled`)
|
||||
}
|
||||
|
||||
const generateReference = async (
|
||||
srcFile: string,
|
||||
outDir: string
|
||||
): Promise<void> => {
|
||||
const { all: logs } = await execa(
|
||||
"yarn",
|
||||
["redocly", "split", srcFile, `--outDir=${outDir}`],
|
||||
{ cwd: basePath, all: true }
|
||||
)
|
||||
console.log(logs)
|
||||
}
|
||||
|
||||
const preview = async (oasFile: string, configFile: string): Promise<void> => {
|
||||
await commandWrapper(previewDocs)({
|
||||
port: 8080,
|
||||
host: "127.0.0.1",
|
||||
api: oasFile,
|
||||
config: configFile,
|
||||
} as yargs.Arguments<PreviewDocsOptions>)
|
||||
}
|
||||
|
||||
const buildHTML = async (
|
||||
srcFile: string,
|
||||
outFile: string,
|
||||
configFile: string
|
||||
): Promise<void> => {
|
||||
const { all: logs } = await execa(
|
||||
"yarn",
|
||||
[
|
||||
"redocly",
|
||||
"build-docs",
|
||||
srcFile,
|
||||
`--output=${outFile}`,
|
||||
`--config=${configFile}`,
|
||||
`--cdn=true`,
|
||||
],
|
||||
{ cwd: basePath, all: true }
|
||||
)
|
||||
console.log(logs)
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
import OpenAPIParser from "@readme/openapi-parser"
|
||||
import { Command, Option, OptionValues } from "commander"
|
||||
import { lstat, mkdir, writeFile } from "fs/promises"
|
||||
import { OpenAPIObject } from "openapi3-ts"
|
||||
import * as path from "path"
|
||||
import swaggerInline from "swagger-inline"
|
||||
import { combineOAS } from "./utils/combine-oas"
|
||||
import {
|
||||
mergeBaseIntoOAS,
|
||||
mergePathsAndSchemasIntoOAS,
|
||||
} from "./utils/merge-oas"
|
||||
import { isFile } from "./utils/fs-utils"
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
// Medusa core package directory
|
||||
const medusaPackagePath = path.dirname(
|
||||
require.resolve("@medusajs/medusa/package.json")
|
||||
)
|
||||
// Types package directory
|
||||
const medusaTypesPath = path.dirname(
|
||||
require.resolve("@medusajs/types/package.json")
|
||||
)
|
||||
// Utils package directory
|
||||
const medusaUtilsPath = path.dirname(
|
||||
require.resolve("@medusajs/utils/package.json")
|
||||
)
|
||||
const basePath = path.resolve(__dirname, "../")
|
||||
|
||||
/**
|
||||
* CLI Command declaration
|
||||
*/
|
||||
export const commandName = "oas"
|
||||
export const commandDescription =
|
||||
"Compile full OAS from swagger-inline compliant JSDoc."
|
||||
|
||||
export const commandOptions: Option[] = [
|
||||
new Option("-t, --type <type>", "API type to compile.")
|
||||
.choices(["admin", "store", "combined"])
|
||||
.makeOptionMandatory(),
|
||||
new Option(
|
||||
"-o, --out-dir <outDir>",
|
||||
"Destination directory to output generated OAS files."
|
||||
).default(process.cwd()),
|
||||
new Option("-D, --dry-run", "Do not output files."),
|
||||
new Option(
|
||||
"-p, --paths <paths...>",
|
||||
"Additional paths to crawl for OAS JSDoc."
|
||||
),
|
||||
new Option(
|
||||
"-b, --base <base>",
|
||||
"Custom base OAS file to use for swagger-inline."
|
||||
),
|
||||
new Option("-F, --force", "Ignore OAS validation and output OAS files."),
|
||||
new Option(
|
||||
"--v2",
|
||||
"Generate OAS files for V2 endpoints. This loads OAS from docs-util/oas-output/operations directory"
|
||||
),
|
||||
new Option(
|
||||
"--local",
|
||||
"Generate OAS from local files rather than public OAS. This is useful for generating references in the Medusa monorepo."
|
||||
)
|
||||
]
|
||||
|
||||
export function getCommand() {
|
||||
const command = new Command(commandName)
|
||||
command.description(commandDescription)
|
||||
for (const opt of commandOptions) {
|
||||
command.addOption(opt)
|
||||
}
|
||||
command.action(async (options) => await execute(options))
|
||||
command.showHelpAfterError(true)
|
||||
return command
|
||||
}
|
||||
|
||||
/**
|
||||
* Main
|
||||
*/
|
||||
export async function execute(cliParams: OptionValues) {
|
||||
/**
|
||||
* Process CLI options
|
||||
*/
|
||||
const dryRun = !!cliParams.dryRun
|
||||
const force = !!cliParams.force
|
||||
const v2 = !!cliParams.v2
|
||||
const local = !!cliParams.local
|
||||
|
||||
const apiType: ApiType = cliParams.type
|
||||
|
||||
const outDir = path.resolve(cliParams.outDir)
|
||||
|
||||
const additionalPaths = (cliParams.paths ?? []).map((additionalPath) =>
|
||||
path.resolve(additionalPath)
|
||||
)
|
||||
for (const additionalPath of additionalPaths) {
|
||||
if (!(await isDirectory(additionalPath))) {
|
||||
throw new Error(`--paths must be a directory - ${additionalPath}`)
|
||||
}
|
||||
}
|
||||
|
||||
const baseFile = cliParams.base ? path.resolve(cliParams.base) : undefined
|
||||
if (baseFile) {
|
||||
if (!(await isFile(cliParams.base))) {
|
||||
throw new Error(`--base must be a file - ${baseFile}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command execution
|
||||
*/
|
||||
if (!dryRun) {
|
||||
await mkdir(outDir, { recursive: true })
|
||||
}
|
||||
|
||||
let oas: OpenAPIObject
|
||||
console.log(`🟣 Generating OAS - ${apiType}`)
|
||||
|
||||
if (apiType === "combined") {
|
||||
const adminOAS = !local ? await getPublicOas("admin", v2) : await getOASFromCodebase("admin", v2)
|
||||
const storeOAS = !local ? await getPublicOas("store", v2) : await getOASFromCodebase("store", v2)
|
||||
oas = await combineOAS(adminOAS, storeOAS)
|
||||
} else {
|
||||
oas = !local ? await getPublicOas(apiType, v2) : await getOASFromCodebase(apiType, v2)
|
||||
}
|
||||
|
||||
if (additionalPaths.length || baseFile) {
|
||||
const customOAS = await getOASFromPaths(additionalPaths, baseFile)
|
||||
if (baseFile) {
|
||||
mergeBaseIntoOAS(oas, customOAS)
|
||||
}
|
||||
if (additionalPaths.length) {
|
||||
mergePathsAndSchemasIntoOAS(oas, customOAS)
|
||||
}
|
||||
}
|
||||
|
||||
await validateOAS(oas, apiType, force)
|
||||
if (dryRun) {
|
||||
console.log(`⚫️ Dry run - no files generated`)
|
||||
return
|
||||
}
|
||||
await exportOASToJSON(oas, apiType, outDir)
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
async function getOASFromCodebase(
|
||||
apiType: ApiType,
|
||||
v2?: boolean
|
||||
): Promise<OpenAPIObject> {
|
||||
/**
|
||||
* OAS output directory
|
||||
*
|
||||
* @privateRemark
|
||||
* This should be the only directory OAS is loaded from for Medusa V2.
|
||||
* For now, we only use it if the --v2 flag it passed to the CLI tool.
|
||||
*/
|
||||
const oasOutputPath = path.resolve(
|
||||
__dirname, "..", "..", "..", "..", "docs-util", "oas-output"
|
||||
)
|
||||
const gen = await swaggerInline(
|
||||
v2 ? [
|
||||
path.resolve(oasOutputPath, "operations", apiType),
|
||||
path.resolve(oasOutputPath, "schemas"),
|
||||
// We currently load error schemas from here. If we change
|
||||
// that in the future, we should change the path.
|
||||
path.resolve(medusaPackagePath, "dist", "api/middlewares"),
|
||||
] : [
|
||||
path.resolve(medusaTypesPath, "dist"),
|
||||
path.resolve(medusaUtilsPath, "dist"),
|
||||
path.resolve(medusaPackagePath, "dist", "models"),
|
||||
path.resolve(medusaPackagePath, "dist", "types"),
|
||||
path.resolve(medusaPackagePath, "dist", "api/middlewares"),
|
||||
path.resolve(medusaPackagePath, "dist", `api/routes/${apiType}`),
|
||||
],
|
||||
{
|
||||
base: path.resolve(oasOutputPath, v2 ? "base-v2" : "base", `${apiType}.oas.base.yaml`),
|
||||
format: ".json",
|
||||
}
|
||||
)
|
||||
return (await OpenAPIParser.parse(JSON.parse(gen))) as OpenAPIObject
|
||||
}
|
||||
|
||||
async function getPublicOas(
|
||||
apiType: ApiType,
|
||||
v2?: boolean
|
||||
) {
|
||||
const url = `https://docs.medusajs.com/api/download/${apiType}?version=${v2 ? "2" : "1"}`
|
||||
return await OpenAPIParser.parse(url) as OpenAPIObject
|
||||
}
|
||||
|
||||
async function getOASFromPaths(
|
||||
additionalPaths: string[] = [],
|
||||
customBaseFile?: string
|
||||
): Promise<OpenAPIObject> {
|
||||
console.log(`🔵 Gathering custom OAS`)
|
||||
const gen = await swaggerInline(additionalPaths, {
|
||||
base:
|
||||
customBaseFile ?? path.resolve(basePath, "oas", "default.oas.base.yaml"),
|
||||
format: ".json",
|
||||
logger: (log) => {
|
||||
console.log(log)
|
||||
},
|
||||
})
|
||||
return (await OpenAPIParser.parse(JSON.parse(gen))) as OpenAPIObject
|
||||
}
|
||||
|
||||
async function validateOAS(
|
||||
oas: OpenAPIObject,
|
||||
apiType: ApiType,
|
||||
force = false
|
||||
): Promise<void> {
|
||||
try {
|
||||
await OpenAPIParser.validate(JSON.parse(JSON.stringify(oas)))
|
||||
console.log(`🟢 Valid OAS - ${apiType}`)
|
||||
} catch (err) {
|
||||
console.error(`🔴 Invalid OAS - ${apiType}`, err)
|
||||
if (!force) {
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function exportOASToJSON(
|
||||
oas: OpenAPIObject,
|
||||
apiType: ApiType,
|
||||
targetDir: string
|
||||
): Promise<void> {
|
||||
const json = JSON.stringify(oas, null, 2)
|
||||
const filePath = path.resolve(targetDir, `${apiType}.oas.json`)
|
||||
await writeFile(filePath, json)
|
||||
console.log(`⚫️ Exported OAS - ${apiType} - ${filePath}`)
|
||||
}
|
||||
|
||||
async function isDirectory(dirPath: string): Promise<boolean> {
|
||||
try {
|
||||
return (await lstat(path.resolve(dirPath))).isDirectory()
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
import { Command } from "commander"
|
||||
import { getCommand as oasGetCommand } from "./command-oas"
|
||||
import { getCommand as clientGetCommand } from "./command-client"
|
||||
import { getCommand as docsGetCommand } from "./command-docs"
|
||||
|
||||
const run = async () => {
|
||||
const program = getBaseCommand()
|
||||
|
||||
/**
|
||||
* Alias to command-oas.ts
|
||||
*/
|
||||
program.addCommand(oasGetCommand())
|
||||
|
||||
/**
|
||||
* Alias to command-client.ts
|
||||
*/
|
||||
program.addCommand(clientGetCommand())
|
||||
|
||||
/**
|
||||
* Alias to command-docs.ts
|
||||
*/
|
||||
program.addCommand(docsGetCommand())
|
||||
|
||||
/**
|
||||
* Run CLI
|
||||
*/
|
||||
await program.parseAsync()
|
||||
}
|
||||
|
||||
export function getBaseCommand() {
|
||||
const command = new Command()
|
||||
command.name("medusa-oas")
|
||||
command.action(async () => {
|
||||
console.log("No command provided.")
|
||||
command.outputHelp({ error: true })
|
||||
})
|
||||
command.showHelpAfterError(true)
|
||||
command.helpOption(false)
|
||||
return command
|
||||
}
|
||||
|
||||
void (async () => {
|
||||
await run()
|
||||
})()
|
||||
@@ -0,0 +1 @@
|
||||
type ApiType = "store" | "admin" | "combined"
|
||||
@@ -0,0 +1,85 @@
|
||||
import { OpenAPIObject, SchemaObject } from "openapi3-ts"
|
||||
import OpenAPIParser from "@readme/openapi-parser"
|
||||
import { $Refs } from "@readme/json-schema-ref-parser"
|
||||
import { jsonObjectToYamlString } from "./yaml-utils"
|
||||
|
||||
export const getCircularReferences = async (
|
||||
srcFile: string
|
||||
): Promise<{ circularRefs: string[]; oas: OpenAPIObject }> => {
|
||||
const parser = new OpenAPIParser()
|
||||
const oas = (await parser.validate(srcFile, {
|
||||
dereference: {
|
||||
circular: "ignore",
|
||||
},
|
||||
})) as OpenAPIObject
|
||||
if (parser.$refs.circular) {
|
||||
const $refs = parser.$refs as $Refs
|
||||
let circularRefs = $refs.circularRefs.map(
|
||||
(ref) => ref.match(/#\/components\/schemas\/.*/)![0]
|
||||
)
|
||||
circularRefs = [...new Set(circularRefs)]
|
||||
circularRefs.sort()
|
||||
return { circularRefs, oas }
|
||||
}
|
||||
return { circularRefs: [], oas }
|
||||
}
|
||||
|
||||
export const getCircularPatchRecommendation = (
|
||||
circularRefs: string[],
|
||||
oas: OpenAPIObject
|
||||
): Record<string, string[]> => {
|
||||
type circularReferenceMatch = {
|
||||
schema: string
|
||||
property: string
|
||||
isArray: boolean
|
||||
referencedSchema: string
|
||||
}
|
||||
const matches: circularReferenceMatch[] = circularRefs
|
||||
.map((ref) => {
|
||||
let match =
|
||||
ref.match(
|
||||
/(?:.*)(?:#\/components\/schemas\/)(.*)(?:\/properties\/?)(.*)/
|
||||
) ?? []
|
||||
let schema = match[1]
|
||||
let property = match[2]
|
||||
let isArray = false
|
||||
if (property.endsWith("/items")) {
|
||||
property = property.replace("/items", "")
|
||||
isArray = true
|
||||
}
|
||||
return { schema, property, isArray }
|
||||
})
|
||||
.filter((match) => match.property !== "")
|
||||
.map((match) => {
|
||||
const baseSchema = oas.components!.schemas![match.schema] as SchemaObject
|
||||
const propertySpec = match.isArray
|
||||
? (baseSchema.properties![match.property] as SchemaObject).items!
|
||||
: baseSchema.properties![match.property]
|
||||
const referencedSchema = propertySpec["$ref"].match(
|
||||
/(?:#\/components\/schemas\/)(.*)/
|
||||
)![1]
|
||||
return {
|
||||
schema: match.schema,
|
||||
property: match.property,
|
||||
isArray: match.isArray,
|
||||
referencedSchema,
|
||||
}
|
||||
})
|
||||
|
||||
const schemas = {}
|
||||
for (const match of matches) {
|
||||
if (!schemas.hasOwnProperty(match.schema)) {
|
||||
schemas[match.schema] = []
|
||||
}
|
||||
schemas[match.schema].push(match.referencedSchema)
|
||||
}
|
||||
return schemas
|
||||
}
|
||||
|
||||
export const formatHintRecommendation = (
|
||||
recommendation: Record<string, string[]>
|
||||
) => {
|
||||
return jsonObjectToYamlString({
|
||||
decorators: { "medusa/circular-patch": { schemas: recommendation } },
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import { OpenAPIObject } from "openapi3-ts"
|
||||
import { upperFirst } from "lodash"
|
||||
|
||||
export async function combineOAS(
|
||||
adminOAS: OpenAPIObject,
|
||||
storeOAS: OpenAPIObject
|
||||
): Promise<OpenAPIObject> {
|
||||
prepareOASForCombine(adminOAS, "admin")
|
||||
prepareOASForCombine(storeOAS, "store")
|
||||
|
||||
const combinedOAS: OpenAPIObject = {
|
||||
openapi: "3.0.0",
|
||||
info: { title: "Medusa API", version: "1.0.0" },
|
||||
servers: [],
|
||||
paths: {},
|
||||
tags: [],
|
||||
components: {
|
||||
callbacks: {},
|
||||
examples: {},
|
||||
headers: {},
|
||||
links: {},
|
||||
parameters: {},
|
||||
requestBodies: {},
|
||||
responses: {},
|
||||
schemas: {},
|
||||
securitySchemes: {},
|
||||
},
|
||||
}
|
||||
|
||||
for (const oas of [adminOAS, storeOAS]) {
|
||||
/**
|
||||
* Combine paths
|
||||
*/
|
||||
Object.assign(combinedOAS.paths, oas.paths)
|
||||
/**
|
||||
* Combine tags
|
||||
*/
|
||||
if (oas.tags) {
|
||||
combinedOAS.tags = [...combinedOAS.tags!, ...oas.tags]
|
||||
}
|
||||
/**
|
||||
* Combine components
|
||||
*/
|
||||
if (oas.components) {
|
||||
for (const componentGroup of [
|
||||
"callbacks",
|
||||
"examples",
|
||||
"headers",
|
||||
"links",
|
||||
"parameters",
|
||||
"requestBodies",
|
||||
"responses",
|
||||
"schemas",
|
||||
"securitySchemes",
|
||||
]) {
|
||||
if (Object.keys(oas.components).includes(componentGroup)) {
|
||||
Object.assign(
|
||||
combinedOAS.components![componentGroup],
|
||||
oas.components[componentGroup]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return combinedOAS
|
||||
}
|
||||
|
||||
function prepareOASForCombine(
|
||||
oas: OpenAPIObject,
|
||||
apiType: ApiType
|
||||
): OpenAPIObject {
|
||||
console.log(
|
||||
`🔵 Prefixing ${apiType} tags and operationId with ${upperFirst(apiType)}`
|
||||
)
|
||||
for (const pathKey in oas.paths) {
|
||||
for (const operationKey in oas.paths[pathKey]) {
|
||||
/**
|
||||
* Prefix tags declared on routes
|
||||
* e.g.: Admin Customer, Store Customer
|
||||
*/
|
||||
if (oas.paths[pathKey][operationKey].tags) {
|
||||
oas.paths[pathKey][operationKey].tags = oas.paths[pathKey][
|
||||
operationKey
|
||||
].tags.map((tag) => getPrefixedTagName(tag, apiType))
|
||||
}
|
||||
/**
|
||||
* Prefix operationId
|
||||
* e.g.: AdminGetCustomers, StoreGetCustomers
|
||||
*/
|
||||
if (oas.paths[pathKey][operationKey].operationId) {
|
||||
oas.paths[pathKey][operationKey].operationId = getPrefixedOperationId(
|
||||
oas.paths[pathKey][operationKey].operationId,
|
||||
apiType
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefix tags globally
|
||||
* e.g.: Admin Customer, Store Customer
|
||||
*/
|
||||
if (oas.tags) {
|
||||
for (const tag of oas.tags) {
|
||||
tag.name = getPrefixedTagName(tag.name, apiType)
|
||||
}
|
||||
}
|
||||
return oas
|
||||
}
|
||||
|
||||
function getPrefixedTagName(tagName: string, apiType: ApiType): string {
|
||||
return `${upperFirst(apiType)} ${tagName}`
|
||||
}
|
||||
|
||||
function getPrefixedOperationId(operationId: string, apiType: ApiType): string {
|
||||
return `${upperFirst(apiType)}${operationId}`
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { access, lstat, mkdtemp } from "fs/promises"
|
||||
import path from "path"
|
||||
import { sep } from "path"
|
||||
import { tmpdir } from "os"
|
||||
|
||||
export async function isFile(filePath: string): Promise<boolean> {
|
||||
try {
|
||||
return (await lstat(path.resolve(filePath))).isFile()
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export async function exists(filePath: string): Promise<boolean> {
|
||||
try {
|
||||
await access(path.resolve(filePath))
|
||||
return true
|
||||
} catch (err) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export const getTmpDirectory = async () => {
|
||||
/**
|
||||
* RUNNER_TEMP: GitHub action, the path to a temporary directory on the runner.
|
||||
*/
|
||||
const tmpDir = process.env["RUNNER_TEMP"] ?? tmpdir()
|
||||
return await mkdtemp(`${tmpDir}${sep}`)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import fs from "fs/promises"
|
||||
|
||||
export const readJson = async (filePath: string): Promise<unknown> => {
|
||||
const jsonString = await fs.readFile(filePath, "utf8")
|
||||
return JSON.parse(jsonString)
|
||||
}
|
||||
|
||||
export const writeJson = async (
|
||||
filePath: string,
|
||||
jsonObject: unknown
|
||||
): Promise<void> => {
|
||||
const jsonString = JSON.stringify(jsonObject)
|
||||
await fs.writeFile(filePath, jsonString, "utf8")
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { OpenAPIObject, TagObject } from "openapi3-ts"
|
||||
|
||||
export function mergeBaseIntoOAS(
|
||||
targetOAS: OpenAPIObject,
|
||||
sourceOAS: OpenAPIObject
|
||||
): void {
|
||||
/**
|
||||
* replace strategy for OpenAPIObject properties
|
||||
*/
|
||||
targetOAS.openapi = sourceOAS.openapi ?? targetOAS.openapi
|
||||
targetOAS.info = sourceOAS.info ?? targetOAS.info
|
||||
targetOAS.servers = sourceOAS.servers ?? targetOAS.servers
|
||||
targetOAS.security = sourceOAS.security ?? targetOAS.security
|
||||
targetOAS.externalDocs = sourceOAS.externalDocs ?? targetOAS.externalDocs
|
||||
targetOAS.webhooks = sourceOAS.webhooks ?? targetOAS.webhooks
|
||||
/**
|
||||
* merge + concat strategy for tags
|
||||
*/
|
||||
const targetTags = targetOAS.tags ?? []
|
||||
const sourceTags = sourceOAS.tags ?? []
|
||||
const combinedTags: TagObject[] = []
|
||||
const sourceIndexes: number[] = []
|
||||
for (const targetTag of targetTags) {
|
||||
for (const [sourceTagIndex, sourceTag] of sourceTags.entries()) {
|
||||
if (targetTag.name === sourceTag.name) {
|
||||
combinedTags.push(sourceTag)
|
||||
sourceIndexes.push(sourceTagIndex)
|
||||
continue
|
||||
}
|
||||
combinedTags.push(targetTag)
|
||||
}
|
||||
}
|
||||
for (const [sourceTagIndex, sourceTag] of sourceTags.entries()) {
|
||||
if (!sourceIndexes.includes(sourceTagIndex)) {
|
||||
combinedTags.push(sourceTag)
|
||||
}
|
||||
}
|
||||
targetOAS.tags = combinedTags
|
||||
/**
|
||||
* merge strategy for paths
|
||||
*/
|
||||
targetOAS.paths = Object.assign(targetOAS.paths ?? {}, sourceOAS.paths ?? {})
|
||||
/**
|
||||
* merge strategy for components
|
||||
*/
|
||||
if (!sourceOAS.components) {
|
||||
return
|
||||
}
|
||||
if (!targetOAS.components) {
|
||||
targetOAS.components = {}
|
||||
}
|
||||
for (const componentGroup of [
|
||||
"callbacks",
|
||||
"examples",
|
||||
"headers",
|
||||
"links",
|
||||
"parameters",
|
||||
"requestBodies",
|
||||
"responses",
|
||||
"schemas",
|
||||
"securitySchemes",
|
||||
]) {
|
||||
if (Object.keys(sourceOAS.components).includes(componentGroup)) {
|
||||
targetOAS.components[componentGroup] = Object.assign(
|
||||
targetOAS.components[componentGroup] ?? {},
|
||||
sourceOAS.components[componentGroup]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function mergePathsAndSchemasIntoOAS(
|
||||
targetOAS: OpenAPIObject,
|
||||
sourceOAS: OpenAPIObject
|
||||
): void {
|
||||
/**
|
||||
* merge paths
|
||||
*/
|
||||
Object.assign(targetOAS.paths, sourceOAS.paths)
|
||||
|
||||
/**
|
||||
* merge components.schemas
|
||||
*/
|
||||
if (sourceOAS.components?.schemas) {
|
||||
if (!targetOAS.components) {
|
||||
targetOAS.components = {}
|
||||
}
|
||||
if (!targetOAS.components.schemas) {
|
||||
targetOAS.components.schemas = {}
|
||||
}
|
||||
Object.assign(targetOAS.components.schemas, sourceOAS.components.schemas)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import fs from "fs/promises"
|
||||
import * as yaml from "js-yaml"
|
||||
|
||||
export const readYaml = async (filePath): Promise<unknown> => {
|
||||
const yamlString = await fs.readFile(filePath, "utf8")
|
||||
return yaml.load(yamlString)
|
||||
}
|
||||
|
||||
export const writeYaml = async (filePath: string, yamlContent: string): Promise<void> => {
|
||||
await fs.writeFile(filePath, yamlContent, "utf8")
|
||||
}
|
||||
|
||||
export const writeYamlFromJson = async (filePath, jsonObject): Promise<void> => {
|
||||
const yamlString = yaml.dump(jsonObject)
|
||||
await fs.writeFile(filePath, yamlString, "utf8")
|
||||
}
|
||||
|
||||
export const jsonObjectToYamlString = (jsonObject): string => {
|
||||
return yaml.dump(jsonObject)
|
||||
}
|
||||
|
||||
export const jsonFileToYamlFile = async (inputJsonFile, outputYamlFile) => {
|
||||
const jsonString = await fs.readFile(inputJsonFile, "utf8")
|
||||
const jsonObject = JSON.parse(jsonString)
|
||||
const yamlString = yaml.dump(jsonObject)
|
||||
await fs.writeFile(outputYamlFile, yamlString, "utf8")
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"es2019"
|
||||
],
|
||||
"target": "es2019",
|
||||
"outDir": "./dist",
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitReturns": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noImplicitThis": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"downlevelIteration": true // to use ES5 specific tooling
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"dist",
|
||||
"src/**/__tests__",
|
||||
"src/**/__mocks__",
|
||||
"src/**/__fixtures__",
|
||||
"node_modules"
|
||||
],
|
||||
"ts-node": {
|
||||
"transpileOnly": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/dist
|
||||
node_modules
|
||||
.DS_store
|
||||
.env*
|
||||
.env
|
||||
*.sql
|
||||
@@ -0,0 +1,279 @@
|
||||
# @medusajs/oas-github-ci
|
||||
|
||||
## 1.0.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6812](https://github.com/medusajs/medusa/pull/6812) [`e005987adf`](https://github.com/medusajs/medusa/commit/e005987adf2a2dd8c2748e7abc360cc93e7c05ad) Thanks [@shahednasser](https://github.com/shahednasser)! - fix(medusa-oas-cli): fix tool not working in Medusa backends
|
||||
|
||||
- Updated dependencies [[`e005987adf`](https://github.com/medusajs/medusa/commit/e005987adf2a2dd8c2748e7abc360cc93e7c05ad)]:
|
||||
- @medusajs/medusa-oas-cli@0.3.2
|
||||
|
||||
## 1.0.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6338](https://github.com/medusajs/medusa/pull/6338) [`374a3f4dab`](https://github.com/medusajs/medusa/commit/374a3f4dab7bf893ba3c579fa7f9c346fa30ad64) Thanks [@shahednasser](https://github.com/shahednasser)! - feat(@medusajs/medusa-oas-cli): added v2 flag
|
||||
feat(@medusajs/oas-github-ci): added v2 flag
|
||||
|
||||
- [#6710](https://github.com/medusajs/medusa/pull/6710) [`bb87db8342`](https://github.com/medusajs/medusa/commit/bb87db83424e2625e273fd5cf06cece37245b6da) Thanks [@shahednasser](https://github.com/shahednasser)! - feat(oas-github-ci): output specs into `specs-v2` directory when the `--v2` option is passed
|
||||
|
||||
- Updated dependencies [[`374a3f4dab`](https://github.com/medusajs/medusa/commit/374a3f4dab7bf893ba3c579fa7f9c346fa30ad64)]:
|
||||
- @medusajs/medusa-oas-cli@0.3.1
|
||||
|
||||
## 1.0.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`e84847be3`](https://github.com/medusajs/medusa/commit/e84847be36c88c5bd8e49e1e8aca734ce941a7c2)]:
|
||||
- @medusajs/medusa-oas-cli@0.3.0
|
||||
|
||||
## 1.0.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.24
|
||||
|
||||
## 1.0.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5453](https://github.com/medusajs/medusa/pull/5453) [`c1b97050a`](https://github.com/medusajs/medusa/commit/c1b97050ab801c6b5702311f777ebd7f98080a97) Thanks [@shahednasser](https://github.com/shahednasser)! - feat(medusa-oas-cli): Added `--main-file-name` option to specify output file name
|
||||
feat(oas-github-ci): Added `--with-full-file"` option to output both split and full files
|
||||
- Updated dependencies [[`c1b97050a`](https://github.com/medusajs/medusa/commit/c1b97050ab801c6b5702311f777ebd7f98080a97)]:
|
||||
- @medusajs/medusa-oas-cli@0.2.23
|
||||
|
||||
## 1.0.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.22
|
||||
|
||||
## 1.0.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.21
|
||||
|
||||
## 1.0.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5174](https://github.com/medusajs/medusa/pull/5174) [`fa7c94b4c`](https://github.com/medusajs/medusa/commit/fa7c94b4ccf864d7a6c7ed4bba26b7086ed99b2f) Thanks [@shahednasser](https://github.com/shahednasser)! - feat(@medusajs/oas-github-ci): changed output path to match new docs workspace
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.20
|
||||
|
||||
## 1.0.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.19
|
||||
|
||||
## 1.0.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.18
|
||||
|
||||
## 1.0.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.17
|
||||
|
||||
## 1.0.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.16
|
||||
|
||||
## 1.0.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#4770](https://github.com/medusajs/medusa/pull/4770) [`914d773d3`](https://github.com/medusajs/medusa/commit/914d773d3a82c86685b66c0c33ab1d7a9bad7dd4) Thanks [@shahednasser](https://github.com/shahednasser)! - feat(@medusajs/oas-github-ci): Improvements for custom API reference
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.15
|
||||
|
||||
## 1.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.14
|
||||
|
||||
## 1.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.13
|
||||
|
||||
## 1.0.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.12
|
||||
|
||||
## 1.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.11
|
||||
|
||||
## 1.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.10
|
||||
|
||||
## 1.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.9
|
||||
|
||||
## 1.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.8
|
||||
|
||||
## 1.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.7
|
||||
|
||||
## 1.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`cfcd2d54f`](https://github.com/medusajs/medusa/commit/cfcd2d54fd281fd98de881fc6dfbcc6b1b47c855)]:
|
||||
- @medusajs/medusa-oas-cli@0.2.6
|
||||
|
||||
## 1.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.5
|
||||
|
||||
## 1.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.4
|
||||
|
||||
## 1.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.3
|
||||
|
||||
## 1.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`1456056e8`](https://github.com/medusajs/medusa/commit/1456056e8f9d48cc1cb64c1836a6de5d5b263b05)]:
|
||||
- @medusajs/medusa-oas-cli@0.2.2
|
||||
|
||||
## 1.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.1
|
||||
|
||||
## 1.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3410](https://github.com/medusajs/medusa/pull/3410) [`8ed67d2d7`](https://github.com/medusajs/medusa/commit/8ed67d2d7d36da2d0cb3541e42bba1770aefc60a) Thanks [@olivermrbl](https://github.com/olivermrbl)! - fix(admin,oas-github-cli): Change public config to private to avoid publishing attempts + include `setup/` in npm release for `admin-ui`
|
||||
|
||||
- Updated dependencies [[`813706190`](https://github.com/medusajs/medusa/commit/8137061908d20314314b95d049b966a624e7123d), [`377b9ce8c`](https://github.com/medusajs/medusa/commit/377b9ce8c27cb2c4d10d154c005c7553c173c0e8), [`1c40346e9`](https://github.com/medusajs/medusa/commit/1c40346e9e56718de4a6e2d5c2d52abd388343e3), [`53c4a43ca`](https://github.com/medusajs/medusa/commit/53c4a43ca2b2c04920dc6f38e07348e7dfc23195), [`966aea65c`](https://github.com/medusajs/medusa/commit/966aea65c221403bf316ae7665cc8f73bccd9c38)]:
|
||||
- @medusajs/medusa-oas-cli@0.2.0
|
||||
|
||||
## 1.0.1-rc.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.0-rc.8
|
||||
|
||||
## 1.0.1-rc.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.0-rc.7
|
||||
|
||||
## 1.0.1-rc.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.0-rc.6
|
||||
|
||||
## 1.0.1-rc.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.0-rc.5
|
||||
|
||||
## 1.0.1-rc.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`377b9ce8c`](https://github.com/medusajs/medusa/commit/377b9ce8c27cb2c4d10d154c005c7553c173c0e8)]:
|
||||
- @medusajs/medusa-oas-cli@0.2.0-rc.4
|
||||
|
||||
## 1.0.1-rc.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.0-rc.3
|
||||
|
||||
## 1.0.1-rc.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @medusajs/medusa-oas-cli@0.2.0-rc.2
|
||||
|
||||
## 1.0.1-rc.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`53c4a43ca`](https://github.com/medusajs/medusa/commit/53c4a43ca2b2c04920dc6f38e07348e7dfc23195)]:
|
||||
- @medusajs/medusa-oas-cli@0.2.0-rc.1
|
||||
|
||||
## 1.0.1-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3410](https://github.com/medusajs/medusa/pull/3410) [`8ed67d2d7`](https://github.com/medusajs/medusa/commit/8ed67d2d7d36da2d0cb3541e42bba1770aefc60a) Thanks [@olivermrbl](https://github.com/olivermrbl)! - fix(admin,oas-github-cli): Change public config to private to avoid publishing attempts + include `setup/` in npm release for `admin-ui`
|
||||
|
||||
- Updated dependencies [[`813706190`](https://github.com/medusajs/medusa/commit/8137061908d20314314b95d049b966a624e7123d), [`1c40346e9`](https://github.com/medusajs/medusa/commit/1c40346e9e56718de4a6e2d5c2d52abd388343e3), [`966aea65c`](https://github.com/medusajs/medusa/commit/966aea65c221403bf316ae7665cc8f73bccd9c38)]:
|
||||
- @medusajs/medusa-oas-cli@0.2.0-rc.0
|
||||
|
||||
## 1.0.0
|
||||
@@ -0,0 +1,3 @@
|
||||
# oas-github-ci - 1.0.0
|
||||
|
||||
Script used in CI for validating OAS documentation.
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "@medusajs/oas-github-ci",
|
||||
"version": "1.0.27",
|
||||
"description": "OAS Github CI",
|
||||
"main": "scripts/build-openapi.js",
|
||||
"files": [
|
||||
"scripts"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/medusajs/medusa",
|
||||
"directory": "packages/oas/oas-github-ci"
|
||||
},
|
||||
"private": true,
|
||||
"author": "Medusa",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"ci": "node scripts/build-openapi.js",
|
||||
"preview:admin": "yarn medusa-oas docs --src-file ../../../docs/api/admin/openapi.yaml --preview",
|
||||
"preview:store": "yarn medusa-oas docs --src-file ../../../docs/api/store/openapi.yaml --preview",
|
||||
"test": "jest --passWithNoTests"
|
||||
},
|
||||
"dependencies": {
|
||||
"@medusajs/medusa-oas-cli": "0.3.2",
|
||||
"execa": "^5.1.1"
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("fs/promises")
|
||||
const os = require("os")
|
||||
const path = require("path")
|
||||
const execa = require("execa")
|
||||
|
||||
const isDryRun = process.argv.indexOf("--dry-run") !== -1
|
||||
const withFullFile = process.argv.indexOf("--with-full-file") !== -1
|
||||
const v2 = process.argv.indexOf("--v2") !== -1
|
||||
const basePath = path.resolve(__dirname, `../`)
|
||||
const repoRootPath = path.resolve(basePath, `../../../`)
|
||||
const docsApiPath = v2 ? path.resolve(repoRootPath, "www/apps/api-reference/specs-v2") :
|
||||
path.resolve(repoRootPath, "www/apps/api-reference/specs")
|
||||
|
||||
const run = async () => {
|
||||
const oasOutDir = isDryRun ? await getTmpDirectory() : docsApiPath
|
||||
for (const apiType of ["store", "admin"]) {
|
||||
await generateOASSource(oasOutDir, apiType)
|
||||
const oasSrcFile = path.resolve(oasOutDir, `${apiType}.oas.json`)
|
||||
const docsOutDir = path.resolve(oasOutDir, apiType)
|
||||
await generateDocs(oasSrcFile, docsOutDir, isDryRun)
|
||||
}
|
||||
}
|
||||
|
||||
const generateOASSource = async (outDir, apiType) => {
|
||||
const commandParams = ["oas", `--type=${apiType}`, `--out-dir=${outDir}`, "--local"]
|
||||
if (v2) {
|
||||
commandParams.push(`--v2`)
|
||||
}
|
||||
const { all: logs } = await execa(
|
||||
"medusa-oas",
|
||||
commandParams,
|
||||
{ cwd: basePath, all: true }
|
||||
)
|
||||
console.log(logs)
|
||||
}
|
||||
|
||||
const generateDocs = async (srcFile, outDir, isDryRun) => {
|
||||
let params = [
|
||||
"docs",
|
||||
`--src-file=${srcFile}`,
|
||||
`--out-dir=${outDir}`,
|
||||
`--clean`,
|
||||
`--split`,
|
||||
]
|
||||
if (isDryRun) {
|
||||
params.push("--dry-run")
|
||||
}
|
||||
await runMedusaOasCommand(params)
|
||||
if (withFullFile && !isDryRun) {
|
||||
console.log("Generating full file...")
|
||||
params = [
|
||||
"docs",
|
||||
`--src-file=${srcFile}`,
|
||||
`--out-dir=${outDir}`,
|
||||
`--main-file-name=openapi.full.yaml`
|
||||
]
|
||||
await runMedusaOasCommand(params)
|
||||
console.log("Finished generating full file.")
|
||||
}
|
||||
}
|
||||
|
||||
const runMedusaOasCommand = async (params) => {
|
||||
const { all: logs } = await execa("medusa-oas", params, {
|
||||
cwd: basePath,
|
||||
all: true,
|
||||
})
|
||||
console.log(logs)
|
||||
}
|
||||
|
||||
const getTmpDirectory = async () => {
|
||||
/**
|
||||
* RUNNER_TEMP: GitHub action, the path to a temporary directory on the runner.
|
||||
*/
|
||||
const tmpDir = process.env["RUNNER_TEMP"] ?? os.tmpdir()
|
||||
return await fs.mkdtemp(tmpDir)
|
||||
}
|
||||
|
||||
void (async () => {
|
||||
try {
|
||||
await run()
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
process.exit(1)
|
||||
}
|
||||
})()
|
||||
@@ -0,0 +1,7 @@
|
||||
/dist
|
||||
node_modules
|
||||
.DS_store
|
||||
.env*
|
||||
.env
|
||||
*.sql
|
||||
/bin
|
||||
@@ -0,0 +1 @@
|
||||
*.hbs
|
||||
@@ -0,0 +1,33 @@
|
||||
# @medusajs/openapi-typescript-codegen
|
||||
|
||||
## 0.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3675](https://github.com/medusajs/medusa/pull/3675) [`0b3c6fde3`](https://github.com/medusajs/medusa/commit/0b3c6fde30c9bac052a8e1aa641ef925b6937c0e) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(codegen:test): coverage x-expanded-relation + x-codegen.queryParams
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#3477](https://github.com/medusajs/medusa/pull/3477) [`826d4bedf`](https://github.com/medusajs/medusa/commit/826d4bedfe1b6459163711d5173eb8eadfdea26e) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(codegen,types): SetRelation on expanded types
|
||||
|
||||
- [#3442](https://github.com/medusajs/medusa/pull/3442) [`7b57695e0`](https://github.com/medusajs/medusa/commit/7b57695e00433e1d54f8cdc912ef7e5f28fc1071) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(codegen): x-expanded-relations
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3272](https://github.com/medusajs/medusa/pull/3272) [`1c40346e9`](https://github.com/medusajs/medusa/commit/1c40346e9e56718de4a6e2d5c2d52abd388343e3) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(codegen): openapi-typescript-codegen fork
|
||||
|
||||
## 0.2.0-rc.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#3477](https://github.com/medusajs/medusa/pull/3477) [`826d4bedf`](https://github.com/medusajs/medusa/commit/826d4bedfe1b6459163711d5173eb8eadfdea26e) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(codegen,types): SetRelation on expanded types
|
||||
|
||||
- [#3442](https://github.com/medusajs/medusa/pull/3442) [`7b57695e0`](https://github.com/medusajs/medusa/commit/7b57695e00433e1d54f8cdc912ef7e5f28fc1071) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(codegen): x-expanded-relations
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3272](https://github.com/medusajs/medusa/pull/3272) [`1c40346e9`](https://github.com/medusajs/medusa/commit/1c40346e9e56718de4a6e2d5c2d52abd388343e3) Thanks [@patrick-medusajs](https://github.com/patrick-medusajs)! - feat(codegen): openapi-typescript-codegen fork
|
||||
|
||||
## 0.1.0
|
||||
@@ -0,0 +1,39 @@
|
||||
# OpenAPI Typescript Codegen - 0.1.0 - experimental
|
||||
|
||||
Node.js library that generates Typescript clients based on the OpenAPI specification.
|
||||
|
||||
## About this fork
|
||||
|
||||
This package is a significantly customized fork of
|
||||
the amazing npm [openapi-typescript-codegen](https://github.com/ferdikoomen/openapi-typescript-codegen) package 💜.
|
||||
|
||||
### Brief reasoning
|
||||
|
||||
We wanted a level of customization that was not achievable through the source package's interface.
|
||||
We started with a conventional fork but the development workflow was hindering our ability to iterate quickly.
|
||||
We decided to fold the package within our monorepo to hopefully accelerate development and innovation.
|
||||
|
||||
### Noteworthy differences
|
||||
|
||||
* Added ability to generate React hooks in the style of `medusa-react`.
|
||||
* Added access to the raw OAS on parsed element from the parser.
|
||||
* Added access `operationId` from path.
|
||||
* Added access `x-codegen` from path.
|
||||
* Added renaming of service method when `x-codegen.method` is declared.
|
||||
* Added bundling of query params into a typed object when `x-codegen.queryParams` is declared.
|
||||
* Added parameterization of import path for the client and models.
|
||||
* Added generated `index.ts` files in directories to simplify imports.
|
||||
* Updated npm dependencies' version to match existing versions found in the monorepo.
|
||||
* Updated coding style to match the convention of the monorepo.
|
||||
* Removed support for Angular client generation.
|
||||
* Removed support for OAS v2 parsing.
|
||||
* Removed documentation.
|
||||
* Removed tests (temporarily).
|
||||
|
||||
## Install
|
||||
|
||||
`yarn add --dev @medusajs/openapi-typescript-codegen`
|
||||
|
||||
## How to use
|
||||
|
||||
See `@medusajs/medusa-oas-cli` for usage.
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"node": "12"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"@babel/preset-typescript",
|
||||
{
|
||||
"onlyRemoveTypeImports": true
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
globals: {
|
||||
"ts-jest": {
|
||||
tsconfig: "tsconfig.json",
|
||||
isolatedModules: false,
|
||||
},
|
||||
},
|
||||
transform: {
|
||||
"^.+\\.[jt]s?$": "ts-jest",
|
||||
},
|
||||
testEnvironment: `node`,
|
||||
moduleFileExtensions: [`js`, `ts`],
|
||||
testTimeout: 30000,
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "@medusajs/openapi-typescript-codegen",
|
||||
"version": "0.2.1",
|
||||
"description": "Library that generates Typescript clients based on the OpenAPI specification.",
|
||||
"main": "dist/index.js",
|
||||
"types": "types/index.d.ts",
|
||||
"files": [
|
||||
"dist/index.js",
|
||||
"types/index.d.ts"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/medusajs/medusa",
|
||||
"directory": "packages/oas/openapi-typescript-codegen"
|
||||
},
|
||||
"author": "Medusa",
|
||||
"contributors": [
|
||||
"Ferdi Koomen"
|
||||
],
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"prepare": "cross-env NODE_ENV=production yarn run release",
|
||||
"build": "rollup --config --environment NODE_ENV:development",
|
||||
"release": "rollup --config --environment NODE_ENV:production",
|
||||
"test": "jest src --passWithNoTests"
|
||||
},
|
||||
"dependencies": {
|
||||
"camelcase": "^6.3.0",
|
||||
"commander": "^9.4.1",
|
||||
"fs-extra": "^10.1.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"json-schema-ref-parser": "^9.0.9",
|
||||
"pascalcase": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.14.3",
|
||||
"@babel/core": "7.14.3",
|
||||
"@babel/preset-env": "7.11.5",
|
||||
"@babel/preset-typescript": "7.18.6",
|
||||
"@rollup/plugin-commonjs": "24.0.0",
|
||||
"@rollup/plugin-node-resolve": "15.0.1",
|
||||
"@rollup/plugin-typescript": "9.0.2",
|
||||
"@types/fs-extra": "^9.0.12",
|
||||
"@types/jest": "27.5.0",
|
||||
"@types/node": "18.11.9",
|
||||
"@types/node-fetch": "2.6.2",
|
||||
"@types/pascalcase": "^1.0.1",
|
||||
"@types/qs": "6.9.7",
|
||||
"abort-controller": "3.0.0",
|
||||
"axios": "1.2.0",
|
||||
"form-data": "4.0.0",
|
||||
"jest": "^25.5.4",
|
||||
"node-fetch": "2.6.7",
|
||||
"qs": "6.10.3",
|
||||
"rollup": "3.9.1",
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
"ts-jest": "^25.5.1",
|
||||
"tslib": "2.3.1",
|
||||
"typescript": "4.9.5"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import commonjs from "@rollup/plugin-commonjs"
|
||||
import { nodeResolve } from "@rollup/plugin-node-resolve"
|
||||
import typescript from "@rollup/plugin-typescript"
|
||||
import { readFileSync } from "fs"
|
||||
import handlebars from "handlebars"
|
||||
import { dirname, extname, resolve } from "path"
|
||||
import { terser } from "rollup-plugin-terser"
|
||||
|
||||
const { precompile } = handlebars
|
||||
|
||||
/**
|
||||
* Custom plugin to parse handlebar imports and precompile
|
||||
* the template on the fly. This reduces runtime by about
|
||||
* half on large projects.
|
||||
*/
|
||||
const handlebarsPlugin = () => ({
|
||||
resolveId: (file, importer) => {
|
||||
if (extname(file) === ".hbs") {
|
||||
return resolve(dirname(importer), file)
|
||||
}
|
||||
return null
|
||||
},
|
||||
load: (file) => {
|
||||
if (extname(file) === ".hbs") {
|
||||
const template = readFileSync(file, "utf8").toString().trim()
|
||||
const templateSpec = precompile(template, {
|
||||
strict: true,
|
||||
noEscape: true,
|
||||
preventIndent: true,
|
||||
knownHelpersOnly: true,
|
||||
knownHelpers: {
|
||||
ifdef: true,
|
||||
equals: true,
|
||||
notEquals: true,
|
||||
containsSpaces: true,
|
||||
union: true,
|
||||
intersection: true,
|
||||
enumerator: true,
|
||||
escapeComment: true,
|
||||
escapeDescription: true,
|
||||
camelCase: true,
|
||||
pascalCase: true,
|
||||
},
|
||||
})
|
||||
return `export default ${templateSpec};`
|
||||
}
|
||||
return null
|
||||
},
|
||||
})
|
||||
|
||||
const getPlugins = () => {
|
||||
const plugins = [
|
||||
nodeResolve(),
|
||||
commonjs({
|
||||
sourceMap: false,
|
||||
}),
|
||||
handlebarsPlugin(),
|
||||
typescript({
|
||||
module: "esnext",
|
||||
}),
|
||||
]
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
return plugins
|
||||
}
|
||||
return [...plugins, terser()]
|
||||
}
|
||||
|
||||
export default {
|
||||
input: "./src/index.ts",
|
||||
output: {
|
||||
exports: "named",
|
||||
file: "./dist/index.js",
|
||||
format: "cjs",
|
||||
},
|
||||
external: [
|
||||
"camelcase",
|
||||
"commander",
|
||||
"fs-extra",
|
||||
"handlebars",
|
||||
"json-schema-ref-parser",
|
||||
],
|
||||
plugins: getPlugins(),
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export enum HttpClient {
|
||||
FETCH = "fetch",
|
||||
XHR = "xhr",
|
||||
NODE = "node",
|
||||
AXIOS = "axios",
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export enum Indent {
|
||||
SPACE_4 = "4",
|
||||
SPACE_2 = "2",
|
||||
TAB = "tab",
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { Model } from "./Model"
|
||||
import type { Service } from "./Service"
|
||||
|
||||
export interface Client {
|
||||
version: string
|
||||
server: string
|
||||
models: Model[]
|
||||
services: Service[]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface Enum {
|
||||
name: string
|
||||
value: string
|
||||
type: string
|
||||
description: string | null
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { Enum } from "./Enum"
|
||||
import type { Schema } from "./Schema"
|
||||
|
||||
export type NestedRelation = {
|
||||
field: string
|
||||
nestedRelations: NestedRelation[]
|
||||
base?: string
|
||||
isArray?: boolean
|
||||
hasDepth?: boolean
|
||||
}
|
||||
|
||||
export interface Model extends Schema {
|
||||
name: string
|
||||
export:
|
||||
| "reference"
|
||||
| "generic"
|
||||
| "enum"
|
||||
| "array"
|
||||
| "dictionary"
|
||||
| "interface"
|
||||
| "one-of"
|
||||
| "any-of"
|
||||
| "all-of"
|
||||
type: string
|
||||
base: string
|
||||
template: string | null
|
||||
link: Model | null
|
||||
description: string | null
|
||||
deprecated?: boolean
|
||||
default?: string
|
||||
imports: string[]
|
||||
enum: Enum[]
|
||||
enums: Model[]
|
||||
properties: Model[]
|
||||
nestedRelations?: NestedRelation[]
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import type { Model } from "./Model"
|
||||
|
||||
export interface ModelComposition {
|
||||
type: "one-of" | "any-of" | "all-of"
|
||||
imports: string[]
|
||||
enums: Model[]
|
||||
properties: Model[]
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import type { OperationError } from "./OperationError"
|
||||
import type { OperationParameters } from "./OperationParameters"
|
||||
import type { OperationResponse } from "./OperationResponse"
|
||||
import type { OperationCodegen } from "./OperationCodegen"
|
||||
|
||||
export interface Operation extends OperationParameters {
|
||||
service: string
|
||||
name: string
|
||||
operationId: string | null
|
||||
summary: string | null
|
||||
description: string | null
|
||||
deprecated: boolean
|
||||
method: string
|
||||
path: string
|
||||
errors: OperationError[]
|
||||
results: OperationResponse[]
|
||||
responseHeader: string | null
|
||||
codegen: OperationCodegen
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export interface OperationCodegen {
|
||||
method?: string
|
||||
queryParams?: string
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export interface OperationError {
|
||||
code: number
|
||||
description: string
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import type { Model } from "./Model"
|
||||
import { OpenApiParameter } from "../../openApi/v3/interfaces/OpenApiParameter"
|
||||
import { OpenApiRequestBody } from "../../openApi/v3/interfaces/OpenApiRequestBody"
|
||||
|
||||
export interface OperationParameter extends Model {
|
||||
spec: OpenApiParameter | OpenApiRequestBody
|
||||
in: "path" | "query" | "header" | "formData" | "body" | "cookie"
|
||||
prop: string
|
||||
mediaType: string | null
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import type { OperationParameter } from "./OperationParameter"
|
||||
|
||||
export interface OperationParameters {
|
||||
imports: string[]
|
||||
parameters: OperationParameter[]
|
||||
parametersPath: OperationParameter[]
|
||||
parametersQuery: OperationParameter[]
|
||||
parametersForm: OperationParameter[]
|
||||
parametersCookie: OperationParameter[]
|
||||
parametersHeader: OperationParameter[]
|
||||
parametersBody: OperationParameter | null
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import type { Model } from "./Model"
|
||||
import { OpenApiResponse } from "../../openApi/v3/interfaces/OpenApiResponse"
|
||||
|
||||
export interface OperationResponse extends Model {
|
||||
spec: OpenApiResponse
|
||||
in: "response" | "header"
|
||||
code: number
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import { OpenApiSchema } from "../../openApi/v3/interfaces/OpenApiSchema"
|
||||
|
||||
export interface Schema {
|
||||
spec: OpenApiSchema
|
||||
isDefinition: boolean
|
||||
isReadOnly: boolean
|
||||
isRequired: boolean
|
||||
isNullable: boolean
|
||||
format?:
|
||||
| "int32"
|
||||
| "int64"
|
||||
| "float"
|
||||
| "double"
|
||||
| "string"
|
||||
| "boolean"
|
||||
| "byte"
|
||||
| "binary"
|
||||
| "date"
|
||||
| "date-time"
|
||||
| "password"
|
||||
maximum?: number
|
||||
exclusiveMaximum?: boolean
|
||||
minimum?: number
|
||||
exclusiveMinimum?: boolean
|
||||
multipleOf?: number
|
||||
maxLength?: number
|
||||
minLength?: number
|
||||
pattern?: string
|
||||
maxItems?: number
|
||||
minItems?: number
|
||||
uniqueItems?: boolean
|
||||
maxProperties?: number
|
||||
minProperties?: number
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import type { Operation } from "./Operation"
|
||||
|
||||
export interface Service {
|
||||
name: string
|
||||
operations: Operation[]
|
||||
imports: string[]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface Type {
|
||||
type: string
|
||||
base: string
|
||||
template: string | null
|
||||
imports: string[]
|
||||
isNullable: boolean
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import { HttpClient } from "./HttpClient"
|
||||
import { Indent } from "./Indent"
|
||||
import { parse } from "./openApi/v3"
|
||||
import { getOpenApiSpec } from "./utils/getOpenApiSpec"
|
||||
import { getOpenApiVersion } from "./utils/getOpenApiVersion"
|
||||
import { isString } from "./utils/isString"
|
||||
import { postProcessClient } from "./utils/postProcessClient"
|
||||
import { registerHandlebarTemplates } from "./utils/registerHandlebarTemplates"
|
||||
import { writeClient } from "./utils/writeClient"
|
||||
|
||||
export { HttpClient } from "./HttpClient"
|
||||
export { Indent } from "./Indent"
|
||||
|
||||
export type PackageNames = {
|
||||
models?: string
|
||||
client?: string
|
||||
}
|
||||
|
||||
export type Options = {
|
||||
input: string | Record<string, any>
|
||||
output: string
|
||||
httpClient?: HttpClient
|
||||
clientName?: string
|
||||
useOptions?: boolean
|
||||
useUnionTypes?: boolean
|
||||
exportCore?: boolean
|
||||
exportServices?: boolean
|
||||
exportModels?: boolean
|
||||
exportHooks?: boolean
|
||||
exportSchemas?: boolean
|
||||
indent?: Indent
|
||||
packageNames?: PackageNames
|
||||
postfixServices?: string
|
||||
postfixModels?: string
|
||||
request?: string
|
||||
write?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the OpenAPI client. This method will read the OpenAPI specification and based on the
|
||||
* given language it will generate the client, including the typed models, validation schemas,
|
||||
* service layer, etc.
|
||||
* @param input The relative location of the OpenAPI spec
|
||||
* @param output The relative location of the output directory
|
||||
* @param httpClient The selected httpClient (fetch, xhr, node or axios)
|
||||
* @param clientName Custom client class name
|
||||
* @param useOptions Use options or arguments functions
|
||||
* @param useUnionTypes Use union types instead of enums
|
||||
* @param exportCore Generate core client classes
|
||||
* @param exportServices Generate services
|
||||
* @param exportModels Generate models
|
||||
* @param exportHooks Generate hooks
|
||||
* @param exportSchemas Generate schemas
|
||||
* @param indent Indentation options (4, 2 or tab)
|
||||
* @param packageNames Package name to use in import statements.
|
||||
* @param postfixServices Service name postfix
|
||||
* @param postfixModels Model name postfix
|
||||
* @param request Path to custom request file
|
||||
* @param write Write the files to disk (true or false)
|
||||
*/
|
||||
export const generate = async ({
|
||||
input,
|
||||
output,
|
||||
httpClient = HttpClient.FETCH,
|
||||
clientName,
|
||||
useOptions = false,
|
||||
useUnionTypes = false,
|
||||
exportCore = true,
|
||||
exportServices = true,
|
||||
exportModels = true,
|
||||
exportHooks = true,
|
||||
exportSchemas = false,
|
||||
indent = Indent.SPACE_4,
|
||||
packageNames = {},
|
||||
postfixServices = "Service",
|
||||
postfixModels = "",
|
||||
request,
|
||||
write = true,
|
||||
}: Options): Promise<void> => {
|
||||
const openApi = isString(input) ? await getOpenApiSpec(input) : input
|
||||
const openApiVersion = getOpenApiVersion(openApi)
|
||||
const templates = registerHandlebarTemplates({
|
||||
httpClient,
|
||||
useUnionTypes,
|
||||
useOptions,
|
||||
})
|
||||
|
||||
const client = parse(openApi)
|
||||
const clientFinal = postProcessClient(client)
|
||||
if (write) {
|
||||
await writeClient(
|
||||
clientFinal,
|
||||
templates,
|
||||
output,
|
||||
httpClient,
|
||||
useOptions,
|
||||
useUnionTypes,
|
||||
exportCore,
|
||||
exportServices,
|
||||
exportModels,
|
||||
exportHooks,
|
||||
exportSchemas,
|
||||
indent,
|
||||
packageNames,
|
||||
postfixServices,
|
||||
postfixModels,
|
||||
clientName,
|
||||
request
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
HttpClient,
|
||||
generate,
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { Client } from "../../client/interfaces/Client"
|
||||
import type { OpenApi } from "./interfaces/OpenApi"
|
||||
import { getModels } from "./parser/getModels"
|
||||
import { getServer } from "./parser/getServer"
|
||||
import { getServices } from "./parser/getServices"
|
||||
import { getServiceVersion } from "./parser/getServiceVersion"
|
||||
|
||||
/**
|
||||
* Parse the OpenAPI specification to a Client model that contains
|
||||
* all the models, services and schema's we should output.
|
||||
* @param openApi The OpenAPI spec that we have loaded from disk.
|
||||
*/
|
||||
export const parse = (openApi: OpenApi): Client => {
|
||||
const version = getServiceVersion(openApi.info.version)
|
||||
const server = getServer(openApi)
|
||||
const models = getModels(openApi)
|
||||
const services = getServices(openApi)
|
||||
|
||||
return { version, server, models, services }
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
export interface WithExtendedRelationsExtension {
|
||||
"x-expanded-relations"?: {
|
||||
field: string
|
||||
relations?: string[]
|
||||
totals?: string[]
|
||||
implicit?: string[]
|
||||
eager?: string[]
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export interface WithEnumExtension {
|
||||
"x-enum-varnames"?: string[]
|
||||
"x-enum-descriptions"?: string[]
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import type { OpenApiComponents } from "./OpenApiComponents"
|
||||
import type { OpenApiExternalDocs } from "./OpenApiExternalDocs"
|
||||
import type { OpenApiInfo } from "./OpenApiInfo"
|
||||
import type { OpenApiPaths } from "./OpenApiPaths"
|
||||
import type { OpenApiSecurityRequirement } from "./OpenApiSecurityRequirement"
|
||||
import type { OpenApiServer } from "./OpenApiServer"
|
||||
import type { OpenApiTag } from "./OpenApiTag"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md
|
||||
*/
|
||||
export interface OpenApi {
|
||||
openapi: string
|
||||
info: OpenApiInfo
|
||||
servers?: OpenApiServer[]
|
||||
paths: OpenApiPaths
|
||||
components?: OpenApiComponents
|
||||
security?: OpenApiSecurityRequirement[]
|
||||
tags?: OpenApiTag[]
|
||||
externalDocs?: OpenApiExternalDocs
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import type { OpenApiPath } from "./OpenApiPath"
|
||||
import type { OpenApiReference } from "./OpenApiReference"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#callbackObject
|
||||
*/
|
||||
export interface OpenApiCallback extends OpenApiReference {
|
||||
[key: string]: OpenApiPath
|
||||
}
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
import type { OpenApiCallback } from "./OpenApiCallback"
|
||||
import type { OpenApiExample } from "./OpenApiExample"
|
||||
import type { OpenApiHeader } from "./OpenApiHeader"
|
||||
import type { OpenApiLink } from "./OpenApiLink"
|
||||
import type { OpenApiParameter } from "./OpenApiParameter"
|
||||
import type { OpenApiRequestBody } from "./OpenApiRequestBody"
|
||||
import type { OpenApiResponses } from "./OpenApiResponses"
|
||||
import type { OpenApiSchema } from "./OpenApiSchema"
|
||||
import type { OpenApiSecurityScheme } from "./OpenApiSecurityScheme"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#componentsObject
|
||||
*/
|
||||
export interface OpenApiComponents {
|
||||
schemas?: Dictionary<OpenApiSchema>
|
||||
responses?: Dictionary<OpenApiResponses>
|
||||
parameters?: Dictionary<OpenApiParameter>
|
||||
examples?: Dictionary<OpenApiExample>
|
||||
requestBodies?: Dictionary<OpenApiRequestBody>
|
||||
headers?: Dictionary<OpenApiHeader>
|
||||
securitySchemes?: Dictionary<OpenApiSecurityScheme>
|
||||
links?: Dictionary<OpenApiLink>
|
||||
callbacks?: Dictionary<OpenApiCallback>
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#contactObject
|
||||
*/
|
||||
export interface OpenApiContact {
|
||||
name?: string
|
||||
url?: string
|
||||
email?: string
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#discriminatorObject
|
||||
*/
|
||||
export interface OpenApiDiscriminator {
|
||||
propertyName: string
|
||||
mapping?: Dictionary<string>
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
import type { OpenApiHeader } from "./OpenApiHeader"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#encodingObject
|
||||
*/
|
||||
export interface OpenApiEncoding {
|
||||
contentType?: string
|
||||
headers?: Dictionary<OpenApiHeader>
|
||||
style?: string
|
||||
explode?: boolean
|
||||
allowReserved?: boolean
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import type { OpenApiReference } from "./OpenApiReference"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#exampleObject
|
||||
*/
|
||||
export interface OpenApiExample extends OpenApiReference {
|
||||
summary?: string
|
||||
description?: string
|
||||
value?: any
|
||||
externalValue?: string
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#externalDocumentationObject
|
||||
*/
|
||||
export interface OpenApiExternalDocs {
|
||||
description?: string
|
||||
url: string
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
import type { OpenApiExample } from "./OpenApiExample"
|
||||
import type { OpenApiReference } from "./OpenApiReference"
|
||||
import type { OpenApiSchema } from "./OpenApiSchema"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#headerObject
|
||||
*/
|
||||
export interface OpenApiHeader extends OpenApiReference {
|
||||
description?: string
|
||||
required?: boolean
|
||||
deprecated?: boolean
|
||||
allowEmptyValue?: boolean
|
||||
style?: string
|
||||
explode?: boolean
|
||||
allowReserved?: boolean
|
||||
schema?: OpenApiSchema
|
||||
example?: any
|
||||
examples?: Dictionary<OpenApiExample>
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import type { OpenApiContact } from "./OpenApiContact"
|
||||
import type { OpenApiLicense } from "./OpenApiLicense"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#infoObject
|
||||
*/
|
||||
export interface OpenApiInfo {
|
||||
title: string
|
||||
description?: string
|
||||
termsOfService?: string
|
||||
contact?: OpenApiContact
|
||||
license?: OpenApiLicense
|
||||
version: string
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#licenseObject
|
||||
*/
|
||||
export interface OpenApiLicense {
|
||||
name: string
|
||||
url?: string
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
import type { OpenApiReference } from "./OpenApiReference"
|
||||
import type { OpenApiServer } from "./OpenApiServer"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#linkObject
|
||||
*/
|
||||
export interface OpenApiLink extends OpenApiReference {
|
||||
operationRef?: string
|
||||
operationId?: string
|
||||
parameters?: Dictionary<any>
|
||||
requestBody?: any
|
||||
description?: string
|
||||
server?: OpenApiServer
|
||||
}
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
import type { OpenApiEncoding } from "./OpenApiEncoding"
|
||||
import type { OpenApiExample } from "./OpenApiExample"
|
||||
import type { OpenApiReference } from "./OpenApiReference"
|
||||
import type { OpenApiSchema } from "./OpenApiSchema"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#mediaTypeObject
|
||||
*/
|
||||
export interface OpenApiMediaType extends OpenApiReference {
|
||||
schema?: OpenApiSchema
|
||||
example?: any
|
||||
examples?: Dictionary<OpenApiExample>
|
||||
encoding?: Dictionary<OpenApiEncoding>
|
||||
}
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#oauthFlowObject
|
||||
*/
|
||||
export interface OpenApiOAuthFlow {
|
||||
authorizationUrl: string
|
||||
tokenUrl: string
|
||||
refreshUrl?: string
|
||||
scopes: Dictionary<string>
|
||||
}
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
import type { OpenApiOAuthFlow } from "./OpenApiOAuthFlow"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#oauthFlowsObject
|
||||
*/
|
||||
export interface OpenApiOAuthFlows {
|
||||
implicit?: OpenApiOAuthFlow
|
||||
password?: OpenApiOAuthFlow
|
||||
clientCredentials?: OpenApiOAuthFlow
|
||||
authorizationCode?: OpenApiOAuthFlow
|
||||
}
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
import type { OpenApiCallback } from "./OpenApiCallback"
|
||||
import type { OpenApiExternalDocs } from "./OpenApiExternalDocs"
|
||||
import type { OpenApiParameter } from "./OpenApiParameter"
|
||||
import type { OpenApiRequestBody } from "./OpenApiRequestBody"
|
||||
import type { OpenApiResponses } from "./OpenApiResponses"
|
||||
import type { OpenApiSecurityRequirement } from "./OpenApiSecurityRequirement"
|
||||
import type { OpenApiServer } from "./OpenApiServer"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#operationObject
|
||||
*/
|
||||
export interface OpenApiOperation {
|
||||
tags?: string[]
|
||||
summary?: string
|
||||
description?: string
|
||||
externalDocs?: OpenApiExternalDocs
|
||||
operationId?: string
|
||||
parameters?: OpenApiParameter[]
|
||||
requestBody?: OpenApiRequestBody
|
||||
responses: OpenApiResponses
|
||||
callbacks?: Dictionary<OpenApiCallback>
|
||||
deprecated?: boolean
|
||||
security?: OpenApiSecurityRequirement[]
|
||||
servers?: OpenApiServer[]
|
||||
"x-codegen"?: Record<string, unknown>
|
||||
}
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
import type { OpenApiExample } from "./OpenApiExample"
|
||||
import type { OpenApiReference } from "./OpenApiReference"
|
||||
import type { OpenApiSchema } from "./OpenApiSchema"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#parameterObject
|
||||
*/
|
||||
export interface OpenApiParameter extends OpenApiReference {
|
||||
name: string
|
||||
in: "path" | "query" | "header" | "formData" | "cookie"
|
||||
description?: string
|
||||
required?: boolean
|
||||
nullable?: boolean
|
||||
deprecated?: boolean
|
||||
allowEmptyValue?: boolean
|
||||
style?: string
|
||||
explode?: boolean
|
||||
allowReserved?: boolean
|
||||
schema?: OpenApiSchema
|
||||
example?: any
|
||||
examples?: Dictionary<OpenApiExample>
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import type { OpenApiOperation } from "./OpenApiOperation"
|
||||
import type { OpenApiParameter } from "./OpenApiParameter"
|
||||
import type { OpenApiServer } from "./OpenApiServer"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#pathItemObject
|
||||
*/
|
||||
export interface OpenApiPath {
|
||||
summary?: string
|
||||
description?: string
|
||||
get?: OpenApiOperation
|
||||
put?: OpenApiOperation
|
||||
post?: OpenApiOperation
|
||||
delete?: OpenApiOperation
|
||||
options?: OpenApiOperation
|
||||
head?: OpenApiOperation
|
||||
patch?: OpenApiOperation
|
||||
trace?: OpenApiOperation
|
||||
servers?: OpenApiServer[]
|
||||
parameters?: OpenApiParameter[]
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import type { OpenApiPath } from "./OpenApiPath"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#pathsObject
|
||||
*/
|
||||
export interface OpenApiPaths {
|
||||
[path: string]: OpenApiPath
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#referenceObject
|
||||
*/
|
||||
export interface OpenApiReference {
|
||||
$ref?: string
|
||||
}
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
import type { OpenApiMediaType } from "./OpenApiMediaType"
|
||||
import type { OpenApiReference } from "./OpenApiReference"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#requestBodyObject
|
||||
*/
|
||||
export interface OpenApiRequestBody extends OpenApiReference {
|
||||
description?: string
|
||||
content: Dictionary<OpenApiMediaType>
|
||||
required?: boolean
|
||||
nullable?: boolean
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
import type { OpenApiHeader } from "./OpenApiHeader"
|
||||
import type { OpenApiLink } from "./OpenApiLink"
|
||||
import type { OpenApiMediaType } from "./OpenApiMediaType"
|
||||
import type { OpenApiReference } from "./OpenApiReference"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject
|
||||
*/
|
||||
export interface OpenApiResponse extends OpenApiReference {
|
||||
description: string
|
||||
headers?: Dictionary<OpenApiHeader>
|
||||
content?: Dictionary<OpenApiMediaType>
|
||||
links?: Dictionary<OpenApiLink>
|
||||
}
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
import type { OpenApiReference } from "./OpenApiReference"
|
||||
import type { OpenApiResponse } from "./OpenApiResponse"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject
|
||||
*/
|
||||
export interface OpenApiResponses extends OpenApiReference {
|
||||
default?: OpenApiResponse
|
||||
|
||||
[httpcode: string]: OpenApiResponse
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
import type { WithEnumExtension } from "./Extensions/WithEnumExtension"
|
||||
import type { OpenApiDiscriminator } from "./OpenApiDiscriminator"
|
||||
import type { OpenApiExternalDocs } from "./OpenApiExternalDocs"
|
||||
import type { OpenApiReference } from "./OpenApiReference"
|
||||
import type { OpenApiXml } from "./OpenApiXml"
|
||||
import { WithExtendedRelationsExtension } from "./Extensions/WithDefaultRelationsExtension"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject
|
||||
*/
|
||||
export interface OpenApiSchema
|
||||
extends OpenApiReference,
|
||||
WithEnumExtension,
|
||||
WithExtendedRelationsExtension {
|
||||
title?: string
|
||||
multipleOf?: number
|
||||
maximum?: number
|
||||
exclusiveMaximum?: boolean
|
||||
minimum?: number
|
||||
exclusiveMinimum?: boolean
|
||||
maxLength?: number
|
||||
minLength?: number
|
||||
pattern?: string
|
||||
maxItems?: number
|
||||
minItems?: number
|
||||
uniqueItems?: boolean
|
||||
maxProperties?: number
|
||||
minProperties?: number
|
||||
required?: string[]
|
||||
enum?: (string | number)[]
|
||||
type?: string | string[]
|
||||
allOf?: OpenApiSchema[]
|
||||
oneOf?: OpenApiSchema[]
|
||||
anyOf?: OpenApiSchema[]
|
||||
not?: OpenApiSchema[]
|
||||
items?: OpenApiSchema
|
||||
properties?: Dictionary<OpenApiSchema>
|
||||
additionalProperties?: boolean | OpenApiSchema
|
||||
description?: string
|
||||
format?:
|
||||
| "int32"
|
||||
| "int64"
|
||||
| "float"
|
||||
| "double"
|
||||
| "string"
|
||||
| "boolean"
|
||||
| "byte"
|
||||
| "binary"
|
||||
| "date"
|
||||
| "date-time"
|
||||
| "password"
|
||||
default?: any
|
||||
nullable?: boolean
|
||||
discriminator?: OpenApiDiscriminator
|
||||
readOnly?: boolean
|
||||
writeOnly?: boolean
|
||||
xml?: OpenApiXml
|
||||
externalDocs?: OpenApiExternalDocs
|
||||
example?: any
|
||||
deprecated?: boolean
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#securityRequirementObject
|
||||
*/
|
||||
export interface OpenApiSecurityRequirement {
|
||||
[name: string]: string
|
||||
}
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
import type { OpenApiOAuthFlows } from "./OpenApiOAuthFlows"
|
||||
import type { OpenApiReference } from "./OpenApiReference"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#securitySchemeObject
|
||||
*/
|
||||
export interface OpenApiSecurityScheme extends OpenApiReference {
|
||||
type: "apiKey" | "http" | "oauth2" | "openIdConnect"
|
||||
description?: string
|
||||
name?: string
|
||||
in?: "query" | "header" | "cookie"
|
||||
scheme?: string
|
||||
bearerFormat?: string
|
||||
flows?: OpenApiOAuthFlows
|
||||
openIdConnectUrl?: string
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
import type { OpenApiServerVariable } from "./OpenApiServerVariable"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#serverObject
|
||||
*/
|
||||
export interface OpenApiServer {
|
||||
url: string
|
||||
description?: string
|
||||
variables?: Dictionary<OpenApiServerVariable>
|
||||
}
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
import type { WithEnumExtension } from "./Extensions/WithEnumExtension"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#serverVariableObject
|
||||
*/
|
||||
export interface OpenApiServerVariable extends WithEnumExtension {
|
||||
enum?: (string | number)[]
|
||||
default: string
|
||||
description?: string
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import type { OpenApiExternalDocs } from "./OpenApiExternalDocs"
|
||||
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#tagObject
|
||||
*/
|
||||
export interface OpenApiTag {
|
||||
name: string
|
||||
description?: string
|
||||
externalDocs?: OpenApiExternalDocs
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#xmlObject
|
||||
*/
|
||||
export interface OpenApiXml {
|
||||
name?: string
|
||||
namespace?: string
|
||||
prefix?: string
|
||||
attribute?: boolean
|
||||
wrapped?: boolean
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { getModel } from "../getModel"
|
||||
import { OpenApi } from "../../interfaces/OpenApi"
|
||||
import { Model } from "../../../../client/interfaces/Model"
|
||||
import { OpenApiSchema } from "../../interfaces/OpenApiSchema"
|
||||
|
||||
describe("getModel", () => {
|
||||
let openApi: OpenApi
|
||||
beforeEach(async () => {
|
||||
openApi = {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
title: "Test",
|
||||
version: "1.0.0",
|
||||
},
|
||||
paths: {},
|
||||
components: {},
|
||||
}
|
||||
})
|
||||
|
||||
it("should set model spec with definition", () => {
|
||||
const modelName = "OrderRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
expect(model.spec).toEqual(definition)
|
||||
})
|
||||
|
||||
it("should set property spec with definition", () => {
|
||||
const modelName = "OrderRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
order: {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
expect(model.properties[0].spec).toEqual(definition.properties!.order)
|
||||
})
|
||||
})
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
import { getModels } from "../getModels"
|
||||
import { OpenApi } from "../../interfaces/OpenApi"
|
||||
|
||||
describe("getModels", () => {
|
||||
let openApi: OpenApi
|
||||
beforeEach(async () => {
|
||||
openApi = {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
title: "Test",
|
||||
version: "1.0.0",
|
||||
},
|
||||
paths: {},
|
||||
components: {},
|
||||
}
|
||||
})
|
||||
|
||||
it("should return an empty array if no models are found", () => {
|
||||
const models = getModels(openApi)
|
||||
expect(models).toEqual([])
|
||||
})
|
||||
|
||||
it("should return an array of models", () => {
|
||||
openApi.components = {
|
||||
schemas: {
|
||||
OrderRes: {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
const models = getModels(openApi)
|
||||
expect(models).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: "OrderRes",
|
||||
properties: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: "id",
|
||||
type: "string",
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("should return an array of models with expanded relations", () => {
|
||||
openApi.components = {
|
||||
schemas: {
|
||||
OrderRes: {
|
||||
type: "object",
|
||||
"x-expanded-relations": {
|
||||
field: "order",
|
||||
relations: ["region", "region.country"],
|
||||
},
|
||||
properties: {
|
||||
order: {
|
||||
$ref: "#/components/schemas/Order",
|
||||
},
|
||||
},
|
||||
},
|
||||
Order: {
|
||||
type: "object",
|
||||
properties: {
|
||||
region: {
|
||||
$ref: "#/components/schemas/Region",
|
||||
},
|
||||
},
|
||||
},
|
||||
Region: {
|
||||
type: "object",
|
||||
properties: {
|
||||
country: {
|
||||
$ref: "#/components/schemas/Country",
|
||||
},
|
||||
},
|
||||
},
|
||||
Country: {
|
||||
type: "object",
|
||||
},
|
||||
},
|
||||
}
|
||||
const models = getModels(openApi)
|
||||
expect(models).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: "OrderRes",
|
||||
properties: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: "order",
|
||||
base: "Order",
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
base: "Order",
|
||||
field: "order",
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "region",
|
||||
base: "Region",
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
base: "Country",
|
||||
field: "country",
|
||||
nestedRelations: [],
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("should convert query parameters into a schema when x-codegen.queryParams is declared", () => {
|
||||
openApi.paths = {
|
||||
"/": {
|
||||
get: {
|
||||
operationId: "GetOrder",
|
||||
"x-codegen": {
|
||||
queryParams: "GetOrderQueryParams",
|
||||
},
|
||||
parameters: [
|
||||
{
|
||||
description: "Limit the number of results",
|
||||
in: "query",
|
||||
name: "limit",
|
||||
schema: {
|
||||
type: "integer",
|
||||
},
|
||||
required: true,
|
||||
deprecated: true,
|
||||
},
|
||||
],
|
||||
responses: {
|
||||
"200": {
|
||||
description: "OK",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
const models = getModels(openApi)
|
||||
expect(models).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: "GetOrderQueryParams",
|
||||
properties: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
description: "Limit the number of results",
|
||||
name: "limit",
|
||||
type: "number",
|
||||
isRequired: true,
|
||||
deprecated: true,
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
})
|
||||
+436
@@ -0,0 +1,436 @@
|
||||
import { Model } from "../../../../client/interfaces/Model"
|
||||
import { handleExpandedRelations } from "../getModelsExpandedRelations"
|
||||
import { getModel } from "../getModel"
|
||||
import { OpenApi } from "../../interfaces/OpenApi"
|
||||
import { OpenApiSchema } from "../../interfaces/OpenApiSchema"
|
||||
import { getType } from "../getType"
|
||||
|
||||
function getModelsTest(openApi: OpenApi): Model[] {
|
||||
const models: Model[] = []
|
||||
if (openApi.components) {
|
||||
for (const definitionName in openApi.components.schemas) {
|
||||
if (openApi.components.schemas.hasOwnProperty(definitionName)) {
|
||||
const definition = openApi.components.schemas[definitionName]
|
||||
const definitionType = getType(definitionName)
|
||||
const model = getModel(openApi, definition, true, definitionType.base)
|
||||
models.push(model)
|
||||
}
|
||||
}
|
||||
}
|
||||
return models
|
||||
}
|
||||
|
||||
describe("getModelsExpandedRelations", () => {
|
||||
let openApi: OpenApi
|
||||
beforeEach(async () => {
|
||||
openApi = {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
title: "Test",
|
||||
version: "1.0.0",
|
||||
},
|
||||
paths: {},
|
||||
components: {
|
||||
schemas: {
|
||||
Order: {
|
||||
type: "object",
|
||||
properties: {
|
||||
region: {
|
||||
$ref: "#/components/schemas/Region",
|
||||
},
|
||||
total: {
|
||||
type: "number",
|
||||
},
|
||||
},
|
||||
},
|
||||
Region: {
|
||||
type: "object",
|
||||
properties: {
|
||||
country: {
|
||||
$ref: "#/components/schemas/Country",
|
||||
},
|
||||
},
|
||||
},
|
||||
Country: {
|
||||
type: "object",
|
||||
},
|
||||
Customer: {
|
||||
type: "object",
|
||||
properties: {
|
||||
orders: {
|
||||
type: "array",
|
||||
items: {
|
||||
$ref: "#/components/schemas/Order",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
describe("basic use cases", () => {
|
||||
it("should find nested relation - model", () => {
|
||||
const modelName: string = "OrderRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
"x-expanded-relations": {
|
||||
field: "order",
|
||||
relations: ["region"],
|
||||
},
|
||||
properties: {
|
||||
order: {
|
||||
$ref: "#/components/schemas/Order",
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
const models: Model[] = [...getModelsTest(openApi), model]
|
||||
|
||||
handleExpandedRelations(model, models)
|
||||
|
||||
expect(model.properties[0].nestedRelations).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "order",
|
||||
base: "Order",
|
||||
isArray: false,
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "region",
|
||||
base: "Region",
|
||||
isArray: false,
|
||||
nestedRelations: [],
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("should find nested relation - shallow", () => {
|
||||
const modelName: string = "OrderRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
"x-expanded-relations": {
|
||||
field: "order",
|
||||
relations: ["total"],
|
||||
},
|
||||
properties: {
|
||||
order: {
|
||||
$ref: "#/components/schemas/Order",
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
const models: Model[] = [...getModelsTest(openApi), model]
|
||||
|
||||
handleExpandedRelations(model, models)
|
||||
|
||||
expect(model.properties[0].nestedRelations).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "order",
|
||||
base: "Order",
|
||||
isArray: false,
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "total",
|
||||
nestedRelations: [],
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("should find nested relation - array", () => {
|
||||
const modelName: string = "CustomerRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
"x-expanded-relations": {
|
||||
field: "customer",
|
||||
relations: ["orders"],
|
||||
},
|
||||
properties: {
|
||||
customer: {
|
||||
$ref: "#/components/schemas/Customer",
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
const models: Model[] = [...getModelsTest(openApi), model]
|
||||
|
||||
handleExpandedRelations(model, models)
|
||||
|
||||
expect(model.properties[0].nestedRelations).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "customer",
|
||||
base: "Customer",
|
||||
isArray: false,
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "orders",
|
||||
base: "Order",
|
||||
isArray: true,
|
||||
nestedRelations: [],
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("misc usage", () => {
|
||||
it.each([["allOf"], ["anyOf"], ["oneOf"]])(
|
||||
"should findPropInCombination - %s",
|
||||
(combination) => {
|
||||
openApi.components!.schemas!.ExpandedOrder = {
|
||||
[combination]: [{ $ref: "#/components/schemas/Order" }],
|
||||
}
|
||||
const modelName: string = "OrderRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
"x-expanded-relations": {
|
||||
field: "order",
|
||||
relations: ["region"],
|
||||
},
|
||||
properties: {
|
||||
order: {
|
||||
$ref: "#/components/schemas/ExpandedOrder",
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
const models: Model[] = [...getModelsTest(openApi), model]
|
||||
|
||||
handleExpandedRelations(model, models)
|
||||
|
||||
expect(model.properties[0].nestedRelations).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "region",
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
it.each([["relations"], ["totals"], ["implicit"], ["eager"]])(
|
||||
"should find nested relation with relation type - %s",
|
||||
(relationType) => {
|
||||
const modelName: string = "OrderRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
"x-expanded-relations": {
|
||||
field: "order",
|
||||
[relationType]: ["region"],
|
||||
},
|
||||
properties: {
|
||||
order: {
|
||||
$ref: "#/components/schemas/Order",
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
const models: Model[] = [...getModelsTest(openApi), model]
|
||||
|
||||
handleExpandedRelations(model, models)
|
||||
|
||||
expect(model.properties[0].nestedRelations).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "region",
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
it("should set field hasDepth - true", () => {
|
||||
const modelName: string = "OrderRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
"x-expanded-relations": {
|
||||
field: "order",
|
||||
relations: ["region.country"],
|
||||
},
|
||||
properties: {
|
||||
order: {
|
||||
$ref: "#/components/schemas/Order",
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
const models: Model[] = [...getModelsTest(openApi), model]
|
||||
|
||||
handleExpandedRelations(model, models)
|
||||
|
||||
expect(model.properties[0].nestedRelations).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
hasDepth: true,
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "region",
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "country",
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("should set relation hasDepth - true", () => {
|
||||
const modelName: string = "CustomerRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
"x-expanded-relations": {
|
||||
field: "customer",
|
||||
relations: ["orders.region.country"],
|
||||
},
|
||||
properties: {
|
||||
customer: {
|
||||
$ref: "#/components/schemas/Customer",
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
const models: Model[] = [...getModelsTest(openApi), model]
|
||||
|
||||
handleExpandedRelations(model, models)
|
||||
|
||||
expect(model.properties[0].nestedRelations).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
hasDepth: true,
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "orders",
|
||||
hasDepth: true,
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "region",
|
||||
nestedRelations: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
field: "country",
|
||||
nestedRelations: [],
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("should add models with relation to root model imports, only once", () => {
|
||||
const modelName: string = "OrderRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
"x-expanded-relations": {
|
||||
field: "order",
|
||||
relations: ["region", "region.country"],
|
||||
},
|
||||
properties: {
|
||||
order: {
|
||||
$ref: "#/components/schemas/Order",
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
const models: Model[] = [...getModelsTest(openApi), model]
|
||||
|
||||
handleExpandedRelations(model, models)
|
||||
|
||||
expect(model.imports).toEqual(expect.arrayContaining(["Order", "Region"]))
|
||||
})
|
||||
})
|
||||
|
||||
describe("errors", () => {
|
||||
it("should throw if field is not found", () => {
|
||||
const modelName: string = "OrderRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
"x-expanded-relations": {
|
||||
field: "nope",
|
||||
},
|
||||
properties: {
|
||||
order: {
|
||||
$ref: "#/components/schemas/Order",
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
const models: Model[] = [...getModelsTest(openApi), model]
|
||||
|
||||
expect(() => handleExpandedRelations(model, models)).toThrow(
|
||||
"x-expanded-relations - field not found"
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw if relation is not found", () => {
|
||||
const modelName: string = "OrderRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
"x-expanded-relations": {
|
||||
field: "order",
|
||||
relations: ["nope"],
|
||||
},
|
||||
properties: {
|
||||
order: {
|
||||
$ref: "#/components/schemas/Order",
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
const models: Model[] = [...getModelsTest(openApi), model]
|
||||
|
||||
expect(() => handleExpandedRelations(model, models)).toThrow(
|
||||
"x-expanded-relations - relation not found"
|
||||
)
|
||||
})
|
||||
|
||||
it.each([["allOf"], ["anyOf"], ["oneOf"]])(
|
||||
"should throw if field exports as a combination - %s",
|
||||
(combination) => {
|
||||
const modelName: string = "OrderRes"
|
||||
const definition: OpenApiSchema = {
|
||||
type: "object",
|
||||
"x-expanded-relations": {
|
||||
field: "order",
|
||||
relations: ["region"],
|
||||
},
|
||||
properties: {
|
||||
order: {
|
||||
[combination]: [{ $ref: "#/components/schemas/Order" }],
|
||||
},
|
||||
},
|
||||
}
|
||||
const model: Model = getModel(openApi, definition, true, modelName)
|
||||
const models: Model[] = [...getModelsTest(openApi), model]
|
||||
|
||||
expect(() => handleExpandedRelations(model, models)).toThrow(
|
||||
"x-expanded-relations - unsupported - field referencing multiple models"
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
import { OpenApi } from "../../interfaces/OpenApi"
|
||||
import { OpenApiOperation } from "../../interfaces/OpenApiOperation"
|
||||
import { getOperation } from "../getOperation"
|
||||
import { getOperationParameters } from "../getOperationParameters"
|
||||
|
||||
describe("getOperation", () => {
|
||||
let openApi: OpenApi
|
||||
beforeEach(async () => {
|
||||
openApi = {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
title: "Test",
|
||||
version: "1.0.0",
|
||||
},
|
||||
paths: {},
|
||||
components: {},
|
||||
}
|
||||
})
|
||||
|
||||
it("should parse x-codegen", () => {
|
||||
const op: OpenApiOperation = {
|
||||
"x-codegen": {
|
||||
method: "list",
|
||||
},
|
||||
responses: {
|
||||
"200": {
|
||||
description: "OK",
|
||||
},
|
||||
},
|
||||
}
|
||||
const pathParams = getOperationParameters(openApi, [])
|
||||
const operation = getOperation(
|
||||
openApi,
|
||||
"/orders",
|
||||
"get",
|
||||
"Orders",
|
||||
op,
|
||||
pathParams
|
||||
)
|
||||
expect(operation).toEqual(
|
||||
expect.objectContaining({
|
||||
codegen: { method: "list" },
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should add x-codegen.queryParams to imports", () => {
|
||||
const op: OpenApiOperation = {
|
||||
"x-codegen": {
|
||||
queryParams: "OrdersQueryParams",
|
||||
},
|
||||
responses: {
|
||||
"200": {
|
||||
description: "OK",
|
||||
},
|
||||
},
|
||||
}
|
||||
const pathParams = getOperationParameters(openApi, [])
|
||||
const operation = getOperation(
|
||||
openApi,
|
||||
"/orders",
|
||||
"get",
|
||||
"Orders",
|
||||
op,
|
||||
pathParams
|
||||
)
|
||||
expect(operation.imports).toEqual(
|
||||
expect.arrayContaining(["OrdersQueryParams"])
|
||||
)
|
||||
})
|
||||
})
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import { OpenApi } from "../../interfaces/OpenApi"
|
||||
import { getOperationParameter } from "../getOperationParameter"
|
||||
import { OpenApiParameter } from "../../interfaces/OpenApiParameter"
|
||||
|
||||
describe("getOperation", () => {
|
||||
let openApi: OpenApi
|
||||
beforeEach(async () => {
|
||||
openApi = {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
title: "Test",
|
||||
version: "1.0.0",
|
||||
},
|
||||
paths: {},
|
||||
components: {},
|
||||
}
|
||||
})
|
||||
|
||||
it("should set spec with definition", () => {
|
||||
const parameter: OpenApiParameter = {
|
||||
name: "id",
|
||||
in: "path",
|
||||
}
|
||||
const operationParameter = getOperationParameter(openApi, parameter)
|
||||
expect(operationParameter.spec).toEqual(parameter)
|
||||
})
|
||||
})
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
import { OpenApi } from "../../interfaces/OpenApi"
|
||||
import { getOperationRequestBody } from "../getOperationRequestBody"
|
||||
import { OpenApiRequestBody } from "../../interfaces/OpenApiRequestBody"
|
||||
|
||||
describe("getOperation", () => {
|
||||
let openApi: OpenApi
|
||||
beforeEach(async () => {
|
||||
openApi = {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
title: "Test",
|
||||
version: "1.0.0",
|
||||
},
|
||||
paths: {},
|
||||
components: {},
|
||||
}
|
||||
})
|
||||
|
||||
it("should set spec with definition", () => {
|
||||
const body: OpenApiRequestBody = {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
const operationRequestBody = getOperationRequestBody(openApi, body)
|
||||
expect(operationRequestBody.spec).toEqual(body)
|
||||
})
|
||||
})
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
import { OpenApi } from "../../interfaces/OpenApi"
|
||||
import { getOperationResponse } from "../getOperationResponse"
|
||||
import { OpenApiResponse } from "../../interfaces/OpenApiResponse"
|
||||
|
||||
describe("getOperation", () => {
|
||||
let openApi: OpenApi
|
||||
beforeEach(async () => {
|
||||
openApi = {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
title: "Test",
|
||||
version: "1.0.0",
|
||||
},
|
||||
paths: {},
|
||||
components: {},
|
||||
}
|
||||
})
|
||||
|
||||
it("should set spec with definition", () => {
|
||||
const response: OpenApiResponse = {
|
||||
description: "OK",
|
||||
}
|
||||
const operationResponse = getOperationResponse(openApi, response, 200)
|
||||
expect(operationResponse.spec).toEqual(response)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
export const escapeName = (value: string): string => {
|
||||
if (value || value === "") {
|
||||
const validName = /^[a-zA-Z_$][\w$]+$/g.test(value)
|
||||
if (!validName) {
|
||||
return `'${value}'`
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { Enum } from "../../../client/interfaces/Enum"
|
||||
import { isString } from "../../../utils/isString"
|
||||
import type { WithEnumExtension } from "../interfaces/Extensions/WithEnumExtension"
|
||||
|
||||
/**
|
||||
* Extend the enum with the x-enum properties. This adds the capability
|
||||
* to use names and descriptions inside the generated enums.
|
||||
* @param enumerators
|
||||
* @param definition
|
||||
*/
|
||||
export const extendEnum = (
|
||||
enumerators: Enum[],
|
||||
definition: WithEnumExtension
|
||||
): Enum[] => {
|
||||
const names = definition["x-enum-varnames"]?.filter(isString)
|
||||
const descriptions = definition["x-enum-descriptions"]?.filter(isString)
|
||||
|
||||
return enumerators.map((enumerator, index) => ({
|
||||
name: names?.[index] || enumerator.name,
|
||||
description: descriptions?.[index] || enumerator.description,
|
||||
value: enumerator.value,
|
||||
type: enumerator.type,
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { isDefined } from "../../../utils/isDefined"
|
||||
import type { Dictionary } from "../../../utils/types"
|
||||
import type { OpenApi } from "../interfaces/OpenApi"
|
||||
import type { OpenApiMediaType } from "../interfaces/OpenApiMediaType"
|
||||
import type { OpenApiSchema } from "../interfaces/OpenApiSchema"
|
||||
|
||||
export interface Content {
|
||||
mediaType: string
|
||||
schema: OpenApiSchema
|
||||
}
|
||||
|
||||
const BASIC_MEDIA_TYPES = [
|
||||
"application/json-patch+json",
|
||||
"application/json",
|
||||
"application/x-www-form-urlencoded",
|
||||
"text/json",
|
||||
"text/plain",
|
||||
"multipart/form-data",
|
||||
"multipart/mixed",
|
||||
"multipart/related",
|
||||
"multipart/batch",
|
||||
]
|
||||
|
||||
export const getContent = (
|
||||
openApi: OpenApi,
|
||||
content: Dictionary<OpenApiMediaType>
|
||||
): Content | null => {
|
||||
const basicMediaTypeWithSchema = Object.keys(content)
|
||||
.filter((mediaType) => {
|
||||
const cleanMediaType = mediaType.split(";")[0].trim()
|
||||
return BASIC_MEDIA_TYPES.includes(cleanMediaType)
|
||||
})
|
||||
.find((mediaType) => isDefined(content[mediaType]?.schema))
|
||||
if (basicMediaTypeWithSchema) {
|
||||
return {
|
||||
mediaType: basicMediaTypeWithSchema,
|
||||
schema: content[basicMediaTypeWithSchema].schema as OpenApiSchema,
|
||||
}
|
||||
}
|
||||
|
||||
const firstMediaTypeWithSchema = Object.keys(content).find((mediaType) =>
|
||||
isDefined(content[mediaType]?.schema)
|
||||
)
|
||||
if (firstMediaTypeWithSchema) {
|
||||
return {
|
||||
mediaType: firstMediaTypeWithSchema,
|
||||
schema: content[firstMediaTypeWithSchema].schema as OpenApiSchema,
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { Enum } from "../../../client/interfaces/Enum"
|
||||
|
||||
export const getEnum = (values?: (string | number)[]): Enum[] => {
|
||||
if (Array.isArray(values)) {
|
||||
return values
|
||||
.filter((value, index, arr) => {
|
||||
return arr.indexOf(value) === index
|
||||
})
|
||||
.filter((value: any) => {
|
||||
return typeof value === "number" || typeof value === "string"
|
||||
})
|
||||
.map((value) => {
|
||||
if (typeof value === "number") {
|
||||
return {
|
||||
name: `'_${value}'`,
|
||||
value: String(value),
|
||||
type: "number",
|
||||
description: null,
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: String(value)
|
||||
.replace(/\W+/g, "_")
|
||||
.replace(/^(\d+)/g, "_$1")
|
||||
.replace(/([a-z])([A-Z]+)/g, "$1_$2")
|
||||
.toUpperCase(),
|
||||
value: `'${value.replace(/'/g, "\\'")}'`,
|
||||
type: "string",
|
||||
description: null,
|
||||
}
|
||||
})
|
||||
}
|
||||
return []
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
const TYPE_MAPPINGS = new Map<string, string>([
|
||||
["file", "binary"],
|
||||
["any", "any"],
|
||||
["object", "any"],
|
||||
["array", "any[]"],
|
||||
["boolean", "boolean"],
|
||||
["byte", "number"],
|
||||
["int", "number"],
|
||||
["integer", "number"],
|
||||
["float", "number"],
|
||||
["double", "number"],
|
||||
["short", "number"],
|
||||
["long", "number"],
|
||||
["number", "number"],
|
||||
["char", "string"],
|
||||
["date", "string"],
|
||||
["date-time", "string"],
|
||||
["password", "string"],
|
||||
["string", "string"],
|
||||
["void", "void"],
|
||||
["null", "null"],
|
||||
])
|
||||
|
||||
/**
|
||||
* Get mapped type for given type to any basic Typescript/Javascript type.
|
||||
*/
|
||||
export const getMappedType = (
|
||||
type: string,
|
||||
format?: string
|
||||
): string | undefined => {
|
||||
if (format === "binary") {
|
||||
return "binary"
|
||||
}
|
||||
return TYPE_MAPPINGS.get(type)
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
import type { Model } from "../../../client/interfaces/Model"
|
||||
import { getPattern } from "../../../utils/getPattern"
|
||||
import type { OpenApi } from "../interfaces/OpenApi"
|
||||
import type { OpenApiSchema } from "../interfaces/OpenApiSchema"
|
||||
import { extendEnum } from "./extendEnum"
|
||||
import { getEnum } from "./getEnum"
|
||||
import { getModelComposition } from "./getModelComposition"
|
||||
import { getModelDefault } from "./getModelDefault"
|
||||
import { getModelProperties } from "./getModelProperties"
|
||||
import { getType } from "./getType"
|
||||
|
||||
export const getModel = (
|
||||
openApi: OpenApi,
|
||||
definition: OpenApiSchema,
|
||||
isDefinition: boolean = false,
|
||||
name: string = ""
|
||||
): Model => {
|
||||
const model: Model = {
|
||||
spec: definition,
|
||||
name,
|
||||
export: "interface",
|
||||
type: "any",
|
||||
base: "any",
|
||||
template: null,
|
||||
link: null,
|
||||
description: definition.description || null,
|
||||
deprecated: definition.deprecated === true,
|
||||
isDefinition,
|
||||
isReadOnly: definition.readOnly === true,
|
||||
isNullable: definition.nullable === true,
|
||||
isRequired: false,
|
||||
format: definition.format,
|
||||
maximum: definition.maximum,
|
||||
exclusiveMaximum: definition.exclusiveMaximum,
|
||||
minimum: definition.minimum,
|
||||
exclusiveMinimum: definition.exclusiveMinimum,
|
||||
multipleOf: definition.multipleOf,
|
||||
maxLength: definition.maxLength,
|
||||
minLength: definition.minLength,
|
||||
maxItems: definition.maxItems,
|
||||
minItems: definition.minItems,
|
||||
uniqueItems: definition.uniqueItems,
|
||||
maxProperties: definition.maxProperties,
|
||||
minProperties: definition.minProperties,
|
||||
pattern: getPattern(definition.pattern),
|
||||
imports: [],
|
||||
enum: [],
|
||||
enums: [],
|
||||
properties: [],
|
||||
}
|
||||
|
||||
if (definition.$ref) {
|
||||
const definitionRef = getType(definition.$ref)
|
||||
model.export = "reference"
|
||||
model.type = definitionRef.type
|
||||
model.base = definitionRef.base
|
||||
model.template = definitionRef.template
|
||||
model.imports.push(...definitionRef.imports)
|
||||
model.default = getModelDefault(definition, model)
|
||||
return model
|
||||
}
|
||||
|
||||
if (definition.enum && definition.type !== "boolean") {
|
||||
const enumerators = getEnum(definition.enum)
|
||||
const extendedEnumerators = extendEnum(enumerators, definition)
|
||||
if (extendedEnumerators.length) {
|
||||
model.export = "enum"
|
||||
model.type = "string"
|
||||
model.base = "string"
|
||||
model.enum.push(...extendedEnumerators)
|
||||
model.default = getModelDefault(definition, model)
|
||||
return model
|
||||
}
|
||||
}
|
||||
|
||||
if (definition.type === "array" && definition.items) {
|
||||
if (definition.items.$ref) {
|
||||
const arrayItems = getType(definition.items.$ref)
|
||||
model.export = "array"
|
||||
model.type = arrayItems.type
|
||||
model.base = arrayItems.base
|
||||
model.template = arrayItems.template
|
||||
model.imports.push(...arrayItems.imports)
|
||||
model.default = getModelDefault(definition, model)
|
||||
return model
|
||||
} else {
|
||||
const arrayItems = getModel(openApi, definition.items)
|
||||
model.export = "array"
|
||||
model.type = arrayItems.type
|
||||
model.base = arrayItems.base
|
||||
model.template = arrayItems.template
|
||||
model.link = arrayItems
|
||||
model.imports.push(...arrayItems.imports)
|
||||
model.default = getModelDefault(definition, model)
|
||||
return model
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
definition.type === "object" &&
|
||||
(typeof definition.additionalProperties === "object" ||
|
||||
definition.additionalProperties === true)
|
||||
) {
|
||||
const ap =
|
||||
typeof definition.additionalProperties === "object"
|
||||
? definition.additionalProperties
|
||||
: {}
|
||||
if (ap.$ref) {
|
||||
const additionalProperties = getType(ap.$ref)
|
||||
model.export = "dictionary"
|
||||
model.type = additionalProperties.type
|
||||
model.base = additionalProperties.base
|
||||
model.template = additionalProperties.template
|
||||
model.imports.push(...additionalProperties.imports)
|
||||
model.default = getModelDefault(definition, model)
|
||||
return model
|
||||
} else {
|
||||
const additionalProperties = getModel(openApi, ap)
|
||||
model.export = "dictionary"
|
||||
model.type = additionalProperties.type
|
||||
model.base = additionalProperties.base
|
||||
model.template = additionalProperties.template
|
||||
model.link = additionalProperties
|
||||
model.imports.push(...additionalProperties.imports)
|
||||
model.default = getModelDefault(definition, model)
|
||||
return model
|
||||
}
|
||||
}
|
||||
|
||||
if (definition.oneOf?.length) {
|
||||
const composition = getModelComposition(
|
||||
openApi,
|
||||
definition,
|
||||
definition.oneOf,
|
||||
"one-of",
|
||||
getModel
|
||||
)
|
||||
model.export = composition.type
|
||||
model.imports.push(...composition.imports)
|
||||
model.properties.push(...composition.properties)
|
||||
model.enums.push(...composition.enums)
|
||||
return model
|
||||
}
|
||||
|
||||
if (definition.anyOf?.length) {
|
||||
const composition = getModelComposition(
|
||||
openApi,
|
||||
definition,
|
||||
definition.anyOf,
|
||||
"any-of",
|
||||
getModel
|
||||
)
|
||||
model.export = composition.type
|
||||
model.imports.push(...composition.imports)
|
||||
model.properties.push(...composition.properties)
|
||||
model.enums.push(...composition.enums)
|
||||
return model
|
||||
}
|
||||
|
||||
if (definition.allOf?.length) {
|
||||
const composition = getModelComposition(
|
||||
openApi,
|
||||
definition,
|
||||
definition.allOf,
|
||||
"all-of",
|
||||
getModel
|
||||
)
|
||||
model.export = composition.type
|
||||
model.imports.push(...composition.imports)
|
||||
model.properties.push(...composition.properties)
|
||||
model.enums.push(...composition.enums)
|
||||
return model
|
||||
}
|
||||
|
||||
if (definition.type === "object") {
|
||||
if (definition.properties) {
|
||||
model.export = "interface"
|
||||
model.type = "any"
|
||||
model.base = "any"
|
||||
model.default = getModelDefault(definition, model)
|
||||
|
||||
const modelProperties = getModelProperties(
|
||||
openApi,
|
||||
definition,
|
||||
getModel,
|
||||
model
|
||||
)
|
||||
modelProperties.forEach((modelProperty) => {
|
||||
model.imports.push(...modelProperty.imports)
|
||||
model.enums.push(...modelProperty.enums)
|
||||
model.properties.push(modelProperty)
|
||||
if (modelProperty.export === "enum") {
|
||||
model.enums.push(modelProperty)
|
||||
}
|
||||
})
|
||||
return model
|
||||
} else {
|
||||
const additionalProperties = getModel(openApi, {})
|
||||
model.export = "dictionary"
|
||||
model.type = additionalProperties.type
|
||||
model.base = additionalProperties.base
|
||||
model.template = additionalProperties.template
|
||||
model.link = additionalProperties
|
||||
model.imports.push(...additionalProperties.imports)
|
||||
model.default = getModelDefault(definition, model)
|
||||
return model
|
||||
}
|
||||
}
|
||||
|
||||
// If the schema has a type than it can be a basic or generic type.
|
||||
if (definition.type) {
|
||||
const definitionType = getType(definition.type, definition.format)
|
||||
model.export = "generic"
|
||||
model.type = definitionType.type
|
||||
model.base = definitionType.base
|
||||
model.template = definitionType.template
|
||||
model.isNullable = definitionType.isNullable || model.isNullable
|
||||
model.imports.push(...definitionType.imports)
|
||||
model.default = getModelDefault(definition, model)
|
||||
return model
|
||||
}
|
||||
|
||||
return model
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
import type { Model } from "../../../client/interfaces/Model"
|
||||
import type { ModelComposition } from "../../../client/interfaces/ModelComposition"
|
||||
import type { OpenApi } from "../interfaces/OpenApi"
|
||||
import type { OpenApiSchema } from "../interfaces/OpenApiSchema"
|
||||
import type { getModel } from "./getModel"
|
||||
import { getModelProperties } from "./getModelProperties"
|
||||
import { getRequiredPropertiesFromComposition } from "./getRequiredPropertiesFromComposition"
|
||||
|
||||
// Fix for circular dependency
|
||||
export type GetModelFn = typeof getModel
|
||||
|
||||
export const getModelComposition = (
|
||||
openApi: OpenApi,
|
||||
definition: OpenApiSchema,
|
||||
definitions: OpenApiSchema[],
|
||||
type: "one-of" | "any-of" | "all-of",
|
||||
getModel: GetModelFn
|
||||
): ModelComposition => {
|
||||
const composition: ModelComposition = {
|
||||
type,
|
||||
imports: [],
|
||||
enums: [],
|
||||
properties: [],
|
||||
}
|
||||
|
||||
const properties: Model[] = []
|
||||
|
||||
definitions
|
||||
.map((definition) => getModel(openApi, definition))
|
||||
.filter((model) => {
|
||||
const hasProperties = model.properties.length
|
||||
const hasEnums = model.enums.length
|
||||
const isObject = model.type === "any"
|
||||
const isDictionary = model.export === "dictionary"
|
||||
const isEmpty = isObject && !hasProperties && !hasEnums
|
||||
return !isEmpty || isDictionary
|
||||
})
|
||||
.forEach((model) => {
|
||||
composition.imports.push(...model.imports)
|
||||
composition.enums.push(...model.enums)
|
||||
composition.properties.push(model)
|
||||
})
|
||||
|
||||
if (definition.required) {
|
||||
const requiredProperties = getRequiredPropertiesFromComposition(
|
||||
openApi,
|
||||
definition.required,
|
||||
definitions,
|
||||
getModel
|
||||
)
|
||||
requiredProperties.forEach((requiredProperty) => {
|
||||
composition.imports.push(...requiredProperty.imports)
|
||||
composition.enums.push(...requiredProperty.enums)
|
||||
})
|
||||
properties.push(...requiredProperties)
|
||||
}
|
||||
|
||||
if (definition.properties) {
|
||||
const modelProperties = getModelProperties(openApi, definition, getModel)
|
||||
modelProperties.forEach((modelProperty) => {
|
||||
composition.imports.push(...modelProperty.imports)
|
||||
composition.enums.push(...modelProperty.enums)
|
||||
if (modelProperty.export === "enum") {
|
||||
composition.enums.push(modelProperty)
|
||||
}
|
||||
})
|
||||
properties.push(...modelProperties)
|
||||
}
|
||||
|
||||
if (properties.length) {
|
||||
composition.properties.push({
|
||||
spec: definition,
|
||||
name: "properties",
|
||||
export: "interface",
|
||||
type: "any",
|
||||
base: "any",
|
||||
template: null,
|
||||
link: null,
|
||||
description: "",
|
||||
isDefinition: false,
|
||||
isReadOnly: false,
|
||||
isNullable: false,
|
||||
isRequired: false,
|
||||
imports: [],
|
||||
enum: [],
|
||||
enums: [],
|
||||
properties,
|
||||
})
|
||||
}
|
||||
|
||||
return composition
|
||||
}
|
||||
Loaded 100 of 1436 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user