Merge commit '36c66dd290d3ce6eb1ccd310d0c658d4a32bb8eb' as 'repos/effect'
This commit is contained in:
823
repos/effect/packages/tools/openapi-generator/CHANGELOG.md
Normal file
823
repos/effect/packages/tools/openapi-generator/CHANGELOG.md
Normal file
@@ -0,0 +1,823 @@
|
||||
# @effect/openapi-generator
|
||||
|
||||
## 4.0.0-beta.99
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`8ce4795`](https://github.com/Effect-TS/effect/commit/8ce4795ccbaebca4292757db568c005a992546a4), [`80b539f`](https://github.com/Effect-TS/effect/commit/80b539f8aba68f478c75c35c2b4140c4ffc4fada), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`e6e6dba`](https://github.com/Effect-TS/effect/commit/e6e6dba6e9d86e7c2ad27dcedf289db76a19697f), [`bfb203e`](https://github.com/Effect-TS/effect/commit/bfb203e95aa439f731acad37fc3a9a831a190f1c), [`2e9a34a`](https://github.com/Effect-TS/effect/commit/2e9a34ac2bece4f3a206160480c991e3841dc67a), [`55d4eb3`](https://github.com/Effect-TS/effect/commit/55d4eb34f2c64d54f6a25a305b5c5438ebd7934e), [`bddb010`](https://github.com/Effect-TS/effect/commit/bddb010eac3d4436cb094edbbee7460c5440c162), [`a328835`](https://github.com/Effect-TS/effect/commit/a328835e50d76bc96648a1c1550456e8c9f81210), [`5560d05`](https://github.com/Effect-TS/effect/commit/5560d05aa6abdd29466d9c3412cc5e648b0adbde), [`8f6e3ad`](https://github.com/Effect-TS/effect/commit/8f6e3adb185b16e8820b98c509b308086f7ff1af), [`46997fa`](https://github.com/Effect-TS/effect/commit/46997fa60401f5e3c93daa4b61f7df8e31caaab4), [`9e6e12d`](https://github.com/Effect-TS/effect/commit/9e6e12d75c118cd265496f2880490d1f33a5c8bf), [`3394b93`](https://github.com/Effect-TS/effect/commit/3394b93d97d6f24fc38670641d1490289ffca7f1), [`febeabc`](https://github.com/Effect-TS/effect/commit/febeabc3f7c31094da000a23edeaabfe2ab00a38), [`54161c9`](https://github.com/Effect-TS/effect/commit/54161c98f6f3569e0c31842f54e6a257f9421c4c), [`385f7a4`](https://github.com/Effect-TS/effect/commit/385f7a4ee4a7359928597ea56d151dbaf5eb5802), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`7543afe`](https://github.com/Effect-TS/effect/commit/7543afea6f4d97d1f1ad876224323838a48daadd), [`44b9cf3`](https://github.com/Effect-TS/effect/commit/44b9cf3d240d726997b4bbcd0ede48e074d3c456), [`7eea4d0`](https://github.com/Effect-TS/effect/commit/7eea4d0b73ec554915d7066a71f46326ce2ba45f), [`0a8aa6a`](https://github.com/Effect-TS/effect/commit/0a8aa6acb90a72b91c24d17133c950e4cacd8abd), [`c8d9fcf`](https://github.com/Effect-TS/effect/commit/c8d9fcf7b030f7c474effbab2764ce7aee1c7209), [`9ca7f9a`](https://github.com/Effect-TS/effect/commit/9ca7f9a69363e4485645966d5a93b8f9597c5206), [`e7aca89`](https://github.com/Effect-TS/effect/commit/e7aca894bb32fbb785b5830837e6061c415a6015), [`55d7560`](https://github.com/Effect-TS/effect/commit/55d75609b8acf8a1b54c1b1c7fbbb65ec741aa3e), [`f809189`](https://github.com/Effect-TS/effect/commit/f809189ddf6b6011ba43a9901baaa734e315da2a), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`0ebdbe7`](https://github.com/Effect-TS/effect/commit/0ebdbe74463dc84385956d0b1e8c2b79ebab5400), [`7517d09`](https://github.com/Effect-TS/effect/commit/7517d09f12a0b183a81bd425962c4e280a68b05d), [`212493b`](https://github.com/Effect-TS/effect/commit/212493b9a1eb98cd1ef6959c707a2e5784a5ae91), [`88a54cc`](https://github.com/Effect-TS/effect/commit/88a54cc341006e3ebcb13482c618f62a680ce199), [`80ea8cb`](https://github.com/Effect-TS/effect/commit/80ea8cb9222ca73f564c8267ab2f82966fea027a), [`8df19f4`](https://github.com/Effect-TS/effect/commit/8df19f4fe81d90cc33ace88b9a77e5534f82d604)]:
|
||||
- effect@4.0.0-beta.99
|
||||
- @effect/platform-node@4.0.0-beta.99
|
||||
|
||||
## 4.0.0-beta.98
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`989603b`](https://github.com/Effect-TS/effect-smol/commit/989603b60ab1197b64acf214208e0d370cd1f842), [`214c458`](https://github.com/Effect-TS/effect-smol/commit/214c458084bb6995d543cd37d1055f24be3d454e), [`a037273`](https://github.com/Effect-TS/effect-smol/commit/a0372736ac34796969b051bbba4717d7983f1ebe), [`97fdaa9`](https://github.com/Effect-TS/effect-smol/commit/97fdaa9c1f522c65e579365d314a07878e2b904f), [`b24d248`](https://github.com/Effect-TS/effect-smol/commit/b24d248c8df44222ce642087cde2bd859a2dc709), [`19c222c`](https://github.com/Effect-TS/effect-smol/commit/19c222cac2353a3d7b7733caecb00556fffe9a5c), [`eec85dd`](https://github.com/Effect-TS/effect-smol/commit/eec85ddba09ea326fd268ee33eeffd47e50d4671), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`8849052`](https://github.com/Effect-TS/effect-smol/commit/884905232d1e9a365e046d8dde27bf9c5707f57f), [`c15e16a`](https://github.com/Effect-TS/effect-smol/commit/c15e16ad130d1fbde25d912b7ac55995066cb35b), [`01d00a3`](https://github.com/Effect-TS/effect-smol/commit/01d00a3abfbf1f37996cdbe738ea5137c646cdd7), [`8bd4589`](https://github.com/Effect-TS/effect-smol/commit/8bd458975a1b3a8ed042eccf317b93d28ded91e7), [`0082f4f`](https://github.com/Effect-TS/effect-smol/commit/0082f4f74fb139fd578f87f0a790e845133983dc), [`6e08428`](https://github.com/Effect-TS/effect-smol/commit/6e08428d980501b856f846ad3f3f0e4ea46e7786), [`388dcf9`](https://github.com/Effect-TS/effect-smol/commit/388dcf953f65d317547f34d40e6443c5f264205f), [`2b7ce2b`](https://github.com/Effect-TS/effect-smol/commit/2b7ce2b513e7ec2a77822f1116dc6ffb6ba93f4e), [`87bea7e`](https://github.com/Effect-TS/effect-smol/commit/87bea7e16259246f3bcdf565446394751abca953), [`ce38dc3`](https://github.com/Effect-TS/effect-smol/commit/ce38dc33bda805a684432cca071f4dc3c6b9a1ba), [`a807cd1`](https://github.com/Effect-TS/effect-smol/commit/a807cd170341deca8a1cfb52c4222585f2431bb9), [`fd8a356`](https://github.com/Effect-TS/effect-smol/commit/fd8a356f06a8c9ce4e7e0a13fc4021c178ed31de), [`c2a5edc`](https://github.com/Effect-TS/effect-smol/commit/c2a5edc3abd31ad5bc123362bc1213e03e4095c3), [`5946da3`](https://github.com/Effect-TS/effect-smol/commit/5946da3804a1be5e752b05b96bd058cdba50a1bf), [`4ae0c5f`](https://github.com/Effect-TS/effect-smol/commit/4ae0c5ffcbe6c56ddfcb05c639112a079483539e), [`5b2a0bc`](https://github.com/Effect-TS/effect-smol/commit/5b2a0bceea3a28a33a58555210c90a415dc74a76), [`72ac585`](https://github.com/Effect-TS/effect-smol/commit/72ac585884befde6af9208da738699a93f1bae79), [`5e8c1b8`](https://github.com/Effect-TS/effect-smol/commit/5e8c1b82bfafa121311f987a49ab75395e3647a7), [`0f9c078`](https://github.com/Effect-TS/effect-smol/commit/0f9c07841b04183f485ee6e6458de73b290b09f5)]:
|
||||
- effect@4.0.0-beta.98
|
||||
- @effect/platform-node@4.0.0-beta.98
|
||||
|
||||
## 4.0.0-beta.97
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- effect@4.0.0-beta.97
|
||||
- @effect/platform-node@4.0.0-beta.97
|
||||
|
||||
## 4.0.0-beta.96
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`1503f45`](https://github.com/Effect-TS/effect-smol/commit/1503f45cb5bb2a74f4705252ec505a1f0ade7e62), [`57fe793`](https://github.com/Effect-TS/effect-smol/commit/57fe79316ffbc380b30626a168981fb26ae97459), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`0c2f78f`](https://github.com/Effect-TS/effect-smol/commit/0c2f78f695ec474e1ff5474da183577975e418f5), [`97f29df`](https://github.com/Effect-TS/effect-smol/commit/97f29df457f7ffd07cfb4b379315c12c086af805)]:
|
||||
- effect@4.0.0-beta.96
|
||||
- @effect/platform-node@4.0.0-beta.96
|
||||
|
||||
## 4.0.0-beta.95
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a482442`](https://github.com/Effect-TS/effect-smol/commit/a482442abdeb490e9652b854ec3495e4aa7273e7), [`fbefa85`](https://github.com/Effect-TS/effect-smol/commit/fbefa850fab2f0a302c20614496aeaaa2a8b5590), [`0b4a32f`](https://github.com/Effect-TS/effect-smol/commit/0b4a32f4260f0d8500942a133001b0d349328102), [`18a49e1`](https://github.com/Effect-TS/effect-smol/commit/18a49e1786679456258002ff9397faf02f678c2d), [`266cb90`](https://github.com/Effect-TS/effect-smol/commit/266cb90bb2c17aabc40563c32db334f09ba3d74b), [`912f095`](https://github.com/Effect-TS/effect-smol/commit/912f095a34572bbd3cedf6edb27878443e3e4a95), [`a6718f9`](https://github.com/Effect-TS/effect-smol/commit/a6718f9e00a15ca903b0732da46116cbf3d6aca7), [`bef5154`](https://github.com/Effect-TS/effect-smol/commit/bef51540a243aa2f872a00c01d0cd58b7a769baa), [`18e0564`](https://github.com/Effect-TS/effect-smol/commit/18e0564bd0f8ebbdfcaf1e2c21529948e9e4a81d), [`fb50f14`](https://github.com/Effect-TS/effect-smol/commit/fb50f14fc3657c1973785aa5b72ecf0b0d28e0b2)]:
|
||||
- effect@4.0.0-beta.95
|
||||
- @effect/platform-node@4.0.0-beta.95
|
||||
|
||||
## 4.0.0-beta.94
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`95a0e9b`](https://github.com/Effect-TS/effect-smol/commit/95a0e9bb62797af0e81c9998773405f248f218c5), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63), [`f11ce73`](https://github.com/Effect-TS/effect-smol/commit/f11ce73af60823754dc24194f4ffc561b9ea1c2d), [`ff30b6e`](https://github.com/Effect-TS/effect-smol/commit/ff30b6e7c2c63ffc56a4c5818d6d86b01b5ad528), [`1caab3c`](https://github.com/Effect-TS/effect-smol/commit/1caab3cc30f626efbf15e59d74f539a487e5c85c), [`aa80c47`](https://github.com/Effect-TS/effect-smol/commit/aa80c4775a04db87553e5568764cab7e32a72814), [`c2ae4fc`](https://github.com/Effect-TS/effect-smol/commit/c2ae4fce2f03a4cd1861c2b1179da7df656e662d), [`a0a3490`](https://github.com/Effect-TS/effect-smol/commit/a0a3490bbce765f199d8e077aceac504f0462e63)]:
|
||||
- effect@4.0.0-beta.94
|
||||
- @effect/platform-node@4.0.0-beta.94
|
||||
|
||||
## 4.0.0-beta.93
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`00652fe`](https://github.com/Effect-TS/effect-smol/commit/00652fe95c18f87208e91343eb8bf218faa2f677), [`6c58167`](https://github.com/Effect-TS/effect-smol/commit/6c5816746eaf91d2a3c7c899c5720809fa230ae3), [`2bc5415`](https://github.com/Effect-TS/effect-smol/commit/2bc541501a7ef89e542d7cb98e96beb53cd205cc), [`e11cccc`](https://github.com/Effect-TS/effect-smol/commit/e11cccc7d5fe631abccc7d6e3bd296938de0fa2e), [`ba7e77e`](https://github.com/Effect-TS/effect-smol/commit/ba7e77e046b8641a3a4e9750bb88ca4a1d063d3f), [`5713ee7`](https://github.com/Effect-TS/effect-smol/commit/5713ee7edbc3054efde407b2286bbfd45bbc6e1c)]:
|
||||
- effect@4.0.0-beta.93
|
||||
- @effect/platform-node@4.0.0-beta.93
|
||||
|
||||
## 4.0.0-beta.92
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`affdc13`](https://github.com/Effect-TS/effect-smol/commit/affdc139045cc325dce321a84a580fdc1b2da7b9)]:
|
||||
- effect@4.0.0-beta.92
|
||||
- @effect/platform-node@4.0.0-beta.92
|
||||
|
||||
## 4.0.0-beta.91
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`b135b25`](https://github.com/Effect-TS/effect-smol/commit/b135b2517fca9e7839734ace3699a7dfa75b9075), [`aaa21a3`](https://github.com/Effect-TS/effect-smol/commit/aaa21a369a171c600db294f2a4f640583043e150), [`3475ee6`](https://github.com/Effect-TS/effect-smol/commit/3475ee6c2bda6b05c6d7a12ce30c8bb840b5b1a6)]:
|
||||
- effect@4.0.0-beta.91
|
||||
- @effect/platform-node@4.0.0-beta.91
|
||||
|
||||
## 4.0.0-beta.90
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d237fdf`](https://github.com/Effect-TS/effect-smol/commit/d237fdf726481f76eb52a6196e111b24122bc3d5)]:
|
||||
- effect@4.0.0-beta.90
|
||||
- @effect/platform-node@4.0.0-beta.90
|
||||
|
||||
## 4.0.0-beta.89
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`b7d46ab`](https://github.com/Effect-TS/effect-smol/commit/b7d46ab7e1a29d8711817bab583c9febf48a0dad), [`7777e15`](https://github.com/Effect-TS/effect-smol/commit/7777e1540fd3680dd8346723cffec812b9384669), [`5376197`](https://github.com/Effect-TS/effect-smol/commit/5376197ca8e50358a41b1fd3cec27bd1ec680ec6)]:
|
||||
- effect@4.0.0-beta.89
|
||||
- @effect/platform-node@4.0.0-beta.89
|
||||
|
||||
## 4.0.0-beta.88
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`911f1b8`](https://github.com/Effect-TS/effect-smol/commit/911f1b84790ce42b3a70c95b33e6f6fd9e74de8b), [`8beeeea`](https://github.com/Effect-TS/effect-smol/commit/8beeeea52879d8613a39468848f01c3092bd54d4), [`c306fcf`](https://github.com/Effect-TS/effect-smol/commit/c306fcfeb1ef38455156932a1faf49292b1318da)]:
|
||||
- effect@4.0.0-beta.88
|
||||
- @effect/platform-node@4.0.0-beta.88
|
||||
|
||||
## 4.0.0-beta.87
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2469](https://github.com/Effect-TS/effect-smol/pull/2469) [`12fcf35`](https://github.com/Effect-TS/effect-smol/commit/12fcf35b92879f70a0e3b32b18359986439b9283) Thanks @jbmusso! - Fix the generated SSE `sseRequest` helper to reference `Schema.ConstraintDecoder` instead of the no-longer-exported `Schema.Decoder`.
|
||||
|
||||
For specs with `text/event-stream` responses the generator emitted a helper typed as `Schema.Decoder<Type, DecodingServices>`, but `Schema` exports that decode-only interface as `ConstraintDecoder`, so generated clients failed to compile (`'"effect/Schema"' has no exported member named 'Decoder'`). The emitted helper now uses `Schema.ConstraintDecoder`.
|
||||
|
||||
- Updated dependencies [[`5a0c1a4`](https://github.com/Effect-TS/effect-smol/commit/5a0c1a4faee5707b5cc35e646ff1ffdad70f1956), [`1eea2ea`](https://github.com/Effect-TS/effect-smol/commit/1eea2ea3795ba47316b82b1ac8d4612c0ba389ed)]:
|
||||
- effect@4.0.0-beta.87
|
||||
- @effect/platform-node@4.0.0-beta.87
|
||||
|
||||
## 4.0.0-beta.86
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`0b5795a`](https://github.com/Effect-TS/effect-smol/commit/0b5795a0ab4395e8f15955d8d96f2303084bfc64), [`3e3a859`](https://github.com/Effect-TS/effect-smol/commit/3e3a859ec6351a9e0d31674aabbd48fcefabb12e), [`7dbec24`](https://github.com/Effect-TS/effect-smol/commit/7dbec240dbf3bca599a20c486632abce694ef5ab), [`d8c00a1`](https://github.com/Effect-TS/effect-smol/commit/d8c00a171ac7141e8adc08c332d1162d9a9d56fc), [`85b6317`](https://github.com/Effect-TS/effect-smol/commit/85b631701e935866f2762bd595237aa718370cd9), [`28b4196`](https://github.com/Effect-TS/effect-smol/commit/28b4196390d3ab83be1567b65440919a9061fcc3), [`6d0fda0`](https://github.com/Effect-TS/effect-smol/commit/6d0fda0d0cbdfffc523c89c57dfdb1608f84fb12), [`108a933`](https://github.com/Effect-TS/effect-smol/commit/108a9335ff8571928197e5847a09c28ac83d6f46), [`7e1f455`](https://github.com/Effect-TS/effect-smol/commit/7e1f455fab5005d769b939c91e519d450f802cf9), [`46b3e79`](https://github.com/Effect-TS/effect-smol/commit/46b3e79944cfdae7901eb148135c85b7eb39834e)]:
|
||||
- effect@4.0.0-beta.86
|
||||
- @effect/platform-node@4.0.0-beta.86
|
||||
|
||||
## 4.0.0-beta.85
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`328d97c`](https://github.com/Effect-TS/effect-smol/commit/328d97cc53c0dcb89077a5623e35b095eaa59a8c), [`8441836`](https://github.com/Effect-TS/effect-smol/commit/8441836e6dde70e8ae2126be9cefe9b45798b134), [`074e436`](https://github.com/Effect-TS/effect-smol/commit/074e4361091289104cb0ab6959dc3b0ea7794a6a), [`c1dfd60`](https://github.com/Effect-TS/effect-smol/commit/c1dfd60663eb13a58916f3712d877499943b628a), [`2ba316b`](https://github.com/Effect-TS/effect-smol/commit/2ba316bd15fcbf1c50626500d44a2c9b3bec19f5), [`7ce7344`](https://github.com/Effect-TS/effect-smol/commit/7ce7344c41056c79e2ee19ee6a9346c0f1d227c1)]:
|
||||
- effect@4.0.0-beta.85
|
||||
- @effect/platform-node@4.0.0-beta.85
|
||||
|
||||
## 4.0.0-beta.84
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`87f52ba`](https://github.com/Effect-TS/effect-smol/commit/87f52ba16c4370ffa3f84bf8e53038e1419c284e), [`b8ee07f`](https://github.com/Effect-TS/effect-smol/commit/b8ee07ffda8903b5ec2e45a786ddcba59f128fda), [`867c0d7`](https://github.com/Effect-TS/effect-smol/commit/867c0d70a09079b040260d45a1e92ff04dbfbf2f), [`b93bc6c`](https://github.com/Effect-TS/effect-smol/commit/b93bc6c9cb27b909a41d094c97c4f9d25bbc6d6b), [`57d387f`](https://github.com/Effect-TS/effect-smol/commit/57d387f92c30ab63e15e3e641f0a903b65886610), [`bacca41`](https://github.com/Effect-TS/effect-smol/commit/bacca4141c2400effae1eabfdb36c89a459cf246), [`0f8ac79`](https://github.com/Effect-TS/effect-smol/commit/0f8ac7959d29ed68c68ce25aabd6bf0cb7e63ecc), [`25b4482`](https://github.com/Effect-TS/effect-smol/commit/25b448270c01317703f25107e1480d4cd0246d9a), [`9cf3a25`](https://github.com/Effect-TS/effect-smol/commit/9cf3a25c66b0c44a52be9829870c44517ea52db2), [`8def767`](https://github.com/Effect-TS/effect-smol/commit/8def7674b1787f91035298cda4d122937e87ef72)]:
|
||||
- effect@4.0.0-beta.84
|
||||
- @effect/platform-node@4.0.0-beta.84
|
||||
|
||||
## 4.0.0-beta.83
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`1f2e8ce`](https://github.com/Effect-TS/effect-smol/commit/1f2e8ceef09e0a791c850ed2ade01f97089596f9)]:
|
||||
- effect@4.0.0-beta.83
|
||||
- @effect/platform-node@4.0.0-beta.83
|
||||
|
||||
## 4.0.0-beta.82
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`193690b`](https://github.com/Effect-TS/effect-smol/commit/193690b642ea802bbed40d663bd677251bbe9dc3)]:
|
||||
- effect@4.0.0-beta.82
|
||||
- @effect/platform-node@4.0.0-beta.82
|
||||
|
||||
## 4.0.0-beta.81
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2270](https://github.com/Effect-TS/effect-smol/pull/2270) [`4500fbf`](https://github.com/Effect-TS/effect-smol/commit/4500fbfe00763d8a72af6e5d6c5988e8bd4ade36) Thanks @IMax153! - Add HTTP API streaming response support
|
||||
|
||||
- Updated dependencies [[`93cb4f8`](https://github.com/Effect-TS/effect-smol/commit/93cb4f8fbfb9e07cb9dc86ce6b155fd1f8167914), [`60341d9`](https://github.com/Effect-TS/effect-smol/commit/60341d9ca744d0473ce3fab621ca9bd225af3a39), [`1105ab5`](https://github.com/Effect-TS/effect-smol/commit/1105ab56cb724212f7ea7b431396ce82e8fd0484), [`4500fbf`](https://github.com/Effect-TS/effect-smol/commit/4500fbfe00763d8a72af6e5d6c5988e8bd4ade36)]:
|
||||
- effect@4.0.0-beta.81
|
||||
- @effect/platform-node@4.0.0-beta.81
|
||||
|
||||
## 4.0.0-beta.80
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d944330`](https://github.com/Effect-TS/effect-smol/commit/d94433090ee03f426d43e13b883abae4494e55e6), [`f48659f`](https://github.com/Effect-TS/effect-smol/commit/f48659fdcc84930ebc1e5b45b540c0f973389182), [`7652aaa`](https://github.com/Effect-TS/effect-smol/commit/7652aaa3bdbc39f241fe58b54b9a43b713e22e12), [`98630b7`](https://github.com/Effect-TS/effect-smol/commit/98630b7c8f679c352ba6796636c85688fa009d8d), [`90ae23c`](https://github.com/Effect-TS/effect-smol/commit/90ae23cf07284da5e1bcd9dffa882e85df7e617b)]:
|
||||
- effect@4.0.0-beta.80
|
||||
- @effect/platform-node@4.0.0-beta.80
|
||||
|
||||
## 4.0.0-beta.79
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2350](https://github.com/Effect-TS/effect-smol/pull/2350) [`3bbdf8c`](https://github.com/Effect-TS/effect-smol/commit/3bbdf8cbbdad27c889fa30436fdcfd8eeb606b6c) Thanks @wer416182-afk! - Declare `swagger2openapi` as a runtime dependency so published `openapigen` installs can resolve the converter imported by `OpenApiGenerator`.
|
||||
|
||||
- Updated dependencies [[`b9704dc`](https://github.com/Effect-TS/effect-smol/commit/b9704dc9de9f1649ad502371014fe869b69a49a3), [`a207113`](https://github.com/Effect-TS/effect-smol/commit/a207113f66837bb54416926718a9a7d66774d079), [`5e9b9e2`](https://github.com/Effect-TS/effect-smol/commit/5e9b9e217b164ebfd4a002dd4380b3b1563200c3), [`7c128ae`](https://github.com/Effect-TS/effect-smol/commit/7c128aef458a1e2d224712e51c483c9badad1d44), [`0ada457`](https://github.com/Effect-TS/effect-smol/commit/0ada457c0513d8d908254ab77ebb7d29d2b523d6), [`d7cc5a2`](https://github.com/Effect-TS/effect-smol/commit/d7cc5a2bede3de10943aa0c6bdb4f26836a91efd), [`aad63be`](https://github.com/Effect-TS/effect-smol/commit/aad63becf65e0a6b076e94f8973be7bbe7fbd46f), [`09809f6`](https://github.com/Effect-TS/effect-smol/commit/09809f60f19ec98232f98b33e33e02ecb7e4fbd6), [`2fddda5`](https://github.com/Effect-TS/effect-smol/commit/2fddda5311929f46b61e503f0ade4fc749e8c77d), [`5f21768`](https://github.com/Effect-TS/effect-smol/commit/5f2176833399757c4500d8875b7f2fba0393de75), [`f27003e`](https://github.com/Effect-TS/effect-smol/commit/f27003e00524ff83f20dd9909f62b2f8795efe03)]:
|
||||
- effect@4.0.0-beta.79
|
||||
- @effect/platform-node@4.0.0-beta.79
|
||||
|
||||
## 4.0.0-beta.78
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7836b8e`](https://github.com/Effect-TS/effect-smol/commit/7836b8eb8bb0f3e04cdf554ee070caccf74f00c1), [`35d49a3`](https://github.com/Effect-TS/effect-smol/commit/35d49a3a09bdba6b513de87ddcead9e61a1042ba), [`4093258`](https://github.com/Effect-TS/effect-smol/commit/40932580e65bafab5f23c5f14b520cb411d0b2cd)]:
|
||||
- effect@4.0.0-beta.78
|
||||
- @effect/platform-node@4.0.0-beta.78
|
||||
|
||||
## 4.0.0-beta.77
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`6e9a5ca`](https://github.com/Effect-TS/effect-smol/commit/6e9a5ca62a61156fd67b2518ad3ab14ac0d25f23), [`302f398`](https://github.com/Effect-TS/effect-smol/commit/302f3984ce206e35d86ddd99d3b72be144850a51)]:
|
||||
- effect@4.0.0-beta.77
|
||||
- @effect/platform-node@4.0.0-beta.77
|
||||
|
||||
## 4.0.0-beta.76
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`016108a`](https://github.com/Effect-TS/effect-smol/commit/016108a472af7048ddbbfd05f233e67529fafe12), [`95c03d2`](https://github.com/Effect-TS/effect-smol/commit/95c03d2c55930668c215b5a41c23cf7742fead84), [`07299a3`](https://github.com/Effect-TS/effect-smol/commit/07299a33c09fd52faa9810d30835a2622c752386)]:
|
||||
- effect@4.0.0-beta.76
|
||||
- @effect/platform-node@4.0.0-beta.76
|
||||
|
||||
## 4.0.0-beta.75
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`81b187c`](https://github.com/Effect-TS/effect-smol/commit/81b187c17a0d8817b58232826939154010ae49d7), [`ad4b535`](https://github.com/Effect-TS/effect-smol/commit/ad4b535e17f94ce35261829d5a3675f0a7808b4e), [`a29c2e7`](https://github.com/Effect-TS/effect-smol/commit/a29c2e7e3570920156702671d6f3367cd0195f6c), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`1fdd9ae`](https://github.com/Effect-TS/effect-smol/commit/1fdd9aeed92b6bb70987c862e7f6f66ead0339b3), [`ffea4ec`](https://github.com/Effect-TS/effect-smol/commit/ffea4ecf2925f6a4c9fd13079d47584cbf2bed00), [`4255c9b`](https://github.com/Effect-TS/effect-smol/commit/4255c9ba78bb98c7838fbe9dccdd8465e9da5427)]:
|
||||
- effect@4.0.0-beta.75
|
||||
- @effect/platform-node@4.0.0-beta.75
|
||||
|
||||
## 4.0.0-beta.74
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`b1fc6a4`](https://github.com/Effect-TS/effect-smol/commit/b1fc6a4b4d0ca7fa9fd162799ae17c86f2f7ee8e)]:
|
||||
- effect@4.0.0-beta.74
|
||||
- @effect/platform-node@4.0.0-beta.74
|
||||
|
||||
## 4.0.0-beta.73
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2292](https://github.com/Effect-TS/effect-smol/pull/2292) [`ba21055`](https://github.com/Effect-TS/effect-smol/commit/ba2105521173fbef145aa6d986bed1facb3bd94e) Thanks @tim-smart! - Add HttpApi generation support for custom OpenAPI HTTP security schemes.
|
||||
|
||||
- Updated dependencies [[`361ca30`](https://github.com/Effect-TS/effect-smol/commit/361ca30eb6e134feece547d6e00f82be4cb23f75), [`b9598c6`](https://github.com/Effect-TS/effect-smol/commit/b9598c6a209e75bfdb87ee3b024ecd1e3923ff6e)]:
|
||||
- effect@4.0.0-beta.73
|
||||
- @effect/platform-node@4.0.0-beta.73
|
||||
|
||||
## 4.0.0-beta.72
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`73e67d1`](https://github.com/Effect-TS/effect-smol/commit/73e67d119a84d697773eaecb4865c6a71eb1a9cb), [`01d71ec`](https://github.com/Effect-TS/effect-smol/commit/01d71ec5a75f3c2747a8d3b1ad9701d1e27b7ce5), [`fcd707e`](https://github.com/Effect-TS/effect-smol/commit/fcd707e091a16e1b35343c901cc4052274e32239)]:
|
||||
- effect@4.0.0-beta.72
|
||||
- @effect/platform-node@4.0.0-beta.72
|
||||
|
||||
## 4.0.0-beta.71
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d8ac76b`](https://github.com/Effect-TS/effect-smol/commit/d8ac76b5bad458c42cebe8a0c1b3843f955ac293), [`2c3c00a`](https://github.com/Effect-TS/effect-smol/commit/2c3c00af6faba7b7d422af26a7a2bbc35636d230), [`3751e7c`](https://github.com/Effect-TS/effect-smol/commit/3751e7cf353e7a54cd692c37401207d9afba1e63), [`fc5f25b`](https://github.com/Effect-TS/effect-smol/commit/fc5f25b03ada5fc2431987768a74d3d3e75ca485), [`7ccced4`](https://github.com/Effect-TS/effect-smol/commit/7ccced42867c14c013b01160b3d292f14c05bd04), [`a2e1fe5`](https://github.com/Effect-TS/effect-smol/commit/a2e1fe5835c98c8ee4393a091b1d11b75126e349), [`4a4a36b`](https://github.com/Effect-TS/effect-smol/commit/4a4a36b10e6e616cad07584a43908f6a7e07e618), [`d350292`](https://github.com/Effect-TS/effect-smol/commit/d3502922b4740fa9d745797cbc3775cb67839b6d), [`730afb6`](https://github.com/Effect-TS/effect-smol/commit/730afb66696adf9bd5a328cbca29df9c05968771), [`df1b008`](https://github.com/Effect-TS/effect-smol/commit/df1b008f370f414c2a67a7b8139ef747af8e5fba), [`6d469d5`](https://github.com/Effect-TS/effect-smol/commit/6d469d567a7c41d7e5343bdee21d45b07b0e8190)]:
|
||||
- effect@4.0.0-beta.71
|
||||
- @effect/platform-node@4.0.0-beta.71
|
||||
|
||||
## 4.0.0-beta.70
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`af7782d`](https://github.com/Effect-TS/effect-smol/commit/af7782d3008d08b043f3a3f261516001514b2b4e), [`7212d70`](https://github.com/Effect-TS/effect-smol/commit/7212d701a3eee7b3553ff502e2c066126e52e839)]:
|
||||
- effect@4.0.0-beta.70
|
||||
- @effect/platform-node@4.0.0-beta.70
|
||||
|
||||
## 4.0.0-beta.69
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`70ea04a`](https://github.com/Effect-TS/effect-smol/commit/70ea04aa96a2a7859d738d414e1f0e3ed081a27a), [`d0ea8b0`](https://github.com/Effect-TS/effect-smol/commit/d0ea8b03f7d73ae076c1db12666141e480d11178), [`a57674b`](https://github.com/Effect-TS/effect-smol/commit/a57674b64845e9e75a456cf907bfdcb858859118), [`59aa334`](https://github.com/Effect-TS/effect-smol/commit/59aa334fbd0a504dda3c36f6d2ef1be7449b4b8b), [`8f4208e`](https://github.com/Effect-TS/effect-smol/commit/8f4208ee83bc7bdaa6793b5429847b45aab72470)]:
|
||||
- effect@4.0.0-beta.69
|
||||
- @effect/platform-node@4.0.0-beta.69
|
||||
|
||||
## 4.0.0-beta.68
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`af8267f`](https://github.com/Effect-TS/effect-smol/commit/af8267f2f3588c3fb611e9286f6f933f29ce1217), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`0176eaf`](https://github.com/Effect-TS/effect-smol/commit/0176eaf3ecd7c1b99a10268f2af02d7e8ce161e5), [`f136bb7`](https://github.com/Effect-TS/effect-smol/commit/f136bb763048cbc6b17edd26496dba3e2415b9fa), [`6f38f07`](https://github.com/Effect-TS/effect-smol/commit/6f38f07d5941a211b251383aaab0f4f55e8a6557), [`aec9c40`](https://github.com/Effect-TS/effect-smol/commit/aec9c401a53db227f18bf5e0c84db7130ad862d6)]:
|
||||
- effect@4.0.0-beta.68
|
||||
- @effect/platform-node@4.0.0-beta.68
|
||||
|
||||
## 4.0.0-beta.67
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a42ef66`](https://github.com/Effect-TS/effect-smol/commit/a42ef6632abbddfa820995ae310ccc84ae8d9b6f), [`35594f8`](https://github.com/Effect-TS/effect-smol/commit/35594f811cafe471acd490114b103a1f8392c8d8), [`8bddd62`](https://github.com/Effect-TS/effect-smol/commit/8bddd628cb623f9533d345082583ff51cead6836), [`4be4c8d`](https://github.com/Effect-TS/effect-smol/commit/4be4c8d60862aa963869ee2ed9ffa048ffac0527), [`0c9d3ab`](https://github.com/Effect-TS/effect-smol/commit/0c9d3ab43eb721a370ed8306260cbac218c27e87), [`b156acc`](https://github.com/Effect-TS/effect-smol/commit/b156accd2691b4a051f823affdece7c39923ce85), [`d16c034`](https://github.com/Effect-TS/effect-smol/commit/d16c03434ee3e6dcd3bfc82b65d99e881d89025b), [`b559d68`](https://github.com/Effect-TS/effect-smol/commit/b559d68845f848a10153395778f035682d399075), [`a3de5d9`](https://github.com/Effect-TS/effect-smol/commit/a3de5d9215e5cc4a62e2666efbd7c1bf595eb84f), [`7e6c12e`](https://github.com/Effect-TS/effect-smol/commit/7e6c12ec9b3a5945f6c26e272cc8f6390541ad3e), [`098167a`](https://github.com/Effect-TS/effect-smol/commit/098167a220fe07da6f14455818733ab1b269c9dd)]:
|
||||
- effect@4.0.0-beta.67
|
||||
- @effect/platform-node@4.0.0-beta.67
|
||||
|
||||
## 4.0.0-beta.66
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ca2498e`](https://github.com/Effect-TS/effect-smol/commit/ca2498e702ac2d83fb7187707b7eb069bdb261a2), [`cd7d1fb`](https://github.com/Effect-TS/effect-smol/commit/cd7d1fba7e2e2c5ac3ad64e1be433440a5bda436), [`19a7033`](https://github.com/Effect-TS/effect-smol/commit/19a703367ec817cffc41d152da9b594827408e2b), [`33d26b4`](https://github.com/Effect-TS/effect-smol/commit/33d26b4210b2e974f146a71e7eed962f8ce00900), [`856766b`](https://github.com/Effect-TS/effect-smol/commit/856766b2c506aaed6d2df1d63bf3a5b1b062e1d4), [`079c7df`](https://github.com/Effect-TS/effect-smol/commit/079c7df82559bb9ce10a86dffb85d25e6ce07dc3)]:
|
||||
- effect@4.0.0-beta.66
|
||||
- @effect/platform-node@4.0.0-beta.66
|
||||
|
||||
## 4.0.0-beta.65
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`6f11454`](https://github.com/Effect-TS/effect-smol/commit/6f11454a9b6c3bd00f6b35fd7af14a2f2d63a0a2)]:
|
||||
- effect@4.0.0-beta.65
|
||||
- @effect/platform-node@4.0.0-beta.65
|
||||
|
||||
## 4.0.0-beta.64
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7d4877a`](https://github.com/Effect-TS/effect-smol/commit/7d4877a1929cdb690280ea254326c04f2ec97ea5)]:
|
||||
- effect@4.0.0-beta.64
|
||||
- @effect/platform-node@4.0.0-beta.64
|
||||
|
||||
## 4.0.0-beta.63
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7f927ff`](https://github.com/Effect-TS/effect-smol/commit/7f927ffb7a9801dcfc4096c29e369d13d65cd0ac), [`a696b3e`](https://github.com/Effect-TS/effect-smol/commit/a696b3e83a8504cdbe261a18c10a1cc0619ae102)]:
|
||||
- effect@4.0.0-beta.63
|
||||
- @effect/platform-node@4.0.0-beta.63
|
||||
|
||||
## 4.0.0-beta.62
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4ab4b90`](https://github.com/Effect-TS/effect-smol/commit/4ab4b9007dc27a52ffabc6fcb37c96eeec795bf7)]:
|
||||
- effect@4.0.0-beta.62
|
||||
- @effect/platform-node@4.0.0-beta.62
|
||||
|
||||
## 4.0.0-beta.61
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`50790af`](https://github.com/Effect-TS/effect-smol/commit/50790af9b190c38d10fb0723837d49b66432638f), [`71f7c3d`](https://github.com/Effect-TS/effect-smol/commit/71f7c3df997deda92c84146d569696dab3bd645c), [`aae8797`](https://github.com/Effect-TS/effect-smol/commit/aae8797b9cb383be0c182dd58d03d787c354238b)]:
|
||||
- effect@4.0.0-beta.61
|
||||
- @effect/platform-node@4.0.0-beta.61
|
||||
|
||||
## 4.0.0-beta.60
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`f69d567`](https://github.com/Effect-TS/effect-smol/commit/f69d5675dcff9f4137295752baf066b7153fdc09), [`7909c95`](https://github.com/Effect-TS/effect-smol/commit/7909c954b8f6244a35a4b429f8dd0dff45dad620), [`bbb4dcc`](https://github.com/Effect-TS/effect-smol/commit/bbb4dcc6c406b83a416b4ad3541cc02037c420e4), [`7af2207`](https://github.com/Effect-TS/effect-smol/commit/7af2207901eabf3132c1b7010a69b3899c06fbbe), [`848b40a`](https://github.com/Effect-TS/effect-smol/commit/848b40a4bd4bf54a5098617d50c33c88eee8270a)]:
|
||||
- effect@4.0.0-beta.60
|
||||
- @effect/platform-node@4.0.0-beta.60
|
||||
|
||||
## 4.0.0-beta.59
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`56837ea`](https://github.com/Effect-TS/effect-smol/commit/56837ea2a338395b35550641374e9e589bd8b71d)]:
|
||||
- effect@4.0.0-beta.59
|
||||
- @effect/platform-node@4.0.0-beta.59
|
||||
|
||||
## 4.0.0-beta.58
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`11993d4`](https://github.com/Effect-TS/effect-smol/commit/11993d4934c66f5dc611b8bbf553f01d501ef8f7), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec), [`96c8b22`](https://github.com/Effect-TS/effect-smol/commit/96c8b22c2057ccddbf10ed269d7697f22119b3ec)]:
|
||||
- effect@4.0.0-beta.58
|
||||
- @effect/platform-node@4.0.0-beta.58
|
||||
|
||||
## 4.0.0-beta.57
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a971f5c`](https://github.com/Effect-TS/effect-smol/commit/a971f5cbd92dfe4274420bf0966595eb35531060), [`8e110c5`](https://github.com/Effect-TS/effect-smol/commit/8e110c5f02a429ccc43a91df8678e402138c0851)]:
|
||||
- effect@4.0.0-beta.57
|
||||
- @effect/platform-node@4.0.0-beta.57
|
||||
|
||||
## 4.0.0-beta.56
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- effect@4.0.0-beta.56
|
||||
- @effect/platform-node@4.0.0-beta.56
|
||||
|
||||
## 4.0.0-beta.55
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`42cc744`](https://github.com/Effect-TS/effect-smol/commit/42cc744570968deb365fb46d47b53d3277050c93), [`04855ce`](https://github.com/Effect-TS/effect-smol/commit/04855ceeca4d40c55a5750dd9893b691f8ea741a)]:
|
||||
- effect@4.0.0-beta.55
|
||||
- @effect/platform-node@4.0.0-beta.55
|
||||
|
||||
## 4.0.0-beta.54
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`e4b74f9`](https://github.com/Effect-TS/effect-smol/commit/e4b74f9c01a0e9b6cd58416de4af3a26d51da7c8), [`4c72808`](https://github.com/Effect-TS/effect-smol/commit/4c728081851c66dacf889a816535671bc841ae96)]:
|
||||
- effect@4.0.0-beta.54
|
||||
- @effect/platform-node@4.0.0-beta.54
|
||||
|
||||
## 4.0.0-beta.53
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`0768509`](https://github.com/Effect-TS/effect-smol/commit/07685094e931af07d104165195826a535b55fa7e), [`476aede`](https://github.com/Effect-TS/effect-smol/commit/476aede69c6efa06b5781ca5eb3e3b128ca29141), [`4f79c54`](https://github.com/Effect-TS/effect-smol/commit/4f79c542e7b508c235ff485d862cc8b29a8260c5), [`4be6a7c`](https://github.com/Effect-TS/effect-smol/commit/4be6a7cf35dab2a01d652f56dd35f0358c5a7e88), [`88927eb`](https://github.com/Effect-TS/effect-smol/commit/88927ebb896162cdba103b36553280b58e0facac)]:
|
||||
- effect@4.0.0-beta.53
|
||||
- @effect/platform-node@4.0.0-beta.53
|
||||
|
||||
## 4.0.0-beta.52
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`cf3a311`](https://github.com/Effect-TS/effect-smol/commit/cf3a311d863a8abb818840c3b80f847e621c43c1), [`8e04bfc`](https://github.com/Effect-TS/effect-smol/commit/8e04bfc95554b74eac205d67a20388e056b21499), [`131fdd5`](https://github.com/Effect-TS/effect-smol/commit/131fdd5b1f26531e265fe1a08f002002f47c276e)]:
|
||||
- effect@4.0.0-beta.52
|
||||
- @effect/platform-node@4.0.0-beta.52
|
||||
|
||||
## 4.0.0-beta.51
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`778d2af`](https://github.com/Effect-TS/effect-smol/commit/778d2afe9b5154bc1f9abae46d93ea7e54c87344), [`4e24dcf`](https://github.com/Effect-TS/effect-smol/commit/4e24dcf75037f65eebc1eb68623bc7cbf9d5512a), [`4b1c015`](https://github.com/Effect-TS/effect-smol/commit/4b1c0150e9bdb5559ed32d250deb66e17b4240c7), [`454f8ad`](https://github.com/Effect-TS/effect-smol/commit/454f8adad822929c3ef60f8280d0987226b049fd), [`6754a0c`](https://github.com/Effect-TS/effect-smol/commit/6754a0cd18626b06805a079cc5265525a5eb7d27), [`90f7fd5`](https://github.com/Effect-TS/effect-smol/commit/90f7fd5243871b30980964135db4512b8119fa82), [`d7e1519`](https://github.com/Effect-TS/effect-smol/commit/d7e151974934201fd93fa4c8a1192ee9a5d965a0), [`72a8122`](https://github.com/Effect-TS/effect-smol/commit/72a81228e09782bae512f7d041bbfbc78bc668d0)]:
|
||||
- effect@4.0.0-beta.51
|
||||
- @effect/platform-node@4.0.0-beta.51
|
||||
|
||||
## 4.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`07be594`](https://github.com/Effect-TS/effect-smol/commit/07be594825de60f8e1b2102d21dbb9b8fc63b414), [`ae02433`](https://github.com/Effect-TS/effect-smol/commit/ae02433103ce28f53a0c9bfb4a44e75773289b7b)]:
|
||||
- effect@4.0.0-beta.50
|
||||
- @effect/platform-node@4.0.0-beta.50
|
||||
|
||||
## 4.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7d87873`](https://github.com/Effect-TS/effect-smol/commit/7d8787340ff549370f6f2a88b612e9ebbfd6ba45), [`c2f6f90`](https://github.com/Effect-TS/effect-smol/commit/c2f6f901b200a6e515b4f02c93ce8005b7bbf1c5), [`216f13c`](https://github.com/Effect-TS/effect-smol/commit/216f13c1fce454a21b489bb915714a17e791a1ac)]:
|
||||
- effect@4.0.0-beta.49
|
||||
- @effect/platform-node@4.0.0-beta.49
|
||||
|
||||
## 4.0.0-beta.48
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4da56ec`](https://github.com/Effect-TS/effect-smol/commit/4da56ecff129b2da40137ffede23a73cc4e532d8), [`a5e6f77`](https://github.com/Effect-TS/effect-smol/commit/a5e6f774bab195cf50ecdc818240765f69a3bf4a), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070), [`f1ba5b8`](https://github.com/Effect-TS/effect-smol/commit/f1ba5b8584d325a541156928cecf041b37fd5070)]:
|
||||
- effect@4.0.0-beta.48
|
||||
- @effect/platform-node@4.0.0-beta.48
|
||||
|
||||
## 4.0.0-beta.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`c584726`](https://github.com/Effect-TS/effect-smol/commit/c58472674e750e6938df955044eab88feda95e45), [`86a91a4`](https://github.com/Effect-TS/effect-smol/commit/86a91a4f0c59286dfa9393232d8020dea70ed4db), [`131caf9`](https://github.com/Effect-TS/effect-smol/commit/131caf9525151a0cb29803a8f1dffa0f4f479d12), [`c3615c8`](https://github.com/Effect-TS/effect-smol/commit/c3615c88379b9daf252df0db72c6ac5a20326406)]:
|
||||
- effect@4.0.0-beta.47
|
||||
- @effect/platform-node@4.0.0-beta.47
|
||||
|
||||
## 4.0.0-beta.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3a30b9e`](https://github.com/Effect-TS/effect-smol/commit/3a30b9e2ec2bd8b8193e1aa139f6878a07e3f5ee)]:
|
||||
- effect@4.0.0-beta.46
|
||||
- @effect/platform-node@4.0.0-beta.46
|
||||
|
||||
## 4.0.0-beta.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`5c3af6d`](https://github.com/Effect-TS/effect-smol/commit/5c3af6d554f60be34f8fc21d598d9a298ae11beb)]:
|
||||
- effect@4.0.0-beta.45
|
||||
- @effect/platform-node@4.0.0-beta.45
|
||||
|
||||
## 4.0.0-beta.44
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1910](https://github.com/Effect-TS/effect-smol/pull/1910) [`698296f`](https://github.com/Effect-TS/effect-smol/commit/698296f919859010dfcc713ad29927157f8aec00) Thanks @craigsmitham! - Support `application/x-www-form-urlencoded` request bodies in `httpclient` output format. Previously, form-urlencoded request bodies were silently dropped, producing operations with no payload parameter. The generator now emits `HttpClientRequest.bodyUrlParams` for these endpoints, matching the existing pattern for `multipart/form-data` (`bodyFormData`) and `application/json` (`bodyJsonUnsafe`). The `httpapi` format was already handling this content type correctly.
|
||||
|
||||
- [#1961](https://github.com/Effect-TS/effect-smol/pull/1961) [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970) Thanks @IMax153! - Rename the `ServiceMap` module to `Context` across exports, docs, and tests.
|
||||
|
||||
- Updated dependencies [[`e3f0621`](https://github.com/Effect-TS/effect-smol/commit/e3f0621454c3f5d11070d30619da27c9232cadc1), [`5b476ab`](https://github.com/Effect-TS/effect-smol/commit/5b476abc0bd7e9bb59135ea1bcad2e4936227ced), [`6b40e5a`](https://github.com/Effect-TS/effect-smol/commit/6b40e5a4a6bd2087c15a3d7374d25057fdedfa16), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`3b09fb3`](https://github.com/Effect-TS/effect-smol/commit/3b09fb31c40c2802b01f21c23bcdd1fe7fb0aa82), [`2370410`](https://github.com/Effect-TS/effect-smol/commit/237041062e5af4594d32db91597e34e70a632877), [`dabc272`](https://github.com/Effect-TS/effect-smol/commit/dabc272444a700eb629c07ba3e77671a841ca86e), [`08b63c3`](https://github.com/Effect-TS/effect-smol/commit/08b63c3df11bd35c9fd6090dbd166287fdc40664), [`dfff04c`](https://github.com/Effect-TS/effect-smol/commit/dfff04c4c2b1d352dfad83992a6dce1280c85cf9), [`9baed9e`](https://github.com/Effect-TS/effect-smol/commit/9baed9e17e84702e6e480fcef6f86404f9e24be9), [`7846792`](https://github.com/Effect-TS/effect-smol/commit/7846792adc7e1631d62d26d657bd7ba6139f369b), [`1556a24`](https://github.com/Effect-TS/effect-smol/commit/1556a247623636b7ebe438fb56d77f1a7bf957bb), [`7c11bc2`](https://github.com/Effect-TS/effect-smol/commit/7c11bc292ab8e46252fe8f7576fb685917bfb8b5), [`b5ea591`](https://github.com/Effect-TS/effect-smol/commit/b5ea5913ec1d45d0dd12a327b9dd966bda2f6d02), [`0853afa`](https://github.com/Effect-TS/effect-smol/commit/0853afaeb1633b2d7f8b66893bd01c3aa1ef2c22), [`ac845f3`](https://github.com/Effect-TS/effect-smol/commit/ac845f3ab40e0b8719576e7f9bc16ea2e0e02cd4), [`b80c462`](https://github.com/Effect-TS/effect-smol/commit/b80c46247480f47bb64fc480fab48a3f37bc8888), [`b3f535d`](https://github.com/Effect-TS/effect-smol/commit/b3f535d9a7ac13b5fb984c29f93561c57a081ff0), [`6fe2e93`](https://github.com/Effect-TS/effect-smol/commit/6fe2e93cc2f1b173ef89651d74b6a5d2626b3226), [`cda8004`](https://github.com/Effect-TS/effect-smol/commit/cda800451c1ffbdddfc08415aed7b2d91e0412ee), [`8335477`](https://github.com/Effect-TS/effect-smol/commit/8335477a8a936a24b5f3ee6203c1b268bd1bfc3c), [`8c836f9`](https://github.com/Effect-TS/effect-smol/commit/8c836f99ab1e896b9580a71d67773625baff2eaf), [`718ff6f`](https://github.com/Effect-TS/effect-smol/commit/718ff6fe3e3d3820cefd67d2bff1b2224fe08060), [`7eed84f`](https://github.com/Effect-TS/effect-smol/commit/7eed84fc33c5781a6fb11bf4fd189d424902ebd4), [`5df46fe`](https://github.com/Effect-TS/effect-smol/commit/5df46fe2f654d59ab5fc1578f4fc27fa40368ef9), [`82dd0f2`](https://github.com/Effect-TS/effect-smol/commit/82dd0f26c6442b07143762ef7bc33742d3978dd6), [`03ae41e`](https://github.com/Effect-TS/effect-smol/commit/03ae41e7304cffac9f18feea22b73468feafc43a), [`4677a0a`](https://github.com/Effect-TS/effect-smol/commit/4677a0a58f95eea38a211efcd3f345f237a9e44a), [`87e1fc8`](https://github.com/Effect-TS/effect-smol/commit/87e1fc8b67e4901d75f567b2fecc3841ab762cc4), [`c1af1b7`](https://github.com/Effect-TS/effect-smol/commit/c1af1b756f63291e9c0298cf95c98a6920a0c2a0), [`7bb5dce`](https://github.com/Effect-TS/effect-smol/commit/7bb5dce60e1d904ef049a0287dec2b2e6113c970), [`c8a877b`](https://github.com/Effect-TS/effect-smol/commit/c8a877b53e8f29616335719e5dd1c3992dddf780), [`7da961a`](https://github.com/Effect-TS/effect-smol/commit/7da961ae4916229d2246699a5d3b20e5b2dd2020)]:
|
||||
- effect@4.0.0-beta.44
|
||||
- @effect/platform-node@4.0.0-beta.44
|
||||
|
||||
## 4.0.0-beta.43
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`2ae33d0`](https://github.com/Effect-TS/effect-smol/commit/2ae33d050914915f7cb9c25ab0a020901e08d596), [`979811a`](https://github.com/Effect-TS/effect-smol/commit/979811a4c3f7ed21ed18ef560c49fb7f5569e80e), [`eb7dbef`](https://github.com/Effect-TS/effect-smol/commit/eb7dbeffa883386ad912815e62c0820cac1fdf8e), [`cf50eb4`](https://github.com/Effect-TS/effect-smol/commit/cf50eb49cb04706dae5185f624708117c413dee8), [`1d046fe`](https://github.com/Effect-TS/effect-smol/commit/1d046fe484560e23f3e22cb23eec6433f8f1fa02)]:
|
||||
- effect@4.0.0-beta.43
|
||||
- @effect/platform-node@4.0.0-beta.43
|
||||
|
||||
## 4.0.0-beta.42
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`924e216`](https://github.com/Effect-TS/effect-smol/commit/924e216caa7e0bbf22e994a0cd2ce8b1f0f0b3ee), [`80e7f0c`](https://github.com/Effect-TS/effect-smol/commit/80e7f0cd9116e811e97b0ce30a77a8d1ecd072aa), [`f8328bf`](https://github.com/Effect-TS/effect-smol/commit/f8328bf0314da3dc7f31d314f94a5840e8d5217f), [`66d1c06`](https://github.com/Effect-TS/effect-smol/commit/66d1c06039079129707a230f7ad8c676439d7133), [`bee800b`](https://github.com/Effect-TS/effect-smol/commit/bee800bf285192a01bec72a7b7b51bc1159434e6), [`8930441`](https://github.com/Effect-TS/effect-smol/commit/8930441dee6f94c59c583d18d3ebd677cf1f2623)]:
|
||||
- effect@4.0.0-beta.42
|
||||
- @effect/platform-node@4.0.0-beta.42
|
||||
|
||||
## 4.0.0-beta.41
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1852](https://github.com/Effect-TS/effect-smol/pull/1852) [`54769ed`](https://github.com/Effect-TS/effect-smol/commit/54769ed9aa8ee513bbdc4a15d51e2e4042e67394) Thanks @tim-smart! - Finalize the OpenAPI generator public migration by replacing the `typeOnly` option and `--type-only` CLI flag with the `format` option and `--format` flag, and by adding `httpapi` as a supported output alongside `httpclient` and `httpclient-type-only`.
|
||||
|
||||
- [#1852](https://github.com/Effect-TS/effect-smol/pull/1852) [`54769ed`](https://github.com/Effect-TS/effect-smol/commit/54769ed9aa8ee513bbdc4a15d51e2e4042e67394) Thanks @tim-smart! - Fix generated schema declaration ordering when non-recursive schemas reference recursive schemas, preventing TypeScript use-before-declaration errors in generated clients and HttpApi modules.
|
||||
|
||||
- Updated dependencies [[`36f5c21`](https://github.com/Effect-TS/effect-smol/commit/36f5c2174d31ab42c4598bf81f178f40d0802283), [`d8ce758`](https://github.com/Effect-TS/effect-smol/commit/d8ce758669d6297ae932ac3251d83e7b49b22f30), [`11aab4c`](https://github.com/Effect-TS/effect-smol/commit/11aab4c6d37d5691adafc2d33da1a631b28ce814), [`3bc1efb`](https://github.com/Effect-TS/effect-smol/commit/3bc1efb53dd75b4a40de46f1f80c7f8a7d50af86), [`70e724e`](https://github.com/Effect-TS/effect-smol/commit/70e724e604604d4be1061cd8da0d360494998c84), [`738dee7`](https://github.com/Effect-TS/effect-smol/commit/738dee7edfd70af82dc4d2376db3a8ebe603eb48), [`2111963`](https://github.com/Effect-TS/effect-smol/commit/2111963f19b4c28c800664a8fac9590c1321885f), [`198a553`](https://github.com/Effect-TS/effect-smol/commit/198a553d9ce45f6a00bfc4d65ed0640669602d95)]:
|
||||
- effect@4.0.0-beta.41
|
||||
- @effect/platform-node@4.0.0-beta.41
|
||||
|
||||
## 4.0.0-beta.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`f62860f`](https://github.com/Effect-TS/effect-smol/commit/f62860f0e5e45978fabf7256ae620a13152a772a), [`973f281`](https://github.com/Effect-TS/effect-smol/commit/973f2812529aadc1cc54598b2039799fa72b80f8)]:
|
||||
- effect@4.0.0-beta.40
|
||||
- @effect/platform-node@4.0.0-beta.40
|
||||
|
||||
## 4.0.0-beta.39
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`f91fd3d`](https://github.com/Effect-TS/effect-smol/commit/f91fd3db39fe5628439fd175fba201a65a1aa9d0), [`edaae9d`](https://github.com/Effect-TS/effect-smol/commit/edaae9d65f464f941d7eddd723cd33d324f4b071), [`b47db0b`](https://github.com/Effect-TS/effect-smol/commit/b47db0bd5802064b6a24b3ea27c6ff2e0520d513), [`82d3c8e`](https://github.com/Effect-TS/effect-smol/commit/82d3c8e4f3f49b00df611b25aa6f8f74ec21b59b), [`7c22b31`](https://github.com/Effect-TS/effect-smol/commit/7c22b315d198dcbf44ae8cdb8b37879e1c9e3996)]:
|
||||
- effect@4.0.0-beta.39
|
||||
- @effect/platform-node@4.0.0-beta.39
|
||||
|
||||
## 4.0.0-beta.38
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`f4dbe5b`](https://github.com/Effect-TS/effect-smol/commit/f4dbe5b26b9c2d33fae024bf44afbdf8541792cd), [`a71a607`](https://github.com/Effect-TS/effect-smol/commit/a71a607c89fb6669a12a562c2c23be81dfbe1adb), [`66a0494`](https://github.com/Effect-TS/effect-smol/commit/66a0494ed75cd12f2721dcbb1d8a072e3d9e14b6), [`5ef7218`](https://github.com/Effect-TS/effect-smol/commit/5ef7218fc559d57301fe929b8a0cab4033f4f1fd), [`472d260`](https://github.com/Effect-TS/effect-smol/commit/472d260655bc311fba5c2c6e23bb77d8f7e36ba0)]:
|
||||
- effect@4.0.0-beta.38
|
||||
- @effect/platform-node@4.0.0-beta.38
|
||||
|
||||
## 4.0.0-beta.37
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`f7a0b71`](https://github.com/Effect-TS/effect-smol/commit/f7a0b711da8fdd645597dee29cacc5619c6afcf2), [`1e223c3`](https://github.com/Effect-TS/effect-smol/commit/1e223c30ccf835dfbb21284535d78549efaeca80), [`53740f4`](https://github.com/Effect-TS/effect-smol/commit/53740f47aa76d114b7d535649fb50efc54a09608), [`8c7cf89`](https://github.com/Effect-TS/effect-smol/commit/8c7cf89f719e580cbce1bf6c24e6996f1992a0a6), [`b6b81a9`](https://github.com/Effect-TS/effect-smol/commit/b6b81a940eaafcbc792d25413d6c02c707de31b2), [`8f4c1f9`](https://github.com/Effect-TS/effect-smol/commit/8f4c1f97ed60f8810b0b327b50117ffb2d8260d4), [`f2479f9`](https://github.com/Effect-TS/effect-smol/commit/f2479f9d3113b1f012db17a3852b4e28f478cf9c), [`c919921`](https://github.com/Effect-TS/effect-smol/commit/c9199217fad65529421d2cf95ecfff41257090fd), [`7af90c2`](https://github.com/Effect-TS/effect-smol/commit/7af90c2e3c99038eafa39650433839523790e2fe), [`f3be185`](https://github.com/Effect-TS/effect-smol/commit/f3be18569e5ca57c25eabf00df3ca601ebab43c7)]:
|
||||
- effect@4.0.0-beta.37
|
||||
- @effect/platform-node@4.0.0-beta.37
|
||||
|
||||
## 4.0.0-beta.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`60fcbcc`](https://github.com/Effect-TS/effect-smol/commit/60fcbcc43d09471e8f7e0969955d99dcefc5be81), [`0a60837`](https://github.com/Effect-TS/effect-smol/commit/0a6083713124440e630030375bab367e8d7df24e), [`49164d2`](https://github.com/Effect-TS/effect-smol/commit/49164d2c20a8d21b66514992c4a15d8521f6b36e), [`334b6e4`](https://github.com/Effect-TS/effect-smol/commit/334b6e4f76fe11941b516d61f57e268bc31f0ca6), [`5700695`](https://github.com/Effect-TS/effect-smol/commit/5700695f76ae6da6b94c9c87d4dd2b8054fb829b), [`f8f4456`](https://github.com/Effect-TS/effect-smol/commit/f8f445644f3aa7ec093cab7445198a62ba18a480), [`969d24f`](https://github.com/Effect-TS/effect-smol/commit/969d24fdfa48c4838e811983848d9cb4e9b3b12c), [`851eda0`](https://github.com/Effect-TS/effect-smol/commit/851eda0533946e39bacaaf581896320d7a4f3e8c), [`8059c1c`](https://github.com/Effect-TS/effect-smol/commit/8059c1c3eba9a90af7cd889ea261bcb8fff0c185), [`6f83295`](https://github.com/Effect-TS/effect-smol/commit/6f8329546a73eaddc7cb5e85ea8e37e73fbfb611), [`65f7f57`](https://github.com/Effect-TS/effect-smol/commit/65f7f5737575fed668987462c96d29a446707c32), [`e7fabd2`](https://github.com/Effect-TS/effect-smol/commit/e7fabd2265db690eae5cfc9b83730c84699aef61), [`89c3e98`](https://github.com/Effect-TS/effect-smol/commit/89c3e985401eb38f33a3ae21a94ad27de3c1d28b), [`53794ab`](https://github.com/Effect-TS/effect-smol/commit/53794ab7af30aa5c5004ecf53659fafbe4b10542)]:
|
||||
- effect@4.0.0-beta.36
|
||||
- @effect/platform-node@4.0.0-beta.36
|
||||
|
||||
## 4.0.0-beta.35
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`9252b43`](https://github.com/Effect-TS/effect-smol/commit/9252b43560f507709c2985abcf52a7837b23ddf8), [`7daf387`](https://github.com/Effect-TS/effect-smol/commit/7daf3870a656882a488a60f67881e6808c8f4d04), [`e1664a3`](https://github.com/Effect-TS/effect-smol/commit/e1664a38bc31ef4ceb4e9324c7226e1e99bf9c07), [`fdaa6e0`](https://github.com/Effect-TS/effect-smol/commit/fdaa6e0a41b6b6605438fa8557441792135380a2), [`19aa47e`](https://github.com/Effect-TS/effect-smol/commit/19aa47ef7b470e427620edca8970dd9cdd551216), [`c667dad`](https://github.com/Effect-TS/effect-smol/commit/c667dad07777b860e4764a3ba9a6cc41c236cd98), [`764d150`](https://github.com/Effect-TS/effect-smol/commit/764d1501bc5026b60fc8aef6cb02a5a87c762801), [`3c27098`](https://github.com/Effect-TS/effect-smol/commit/3c27098b5685a63db2c2eff654a250c94d3fcfa7), [`3015c2d`](https://github.com/Effect-TS/effect-smol/commit/3015c2dc25fb44694978b4ff921af9b24178fcc0)]:
|
||||
- effect@4.0.0-beta.35
|
||||
- @effect/platform-node@4.0.0-beta.35
|
||||
|
||||
## 4.0.0-beta.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`f2f75ee`](https://github.com/Effect-TS/effect-smol/commit/f2f75ee564bce1cd95f5189c7bdeeed4f92dacb1), [`342fc4b`](https://github.com/Effect-TS/effect-smol/commit/342fc4b051739e32e7977159f26ff9541eda664f), [`5d704ee`](https://github.com/Effect-TS/effect-smol/commit/5d704ee10d20e8eb107e34bb8a21feb5aa4a7685), [`00add69`](https://github.com/Effect-TS/effect-smol/commit/00add69b59551e9df34772eb927638b093f6d71e), [`58217d3`](https://github.com/Effect-TS/effect-smol/commit/58217d318a7d716ccd707cce0f41573946939c28), [`f4e2aba`](https://github.com/Effect-TS/effect-smol/commit/f4e2aba01b76d1e3059b297e3cc942284dfeafb2), [`e3b44b6`](https://github.com/Effect-TS/effect-smol/commit/e3b44b6a2af9ee21dc5c1e928f0c20af857fa7a9), [`e1472b7`](https://github.com/Effect-TS/effect-smol/commit/e1472b7525c5d57a48bdec2353c3b742f7f916c0), [`7686320`](https://github.com/Effect-TS/effect-smol/commit/7686320cd123fa352b5c3d076fb18a3cac0a9bba)]:
|
||||
- effect@4.0.0-beta.34
|
||||
- @effect/platform-node@4.0.0-beta.34
|
||||
|
||||
## 4.0.0-beta.33
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`571447d`](https://github.com/Effect-TS/effect-smol/commit/571447da67334449f8ae3d6ecb3d77ea4e0c4295)]:
|
||||
- effect@4.0.0-beta.33
|
||||
- @effect/platform-node@4.0.0-beta.33
|
||||
|
||||
## 4.0.0-beta.32
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`bf8fff8`](https://github.com/Effect-TS/effect-smol/commit/bf8fff8a5f54b6df74cb7bbb42346fe9ba52435a), [`1af3ef3`](https://github.com/Effect-TS/effect-smol/commit/1af3ef3e3ca7fd417d0fc15f8ca8fe207eba4f74), [`27fea0f`](https://github.com/Effect-TS/effect-smol/commit/27fea0f66910de5905f40fd63f8ddbb6f7ac5aba), [`2ad6c1b`](https://github.com/Effect-TS/effect-smol/commit/2ad6c1b2c85a3a0fe351e3d56636a75eb76b4b4e), [`398ac3e`](https://github.com/Effect-TS/effect-smol/commit/398ac3e01cb75efce0e4e2913d1450cf65866732), [`51fe22f`](https://github.com/Effect-TS/effect-smol/commit/51fe22f3266e417b6c541aaed4b75d246fac91e7), [`4605db6`](https://github.com/Effect-TS/effect-smol/commit/4605db69cfacddbdbf1525865ddfde135158090c), [`f4de1b0`](https://github.com/Effect-TS/effect-smol/commit/f4de1b087c998d0bad1d9468f70b7d16c13b9f6f), [`60214f2`](https://github.com/Effect-TS/effect-smol/commit/60214f2080b2aeb091f691140eb20acb741691c3), [`c4b8b0f`](https://github.com/Effect-TS/effect-smol/commit/c4b8b0ffa8efb47c4cd7578a8943d6868509373f), [`6d9393a`](https://github.com/Effect-TS/effect-smol/commit/6d9393a0770a18722d23340e77f15455de341245), [`6de4efe`](https://github.com/Effect-TS/effect-smol/commit/6de4efe463c783614ceb0c094d77a336a899cbe0), [`4f969d1`](https://github.com/Effect-TS/effect-smol/commit/4f969d1563ba755ffa116c8ae409bb3436bd881d), [`6cc67c8`](https://github.com/Effect-TS/effect-smol/commit/6cc67c855e054ee3f3ac3485dca5f7805e79e8fb), [`8531a22`](https://github.com/Effect-TS/effect-smol/commit/8531a22ffbb52e11a030b09f358cafbfdf5edff7), [`b226760`](https://github.com/Effect-TS/effect-smol/commit/b22676067617f15c00722a3a63fd7c2c172c3d45), [`47a51ab`](https://github.com/Effect-TS/effect-smol/commit/47a51aba0ecdf3ef478bfa28a498bca188399bd4), [`1521d02`](https://github.com/Effect-TS/effect-smol/commit/1521d02e1f19f1d795edaaf862c1a1031d9c755e)]:
|
||||
- effect@4.0.0-beta.32
|
||||
- @effect/platform-node@4.0.0-beta.32
|
||||
|
||||
## 4.0.0-beta.31
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6f23f0e`](https://github.com/Effect-TS/effect-smol/commit/6f23f0ed4cba573cd9395c2e582f582fe7271544), [`654aaec`](https://github.com/Effect-TS/effect-smol/commit/654aaec593305521b65dd042c204d761cc6e8c28), [`2958a42`](https://github.com/Effect-TS/effect-smol/commit/2958a42078966a8713a98f00485ab36484d5eccf), [`95d27a2`](https://github.com/Effect-TS/effect-smol/commit/95d27a239ed5147302605ab0b3147a056541b0c7), [`0fbaea8`](https://github.com/Effect-TS/effect-smol/commit/0fbaea8f9555a8044cec31a770394db613fc78e2), [`21d5d5e`](https://github.com/Effect-TS/effect-smol/commit/21d5d5e0439fd4d9bb6e508377215b1087555d45), [`5a84853`](https://github.com/Effect-TS/effect-smol/commit/5a8485397b7f321ae021640c1999821143659462), [`6e49959`](https://github.com/Effect-TS/effect-smol/commit/6e499590357a104c81779b3176cd3f84e4f91064), [`8f5805d`](https://github.com/Effect-TS/effect-smol/commit/8f5805dbdd0d1bc0ff0727cc398c8d80e544edee), [`990df2c`](https://github.com/Effect-TS/effect-smol/commit/990df2c3ceeb32e659acc10cc9485617f7b3c423)]:
|
||||
- effect@4.0.0-beta.31
|
||||
- @effect/platform-node@4.0.0-beta.31
|
||||
|
||||
## 4.0.0-beta.30
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`c88e5b7`](https://github.com/Effect-TS/effect-smol/commit/c88e5b723ff09da4edaef6ce14d927ca01104a32), [`947d0e4`](https://github.com/Effect-TS/effect-smol/commit/947d0e4268ba5c4020ead380aa80812c7342408f), [`7517908`](https://github.com/Effect-TS/effect-smol/commit/75179085d159b88a1ab0bce70669d76dcf0d79a4), [`a49ecd5`](https://github.com/Effect-TS/effect-smol/commit/a49ecd5a183d7e7d33f47ff95e9d2dea5a12ead5), [`6993e33`](https://github.com/Effect-TS/effect-smol/commit/6993e3329122c834c20bacea72d8678232f4f103), [`514f2a2`](https://github.com/Effect-TS/effect-smol/commit/514f2a2ae54580fcacdbe2ea2196a83a852d0748), [`3214b47`](https://github.com/Effect-TS/effect-smol/commit/3214b47676de2d33fddc5fecfc2d226e6e83cc7b), [`95ec5ed`](https://github.com/Effect-TS/effect-smol/commit/95ec5ed345de77c893049e182d37a37cf164a268)]:
|
||||
- effect@4.0.0-beta.30
|
||||
- @effect/platform-node@4.0.0-beta.30
|
||||
|
||||
## 4.0.0-beta.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`9d93adb`](https://github.com/Effect-TS/effect-smol/commit/9d93adb1c1795d1978391b30d7d2972c88052662), [`b52721c`](https://github.com/Effect-TS/effect-smol/commit/b52721cf0d11a567722b060c8536e3bdd4161f07), [`a891c7b`](https://github.com/Effect-TS/effect-smol/commit/a891c7b12f415b2287613dd4b91a09dfd38ef30d), [`ef26cdf`](https://github.com/Effect-TS/effect-smol/commit/ef26cdfb65d9955fc7e161629191930c2cc2c63f), [`82fd3ed`](https://github.com/Effect-TS/effect-smol/commit/82fd3ed922063ee5a34f96f3993c15c7515e4f67)]:
|
||||
- effect@4.0.0-beta.29
|
||||
- @effect/platform-node@4.0.0-beta.29
|
||||
|
||||
## 4.0.0-beta.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ff533f2`](https://github.com/Effect-TS/effect-smol/commit/ff533f203cd06302ad08032a27e01269b4a2d4c6), [`dc803ee`](https://github.com/Effect-TS/effect-smol/commit/dc803ee52ebd3e9f931118f0dfcb804542847556), [`d660b1c`](https://github.com/Effect-TS/effect-smol/commit/d660b1c99cb93d4f79715e91c7a4486801c0eefa), [`93a05e3`](https://github.com/Effect-TS/effect-smol/commit/93a05e3eaa624058b162aedd66aad70102837270), [`2a65cf6`](https://github.com/Effect-TS/effect-smol/commit/2a65cf6fd81ef63d944e6fb51f058d439bf4a834), [`a561a40`](https://github.com/Effect-TS/effect-smol/commit/a561a40cc41c548c2cf3153aca065ee92ee8aa57), [`29cd24d`](https://github.com/Effect-TS/effect-smol/commit/29cd24d1fe78480a72eeb38a90281ffddc0530bc), [`662a8e6`](https://github.com/Effect-TS/effect-smol/commit/662a8e6857dac64a7cd13bd8df4b0674654622f8), [`d2b52ba`](https://github.com/Effect-TS/effect-smol/commit/d2b52bae5b9336cf59729fbdcc4d7f09512b0cbf), [`407c3b4`](https://github.com/Effect-TS/effect-smol/commit/407c3b43a5d1414558e0e33b6f1fc0e6a6d489cc), [`42bc7ce`](https://github.com/Effect-TS/effect-smol/commit/42bc7ce5480f6f2953c39f8cb5c850d61df6f5a2), [`e741322`](https://github.com/Effect-TS/effect-smol/commit/e74132226cbfee24234311c7c1c13e6b7391384e), [`5c75fa8`](https://github.com/Effect-TS/effect-smol/commit/5c75fa8fb71163bc4c035ba1a215574dfd4badfc), [`747177b`](https://github.com/Effect-TS/effect-smol/commit/747177b0602f12d4461a843e953dfdffbeb0a429), [`326cd48`](https://github.com/Effect-TS/effect-smol/commit/326cd4828bce573fe985f35152155464bf4c5a70), [`627e922`](https://github.com/Effect-TS/effect-smol/commit/627e922b8d1e9521eae5e1caa5d667ad00b1619a), [`662287e`](https://github.com/Effect-TS/effect-smol/commit/662287e9abc76c941ccc2ee330aa07904d571341)]:
|
||||
- effect@4.0.0-beta.28
|
||||
- @effect/platform-node@4.0.0-beta.28
|
||||
|
||||
## 4.0.0-beta.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`903a839`](https://github.com/Effect-TS/effect-smol/commit/903a839e94239e6ec4568315af28e405bcad95f4), [`91a0168`](https://github.com/Effect-TS/effect-smol/commit/91a016836680a6669308ecf464d3584bcc4ae1b7), [`c890f9a`](https://github.com/Effect-TS/effect-smol/commit/c890f9a1b3a989ed22528bd5a43326342e05b142), [`1e985f2`](https://github.com/Effect-TS/effect-smol/commit/1e985f237d250b51b91de22dde77160c1e778ce7)]:
|
||||
- effect@4.0.0-beta.27
|
||||
- @effect/platform-node@4.0.0-beta.27
|
||||
|
||||
## 4.0.0-beta.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`fb21462`](https://github.com/Effect-TS/effect-smol/commit/fb21462642cdd5b1bada92f3eba18ae20445be42), [`2ed26b1`](https://github.com/Effect-TS/effect-smol/commit/2ed26b139805700e3df39efaa768ff01565e5c86), [`e832a57`](https://github.com/Effect-TS/effect-smol/commit/e832a57b570fe38f010c1fd99bceac5a325a9e07), [`7f01be7`](https://github.com/Effect-TS/effect-smol/commit/7f01be7f8db363d4b2e88e6b5571e96bb815786f), [`e965143`](https://github.com/Effect-TS/effect-smol/commit/e9651431e114479e6becf8ca7b1ed99ac7e91ccc), [`b9b80f1`](https://github.com/Effect-TS/effect-smol/commit/b9b80f1f15e152ceef0a727d150b7dc230abae99), [`98252aa`](https://github.com/Effect-TS/effect-smol/commit/98252aa0c0b17fc73fbdad65d0a1104965f9fc0f), [`56fbd94`](https://github.com/Effect-TS/effect-smol/commit/56fbd94311ad19a05001ad649d9e34ab00c74541), [`3faa109`](https://github.com/Effect-TS/effect-smol/commit/3faa109b7d093fbf14ad410d3e11d663f16e28f1), [`692ecfe`](https://github.com/Effect-TS/effect-smol/commit/692ecfed99fe58056b7a5afe001f4fcd1a61c446), [`1e70b72`](https://github.com/Effect-TS/effect-smol/commit/1e70b72d0b210474d0e96a15a5cfc279eae37e0c), [`ecf0782`](https://github.com/Effect-TS/effect-smol/commit/ecf07829ef2dfc01d8943c96c4fe9c1b44b97926)]:
|
||||
- effect@4.0.0-beta.26
|
||||
- @effect/platform-node@4.0.0-beta.26
|
||||
|
||||
## 4.0.0-beta.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`fa17bb5`](https://github.com/Effect-TS/effect-smol/commit/fa17bb5be9f2533d01e11322b14804c7dec43714), [`f46e5b5`](https://github.com/Effect-TS/effect-smol/commit/f46e5b5ca2a918ee4d9270167e79db223077c96f), [`ce4767c`](https://github.com/Effect-TS/effect-smol/commit/ce4767cadcacc6ce8ff4c3a0d0fbc82ede655f63), [`c830a8b`](https://github.com/Effect-TS/effect-smol/commit/c830a8b6c292a6528d7f9318759d34800b00372d)]:
|
||||
- effect@4.0.0-beta.25
|
||||
- @effect/platform-node@4.0.0-beta.25
|
||||
|
||||
## 4.0.0-beta.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a909e1c`](https://github.com/Effect-TS/effect-smol/commit/a909e1c1ac2bc707527f5073776e3e7d239688d9), [`8814a4e`](https://github.com/Effect-TS/effect-smol/commit/8814a4ef78d67144d27689370af10099ea210399), [`3f942c5`](https://github.com/Effect-TS/effect-smol/commit/3f942c51cefa7b2ffa7c49e8c8a2c887570ba4c0), [`774ed59`](https://github.com/Effect-TS/effect-smol/commit/774ed59c52b2ab578bbb897c4f551f812231e1d2), [`f54b8d3`](https://github.com/Effect-TS/effect-smol/commit/f54b8d398fedad1815fd1f4c49814ab938cfc385)]:
|
||||
- effect@4.0.0-beta.24
|
||||
- @effect/platform-node@4.0.0-beta.24
|
||||
|
||||
## 4.0.0-beta.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`5c73c41`](https://github.com/Effect-TS/effect-smol/commit/5c73c41b69eaeab80fcd62c9bfda490b446d1966)]:
|
||||
- effect@4.0.0-beta.23
|
||||
- @effect/platform-node@4.0.0-beta.23
|
||||
|
||||
## 4.0.0-beta.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`0874332`](https://github.com/Effect-TS/effect-smol/commit/0874332f7c81118b06ac2eb105e0710211631479), [`c592dcd`](https://github.com/Effect-TS/effect-smol/commit/c592dcde0697e322065c8f418c0480ef910cb183), [`1dbe28d`](https://github.com/Effect-TS/effect-smol/commit/1dbe28dac8299cd3e218c9768450cfd173b5e294), [`564d730`](https://github.com/Effect-TS/effect-smol/commit/564d730b6bbf38dd8548a3b046e7a693b28699a4), [`3cfadc4`](https://github.com/Effect-TS/effect-smol/commit/3cfadc458b070c6cba6c5674b72a059f1e49118b), [`6634fd0`](https://github.com/Effect-TS/effect-smol/commit/6634fd07da067d80b8261fb2959d1a952b9e412e), [`d10dabe`](https://github.com/Effect-TS/effect-smol/commit/d10dabeb7af9a368f995829cd36ad08167cd8f95), [`f82f549`](https://github.com/Effect-TS/effect-smol/commit/f82f549a09e950e9d4987f279a800f4d953f0939), [`78a3382`](https://github.com/Effect-TS/effect-smol/commit/78a3382ddfbe034408f7480fa794733d9e82147b)]:
|
||||
- effect@4.0.0-beta.22
|
||||
- @effect/platform-node@4.0.0-beta.22
|
||||
|
||||
## 4.0.0-beta.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`e691909`](https://github.com/Effect-TS/effect-smol/commit/e691909495ccb162ea7bfa351dd74632b99997cb), [`d5f413f`](https://github.com/Effect-TS/effect-smol/commit/d5f413f3c8fc57f2413cc5649c2003d6d4e5a6d7), [`139d152`](https://github.com/Effect-TS/effect-smol/commit/139d152941e562a073b5be12e8d66c8a4d4a8a57), [`947e3d4`](https://github.com/Effect-TS/effect-smol/commit/947e3d436ab8a017efda9b29be523efd1ca8df28), [`84b2cce`](https://github.com/Effect-TS/effect-smol/commit/84b2ccefe2aa3a7413b86738a4dc33cdb311ca55), [`7f5305e`](https://github.com/Effect-TS/effect-smol/commit/7f5305e69f5a33309e77b08a576edb25d7daaee2), [`9e6fd84`](https://github.com/Effect-TS/effect-smol/commit/9e6fd8471c93a3c643929151a3bdb62cb9c0ca0e), [`fdb8a4b`](https://github.com/Effect-TS/effect-smol/commit/fdb8a4b172721fbefe98bd5aa6fe4f0efd1da3eb), [`0f986ef`](https://github.com/Effect-TS/effect-smol/commit/0f986ef22f196fe091a7afdbd179485a7d888882), [`9355fc0`](https://github.com/Effect-TS/effect-smol/commit/9355fc0ffb5b7382146a5aed9eea83974b10d007)]:
|
||||
- effect@4.0.0-beta.21
|
||||
- @effect/platform-node@4.0.0-beta.21
|
||||
|
||||
## 4.0.0-beta.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`842a624`](https://github.com/Effect-TS/effect-smol/commit/842a624f79d5e1407460b0ef3ab27d14d48ccf74), [`4785eef`](https://github.com/Effect-TS/effect-smol/commit/4785eef5d7cf1edb96ef2509aed2ba4d1edf3862), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`12ee8e2`](https://github.com/Effect-TS/effect-smol/commit/12ee8e27df7eb393d83a5e403390d0cfc82ca732), [`e542c94`](https://github.com/Effect-TS/effect-smol/commit/e542c942bee4729138b02222f4421220a90a57d8), [`8fac95b`](https://github.com/Effect-TS/effect-smol/commit/8fac95bd9e0338b7a82da8da579c1ac22afa045c), [`6f4ebd1`](https://github.com/Effect-TS/effect-smol/commit/6f4ebd193c2595983394127dd808601b75430d34), [`989d1cc`](https://github.com/Effect-TS/effect-smol/commit/989d1cca936fce0cc459057825ba40e3f5ef3827)]:
|
||||
- effect@4.0.0-beta.20
|
||||
- @effect/platform-node@4.0.0-beta.20
|
||||
|
||||
## 4.0.0-beta.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- effect@4.0.0-beta.19
|
||||
- @effect/platform-node@4.0.0-beta.19
|
||||
|
||||
## 4.0.0-beta.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`01e31fd`](https://github.com/Effect-TS/effect-smol/commit/01e31fdf8e5206849d23cbafd23a346f2f177ab8), [`0890aab`](https://github.com/Effect-TS/effect-smol/commit/0890aab15ed9c5ba52c383a72fdc6a444d7504d5), [`725260b`](https://github.com/Effect-TS/effect-smol/commit/725260b53f5142d6af7a93a2f9f464f974eda92d)]:
|
||||
- effect@4.0.0-beta.18
|
||||
- @effect/platform-node@4.0.0-beta.18
|
||||
|
||||
## 4.0.0-beta.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`8f59c32`](https://github.com/Effect-TS/effect-smol/commit/8f59c32922597a48392744f7203e284866747781)]:
|
||||
- effect@4.0.0-beta.17
|
||||
- @effect/platform-node@4.0.0-beta.17
|
||||
|
||||
## 4.0.0-beta.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`bf9096c`](https://github.com/Effect-TS/effect-smol/commit/bf9096c52a7d8791d93d232739e523eb84f6625a), [`29f81ca`](https://github.com/Effect-TS/effect-smol/commit/29f81ca07c67dba265804b140a7487fb15a5fc6b), [`68eb28c`](https://github.com/Effect-TS/effect-smol/commit/68eb28c2b0fc67a9f6204ade9bd16c5b37803bfb)]:
|
||||
- effect@4.0.0-beta.16
|
||||
- @effect/platform-node@4.0.0-beta.16
|
||||
|
||||
## 4.0.0-beta.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`24ae609`](https://github.com/Effect-TS/effect-smol/commit/24ae60995d2fd7d621be356cdfdfd328c79639ba), [`0e3c059`](https://github.com/Effect-TS/effect-smol/commit/0e3c059987caa55ebd0c134f7c7b147c639c328e), [`e843b0a`](https://github.com/Effect-TS/effect-smol/commit/e843b0a7d7e7b600a0b3bd477f24e2e4cd26bc8b), [`f4389a2`](https://github.com/Effect-TS/effect-smol/commit/f4389a2cca3c5bbf00d69779f52ce41255f15a28), [`5b73de0`](https://github.com/Effect-TS/effect-smol/commit/5b73de095b3402d0c5c74092ace6ce18ebfad566), [`595d2d6`](https://github.com/Effect-TS/effect-smol/commit/595d2d6e7d50419f3532bd39266191532ace38f2)]:
|
||||
- effect@4.0.0-beta.15
|
||||
- @effect/platform-node@4.0.0-beta.15
|
||||
|
||||
## 4.0.0-beta.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`c414700`](https://github.com/Effect-TS/effect-smol/commit/c414700ef1932e4b67d0102856de417336912350), [`a30c969`](https://github.com/Effect-TS/effect-smol/commit/a30c9699c0d736cf3952041e45d508b7d58907a9)]:
|
||||
- effect@4.0.0-beta.14
|
||||
- @effect/platform-node@4.0.0-beta.14
|
||||
|
||||
## 4.0.0-beta.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`368f4c3`](https://github.com/Effect-TS/effect-smol/commit/368f4c363dd117e6f5a19ad77b161176cfd29fdd), [`db8a579`](https://github.com/Effect-TS/effect-smol/commit/db8a579e93e93ff73b1e60712732e03b597b916b), [`668b703`](https://github.com/Effect-TS/effect-smol/commit/668b70337e9ddbb0d1ae2282a95c282ce404e562), [`d40e76b`](https://github.com/Effect-TS/effect-smol/commit/d40e76b973543979e60e04a6baca04a8c65bdfc2), [`6e18cf8`](https://github.com/Effect-TS/effect-smol/commit/6e18cf883e9905ca718a6697b6a2a4bbd42739aa), [`86062e8`](https://github.com/Effect-TS/effect-smol/commit/86062e8a0c61bca5412fc40d2cf151d676901f08), [`c27ce75`](https://github.com/Effect-TS/effect-smol/commit/c27ce75d34c74dcfc6dba1bf77f1ce88f410a0de), [`e2d4fbf`](https://github.com/Effect-TS/effect-smol/commit/e2d4fbfeeda6a5d2a4c5aeb0501d8240c248b9eb), [`114ab42`](https://github.com/Effect-TS/effect-smol/commit/114ab42ad0edc590d29169675a493e0e915aa58f), [`484caec`](https://github.com/Effect-TS/effect-smol/commit/484caec47cccac8b86db2910742e406dfc7173ab)]:
|
||||
- effect@4.0.0-beta.13
|
||||
- @effect/platform-node@4.0.0-beta.13
|
||||
|
||||
## 4.0.0-beta.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`70a74e8`](https://github.com/Effect-TS/effect-smol/commit/70a74e88a8767c9d4acdb9e5f25aec9a33588d07), [`b5b6e10`](https://github.com/Effect-TS/effect-smol/commit/b5b6e10621d54bf8c9857fec0d647ced78ecd857), [`f5ce5a9`](https://github.com/Effect-TS/effect-smol/commit/f5ce5a915359c6ebf254079e1da23cab6cde34fb), [`a29eb70`](https://github.com/Effect-TS/effect-smol/commit/a29eb702ffe3fc58bd28c4d7857298cd65d73668), [`c7b36e5`](https://github.com/Effect-TS/effect-smol/commit/c7b36e541a23e9a00f64e25b23851e51a37dfce5), [`9381d6d`](https://github.com/Effect-TS/effect-smol/commit/9381d6d4d9d819a81a46e56d0364c76e92a4fbca), [`88439f1`](https://github.com/Effect-TS/effect-smol/commit/88439f13ca13549f3e4822c48c4f019c14fc2bcc), [`e35307d`](https://github.com/Effect-TS/effect-smol/commit/e35307dbeb8eb26a9923f958b894a8eaaf259bf2), [`c7df4bc`](https://github.com/Effect-TS/effect-smol/commit/c7df4bce34009474c63d62a807abfdafb76971eb), [`accaf3b`](https://github.com/Effect-TS/effect-smol/commit/accaf3be7ac8da36e2334c509c23b8c9e88ea160), [`3e1c270`](https://github.com/Effect-TS/effect-smol/commit/3e1c2707bbdf67720af1509642b8ced195790882), [`6cd81f7`](https://github.com/Effect-TS/effect-smol/commit/6cd81f73baad86f5bbfa455a55d75cde71e9611a), [`f222da3`](https://github.com/Effect-TS/effect-smol/commit/f222da3cdb44554f3324c2c52d0d005ee575053e), [`61f901d`](https://github.com/Effect-TS/effect-smol/commit/61f901d830005b66e22d1de889fda132aeea97cd)]:
|
||||
- effect@4.0.0-beta.12
|
||||
- @effect/platform-node@4.0.0-beta.12
|
||||
|
||||
## 4.0.0-beta.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`88659ed`](https://github.com/Effect-TS/effect-smol/commit/88659edb26e3623d557dccfe914c2c949672da16), [`f2915e8`](https://github.com/Effect-TS/effect-smol/commit/f2915e8e2efe80d50c281e53f297b9701d6dc199), [`eb71ace`](https://github.com/Effect-TS/effect-smol/commit/eb71acebbe0f228e4920278013beee3b67d62310), [`2a16999`](https://github.com/Effect-TS/effect-smol/commit/2a169996c7513d377ac47adbfd68e1490457135c), [`d42dd52`](https://github.com/Effect-TS/effect-smol/commit/d42dd52f11203f8e749fb5d3ecf7153e4a5a6814), [`339adaf`](https://github.com/Effect-TS/effect-smol/commit/339adaf850a62a892adebcb208c2d9dddf3b97b3), [`de19645`](https://github.com/Effect-TS/effect-smol/commit/de1964526d01102dd1cb99c8cfdd3e8df1f49ef1), [`9b1dc3b`](https://github.com/Effect-TS/effect-smol/commit/9b1dc3bcf2a1b68d0a67e3465db5ad01a1a56997), [`e4cb2f5`](https://github.com/Effect-TS/effect-smol/commit/e4cb2f55b30f4771ec1bf613ced36d6d96464dd5), [`8bced95`](https://github.com/Effect-TS/effect-smol/commit/8bced954ecb35d4489197a57b0efe927e7d75f49), [`9431420`](https://github.com/Effect-TS/effect-smol/commit/94314207c8019918200fbcb97aec992219f801f0), [`948dca2`](https://github.com/Effect-TS/effect-smol/commit/948dca22e4f672ba7a6db57f9899272bec7c08b8), [`d18e327`](https://github.com/Effect-TS/effect-smol/commit/d18e32765a2665e31ffb31e746bf983fcfac34c5), [`ab512f7`](https://github.com/Effect-TS/effect-smol/commit/ab512f7be1c0e6b359da921e22cd4944e4c57d3e)]:
|
||||
- effect@4.0.0-beta.11
|
||||
- @effect/platform-node@4.0.0-beta.11
|
||||
|
||||
## 4.0.0-beta.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`371acab`](https://github.com/Effect-TS/effect-smol/commit/371acabb58d56f3a7a5e3e33d3d5fdc9f5573c74), [`856d774`](https://github.com/Effect-TS/effect-smol/commit/856d7741f1e296dd5048c6ff2b44b95d023e6ae4), [`b9e9202`](https://github.com/Effect-TS/effect-smol/commit/b9e92023c38caa322975d77cfe83e2d34ac9305a), [`1d1a974`](https://github.com/Effect-TS/effect-smol/commit/1d1a974bd280c81bff5d4505491cda03ba7a3f36), [`6bfe2a6`](https://github.com/Effect-TS/effect-smol/commit/6bfe2a659bc6335db75709931f405da45301cba2), [`b12c811`](https://github.com/Effect-TS/effect-smol/commit/b12c81157be287b1649c210616a244b50ec094d2), [`d17d98a`](https://github.com/Effect-TS/effect-smol/commit/d17d98ad78e2b44d95ef434adab79ac3c35e75ab), [`68c3c7c`](https://github.com/Effect-TS/effect-smol/commit/68c3c7cb1e06ed94fa5c4c123a234b4ccbfdecd8)]:
|
||||
- effect@4.0.0-beta.10
|
||||
- @effect/platform-node@4.0.0-beta.10
|
||||
|
||||
## 4.0.0-beta.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3386557`](https://github.com/Effect-TS/effect-smol/commit/338655731564a7be9f8859dedbf4d5bcac6eb350), [`b6666e3`](https://github.com/Effect-TS/effect-smol/commit/b6666e3cf6bd44ba1a8704e65c256c30359cb422)]:
|
||||
- effect@4.0.0-beta.9
|
||||
- @effect/platform-node@4.0.0-beta.9
|
||||
|
||||
## 4.0.0-beta.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`246e672`](https://github.com/Effect-TS/effect-smol/commit/246e672dbbd7848d60e0c78fd66671b2f10b3752), [`807dec0`](https://github.com/Effect-TS/effect-smol/commit/807dec03801b4c58a6d00c237b6d98d6386911df)]:
|
||||
- effect@4.0.0-beta.8
|
||||
- @effect/platform-node@4.0.0-beta.8
|
||||
|
||||
## 4.0.0-beta.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a2bda6d`](https://github.com/Effect-TS/effect-smol/commit/a2bda6d4ef6de9d9b0c53ae2df5434f778d6161a), [`1f95a2b`](https://github.com/Effect-TS/effect-smol/commit/1f95a2b5aa9524bb38f4437f4691a664bf463ca1), [`a8d5e79`](https://github.com/Effect-TS/effect-smol/commit/a8d5e792fec201a83af0eb92fc79928d055125fd), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`a5386ba`](https://github.com/Effect-TS/effect-smol/commit/a5386ba67005dff697d45a45398f398773f58dcf), [`06d8a03`](https://github.com/Effect-TS/effect-smol/commit/06d8a0391631e6130e3ab25227e59817852e227f), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430), [`f9e883e`](https://github.com/Effect-TS/effect-smol/commit/f9e883e266fbda870336ee62f46b7ac85ba3de6e), [`8caac76`](https://github.com/Effect-TS/effect-smol/commit/8caac76a35821edfe03c75dab5eb056e8fc05430)]:
|
||||
- effect@4.0.0-beta.7
|
||||
- @effect/platform-node@4.0.0-beta.7
|
||||
|
||||
## 4.0.0-beta.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3247da2`](https://github.com/Effect-TS/effect-smol/commit/3247da28331f345f68be5dbd2974a7e03d300fe1), [`f205705`](https://github.com/Effect-TS/effect-smol/commit/f2057050dbd034b8c186be2d40c3d03ee63a5a3b), [`f35022c`](https://github.com/Effect-TS/effect-smol/commit/f35022c212e4111527e1bb43f360a67b2b49fa85), [`8622721`](https://github.com/Effect-TS/effect-smol/commit/86227217b02d43680a3c6f3c21731b1d852c91f5), [`fc660ab`](https://github.com/Effect-TS/effect-smol/commit/fc660ab8b5ebae38b8d6b96cbf2f9b880cc09253), [`f37dc33`](https://github.com/Effect-TS/effect-smol/commit/f37dc335f64622fa9ce8d6d1d5dd8fc3f260257b), [`3662f32`](https://github.com/Effect-TS/effect-smol/commit/3662f328fcfa3b2fa01ffa79da40e12e93fcede8), [`a7d436f`](https://github.com/Effect-TS/effect-smol/commit/a7d436f438dcd7f49b9485e4e95a4511f31fad7d), [`6856a41`](https://github.com/Effect-TS/effect-smol/commit/6856a415d7eddd9d73d60919e976f1d071421be4), [`8c417d0`](https://github.com/Effect-TS/effect-smol/commit/8c417d03475e5e12d00dca0c4781d0af7e66b86c), [`5419570`](https://github.com/Effect-TS/effect-smol/commit/5419570ba47ce882a3a10882707b46f66e464906), [`449c5ed`](https://github.com/Effect-TS/effect-smol/commit/449c5ed5318e8a874e730420bcf52918fa2ec80f), [`4b5ec12`](https://github.com/Effect-TS/effect-smol/commit/4b5ec12f87f95f2a3cd8fe4d5b26c6eb0529381a), [`df87937`](https://github.com/Effect-TS/effect-smol/commit/df879375fc3b169c43f9c434b3775e12b80dffe4), [`5dbfca8`](https://github.com/Effect-TS/effect-smol/commit/5dbfca8d1dbb6d18d1605d4f8562e99c86e2ff11), [`e629497`](https://github.com/Effect-TS/effect-smol/commit/e6294973d55597ab6b6deca6babbe1e946b2c91d), [`981c991`](https://github.com/Effect-TS/effect-smol/commit/981c991cd78db34def815d5754379d737157f005), [`1ca2ed6`](https://github.com/Effect-TS/effect-smol/commit/1ca2ed67301a5dc40ae0ed94346b99f26fd22bbe), [`45722bd`](https://github.com/Effect-TS/effect-smol/commit/45722bde974458311f11ad237711363a10ec6894), [`eb2a85e`](https://github.com/Effect-TS/effect-smol/commit/eb2a85ed4dc162b2535d304799333a5a20477fd0)]:
|
||||
- effect@4.0.0-beta.6
|
||||
- @effect/platform-node@4.0.0-beta.6
|
||||
|
||||
## 4.0.0-beta.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`f6e133e`](https://github.com/Effect-TS/effect-smol/commit/f6e133e9a16b32317bd09ff08c12b97a0ae44600), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8), [`a88e206`](https://github.com/Effect-TS/effect-smol/commit/a88e206e44dc66ca5a2b45bedc797877c5dbb083), [`e3893cc`](https://github.com/Effect-TS/effect-smol/commit/e3893ccf2632338c7d8e745f639dcd825a9d42f8)]:
|
||||
- effect@4.0.0-beta.5
|
||||
- @effect/platform-node@4.0.0-beta.5
|
||||
|
||||
## 4.0.0-beta.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`c5a18ef`](https://github.com/Effect-TS/effect-smol/commit/c5a18ef44171e3880bf983faee74529908974b32), [`bc6b885`](https://github.com/Effect-TS/effect-smol/commit/bc6b885b94d887a200657c0775dfa874dc15bc0c)]:
|
||||
- effect@4.0.0-beta.4
|
||||
- @effect/platform-node@4.0.0-beta.4
|
||||
|
||||
## 4.0.0-beta.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3a0cf36`](https://github.com/Effect-TS/effect-smol/commit/3a0cf36eff106ba48d74e133c1598cd40613e530), [`c4da328`](https://github.com/Effect-TS/effect-smol/commit/c4da328d32fad1d61e0e538f5d371edf61521d7e)]:
|
||||
- effect@4.0.0-beta.3
|
||||
- @effect/platform-node@4.0.0-beta.3
|
||||
|
||||
## 4.0.0-beta.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a22ce73`](https://github.com/Effect-TS/effect-smol/commit/a22ce73b2bd9305b7ba665694d2255c0e6d5a8d0), [`ebdabf7`](https://github.com/Effect-TS/effect-smol/commit/ebdabf79ff4e62c8384aa8cf9a8d2787d536ee78), [`8f663bb`](https://github.com/Effect-TS/effect-smol/commit/8f663bb121021bf12bd264e8ae385187cb7a5dae)]:
|
||||
- effect@4.0.0-beta.2
|
||||
- @effect/platform-node@4.0.0-beta.2
|
||||
|
||||
## 4.0.0-beta.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`0fecf70`](https://github.com/Effect-TS/effect-smol/commit/0fecf70048057623eed7c584a06671773a2b1743), [`709569e`](https://github.com/Effect-TS/effect-smol/commit/709569ed76bead9ebb0670599e4d890a07ca5a43)]:
|
||||
- effect@4.0.0-beta.1
|
||||
- @effect/platform-node@4.0.0-beta.1
|
||||
|
||||
## 4.0.0-beta.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- [#1183](https://github.com/Effect-TS/effect-smol/pull/1183) [`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66) Thanks @tim-smart! - v4 beta
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`be642ab`](https://github.com/Effect-TS/effect-smol/commit/be642ab1b3b4cd49e53c9732d7aba1b367fddd66)]:
|
||||
- @effect/platform-node@4.0.0-beta.0
|
||||
- effect@4.0.0-beta.0
|
||||
21
repos/effect/packages/tools/openapi-generator/LICENSE
Normal file
21
repos/effect/packages/tools/openapi-generator/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Effectful Technologies Inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/@effect/docgen/schema.json",
|
||||
"exclude": ["**/*.ts"]
|
||||
}
|
||||
77
repos/effect/packages/tools/openapi-generator/package.json
Normal file
77
repos/effect/packages/tools/openapi-generator/package.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"name": "@effect/openapi-generator",
|
||||
"type": "module",
|
||||
"version": "4.0.0-beta.99",
|
||||
"license": "MIT",
|
||||
"description": "Generate Effect Schema types, HTTP clients, and HttpApi modules from OpenAPI specifications",
|
||||
"homepage": "https://effect.website",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Effect-TS/effect.git",
|
||||
"directory": "packages/tools/openapi-generator"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Effect-TS/effect/issues"
|
||||
},
|
||||
"tags": [
|
||||
"typescript",
|
||||
"openapi",
|
||||
"codegen"
|
||||
],
|
||||
"keywords": [
|
||||
"typescript",
|
||||
"openapi",
|
||||
"codegen"
|
||||
],
|
||||
"bin": {
|
||||
"openapigen": "./src/bin.ts"
|
||||
},
|
||||
"sideEffects": [],
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
"./*": "./src/*.ts",
|
||||
"./bin": null,
|
||||
"./main": null
|
||||
},
|
||||
"files": [
|
||||
"src/**/*.ts",
|
||||
"dist/**/*.js",
|
||||
"dist/**/*.js.map",
|
||||
"dist/**/*.d.ts",
|
||||
"dist/**/*.d.ts.map"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"provenance": true,
|
||||
"bin": {
|
||||
"openapigen": "./dist/bin.js"
|
||||
},
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
"./*": "./dist/*.js",
|
||||
"./bin": null,
|
||||
"./main": null
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -b tsconfig.json && pnpm babel",
|
||||
"babel": "babel dist --plugins annotate-pure-calls --out-dir dist --source-maps",
|
||||
"check": "tsc -b tsconfig.json",
|
||||
"test": "vitest",
|
||||
"coverage": "vitest --coverage"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@effect/platform-node": "workspace:^",
|
||||
"effect": "workspace:^"
|
||||
},
|
||||
"dependencies": {
|
||||
"swagger2openapi": "^7.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/swagger2openapi": "^7.0.4",
|
||||
"effect": "workspace:^",
|
||||
"json-schema-typed": "^8.0.2",
|
||||
"openapi-typescript": "^7.13.0",
|
||||
"yaml": "^2.9.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,552 @@
|
||||
/**
|
||||
* Renders parsed OpenAPI operations into generated Effect HttpApi source code.
|
||||
*
|
||||
* This module maps normalized OpenAPI metadata, tags, request bodies,
|
||||
* responses, and security requirements into import declarations, HttpApi
|
||||
* groups, endpoint definitions, schema annotations, and middleware classes.
|
||||
* The rendered TypeScript can be emitted by the OpenAPI generator as an
|
||||
* executable Effect `HttpApi` module.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
import type {
|
||||
ParsedOpenApi,
|
||||
ParsedOpenApiSecurityScheme,
|
||||
ParsedOpenApiTag,
|
||||
ParsedOperation,
|
||||
ParsedOperationMediaTypeSchema,
|
||||
ParsedOperationResponse
|
||||
} from "./ParsedOperation.ts"
|
||||
import * as Utils from "./Utils.ts"
|
||||
|
||||
interface GroupRenderModel {
|
||||
readonly identifier: string
|
||||
readonly topLevel: boolean
|
||||
readonly metadata: ParsedOpenApiTag | undefined
|
||||
readonly operations: ReadonlyArray<ParsedOperation>
|
||||
readonly constName: string
|
||||
}
|
||||
|
||||
interface SecurityRenderModel {
|
||||
readonly securityDeclarations: ReadonlyArray<string>
|
||||
readonly middlewareDeclarations: ReadonlyArray<string>
|
||||
readonly endpointMiddlewares: ReadonlyMap<string, ReadonlyArray<string>>
|
||||
}
|
||||
|
||||
const fallbackGroupIdentifier = "default"
|
||||
|
||||
/**
|
||||
* Render the import declarations required by generated HttpApi source.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* The schema namespace import is named by the caller so generated code can
|
||||
* avoid collisions with symbols already present in the output module. Multipart
|
||||
* support is included only when the parsed OpenAPI document needs it.
|
||||
*
|
||||
* @category code generation
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const imports = (
|
||||
importName: string,
|
||||
options?: {
|
||||
readonly multipart?: boolean | undefined
|
||||
}
|
||||
): string =>
|
||||
[
|
||||
`import * as ${importName} from "effect/Schema"`,
|
||||
...(options?.multipart === true ? [`import { Multipart } from "effect/unstable/http"`] : []),
|
||||
`import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, HttpApiSecurity, OpenApi } from "effect/unstable/httpapi"`
|
||||
].join("\n")
|
||||
|
||||
/**
|
||||
* Convert a parsed OpenAPI document into Effect HttpApi source code.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* The generated implementation contains security declarations, reusable
|
||||
* middleware classes, HttpApi groups, endpoint definitions, and OpenAPI
|
||||
* annotations derived from the parsed operation metadata.
|
||||
*
|
||||
* @category code generation
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const toImplementation = (
|
||||
_importName: string,
|
||||
name: string,
|
||||
parsed: ParsedOpenApi
|
||||
): string => {
|
||||
const security = buildSecurityRenderModel(parsed)
|
||||
const groups = groupOperations(parsed)
|
||||
const groupSources = groups.map((group) => renderGroup(group, security.endpointMiddlewares))
|
||||
const metadataAnnotations = renderApiAnnotations(parsed)
|
||||
|
||||
let apiValue = `export class ${name} extends HttpApi.make(${JSON.stringify(name)})`
|
||||
for (const annotation of metadataAnnotations) {
|
||||
apiValue += `\n .${annotation}`
|
||||
}
|
||||
if (groups.length > 0) {
|
||||
apiValue += `\n .add(${groups.map((group) => group.constName).join(", ")})`
|
||||
}
|
||||
apiValue += ` {}`
|
||||
|
||||
return [
|
||||
...security.securityDeclarations,
|
||||
...security.middlewareDeclarations,
|
||||
...groupSources,
|
||||
apiValue
|
||||
].join("\n\n")
|
||||
}
|
||||
|
||||
const groupOperations = (parsed: ParsedOpenApi): ReadonlyArray<GroupRenderModel> => {
|
||||
const tagMetadata = new Map(parsed.tags.map((tag) => [tag.name, tag]))
|
||||
const byIdentifier = new Map<string, {
|
||||
readonly identifier: string
|
||||
topLevel: boolean
|
||||
readonly metadata: ParsedOpenApiTag | undefined
|
||||
readonly operations: Array<ParsedOperation>
|
||||
}>()
|
||||
|
||||
for (const operation of parsed.operations) {
|
||||
const identifier = operation.tags[0] ?? fallbackGroupIdentifier
|
||||
const topLevel = operation.tags.length === 0
|
||||
const existing = byIdentifier.get(identifier)
|
||||
if (existing) {
|
||||
if (topLevel) {
|
||||
existing.topLevel = true
|
||||
}
|
||||
existing.operations.push(operation)
|
||||
continue
|
||||
}
|
||||
byIdentifier.set(identifier, {
|
||||
identifier,
|
||||
topLevel,
|
||||
metadata: tagMetadata.get(identifier),
|
||||
operations: [operation]
|
||||
})
|
||||
}
|
||||
|
||||
const allocateName = makeNameAllocator()
|
||||
const groups: Array<GroupRenderModel> = []
|
||||
for (const group of byIdentifier.values()) {
|
||||
const baseName = ensureIdentifier(group.identifier, "Group")
|
||||
groups.push({
|
||||
...group,
|
||||
constName: allocateName(`${baseName}Group`)
|
||||
})
|
||||
}
|
||||
return groups
|
||||
}
|
||||
|
||||
const renderGroup = (
|
||||
group: GroupRenderModel,
|
||||
endpointMiddlewares: ReadonlyMap<string, ReadonlyArray<string>>
|
||||
): string => {
|
||||
let source = `class ${group.constName} extends HttpApiGroup.make(${JSON.stringify(group.identifier)}${
|
||||
group.topLevel ? ", { topLevel: true }" : ""
|
||||
})`
|
||||
|
||||
const allocateEndpointName = makeNameAllocator()
|
||||
const endpointSources = group.operations.map((operation) =>
|
||||
renderEndpoint(
|
||||
operation,
|
||||
allocateEndpointName(operation.id),
|
||||
endpointMiddlewares.get(toOperationKey(operation)) ?? []
|
||||
)
|
||||
)
|
||||
if (endpointSources.length > 0) {
|
||||
source += `\n .add(${endpointSources.join(", \n ")})`
|
||||
}
|
||||
|
||||
if (group.metadata?.description !== undefined) {
|
||||
source += `\n .annotate(OpenApi.Description, ${JSON.stringify(group.metadata.description)})`
|
||||
}
|
||||
if (group.metadata?.externalDocs !== undefined) {
|
||||
source += `\n .annotate(OpenApi.ExternalDocs, ${JSON.stringify(group.metadata.externalDocs)})`
|
||||
}
|
||||
|
||||
source += ` {}`
|
||||
|
||||
return source
|
||||
}
|
||||
|
||||
const renderEndpoint = (
|
||||
operation: ParsedOperation,
|
||||
endpointName: string,
|
||||
endpointMiddlewares: ReadonlyArray<string>
|
||||
): string => {
|
||||
const options: Array<string> = []
|
||||
if (operation.pathSchema !== undefined) {
|
||||
options.push(`params: ${operation.pathSchema}`)
|
||||
}
|
||||
if (operation.querySchema !== undefined) {
|
||||
options.push(`query: ${operation.querySchema}`)
|
||||
}
|
||||
if (operation.headersSchema !== undefined) {
|
||||
options.push(`headers: ${operation.headersSchema}`)
|
||||
}
|
||||
|
||||
const payload = renderPayload(operation)
|
||||
if (payload !== undefined) {
|
||||
options.push(`payload: ${payload}`)
|
||||
}
|
||||
|
||||
const success = renderResponseSet(operation.responses, "success")
|
||||
if (success !== undefined) {
|
||||
options.push(`success: ${success}`)
|
||||
}
|
||||
|
||||
const error = renderResponseSet(operation.responses, "error")
|
||||
if (error !== undefined) {
|
||||
options.push(`error: ${error}`)
|
||||
}
|
||||
|
||||
const endpoint = options.length === 0
|
||||
? `HttpApiEndpoint.${operation.method}(${JSON.stringify(endpointName)}, ${
|
||||
JSON.stringify(toHttpApiPath(operation.path))
|
||||
})`
|
||||
: `HttpApiEndpoint.${operation.method}(${JSON.stringify(endpointName)}, ${
|
||||
JSON.stringify(toHttpApiPath(operation.path))
|
||||
}, { ${options.join(", ")} })`
|
||||
|
||||
const annotations: Array<string> = []
|
||||
if (operation.operationId !== undefined) {
|
||||
annotations.push(`annotate(OpenApi.Identifier, ${JSON.stringify(operation.operationId)})`)
|
||||
}
|
||||
if (operation.metadata.summary !== undefined) {
|
||||
annotations.push(`annotate(OpenApi.Summary, ${JSON.stringify(operation.metadata.summary)})`)
|
||||
}
|
||||
if (operation.metadata.description !== undefined) {
|
||||
annotations.push(`annotate(OpenApi.Description, ${JSON.stringify(operation.metadata.description)})`)
|
||||
}
|
||||
if (operation.metadata.deprecated) {
|
||||
annotations.push(`annotate(OpenApi.Deprecated, true)`)
|
||||
}
|
||||
if (operation.metadata.externalDocs !== undefined) {
|
||||
annotations.push(`annotate(OpenApi.ExternalDocs, ${JSON.stringify(operation.metadata.externalDocs)})`)
|
||||
}
|
||||
|
||||
if (annotations.length === 0 && endpointMiddlewares.length === 0) {
|
||||
return endpoint
|
||||
}
|
||||
|
||||
let out = endpoint
|
||||
for (const middleware of endpointMiddlewares) {
|
||||
out += `\n .middleware(${middleware})`
|
||||
}
|
||||
for (const annotation of annotations) {
|
||||
out += `\n .${annotation}`
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
const renderPayload = (operation: ParsedOperation): string | undefined => {
|
||||
if (!methodSupportsBody(operation.method)) {
|
||||
return
|
||||
}
|
||||
const payloads = operation.requestBodyRepresentable.map((schema) => renderMediaSchema(schema))
|
||||
if (payloads.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (operation.requestBody?.required === false) {
|
||||
payloads.unshift("HttpApiSchema.NoContent")
|
||||
}
|
||||
|
||||
return joinSchemas(payloads)
|
||||
}
|
||||
|
||||
const renderResponseSet = (
|
||||
responses: ReadonlyArray<ParsedOperationResponse>,
|
||||
target: "success" | "error"
|
||||
): string | undefined => {
|
||||
const rendered: Array<string> = []
|
||||
|
||||
for (const response of responses) {
|
||||
const status = toStatus(response.status)
|
||||
if (status === undefined) {
|
||||
continue
|
||||
}
|
||||
|
||||
const isSuccess = status < 400
|
||||
if ((target === "success") !== isSuccess) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (response.isEmpty) {
|
||||
rendered.push(`HttpApiSchema.Empty(${status})`)
|
||||
continue
|
||||
}
|
||||
|
||||
for (const media of response.representable) {
|
||||
rendered.push(applyStatus(renderMediaSchema(media), status, target))
|
||||
}
|
||||
}
|
||||
|
||||
if (rendered.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
return joinSchemas(rendered)
|
||||
}
|
||||
|
||||
const joinSchemas = (schemas: ReadonlyArray<string>): string =>
|
||||
schemas.length === 1 ? schemas[0] : `[${schemas.join(", ")}]`
|
||||
|
||||
const renderMediaSchema = (media: ParsedOperationMediaTypeSchema): string => {
|
||||
if (media.effectStream === "sse") {
|
||||
const options = media.contentType === "text/event-stream"
|
||||
? `{ events: ${media.schema}, error: ${media.errorSchema} }`
|
||||
: `{ contentType: ${JSON.stringify(media.contentType)}, events: ${media.schema}, error: ${media.errorSchema} }`
|
||||
return `HttpApiSchema.StreamSse(${options})`
|
||||
}
|
||||
|
||||
if (media.effectStream === "uint8array") {
|
||||
if (media.contentType === "application/octet-stream") {
|
||||
return "HttpApiSchema.StreamUint8Array()"
|
||||
}
|
||||
return `HttpApiSchema.StreamUint8Array({ contentType: ${JSON.stringify(media.contentType)} })`
|
||||
}
|
||||
|
||||
switch (media.encoding) {
|
||||
case "json": {
|
||||
if (media.contentType === "application/json") {
|
||||
return media.schema
|
||||
}
|
||||
return `${media.schema}.pipe(HttpApiSchema.asJson({ contentType: ${JSON.stringify(media.contentType)} }))`
|
||||
}
|
||||
case "multipart": {
|
||||
return `${media.schema}.pipe(HttpApiSchema.asMultipart())`
|
||||
}
|
||||
case "form-url-encoded": {
|
||||
if (media.contentType === "application/x-www-form-urlencoded") {
|
||||
return `${media.schema}.pipe(HttpApiSchema.asFormUrlEncoded())`
|
||||
}
|
||||
return `${media.schema}.pipe(HttpApiSchema.asFormUrlEncoded({ contentType: ${
|
||||
JSON.stringify(media.contentType)
|
||||
} }))`
|
||||
}
|
||||
case "text": {
|
||||
if (media.contentType === "text/plain") {
|
||||
return `${media.schema}.pipe(HttpApiSchema.asText())`
|
||||
}
|
||||
return `${media.schema}.pipe(HttpApiSchema.asText({ contentType: ${JSON.stringify(media.contentType)} }))`
|
||||
}
|
||||
case "binary": {
|
||||
if (media.contentType === "application/octet-stream") {
|
||||
return `${media.schema}.pipe(HttpApiSchema.asUint8Array())`
|
||||
}
|
||||
return `${media.schema}.pipe(HttpApiSchema.asUint8Array({ contentType: ${JSON.stringify(media.contentType)} }))`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const renderApiAnnotations = (parsed: ParsedOpenApi): ReadonlyArray<string> => {
|
||||
const annotations: Array<string> = [
|
||||
`annotate(OpenApi.Title, ${JSON.stringify(parsed.metadata.title)})`,
|
||||
`annotate(OpenApi.Version, ${JSON.stringify(parsed.metadata.version)})`
|
||||
]
|
||||
|
||||
if (parsed.metadata.summary !== undefined) {
|
||||
annotations.push(`annotate(OpenApi.Summary, ${JSON.stringify(parsed.metadata.summary)})`)
|
||||
}
|
||||
if (parsed.metadata.description !== undefined) {
|
||||
annotations.push(`annotate(OpenApi.Description, ${JSON.stringify(parsed.metadata.description)})`)
|
||||
}
|
||||
if (parsed.metadata.license !== undefined) {
|
||||
annotations.push(`annotate(OpenApi.License, ${JSON.stringify(parsed.metadata.license)})`)
|
||||
}
|
||||
if (parsed.metadata.servers !== undefined) {
|
||||
annotations.push(`annotate(OpenApi.Servers, ${JSON.stringify(parsed.metadata.servers)})`)
|
||||
}
|
||||
|
||||
return annotations
|
||||
}
|
||||
|
||||
const buildSecurityRenderModel = (parsed: ParsedOpenApi): SecurityRenderModel => {
|
||||
const allocateName = makeNameAllocator()
|
||||
const securityDeclarations: Array<string> = []
|
||||
const middlewareDeclarations: Array<string> = []
|
||||
const endpointMiddlewares = new Map<string, ReadonlyArray<string>>()
|
||||
const schemeDeclarations = new Map<string, string>()
|
||||
const middlewareNames = new Map<string, string>()
|
||||
|
||||
for (const securityScheme of parsed.securitySchemes) {
|
||||
const baseName = ensureIdentifier(securityScheme.name, "Security")
|
||||
const declarationName = allocateName(`${baseName}Security`)
|
||||
schemeDeclarations.set(securityScheme.name, declarationName)
|
||||
securityDeclarations.push(`export const ${declarationName} = ${renderSecurityScheme(securityScheme)}`)
|
||||
}
|
||||
|
||||
for (const operation of parsed.operations) {
|
||||
if (operation.effectiveSecurity.length === 0) {
|
||||
continue
|
||||
}
|
||||
if (operation.effectiveSecurity.some((requirement) => Object.keys(requirement).length === 0)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const operationMiddlewareNames: Array<string> = []
|
||||
const seenOrSchemes = new Set<string>()
|
||||
const andRequirements: Array<ReadonlyArray<string>> = []
|
||||
|
||||
for (const requirement of operation.effectiveSecurity) {
|
||||
const schemes = Object.keys(requirement)
|
||||
if (schemes.length === 1) {
|
||||
const schemeName = schemes[0]
|
||||
if (schemeDeclarations.has(schemeName) && !seenOrSchemes.has(schemeName)) {
|
||||
seenOrSchemes.add(schemeName)
|
||||
}
|
||||
} else if (schemes.length > 1) {
|
||||
andRequirements.push([...schemes].sort())
|
||||
}
|
||||
}
|
||||
|
||||
const orSchemeNames = Array.from(seenOrSchemes).sort()
|
||||
if (orSchemeNames.length > 0) {
|
||||
const className = getOrSecurityMiddlewareName(orSchemeNames)
|
||||
operationMiddlewareNames.push(className)
|
||||
}
|
||||
|
||||
const seenAndRequirements = new Set<string>()
|
||||
for (const requirement of andRequirements) {
|
||||
const key = requirement.join("\u0000")
|
||||
if (seenAndRequirements.has(key)) {
|
||||
continue
|
||||
}
|
||||
seenAndRequirements.add(key)
|
||||
const className = getAndSecurityMiddlewareName(requirement)
|
||||
operationMiddlewareNames.push(className)
|
||||
}
|
||||
|
||||
if (operationMiddlewareNames.length > 0) {
|
||||
endpointMiddlewares.set(toOperationKey(operation), operationMiddlewareNames)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
securityDeclarations,
|
||||
middlewareDeclarations,
|
||||
endpointMiddlewares
|
||||
}
|
||||
|
||||
function getOrSecurityMiddlewareName(schemes: ReadonlyArray<string>): string {
|
||||
const key = `or:${schemes.join("\u0000")}`
|
||||
const existing = middlewareNames.get(key)
|
||||
if (existing !== undefined) {
|
||||
return existing
|
||||
}
|
||||
|
||||
const className = allocateName(`${getSecurityMiddlewareBaseName(schemes, "Or")}SecurityMiddleware`)
|
||||
const securityEntries = schemes.map((name) => `${JSON.stringify(name)}: ${schemeDeclarations.get(name)!}`).join(
|
||||
", "
|
||||
)
|
||||
middlewareDeclarations.push(
|
||||
`export class ${className} extends HttpApiMiddleware.Service<${className}>()(${
|
||||
JSON.stringify(`${schemes.join(" | ")} security`)
|
||||
}, { security: { ${securityEntries} } }) {}`
|
||||
)
|
||||
middlewareNames.set(key, className)
|
||||
return className
|
||||
}
|
||||
|
||||
function getAndSecurityMiddlewareName(schemes: ReadonlyArray<string>): string {
|
||||
const key = `and:${schemes.join("\u0000")}`
|
||||
const existing = middlewareNames.get(key)
|
||||
if (existing !== undefined) {
|
||||
return existing
|
||||
}
|
||||
|
||||
const className = allocateName(`${getSecurityMiddlewareBaseName(schemes, "And")}SecurityMiddleware`)
|
||||
middlewareDeclarations.push(
|
||||
`class ${className} extends HttpApiMiddleware.Service<${className}>()(${
|
||||
JSON.stringify(`${schemes.join(" & ")} security`)
|
||||
}) {}`
|
||||
)
|
||||
middlewareNames.set(key, className)
|
||||
return className
|
||||
}
|
||||
}
|
||||
|
||||
const getSecurityMiddlewareBaseName = (
|
||||
schemes: ReadonlyArray<string>,
|
||||
joiner: "And" | "Or"
|
||||
): string => {
|
||||
const [head, ...tail] = schemes.map((scheme) => ensureIdentifier(scheme, "Security"))
|
||||
return tail.length === 0 ? head : [head, ...tail.map((scheme) => `${joiner}${scheme}`)].join("")
|
||||
}
|
||||
|
||||
const renderSecurityScheme = (securityScheme: ParsedOpenApiSecurityScheme): string => {
|
||||
let source: string
|
||||
switch (securityScheme.type) {
|
||||
case "basic": {
|
||||
source = "HttpApiSecurity.basic"
|
||||
break
|
||||
}
|
||||
case "bearer": {
|
||||
source = "HttpApiSecurity.bearer"
|
||||
break
|
||||
}
|
||||
case "http": {
|
||||
source = `HttpApiSecurity.http({ scheme: ${JSON.stringify(securityScheme.scheme!)} })`
|
||||
break
|
||||
}
|
||||
case "apiKey": {
|
||||
source = `HttpApiSecurity.apiKey({ key: ${JSON.stringify(securityScheme.key!)}, in: ${
|
||||
JSON.stringify(securityScheme.in!)
|
||||
} })`
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (securityScheme.description !== undefined) {
|
||||
source += `.pipe(HttpApiSecurity.annotate(OpenApi.Description, ${JSON.stringify(securityScheme.description)}))`
|
||||
}
|
||||
if (
|
||||
(securityScheme.type === "bearer" || securityScheme.type === "http") && securityScheme.bearerFormat !== undefined
|
||||
) {
|
||||
source += `.pipe(HttpApiSecurity.annotate(OpenApi.Format, ${JSON.stringify(securityScheme.bearerFormat)}))`
|
||||
}
|
||||
|
||||
return source
|
||||
}
|
||||
|
||||
const toOperationKey = (operation: ParsedOperation): string => `${operation.method}:${operation.path}`
|
||||
|
||||
const toHttpApiPath = (path: string): string => path.replace(/{([^}]+)}/g, ":$1")
|
||||
|
||||
const toStatus = (status: string): number | undefined => {
|
||||
if (!/^\d{3}$/.test(status)) {
|
||||
return
|
||||
}
|
||||
return Number(status)
|
||||
}
|
||||
|
||||
const applyStatus = (schema: string, status: number, target: "success" | "error"): string => {
|
||||
if ((target === "success" && status === 200) || (target === "error" && status === 500)) {
|
||||
return schema
|
||||
}
|
||||
return `${schema}.pipe(HttpApiSchema.status(${status}))`
|
||||
}
|
||||
|
||||
const methodSupportsBody = (method: ParsedOperation["method"]): boolean =>
|
||||
method !== "get" && method !== "head" && method !== "options" && method !== "trace"
|
||||
|
||||
const ensureIdentifier = (value: string, fallback: string): string => {
|
||||
const sanitized = Utils.identifier(value)
|
||||
return sanitized.length > 0 ? sanitized : fallback
|
||||
}
|
||||
|
||||
const makeNameAllocator = () => {
|
||||
const used = new Set<string>()
|
||||
return (base: string) => {
|
||||
let candidate = base
|
||||
let index = 2
|
||||
while (used.has(candidate)) {
|
||||
candidate = `${base}${index}`
|
||||
index += 1
|
||||
}
|
||||
used.add(candidate)
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
/**
|
||||
* Generate TypeScript source for JSON Schema declarations extracted from
|
||||
* OpenAPI documents.
|
||||
*
|
||||
* This module is the schema-rendering stage of the OpenAPI generator. Callers
|
||||
* register named OpenAPI 3.0 or 3.1 schemas, provide the reusable component
|
||||
* definitions for the document, and receive source text containing exported
|
||||
* TypeScript aliases plus Effect Schema runtime values. The generator first
|
||||
* normalizes OpenAPI-specific schema shapes into Effect's JSON Schema model,
|
||||
* then delegates recursive analysis and runtime expression construction to
|
||||
* `SchemaRepresentation`.
|
||||
*
|
||||
* The renderer keeps the emitted module usable for both human maintainers and
|
||||
* automated code-generation consumers by grouping recursive declarations,
|
||||
* reusable references, and locally registered schemas. It also contains the
|
||||
* HttpApi-specific multipart file substitutions that map generated schemas to
|
||||
* Effect's multipart runtime types.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
import * as Arr from "effect/Array"
|
||||
import * as JsonSchema from "effect/JsonSchema"
|
||||
import * as Rec from "effect/Record"
|
||||
import * as SchemaRepresentation from "effect/SchemaRepresentation"
|
||||
|
||||
type Source = "openapi-3.0" | "openapi-3.1"
|
||||
|
||||
interface GenerateOptions {
|
||||
readonly onEnter?: ((js: JsonSchema.JsonSchema) => JsonSchema.JsonSchema) | undefined
|
||||
}
|
||||
|
||||
interface GenerateHttpApiOptions extends GenerateOptions {
|
||||
readonly multipartSchemaRefs?: {
|
||||
readonly singleFile: string
|
||||
readonly files: string
|
||||
} | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a stateful JSON Schema code generator for OpenAPI-derived schemas.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* Schemas registered with the returned generator are converted into TypeScript
|
||||
* type aliases and Effect Schema runtime declarations, with reusable OpenAPI
|
||||
* component definitions supplied at generation time.
|
||||
*
|
||||
* @category code generation
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export function make() {
|
||||
const store: Record<string, JsonSchema.JsonSchema> = {}
|
||||
|
||||
function addSchema(name: string, schema: JsonSchema.JsonSchema): string {
|
||||
if (name in store) {
|
||||
throw new Error(`Schema ${name} already exists`)
|
||||
}
|
||||
store[name] = schema
|
||||
return name
|
||||
}
|
||||
|
||||
function generate(
|
||||
source: Source,
|
||||
components: JsonSchema.Definitions,
|
||||
typeOnly: boolean,
|
||||
options?: GenerateOptions
|
||||
) {
|
||||
const generated = makeCodeDocument(source, components, options)
|
||||
if (generated === undefined) {
|
||||
return ""
|
||||
}
|
||||
|
||||
const nonRecursiveReferences = generated.codeDocument.references.nonRecursives
|
||||
const recursiveReferences = Object.entries(generated.codeDocument.references.recursives)
|
||||
|
||||
const nonRecursives = nonRecursiveReferences.map(({ $ref, code }) =>
|
||||
renderSchemaTypeAndRuntime($ref, code, typeOnly)
|
||||
)
|
||||
|
||||
const recursiveDeclarations: Array<string> = []
|
||||
const recursives: Array<string> = []
|
||||
|
||||
if (typeOnly) {
|
||||
for (const [$ref, code] of recursiveReferences) {
|
||||
recursives.push(renderSchemaTypeAndRuntime($ref, code, true))
|
||||
}
|
||||
} else {
|
||||
const recursivelyForwardReferenced = collectForwardReferencedRecursives(
|
||||
nonRecursiveReferences,
|
||||
recursiveReferences
|
||||
)
|
||||
const recursiveInternalNames = makeRecursiveInternalNameMap(
|
||||
recursivelyForwardReferenced,
|
||||
[
|
||||
...nonRecursiveReferences.map(({ $ref }) => $ref),
|
||||
...recursiveReferences.map(([$ref]) => $ref),
|
||||
...generated.nameMap
|
||||
]
|
||||
)
|
||||
|
||||
for (const [$ref, code] of recursiveReferences) {
|
||||
if (recursivelyForwardReferenced.has($ref)) {
|
||||
const internalName = recursiveInternalNames.get($ref)!
|
||||
recursiveDeclarations.push(renderRecursiveReferenceDeclaration($ref, code, internalName))
|
||||
recursives.push(`const ${internalName} = ${code.runtime}`)
|
||||
continue
|
||||
}
|
||||
|
||||
recursives.push(renderSchemaTypeAndRuntime($ref, code, false))
|
||||
}
|
||||
}
|
||||
|
||||
const codes = generated.codeDocument.codes.map((code, i) =>
|
||||
renderSchemaTypeAndRuntime(generated.nameMap[i], code, typeOnly)
|
||||
)
|
||||
|
||||
return render("recursive declarations", recursiveDeclarations) +
|
||||
render("non-recursive definitions", nonRecursives) +
|
||||
render("recursive definitions", recursives) +
|
||||
render("schemas", codes)
|
||||
}
|
||||
|
||||
function generateHttpApi(
|
||||
source: Source,
|
||||
components: JsonSchema.Definitions,
|
||||
options?: GenerateHttpApiOptions
|
||||
) {
|
||||
const generated = makeCodeDocument(source, components, options)
|
||||
if (generated === undefined) {
|
||||
return ""
|
||||
}
|
||||
|
||||
const nonRecursiveReferences = generated.codeDocument.references.nonRecursives
|
||||
const recursiveReferences = Object.entries(generated.codeDocument.references.recursives)
|
||||
|
||||
const nonRecursives = nonRecursiveReferences.map(({ $ref, code }) =>
|
||||
renderSchemaTypeAndRuntime($ref, code, false, options?.multipartSchemaRefs)
|
||||
)
|
||||
|
||||
const recursivelyForwardReferenced = collectForwardReferencedRecursives(nonRecursiveReferences, recursiveReferences)
|
||||
const recursiveInternalNames = makeRecursiveInternalNameMap(
|
||||
recursivelyForwardReferenced,
|
||||
[
|
||||
...nonRecursiveReferences.map(({ $ref }) => $ref),
|
||||
...recursiveReferences.map(([$ref]) => $ref),
|
||||
...generated.nameMap
|
||||
]
|
||||
)
|
||||
|
||||
const recursiveDeclarations: Array<string> = []
|
||||
const recursives: Array<string> = []
|
||||
|
||||
for (const [$ref, code] of recursiveReferences) {
|
||||
if (recursivelyForwardReferenced.has($ref)) {
|
||||
const internalName = recursiveInternalNames.get($ref)!
|
||||
recursiveDeclarations.push(renderRecursiveReferenceDeclaration($ref, code, internalName))
|
||||
recursives.push(`const ${internalName} = ${code.runtime}`)
|
||||
continue
|
||||
}
|
||||
|
||||
recursives.push(renderSchemaTypeAndRuntime($ref, code, false, options?.multipartSchemaRefs))
|
||||
}
|
||||
|
||||
const codes = generated.codeDocument.codes.map((code, i) =>
|
||||
renderSchemaTypeAndRuntime(generated.nameMap[i], code, false, options?.multipartSchemaRefs)
|
||||
)
|
||||
|
||||
return render("recursive declarations", recursiveDeclarations) +
|
||||
render("non-recursive definitions", nonRecursives) +
|
||||
render("recursive definitions", recursives) +
|
||||
render("schemas", codes)
|
||||
}
|
||||
|
||||
function makeCodeDocument(
|
||||
source: Source,
|
||||
components: JsonSchema.Definitions,
|
||||
options?: GenerateOptions
|
||||
): {
|
||||
readonly nameMap: Array<string>
|
||||
readonly codeDocument: SchemaRepresentation.CodeDocument
|
||||
} | undefined {
|
||||
const nameMap: Array<string> = []
|
||||
const schemas: Array<JsonSchema.JsonSchema> = []
|
||||
|
||||
const definitions: JsonSchema.Definitions = Rec.map(
|
||||
components,
|
||||
(js) => fromSchemaOpenApi(source, js).schema
|
||||
)
|
||||
|
||||
for (const [name, js] of Object.entries(store)) {
|
||||
nameMap.push(name)
|
||||
schemas.push(fromSchemaOpenApi(source, js).schema)
|
||||
}
|
||||
|
||||
if (!Arr.isArrayNonEmpty(schemas)) {
|
||||
return
|
||||
}
|
||||
|
||||
const multiDocument: SchemaRepresentation.MultiDocument = SchemaRepresentation.fromJsonSchemaMultiDocument({
|
||||
dialect: "draft-2020-12",
|
||||
schemas,
|
||||
definitions
|
||||
}, {
|
||||
onEnter(js) {
|
||||
const out = { ...js }
|
||||
if (out.type === "object" && out.additionalProperties === undefined) {
|
||||
out.additionalProperties = false
|
||||
}
|
||||
return options?.onEnter?.(out) ?? out
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
nameMap,
|
||||
codeDocument: SchemaRepresentation.toCodeDocument(multiDocument)
|
||||
}
|
||||
}
|
||||
|
||||
return { addSchema, generate, generateHttpApi } as const
|
||||
}
|
||||
|
||||
function fromSchemaOpenApi(source: Source, jsonSchema: JsonSchema.JsonSchema) {
|
||||
switch (source) {
|
||||
case "openapi-3.1":
|
||||
return JsonSchema.fromSchemaOpenApi3_1(jsonSchema)
|
||||
case "openapi-3.0":
|
||||
return JsonSchema.fromSchemaOpenApi3_0(jsonSchema)
|
||||
}
|
||||
}
|
||||
|
||||
function renderSchemaTypeAndRuntime(
|
||||
$ref: string,
|
||||
code: SchemaRepresentation.Code,
|
||||
typeOnly: boolean,
|
||||
multipartSchemaRefs?: {
|
||||
readonly singleFile: string
|
||||
readonly files: string
|
||||
}
|
||||
) {
|
||||
if (!typeOnly && multipartSchemaRefs !== undefined) {
|
||||
if ($ref === multipartSchemaRefs.singleFile) {
|
||||
return [
|
||||
`export type ${$ref} = Multipart.PersistedFile`,
|
||||
`export const ${$ref} = Multipart.SingleFileSchema`
|
||||
].join("\n")
|
||||
}
|
||||
if ($ref === multipartSchemaRefs.files) {
|
||||
return [
|
||||
`export type ${$ref} = ReadonlyArray<Multipart.PersistedFile>`,
|
||||
`export const ${$ref} = Multipart.FilesSchema`
|
||||
].join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
const strings = [`export type ${$ref} = ${code.Type}`]
|
||||
if (!typeOnly) {
|
||||
strings.push(`export const ${$ref} = ${code.runtime}`)
|
||||
}
|
||||
return strings.join("\n")
|
||||
}
|
||||
|
||||
function renderRecursiveReferenceDeclaration(
|
||||
$ref: string,
|
||||
code: SchemaRepresentation.Code,
|
||||
internalName: string
|
||||
): string {
|
||||
return [
|
||||
`export type ${$ref} = ${code.Type}`,
|
||||
`export const ${$ref} = Schema.suspend((): Schema.Codec<${$ref}> => ${internalName})`
|
||||
].join("\n")
|
||||
}
|
||||
|
||||
function render(title: string, as: ReadonlyArray<string>) {
|
||||
if (as.length === 0) return ""
|
||||
return "// " + title + "\n" + as.join("\n") + "\n"
|
||||
}
|
||||
|
||||
const tokenPattern = /[A-Za-z_$][A-Za-z0-9_$]*/g
|
||||
|
||||
function collectForwardReferencedRecursives(
|
||||
nonRecursives: ReadonlyArray<{
|
||||
readonly $ref: string
|
||||
readonly code: SchemaRepresentation.Code
|
||||
}>,
|
||||
recursives: ReadonlyArray<readonly [string, SchemaRepresentation.Code]>
|
||||
): Set<string> {
|
||||
const recursiveNames = new Set(recursives.map(([name]) => name))
|
||||
const recursiveIndexes = new Map(recursives.map(([name], index) => [name, index]))
|
||||
const referenced = new Set<string>()
|
||||
|
||||
for (const { code } of nonRecursives) {
|
||||
for (const token of code.runtime.matchAll(tokenPattern)) {
|
||||
const identifier = token[0]
|
||||
if (recursiveNames.has(identifier)) {
|
||||
referenced.add(identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let index = 0; index < recursives.length; index++) {
|
||||
const [, code] = recursives[index]
|
||||
for (const token of code.runtime.matchAll(tokenPattern)) {
|
||||
const identifier = token[0]
|
||||
const referencedIndex = recursiveIndexes.get(identifier)
|
||||
if (referencedIndex !== undefined && referencedIndex > index) {
|
||||
referenced.add(identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return referenced
|
||||
}
|
||||
|
||||
function makeRecursiveInternalNameMap(
|
||||
recursiveNames: ReadonlySet<string>,
|
||||
existingNames: ReadonlyArray<string>
|
||||
): Map<string, string> {
|
||||
const usedNames = new Set(existingNames)
|
||||
const internalNames = new Map<string, string>()
|
||||
|
||||
for (const name of recursiveNames) {
|
||||
let candidate = `__recursive_${name}`
|
||||
while (usedNames.has(candidate)) {
|
||||
candidate = `_${candidate}`
|
||||
}
|
||||
usedNames.add(candidate)
|
||||
internalNames.set(name, candidate)
|
||||
}
|
||||
|
||||
return internalNames
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,539 @@
|
||||
/**
|
||||
* OpenAPI spec patching utilities.
|
||||
*
|
||||
* Handles parsing and applying JSON Patch documents (RFC 6902) to OpenAPI
|
||||
* specs. Supports patches from:
|
||||
* - JSON files (.json)
|
||||
* - YAML files (.yaml, .yml)
|
||||
* - Inline JSON strings
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
|
||||
import * as Effect from "effect/Effect"
|
||||
import * as FileSystem from "effect/FileSystem"
|
||||
import { constFalse, constUndefined } from "effect/Function"
|
||||
import * as JsonPatch from "effect/JsonPatch"
|
||||
import * as Path from "effect/Path"
|
||||
import * as Predicate from "effect/Predicate"
|
||||
import * as Schema from "effect/Schema"
|
||||
import * as Yaml from "yaml"
|
||||
|
||||
// =============================================================================
|
||||
// Error Types
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Error thrown when parsing a JSON Patch input fails.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* This error occurs when:
|
||||
* - A patch file cannot be read
|
||||
* - JSON or YAML syntax is invalid
|
||||
* - The file format is unsupported
|
||||
*
|
||||
* **Example** (Creating a parse error)
|
||||
*
|
||||
* ```ts
|
||||
* import * as OpenApiPatch from "@effect/openapi-generator/OpenApiPatch"
|
||||
*
|
||||
* const error = new OpenApiPatch.JsonPatchParseError({
|
||||
* source: "./patches/fix.json",
|
||||
* reason: "Unexpected token at position 42"
|
||||
* })
|
||||
*
|
||||
* console.log(error.message)
|
||||
* // "Failed to parse patch from ./patches/fix.json: Unexpected token at position 42"
|
||||
* ```
|
||||
*
|
||||
* @category errors
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export class JsonPatchParseError extends Schema.ErrorClass<JsonPatchParseError>("JsonPatchParseError")({
|
||||
_tag: Schema.tag("JsonPatchParseError"),
|
||||
source: Schema.String,
|
||||
reason: Schema.String
|
||||
}) {
|
||||
override get message() {
|
||||
return `Failed to parse patch from ${this.source}: ${this.reason}`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error thrown when a parsed value does not conform to the JSON Patch schema.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* This error occurs when:
|
||||
* - The patch is not an array
|
||||
* - An operation is missing required fields (op, path)
|
||||
* - An operation has an unsupported op value
|
||||
* - An add/replace operation is missing the value field
|
||||
*
|
||||
* **Example** (Creating a validation error)
|
||||
*
|
||||
* ```ts
|
||||
* import * as OpenApiPatch from "@effect/openapi-generator/OpenApiPatch"
|
||||
*
|
||||
* const error = new OpenApiPatch.JsonPatchValidationError({
|
||||
* source: "inline",
|
||||
* reason: "Expected 'add' | 'remove' | 'replace' at [0].op, got 'copy'"
|
||||
* })
|
||||
*
|
||||
* console.log(error.message)
|
||||
* // "Invalid JSON Patch from inline: Expected 'add' | 'remove' | 'replace' at [0].op, got 'copy'"
|
||||
* ```
|
||||
*
|
||||
* @category errors
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export class JsonPatchValidationError extends Schema.ErrorClass<JsonPatchValidationError>("JsonPatchValidationError")({
|
||||
_tag: Schema.tag("JsonPatchValidationError"),
|
||||
source: Schema.String,
|
||||
reason: Schema.String
|
||||
}) {
|
||||
override get message() {
|
||||
return `Invalid JSON Patch from ${this.source}: ${this.reason}`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error thrown when applying a JSON Patch operation fails.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* This error occurs when:
|
||||
* - A path does not exist for remove/replace operations
|
||||
* - An array index is out of bounds
|
||||
* - The target location is not a valid container
|
||||
*
|
||||
* **Example** (Creating an application error)
|
||||
*
|
||||
* ```ts
|
||||
* import * as OpenApiPatch from "@effect/openapi-generator/OpenApiPatch"
|
||||
*
|
||||
* const error = new OpenApiPatch.JsonPatchApplicationError({
|
||||
* source: "./patches/fix.json",
|
||||
* operationIndex: 2,
|
||||
* operation: "remove",
|
||||
* path: "/paths/~1users",
|
||||
* reason: "Property \"users\" does not exist"
|
||||
* })
|
||||
*
|
||||
* console.log(error.message)
|
||||
* // "Failed to apply patch from ./patches/fix.json: operation 2 (remove at /paths/~1users): Property \"users\" does not exist"
|
||||
* ```
|
||||
*
|
||||
* @category errors
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export class JsonPatchApplicationError
|
||||
extends Schema.ErrorClass<JsonPatchApplicationError>("JsonPatchApplicationError")({
|
||||
_tag: Schema.tag("JsonPatchApplicationError"),
|
||||
source: Schema.String,
|
||||
operationIndex: Schema.Number,
|
||||
operation: Schema.String,
|
||||
path: Schema.String,
|
||||
reason: Schema.String
|
||||
})
|
||||
{
|
||||
override get message() {
|
||||
return `Failed to apply patch from ${this.source}: operation ${this.operationIndex} ` +
|
||||
`(${this.operation} at ${this.path}): ${this.reason}`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error thrown when multiple JSON Patch operations fail.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* This error aggregates all application errors so users can see every
|
||||
* failing operation at once instead of fixing them one at a time.
|
||||
*
|
||||
* **Example** (Creating an aggregate error)
|
||||
*
|
||||
* ```ts
|
||||
* import * as OpenApiPatch from "@effect/openapi-generator/OpenApiPatch"
|
||||
*
|
||||
* const error = new OpenApiPatch.JsonPatchAggregateError({
|
||||
* errors: [
|
||||
* new OpenApiPatch.JsonPatchApplicationError({
|
||||
* source: "./fix.json",
|
||||
* operationIndex: 0,
|
||||
* operation: "replace",
|
||||
* path: "/info/x",
|
||||
* reason: "Property does not exist"
|
||||
* }),
|
||||
* new OpenApiPatch.JsonPatchApplicationError({
|
||||
* source: "./fix.json",
|
||||
* operationIndex: 2,
|
||||
* operation: "remove",
|
||||
* path: "/paths/~1users",
|
||||
* reason: "Property does not exist"
|
||||
* })
|
||||
* ]
|
||||
* })
|
||||
*
|
||||
* console.log(error.message)
|
||||
* // "2 patch operations failed:\n 1. ..."
|
||||
* ```
|
||||
*
|
||||
* @category errors
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export class JsonPatchAggregateError extends Schema.ErrorClass<JsonPatchAggregateError>("JsonPatchAggregateError")({
|
||||
_tag: Schema.tag("JsonPatchAggregateError"),
|
||||
errors: Schema.Array(Schema.Unknown)
|
||||
}) {
|
||||
override get message() {
|
||||
const errors = this.errors as ReadonlyArray<JsonPatchApplicationError>
|
||||
const count = errors.length
|
||||
const plural = count === 1 ? "operation" : "operations"
|
||||
const details = errors
|
||||
.map((e, i) => ` ${i + 1}. [${e.source}] op ${e.operationIndex} (${e.operation} at ${e.path}): ${e.reason}`)
|
||||
.join("\n")
|
||||
return `${count} patch ${plural} failed:\n${details}`
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Schema
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Schema for a JSON Patch "add" operation.
|
||||
*
|
||||
* @category schemas
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const JsonPatchAdd: Schema.Codec<
|
||||
Extract<
|
||||
JsonPatch.JsonPatchOperation,
|
||||
{ op: "add" }
|
||||
>
|
||||
> = Schema.Struct({
|
||||
op: Schema.Literal("add"),
|
||||
path: Schema.String,
|
||||
value: Schema.Json,
|
||||
description: Schema.optionalKey(Schema.String)
|
||||
})
|
||||
|
||||
/**
|
||||
* Schema for a JSON Patch "remove" operation.
|
||||
*
|
||||
* @category schemas
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const JsonPatchRemove: Schema.Codec<
|
||||
Extract<
|
||||
JsonPatch.JsonPatchOperation,
|
||||
{ op: "remove" }
|
||||
>
|
||||
> = Schema.Struct({
|
||||
op: Schema.Literal("remove"),
|
||||
path: Schema.String,
|
||||
description: Schema.optionalKey(Schema.String)
|
||||
})
|
||||
|
||||
/**
|
||||
* Schema for a JSON Patch "replace" operation.
|
||||
*
|
||||
* @category schemas
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const JsonPatchReplace: Schema.Codec<
|
||||
Extract<
|
||||
JsonPatch.JsonPatchOperation,
|
||||
{ op: "replace" }
|
||||
>
|
||||
> = Schema.Struct({
|
||||
op: Schema.Literal("replace"),
|
||||
path: Schema.String,
|
||||
value: Schema.Json,
|
||||
description: Schema.optionalKey(Schema.String)
|
||||
})
|
||||
|
||||
/**
|
||||
* Schema for a single JSON Patch operation.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* Supports the subset of RFC 6902 operations that Effect's JsonPatch module
|
||||
* implements: `add`, `remove`, and `replace`.
|
||||
*
|
||||
* @category schemas
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const JsonPatchOperation: Schema.Codec<JsonPatch.JsonPatchOperation> = Schema.Union([
|
||||
JsonPatchAdd,
|
||||
JsonPatchRemove,
|
||||
JsonPatchReplace
|
||||
])
|
||||
|
||||
/**
|
||||
* Schema for a JSON Patch document (array of operations).
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* A JSON Patch document is an ordered list of operations to apply to a JSON
|
||||
* document. Operations are applied in sequence, with each operation seeing
|
||||
* the result of previous operations.
|
||||
*
|
||||
* **Example** (Decoding a patch document)
|
||||
*
|
||||
* ```ts
|
||||
* import { Schema } from "effect"
|
||||
* import * as OpenApiPatch from "@effect/openapi-generator/OpenApiPatch"
|
||||
*
|
||||
* const patch = Schema.decodeUnknownSync(OpenApiPatch.JsonPatchDocument)([
|
||||
* { op: "add", path: "/foo", value: "bar" },
|
||||
* { op: "remove", path: "/baz" },
|
||||
* { op: "replace", path: "/qux", value: 42 }
|
||||
* ])
|
||||
* ```
|
||||
*
|
||||
* @category schemas
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const JsonPatchDocument = Schema.Array(JsonPatchOperation)
|
||||
|
||||
/**
|
||||
* Type for a JSON Patch document.
|
||||
*
|
||||
* @category types
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export type JsonPatchDocument = typeof JsonPatchDocument.Type
|
||||
|
||||
// =============================================================================
|
||||
// Parsing Functions
|
||||
// =============================================================================
|
||||
|
||||
const decodeJsonPatchDocument = Schema.decodeUnknownEffect(JsonPatchDocument)
|
||||
|
||||
/**
|
||||
* Check if a string looks like it could be a file path.
|
||||
*
|
||||
* Heuristic: contains path separators or ends with a known extension.
|
||||
*/
|
||||
const looksLikeFilePath = (input: string): boolean => {
|
||||
const trimmed = input.trim()
|
||||
if (trimmed.startsWith("[")) return false
|
||||
if (trimmed.includes("/") || trimmed.includes("\\")) return true
|
||||
if (/\.(json|yaml|yml)$/i.test(trimmed)) return true
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine file format from extension.
|
||||
*/
|
||||
const getFileFormat = Effect.fn(function*(filePath: string) {
|
||||
const path = yield* Path.Path
|
||||
const { ext } = path.parse(filePath)
|
||||
if (ext === ".json") return "json"
|
||||
if (ext === ".yaml" || ext === ".yml") return "yaml"
|
||||
return undefined
|
||||
})
|
||||
|
||||
/**
|
||||
* Check if a file path exists and is a file.
|
||||
*/
|
||||
const checkFileExists = Effect.fn("checkFileExists")(function*(filePath: string) {
|
||||
const fs = yield* FileSystem.FileSystem
|
||||
const path = yield* Path.Path
|
||||
const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath)
|
||||
const exists = yield* Effect.orElseSucceed(fs.exists(absolutePath), constFalse)
|
||||
if (!exists) return false
|
||||
const stat = yield* Effect.orElseSucceed(fs.stat(absolutePath), constUndefined)
|
||||
return Predicate.isNotUndefined(stat) && stat.type === "File"
|
||||
})
|
||||
|
||||
/**
|
||||
* Parse content as JSON.
|
||||
*/
|
||||
const parseJsonContent = Effect.fnUntraced(function*(content: string, source: string) {
|
||||
return yield* Effect.try({
|
||||
try: () => JSON.parse(content) as unknown,
|
||||
catch: (error) =>
|
||||
new JsonPatchParseError({
|
||||
source,
|
||||
reason: error instanceof Error ? error.message : String(error)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* Parse content as YAML.
|
||||
*/
|
||||
const parseYamlContent = Effect.fnUntraced(function*(content: string, source: string) {
|
||||
return yield* Effect.try({
|
||||
try: () => Yaml.parse(content) as unknown,
|
||||
catch: (error) =>
|
||||
new JsonPatchParseError({
|
||||
source,
|
||||
reason: error instanceof Error ? error.message : String(error)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* Read and parse a patch file.
|
||||
*/
|
||||
const parsePatchFile = Effect.fn("parsePatchFile")(function*(filePath: string) {
|
||||
const fs = yield* FileSystem.FileSystem
|
||||
const path = yield* Path.Path
|
||||
const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath)
|
||||
|
||||
const fileFormat = yield* getFileFormat(filePath)
|
||||
if (Predicate.isUndefined(fileFormat)) {
|
||||
return yield* new JsonPatchParseError({
|
||||
source: filePath,
|
||||
reason: `Unsupported file format. Expected .json, .yaml, or .yml`
|
||||
})
|
||||
}
|
||||
|
||||
const content = yield* Effect.mapError(fs.readFileString(absolutePath), (error) =>
|
||||
new JsonPatchParseError({
|
||||
source: filePath,
|
||||
reason: `Failed to read file: ${error.message}`
|
||||
}))
|
||||
|
||||
const parsed = fileFormat === "json"
|
||||
? yield* parseJsonContent(content, filePath)
|
||||
: yield* parseYamlContent(content, filePath)
|
||||
|
||||
return yield* Effect.mapError(decodeJsonPatchDocument(parsed), (error) =>
|
||||
new JsonPatchValidationError({
|
||||
source: filePath,
|
||||
reason: error.message
|
||||
}))
|
||||
})
|
||||
|
||||
/**
|
||||
* Parse inline JSON string as a patch document.
|
||||
*/
|
||||
const parseInlinePatch = Effect.fn("parseInlinePatch")(function*(input: string) {
|
||||
const parsed = yield* parseJsonContent(input, "inline")
|
||||
return yield* Effect.mapError(decodeJsonPatchDocument(parsed), (error) =>
|
||||
new JsonPatchValidationError({
|
||||
source: "inline",
|
||||
reason: error.message
|
||||
}))
|
||||
})
|
||||
|
||||
/**
|
||||
* Parse a JSON Patch from either a file path or inline JSON string.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* The input is first checked as a file path. If the file exists, it is read
|
||||
* and parsed based on its extension (.json, .yaml, .yml). Otherwise, the
|
||||
* input is parsed as inline JSON.
|
||||
*
|
||||
* **Example** (Parsing patch input)
|
||||
*
|
||||
* ```ts
|
||||
* import { Effect } from "effect"
|
||||
* import * as OpenApiPatch from "@effect/openapi-generator/OpenApiPatch"
|
||||
*
|
||||
* // From inline JSON
|
||||
* const fromInline = OpenApiPatch.parsePatchInput(
|
||||
* '[{"op":"replace","path":"/info/title","value":"My API"}]'
|
||||
* )
|
||||
*
|
||||
* // From file path
|
||||
* const fromFile = OpenApiPatch.parsePatchInput("./patches/fix-api.json")
|
||||
*
|
||||
* const program = Effect.gen(function*() {
|
||||
* const patch = yield* fromInline
|
||||
* console.log(patch)
|
||||
* // [{ op: "replace", path: "/info/title", value: "My API" }]
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @category parsing
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const parsePatchInput = Effect.fn("parsePatchInput")(function*(input: string) {
|
||||
if (looksLikeFilePath(input)) {
|
||||
const exists = yield* checkFileExists(input)
|
||||
if (exists) {
|
||||
return yield* parsePatchFile(input)
|
||||
}
|
||||
}
|
||||
return yield* parseInlinePatch(input)
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// Application Functions
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Apply a sequence of JSON patches to a document.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* Patches are applied in order, with each patch operating on the result of
|
||||
* the previous one. All operations are attempted, and if any fail, the errors
|
||||
* are accumulated and reported together so users can fix all issues at once.
|
||||
*
|
||||
* **Example** (Applying patches)
|
||||
*
|
||||
* ```ts
|
||||
* import { Effect } from "effect"
|
||||
* import * as OpenApiPatch from "@effect/openapi-generator/OpenApiPatch"
|
||||
*
|
||||
* const document = { info: { title: "Old Title" }, paths: {} }
|
||||
* const patches = [
|
||||
* {
|
||||
* source: "inline",
|
||||
* patch: [{ op: "replace" as const, path: "/info/title", value: "New Title" }]
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* const program = Effect.gen(function*() {
|
||||
* const result = yield* OpenApiPatch.applyPatches(patches, document)
|
||||
* console.log(result)
|
||||
* // { info: { title: "New Title" }, paths: {} }
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @category application
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const applyPatches = Effect.fn("applyPatches")(function*(
|
||||
patches: ReadonlyArray<{ readonly source: string; readonly patch: JsonPatchDocument }>,
|
||||
document: Schema.Json
|
||||
) {
|
||||
let result: Schema.Json = document
|
||||
const errors: Array<JsonPatchApplicationError> = []
|
||||
|
||||
for (const { source, patch } of patches) {
|
||||
for (let i = 0; i < patch.length; i++) {
|
||||
const op = patch[i]
|
||||
yield* Effect.ignore(Effect.try({
|
||||
try: () => {
|
||||
result = JsonPatch.apply([op], result)
|
||||
},
|
||||
catch: (error) =>
|
||||
errors.push(
|
||||
new JsonPatchApplicationError({
|
||||
source,
|
||||
operationIndex: i,
|
||||
operation: op.op,
|
||||
path: op.path,
|
||||
reason: error instanceof Error ? error.message : String(error)
|
||||
})
|
||||
)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
return yield* new JsonPatchAggregateError({ errors })
|
||||
}
|
||||
|
||||
return result
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,277 @@
|
||||
/**
|
||||
* Normalized OpenAPI operation model shared by the generator pipeline.
|
||||
*
|
||||
* This module records the shape produced after an OpenAPI document is resolved
|
||||
* into stable generator inputs: document metadata, tags, security schemes,
|
||||
* per-operation parameters, request bodies, response media types, derived
|
||||
* schema references, path templates, and streaming capabilities. Renderers
|
||||
* consume this representation to emit HttpClient or HttpApi modules without
|
||||
* reinterpreting raw OpenAPI path-item structures.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
import type * as Types from "effect/Types"
|
||||
import type {
|
||||
OpenAPISecurityRequirement,
|
||||
OpenAPISpecExternalDocs,
|
||||
OpenAPISpecLicense,
|
||||
OpenAPISpecMethodName,
|
||||
OpenAPISpecServer
|
||||
} from "effect/unstable/httpapi/OpenApi"
|
||||
|
||||
/**
|
||||
* Root OpenAPI metadata preserved for generated client and HttpApi output.
|
||||
*
|
||||
* @category models
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export interface ParsedOpenApiMetadata {
|
||||
readonly title: string
|
||||
readonly version: string
|
||||
readonly summary: string | undefined
|
||||
readonly description: string | undefined
|
||||
readonly license: OpenAPISpecLicense | undefined
|
||||
readonly servers: ReadonlyArray<OpenAPISpecServer> | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag metadata used to group and annotate generated operations.
|
||||
*
|
||||
* @category models
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export interface ParsedOpenApiTag {
|
||||
readonly name: string
|
||||
readonly description: string | undefined
|
||||
readonly externalDocs: OpenAPISpecExternalDocs | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported security scheme extracted from an OpenAPI components section.
|
||||
*
|
||||
* @category models
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export interface ParsedOpenApiSecurityScheme {
|
||||
readonly name: string
|
||||
readonly type: "basic" | "bearer" | "apiKey" | "http"
|
||||
readonly description: string | undefined
|
||||
readonly bearerFormat: string | undefined
|
||||
readonly scheme: string | undefined
|
||||
readonly key: string | undefined
|
||||
readonly in: "header" | "query" | "cookie" | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalized OpenAPI document consumed by the generator renderers.
|
||||
*
|
||||
* @category models
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export interface ParsedOpenApi {
|
||||
readonly metadata: ParsedOpenApiMetadata
|
||||
readonly tags: ReadonlyArray<ParsedOpenApiTag>
|
||||
readonly securitySchemes: ReadonlyArray<ParsedOpenApiSecurityScheme>
|
||||
readonly operations: ReadonlyArray<ParsedOperation>
|
||||
}
|
||||
|
||||
/**
|
||||
* Documentation and lifecycle metadata associated with an operation.
|
||||
*
|
||||
* @category models
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export interface ParsedOperationMetadata {
|
||||
readonly summary: string | undefined
|
||||
readonly description: string | undefined
|
||||
readonly deprecated: boolean
|
||||
readonly externalDocs: OpenAPISpecExternalDocs | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolved OpenAPI parameter grouped by where it appears in the request.
|
||||
*
|
||||
* @category models
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export interface ParsedOperationParameter {
|
||||
readonly name: string
|
||||
readonly in: "path" | "query" | "header" | "cookie"
|
||||
readonly required: boolean
|
||||
readonly description: string | undefined
|
||||
readonly schema: {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Summary of the request body declaration before per-media schemas are rendered.
|
||||
*
|
||||
* @category models
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export interface ParsedOperationRequestBody {
|
||||
readonly required: boolean
|
||||
readonly contentTypes: Array<string>
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoding strategy the generator can use for a request or response media type.
|
||||
*
|
||||
* @category models
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export type ParsedOperationMediaTypeEncoding =
|
||||
| "json"
|
||||
| "multipart"
|
||||
| "form-url-encoded"
|
||||
| "text"
|
||||
| "binary"
|
||||
|
||||
/**
|
||||
* Media type whose schema can be represented in generated Effect code.
|
||||
*
|
||||
* @category models
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export type ParsedOperationMediaTypeSchema =
|
||||
| {
|
||||
readonly contentType: string
|
||||
readonly encoding: ParsedOperationMediaTypeEncoding
|
||||
readonly schema: string
|
||||
readonly effectStream?: undefined
|
||||
}
|
||||
| {
|
||||
readonly contentType: string
|
||||
readonly encoding: "text"
|
||||
readonly schema: string
|
||||
readonly effectStream: "sse"
|
||||
readonly errorSchema: string
|
||||
}
|
||||
| {
|
||||
readonly contentType: string
|
||||
readonly encoding: "binary"
|
||||
readonly schema?: undefined
|
||||
readonly effectStream: "uint8array"
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsed response metadata together with generated schema references.
|
||||
*
|
||||
* @category models
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export interface ParsedOperationResponse {
|
||||
readonly status: string
|
||||
readonly description: string | undefined
|
||||
readonly contentTypes: Array<string>
|
||||
readonly hasHeaders: boolean
|
||||
readonly isEmpty: boolean
|
||||
readonly representable: ReadonlyArray<ParsedOperationMediaTypeSchema>
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolved security requirement applied to a parsed operation.
|
||||
*
|
||||
* @category models
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export type ParsedOperationSecurityRequirement = Readonly<OpenAPISecurityRequirement>
|
||||
|
||||
/**
|
||||
* Normalized operation model shared by all OpenAPI generator backends.
|
||||
*
|
||||
* @category models
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export interface ParsedOperation {
|
||||
readonly id: string
|
||||
readonly operationId: string | undefined
|
||||
readonly path: string
|
||||
readonly method: OpenAPISpecMethodName
|
||||
readonly tags: ReadonlyArray<string>
|
||||
readonly metadata: ParsedOperationMetadata
|
||||
readonly parameters: {
|
||||
readonly path: ReadonlyArray<ParsedOperationParameter>
|
||||
readonly query: ReadonlyArray<ParsedOperationParameter>
|
||||
readonly header: ReadonlyArray<ParsedOperationParameter>
|
||||
readonly cookie: ReadonlyArray<ParsedOperationParameter>
|
||||
}
|
||||
readonly requestBody: ParsedOperationRequestBody | undefined
|
||||
readonly responses: ReadonlyArray<ParsedOperationResponse>
|
||||
readonly defaultResponse: ParsedOperationResponse | undefined
|
||||
readonly effectiveSecurity: ReadonlyArray<ParsedOperationSecurityRequirement>
|
||||
readonly description: string | undefined
|
||||
readonly params?: string
|
||||
readonly paramsOptional: boolean
|
||||
readonly urlParams: ReadonlyArray<string>
|
||||
readonly headers: ReadonlyArray<string>
|
||||
readonly cookies: ReadonlyArray<string>
|
||||
readonly payload?: string
|
||||
readonly payloadFormData: boolean
|
||||
readonly payloadFormUrlEncoded: boolean
|
||||
readonly pathSchema: string | undefined
|
||||
readonly querySchema: string | undefined
|
||||
readonly querySchemaOptional: boolean
|
||||
readonly headersSchema: string | undefined
|
||||
readonly headersSchemaOptional: boolean
|
||||
readonly requestBodyRepresentable: ReadonlyArray<ParsedOperationMediaTypeSchema>
|
||||
readonly pathIds: ReadonlyArray<string>
|
||||
readonly pathTemplate: string
|
||||
readonly successSchemas: ReadonlyMap<string, string>
|
||||
readonly errorSchemas: ReadonlyMap<string, string>
|
||||
readonly voidSchemas: ReadonlySet<string>
|
||||
// SSE streaming response schema (text/event-stream)
|
||||
readonly sseSchema?: string
|
||||
// Binary stream response (application/octet-stream)
|
||||
readonly binaryResponse: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mutable operation accumulator populated with parser defaults.
|
||||
*
|
||||
* @category constructors
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const makeDeepMutable = (options: {
|
||||
readonly id: string
|
||||
readonly method: OpenAPISpecMethodName
|
||||
readonly pathIds: Array<string>
|
||||
readonly pathTemplate: string
|
||||
readonly description: string | undefined
|
||||
}): Types.DeepMutable<ParsedOperation> => ({
|
||||
...options,
|
||||
operationId: undefined,
|
||||
path: "",
|
||||
tags: [],
|
||||
metadata: {
|
||||
summary: undefined,
|
||||
description: options.description,
|
||||
deprecated: false,
|
||||
externalDocs: undefined
|
||||
},
|
||||
parameters: {
|
||||
path: [],
|
||||
query: [],
|
||||
header: [],
|
||||
cookie: []
|
||||
},
|
||||
requestBody: undefined,
|
||||
responses: [],
|
||||
defaultResponse: undefined,
|
||||
effectiveSecurity: [],
|
||||
urlParams: [],
|
||||
headers: [],
|
||||
cookies: [],
|
||||
payloadFormData: false,
|
||||
payloadFormUrlEncoded: false,
|
||||
pathSchema: undefined,
|
||||
querySchema: undefined,
|
||||
querySchemaOptional: true,
|
||||
headersSchema: undefined,
|
||||
headersSchemaOptional: true,
|
||||
requestBodyRepresentable: [],
|
||||
successSchemas: new Map(),
|
||||
errorSchemas: new Map(),
|
||||
voidSchemas: new Set(),
|
||||
paramsOptional: true,
|
||||
binaryResponse: false
|
||||
})
|
||||
111
repos/effect/packages/tools/openapi-generator/src/Utils.ts
Normal file
111
repos/effect/packages/tools/openapi-generator/src/Utils.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Shared utility helpers for the OpenAPI generator.
|
||||
*
|
||||
* This module centralizes the small transformations used while rendering
|
||||
* generated TypeScript, including operation-name normalization, optional
|
||||
* description handling, safe JSDoc comment emission, and direct array merging
|
||||
* for code-generation accumulators.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
import * as String from "effect/String"
|
||||
import * as UndefinedOr from "effect/UndefinedOr"
|
||||
|
||||
/**
|
||||
* Converts an OpenAPI name into the generator's camel-case form.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* Separators are removed, leading digits are ignored, and letters following a
|
||||
* separator or digit are upper-cased without otherwise changing letter casing.
|
||||
*
|
||||
* @category converting
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const camelize = (self: string): string => {
|
||||
let str = ""
|
||||
let hadSymbol = false
|
||||
for (let i = 0; i < self.length; i++) {
|
||||
const charCode = self.charCodeAt(i)
|
||||
if (
|
||||
(charCode >= 65 && charCode <= 90) ||
|
||||
(charCode >= 97 && charCode <= 122)
|
||||
) {
|
||||
str += hadSymbol ? self[i].toUpperCase() : self[i]
|
||||
hadSymbol = false
|
||||
} else if (charCode >= 48 && charCode <= 57) {
|
||||
if (str.length > 0) {
|
||||
str += self[i]
|
||||
hadSymbol = true
|
||||
}
|
||||
} else if (str.length > 0) {
|
||||
hadSymbol = true
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an OpenAPI operation id into the exported operation identifier used
|
||||
* by generated TypeScript modules.
|
||||
*
|
||||
* @category converting
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const identifier = (operationId: string) => String.capitalize(camelize(operationId))
|
||||
|
||||
/**
|
||||
* Extracts a trimmed, non-empty string from an unknown value.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* Returns `undefined` for non-string values and for strings containing only
|
||||
* whitespace.
|
||||
*
|
||||
* @category filtering
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const nonEmptyString = (a: unknown): string | undefined => {
|
||||
if (typeof a === "string") {
|
||||
const trimmed = String.trim(a)
|
||||
if (String.isNonEmpty(trimmed)) {
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an optional description as a JSDoc block for generated TypeScript.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* Returns an empty string when the description is absent and escapes any
|
||||
* closing comment marker so generated source remains syntactically valid.
|
||||
*
|
||||
* @category converting
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const toComment = UndefinedOr.match({
|
||||
onUndefined: () => "",
|
||||
onDefined: (description: string) =>
|
||||
`/**
|
||||
* ${description.replace(/\*\//g, " * /").split("\n").join("\n* ")}
|
||||
*/\n`
|
||||
})
|
||||
|
||||
/**
|
||||
* Appends every element from `source` into `destination` in order.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* This mutates `destination` directly, which avoids allocating an intermediate
|
||||
* array when generator code needs to merge collections.
|
||||
*
|
||||
* @category concatenating
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const spreadElementsInto = <A>(source: Array<A>, destination: Array<A>): void => {
|
||||
for (let i = 0; i < source.length; i++) {
|
||||
destination.push(source[i])
|
||||
}
|
||||
}
|
||||
10
repos/effect/packages/tools/openapi-generator/src/bin.ts
Executable file
10
repos/effect/packages/tools/openapi-generator/src/bin.ts
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
import * as NodeRuntime from "@effect/platform-node/NodeRuntime"
|
||||
import * as NodeServices from "@effect/platform-node/NodeServices"
|
||||
import * as Effect from "effect/Effect"
|
||||
import { run } from "./main.ts"
|
||||
|
||||
run.pipe(
|
||||
Effect.provide(NodeServices.layer),
|
||||
NodeRuntime.runMain
|
||||
)
|
||||
116
repos/effect/packages/tools/openapi-generator/src/main.ts
Normal file
116
repos/effect/packages/tools/openapi-generator/src/main.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Command-line entry point for generating Effect HTTP clients or HttpApi
|
||||
* definitions from an OpenAPI specification.
|
||||
*
|
||||
* The CLI reads a spec file, optionally applies JSON patches in order, selects
|
||||
* the generator layer for the requested output format, reports generation
|
||||
* warnings to stderr, and writes the generated source to stdout.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
import * as Console from "effect/Console"
|
||||
import * as Effect from "effect/Effect"
|
||||
import type * as Schema from "effect/Schema"
|
||||
import * as CliError from "effect/unstable/cli/CliError"
|
||||
import * as Command from "effect/unstable/cli/Command"
|
||||
import * as Flag from "effect/unstable/cli/Flag"
|
||||
import type { OpenAPISpec } from "effect/unstable/httpapi/OpenApi"
|
||||
import * as OpenApiGenerator from "./OpenApiGenerator.ts"
|
||||
import * as OpenApiPatch from "./OpenApiPatch.ts"
|
||||
|
||||
const spec = Flag.fileParse("spec").pipe(
|
||||
Flag.withAlias("s"),
|
||||
Flag.withDescription("The OpenAPI spec file to generate output from")
|
||||
)
|
||||
|
||||
const name = Flag.string("name").pipe(
|
||||
Flag.withAlias("n"),
|
||||
Flag.withDescription("The name of the generated output"),
|
||||
Flag.withDefault("Client")
|
||||
)
|
||||
|
||||
const format = Flag.choice("format", ["httpclient", "httpclient-type-only", "httpapi"] as const).pipe(
|
||||
Flag.withAlias("f"),
|
||||
Flag.withDescription(
|
||||
"Output format to generate: httpclient | httpclient-type-only | httpapi (default: httpclient)"
|
||||
),
|
||||
Flag.withDefault("httpclient")
|
||||
)
|
||||
|
||||
const patch = Flag.string("patch").pipe(
|
||||
Flag.withAlias("p"),
|
||||
Flag.withDescription(
|
||||
"JSON patch to apply to OpenAPI spec before generation. " +
|
||||
"Can be a file path (.json, .yaml, .yml) or inline JSON array. " +
|
||||
"Multiple patches are applied in order."
|
||||
),
|
||||
Flag.between(0, Infinity)
|
||||
)
|
||||
|
||||
const root = Command.make("openapigen", { spec, format, name, patch }).pipe(
|
||||
Command.withHandler(Effect.fnUntraced(function*({ name, spec, format, patch }) {
|
||||
let patchedSpec: Schema.Json = spec as Schema.Json
|
||||
|
||||
if (patch.length > 0) {
|
||||
const parsedPatches = yield* Effect.forEach(
|
||||
patch,
|
||||
(input) =>
|
||||
OpenApiPatch.parsePatchInput(input).pipe(
|
||||
Effect.map((p) => ({ source: input, patch: p })),
|
||||
Effect.mapError((error) => new CliError.UserError({ cause: error }))
|
||||
)
|
||||
)
|
||||
patchedSpec = yield* OpenApiPatch.applyPatches(parsedPatches, patchedSpec).pipe(
|
||||
Effect.mapError((error) => new CliError.UserError({ cause: error }))
|
||||
)
|
||||
}
|
||||
|
||||
const generator = yield* OpenApiGenerator.OpenApiGenerator
|
||||
const warnings: Array<OpenApiGenerator.OpenApiGeneratorWarning> = []
|
||||
const source = yield* generator.generate(patchedSpec as unknown as OpenAPISpec, {
|
||||
name,
|
||||
format,
|
||||
onWarning: (warning) => {
|
||||
warnings.push(warning)
|
||||
}
|
||||
})
|
||||
yield* Effect.forEach(
|
||||
warnings,
|
||||
(warning) => Console.error(formatWarning(warning)),
|
||||
{ discard: true }
|
||||
)
|
||||
return yield* Console.log(source)
|
||||
})),
|
||||
Command.provide(({ format }) =>
|
||||
format === "httpclient-type-only"
|
||||
? OpenApiGenerator.layerTransformerTs
|
||||
: OpenApiGenerator.layerTransformerSchema
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* Runs the OpenAPI generator command-line program.
|
||||
*
|
||||
* **Details**
|
||||
*
|
||||
* The command reads an OpenAPI specification, optionally applies JSON patches,
|
||||
* generates source code in the selected format, writes any generation warnings
|
||||
* to stderr, and prints the generated source to stdout.
|
||||
*
|
||||
* @category running
|
||||
* @since 4.0.0
|
||||
*/
|
||||
export const run: Effect.Effect<void, CliError.CliError, Command.Environment> = Command.run(root, {
|
||||
version: "0.0.0"
|
||||
})
|
||||
|
||||
const formatWarning = (warning: OpenApiGenerator.OpenApiGeneratorWarning): string => {
|
||||
const context = [
|
||||
warning.method?.toUpperCase(),
|
||||
warning.path,
|
||||
warning.operationId ? `(${warning.operationId})` : undefined
|
||||
].filter((value): value is string => value !== undefined)
|
||||
return context.length > 0
|
||||
? `WARNING [${warning.code}] ${context.join(" ")}: ${warning.message}`
|
||||
: `WARNING [${warning.code}] ${warning.message}`
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
import * as JsonSchemaGenerator from "@effect/openapi-generator/JsonSchemaGenerator"
|
||||
import { describe, expect, it } from "@effect/vitest"
|
||||
|
||||
describe("JsonSchemaGenerator", () => {
|
||||
it("schema & no definitions", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { type: "string" })
|
||||
const definitions = {}
|
||||
const result = generator.generate("openapi-3.1", definitions, false)
|
||||
expect(result).toBe(`// schemas
|
||||
export type A = string
|
||||
export const A = Schema.String
|
||||
`)
|
||||
})
|
||||
|
||||
it("schema & definitions", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { $ref: "#/components/schemas/B" })
|
||||
const definitions = {
|
||||
B: { type: "string" }
|
||||
}
|
||||
const result = generator.generate("openapi-3.1", definitions, false)
|
||||
expect(result).toBe(`// non-recursive definitions
|
||||
export type B = string
|
||||
export const B = Schema.String
|
||||
// schemas
|
||||
export type A = B
|
||||
export const A = B
|
||||
`)
|
||||
})
|
||||
|
||||
it("onEnter strips specified keys", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { type: "string", description: "desc", examples: ["ex"] })
|
||||
const definitions = {}
|
||||
const result = generator.generate("openapi-3.1", definitions, false, {
|
||||
onEnter: (js) => {
|
||||
const out = { ...js }
|
||||
delete out.examples
|
||||
return out
|
||||
}
|
||||
})
|
||||
expect(result).toBe(`// schemas
|
||||
export type A = string
|
||||
export const A = Schema.String.annotate({ "description": "desc" })
|
||||
`)
|
||||
})
|
||||
|
||||
it("default preserves all annotations", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { type: "string", description: "desc", examples: ["ex"] })
|
||||
const definitions = {}
|
||||
const result = generator.generate("openapi-3.1", definitions, false)
|
||||
expect(result).toBe(`// schemas
|
||||
export type A = string
|
||||
export const A = Schema.String.annotate({ "description": "desc", "examples": ["ex"] })
|
||||
`)
|
||||
})
|
||||
|
||||
it("generateHttpApi emits explicit type and const declarations", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { type: "string" })
|
||||
generator.addSchema("B", {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
required: ["id"],
|
||||
additionalProperties: false
|
||||
})
|
||||
|
||||
const result = generator.generateHttpApi("openapi-3.1", {})
|
||||
|
||||
expect(result).toContain(`export type A = string
|
||||
export const A = Schema.String`)
|
||||
expect(result).toContain(`export type B = { readonly "id": string }
|
||||
export const B = Schema.Struct({ "id": Schema.String })`)
|
||||
expect(result).not.toContain("Schema.Class<")
|
||||
expect(result).not.toContain("Schema.Opaque<")
|
||||
})
|
||||
|
||||
it("recursive schema", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { $ref: "#/components/schemas/B" })
|
||||
const definitions = {
|
||||
B: {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"children": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/B"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"children"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
const result = generator.generate("openapi-3.1", definitions, false)
|
||||
expect(result).toBe(`// recursive definitions
|
||||
export type B = { readonly "name": string, readonly "children": ReadonlyArray<B> }
|
||||
export const B = Schema.Struct({ "name": Schema.String, "children": Schema.Array(Schema.suspend((): Schema.Codec<B> => B)) })
|
||||
// schemas
|
||||
export type A = B
|
||||
export const A = B
|
||||
`)
|
||||
})
|
||||
|
||||
it("hoists recursive definitions referenced by earlier recursive definitions", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { $ref: "#/components/schemas/ResourcesNetworkCard" })
|
||||
const definitions = {
|
||||
ResourcesNetworkCard: {
|
||||
type: "object",
|
||||
properties: {
|
||||
sriov: {
|
||||
$ref: "#/components/schemas/ResourcesNetworkCardSRIOV"
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
},
|
||||
ResourcesNetworkCardSRIOV: {
|
||||
type: "object",
|
||||
properties: {
|
||||
vfs: {
|
||||
type: "array",
|
||||
items: {
|
||||
$ref: "#/components/schemas/ResourcesNetworkCard"
|
||||
}
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
}
|
||||
|
||||
const result = generator.generate("openapi-3.1", definitions, false)
|
||||
const recursiveDeclaration =
|
||||
"export const ResourcesNetworkCardSRIOV = Schema.suspend((): Schema.Codec<ResourcesNetworkCardSRIOV> => __recursive_ResourcesNetworkCardSRIOV)"
|
||||
|
||||
expect(result).toContain(recursiveDeclaration)
|
||||
expect(result).toContain("const __recursive_ResourcesNetworkCardSRIOV =")
|
||||
expect(result.indexOf(recursiveDeclaration)).toBeLessThan(
|
||||
result.indexOf("export const ResourcesNetworkCard =")
|
||||
)
|
||||
expect(result.indexOf("export const ResourcesNetworkCard =")).toBeLessThan(
|
||||
result.indexOf("const __recursive_ResourcesNetworkCardSRIOV =")
|
||||
)
|
||||
})
|
||||
|
||||
it("renders recursive definitions before non-recursive references for runtime generation", () => {
|
||||
const generator = JsonSchemaGenerator.make()
|
||||
generator.addSchema("A", { $ref: "#/components/schemas/ErrorResponse" })
|
||||
const definitions = {
|
||||
InnerErrors: {
|
||||
type: "object",
|
||||
properties: {
|
||||
field: {
|
||||
type: "string"
|
||||
}
|
||||
},
|
||||
required: ["field"],
|
||||
additionalProperties: false
|
||||
},
|
||||
ErrorDetails: {
|
||||
oneOf: [
|
||||
{
|
||||
type: "object",
|
||||
additionalProperties: {
|
||||
$ref: "#/components/schemas/ErrorDetails"
|
||||
}
|
||||
},
|
||||
{
|
||||
$ref: "#/components/schemas/InnerErrors"
|
||||
}
|
||||
]
|
||||
},
|
||||
ErrorResponse: {
|
||||
type: "object",
|
||||
properties: {
|
||||
errors: {
|
||||
$ref: "#/components/schemas/ErrorDetails"
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
}
|
||||
|
||||
const runtimeResult = generator.generate("openapi-3.1", definitions, false)
|
||||
const recursiveDeclaration =
|
||||
"export const ErrorDetails = Schema.suspend((): Schema.Codec<ErrorDetails> => __recursive_ErrorDetails)"
|
||||
|
||||
expect(runtimeResult).toContain(recursiveDeclaration)
|
||||
expect(runtimeResult).toContain("const __recursive_ErrorDetails =")
|
||||
expect(runtimeResult.indexOf(recursiveDeclaration)).toBeLessThan(
|
||||
runtimeResult.indexOf("export const ErrorResponse =")
|
||||
)
|
||||
|
||||
const httpApiResult = generator.generateHttpApi("openapi-3.1", definitions)
|
||||
expect(httpApiResult).toContain(recursiveDeclaration)
|
||||
expect(httpApiResult).toContain("const __recursive_ErrorDetails =")
|
||||
expect(httpApiResult.indexOf(recursiveDeclaration)).toBeLessThan(
|
||||
httpApiResult.indexOf("export const ErrorResponse =")
|
||||
)
|
||||
})
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,147 @@
|
||||
import * as NodeServices from "@effect/platform-node/NodeServices"
|
||||
import { assert, describe, it } from "@effect/vitest"
|
||||
import { Effect, Layer, Stdio, Stream } from "effect"
|
||||
import * as Exit from "effect/Exit"
|
||||
import { TestConsole } from "effect/testing"
|
||||
import { CliOutput } from "effect/unstable/cli"
|
||||
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
||||
|
||||
const makeLayer = (args: ReadonlyArray<string>) =>
|
||||
Layer.mergeAll(
|
||||
TestConsole.layer,
|
||||
CliOutput.layer(CliOutput.defaultFormatter({ colors: false })),
|
||||
NodeServices.layer,
|
||||
Stdio.layerTest({ args: Effect.succeed(args) })
|
||||
)
|
||||
|
||||
const fixturePath = (fileName: string) => `${import.meta.dirname}/fixtures/${fileName}`
|
||||
const cliProcessPath = `${import.meta.dirname}/../src/bin.ts`
|
||||
|
||||
type CliMainModule = {
|
||||
readonly run: Effect.Effect<void>
|
||||
}
|
||||
|
||||
const runCli = Effect.fnUntraced(function*(args: ReadonlyArray<string>) {
|
||||
const module = (yield* Effect.promise(
|
||||
() => import(new URL("../src/main.ts", import.meta.url).href)
|
||||
)) as CliMainModule
|
||||
|
||||
return yield* Effect.gen(function*() {
|
||||
const exit = yield* Effect.exit(module.run)
|
||||
const stdoutLines = yield* TestConsole.logLines
|
||||
const stderrLines = yield* TestConsole.errorLines
|
||||
const stdout = stdoutLines.length > 0 ? String(stdoutLines[stdoutLines.length - 1]) : ""
|
||||
const stderr = stderrLines.map(String).join("\n")
|
||||
return { exit, stdout, stderr } as const
|
||||
}).pipe(Effect.provide(makeLayer(args)))
|
||||
})
|
||||
|
||||
const runCliProcess = Effect.fnUntraced(function*(args: ReadonlyArray<string>) {
|
||||
const handle = yield* ChildProcess.make("node", [cliProcessPath, ...args])
|
||||
return yield* Effect.all({
|
||||
exitCode: handle.exitCode,
|
||||
stdout: Stream.mkString(Stream.decodeText(handle.stdout)),
|
||||
stderr: Stream.mkString(Stream.decodeText(handle.stderr))
|
||||
}, { concurrency: "unbounded" })
|
||||
})
|
||||
|
||||
describe("openapigen CLI", () => {
|
||||
it.effect("documents --format values and default in --help", () =>
|
||||
Effect.gen(function*() {
|
||||
const result = yield* runCli(["--help"])
|
||||
|
||||
assert.isTrue(Exit.isSuccess(result.exit))
|
||||
assert.include(result.stdout, "--format")
|
||||
assert.include(result.stdout, "httpclient")
|
||||
assert.include(result.stdout, "httpclient-type-only")
|
||||
assert.include(result.stdout, "httpapi")
|
||||
assert.include(result.stdout, "default: httpclient")
|
||||
assert.strictEqual(result.stderr, "")
|
||||
}))
|
||||
|
||||
it.effect("routes --format values and defaults to httpclient", () =>
|
||||
Effect.gen(function*() {
|
||||
const spec = fixturePath("cli-basic-spec.json")
|
||||
|
||||
const defaultResult = yield* runCli(["--spec", spec, "--name", "CliClient"])
|
||||
const httpclientResult = yield* runCli([
|
||||
"--spec",
|
||||
spec,
|
||||
"--name",
|
||||
"CliClient",
|
||||
"--format",
|
||||
"httpclient"
|
||||
])
|
||||
const typeOnlyResult = yield* runCli([
|
||||
"--spec",
|
||||
spec,
|
||||
"--name",
|
||||
"CliClient",
|
||||
"--format",
|
||||
"httpclient-type-only"
|
||||
])
|
||||
const httpapiResult = yield* runCli([
|
||||
"--spec",
|
||||
spec,
|
||||
"--name",
|
||||
"CliClient",
|
||||
"--format",
|
||||
"httpapi"
|
||||
])
|
||||
|
||||
assert.isTrue(Exit.isSuccess(defaultResult.exit))
|
||||
assert.isTrue(Exit.isSuccess(httpclientResult.exit))
|
||||
assert.isTrue(Exit.isSuccess(typeOnlyResult.exit))
|
||||
assert.isTrue(Exit.isSuccess(httpapiResult.exit))
|
||||
|
||||
assert.strictEqual(defaultResult.stderr, "")
|
||||
assert.strictEqual(httpclientResult.stderr, "")
|
||||
assert.strictEqual(typeOnlyResult.stderr, "")
|
||||
assert.strictEqual(httpapiResult.stderr, "")
|
||||
|
||||
assert.strictEqual(defaultResult.stdout, httpclientResult.stdout)
|
||||
assert.include(httpclientResult.stdout, "import * as Schema from \"effect/Schema\"")
|
||||
assert.notInclude(typeOnlyResult.stdout, "import * as Schema from \"effect/Schema\"")
|
||||
assert.include(typeOnlyResult.stdout, "import type * as HttpClient from \"effect/unstable/http/HttpClient\"")
|
||||
assert.include(httpapiResult.stdout, "export class CliClient extends HttpApi.make(\"CliClient\")")
|
||||
}))
|
||||
|
||||
it.effect("rejects legacy --type-only flag", () =>
|
||||
Effect.gen(function*() {
|
||||
const spec = fixturePath("cli-basic-spec.json")
|
||||
const result = yield* runCli(["--spec", spec, "--name", "CliClient", "--type-only"])
|
||||
|
||||
assert.isTrue(Exit.isFailure(result.exit))
|
||||
assert.include(result.stdout, "USAGE")
|
||||
assert.include(result.stderr, "Unrecognized flag: --type-only")
|
||||
}))
|
||||
|
||||
it.effect("writes warnings to stderr and keeps stdout as generated source", () =>
|
||||
Effect.gen(function*() {
|
||||
const spec = fixturePath("cli-warning-spec.json")
|
||||
const result = yield* runCli(["--spec", spec, "--name", "CliClient"])
|
||||
|
||||
assert.isTrue(Exit.isSuccess(result.exit))
|
||||
assert.include(result.stdout, "export const make = (")
|
||||
assert.include(result.stderr, "WARNING [cookie-parameter-dropped]")
|
||||
assert.include(result.stderr, "cookie-parameter-dropped")
|
||||
assert.notInclude(result.stdout, "cookie-parameter-dropped")
|
||||
assert.notInclude(result.stderr, "export const make = (")
|
||||
}))
|
||||
|
||||
it.effect("separates generated source and warnings when spawned as a child process", () =>
|
||||
Effect.gen(function*() {
|
||||
const spec = fixturePath("cli-warning-spec.json")
|
||||
const result = yield* runCliProcess(["--spec", spec, "--name", "CliClient"])
|
||||
|
||||
assert.strictEqual(result.exitCode, ChildProcessSpawner.ExitCode(0))
|
||||
assert.include(result.stdout, "export const make = (")
|
||||
assert.notInclude(result.stdout, "WARNING [")
|
||||
assert.notInclude(result.stdout, "cookie-parameter-dropped")
|
||||
assert.include(
|
||||
result.stderr,
|
||||
"WARNING [cookie-parameter-dropped] GET /users/{id} (getUser): Cookie parameter \"session\" was dropped because non-security cookie parameters are not supported."
|
||||
)
|
||||
assert.notInclude(result.stderr, "export const make = (")
|
||||
}).pipe(Effect.scoped, Effect.provide(NodeServices.layer)))
|
||||
})
|
||||
@@ -0,0 +1,380 @@
|
||||
import * as OpenApiPatch from "@effect/openapi-generator/OpenApiPatch"
|
||||
import * as NodeServices from "@effect/platform-node/NodeServices"
|
||||
import { assert, describe, it } from "@effect/vitest"
|
||||
import * as Effect from "effect/Effect"
|
||||
import * as Exit from "effect/Exit"
|
||||
import * as Path from "effect/Path"
|
||||
|
||||
const testLayer = NodeServices.layer
|
||||
|
||||
describe("OpenApiPatch", () => {
|
||||
describe("parsePatchInput", () => {
|
||||
describe("inline JSON", () => {
|
||||
it.effect("parses valid inline JSON patch", () =>
|
||||
Effect.gen(function*() {
|
||||
const result = yield* OpenApiPatch.parsePatchInput(
|
||||
"[{\"op\":\"add\",\"path\":\"/foo\",\"value\":\"bar\"}]"
|
||||
)
|
||||
assert.deepStrictEqual(result, [{ op: "add", path: "/foo", value: "bar" }])
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
|
||||
it.effect("parses inline JSON with multiple operations", () =>
|
||||
Effect.gen(function*() {
|
||||
const result = yield* OpenApiPatch.parsePatchInput(
|
||||
"[{\"op\":\"add\",\"path\":\"/a\",\"value\":1},{\"op\":\"remove\",\"path\":\"/b\"},{\"op\":\"replace\",\"path\":\"/c\",\"value\":true}]"
|
||||
)
|
||||
assert.strictEqual(result.length, 3)
|
||||
assert.strictEqual(result[0].op, "add")
|
||||
assert.strictEqual(result[1].op, "remove")
|
||||
assert.strictEqual(result[2].op, "replace")
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
|
||||
it.effect("fails on invalid JSON syntax", () =>
|
||||
Effect.gen(function*() {
|
||||
const exit = yield* Effect.exit(
|
||||
OpenApiPatch.parsePatchInput("[{\"op\":\"add\" \"path\":\"/foo\"}]")
|
||||
)
|
||||
assert.isTrue(Exit.isFailure(exit))
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
|
||||
it.effect("fails on unsupported operation", () =>
|
||||
Effect.gen(function*() {
|
||||
const exit = yield* Effect.exit(
|
||||
OpenApiPatch.parsePatchInput("[{\"op\":\"copy\",\"from\":\"/a\",\"path\":\"/b\"}]")
|
||||
)
|
||||
assert.isTrue(Exit.isFailure(exit))
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
|
||||
it.effect("fails on missing path field", () =>
|
||||
Effect.gen(function*() {
|
||||
const exit = yield* Effect.exit(
|
||||
OpenApiPatch.parsePatchInput("[{\"op\":\"add\",\"value\":\"test\"}]")
|
||||
)
|
||||
assert.isTrue(Exit.isFailure(exit))
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
|
||||
it.effect("fails on missing value for add operation", () =>
|
||||
Effect.gen(function*() {
|
||||
const exit = yield* Effect.exit(
|
||||
OpenApiPatch.parsePatchInput("[{\"op\":\"add\",\"path\":\"/foo\"}]")
|
||||
)
|
||||
assert.isTrue(Exit.isFailure(exit))
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
|
||||
it.effect("allows missing value for remove operation", () =>
|
||||
Effect.gen(function*() {
|
||||
const result = yield* OpenApiPatch.parsePatchInput(
|
||||
"[{\"op\":\"remove\",\"path\":\"/foo\"}]"
|
||||
)
|
||||
assert.deepStrictEqual(result, [{ op: "remove", path: "/foo" }])
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
})
|
||||
|
||||
describe("file paths", () => {
|
||||
it.effect("parses valid JSON file", () =>
|
||||
Effect.gen(function*() {
|
||||
const pathService = yield* Path.Path
|
||||
const filePath = pathService.join(
|
||||
import.meta.dirname,
|
||||
"fixtures/patches/valid-add.json"
|
||||
)
|
||||
const result = yield* OpenApiPatch.parsePatchInput(filePath)
|
||||
assert.strictEqual(result.length, 1)
|
||||
assert.strictEqual(result[0].op, "add")
|
||||
assert.strictEqual(result[0].path, "/info/x-custom")
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
|
||||
it.effect("parses valid YAML file", () =>
|
||||
Effect.gen(function*() {
|
||||
const pathService = yield* Path.Path
|
||||
const filePath = pathService.join(
|
||||
import.meta.dirname,
|
||||
"fixtures/patches/valid-patch.yaml"
|
||||
)
|
||||
const result = yield* OpenApiPatch.parsePatchInput(filePath)
|
||||
assert.strictEqual(result.length, 2)
|
||||
assert.strictEqual(result[0].op, "replace")
|
||||
assert.strictEqual(result[1].op, "add")
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
|
||||
it.effect("parses multiple operations from JSON file", () =>
|
||||
Effect.gen(function*() {
|
||||
const pathService = yield* Path.Path
|
||||
const filePath = pathService.join(
|
||||
import.meta.dirname,
|
||||
"fixtures/patches/valid-multiple.json"
|
||||
)
|
||||
const result = yield* OpenApiPatch.parsePatchInput(filePath)
|
||||
assert.strictEqual(result.length, 3)
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
|
||||
it.effect("fails on file with unsupported operation", () =>
|
||||
Effect.gen(function*() {
|
||||
const pathService = yield* Path.Path
|
||||
const filePath = pathService.join(
|
||||
import.meta.dirname,
|
||||
"fixtures/patches/invalid-op.json"
|
||||
)
|
||||
const exit = yield* Effect.exit(OpenApiPatch.parsePatchInput(filePath))
|
||||
assert.isTrue(Exit.isFailure(exit))
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
|
||||
it.effect("fails on file with missing path", () =>
|
||||
Effect.gen(function*() {
|
||||
const pathService = yield* Path.Path
|
||||
const filePath = pathService.join(
|
||||
import.meta.dirname,
|
||||
"fixtures/patches/missing-path.json"
|
||||
)
|
||||
const exit = yield* Effect.exit(OpenApiPatch.parsePatchInput(filePath))
|
||||
assert.isTrue(Exit.isFailure(exit))
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
|
||||
it.effect("falls back to inline JSON when file does not exist", () =>
|
||||
Effect.gen(function*() {
|
||||
const result = yield* OpenApiPatch.parsePatchInput(
|
||||
"[{\"op\":\"add\",\"path\":\"/x\",\"value\":1}]"
|
||||
)
|
||||
assert.deepStrictEqual(result, [{ op: "add", path: "/x", value: 1 }])
|
||||
}).pipe(Effect.provide(testLayer)))
|
||||
})
|
||||
})
|
||||
|
||||
describe("applyPatches", () => {
|
||||
it.effect("applies single add patch", () =>
|
||||
Effect.gen(function*() {
|
||||
const document = { info: { title: "Test" } }
|
||||
const patches = [{
|
||||
source: "test",
|
||||
patch: [{ op: "add" as const, path: "/info/version", value: "1.0.0" }]
|
||||
}]
|
||||
const result = yield* OpenApiPatch.applyPatches(patches, document)
|
||||
assert.deepStrictEqual(result, { info: { title: "Test", version: "1.0.0" } })
|
||||
}))
|
||||
|
||||
it.effect("applies single remove patch", () =>
|
||||
Effect.gen(function*() {
|
||||
const document = { info: { title: "Test", deprecated: true } }
|
||||
const patches = [{
|
||||
source: "test",
|
||||
patch: [{ op: "remove" as const, path: "/info/deprecated" }]
|
||||
}]
|
||||
const result = yield* OpenApiPatch.applyPatches(patches, document)
|
||||
assert.deepStrictEqual(result, { info: { title: "Test" } })
|
||||
}))
|
||||
|
||||
it.effect("applies single replace patch", () =>
|
||||
Effect.gen(function*() {
|
||||
const document = { info: { title: "Old Title" } }
|
||||
const patches = [{
|
||||
source: "test",
|
||||
patch: [{ op: "replace" as const, path: "/info/title", value: "New Title" }]
|
||||
}]
|
||||
const result = yield* OpenApiPatch.applyPatches(patches, document)
|
||||
assert.deepStrictEqual(result, { info: { title: "New Title" } })
|
||||
}))
|
||||
|
||||
it.effect("applies multiple patches in sequence", () =>
|
||||
Effect.gen(function*() {
|
||||
const document = { info: { title: "Original", version: "0.0.1" } }
|
||||
const patches = [
|
||||
{
|
||||
source: "patch1",
|
||||
patch: [{ op: "replace" as const, path: "/info/title", value: "Step 1" }]
|
||||
},
|
||||
{
|
||||
source: "patch2",
|
||||
patch: [{ op: "replace" as const, path: "/info/version", value: "1.0.0" }]
|
||||
},
|
||||
{
|
||||
source: "patch3",
|
||||
patch: [{ op: "add" as const, path: "/info/x-patched", value: true }]
|
||||
}
|
||||
]
|
||||
const result = yield* OpenApiPatch.applyPatches(patches, document)
|
||||
assert.deepStrictEqual(result, {
|
||||
info: { title: "Step 1", version: "1.0.0", "x-patched": true }
|
||||
})
|
||||
}))
|
||||
|
||||
it.effect("applies multiple operations within a single patch", () =>
|
||||
Effect.gen(function*() {
|
||||
const document = { info: { title: "Test" }, paths: {} }
|
||||
const patches = [{
|
||||
source: "test",
|
||||
patch: [
|
||||
{ op: "replace" as const, path: "/info/title", value: "Updated" },
|
||||
{ op: "add" as const, path: "/info/version", value: "2.0.0" }
|
||||
]
|
||||
}]
|
||||
const result = yield* OpenApiPatch.applyPatches(patches, document)
|
||||
assert.deepStrictEqual(result, {
|
||||
info: { title: "Updated", version: "2.0.0" },
|
||||
paths: {}
|
||||
})
|
||||
}))
|
||||
|
||||
it.effect("fails when path does not exist for replace", () =>
|
||||
Effect.gen(function*() {
|
||||
const document = { info: { title: "Test" } }
|
||||
const patches = [{
|
||||
source: "test",
|
||||
patch: [{ op: "replace" as const, path: "/info/nonexistent", value: "x" }]
|
||||
}]
|
||||
const exit = yield* Effect.exit(OpenApiPatch.applyPatches(patches, document))
|
||||
assert.isTrue(Exit.isFailure(exit))
|
||||
}))
|
||||
|
||||
it.effect("fails when path does not exist for remove", () =>
|
||||
Effect.gen(function*() {
|
||||
const document = { info: { title: "Test" } }
|
||||
const patches = [{
|
||||
source: "test",
|
||||
patch: [{ op: "remove" as const, path: "/info/nonexistent" }]
|
||||
}]
|
||||
const exit = yield* Effect.exit(OpenApiPatch.applyPatches(patches, document))
|
||||
assert.isTrue(Exit.isFailure(exit))
|
||||
}))
|
||||
|
||||
it.effect("accumulates multiple errors", () =>
|
||||
Effect.gen(function*() {
|
||||
const document = { info: { title: "Test" } }
|
||||
const patches = [{
|
||||
source: "test.json",
|
||||
patch: [
|
||||
{ op: "replace" as const, path: "/info/nonexistent1", value: "x" },
|
||||
{ op: "remove" as const, path: "/info/nonexistent2" },
|
||||
{ op: "replace" as const, path: "/info/nonexistent3", value: "y" }
|
||||
]
|
||||
}]
|
||||
const exit = yield* Effect.exit(OpenApiPatch.applyPatches(patches, document))
|
||||
assert.isTrue(Exit.isFailure(exit))
|
||||
if (Exit.isFailure(exit)) {
|
||||
const failure = exit.cause.reasons[0]
|
||||
if (failure._tag === "Fail") {
|
||||
assert.strictEqual(failure.error._tag, "JsonPatchAggregateError")
|
||||
assert.strictEqual(failure.error.errors.length, 3)
|
||||
assert.include(failure.error.message, "3 patch operations failed")
|
||||
assert.include(failure.error.message, "/info/nonexistent1")
|
||||
assert.include(failure.error.message, "/info/nonexistent2")
|
||||
assert.include(failure.error.message, "/info/nonexistent3")
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
it.effect("accumulates errors across multiple patches", () =>
|
||||
Effect.gen(function*() {
|
||||
const document = { info: { title: "Test" } }
|
||||
const patches = [
|
||||
{
|
||||
source: "patch1.json",
|
||||
patch: [{ op: "remove" as const, path: "/info/missing1" }]
|
||||
},
|
||||
{
|
||||
source: "patch2.json",
|
||||
patch: [{ op: "remove" as const, path: "/info/missing2" }]
|
||||
}
|
||||
]
|
||||
const exit = yield* Effect.exit(OpenApiPatch.applyPatches(patches, document))
|
||||
assert.isTrue(Exit.isFailure(exit))
|
||||
if (Exit.isFailure(exit)) {
|
||||
const failure = exit.cause.reasons[0]
|
||||
if (failure._tag === "Fail") {
|
||||
assert.strictEqual(failure.error.errors.length, 2)
|
||||
assert.include(failure.error.message, "patch1.json")
|
||||
assert.include(failure.error.message, "patch2.json")
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
it.effect("preserves unmodified parts of document", () =>
|
||||
Effect.gen(function*() {
|
||||
const document = {
|
||||
info: { title: "Test", description: "Unchanged" },
|
||||
paths: { "/users": { get: {} } },
|
||||
components: { schemas: {} }
|
||||
}
|
||||
const patches = [{
|
||||
source: "test",
|
||||
patch: [{ op: "replace" as const, path: "/info/title", value: "Changed" }]
|
||||
}]
|
||||
const result = yield* OpenApiPatch.applyPatches(patches, document)
|
||||
assert.strictEqual((result as { info: { description: string } }).info.description, "Unchanged")
|
||||
assert.deepStrictEqual((result as { paths: object }).paths, { "/users": { get: {} } })
|
||||
assert.deepStrictEqual((result as { components: object }).components, { schemas: {} })
|
||||
}))
|
||||
|
||||
it.effect("returns original document when no patches provided", () =>
|
||||
Effect.gen(function*() {
|
||||
const document = { info: { title: "Test" } }
|
||||
const result = yield* OpenApiPatch.applyPatches([], document)
|
||||
assert.deepStrictEqual(result, document)
|
||||
}))
|
||||
})
|
||||
|
||||
describe("error messages", () => {
|
||||
it.effect("JsonPatchParseError has descriptive message", () =>
|
||||
Effect.gen(function*() {
|
||||
const error = new OpenApiPatch.JsonPatchParseError({
|
||||
source: "./fix.json",
|
||||
reason: "Unexpected token"
|
||||
})
|
||||
assert.strictEqual(
|
||||
error.message,
|
||||
"Failed to parse patch from ./fix.json: Unexpected token"
|
||||
)
|
||||
}))
|
||||
|
||||
it.effect("JsonPatchValidationError has descriptive message", () =>
|
||||
Effect.gen(function*() {
|
||||
const error = new OpenApiPatch.JsonPatchValidationError({
|
||||
source: "inline",
|
||||
reason: "Missing 'path' field"
|
||||
})
|
||||
assert.strictEqual(
|
||||
error.message,
|
||||
"Invalid JSON Patch from inline: Missing 'path' field"
|
||||
)
|
||||
}))
|
||||
|
||||
it.effect("JsonPatchApplicationError has descriptive message", () =>
|
||||
Effect.gen(function*() {
|
||||
const error = new OpenApiPatch.JsonPatchApplicationError({
|
||||
source: "./fix.json",
|
||||
operationIndex: 2,
|
||||
operation: "remove",
|
||||
path: "/info/x",
|
||||
reason: "Property does not exist"
|
||||
})
|
||||
assert.strictEqual(
|
||||
error.message,
|
||||
"Failed to apply patch from ./fix.json: operation 2 (remove at /info/x): Property does not exist"
|
||||
)
|
||||
}))
|
||||
|
||||
it.effect("JsonPatchAggregateError has descriptive message", () =>
|
||||
Effect.gen(function*() {
|
||||
const error = new OpenApiPatch.JsonPatchAggregateError({
|
||||
errors: [
|
||||
new OpenApiPatch.JsonPatchApplicationError({
|
||||
source: "./fix.json",
|
||||
operationIndex: 0,
|
||||
operation: "replace",
|
||||
path: "/info/x",
|
||||
reason: "Property does not exist"
|
||||
}),
|
||||
new OpenApiPatch.JsonPatchApplicationError({
|
||||
source: "./other.json",
|
||||
operationIndex: 1,
|
||||
operation: "remove",
|
||||
path: "/paths/~1users",
|
||||
reason: "Path not found"
|
||||
})
|
||||
]
|
||||
})
|
||||
assert.include(error.message, "2 patch operations failed")
|
||||
assert.include(error.message, "1. [./fix.json] op 0 (replace at /info/x)")
|
||||
assert.include(error.message, "2. [./other.json] op 1 (remove at /paths/~1users)")
|
||||
}))
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,33 @@
|
||||
import * as Utils from "@effect/openapi-generator/Utils"
|
||||
import { describe, expect, it } from "vitest"
|
||||
|
||||
describe("Utils", () => {
|
||||
describe("camelize", () => {
|
||||
it("removes hyphens and capitalizes following letters", () => {
|
||||
expect(Utils.camelize("my-operation-id")).toBe("myOperationId")
|
||||
})
|
||||
|
||||
it("removes slashes and capitalizes following letters", () => {
|
||||
expect(Utils.camelize("my/operation/id")).toBe("myOperationId")
|
||||
})
|
||||
|
||||
it("handles numbers", () => {
|
||||
expect(Utils.camelize("operation-2")).toBe("operation2")
|
||||
})
|
||||
|
||||
it("removes leading numbers", () => {
|
||||
expect(Utils.camelize("2operation")).toBe("operation")
|
||||
})
|
||||
|
||||
it("handles empty string", () => {
|
||||
expect(Utils.camelize("")).toBe("")
|
||||
})
|
||||
})
|
||||
|
||||
describe("identifier", () => {
|
||||
it("capitalizes camelized string", () => {
|
||||
expect(Utils.identifier("my-operation")).toBe("MyOperation")
|
||||
expect(Utils.identifier("operation-2")).toBe("Operation2")
|
||||
})
|
||||
})
|
||||
})
|
||||
35
repos/effect/packages/tools/openapi-generator/test/fixtures/cli-basic-spec.json
vendored
Normal file
35
repos/effect/packages/tools/openapi-generator/test/fixtures/cli-basic-spec.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "CLI Basic API",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"/users": {
|
||||
"get": {
|
||||
"operationId": "listUsers",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "List users",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {},
|
||||
"securitySchemes": {}
|
||||
},
|
||||
"security": [],
|
||||
"tags": []
|
||||
}
|
||||
57
repos/effect/packages/tools/openapi-generator/test/fixtures/cli-warning-spec.json
vendored
Normal file
57
repos/effect/packages/tools/openapi-generator/test/fixtures/cli-warning-spec.json
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "CLI Warning API",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"/users/{id}": {
|
||||
"get": {
|
||||
"operationId": "getUser",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "session",
|
||||
"in": "cookie",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "User response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {},
|
||||
"securitySchemes": {}
|
||||
},
|
||||
"security": [],
|
||||
"tags": []
|
||||
}
|
||||
7
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/invalid-op.json
vendored
Normal file
7
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/invalid-op.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"op": "copy",
|
||||
"from": "/info/title",
|
||||
"path": "/info/x-title"
|
||||
}
|
||||
]
|
||||
6
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/missing-path.json
vendored
Normal file
6
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/missing-path.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"op": "add",
|
||||
"value": "test"
|
||||
}
|
||||
]
|
||||
6
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/missing-value.json
vendored
Normal file
6
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/missing-value.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"op": "add",
|
||||
"path": "/info/x-missing"
|
||||
}
|
||||
]
|
||||
8
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/valid-add.json
vendored
Normal file
8
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/valid-add.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"op": "add",
|
||||
"path": "/info/x-custom",
|
||||
"value": "custom-value",
|
||||
"description": "Add custom extension"
|
||||
}
|
||||
]
|
||||
17
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/valid-multiple.json
vendored
Normal file
17
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/valid-multiple.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
[
|
||||
{
|
||||
"op": "replace",
|
||||
"path": "/info/title",
|
||||
"value": "My Custom API"
|
||||
},
|
||||
{
|
||||
"op": "add",
|
||||
"path": "/info/x-generator",
|
||||
"value": "effect-openapi"
|
||||
},
|
||||
{
|
||||
"op": "replace",
|
||||
"path": "/info/version",
|
||||
"value": "2.0.0"
|
||||
}
|
||||
]
|
||||
6
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/valid-patch.yaml
vendored
Normal file
6
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/valid-patch.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
- op: replace
|
||||
path: /info/title
|
||||
value: YAML Patched Title
|
||||
- op: add
|
||||
path: /info/x-yaml-patch
|
||||
value: true
|
||||
6
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/valid-remove.json
vendored
Normal file
6
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/valid-remove.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"op": "remove",
|
||||
"path": "/paths/~1deprecated"
|
||||
}
|
||||
]
|
||||
7
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/valid-replace.json
vendored
Normal file
7
repos/effect/packages/tools/openapi-generator/test/fixtures/patches/valid-replace.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"op": "replace",
|
||||
"path": "/info/title",
|
||||
"value": "Updated API Title"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/tsconfig",
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"include": ["src"],
|
||||
"references": [
|
||||
{ "path": "../../effect" },
|
||||
{ "path": "../../platform-node" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { mergeConfig, type ViteUserConfig } from "vitest/config"
|
||||
import shared from "../../../vitest.shared.ts"
|
||||
|
||||
const config: ViteUserConfig = {}
|
||||
|
||||
export default mergeConfig(shared, config)
|
||||
Reference in New Issue
Block a user