chore(): start moving some packages to the core directory (#7215)

This commit is contained in:
Adrien de Peretti authored and GitHub committed 2024-05-03 13:37:41 +02:00
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
+219
View File
@@ -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
+279
View File
@@ -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
+3
View File
@@ -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
View File
@@ -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[]
}
@@ -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[]
}
@@ -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
}
@@ -0,0 +1,4 @@
export interface OperationCodegen {
method?: string
queryParams?: string
}
@@ -0,0 +1,4 @@
export interface OperationError {
code: number
description: string
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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 }
}
@@ -0,0 +1,9 @@
export interface WithExtendedRelationsExtension {
"x-expanded-relations"?: {
field: string
relations?: string[]
totals?: string[]
implicit?: string[]
eager?: string[]
}
}
@@ -0,0 +1,4 @@
export interface WithEnumExtension {
"x-enum-varnames"?: string[]
"x-enum-descriptions"?: string[]
}
@@ -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
}
@@ -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
}
@@ -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>
}
@@ -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
}
@@ -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>
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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>
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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>
}
@@ -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>
}
@@ -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
}
@@ -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>
}
@@ -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>
}
@@ -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[]
}
@@ -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
}
@@ -0,0 +1,6 @@
/**
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#referenceObject
*/
export interface OpenApiReference {
$ref?: string
}
@@ -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
}
@@ -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>
}
@@ -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
}
@@ -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
}
@@ -0,0 +1,6 @@
/**
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#securityRequirementObject
*/
export interface OpenApiSecurityRequirement {
[name: string]: string
}
@@ -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
}
@@ -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>
}
@@ -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
}
@@ -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
}
@@ -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
}
@@ -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)
})
})
@@ -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,
}),
]),
}),
])
)
})
})
@@ -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"
)
}
)
})
})
@@ -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"])
)
})
})
@@ -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)
})
})
@@ -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)
})
})
@@ -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
}
@@ -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