https://project.mdnd-it.cc/work_packages/94
This commit is contained in:
2025-08-23 04:25:28 +02:00
parent 725516ad6c
commit 19cfa031d0
25823 changed files with 1095587 additions and 2801760 deletions
+558
View File
@@ -0,0 +1,558 @@
## Change Log
### v6.0.9 (2021/03/07 10:34 +00:00)
- [#256](https://github.com/Surnet/swagger-jsdoc/pull/256) fix(anchors): applied a fix for anchors living in seperate files with… (#256) (@goldsziggy)
### v7.0.0-rc.4 (2021/03/01 16:00 +00:00)
- [15bce04](https://github.com/Surnet/swagger-jsdoc/commit/15bce0415b4dfff7ca21d8931b5498e71a9013ff) correction: v6.0.8 (@kalinchernev)
### v6.0.8 (2021/03/01 15:20 +00:00)
- [fc3d62c](https://github.com/Surnet/swagger-jsdoc/commit/fc3d62c61a266b879fd8ab1531f77634645f0247) v6.0.7 (@kalinchernev)
- [#253](https://github.com/Surnet/swagger-jsdoc/pull/253) fix(specification): apply fix for multiple anchors (#253) (@goldsziggy)
### v7.0.0-rc.3 (2021/02/26 14:33 +00:00)
- [8873370](https://github.com/Surnet/swagger-jsdoc/commit/887337050ec3b2d246d2fa9a9bd3570b3746d379) Update docs (@kalinchernev)
- [#250](https://github.com/Surnet/swagger-jsdoc/pull/250) Update FIRST-STEPS.md (#250) (@azizkale)
- [da152ea](https://github.com/Surnet/swagger-jsdoc/commit/da152eaf81656b77f49628005225ef7e0f647c9e) Update docs (@kalinchernev)
### v6.0.6 (2021/02/16 09:01 +00:00)
- [32540d1](https://github.com/Surnet/swagger-jsdoc/commit/32540d1f36fc286c72d260f4690465744ba08ca0) docs version bump (@kalinchernev)
- [12a4e6d](https://github.com/Surnet/swagger-jsdoc/commit/12a4e6d9cdcbd2c9d7497413425ac9dedffcdbcc) Update landing page readme (@kalinchernev)
- [c65d659](https://github.com/Surnet/swagger-jsdoc/commit/c65d659b6df554b1e0cc2552d4340cdfdc27f4c3) Update issue templates (@kalinchernev)
### v6.0.5 (2021/02/15 15:52 +00:00)
- [05bc5a9](https://github.com/Surnet/swagger-jsdoc/commit/05bc5a91b8dc008243c74109ffd557ef5ed9d8a8) bump (@kalinchernev)
- [a56522f](https://github.com/Surnet/swagger-jsdoc/commit/a56522f11560727fc7327f7c0e9c083d8517dd2e) changelog (@kalinchernev)
- [#247](https://github.com/Surnet/swagger-jsdoc/pull/247) feat: support cjs and update docs (#247) (@kalinchernev)
### v6.0.3 (2021/02/15 08:40 +00:00)
- [#245](https://github.com/Surnet/swagger-jsdoc/pull/245) fix yaml formatting (#245) (@kalinchernev)
### v6.0.2 (2021/01/29 11:02 +00:00)
- [87e51e9](https://github.com/Surnet/swagger-jsdoc/commit/87e51e9688aa75994d38735369cf210a65813159) chore: prepare v6.0.2 (@kalinchernev)
- [#241](https://github.com/Surnet/swagger-jsdoc/pull/241) Issue with error message when using deprecated "apis" key (#241) (@CleyFaye)
### v6.0.1 (2021/01/07 06:23 +00:00)
- [92d51ba](https://github.com/Surnet/swagger-jsdoc/commit/92d51bacae77f4bc3d421872dea33ce366b7a108) update version (@kalinchernev)
- [#238](https://github.com/Surnet/swagger-jsdoc/pull/238) fix: yaml export format (#238) (@kalinchernev)
### v6.0.0 (2020/12/23 09:38 +00:00)
- [7aaa3e0](https://github.com/Surnet/swagger-jsdoc/commit/7aaa3e00b75c6deffcce09126beee391716549d2) Update TYPESCRIPT.md (@kalinchernev)
- [d2965db](https://github.com/Surnet/swagger-jsdoc/commit/d2965dbf919956010bcc156e29fa086986e324e3) Release 6.0 (@kalinchernev)
- [0d0be79](https://github.com/Surnet/swagger-jsdoc/commit/0d0be797263a6f95dd0efcc5386b37b8757f8ecb) Update documentation (@kalinchernev)
- [6db97e2](https://github.com/Surnet/swagger-jsdoc/commit/6db97e25832e0f94f87db9c5d5340122efe4f385) update changelog (@kalinchernev)
- [a72a91f](https://github.com/Surnet/swagger-jsdoc/commit/a72a91f6262172b0bb49f089039cc176f1564d6c) prepare rc5 (@kalinchernev)
### v6.0.0-rc.5 (2020/12/16 08:56 +00:00)
- [#235](https://github.com/Surnet/swagger-jsdoc/pull/235) feat: support x-webhooks (#235) (@kalinchernev)
- [348687e](https://github.com/Surnet/swagger-jsdoc/commit/348687ea0faffe47bf842fe4ecf22abf92bd00a2) Simplify docs (@kalinchernev)
- [d2b194c](https://github.com/Surnet/swagger-jsdoc/commit/d2b194c82ea2956d8c424c6c3b1b1269c18a94a9) Update changelog (@kalinchernev)
### v6.0.0-rc.4 (2020/12/12 17:15 +00:00)
- [#234](https://github.com/Surnet/swagger-jsdoc/pull/234) Remove 'api' attr from swagger definition (#234) (@mits87)
### v6.0.0-rc.3 (2020/11/28 15:37 +00:00)
- [7ec0825](https://github.com/Surnet/swagger-jsdoc/commit/7ec08259e1ca36343be0a7ed5e3a2475b28b325a) chore: prepare v6.0.0-rc.3 (@kalinchernev)
- [d99fbd5](https://github.com/Surnet/swagger-jsdoc/commit/d99fbd56599cbabbb3eaeee1497a5060e4e4bbc4) chore: prepare v6.0.0-rc.3 (@kalinchernev)
- [9686d62](https://github.com/Surnet/swagger-jsdoc/commit/9686d62adbca6544241ac47027a23f8aa05a379b) docs: update examples (@kalinchernev)
- [c4cea4c](https://github.com/Surnet/swagger-jsdoc/commit/c4cea4caaf94624d63e67be68f1e72a47d776cdc) docs: update changelog upcoming (@kalinchernev)
- [74395f2](https://github.com/Surnet/swagger-jsdoc/commit/74395f243d5e8977d8b20a253a90320318bc03f1) feat: support custom encoding in api files (@kalinchernev)
- [270c0af](https://github.com/Surnet/swagger-jsdoc/commit/270c0af310d9c0090b4f9f48ad051565d5f4bf7e) documentation fixes (@kalinchernev)
- [d217725](https://github.com/Surnet/swagger-jsdoc/commit/d2177254e9424fd4c93fea92c45b45c41d927e15) remove github-changes because of vulnerabilities (@kalinchernev)
- [5908281](https://github.com/Surnet/swagger-jsdoc/commit/590828123201910b7ed62105a53719431635fb8a) add changelog (@kalinchernev)
### v6.0.0-rc.2 (2020/11/28 09:34 +00:00)
- [3379925](https://github.com/Surnet/swagger-jsdoc/commit/337992556529bd2030a6e512dfb7951945fe7026) sync published version (@kalinchernev)
- [#229](https://github.com/Surnet/swagger-jsdoc/pull/229) Add empty array fallback to regex match (#229) (@evans)
### v6.0.0-rc.1 (2020/11/27 06:38 +00:00)
- [2a08842](https://github.com/Surnet/swagger-jsdoc/commit/2a08842ab3a970c117358d2a667e5a598ee54d70) bump (@kalinchernev)
- [#227](https://github.com/Surnet/swagger-jsdoc/pull/227) feat: handle yaml references between separate documents (#227) (@kalinchernev)
### v5.0.1 (2020/11/08 08:22 +00:00)
- [#224](https://github.com/Surnet/swagger-jsdoc/pull/224) Update README.md (#224) (@zeevo)
### v5.0.0 (2020/10/28 15:36 +00:00)
- [#220](https://github.com/Surnet/swagger-jsdoc/pull/220) chore: refactor helpers (#220) (@kalinchernev)
### v4.3.1 (2020/10/22 06:10 +00:00)
- [b95f784](https://github.com/Surnet/swagger-jsdoc/commit/b95f784783b5915259c62e78cb401e58bb3b18b4) bump version (@kalinchernev)
- [bf44557](https://github.com/Surnet/swagger-jsdoc/commit/bf4455707464783ba30ca48c38bb1dd25d6525b5) add back coverage ignore-s (@kalinchernev)
- [c3cdcc5](https://github.com/Surnet/swagger-jsdoc/commit/c3cdcc508a876c2888b92a1d34a0aa31aceb0a02) refactor cli a bit (@kalinchernev)
- [2b7d6a8](https://github.com/Surnet/swagger-jsdoc/commit/2b7d6a8aee06793a571f452b7cedc70404f04520) add specs for public functions (@kalinchernev)
- [105f461](https://github.com/Surnet/swagger-jsdoc/commit/105f4610c7a42bac55a7120b4c845885e6c0bcd3) coverage for yaml malformatting (@kalinchernev)
- [1f2d9d6](https://github.com/Surnet/swagger-jsdoc/commit/1f2d9d6873e7b6c024d32a8346025300534f6208) increase coverage for initial error handling (@kalinchernev)
- [9058113](https://github.com/Surnet/swagger-jsdoc/commit/90581132d817c82777cc70341d20d8a7c26d60e2) remove deprecated coverage ignore lines (@kalinchernev)
- [0d66d5c](https://github.com/Surnet/swagger-jsdoc/commit/0d66d5ceaa141e21e97a940665e71c59f97ae186) remove @requires (@kalinchernev)
- [068581a](https://github.com/Surnet/swagger-jsdoc/commit/068581a1eb46649e3720d04a4d4b3321bd3f474c) remove unnecessary @function annotations (@kalinchernev)
- [a19d7e0](https://github.com/Surnet/swagger-jsdoc/commit/a19d7e04f10a6eb5c227ba4012caeaec0eb413f7) remove @module definition (@kalinchernev)
- [fe97fee](https://github.com/Surnet/swagger-jsdoc/commit/fe97fee707a9afd12b8cc32184bac03843402a12) remove vscode settings (@kalinchernev)
### v4.3.0 (2020/10/13 13:47 +00:00)
- [#52](https://github.com/Surnet/swagger-jsdoc/pull/52) feat: add coffeescript support (#52) (@Aslan11)
### v4.2.3 (2020/10/08 14:58 +00:00)
- [#214](https://github.com/Surnet/swagger-jsdoc/pull/214) chore: use jest over mocha (#214) (@kalinchernev)
### v4.2.2 (2020/10/08 14:49 +00:00)
- [#217](https://github.com/Surnet/swagger-jsdoc/pull/217) make a test with patch version (#217) (@kalinchernev)
### v4.2.1 (2020/10/08 14:44 +00:00)
- [e3a670b](https://github.com/Surnet/swagger-jsdoc/commit/e3a670baf214b8e23f2f992df72654ef92f9e0ae) update github workflow (@kalinchernev)
- [3017902](https://github.com/Surnet/swagger-jsdoc/commit/30179029e9da52833fdfc231eb286aea9c89fdcb) update docs (@kalinchernev)
- [8e9da9b](https://github.com/Surnet/swagger-jsdoc/commit/8e9da9b1f780f1dbe10b3921ba4d2e9e8791ddb4) remove circle ci (@kalinchernev)
- [2644db6](https://github.com/Surnet/swagger-jsdoc/commit/2644db6a36c53ad7253592a5d884d4b0f828e2d2) update readme (@kalinchernev)
- [#213](https://github.com/Surnet/swagger-jsdoc/pull/213) Add github actions (#213) (@kalinchernev)
- [98d7cf4](https://github.com/Surnet/swagger-jsdoc/commit/98d7cf4ed408fa95614d7421398005d73aab021f) Update version (@kalinchernev)
### v4.2.0 (2020/09/25 10:47 +00:00)
- [#200](https://github.com/Surnet/swagger-jsdoc/pull/200) add openapi jsdoc annotation with test (#200) (@Uzlopak)
- [#208](https://github.com/Surnet/swagger-jsdoc/pull/208) Better describing errors (#208) (@allisonverdam)
### v4.1.0 (2020/09/25 10:24 +00:00)
- [f508180](https://github.com/Surnet/swagger-jsdoc/commit/f508180239ad90b92712f01edf0e5f0fdea2e276) Update dependencies (@kalinchernev)
### v4.0.0 (2020/03/22 13:18 +00:00)
- [5ab0e06](https://github.com/Surnet/swagger-jsdoc/commit/5ab0e06bba19866fa98880068c816fa76fd6c664) Upgrade to Node Dubnium (@kalinchernev)
### v3.7.0 (2020/03/22 13:09 +00:00)
- [a9c0a24](https://github.com/Surnet/swagger-jsdoc/commit/a9c0a24ebc757612cc7caf20972a482362d40d3f) Downgrade deps to node carbon (@kalinchernev)
- [d105727](https://github.com/Surnet/swagger-jsdoc/commit/d105727f1ca90cbe17c449848ebbf627e63b4f5d) Update mocka opts (@kalinchernev)
- [#191](https://github.com/Surnet/swagger-jsdoc/pull/191) Bump acorn from 7.1.0 to 7.1.1 (#191) (@dependabot[bot])
### v3.6.0 (2020/03/22 12:32 +00:00)
- [598b7e7](https://github.com/Surnet/swagger-jsdoc/commit/598b7e7e405ff224e1b38be1cdacac2f7918989d) Upgrade deps + bump to 3.6.0 (@kalinchernev)
### v3.5.0 (2019/12/04 17:38 +00:00)
- [9b5b392](https://github.com/Surnet/swagger-jsdoc/commit/9b5b3920121310c29d9857f49f554db8e9170bee) Release 3.5.0 (@kalinchernev)
- [#183](https://github.com/Surnet/swagger-jsdoc/pull/183) feat: update commander to latest version (#183) (@jamesburns-rts)
- [591b0aa](https://github.com/Surnet/swagger-jsdoc/commit/591b0aa1935cff4d728d903762f74833de387a40) Upgrades (@kalinchernev)
- [#180](https://github.com/Surnet/swagger-jsdoc/pull/180) Bump eslint-utils from 1.3.1 to 1.4.3 (#180) (@dependabot[bot])
- [#181](https://github.com/Surnet/swagger-jsdoc/pull/181) Bump lodash from 4.17.11 to 4.17.15 (#181) (@dependabot[bot])
### v3.4.0 (2019/08/08 08:59 +00:00)
- [80c350f](https://github.com/Surnet/swagger-jsdoc/commit/80c350f9cf3b91bc9f4f905c9b16ab920a588157) Release 3.4.0 (@kalinchernev)
- [#170](https://github.com/Surnet/swagger-jsdoc/pull/170) refactor(parser): expose specification builder methods (#170) (@gautier-lefebvre)
### v3.3.0 (2019/07/08 09:05 +00:00)
- [ce9ad85](https://github.com/Surnet/swagger-jsdoc/commit/ce9ad851f305b047c563163f436b89a9119025e0) Release 3.3.0 (@kalinchernev)
- [#166](https://github.com/Surnet/swagger-jsdoc/pull/166) chore(deps): upgrade all dependencies (#166) (@kalinchernev)
- [#165](https://github.com/Surnet/swagger-jsdoc/pull/165) Update swagger-parser to fix remote execution bug (#165) (@posquit0)
- [#164](https://github.com/Surnet/swagger-jsdoc/pull/164) Update outdated dev dependencies (#164) (@posquit0)
- [#162](https://github.com/Surnet/swagger-jsdoc/pull/162) fix: JSDoc Official website link (#162) (@katalonne)
### v3.2.9 (2019/04/16 06:42 +00:00)
- [ece24be](https://github.com/Surnet/swagger-jsdoc/commit/ece24be07458d9a4ff1b8a1020a4581624bb0f7c) Release 3.2.9 (@kalinchernev)
- [#157](https://github.com/Surnet/swagger-jsdoc/pull/157) Updating js-yaml dependency to 3.13.1 to fix remote execution vulnerability (#157) (@lerignoux)
### v3.2.8 (2019/03/22 06:40 +00:00)
- [098078b](https://github.com/Surnet/swagger-jsdoc/commit/098078b469eb0655fdb4143a0e99ea43b547e2f8) Release 3.2.8 (@kalinchernev)
- [#156](https://github.com/Surnet/swagger-jsdoc/pull/156) Bump js-yaml version to fix https://www.npmjs.com/advisories/788 (#156) (@iansltx)
- [#154](https://github.com/Surnet/swagger-jsdoc/pull/154) fix: CLI usage example (#154) (@GabrielDelepine)
### v3.2.7 (2019/02/12 14:18 +00:00)
- [9769dfd](https://github.com/Surnet/swagger-jsdoc/commit/9769dfd4326fb079bc9a0520ac30495909bf7e9e) Release 3.2.7 (@kalinchernev)
- [#151](https://github.com/Surnet/swagger-jsdoc/pull/151) Removes apis from input Def before generation. (#151) (@spencermcw)
### v3.2.6 (2018/11/30 16:09 +00:00)
- [3563890](https://github.com/Surnet/swagger-jsdoc/commit/35638903cd84c11b58d0f980b3e3aeb0ee70e22f) Release 3.2.6 (@kalinchernev)
- [#147](https://github.com/Surnet/swagger-jsdoc/pull/147) Adding specification configuration documentation to GETTING-STARTED.md (#147) (Mason Everett)
### v3.2.5 (2018/11/26 18:44 +00:00)
- [d0555ae](https://github.com/Surnet/swagger-jsdoc/commit/d0555ae18c0f0a5097695ef31db1b40f6f127530) Release 3.2.5 (@kalinchernev)
- [#145](https://github.com/Surnet/swagger-jsdoc/pull/145) fix: remove es2017 specific language feature (#145) (@a-morn)
### v3.2.4 (2018/11/23 10:31 +00:00)
- [714d42b](https://github.com/Surnet/swagger-jsdoc/commit/714d42b4539ec744e906f91aee399ac6995e9942) Release 3.2.4 (@kalinchernev)
- [#143](https://github.com/Surnet/swagger-jsdoc/pull/143) Return false for non-empty objects (#143) (@a-morn)
- [#140](https://github.com/Surnet/swagger-jsdoc/pull/140) Update CLI usage example (#140) (@ndelvalle)
- [#135](https://github.com/Surnet/swagger-jsdoc/pull/135) Quick spelling change (#135) (@antonjb)
### v3.2.3 (2018/09/19 06:50 +00:00)
- [36984bf](https://github.com/Surnet/swagger-jsdoc/commit/36984bf62c5f58e30e180176b6f9b68a4b451337) Correction (@kalinchernev)
- [2d2a6c7](https://github.com/Surnet/swagger-jsdoc/commit/2d2a6c791d968010fe66ed03c20a781df991675b) Release 3.2.2 (@kalinchernev)
- [e2e12fa](https://github.com/Surnet/swagger-jsdoc/commit/e2e12fa0153b8b627d910ed7f8508097951d6c02) Simplify (@kalinchernev)
- [36e2a48](https://github.com/Surnet/swagger-jsdoc/commit/36e2a48692a4db6252794d9a9c22984e7318d0fe) Add documentation section (@kalinchernev)
### v3.2.0 (2018/09/17 20:28 +00:00)
- [d4fc538](https://github.com/Surnet/swagger-jsdoc/commit/d4fc5386e53dc4168e998793045912a4b6ef371a) Release 3.2.0 (@kalinchernev)
- [#96](https://github.com/Surnet/swagger-jsdoc/pull/96) error reporting help with new "verbose" flag (#96) (@liquidg3)
### v3.1.1 (2018/09/16 15:47 +00:00)
- [fc5443e](https://github.com/Surnet/swagger-jsdoc/commit/fc5443e59b47f256128bb1c065909996097f5ddb) Release 3.1.1 (@kalinchernev)
- [9a3aaef](https://github.com/Surnet/swagger-jsdoc/commit/9a3aaef437256b88d3ccb0fff5fb94928c93de29) correction (@kalinchernev)
- [2c116a1](https://github.com/Surnet/swagger-jsdoc/commit/2c116a1ff4f1b0f502234939a9768b7f856da818) Add documentation (@kalinchernev)
- [aa7833d](https://github.com/Surnet/swagger-jsdoc/commit/aa7833dac699c504311839a0295c72af9c69e782) Add documentation (@kalinchernev)
- [a9d9bc6](https://github.com/Surnet/swagger-jsdoc/commit/a9d9bc685700374d3246784d894866c4d0c8628c) Add notes on relative paths (@kalinchernev)
### v3.1.0 (2018/09/16 09:49 +00:00)
- [6177568](https://github.com/Surnet/swagger-jsdoc/commit/6177568ea9888148d1ece64449e5274fa1d3bf3d) Release 3.1.0 (@kalinchernev)
- [#105](https://github.com/Surnet/swagger-jsdoc/pull/105) Feature/yaml input definition (#105) (@ehmicky)
- [4627728](https://github.com/Surnet/swagger-jsdoc/commit/462772861e2a69a27eda9dc5284a74a892cb6c0d) Update badge (@kalinchernev)
- [#131](https://github.com/Surnet/swagger-jsdoc/pull/131) refactor(helpers): remove unused functions (#131) (@kalinchernev)
- [#108](https://github.com/Surnet/swagger-jsdoc/pull/108) Allow YAML anchors (#108) (@ehmicky)
### 3.0.3 (2018/09/04 13:22 +00:00)
- [7b1d059](https://github.com/Surnet/swagger-jsdoc/commit/7b1d059da7c7ae63a9507f8b9a7ea4cd93b9ddab) Release 3.0.3 (@kalinchernev)
- [#130](https://github.com/Surnet/swagger-jsdoc/pull/130) chore(deps): upgrades (#130) (@kalinchernev)
- [#127](https://github.com/Surnet/swagger-jsdoc/pull/127) fix npm start, add env PORT as param (#127) (@Laboratory)
### 3.0.2 (2018/08/01 11:34 +00:00)
- [d676ba4](https://github.com/Surnet/swagger-jsdoc/commit/d676ba4553d16ee679ef9fac2ed80af28d574f92) Release 3.0.2 (same as 3.0.0, but npm cache issues) (@kalinchernev)
- [#122](https://github.com/Surnet/swagger-jsdoc/pull/122) OpenAPI support (#122) (@kalinchernev)
- [#121](https://github.com/Surnet/swagger-jsdoc/pull/121) Upgrades (#121) (@kalinchernev)
### v1.10.3 (2018/07/22 12:59 +00:00)
- [0da844f](https://github.com/Surnet/swagger-jsdoc/commit/0da844f98cdf2657546d898835530a84c3c7ec7b) Release 1.10.3 (@kalinchernev)
- [#115](https://github.com/Surnet/swagger-jsdoc/pull/115) Fix Issue #78 - Prevent paths overriding each other (#115) (@willvincent)
- [#109](https://github.com/Surnet/swagger-jsdoc/pull/109) Do not serialize YAML anchors (#109) (@ehmicky)
### 1.10.2 (2018/07/18 18:39 +00:00)
- [#120](https://github.com/Surnet/swagger-jsdoc/pull/120) Release 1.10.2 (#120) (@kalinchernev)
- [#119](https://github.com/Surnet/swagger-jsdoc/pull/119) Upgrade CircleCI to 2.0 (#119) (@kalinchernev)
- [#113](https://github.com/Surnet/swagger-jsdoc/pull/113) Update GETTING-STARTED.md (#113) (@hg-pyun)
- [#110](https://github.com/Surnet/swagger-jsdoc/pull/110) Upgrade chokidar 1.7.0 -> 2.0.3 (#110) (@ehmicky)
- [#118](https://github.com/Surnet/swagger-jsdoc/pull/118) Remove deprecated shield (#118) (@kalinchernev)
- [#97](https://github.com/Surnet/swagger-jsdoc/pull/97) Fix misleading description (#97) (@danielkhan)
- [#87](https://github.com/Surnet/swagger-jsdoc/pull/87) Fix apis name in CLI docs and error message (#87) (@sapegin)
- [#88](https://github.com/Surnet/swagger-jsdoc/pull/88) Add missed space (#88) (@sapegin)
### v1.9.7 (2017/07/24 17:11 +00:00)
- [#86](https://github.com/Surnet/swagger-jsdoc/pull/86) Bump to v1.9.7 (#86) (@drGrove)
- [#82](https://github.com/Surnet/swagger-jsdoc/pull/82) chore(deps): update dependencies and bump release (#82) (@kalinchernev)
- [#79](https://github.com/Surnet/swagger-jsdoc/pull/79) Remove unused swagger keys from swagger output object (#79) (@dolphub)
- [#77](https://github.com/Surnet/swagger-jsdoc/pull/77) chore(deps): update packages (#77) (@kalinchernev)
- [#72](https://github.com/Surnet/swagger-jsdoc/pull/72) Adding support for APIs in definition file. (#72) (Jesse O'Brien)
### v1.9.3 (2017/04/29 15:39 +00:00)
- [#69](https://github.com/Surnet/swagger-jsdoc/pull/69) docs(readme): improve documentation (#69) (@kalinchernev)
- [cd60d8a](https://github.com/Surnet/swagger-jsdoc/commit/cd60d8a5c54080a6ce7b43ce8932bc02aceae354) Removing Donation Link (@chdanielmueller)
### v1.9.2 (2017/02/22 13:05 +00:00)
- [6243281](https://github.com/Surnet/swagger-jsdoc/commit/6243281c0c8fbfc7e15a91f0a43f53915395606d) Release v.1.9.2 (@kalinchernev)
- [#59](https://github.com/Surnet/swagger-jsdoc/pull/59) Merge pull request #59 from Surnet/fix/dependencies (@Surnet)
- [b8fdd61](https://github.com/Surnet/swagger-jsdoc/commit/b8fdd6110628178f65f041583b881a4aee9f5b98) Moving chokidar dependency. (@kalinchernev)
### v1.9.1 (2017/01/22 11:26 +00:00)
- [50c3a2c](https://github.com/Surnet/swagger-jsdoc/commit/50c3a2c1842a243cd8d2a4245077c417c6d78e7e) Release v1.9.1 (@kalinchernev)
- [#55](https://github.com/Surnet/swagger-jsdoc/pull/55) Merge pull request #55 from Surnet/chore/npmignore (@Surnet)
- [3e9a2b2](https://github.com/Surnet/swagger-jsdoc/commit/3e9a2b27ed88d37e6de1d687d574e15455f927f5) Ignore c9 hidden folder on npm publish (@kalinchernev)
- [d7deb0b](https://github.com/Surnet/swagger-jsdoc/commit/d7deb0bd723eedfd77b899e0b3126ddf324f1486) Default output file is actually swagger.json (@kalinchernev)
### v1.9.0 (2017/01/17 09:25 +00:00)
- [ee44bb2](https://github.com/Surnet/swagger-jsdoc/commit/ee44bb2f3893f57c7b31d444caf48248862ad585) Release v1.9.0 (@kalinchernev)
- [#49](https://github.com/Surnet/swagger-jsdoc/pull/49) Merge pull request #49 from Surnet/feature/watch-task (@Surnet)
- [6993f69](https://github.com/Surnet/swagger-jsdoc/commit/6993f69586640ea87b4d354fcd540f837b20f22f) Update tests (@kalinchernev)
- [7117fd8](https://github.com/Surnet/swagger-jsdoc/commit/7117fd89b507c88f48edf7873b2ec474d974a6e9) Update to latest master (@kalinchernev)
- [#53](https://github.com/Surnet/swagger-jsdoc/pull/53) Merge pull request #53 from mandrean/feat/yaml-output (@mandrean)
- [f249ee4](https://github.com/Surnet/swagger-jsdoc/commit/f249ee4f249f93cbe2676fbdeb0cee19137c2234) Remove extra space (@kalinchernev)
- [87527c2](https://github.com/Surnet/swagger-jsdoc/commit/87527c26a515cbf78ce06d3cccfcf6353e43fb9a) Turn off coverage requirements for example code (@kalinchernev)
- [5d4e599](https://github.com/Surnet/swagger-jsdoc/commit/5d4e599d424cd472bfd3636afaaf78eaff3d373e) Avoid tags duplication (@kalinchernev)
- [8986e85](https://github.com/Surnet/swagger-jsdoc/commit/8986e8549b0cf1b71052b10e16ae01a86e363b98) Add CLI support for YAML output (@mandrean)
- [103aab6](https://github.com/Surnet/swagger-jsdoc/commit/103aab6f5df92b87c2c951475471b64794078ada) Update documentation of CLI tool (@kalinchernev)
- [ccfa0f9](https://github.com/Surnet/swagger-jsdoc/commit/ccfa0f9a4c842d70765d607459fe41047937136b) Watch only files with API documentation (@kalinchernev)
- [5713535](https://github.com/Surnet/swagger-jsdoc/commit/571353584e065e24cc3c28c980c4972c1c527f60) Improve cli watch task (@kalinchernev)
- [fd16962](https://github.com/Surnet/swagger-jsdoc/commit/fd16962d7f1c0bf075ab77b0ca2519ca747be923) Include watch task in cli tool. (@kalinchernev)
### v1.8.4 (2016/12/29 12:04 +00:00)
- [20b9516](https://github.com/Surnet/swagger-jsdoc/commit/20b951663cec24dc44768c42ac92443e57921350) Release v1.8.4 (@kalinchernev)
- [#45](https://github.com/Surnet/swagger-jsdoc/pull/45) Merge pull request #45 from toefraz/master (@toefraz)
- [5ff7718](https://github.com/Surnet/swagger-jsdoc/commit/5ff77186dc1e6ba5dba96ed6f4b0cc782ec00300) Adding tests to verify
- [e0bcb38](https://github.com/Surnet/swagger-jsdoc/commit/e0bcb38ccb15c1fc50306026ad1209caaf579633) Ignore deprecation check (@toefraz)
### v1.8.3 (2016/12/04 13:23 +00:00)
- [d777cde](https://github.com/Surnet/swagger-jsdoc/commit/d777cde8e0e960820e5088ee18739a318ecd8ed4) Release v1.8.3 (@kalinchernev)
- [#43](https://github.com/Surnet/swagger-jsdoc/pull/43) Merge pull request #43 from Surnet/chore/dependencies (@Surnet)
- [ce3859f](https://github.com/Surnet/swagger-jsdoc/commit/ce3859fcc6cf5d56b349b04e073a34509d7ec95a) chore(dependencies): update modules (@kalinchernev)
### v1.8.2 (2016/11/18 19:08 +00:00)
- [44e4168](https://github.com/Surnet/swagger-jsdoc/commit/44e41683849d43edad1bd28b392913409d0744c2) Release v1.8.2 (@kalinchernev)
- [#42](https://github.com/Surnet/swagger-jsdoc/pull/42) Merge pull request #42 from cikasfm/master (@cikasfm)
- [a85c4b8](https://github.com/Surnet/swagger-jsdoc/commit/a85c4b8eeff3c424bb52569f1cd13cd87f36b64b) Updating sample to comply with Swagger v2 (@cikasfm)
### v1.8.1 (2016/10/27 11:55 +00:00)
- [dd1aa0a](https://github.com/Surnet/swagger-jsdoc/commit/dd1aa0a21f34b3be6c0215dddcb6f5394847eb09) Release v1.8.1 (@kalinchernev)
- [eaa1e80](https://github.com/Surnet/swagger-jsdoc/commit/eaa1e804fa97748765008185914f7ef7680fcd2b) Release v1.7.0 (@kalinchernev)
- [#40](https://github.com/Surnet/swagger-jsdoc/pull/40) Merge pull request #40 from Surnet/feature/swagger-spec-revision (@Surnet)
- [50c99c0](https://github.com/Surnet/swagger-jsdoc/commit/50c99c02df376a18d508409709a168a823289681) add iterator to seek for problematic tags (@kalinchernev)
- [1d27a43](https://github.com/Surnet/swagger-jsdoc/commit/1d27a4328843b53d91b9eadfc53951c809308973) include seekWrong method (@kalinchernev)
- [b0e73f1](https://github.com/Surnet/swagger-jsdoc/commit/b0e73f117fac637cbd3271a023ad59611dde8dd3) Preparing for general reporting of deprecated properties. (@kalinchernev)
- [4f3641d](https://github.com/Surnet/swagger-jsdoc/commit/4f3641d1fd24b4a5516d8bbb11a2829e4fb10051) Including checks for securityDefinitions and responses (@kalinchernev)
- [87f6cf5](https://github.com/Surnet/swagger-jsdoc/commit/87f6cf52cc2244ff5ec3b84e1a7e41b68c553d40) Adding test for accepting parameter in singular and plural (@kalinchernev)
- [70f924d](https://github.com/Surnet/swagger-jsdoc/commit/70f924d48128e26551c9170a1cb4ceeff3454502) Updating example files (@kalinchernev)
- [6360c1d](https://github.com/Surnet/swagger-jsdoc/commit/6360c1d1947f92109b1d5abb240a1ee6077fa292) Reducing function cyclomatic complexity (@kalinchernev)
- [ae4e4b8](https://github.com/Surnet/swagger-jsdoc/commit/ae4e4b8bcb54c21f5e32e1ddd7e38d9d1248618b) Separating the switch. (@kalinchernev)
- [f204dde](https://github.com/Surnet/swagger-jsdoc/commit/f204ddec6b8a788f0ab1c9e3a60b824f983c90a0) Correcting definition. (@kalinchernev)
- [5c55c1e](https://github.com/Surnet/swagger-jsdoc/commit/5c55c1e8e7fda9a855de070396e52e0268a8ef4e) End of day commit. (@kalinchernev)
- [ff58ba0](https://github.com/Surnet/swagger-jsdoc/commit/ff58ba059b5c6f0342bbc9e7e5a4997b472137db) addDataToSwaggerObject requires parameters. (@kalinchernev)
- [0579d90](https://github.com/Surnet/swagger-jsdoc/commit/0579d903d3f33aa83df17b10de6ed0f31a76a5e7) Separating swagger related functions in a module. (@kalinchernev)
### v1.7.0 (2016/09/17 17:33 +00:00)
- [973e6b0](https://github.com/Surnet/swagger-jsdoc/commit/973e6b0dab2f5c0b30facadd14a2ce580d9cd48b) Bump to v1.7.0 (@drGrove)
- [#36](https://github.com/Surnet/swagger-jsdoc/pull/36) Tags property parsing refactoring (#36) (@kalinchernev)
### v1.6.0 (2016/09/02 05:30 +00:00)
- [c809ffc](https://github.com/Surnet/swagger-jsdoc/commit/c809ffc075c06c482d4d8d88991aa4fb552326cd) Bump to v1.6.0 (@drGrove)
- [#29](https://github.com/Surnet/swagger-jsdoc/pull/29) Don't override user provided swagger definition options (#29) (@brantw)
- [#30](https://github.com/Surnet/swagger-jsdoc/pull/30) support multiple tags as an array and in definition (#30) (@efmr)
- [#31](https://github.com/Surnet/swagger-jsdoc/pull/31) CLI should use package version (#31) (@drGrove)
### v1.5.0 (2016/08/30 07:13 +00:00)
- [3891ee2](https://github.com/Surnet/swagger-jsdoc/commit/3891ee2c96513009efe901ee60a45ccb84994793) Bump to v1.5.0 (@drGrove)
### v1.4.1 (2016/08/30 07:10 +00:00)
- [0752561](https://github.com/Surnet/swagger-jsdoc/commit/0752561610ada57430204df88f8c043c8362ab67) Bump to v1.4.1 (@drGrove)
- [#27](https://github.com/Surnet/swagger-jsdoc/pull/27) CLI (#27) (@kalinchernev)
### v1.4.0 (2016/08/25 08:52 +00:00)
- [72ae1bb](https://github.com/Surnet/swagger-jsdoc/commit/72ae1bbae07ebd3c9d503fe1a7942efdf1e3e7b4) Bump to v1.4.0 (@drGrove)
### v1.3.1 (2016/07/03 18:12 +00:00)
- [3cccf49](https://github.com/Surnet/swagger-jsdoc/commit/3cccf498ed70c0d8240fea045156f1d837fa928f) Version bump (@chdanielmueller)
- [#23](https://github.com/Surnet/swagger-jsdoc/pull/23) Merge pull request #23 from simast/master (@simast)
- [f01b48b](https://github.com/Surnet/swagger-jsdoc/commit/f01b48b2b14a1f6be0a04a0fa4e8d6ce72b96aa4) Added swagger tags support.
- [e6d3eec](https://github.com/Surnet/swagger-jsdoc/commit/e6d3eec1ac1b3b2239f983a3049ece6b990637c8) Update README.md (@chdanielmueller)
### v1.3.0 (2016/04/07 14:10 +00:00)
- [#20](https://github.com/Surnet/swagger-jsdoc/pull/20) Merge pull request #20 from jonboiser/master (@jonboiser)
- [0af0c5d](https://github.com/Surnet/swagger-jsdoc/commit/0af0c5d7f16f1442cea5aa8c1f33c13913197016) Update to version 1.3.0
- [257bdd3](https://github.com/Surnet/swagger-jsdoc/commit/257bdd380250fe0b397521989e272b44727eb1c3) Remove Login2 definition.
- [1cb5fa0](https://github.com/Surnet/swagger-jsdoc/commit/1cb5fa04825fb2b413395d3ed8bc14f7748c96e5) Create test case for using globs options.apis.
- [2753f8e](https://github.com/Surnet/swagger-jsdoc/commit/2753f8edbd17e1a2b3eec18eae4d8bea79d4e8d7) Factor out glob converter function.
- [e73de29](https://github.com/Surnet/swagger-jsdoc/commit/e73de292abcc3564203a4cfe49f75285101f50ff) Raise jshint maxstatements to 20.
- [2e2ef7c](https://github.com/Surnet/swagger-jsdoc/commit/2e2ef7cdb140befee5d60909dc603fca53bb8ae0) options.api accepts glob strings
### v1.2.1 (2016/03/12 14:09 +00:00)
- [e42fb0c](https://github.com/Surnet/swagger-jsdoc/commit/e42fb0c77835b18e825b832be6622b4f4052d6dd) Update version number, change node test version (@chdanielmueller)
- [#18](https://github.com/Surnet/swagger-jsdoc/pull/18) Merge pull request #18 from mprokopowicz/master (@mprokopowicz)
- [78e7b77](https://github.com/Surnet/swagger-jsdoc/commit/78e7b77145ace4fe8c33d29929638c4c99d14c3e) use path.extname in favor of path.parse to stay compatible with node 0.10.x (@mprokopowicz)
### v1.2.0 (2016/02/26 18:52 +00:00)
- [0b7fe37](https://github.com/Surnet/swagger-jsdoc/commit/0b7fe379a30cc8eeb9391044de7ccfd2f563ed80) Updating version number and dependencies (@chdanielmueller)
- [#15](https://github.com/Surnet/swagger-jsdoc/pull/15) Merge pull request #15 from Cloudoki/master (@Cloudoki)
- [f31413a](https://github.com/Surnet/swagger-jsdoc/commit/f31413ae1a866e0f084dd0070b86c39d2e3b46f3) remove console.log and add forgotten file (@efmr)
- [3e60da2](https://github.com/Surnet/swagger-jsdoc/commit/3e60da2f52c846e627ecf6a992346d42b1465d26) accept yaml as api docs (@efmr)
- [4d7da54](https://github.com/Surnet/swagger-jsdoc/commit/4d7da54d2aee0ebeb7f1c0cc20924815ce8038c3) pass lint and test (@efmr)
- [20b95f2](https://github.com/Surnet/swagger-jsdoc/commit/20b95f280f8ca65776260dcfb714b107989a0d38) add parameters, responses, securityDefinitions (@efmr)
- [#13](https://github.com/Surnet/swagger-jsdoc/pull/13) Merge pull request #13 from ami44/master (@ami44)
- [863a3bb](https://github.com/Surnet/swagger-jsdoc/commit/863a3bb3c84a2f5a1ba68be781dd92d2c4f9551b) Add example to load external definitions
### v1.1.2 (2015/11/25 10:06 +00:00)
- [fb86b3d](https://github.com/Surnet/swagger-jsdoc/commit/fb86b3d39ce1df0b81f2c0cc8912f44026a2a7cc) Update version number to 1.1.2 (@chdanielmueller)
- [#11](https://github.com/Surnet/swagger-jsdoc/pull/11) Merge pull request #11 from trendfischer/master (@trendfischer)
- [b1695c0](https://github.com/Surnet/swagger-jsdoc/commit/b1695c033d8f5dc8274450214cfa5737f8decba8) Removed required path module (@trendfischer)
- [ec1de9c](https://github.com/Surnet/swagger-jsdoc/commit/ec1de9c80814296ad2ebd34c78a0e18113834bdb) Removed filename restriction for "\*.js" (@trendfischer)
### v1.1.1 (2015/09/27 17:07 +00:00)
- [afe96f0](https://github.com/Surnet/swagger-jsdoc/commit/afe96f063e5cd206d22ce724e27643d99b47a4f9) Updating dependencies (@chdanielmueller)
- [#10](https://github.com/Surnet/swagger-jsdoc/pull/10) Merge pull request #10 from drGrove/docs/definition (@drGrove)
- [c77cd0e](https://github.com/Surnet/swagger-jsdoc/commit/c77cd0ec2ab886ad711ad014a6037a8400111907) Adds docs for definition creation (@drGrove)
### v1.1.0 (2015/08/30 15:20 +00:00)
- [511778e](https://github.com/Surnet/swagger-jsdoc/commit/511778e506ec32f1b141273ec43fcacb6f390abd) Updating version number and fixing spelling error (@chdanielmueller)
- [#8](https://github.com/Surnet/swagger-jsdoc/pull/8) Merge pull request #8 from drGrove/feature/definitions (@drGrove)
- [f264e0e](https://github.com/Surnet/swagger-jsdoc/commit/f264e0e3e0a3aeea7e89cf29b5f7ff675a5ec318) Adds editorconfig (@drGrove)
- [6a512b1](https://github.com/Surnet/swagger-jsdoc/commit/6a512b182cd332ede62be2b020c30ad142508c53) Adds support for external definitions. Updates maxstatements to 15 (@drGrove)
### v1.0.1 (2015/08/23 08:25 +00:00)
- [359f239](https://github.com/Surnet/swagger-jsdoc/commit/359f239a85e87f7fc3cdbeead98e52b4ae257e99) Update version number (@chdanielmueller)
- [#6](https://github.com/Surnet/swagger-jsdoc/pull/6) Merge pull request #6 from drGrove/master (@drGrove)
- [0f7a70c](https://github.com/Surnet/swagger-jsdoc/commit/0f7a70cc7a8bdbf58224eb91ed54b57f7cbe6ca4) Adds parser for separate definitions (@drGrove)
- [7b88757](https://github.com/Surnet/swagger-jsdoc/commit/7b887578496c05f572b8b86fe879e48e7e05fb99) Removes console.logs (@drGrove)
- [07e40ad](https://github.com/Surnet/swagger-jsdoc/commit/07e40ada1da9852e7d34f94301b5ec6e06d41045) Adds object merging to allow for swagger docs of same endpoint with different methods [GET,POST] to be associated with the endpoint (@drGrove)
- [#5](https://github.com/Surnet/swagger-jsdoc/pull/5) Merge pull request #5 from chdanielmueller/master (@chdanielmueller)
- [ccd119e](https://github.com/Surnet/swagger-jsdoc/commit/ccd119e25a9730d0b1f95be74ef30d2aa82a870c) More documentation (@chdanielmueller)
- [#4](https://github.com/Surnet/swagger-jsdoc/pull/4) Merge pull request #4 from chdanielmueller/master (@chdanielmueller)
- [b0e7534](https://github.com/Surnet/swagger-jsdoc/commit/b0e75343183576694087d568dd3909cf4db8884b) Adding npm and Gratipay badges (@chdanielmueller)
### v1.0.0 (2015/06/09 16:33 +00:00)
- [#3](https://github.com/Surnet/swagger-jsdoc/pull/3) Merge pull request #3 from chdanielmueller/master (@chdanielmueller)
- [62bd690](https://github.com/Surnet/swagger-jsdoc/commit/62bd69001a28bce0c611a63cd9dc38cff5ff810d) Update to version 1.0.0 (@chdanielmueller)
- [3077045](https://github.com/Surnet/swagger-jsdoc/commit/30770457149f205433ff88999ea9fcaa17a99676) README.md (@chdanielmueller)
- [1ddc012](https://github.com/Surnet/swagger-jsdoc/commit/1ddc0121ecfae783b7242d3a82c39cdb2aa68a50) Remove swagger-tools (@chdanielmueller)
- [f63a68b](https://github.com/Surnet/swagger-jsdoc/commit/f63a68bdbe172ea6d17bdb10e3479d69cb82a41e) Exclude swagger serving from library (@chdanielmueller)
- [d6fa533](https://github.com/Surnet/swagger-jsdoc/commit/d6fa5331c18b3f0dd5cf3ea0255ecb8d026d93c1) Clean swagger spec in example (@chdanielmueller)
- [#2](https://github.com/Surnet/swagger-jsdoc/pull/2) Merge pull request #2 from chdanielmueller/master (@chdanielmueller)
- [4c0a6e0](https://github.com/Surnet/swagger-jsdoc/commit/4c0a6e0232c080624d4a3b34bb23f4a4a56389af) Fixing circle.yml (@chdanielmueller)
- [96e12c7](https://github.com/Surnet/swagger-jsdoc/commit/96e12c7fdcedb99176258d497509b24e1f011bae) Adding Badges to README.md (@chdanielmueller)
- [3fa16f2](https://github.com/Surnet/swagger-jsdoc/commit/3fa16f259c118a935652b28d55edc835f5d5b94f) Adding Codacy Coverage Token (@chdanielmueller)
- [64b3121](https://github.com/Surnet/swagger-jsdoc/commit/64b312185d123e9005fef988cd0a521bed5eb6c0) Typo (@chdanielmueller)
- [87e1730](https://github.com/Surnet/swagger-jsdoc/commit/87e1730f2919e2b01dae3f92885bbae41e56e312) Allow more statements (@chdanielmueller)
- [e81460e](https://github.com/Surnet/swagger-jsdoc/commit/e81460e5e0179f289c445362c1652543577a0247) Increasing coverage (@chdanielmueller)
- [f3449bb](https://github.com/Surnet/swagger-jsdoc/commit/f3449bba8786cabeaf97f63e1426a2784e1c8914) Refactoring (@chdanielmueller)
- [617a73f](https://github.com/Surnet/swagger-jsdoc/commit/617a73f6bf962dcfadde6308a1f9f2c7157625e7) Adding tests (@chdanielmueller)
- [2d2ecfe](https://github.com/Surnet/swagger-jsdoc/commit/2d2ecfec3db7d47bc7b62236d16f7b03d0078a8a) Prepare for CI (@chdanielmueller)
- [fea32b5](https://github.com/Surnet/swagger-jsdoc/commit/fea32b57e590c86d1bd2e4c74ba71182bb6645c0) Cleanup README.md (@chdanielmueller)
- [535b66d](https://github.com/Surnet/swagger-jsdoc/commit/535b66d7710d085ab44ba4463d18d217ca70b099) Adding references to external dependencies (@chdanielmueller)
- [c99b300](https://github.com/Surnet/swagger-jsdoc/commit/c99b3008f726dbe6d8bb14ff0f118aeb7737006c) Remove jsdoc from example (@chdanielmueller)
- [365f12b](https://github.com/Surnet/swagger-jsdoc/commit/365f12b25a842b9020bc21b5a1e3aaa77d26144e) Fix jscs and jshint errors (@chdanielmueller)
- [d7d6964](https://github.com/Surnet/swagger-jsdoc/commit/d7d6964762430efa1dc0fa00e9a8ee517747f92e) Adding coverage test (@chdanielmueller)
- [e3f6c3f](https://github.com/Surnet/swagger-jsdoc/commit/e3f6c3f7ac74cd4d764d17018430227c1b8170fa) Tweaks to the package.json (@chdanielmueller)
- [5a68333](https://github.com/Surnet/swagger-jsdoc/commit/5a68333b518d0dee9e3b48d10d2184fee82bbcc1) Remove example files (@chdanielmueller)
- [0df567c](https://github.com/Surnet/swagger-jsdoc/commit/0df567cdc826e1b4d5bae09795afe79cb5211cb2) Rename project, change URLs, Fix LICENSE (@chdanielmueller)
- [1562666](https://github.com/Surnet/swagger-jsdoc/commit/1562666e05efd4ed38af080183c946a2849fae45) Adding tests (@chdanielmueller)
- [e2768ac](https://github.com/Surnet/swagger-jsdoc/commit/e2768aca5117363a102161f00fd85d8b0b0c3d7d) Add jsdoc config (@chdanielmueller)
- [79a0758](https://github.com/Surnet/swagger-jsdoc/commit/79a0758a7410868533e9366390f6d1631d66df3a) Implement jscs and jshint (@chdanielmueller)
- [#1](https://github.com/Surnet/swagger-jsdoc/pull/1) Merge pull request #1 from chdanielmueller/refactor (@chdanielmueller)
- [5313d40](https://github.com/Surnet/swagger-jsdoc/commit/5313d40cef4e96430ec039eb8dd81b03a0b8b367) Working login example (@chdanielmueller)
- [a6b81b6](https://github.com/Surnet/swagger-jsdoc/commit/a6b81b69279cb15191eba84eb6d012a68b106c3a) Adding swaggerDefinition (@chdanielmueller)
- [c80bb01](https://github.com/Surnet/swagger-jsdoc/commit/c80bb0157dc642fb70bff8c51e7069c22ee0bf22) Switch to simple PetStore example (@chdanielmueller)
- [e807d99](https://github.com/Surnet/swagger-jsdoc/commit/e807d9917b7681e139d2825bcdf90086f4ca523d) Adding swagger-example in json and yml (@chdanielmueller)
- [824d1c1](https://github.com/Surnet/swagger-jsdoc/commit/824d1c155d956371d23577712bcb396c2a7769f2) Beautify Code (@chdanielmueller)
- [afed184](https://github.com/Surnet/swagger-jsdoc/commit/afed184047de4d4ea8dffc3b59e3ccbf5a9c9c1f) Remove express as dependency (@chdanielmueller)
- [0051b73](https://github.com/Surnet/swagger-jsdoc/commit/0051b73b9156ab66f3611a1d4b560fd0b54d9dd7) Change Formatting (@chdanielmueller)
- [5cd7b15](https://github.com/Surnet/swagger-jsdoc/commit/5cd7b15628b145c61ba4cf6b01caa356c2c3bcb6) Remove unneeded swaggerUI (@chdanielmueller)
- [dffb84a](https://github.com/Surnet/swagger-jsdoc/commit/dffb84ad40da37a1c0098a289381b35be1cab5e7) Modifiable URLs for documentation and swaggerUI (@chdanielmueller)
- [ebf2d72](https://github.com/Surnet/swagger-jsdoc/commit/ebf2d72c4c880cead651dceac51f2801dfd5ab4b) Adding swagger-tools (@chdanielmueller)
- [5b4c1eb](https://github.com/Surnet/swagger-jsdoc/commit/5b4c1eb1a408ab665e38b008a441e8ced792e528) It works!!! Now I have to refactor and do some tweaks. (@devlouisc)
- [d850f3f](https://github.com/Surnet/swagger-jsdoc/commit/d850f3f5112bc76f87b046003046a5783c5d97e6) Fix listing issues (@devlouisc)
- [7a82b46](https://github.com/Surnet/swagger-jsdoc/commit/7a82b46d468267c96b2cc9e04b3af96dce8fabfc) Remove example directory from ESLint ignore (@devlouisc)
- [fff57be](https://github.com/Surnet/swagger-jsdoc/commit/fff57be848f7e061ef1e9971bef1c589c43af095) Clean up comments (@devlouisc)
- [e65e356](https://github.com/Surnet/swagger-jsdoc/commit/e65e356e4d99cfb09cac96e4eb6cd475c17406ad) Add beginnings of new example app (@devlouisc)
- [f05a51f](https://github.com/Surnet/swagger-jsdoc/commit/f05a51fc1a0c5556971c3db2a62729bc1966391b) Fix linting (@devlouisc)
- [a98b8ab](https://github.com/Surnet/swagger-jsdoc/commit/a98b8aba143138b46bdb2f98722f7be588607b9f) Reorganize files (@devlouisc)
- [51ac313](https://github.com/Surnet/swagger-jsdoc/commit/51ac31387d8336e1962bf5fce1abb57f17050406) Update metadata with new project name and trim dependencies (@devlouisc)
- [8c86b95](https://github.com/Surnet/swagger-jsdoc/commit/8c86b95529e075db8392856a78668c978ede07c3) Remove support for YAML and CoffeeScript (@devlouisc)
- [e0df0ed](https://github.com/Surnet/swagger-jsdoc/commit/e0df0edd0f14e9c8f310ca203ccb7f8729cb460c) Remove old implementation (@devlouisc)
- [00f3be7](https://github.com/Surnet/swagger-jsdoc/commit/00f3be7c554f0fd4a09841ba4b9e4df3a5d6b296) Fix listing problems (@devlouisc)
- [0ba898b](https://github.com/Surnet/swagger-jsdoc/commit/0ba898bab5c37d97c88c39bf16431b8e4ebe92ed) Finish implementation of logic (@devlouisc)
- [cc1fedd](https://github.com/Surnet/swagger-jsdoc/commit/cc1feddff1be165e59a883b5ed56a4783e8a206c) Add example Swagger 2.0 JSON object (@devlouisc)
- [62eae1d](https://github.com/Surnet/swagger-jsdoc/commit/62eae1d32d8e684a7053e862f732dad8045be4b0) Add documentation and beginnings of parsing logic (@devlouisc)
- [465d359](https://github.com/Surnet/swagger-jsdoc/commit/465d3594eb2c2511ca3954b24506376b9d4314b4) Fine tune linting (@devlouisc)
- [bd2b1b4](https://github.com/Surnet/swagger-jsdoc/commit/bd2b1b4379744bea298da2c1e7d1b55322451460) Add and configure ESLint (@devlouisc)
- [e88fc7a](https://github.com/Surnet/swagger-jsdoc/commit/e88fc7a653ebd489f8f8027da29930d87e2d2f84) Add Swagger UI (@devlouisc)
- [95bd90f](https://github.com/Surnet/swagger-jsdoc/commit/95bd90f308ffcdd9468cba34e90e65d0cf08d7c1) Add options validation (@devlouisc)
- [33a1f98](https://github.com/Surnet/swagger-jsdoc/commit/33a1f980a22015dd70d543ecc1ad58898a0c9cb0) Update license (@devlouisc)
- [1160f1d](https://github.com/Surnet/swagger-jsdoc/commit/1160f1d477f9b6febab8d0e3032925b98a0f8408) Update npm dependency references (@devlouisc)
- [3f54b0d](https://github.com/Surnet/swagger-jsdoc/commit/3f54b0dbba7538c12cafff6fe748debfc62a4edc) Remove ignored files that do not pertain to my system (@devlouisc)
- [8031793](https://github.com/Surnet/swagger-jsdoc/commit/803179308f26e9345b32dabde87432158f8717c8) Remove global flag from npm install (@devlouisc)
- [a75ff89](https://github.com/Surnet/swagger-jsdoc/commit/a75ff894b22f3f2eb37f9c76bbc07261b109ff11) Fix formatting of comments (@devlouisc)
- [ca5e5b2](https://github.com/Surnet/swagger-jsdoc/commit/ca5e5b2770bb715b1e3a24829a48c0d22f9b4a4d) Format and alphabetize text (@devlouisc)
- [#25](https://github.com/Surnet/swagger-jsdoc/pull/25) Merge pull request #25 from miltonguty/patch-1 (@miltonguty)
- [8e6f862](https://github.com/Surnet/swagger-jsdoc/commit/8e6f862bc350afa2b979e21444b4063ee911d522) enable "Access-Control-Allow-Origin" in request (@miltonguty)
- [#24](https://github.com/Surnet/swagger-jsdoc/pull/24) Merge pull request #24 from relvao/master (@relvao)
- [e61fcbd](https://github.com/Surnet/swagger-jsdoc/commit/e61fcbde87822767077f14681a7db03e1fabfeab) fix Express 4 warning (@relvao)
- [#21](https://github.com/Surnet/swagger-jsdoc/pull/21) Merge pull request #21 from ElectricHummingbird/master (@ElectricHummingbird)
- [4ef14e4](https://github.com/Surnet/swagger-jsdoc/commit/4ef14e4ac0cc70d3b98c474f5e32f7fb43be9959) allow fullSwaggerJSONPath to be set in the cfg.
- [#18](https://github.com/Surnet/swagger-jsdoc/pull/18) Merge pull request #18 from tlvince/refactor/jshint (@tlvince)
- [#17](https://github.com/Surnet/swagger-jsdoc/pull/17) Merge pull request #17 from tlvince/feature/info (@tlvince)
- [388396c](https://github.com/Surnet/swagger-jsdoc/commit/388396ccd843854c56d3c5bc82d29dd115ca841c) Pass info object (@tlvince)
- [7aa9e99](https://github.com/Surnet/swagger-jsdoc/commit/7aa9e990cbb304493373e8ea0e0abfbd8d6a3d9d) Fix JSHint warning (@tlvince)
- [#16](https://github.com/Surnet/swagger-jsdoc/pull/16) Merge pull request #16 from gierschv/feat-expose (@gierschv)
- [f136d74](https://github.com/Surnet/swagger-jsdoc/commit/f136d74346eaf4fede718628e8285bd105cf09f8) Expose descriptor & resources (@gierschv)
- [#15](https://github.com/Surnet/swagger-jsdoc/pull/15) Merge pull request #15 from relvao/master (@relvao)
- [6190d11](https://github.com/Surnet/swagger-jsdoc/commit/6190d11d03c2361504fd48085081f21f147cbe24) Update index.js (@relvao)
- [#12](https://github.com/Surnet/swagger-jsdoc/pull/12) Merge pull request #12 from sposmen/master (@sposmen)
- [#13](https://github.com/Surnet/swagger-jsdoc/pull/13) Merge pull request #13 from johnywith1n/master (@johnywith1n)
- [0839ab0](https://github.com/Surnet/swagger-jsdoc/commit/0839ab00fcce601b201f94daf752ec5573cf7c3b) remove doc about basePath being optional.
- [bc2fba2](https://github.com/Surnet/swagger-jsdoc/commit/bc2fba285c16e75a165d6425d46951c03be199ee) set version of express to 3.5.1 since v4.0.0 doesnt work with the example app.
- [d8c80f3](https://github.com/Surnet/swagger-jsdoc/commit/d8c80f38b50a2787e440a3678bc973264d8cf845) require base path. match swagger json endpoints based on the full path which may include any parts from the basePath after the host.
- [32b28b2](https://github.com/Surnet/swagger-jsdoc/commit/32b28b205a42851c370c2df54218bf2f5aa731ba) Middleware function support (@sposmen)
- [#10](https://github.com/Surnet/swagger-jsdoc/pull/10) Merge pull request #10 from sposmen/master (@sposmen)
- [7c15437](https://github.com/Surnet/swagger-jsdoc/commit/7c1543719490b3b733eba7ae7ccd4c5392059cd2) Merge branch 'master' of github.com:sposmen/swagger-express (@sposmen)
- [36e27fd](https://github.com/Surnet/swagger-jsdoc/commit/36e27fd901b9fcf9be7f75fb1618953391e81724) README documentantion complement (@sposmen)
- [5e022e6](https://github.com/Surnet/swagger-jsdoc/commit/5e022e60ce1a4ff2df343893924cbe67b8c230f7) README documentantion complement (@sposmen)
- [1aebc40](https://github.com/Surnet/swagger-jsdoc/commit/1aebc40ea9e00134bc2961744387e060810fa8d3) New Jade standard (avoiding errors) (@sposmen)
- [5768a3d](https://github.com/Surnet/swagger-jsdoc/commit/5768a3daca8cee79d30b51025aa535d553d9b149) Specific origin of examples (@sposmen)
- [e528cd2](https://github.com/Surnet/swagger-jsdoc/commit/e528cd2490ada38d3013539d11607f718dd9342d) Coffee support added (@sposmen)
- [e38c3b9](https://github.com/Surnet/swagger-jsdoc/commit/e38c3b947071c85ee73c16113035ab164dd065a6) update version (@fliptoo)
- [14ccf0b](https://github.com/Surnet/swagger-jsdoc/commit/14ccf0b7effc2379f1b7adbe440b70c858f23aee) fixed swagger option (@fliptoo)
- [#6](https://github.com/Surnet/swagger-jsdoc/pull/6) Merge pull request #6 from slajax/master (@slajax)
- [9623f70](https://github.com/Surnet/swagger-jsdoc/commit/9623f704aa0a76824357314de81c2c02c5889549) added basePath to readme (@kc-dot-io)
- [1b4f3d6](https://github.com/Surnet/swagger-jsdoc/commit/1b4f3d6dfb2ba93e9d5e673083db2dbe9e186bad) basePath should still be able to be set so it can be passed to swagger.js (@kc-dot-io)
- [e97684d](https://github.com/Surnet/swagger-jsdoc/commit/e97684da334d7fd7414e87505de39c6e8336553f) Fixes #4 (@fliptoo)
- [9e89f97](https://github.com/Surnet/swagger-jsdoc/commit/9e89f977d831650ae5392a3a89277d4e43a5ecae) Update Example (@fliptoo)
- [4581d7a](https://github.com/Surnet/swagger-jsdoc/commit/4581d7a8f0fe05c10a1b7323f586b9091cade748) Fixes #4 (@fliptoo)
- [d481656](https://github.com/Surnet/swagger-jsdoc/commit/d4816562346ef030844998804c1ae754e3fc6fa6) Update Version (@fliptoo)
- [96262f9](https://github.com/Surnet/swagger-jsdoc/commit/96262f9a12ddb8ef9b79c2fd6084e7669b011199) Update Example (@fliptoo)
- [6e29773](https://github.com/Surnet/swagger-jsdoc/commit/6e29773ddd69351f50d21848d7507926a1027384) Set version on js-yaml to suppress deprecation warning output. (@fliptoo)
- [#3](https://github.com/Surnet/swagger-jsdoc/pull/3) Merge pull request #3 from calmdev/master (@calmdev)
- [39ca987](https://github.com/Surnet/swagger-jsdoc/commit/39ca987997c75c3b984cc3534ecdfcd9b0b62435) Updates the README file. (@calmdev)
- [cf31676](https://github.com/Surnet/swagger-jsdoc/commit/cf31676f7b33404d97d44ae1b1823b38bcae27d8) Base path isnt needed anymore, because we arent modifying the UIs source. (@calmdev)
- [da8bbc1](https://github.com/Surnet/swagger-jsdoc/commit/da8bbc132fc976145395c0604211022433be6e60) This doesnt work with latest swagger UI. Also, people should be encouraged to update and build the swagger UI from source instead of relying on swagger-express to modify the default discovery URL. (@calmdev)
- [3b86bff](https://github.com/Surnet/swagger-jsdoc/commit/3b86bff51d2fc75c7618e77d71f424c52298d528) Serves the swagger static assets from specified swaggerUI path. (@calmdev)
- [c182a47](https://github.com/Surnet/swagger-jsdoc/commit/c182a470c41daea2f35615f14e7f7642f999f970) Adds option to specify swaggers web interface url. (@calmdev)
- [ce80517](https://github.com/Surnet/swagger-jsdoc/commit/ce80517ae397a60b996683f6bcc3bf22e98e289d) Adds option to specify swaggers JSON url. (@calmdev)
- [196d119](https://github.com/Surnet/swagger-jsdoc/commit/196d119c30d53bb328e9c1177f26b4b2515580e1) Update README.md (@fliptoo)
- [37a06c1](https://github.com/Surnet/swagger-jsdoc/commit/37a06c1e89c1d16311d00a2371bfa1df2b74fd18) update version (@fliptoo)
- [69dc86d](https://github.com/Surnet/swagger-jsdoc/commit/69dc86d96875782a78bb8d27095387dce80d7b7a) commit package.json (@fliptoo)
- [#1](https://github.com/Surnet/swagger-jsdoc/pull/1) Merge pull request #1 from stelcheck/develop (@stelcheck)
- [579f1bb](https://github.com/Surnet/swagger-jsdoc/commit/579f1bb9bed6f82ea20757f67eed965e78f65fb5) \* Bugfix: was using path instead of resourcePath (@stelcheck)
- [98fe645](https://github.com/Surnet/swagger-jsdoc/commit/98fe6456ba7848eb212cf45b085911bce9493e0d) \* Code linting (@stelcheck)
- [53212be](https://github.com/Surnet/swagger-jsdoc/commit/53212bec50712856db318fedbcf9b7133a041a1b) Update README.md (@fliptoo)
- [7a6f4b2](https://github.com/Surnet/swagger-jsdoc/commit/7a6f4b2b2fa56c51f4bbf5d8f768a8b2bbe4e9df) Update README.md (@fliptoo)
- [d379519](https://github.com/Surnet/swagger-jsdoc/commit/d379519ee461922dc6b11a5b9aae92b64e281cda) fix require path (@fliptoo)
- [251fbaa](https://github.com/Surnet/swagger-jsdoc/commit/251fbaa623dd0f4c78744545f7d0e20958719507) fix resources (@fliptoo)
- [fed18da](https://github.com/Surnet/swagger-jsdoc/commit/fed18da6efaefdf05ae16fb8c8b1f64734dbf8e7) edit npmignore (@fliptoo)
- [086f3fc](https://github.com/Surnet/swagger-jsdoc/commit/086f3fc8ea69c51f90f9aaf5be48fe420db08d1e) change to example (@fliptoo)
- [4f27c86](https://github.com/Surnet/swagger-jsdoc/commit/4f27c8634b61eb7c4bb711fbe82a688cff976b50) Update README.md (@fliptoo)
- [6a2e19c](https://github.com/Surnet/swagger-jsdoc/commit/6a2e19c7bf1e671369c79d777e4832ed2ccc3f3c) Create README.md (@fliptoo)
- [7b1d808](https://github.com/Surnet/swagger-jsdoc/commit/7b1d80862389dd7aacede4a4bca1d3b423ea0aec) initial commit (@fliptoo)
- [6f64e49](https://github.com/Surnet/swagger-jsdoc/commit/6f64e4992d7953c69694ea87177b3cd59fd9da43) Initial commit (@fliptoo)
+23
View File
@@ -0,0 +1,23 @@
The MIT License (MIT)
Copyright (c) 2013 Fliptoo <fliptoo.studio@gmail.com>
Copyright (c) 2015 devlouisc
Copyright (c) 2015 Surnet
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.
+102
View File
@@ -0,0 +1,102 @@
# swagger-jsdoc
This library reads your [JSDoc](https://jsdoc.app/)-annotated source code and generates an [OpenAPI (Swagger) specification](https://swagger.io/specification/).
[![npm Downloads](https://img.shields.io/npm/dm/swagger-jsdoc.svg)](https://www.npmjs.com/package/swagger-jsdoc)
![CI](https://github.com/Surnet/swagger-jsdoc/workflows/CI/badge.svg)
## Getting started
Imagine having API files like these:
```javascript
/**
* @openapi
* /:
* get:
* description: Welcome to swagger-jsdoc!
* responses:
* 200:
* description: Returns a mysterious string.
*/
app.get('/', (req, res) => {
res.send('Hello World!');
});
```
The library will take the contents of `@openapi` (or `@swagger`) with the following configuration:
```javascript
const swaggerJsdoc = require('swagger-jsdoc');
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'Hello World',
version: '1.0.0',
},
},
apis: ['./src/routes*.js'], // files containing annotations as above
};
const openapiSpecification = swaggerJsdoc(options);
```
The resulting `openapiSpecification` will be a [swagger tools](https://swagger.io/tools/)-compatible (and validated) specification.
![swagger-jsdoc example screenshot](./docs/screenshot.png)
## System requirements
- Node.js 12.x or higher
You are viewing `swagger-jsdoc` v6 which is published in CommonJS module system.
## Installation
```bash
npm install swagger-jsdoc --save
```
Or
```bash
yarn add swagger-jsdoc
```
## Supported specifications
- OpenAPI 3.x
- Swagger 2
- AsyncAPI 2.0
## Validation of swagger docs
By default `swagger-jsdoc` tries to parse all docs to it's best capabilities. If you'd like to you can instruct an Error to be thrown instead if validation failed by setting the options flag `failOnErrors` to `true`. This is for instance useful if you want to verify that your swagger docs validate using a unit test.
```javascript
const swaggerJsdoc = require('swagger-jsdoc');
const options = {
failOnErrors: true, // Whether or not to throw when parsing errors. Defaults to false.
definition: {
openapi: '3.0.0',
info: {
title: 'Hello World',
version: '1.0.0',
},
},
apis: ['./src/routes*.js'],
};
const openapiSpecification = swaggerJsdoc(options);
```
## Documentation
Click on the version you are using for further details:
- [7.x](https://github.com/Surnet/swagger-jsdoc/tree/v7/docs)
- [6.x](https://github.com/Surnet/swagger-jsdoc/tree/v6/docs)
- [5.x](https://github.com/Surnet/swagger-jsdoc/tree/v5)
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const program = require('commander');
const pkg = require('../package.json');
const swaggerJsdoc = require('..');
const { loadDefinition } = require('../src/utils');
program
.version(pkg.version)
.usage('[options] <path ...>')
.option(
'-d, --definition <swaggerDefinition.js>',
'Input swagger definition.'
)
.option('-o, --output [swaggerSpec.json]', 'Output swagger specification.')
.parse(process.argv);
if (!process.argv.slice(2).length) {
program.help();
process.exit();
}
const { definition } = program;
const output = program.output || 'swagger.json';
if (!definition) {
console.log('Definition file is required.');
program.help();
process.exit();
}
let swaggerDefinition;
try {
swaggerDefinition = loadDefinition(
definition,
fs.readFileSync(definition, 'utf-8')
);
} catch (error) {
console.log(
`Error while loading definition file '${definition}':\n${error.message}`
);
process.exit();
}
// Check for info object in the definition.
if (!('info' in swaggerDefinition)) {
console.log('Definition file should contain an info object!');
console.log('More at http://swagger.io/specification/#infoObject');
process.exit();
}
// Check for title and version properties in the info object.
if (
!('title' in swaggerDefinition.info) ||
!('version' in swaggerDefinition.info)
) {
console.log('The title and version properties are required!');
console.log('More at http://swagger.io/specification/#infoObject');
process.exit();
}
// Continue only if arguments provided.
if (!program.args.length) {
console.log('You must provide sources for reading API files.');
process.exit();
}
const format = path.extname(output);
const result = swaggerJsdoc({
swaggerDefinition,
apis: program.args,
format,
});
if (format === '.json') {
fs.writeFileSync(output, JSON.stringify(result, null, 2));
} else {
fs.writeFileSync(output, result);
}
console.log('Swagger specification is ready.');
@@ -0,0 +1,39 @@
{
"root": true,
"extends": [
"eslint:recommended",
"plugin:import/errors",
"plugin:react/recommended",
"plugin:jsx-a11y/recommended",
"plugin:@docusaurus/recommended",
"plugin:prettier/recommended"
],
"plugins": ["react", "import", "jsx-a11y", "@docusaurus"],
"rules": {
"react/prop-types": 0,
"indent": ["error", 2],
"linebreak-style": 1,
"quotes": ["error", "single"],
"import/no-unresolved": [
2,
{ "ignore": ["^@theme", "^@docusaurus", "^@site"] }
]
},
"parserOptions": {
"ecmaVersion": 2021,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"settings": {
"react": {
"version": "detect"
}
},
"env": {
"es6": true,
"browser": true,
"node": true
}
}
+98
View File
@@ -0,0 +1,98 @@
# swagger-jsdoc
This library reads your [JSDoc](https://jsdoc.app/)-annotated source code and generates an [OpenAPI (Swagger) specification](https://swagger.io/specification/).
[![npm Downloads](https://img.shields.io/npm/dm/swagger-jsdoc.svg)](https://www.npmjs.com/package/swagger-jsdoc)
![CI](https://github.com/Surnet/swagger-jsdoc/workflows/CI/badge.svg)
## Getting started
Imagine having API files like these:
```javascript
/**
* @openapi
* /:
* get:
* description: Welcome to swagger-jsdoc!
* responses:
* 200:
* description: Returns a mysterious string.
*/
app.get('/', (req, res) => {
res.send('Hello World!');
});
```
The library will take the contents of `@openapi` (or `@swagger`) with the following configuration:
```javascript
const swaggerJsdoc = require('swagger-jsdoc');
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'Hello World',
version: '1.0.0',
},
},
apis: ['./src/routes*.js'], // files containing annotations as above
};
const openapiSpecification = swaggerJsdoc(options);
```
The resulting `openapiSpecification` will be a [swagger tools](https://swagger.io/tools/)-compatible (and validated) specification.
![swagger-jsdoc example screenshot](/img/screenshot.png)
## System requirements
- Node.js 12.x or higher
You are viewing `swagger-jsdoc` v6 which is published in CommonJS module system.
## Installation
```bash
npm install swagger-jsdoc --save
```
Or
```bash
yarn add swagger-jsdoc
```
## Supported specifications
- OpenAPI 3.x
- Swagger 2
- AsyncAPI 2.0
## Validation of swagger docs
By default `swagger-jsdoc` tries to parse all docs to it's best capabilities. If you'd like to you can instruct an Error to be thrown instead if validation failed by setting the options flag `failOnErrors` to `true`. This is for instance useful if you want to verify that your swagger docs validate using a unit test.
```javascript
const swaggerJsdoc = require('swagger-jsdoc');
const options = {
failOnErrors: true, // Whether or not to throw when parsing errors. Defaults to false.
definition: {
openapi: '3.0.0',
info: {
title: 'Hello World',
version: '1.0.0',
},
},
apis: ['./src/routes*.js'],
};
const openapiSpecification = swaggerJsdoc(options);
```
## Documentation
Click on the version you are using from navigation bar for further details.
@@ -0,0 +1,3 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};
+103
View File
@@ -0,0 +1,103 @@
---
sidebar_position: 1
title: Intro
---
# swagger-jsdoc
This library reads your [JSDoc](https://jsdoc.app/)-annotated source code and generates an [OpenAPI (Swagger) specification](https://swagger.io/specification/).
[![npm Downloads](https://img.shields.io/npm/dm/swagger-jsdoc.svg)](https://www.npmjs.com/package/swagger-jsdoc)
![CI](https://github.com/Surnet/swagger-jsdoc/workflows/CI/badge.svg)
## Getting started
Imagine having API files like these:
```javascript
/**
* @openapi
* /:
* get:
* description: Welcome to swagger-jsdoc!
* responses:
* 200:
* description: Returns a mysterious string.
*/
app.get('/', (req, res) => {
res.send('Hello World!');
});
```
The library will take the contents of `@openapi` (or `@swagger`) with the following configuration:
```javascript
const swaggerJsdoc = require('swagger-jsdoc');
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'Hello World',
version: '1.0.0',
},
},
apis: ['./src/routes*.js'], // files containing annotations as above
};
const openapiSpecification = swaggerJsdoc(options);
```
The resulting `openapiSpecification` will be a [swagger tools](https://swagger.io/tools/)-compatible (and validated) specification.
![swagger-jsdoc example screenshot](/img/screenshot.png)
## System requirements
- Node.js 12.x or higher
You are viewing `swagger-jsdoc` v6 which is published in CommonJS module system.
## Installation
```bash
npm install swagger-jsdoc --save
```
Or
```bash
yarn add swagger-jsdoc
```
## Supported specifications
- OpenAPI 3.x
- Swagger 2
- AsyncAPI 2.0
## Validation of swagger docs
By default `swagger-jsdoc` tries to parse all docs to it's best capabilities. If you'd like to you can instruct an Error to be thrown instead if validation failed by setting the options flag `failOnErrors` to `true`. This is for instance useful if you want to verify that your swagger docs validate using a unit test.
```javascript
const swaggerJsdoc = require('swagger-jsdoc');
const options = {
failOnErrors: true, // Whether or not to throw when parsing errors. Defaults to false.
definition: {
openapi: '3.0.0',
info: {
title: 'Hello World',
version: '1.0.0',
},
},
apis: ['./src/routes*.js'],
};
const openapiSpecification = swaggerJsdoc(options);
```
## Documentation
Click on the version you are using from navigation bar for further details.
@@ -0,0 +1,90 @@
// @ts-check
const lightCodeTheme = require('prism-react-renderer/themes/github');
const darkCodeTheme = require('prism-react-renderer/themes/dracula');
/** @type {import('@docusaurus/types').Config} */
const config = {
title: 'swagger-jsdoc Official Documentation',
tagline:
'Generates swagger/openapi specification based on jsDoc comments and YAML files.',
url: 'https://github.com/Surnet/swagger-jsdoc',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico',
organizationName: 'Surnet',
projectName: 'swagger-jsdoc',
i18n: {
defaultLocale: 'en',
locales: ['en'],
},
presets: [
[
'classic',
/** @type {import('@docusaurus/preset-classic').Options} */
({
docs: {
sidebarPath: require.resolve('./sidebars.js'),
editUrl:
'https://github.com/Surnet/swagger-jsdoc/tree/master/docusaurus',
},
theme: {
customCss: require.resolve('./src/css/custom.css'),
},
}),
],
],
themeConfig:
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
({
navbar: {
title: 'swagger-jsdoc',
// logo: {
// alt: 'My Site Logo',
// src: 'img/logo.svg',
// },
items: [
{
type: 'doc',
docId: 'intro',
position: 'left',
label: 'Tutorial',
},
{
href: 'https://github.com/Surnet/swagger-jsdoc',
label: 'GitHub',
position: 'right',
},
{
type: 'docsVersionDropdown',
},
],
},
footer: {
style: 'dark',
links: [
{
title: 'Docs',
items: [
{
label: 'Tutorial',
to: '/docs/intro',
},
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} swagger-jsdoc, Inc. Built with Docusaurus.`,
},
prism: {
theme: lightCodeTheme,
darkTheme: darkCodeTheme,
},
}),
};
module.exports = config;
+51
View File
@@ -0,0 +1,51 @@
{
"name": "docusaurus",
"version": "0.0.0",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
"start": "docusaurus start",
"build": "docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"clear": "docusaurus clear",
"serve": "docusaurus serve",
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids",
"lint": "eslint ."
},
"dependencies": {
"@docusaurus/core": "2.0.1",
"@docusaurus/preset-classic": "2.0.1",
"@mdx-js/react": "^1.6.22",
"clsx": "^1.2.1",
"prism-react-renderer": "^1.3.5",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@docusaurus/eslint-plugin": "^2.0.1",
"@docusaurus/module-type-aliases": "2.0.1",
"eslint": "^8.21.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.30.1",
"prettier": "^2.7.1"
},
"browserslist": {
"production": [
">0.5%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"engines": {
"node": ">=16.14"
}
}
@@ -0,0 +1,8 @@
// @ts-check
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }],
};
module.exports = sidebars;
@@ -0,0 +1,30 @@
/**
* Any CSS included here will be global. The classic template
* bundles Infima by default. Infima is a CSS framework designed to
* work well for content-centric websites.
*/
/* You can override the default Infima variables here. */
:root {
--ifm-color-primary: #2e8555;
--ifm-color-primary-dark: #29784c;
--ifm-color-primary-darker: #277148;
--ifm-color-primary-darkest: #205d3b;
--ifm-color-primary-light: #33925d;
--ifm-color-primary-lighter: #359962;
--ifm-color-primary-lightest: #3cad6e;
--ifm-code-font-size: 95%;
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
}
/* For readability concerns, you should choose a lighter palette in dark mode. */
[data-theme='dark'] {
--ifm-color-primary: #25c2a0;
--ifm-color-primary-dark: #21af90;
--ifm-color-primary-darker: #1fa588;
--ifm-color-primary-darkest: #1a8870;
--ifm-color-primary-light: #29d5b0;
--ifm-color-primary-lighter: #32d8b4;
--ifm-color-primary-lightest: #4fddbf;
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
}
@@ -0,0 +1,39 @@
import React from 'react';
import clsx from 'clsx';
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import Layout from '@theme/Layout';
import styles from './index.module.css';
function HomepageHeader() {
const { siteConfig } = useDocusaurusContext();
return (
<header className={clsx('hero hero--primary', styles.heroBanner)}>
<div className="container">
<h1 className="hero__title">{siteConfig.title}</h1>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<div className={styles.buttons}>
<Link
className="button button--secondary button--lg"
to="/docs/intro"
>
View Documentation
</Link>
</div>
</div>
</header>
);
}
export default function Home() {
const { siteConfig } = useDocusaurusContext();
return (
<Layout
title={`Hello from ${siteConfig.title}`}
description="Generates swagger/openapi specification based on jsDoc comments and YAML files."
>
<HomepageHeader />
</Layout>
);
}
@@ -0,0 +1,23 @@
/**
* CSS files with the .module.css suffix will be treated as CSS modules
* and scoped locally.
*/
.heroBanner {
padding: 4rem 0;
text-align: center;
position: relative;
overflow: hidden;
}
@media screen and (max-width: 996px) {
.heroBanner {
padding: 2rem;
}
}
.buttons {
display: flex;
align-items: center;
justify-content: center;
}
@@ -0,0 +1,7 @@
---
title: Markdown page example
---
# Markdown page example
You don't need React to write simple standalone pages.
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

@@ -0,0 +1,171 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1088" height="687.962" viewBox="0 0 1088 687.962">
<title>Easy to Use</title>
<g id="Group_12" data-name="Group 12" transform="translate(-57 -56)">
<g id="Group_11" data-name="Group 11" transform="translate(57 56)">
<path id="Path_83" data-name="Path 83" d="M1017.81,560.461c-5.27,45.15-16.22,81.4-31.25,110.31-20,38.52-54.21,54.04-84.77,70.28a193.275,193.275,0,0,1-27.46,11.94c-55.61,19.3-117.85,14.18-166.74,3.99a657.282,657.282,0,0,0-104.09-13.16q-14.97-.675-29.97-.67c-15.42.02-293.07,5.29-360.67-131.57-16.69-33.76-28.13-75-32.24-125.27-11.63-142.12,52.29-235.46,134.74-296.47,155.97-115.41,369.76-110.57,523.43,7.88C941.15,276.621,1036.99,396.031,1017.81,560.461Z" transform="translate(-56 -106.019)" fill="#3f3d56"/>
<path id="Path_84" data-name="Path 84" d="M986.56,670.771c-20,38.52-47.21,64.04-77.77,80.28a193.272,193.272,0,0,1-27.46,11.94c-55.61,19.3-117.85,14.18-166.74,3.99a657.3,657.3,0,0,0-104.09-13.16q-14.97-.675-29.97-.67-23.13.03-46.25,1.72c-100.17,7.36-253.82-6.43-321.42-143.29L382,283.981,444.95,445.6l20.09,51.59,55.37-75.98L549,381.981l130.2,149.27,36.8-81.27L970.78,657.9l14.21,11.59Z" transform="translate(-56 -106.019)" fill="#f2f2f2"/>
<path id="Path_85" data-name="Path 85" d="M302,282.962l26-57,36,83-31-60Z" opacity="0.1"/>
<path id="Path_86" data-name="Path 86" d="M610.5,753.821q-14.97-.675-29.97-.67L465.04,497.191Z" transform="translate(-56 -106.019)" opacity="0.1"/>
<path id="Path_87" data-name="Path 87" d="M464.411,315.191,493,292.962l130,150-132-128Z" opacity="0.1"/>
<path id="Path_88" data-name="Path 88" d="M908.79,751.051a193.265,193.265,0,0,1-27.46,11.94L679.2,531.251Z" transform="translate(-56 -106.019)" opacity="0.1"/>
<circle id="Ellipse_11" data-name="Ellipse 11" cx="3" cy="3" r="3" transform="translate(479 98.962)" fill="#f2f2f2"/>
<circle id="Ellipse_12" data-name="Ellipse 12" cx="3" cy="3" r="3" transform="translate(396 201.962)" fill="#f2f2f2"/>
<circle id="Ellipse_13" data-name="Ellipse 13" cx="2" cy="2" r="2" transform="translate(600 220.962)" fill="#f2f2f2"/>
<circle id="Ellipse_14" data-name="Ellipse 14" cx="2" cy="2" r="2" transform="translate(180 265.962)" fill="#f2f2f2"/>
<circle id="Ellipse_15" data-name="Ellipse 15" cx="2" cy="2" r="2" transform="translate(612 96.962)" fill="#f2f2f2"/>
<circle id="Ellipse_16" data-name="Ellipse 16" cx="2" cy="2" r="2" transform="translate(736 192.962)" fill="#f2f2f2"/>
<circle id="Ellipse_17" data-name="Ellipse 17" cx="2" cy="2" r="2" transform="translate(858 344.962)" fill="#f2f2f2"/>
<path id="Path_89" data-name="Path 89" d="M306,121.222h-2.76v-2.76h-1.48v2.76H299V122.7h2.76v2.759h1.48V122.7H306Z" fill="#f2f2f2"/>
<path id="Path_90" data-name="Path 90" d="M848,424.222h-2.76v-2.76h-1.48v2.76H841V425.7h2.76v2.759h1.48V425.7H848Z" fill="#f2f2f2"/>
<path id="Path_91" data-name="Path 91" d="M1144,719.981c0,16.569-243.557,74-544,74s-544-57.431-544-74,243.557,14,544,14S1144,703.413,1144,719.981Z" transform="translate(-56 -106.019)" fill="#3f3d56"/>
<path id="Path_92" data-name="Path 92" d="M1144,719.981c0,16.569-243.557,74-544,74s-544-57.431-544-74,243.557,14,544,14S1144,703.413,1144,719.981Z" transform="translate(-56 -106.019)" opacity="0.1"/>
<ellipse id="Ellipse_18" data-name="Ellipse 18" cx="544" cy="30" rx="544" ry="30" transform="translate(0 583.962)" fill="#3f3d56"/>
<path id="Path_93" data-name="Path 93" d="M624,677.981c0,33.137-14.775,24-33,24s-33,9.137-33-24,33-96,33-96S624,644.844,624,677.981Z" transform="translate(-56 -106.019)" fill="#ff6584"/>
<path id="Path_94" data-name="Path 94" d="M606,690.66c0,15.062-6.716,10.909-15,10.909s-15,4.153-15-10.909,15-43.636,15-43.636S606,675.6,606,690.66Z" transform="translate(-56 -106.019)" opacity="0.1"/>
<rect id="Rectangle_97" data-name="Rectangle 97" width="92" height="18" rx="9" transform="translate(489 604.962)" fill="#2f2e41"/>
<rect id="Rectangle_98" data-name="Rectangle 98" width="92" height="18" rx="9" transform="translate(489 586.962)" fill="#2f2e41"/>
<path id="Path_95" data-name="Path 95" d="M193,596.547c0,55.343,34.719,100.126,77.626,100.126" transform="translate(-56 -106.019)" fill="#3f3d56"/>
<path id="Path_96" data-name="Path 96" d="M270.626,696.673c0-55.965,38.745-101.251,86.626-101.251" transform="translate(-56 -106.019)" fill="#6c63ff"/>
<path id="Path_97" data-name="Path 97" d="M221.125,601.564c0,52.57,22.14,95.109,49.5,95.109" transform="translate(-56 -106.019)" fill="#6c63ff"/>
<path id="Path_98" data-name="Path 98" d="M270.626,696.673c0-71.511,44.783-129.377,100.126-129.377" transform="translate(-56 -106.019)" fill="#3f3d56"/>
<path id="Path_99" data-name="Path 99" d="M254.3,697.379s11.009-.339,14.326-2.7,16.934-5.183,17.757-1.395,16.544,18.844,4.115,18.945-28.879-1.936-32.19-3.953S254.3,697.379,254.3,697.379Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
<path id="Path_100" data-name="Path 100" d="M290.716,710.909c-12.429.1-28.879-1.936-32.19-3.953-2.522-1.536-3.527-7.048-3.863-9.591l-.368.014s.7,8.879,4.009,10.9,19.761,4.053,32.19,3.953c3.588-.029,4.827-1.305,4.759-3.2C294.755,710.174,293.386,710.887,290.716,710.909Z" transform="translate(-56 -106.019)" opacity="0.2"/>
<path id="Path_101" data-name="Path 101" d="M777.429,633.081c0,38.029,23.857,68.8,53.341,68.8" transform="translate(-56 -106.019)" fill="#3f3d56"/>
<path id="Path_102" data-name="Path 102" d="M830.769,701.882c0-38.456,26.623-69.575,59.525-69.575" transform="translate(-56 -106.019)" fill="#6c63ff"/>
<path id="Path_103" data-name="Path 103" d="M796.755,636.528c0,36.124,15.213,65.354,34.014,65.354" transform="translate(-56 -106.019)" fill="#6c63ff"/>
<path id="Path_104" data-name="Path 104" d="M830.769,701.882c0-49.139,30.773-88.9,68.8-88.9" transform="translate(-56 -106.019)" fill="#3f3d56"/>
<path id="Path_105" data-name="Path 105" d="M819.548,702.367s7.565-.233,9.844-1.856,11.636-3.562,12.2-.958,11.368,12.949,2.828,13.018-19.844-1.33-22.119-2.716S819.548,702.367,819.548,702.367Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
<path id="Path_106" data-name="Path 106" d="M844.574,711.664c-8.54.069-19.844-1.33-22.119-2.716-1.733-1.056-2.423-4.843-2.654-6.59l-.253.01s.479,6.1,2.755,7.487,13.579,2.785,22.119,2.716c2.465-.02,3.317-.9,3.27-2.2C847.349,711.159,846.409,711.649,844.574,711.664Z" transform="translate(-56 -106.019)" opacity="0.2"/>
<path id="Path_107" data-name="Path 107" d="M949.813,724.718s11.36-1.729,14.5-4.591,16.89-7.488,18.217-3.667,19.494,17.447,6.633,19.107-30.153,1.609-33.835-.065S949.813,724.718,949.813,724.718Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
<path id="Path_108" data-name="Path 108" d="M989.228,734.173c-12.86,1.659-30.153,1.609-33.835-.065-2.8-1.275-4.535-6.858-5.2-9.45l-.379.061s1.833,9.109,5.516,10.783,20.975,1.725,33.835.065c3.712-.479,4.836-1.956,4.529-3.906C993.319,732.907,991.991,733.817,989.228,734.173Z" transform="translate(-56 -106.019)" opacity="0.2"/>
<path id="Path_109" data-name="Path 109" d="M670.26,723.9s9.587-1.459,12.237-3.875,14.255-6.32,15.374-3.095,16.452,14.725,5.6,16.125-25.448,1.358-28.555-.055S670.26,723.9,670.26,723.9Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
<path id="Path_110" data-name="Path 110" d="M703.524,731.875c-10.853,1.4-25.448,1.358-28.555-.055-2.367-1.076-3.827-5.788-4.39-7.976l-.32.051s1.547,7.687,4.655,9.1,17.7,1.456,28.555.055c3.133-.4,4.081-1.651,3.822-3.3C706.977,730.807,705.856,731.575,703.524,731.875Z" transform="translate(-56 -106.019)" opacity="0.2"/>
<path id="Path_111" data-name="Path 111" d="M178.389,719.109s7.463-1.136,9.527-3.016,11.1-4.92,11.969-2.409,12.808,11.463,4.358,12.553-19.811,1.057-22.23-.043S178.389,719.109,178.389,719.109Z" transform="translate(-56 -106.019)" fill="#a8a8a8"/>
<path id="Path_112" data-name="Path 112" d="M204.285,725.321c-8.449,1.09-19.811,1.057-22.23-.043-1.842-.838-2.979-4.506-3.417-6.209l-.249.04s1.2,5.984,3.624,7.085,13.781,1.133,22.23.043c2.439-.315,3.177-1.285,2.976-2.566C206.973,724.489,206.1,725.087,204.285,725.321Z" transform="translate(-56 -106.019)" opacity="0.2"/>
<path id="Path_113" data-name="Path 113" d="M439.7,707.337c0,30.22-42.124,20.873-93.7,20.873s-93.074,9.347-93.074-20.873,42.118-36.793,93.694-36.793S439.7,677.117,439.7,707.337Z" transform="translate(-56 -106.019)" opacity="0.1"/>
<path id="Path_114" data-name="Path 114" d="M439.7,699.9c0,30.22-42.124,20.873-93.7,20.873s-93.074,9.347-93.074-20.873S295.04,663.1,346.616,663.1,439.7,669.676,439.7,699.9Z" transform="translate(-56 -106.019)" fill="#3f3d56"/>
</g>
<g id="docusaurus_keytar" transform="translate(312.271 493.733)">
<path id="Path_40" data-name="Path 40" d="M99,52h91.791V89.153H99Z" transform="translate(5.904 -14.001)" fill="#fff" fill-rule="evenodd"/>
<path id="Path_41" data-name="Path 41" d="M24.855,163.927A21.828,21.828,0,0,1,5.947,153a21.829,21.829,0,0,0,18.908,32.782H46.71V163.927Z" transform="translate(-3 -4.634)" fill="#3ecc5f" fill-rule="evenodd"/>
<path id="Path_42" data-name="Path 42" d="M121.861,61.1l76.514-4.782V45.39A21.854,21.854,0,0,0,176.52,23.535H78.173L75.441,18.8a3.154,3.154,0,0,0-5.464,0l-2.732,4.732L64.513,18.8a3.154,3.154,0,0,0-5.464,0l-2.732,4.732L53.586,18.8a3.154,3.154,0,0,0-5.464,0L45.39,23.535c-.024,0-.046,0-.071,0l-4.526-4.525a3.153,3.153,0,0,0-5.276,1.414l-1.5,5.577-5.674-1.521a3.154,3.154,0,0,0-3.863,3.864L26,34.023l-5.575,1.494a3.155,3.155,0,0,0-1.416,5.278l4.526,4.526c0,.023,0,.046,0,.07L18.8,48.122a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,59.05a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,69.977a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,80.9a3.154,3.154,0,0,0,0,5.464L23.535,89.1,18.8,91.832a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,102.76a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,113.687a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,124.615a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,135.542a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,146.469a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,157.4a3.154,3.154,0,0,0,0,5.464l4.732,2.732L18.8,168.324a3.154,3.154,0,0,0,0,5.464l4.732,2.732A21.854,21.854,0,0,0,45.39,198.375H176.52a21.854,21.854,0,0,0,21.855-21.855V89.1l-76.514-4.782a11.632,11.632,0,0,1,0-23.219" transform="translate(-1.681 -17.226)" fill="#3ecc5f" fill-rule="evenodd"/>
<path id="Path_43" data-name="Path 43" d="M143,186.71h32.782V143H143Z" transform="translate(9.984 -5.561)" fill="#3ecc5f" fill-rule="evenodd"/>
<path id="Path_44" data-name="Path 44" d="M196.71,159.855a5.438,5.438,0,0,0-.7.07c-.042-.164-.081-.329-.127-.493a5.457,5.457,0,1,0-5.4-9.372q-.181-.185-.366-.367a5.454,5.454,0,1,0-9.384-5.4c-.162-.046-.325-.084-.486-.126a5.467,5.467,0,1,0-10.788,0c-.162.042-.325.08-.486.126a5.457,5.457,0,1,0-9.384,5.4,21.843,21.843,0,1,0,36.421,21.02,5.452,5.452,0,1,0,.7-10.858" transform="translate(10.912 -6.025)" fill="#44d860" fill-rule="evenodd"/>
<path id="Path_45" data-name="Path 45" d="M153,124.855h32.782V103H153Z" transform="translate(10.912 -9.271)" fill="#3ecc5f" fill-rule="evenodd"/>
<path id="Path_46" data-name="Path 46" d="M194.855,116.765a2.732,2.732,0,1,0,0-5.464,2.811,2.811,0,0,0-.349.035c-.022-.082-.04-.164-.063-.246a2.733,2.733,0,0,0-1.052-5.253,2.7,2.7,0,0,0-1.648.566q-.09-.093-.184-.184a2.7,2.7,0,0,0,.553-1.633,2.732,2.732,0,0,0-5.245-1.07,10.928,10.928,0,1,0,0,21.031,2.732,2.732,0,0,0,5.245-1.07,2.7,2.7,0,0,0-.553-1.633q.093-.09.184-.184a2.7,2.7,0,0,0,1.648.566,2.732,2.732,0,0,0,1.052-5.253c.023-.081.042-.164.063-.246a2.814,2.814,0,0,0,.349.035" transform="translate(12.767 -9.377)" fill="#44d860" fill-rule="evenodd"/>
<path id="Path_47" data-name="Path 47" d="M65.087,56.891a2.732,2.732,0,0,1-2.732-2.732,8.2,8.2,0,0,0-16.391,0,2.732,2.732,0,0,1-5.464,0,13.659,13.659,0,0,1,27.319,0,2.732,2.732,0,0,1-2.732,2.732" transform="translate(0.478 -15.068)" fill-rule="evenodd"/>
<path id="Path_48" data-name="Path 48" d="M103,191.347h65.565a21.854,21.854,0,0,0,21.855-21.855V93H124.855A21.854,21.854,0,0,0,103,114.855Z" transform="translate(6.275 -10.199)" fill="#ffff50" fill-rule="evenodd"/>
<path id="Path_49" data-name="Path 49" d="M173.216,129.787H118.535a1.093,1.093,0,1,1,0-2.185h54.681a1.093,1.093,0,0,1,0,2.185m0,21.855H118.535a1.093,1.093,0,1,1,0-2.186h54.681a1.093,1.093,0,0,1,0,2.186m0,21.855H118.535a1.093,1.093,0,1,1,0-2.185h54.681a1.093,1.093,0,0,1,0,2.185m0-54.434H118.535a1.093,1.093,0,1,1,0-2.185h54.681a1.093,1.093,0,0,1,0,2.185m0,21.652H118.535a1.093,1.093,0,1,1,0-2.186h54.681a1.093,1.093,0,0,1,0,2.186m0,21.855H118.535a1.093,1.093,0,1,1,0-2.186h54.681a1.093,1.093,0,0,1,0,2.186M189.585,61.611c-.013,0-.024-.007-.037-.005-3.377.115-4.974,3.492-6.384,6.472-1.471,3.114-2.608,5.139-4.473,5.078-2.064-.074-3.244-2.406-4.494-4.874-1.436-2.835-3.075-6.049-6.516-5.929-3.329.114-4.932,3.053-6.346,5.646-1.5,2.762-2.529,4.442-4.5,4.364-2.106-.076-3.225-1.972-4.52-4.167-1.444-2.443-3.112-5.191-6.487-5.1-3.272.113-4.879,2.606-6.3,4.808-1.5,2.328-2.552,3.746-4.551,3.662-2.156-.076-3.27-1.65-4.558-3.472-1.447-2.047-3.077-4.363-6.442-4.251-3.2.109-4.807,2.153-6.224,3.954-1.346,1.709-2.4,3.062-4.621,2.977a1.093,1.093,0,0,0-.079,2.186c3.3.11,4.967-1.967,6.417-3.81,1.286-1.635,2.4-3.045,4.582-3.12,2.1-.09,3.091,1.218,4.584,3.327,1.417,2,3.026,4.277,6.263,4.394,3.391.114,5.022-2.42,6.467-4.663,1.292-2,2.406-3.734,4.535-3.807,1.959-.073,3.026,1.475,4.529,4.022,1.417,2.4,3.023,5.121,6.324,5.241,3.415.118,5.064-2.863,6.5-5.5,1.245-2.282,2.419-4.437,4.5-4.509,1.959-.046,2.981,1.743,4.492,4.732,1.412,2.79,3.013,5.95,6.365,6.071l.185,0c3.348,0,4.937-3.36,6.343-6.331,1.245-2.634,2.423-5.114,4.444-5.216Z" transform="translate(7.109 -13.11)" fill-rule="evenodd"/>
<path id="Path_50" data-name="Path 50" d="M83,186.71h43.71V143H83Z" transform="translate(4.42 -5.561)" fill="#3ecc5f" fill-rule="evenodd"/>
<g id="Group_8" data-name="Group 8" transform="matrix(0.966, -0.259, 0.259, 0.966, 109.327, 91.085)">
<rect id="Rectangle_3" data-name="Rectangle 3" width="92.361" height="36.462" rx="2" transform="translate(0 0)" fill="#d8d8d8"/>
<g id="Group_2" data-name="Group 2" transform="translate(1.531 23.03)">
<rect id="Rectangle_4" data-name="Rectangle 4" width="5.336" height="5.336" rx="1" transform="translate(16.797 0)" fill="#4a4a4a"/>
<rect id="Rectangle_5" data-name="Rectangle 5" width="5.336" height="5.336" rx="1" transform="translate(23.12 0)" fill="#4a4a4a"/>
<rect id="Rectangle_6" data-name="Rectangle 6" width="5.336" height="5.336" rx="1" transform="translate(29.444 0)" fill="#4a4a4a"/>
<rect id="Rectangle_7" data-name="Rectangle 7" width="5.336" height="5.336" rx="1" transform="translate(35.768 0)" fill="#4a4a4a"/>
<rect id="Rectangle_8" data-name="Rectangle 8" width="5.336" height="5.336" rx="1" transform="translate(42.091 0)" fill="#4a4a4a"/>
<rect id="Rectangle_9" data-name="Rectangle 9" width="5.336" height="5.336" rx="1" transform="translate(48.415 0)" fill="#4a4a4a"/>
<rect id="Rectangle_10" data-name="Rectangle 10" width="5.336" height="5.336" rx="1" transform="translate(54.739 0)" fill="#4a4a4a"/>
<rect id="Rectangle_11" data-name="Rectangle 11" width="5.336" height="5.336" rx="1" transform="translate(61.063 0)" fill="#4a4a4a"/>
<rect id="Rectangle_12" data-name="Rectangle 12" width="5.336" height="5.336" rx="1" transform="translate(67.386 0)" fill="#4a4a4a"/>
<path id="Path_51" data-name="Path 51" d="M1.093,0H14.518a1.093,1.093,0,0,1,1.093,1.093V4.243a1.093,1.093,0,0,1-1.093,1.093H1.093A1.093,1.093,0,0,1,0,4.243V1.093A1.093,1.093,0,0,1,1.093,0ZM75,0H88.426a1.093,1.093,0,0,1,1.093,1.093V4.243a1.093,1.093,0,0,1-1.093,1.093H75a1.093,1.093,0,0,1-1.093-1.093V1.093A1.093,1.093,0,0,1,75,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
</g>
<g id="Group_3" data-name="Group 3" transform="translate(1.531 10.261)">
<path id="Path_52" data-name="Path 52" d="M1.093,0H6.218A1.093,1.093,0,0,1,7.31,1.093V4.242A1.093,1.093,0,0,1,6.218,5.335H1.093A1.093,1.093,0,0,1,0,4.242V1.093A1.093,1.093,0,0,1,1.093,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
<rect id="Rectangle_13" data-name="Rectangle 13" width="5.336" height="5.336" rx="1" transform="translate(8.299 0)" fill="#4a4a4a"/>
<rect id="Rectangle_14" data-name="Rectangle 14" width="5.336" height="5.336" rx="1" transform="translate(14.623 0)" fill="#4a4a4a"/>
<rect id="Rectangle_15" data-name="Rectangle 15" width="5.336" height="5.336" rx="1" transform="translate(20.947 0)" fill="#4a4a4a"/>
<rect id="Rectangle_16" data-name="Rectangle 16" width="5.336" height="5.336" rx="1" transform="translate(27.271 0)" fill="#4a4a4a"/>
<rect id="Rectangle_17" data-name="Rectangle 17" width="5.336" height="5.336" rx="1" transform="translate(33.594 0)" fill="#4a4a4a"/>
<rect id="Rectangle_18" data-name="Rectangle 18" width="5.336" height="5.336" rx="1" transform="translate(39.918 0)" fill="#4a4a4a"/>
<rect id="Rectangle_19" data-name="Rectangle 19" width="5.336" height="5.336" rx="1" transform="translate(46.242 0)" fill="#4a4a4a"/>
<rect id="Rectangle_20" data-name="Rectangle 20" width="5.336" height="5.336" rx="1" transform="translate(52.565 0)" fill="#4a4a4a"/>
<rect id="Rectangle_21" data-name="Rectangle 21" width="5.336" height="5.336" rx="1" transform="translate(58.888 0)" fill="#4a4a4a"/>
<rect id="Rectangle_22" data-name="Rectangle 22" width="5.336" height="5.336" rx="1" transform="translate(65.212 0)" fill="#4a4a4a"/>
<rect id="Rectangle_23" data-name="Rectangle 23" width="5.336" height="5.336" rx="1" transform="translate(71.536 0)" fill="#4a4a4a"/>
<rect id="Rectangle_24" data-name="Rectangle 24" width="5.336" height="5.336" rx="1" transform="translate(77.859 0)" fill="#4a4a4a"/>
<rect id="Rectangle_25" data-name="Rectangle 25" width="5.336" height="5.336" rx="1" transform="translate(84.183 0)" fill="#4a4a4a"/>
</g>
<g id="Group_4" data-name="Group 4" transform="translate(91.05 9.546) rotate(180)">
<path id="Path_53" data-name="Path 53" d="M1.093,0H6.219A1.093,1.093,0,0,1,7.312,1.093v3.15A1.093,1.093,0,0,1,6.219,5.336H1.093A1.093,1.093,0,0,1,0,4.243V1.093A1.093,1.093,0,0,1,1.093,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
<rect id="Rectangle_26" data-name="Rectangle 26" width="5.336" height="5.336" rx="1" transform="translate(8.299 0)" fill="#4a4a4a"/>
<rect id="Rectangle_27" data-name="Rectangle 27" width="5.336" height="5.336" rx="1" transform="translate(14.623 0)" fill="#4a4a4a"/>
<rect id="Rectangle_28" data-name="Rectangle 28" width="5.336" height="5.336" rx="1" transform="translate(20.947 0)" fill="#4a4a4a"/>
<rect id="Rectangle_29" data-name="Rectangle 29" width="5.336" height="5.336" rx="1" transform="translate(27.271 0)" fill="#4a4a4a"/>
<rect id="Rectangle_30" data-name="Rectangle 30" width="5.336" height="5.336" rx="1" transform="translate(33.594 0)" fill="#4a4a4a"/>
<rect id="Rectangle_31" data-name="Rectangle 31" width="5.336" height="5.336" rx="1" transform="translate(39.918 0)" fill="#4a4a4a"/>
<rect id="Rectangle_32" data-name="Rectangle 32" width="5.336" height="5.336" rx="1" transform="translate(46.242 0)" fill="#4a4a4a"/>
<rect id="Rectangle_33" data-name="Rectangle 33" width="5.336" height="5.336" rx="1" transform="translate(52.565 0)" fill="#4a4a4a"/>
<rect id="Rectangle_34" data-name="Rectangle 34" width="5.336" height="5.336" rx="1" transform="translate(58.889 0)" fill="#4a4a4a"/>
<rect id="Rectangle_35" data-name="Rectangle 35" width="5.336" height="5.336" rx="1" transform="translate(65.213 0)" fill="#4a4a4a"/>
<rect id="Rectangle_36" data-name="Rectangle 36" width="5.336" height="5.336" rx="1" transform="translate(71.537 0)" fill="#4a4a4a"/>
<rect id="Rectangle_37" data-name="Rectangle 37" width="5.336" height="5.336" rx="1" transform="translate(77.86 0)" fill="#4a4a4a"/>
<rect id="Rectangle_38" data-name="Rectangle 38" width="5.336" height="5.336" rx="1" transform="translate(84.183 0)" fill="#4a4a4a"/>
<rect id="Rectangle_39" data-name="Rectangle 39" width="5.336" height="5.336" rx="1" transform="translate(8.299 0)" fill="#4a4a4a"/>
<rect id="Rectangle_40" data-name="Rectangle 40" width="5.336" height="5.336" rx="1" transform="translate(14.623 0)" fill="#4a4a4a"/>
<rect id="Rectangle_41" data-name="Rectangle 41" width="5.336" height="5.336" rx="1" transform="translate(20.947 0)" fill="#4a4a4a"/>
<rect id="Rectangle_42" data-name="Rectangle 42" width="5.336" height="5.336" rx="1" transform="translate(27.271 0)" fill="#4a4a4a"/>
<rect id="Rectangle_43" data-name="Rectangle 43" width="5.336" height="5.336" rx="1" transform="translate(33.594 0)" fill="#4a4a4a"/>
<rect id="Rectangle_44" data-name="Rectangle 44" width="5.336" height="5.336" rx="1" transform="translate(39.918 0)" fill="#4a4a4a"/>
<rect id="Rectangle_45" data-name="Rectangle 45" width="5.336" height="5.336" rx="1" transform="translate(46.242 0)" fill="#4a4a4a"/>
<rect id="Rectangle_46" data-name="Rectangle 46" width="5.336" height="5.336" rx="1" transform="translate(52.565 0)" fill="#4a4a4a"/>
<rect id="Rectangle_47" data-name="Rectangle 47" width="5.336" height="5.336" rx="1" transform="translate(58.889 0)" fill="#4a4a4a"/>
<rect id="Rectangle_48" data-name="Rectangle 48" width="5.336" height="5.336" rx="1" transform="translate(65.213 0)" fill="#4a4a4a"/>
<rect id="Rectangle_49" data-name="Rectangle 49" width="5.336" height="5.336" rx="1" transform="translate(71.537 0)" fill="#4a4a4a"/>
<rect id="Rectangle_50" data-name="Rectangle 50" width="5.336" height="5.336" rx="1" transform="translate(77.86 0)" fill="#4a4a4a"/>
<rect id="Rectangle_51" data-name="Rectangle 51" width="5.336" height="5.336" rx="1" transform="translate(84.183 0)" fill="#4a4a4a"/>
</g>
<g id="Group_6" data-name="Group 6" transform="translate(1.531 16.584)">
<path id="Path_54" data-name="Path 54" d="M1.093,0h7.3A1.093,1.093,0,0,1,9.485,1.093v3.15A1.093,1.093,0,0,1,8.392,5.336h-7.3A1.093,1.093,0,0,1,0,4.243V1.094A1.093,1.093,0,0,1,1.093,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
<g id="Group_5" data-name="Group 5" transform="translate(10.671 0)">
<rect id="Rectangle_52" data-name="Rectangle 52" width="5.336" height="5.336" rx="1" fill="#4a4a4a"/>
<rect id="Rectangle_53" data-name="Rectangle 53" width="5.336" height="5.336" rx="1" transform="translate(6.324 0)" fill="#4a4a4a"/>
<rect id="Rectangle_54" data-name="Rectangle 54" width="5.336" height="5.336" rx="1" transform="translate(12.647 0)" fill="#4a4a4a"/>
<rect id="Rectangle_55" data-name="Rectangle 55" width="5.336" height="5.336" rx="1" transform="translate(18.971 0)" fill="#4a4a4a"/>
<rect id="Rectangle_56" data-name="Rectangle 56" width="5.336" height="5.336" rx="1" transform="translate(25.295 0)" fill="#4a4a4a"/>
<rect id="Rectangle_57" data-name="Rectangle 57" width="5.336" height="5.336" rx="1" transform="translate(31.619 0)" fill="#4a4a4a"/>
<rect id="Rectangle_58" data-name="Rectangle 58" width="5.336" height="5.336" rx="1" transform="translate(37.942 0)" fill="#4a4a4a"/>
<rect id="Rectangle_59" data-name="Rectangle 59" width="5.336" height="5.336" rx="1" transform="translate(44.265 0)" fill="#4a4a4a"/>
<rect id="Rectangle_60" data-name="Rectangle 60" width="5.336" height="5.336" rx="1" transform="translate(50.589 0)" fill="#4a4a4a"/>
<rect id="Rectangle_61" data-name="Rectangle 61" width="5.336" height="5.336" rx="1" transform="translate(56.912 0)" fill="#4a4a4a"/>
<rect id="Rectangle_62" data-name="Rectangle 62" width="5.336" height="5.336" rx="1" transform="translate(63.236 0)" fill="#4a4a4a"/>
</g>
<path id="Path_55" data-name="Path 55" d="M1.094,0H8A1.093,1.093,0,0,1,9.091,1.093v3.15A1.093,1.093,0,0,1,8,5.336H1.093A1.093,1.093,0,0,1,0,4.243V1.094A1.093,1.093,0,0,1,1.093,0Z" transform="translate(80.428 0)" fill="#4a4a4a" fill-rule="evenodd"/>
</g>
<g id="Group_7" data-name="Group 7" transform="translate(1.531 29.627)">
<rect id="Rectangle_63" data-name="Rectangle 63" width="5.336" height="5.336" rx="1" transform="translate(0 0)" fill="#4a4a4a"/>
<rect id="Rectangle_64" data-name="Rectangle 64" width="5.336" height="5.336" rx="1" transform="translate(6.324 0)" fill="#4a4a4a"/>
<rect id="Rectangle_65" data-name="Rectangle 65" width="5.336" height="5.336" rx="1" transform="translate(12.647 0)" fill="#4a4a4a"/>
<rect id="Rectangle_66" data-name="Rectangle 66" width="5.336" height="5.336" rx="1" transform="translate(18.971 0)" fill="#4a4a4a"/>
<path id="Path_56" data-name="Path 56" d="M1.093,0H31.515a1.093,1.093,0,0,1,1.093,1.093V4.244a1.093,1.093,0,0,1-1.093,1.093H1.093A1.093,1.093,0,0,1,0,4.244V1.093A1.093,1.093,0,0,1,1.093,0ZM34.687,0h3.942a1.093,1.093,0,0,1,1.093,1.093V4.244a1.093,1.093,0,0,1-1.093,1.093H34.687a1.093,1.093,0,0,1-1.093-1.093V1.093A1.093,1.093,0,0,1,34.687,0Z" transform="translate(25.294 0)" fill="#4a4a4a" fill-rule="evenodd"/>
<rect id="Rectangle_67" data-name="Rectangle 67" width="5.336" height="5.336" rx="1" transform="translate(66.003 0)" fill="#4a4a4a"/>
<rect id="Rectangle_68" data-name="Rectangle 68" width="5.336" height="5.336" rx="1" transform="translate(72.327 0)" fill="#4a4a4a"/>
<rect id="Rectangle_69" data-name="Rectangle 69" width="5.336" height="5.336" rx="1" transform="translate(84.183 0)" fill="#4a4a4a"/>
<path id="Path_57" data-name="Path 57" d="M5.336,0V1.18A1.093,1.093,0,0,1,4.243,2.273H1.093A1.093,1.093,0,0,1,0,1.18V0Z" transform="translate(83.59 2.273) rotate(180)" fill="#4a4a4a"/>
<path id="Path_58" data-name="Path 58" d="M5.336,0V1.18A1.093,1.093,0,0,1,4.243,2.273H1.093A1.093,1.093,0,0,1,0,1.18V0Z" transform="translate(78.255 3.063)" fill="#4a4a4a"/>
</g>
<rect id="Rectangle_70" data-name="Rectangle 70" width="88.927" height="2.371" rx="1.085" transform="translate(1.925 1.17)" fill="#4a4a4a"/>
<rect id="Rectangle_71" data-name="Rectangle 71" width="4.986" height="1.581" rx="0.723" transform="translate(4.1 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_72" data-name="Rectangle 72" width="4.986" height="1.581" rx="0.723" transform="translate(10.923 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_73" data-name="Rectangle 73" width="4.986" height="1.581" rx="0.723" transform="translate(16.173 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_74" data-name="Rectangle 74" width="4.986" height="1.581" rx="0.723" transform="translate(21.421 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_75" data-name="Rectangle 75" width="4.986" height="1.581" rx="0.723" transform="translate(26.671 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_76" data-name="Rectangle 76" width="4.986" height="1.581" rx="0.723" transform="translate(33.232 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_77" data-name="Rectangle 77" width="4.986" height="1.581" rx="0.723" transform="translate(38.48 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_78" data-name="Rectangle 78" width="4.986" height="1.581" rx="0.723" transform="translate(43.73 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_79" data-name="Rectangle 79" width="4.986" height="1.581" rx="0.723" transform="translate(48.978 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_80" data-name="Rectangle 80" width="4.986" height="1.581" rx="0.723" transform="translate(55.54 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_81" data-name="Rectangle 81" width="4.986" height="1.581" rx="0.723" transform="translate(60.788 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_82" data-name="Rectangle 82" width="4.986" height="1.581" rx="0.723" transform="translate(66.038 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_83" data-name="Rectangle 83" width="4.986" height="1.581" rx="0.723" transform="translate(72.599 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_84" data-name="Rectangle 84" width="4.986" height="1.581" rx="0.723" transform="translate(77.847 1.566)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_85" data-name="Rectangle 85" width="4.986" height="1.581" rx="0.723" transform="translate(83.097 1.566)" fill="#d8d8d8" opacity="0.136"/>
</g>
<path id="Path_59" data-name="Path 59" d="M146.71,159.855a5.439,5.439,0,0,0-.7.07c-.042-.164-.081-.329-.127-.493a5.457,5.457,0,1,0-5.4-9.372q-.181-.185-.366-.367a5.454,5.454,0,1,0-9.384-5.4c-.162-.046-.325-.084-.486-.126a5.467,5.467,0,1,0-10.788,0c-.162.042-.325.08-.486.126a5.457,5.457,0,1,0-9.384,5.4,21.843,21.843,0,1,0,36.421,21.02,5.452,5.452,0,1,0,.7-10.858" transform="translate(6.275 -6.025)" fill="#44d860" fill-rule="evenodd"/>
<path id="Path_60" data-name="Path 60" d="M83,124.855h43.71V103H83Z" transform="translate(4.42 -9.271)" fill="#3ecc5f" fill-rule="evenodd"/>
<path id="Path_61" data-name="Path 61" d="M134.855,116.765a2.732,2.732,0,1,0,0-5.464,2.811,2.811,0,0,0-.349.035c-.022-.082-.04-.164-.063-.246a2.733,2.733,0,0,0-1.052-5.253,2.7,2.7,0,0,0-1.648.566q-.09-.093-.184-.184a2.7,2.7,0,0,0,.553-1.633,2.732,2.732,0,0,0-5.245-1.07,10.928,10.928,0,1,0,0,21.031,2.732,2.732,0,0,0,5.245-1.07,2.7,2.7,0,0,0-.553-1.633q.093-.09.184-.184a2.7,2.7,0,0,0,1.648.566,2.732,2.732,0,0,0,1.052-5.253c.023-.081.042-.164.063-.246a2.811,2.811,0,0,0,.349.035" transform="translate(7.202 -9.377)" fill="#44d860" fill-rule="evenodd"/>
<path id="Path_62" data-name="Path 62" d="M143.232,42.33a2.967,2.967,0,0,1-.535-.055,2.754,2.754,0,0,1-.514-.153,2.838,2.838,0,0,1-.471-.251,4.139,4.139,0,0,1-.415-.339,3.2,3.2,0,0,1-.338-.415A2.7,2.7,0,0,1,140.5,39.6a2.968,2.968,0,0,1,.055-.535,3.152,3.152,0,0,1,.152-.514,2.874,2.874,0,0,1,.252-.47,2.633,2.633,0,0,1,.753-.754,2.837,2.837,0,0,1,.471-.251,2.753,2.753,0,0,1,.514-.153,2.527,2.527,0,0,1,1.071,0,2.654,2.654,0,0,1,.983.4,4.139,4.139,0,0,1,.415.339,4.019,4.019,0,0,1,.339.415,2.786,2.786,0,0,1,.251.47,2.864,2.864,0,0,1,.208,1.049,2.77,2.77,0,0,1-.8,1.934,4.139,4.139,0,0,1-.415.339,2.722,2.722,0,0,1-1.519.459m21.855-1.366a2.789,2.789,0,0,1-1.935-.8,4.162,4.162,0,0,1-.338-.415,2.7,2.7,0,0,1-.459-1.519,2.789,2.789,0,0,1,.8-1.934,4.139,4.139,0,0,1,.415-.339,2.838,2.838,0,0,1,.471-.251,2.752,2.752,0,0,1,.514-.153,2.527,2.527,0,0,1,1.071,0,2.654,2.654,0,0,1,.983.4,4.139,4.139,0,0,1,.415.339,2.79,2.79,0,0,1,.8,1.934,3.069,3.069,0,0,1-.055.535,2.779,2.779,0,0,1-.153.514,3.885,3.885,0,0,1-.251.47,4.02,4.02,0,0,1-.339.415,4.138,4.138,0,0,1-.415.339,2.722,2.722,0,0,1-1.519.459" transform="translate(9.753 -15.532)" fill-rule="evenodd"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 31 KiB

@@ -0,0 +1,170 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1041.277" height="554.141" viewBox="0 0 1041.277 554.141">
<title>Powered by React</title>
<g id="Group_24" data-name="Group 24" transform="translate(-440 -263)">
<g id="Group_23" data-name="Group 23" transform="translate(439.989 262.965)">
<path id="Path_299" data-name="Path 299" d="M1040.82,611.12q-1.74,3.75-3.47,7.4-2.7,5.67-5.33,11.12c-.78,1.61-1.56,3.19-2.32,4.77-8.6,17.57-16.63,33.11-23.45,45.89A73.21,73.21,0,0,1,942.44,719l-151.65,1.65h-1.6l-13,.14-11.12.12-34.1.37h-1.38l-17.36.19h-.53l-107,1.16-95.51,1-11.11.12-69,.75H429l-44.75.48h-.48l-141.5,1.53-42.33.46a87.991,87.991,0,0,1-10.79-.54h0c-1.22-.14-2.44-.3-3.65-.49a87.38,87.38,0,0,1-51.29-27.54C116,678.37,102.75,655,93.85,629.64q-1.93-5.49-3.6-11.12C59.44,514.37,97,380,164.6,290.08q4.25-5.64,8.64-11l.07-.08c20.79-25.52,44.1-46.84,68.93-62,44-26.91,92.75-34.49,140.7-11.9,40.57,19.12,78.45,28.11,115.17,30.55,3.71.24,7.42.42,11.11.53,84.23,2.65,163.17-27.7,255.87-47.29,3.69-.78,7.39-1.55,11.12-2.28,66.13-13.16,139.49-20.1,226.73-5.51a189.089,189.089,0,0,1,26.76,6.4q5.77,1.86,11.12,4c41.64,16.94,64.35,48.24,74,87.46q1.37,5.46,2.37,11.11C1134.3,384.41,1084.19,518.23,1040.82,611.12Z" transform="translate(-79.34 -172.91)" fill="#f2f2f2"/>
<path id="Path_300" data-name="Path 300" d="M576.36,618.52a95.21,95.21,0,0,1-1.87,11.12h93.7V618.52Zm-78.25,62.81,11.11-.09V653.77c-3.81-.17-7.52-.34-11.11-.52ZM265.19,618.52v11.12h198.5V618.52ZM1114.87,279h-74V191.51q-5.35-2.17-11.12-4V279H776.21V186.58c-3.73.73-7.43,1.5-11.12,2.28V279H509.22V236.15c-3.69-.11-7.4-.29-11.11-.53V279H242.24V217c-24.83,15.16-48.14,36.48-68.93,62h-.07v.08q-4.4,5.4-8.64,11h8.64V618.52h-83q1.66,5.63,3.6,11.12h79.39v93.62a87,87,0,0,0,12.2,2.79c1.21.19,2.43.35,3.65.49h0a87.991,87.991,0,0,0,10.79.54l42.33-.46v-97H498.11v94.21l11.11-.12V629.64H765.09V721l11.12-.12V629.64H1029.7v4.77c.76-1.58,1.54-3.16,2.32-4.77q2.63-5.45,5.33-11.12,1.73-3.64,3.47-7.4v-321h76.42Q1116.23,284.43,1114.87,279ZM242.24,618.52V290.08H498.11V618.52Zm267,0V290.08H765.09V618.52Zm520.48,0H776.21V290.08H1029.7Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
<path id="Path_301" data-name="Path 301" d="M863.09,533.65v13l-151.92,1.4-1.62.03-57.74.53-1.38.02-17.55.15h-.52l-106.98.99L349.77,551.4h-.15l-44.65.42-.48.01-198.4,1.82v-15l46.65-28,93.6-.78,2-.01.66-.01,2-.03,44.94-.37,2.01-.01.64-.01,2-.01L315,509.3l.38-.01,35.55-.3h.29l277.4-2.34,6.79-.05h.68l5.18-.05,37.65-.31,2-.03,1.85-.02h.96l11.71-.09,2.32-.03,3.11-.02,9.75-.09,15.47-.13,2-.02,3.48-.02h.65l74.71-.64Z" fill="#65617d"/>
<path id="Path_302" data-name="Path 302" d="M863.09,533.65v13l-151.92,1.4-1.62.03-57.74.53-1.38.02-17.55.15h-.52l-106.98.99L349.77,551.4h-.15l-44.65.42-.48.01-198.4,1.82v-15l46.65-28,93.6-.78,2-.01.66-.01,2-.03,44.94-.37,2.01-.01.64-.01,2-.01L315,509.3l.38-.01,35.55-.3h.29l277.4-2.34,6.79-.05h.68l5.18-.05,37.65-.31,2-.03,1.85-.02h.96l11.71-.09,2.32-.03,3.11-.02,9.75-.09,15.47-.13,2-.02,3.48-.02h.65l74.71-.64Z" opacity="0.2"/>
<path id="Path_303" data-name="Path 303" d="M375.44,656.57v24.49a6.13,6.13,0,0,1-3.5,5.54,6,6,0,0,1-2.5.6l-34.9.74a6,6,0,0,1-2.7-.57,6.12,6.12,0,0,1-3.57-5.57V656.57Z" transform="translate(-79.34 -172.91)" fill="#3f3d56"/>
<path id="Path_304" data-name="Path 304" d="M375.44,656.57v24.49a6.13,6.13,0,0,1-3.5,5.54,6,6,0,0,1-2.5.6l-34.9.74a6,6,0,0,1-2.7-.57,6.12,6.12,0,0,1-3.57-5.57V656.57Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
<path id="Path_305" data-name="Path 305" d="M377.44,656.57v24.49a6.13,6.13,0,0,1-3.5,5.54,6,6,0,0,1-2.5.6l-34.9.74a6,6,0,0,1-2.7-.57,6.12,6.12,0,0,1-3.57-5.57V656.57Z" transform="translate(-79.34 -172.91)" fill="#3f3d56"/>
<rect id="Rectangle_137" data-name="Rectangle 137" width="47.17" height="31.5" transform="translate(680.92 483.65)" fill="#3f3d56"/>
<rect id="Rectangle_138" data-name="Rectangle 138" width="47.17" height="31.5" transform="translate(680.92 483.65)" opacity="0.1"/>
<rect id="Rectangle_139" data-name="Rectangle 139" width="47.17" height="31.5" transform="translate(678.92 483.65)" fill="#3f3d56"/>
<path id="Path_306" data-name="Path 306" d="M298.09,483.65v4.97l-47.17,1.26v-6.23Z" opacity="0.1"/>
<path id="Path_307" data-name="Path 307" d="M460.69,485.27v168.2a4,4,0,0,1-3.85,3.95l-191.65,5.1h-.05a4,4,0,0,1-3.95-3.95V485.27a4,4,0,0,1,3.95-3.95h191.6a4,4,0,0,1,3.95,3.95Z" transform="translate(-79.34 -172.91)" fill="#65617d"/>
<path id="Path_308" data-name="Path 308" d="M265.19,481.32v181.2h-.05a4,4,0,0,1-3.95-3.95V485.27a4,4,0,0,1,3.95-3.95Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
<path id="Path_309" data-name="Path 309" d="M194.59,319.15h177.5V467.4l-177.5,4Z" fill="#39374d"/>
<path id="Path_310" data-name="Path 310" d="M726.09,483.65v6.41l-47.17-1.26v-5.15Z" opacity="0.1"/>
<path id="Path_311" data-name="Path 311" d="M867.69,485.27v173.3a4,4,0,0,1-4,3.95h0L672,657.42a4,4,0,0,1-3.85-3.95V485.27a4,4,0,0,1,3.95-3.95H863.7a4,4,0,0,1,3.99,3.95Z" transform="translate(-79.34 -172.91)" fill="#65617d"/>
<path id="Path_312" data-name="Path 312" d="M867.69,485.27v173.3a4,4,0,0,1-4,3.95h0V481.32h0a4,4,0,0,1,4,3.95Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
<path id="Path_313" data-name="Path 313" d="M775.59,319.15H598.09V467.4l177.5,4Z" fill="#39374d"/>
<path id="Path_314" data-name="Path 314" d="M663.19,485.27v168.2a4,4,0,0,1-3.85,3.95l-191.65,5.1h0a4,4,0,0,1-4-3.95V485.27a4,4,0,0,1,3.95-3.95h191.6A4,4,0,0,1,663.19,485.27Z" transform="translate(-79.34 -172.91)" fill="#65617d"/>
<path id="Path_315" data-name="Path 315" d="M397.09,319.15h177.5V467.4l-177.5,4Z" fill="#4267b2"/>
<path id="Path_316" data-name="Path 316" d="M863.09,533.65v13l-151.92,1.4-1.62.03-57.74.53-1.38.02-17.55.15h-.52l-106.98.99L349.77,551.4h-.15l-44.65.42-.48.01-198.4,1.82v-15l202.51-1.33h.48l40.99-.28h.19l283.08-1.87h.29l.17-.01h.47l4.79-.03h1.46l74.49-.5,4.4-.02.98-.01Z" opacity="0.1"/>
<circle id="Ellipse_111" data-name="Ellipse 111" cx="51.33" cy="51.33" r="51.33" transform="translate(435.93 246.82)" fill="#fbbebe"/>
<path id="Path_317" data-name="Path 317" d="M617.94,550.07s-99.5,12-90,0c3.44-4.34,4.39-17.2,4.2-31.85-.06-4.45-.22-9.06-.45-13.65-1.1-22-3.75-43.5-3.75-43.5s87-41,77-8.5c-4,13.13-2.69,31.57.35,48.88.89,5.05,1.92,10,3,14.7a344.66,344.66,0,0,0,9.65,33.92Z" transform="translate(-79.34 -172.91)" fill="#fbbebe"/>
<path id="Path_318" data-name="Path 318" d="M585.47,546c11.51-2.13,23.7-6,34.53-1.54,2.85,1.17,5.47,2.88,8.39,3.86s6.12,1.22,9.16,1.91c10.68,2.42,19.34,10.55,24.9,20s8.44,20.14,11.26,30.72l6.9,25.83c6,22.45,12,45.09,13.39,68.3a2437.506,2437.506,0,0,1-250.84,1.43c5.44-10.34,11-21.31,10.54-33s-7.19-23.22-4.76-34.74c1.55-7.34,6.57-13.39,9.64-20.22,8.75-19.52,1.94-45.79,17.32-60.65,6.92-6.68,17-9.21,26.63-8.89,12.28.41,24.85,4.24,37,6.11C555.09,547.48,569.79,548.88,585.47,546Z" transform="translate(-79.34 -172.91)" fill="#ff6584"/>
<path id="Path_319" data-name="Path 319" d="M716.37,657.17l-.1,1.43v.1l-.17,2.3-1.33,18.51-1.61,22.3-.46,6.28-1,13.44v.17l-107,1-175.59,1.9v.84h-.14v-1.12l.45-14.36.86-28.06.74-23.79.07-2.37a10.53,10.53,0,0,1,11.42-10.17c4.72.4,10.85.89,18.18,1.41l3,.22c42.33,2.94,120.56,6.74,199.5,2,1.66-.09,3.33-.19,5-.31,12.24-.77,24.47-1.76,36.58-3a10.53,10.53,0,0,1,11.6,11.23Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
<path id="Path_320" data-name="Path 320" d="M429.08,725.44v-.84l175.62-1.91,107-1h.3v-.17l1-13.44.43-6,1.64-22.61,1.29-17.9v-.44a10.617,10.617,0,0,0-.11-2.47.3.3,0,0,0,0-.1,10.391,10.391,0,0,0-2-4.64,10.54,10.54,0,0,0-9.42-4c-12.11,1.24-24.34,2.23-36.58,3-1.67.12-3.34.22-5,.31-78.94,4.69-157.17.89-199.5-2l-3-.22c-7.33-.52-13.46-1-18.18-1.41a10.54,10.54,0,0,0-11.24,8.53,11,11,0,0,0-.18,1.64l-.68,22.16L429.54,710l-.44,14.36v1.12Z" transform="translate(-79.34 -172.91)" fill="#3f3d56"/>
<path id="Path_321" data-name="Path 321" d="M716.67,664.18l-1.23,15.33-1.83,22.85-.46,5.72-1,12.81-.06.64v.17h0l-.15,1.48.11-1.48h-.29l-107,1-175.65,1.9v-.28l.49-14.36,1-28.06.64-18.65A6.36,6.36,0,0,1,434.3,658a6.25,6.25,0,0,1,3.78-.9c2.1.17,4.68.37,7.69.59,4.89.36,10.92.78,17.94,1.22,13,.82,29.31,1.7,48,2.42,52,2,122.2,2.67,188.88-3.17,3-.26,6.1-.55,9.13-.84a6.26,6.26,0,0,1,3.48.66,5.159,5.159,0,0,1,.86.54,6.14,6.14,0,0,1,2,2.46,3.564,3.564,0,0,1,.25.61A6.279,6.279,0,0,1,716.67,664.18Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
<path id="Path_322" data-name="Path 322" d="M377.44,677.87v3.19a6.13,6.13,0,0,1-3.5,5.54l-40.1.77a6.12,6.12,0,0,1-3.57-5.57v-3Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
<path id="Path_323" data-name="Path 323" d="M298.59,515.57l-52.25,1V507.9l52.25-1Z" fill="#3f3d56"/>
<path id="Path_324" data-name="Path 324" d="M298.59,515.57l-52.25,1V507.9l52.25-1Z" opacity="0.1"/>
<path id="Path_325" data-name="Path 325" d="M300.59,515.57l-52.25,1V507.9l52.25-1Z" fill="#3f3d56"/>
<path id="Path_326" data-name="Path 326" d="M758.56,679.87v3.19a6.13,6.13,0,0,0,3.5,5.54l40.1.77a6.12,6.12,0,0,0,3.57-5.57v-3Z" transform="translate(-79.34 -172.91)" opacity="0.1"/>
<path id="Path_327" data-name="Path 327" d="M678.72,517.57l52.25,1V509.9l-52.25-1Z" opacity="0.1"/>
<path id="Path_328" data-name="Path 328" d="M676.72,517.57l52.25,1V509.9l-52.25-1Z" fill="#3f3d56"/>
<path id="Path_329" data-name="Path 329" d="M534.13,486.79c.08,7-3.16,13.6-5.91,20.07a163.491,163.491,0,0,0-12.66,74.71c.73,11,2.58,22,.73,32.9s-8.43,21.77-19,24.9c17.53,10.45,41.26,9.35,57.76-2.66,8.79-6.4,15.34-15.33,21.75-24.11a97.86,97.86,0,0,1-13.31,44.75A103.43,103.43,0,0,0,637,616.53c4.31-5.81,8.06-12.19,9.72-19.23,3.09-13-1.22-26.51-4.51-39.5a266.055,266.055,0,0,1-6.17-33c-.43-3.56-.78-7.22.1-10.7,1-4.07,3.67-7.51,5.64-11.22,5.6-10.54,5.73-23.3,2.86-34.88s-8.49-22.26-14.06-32.81c-4.46-8.46-9.3-17.31-17.46-22.28-5.1-3.1-11-4.39-16.88-5.64l-25.37-5.43c-5.55-1.19-11.26-2.38-16.87-1.51-9.47,1.48-16.14,8.32-22,15.34-4.59,5.46-15.81,15.71-16.6,22.86-.72,6.59,5.1,17.63,6.09,24.58,1.3,9,2.22,6,7.3,11.52C532,478.05,534.07,482,534.13,486.79Z" transform="translate(-79.34 -172.91)" fill="#3f3d56"/>
</g>
<g id="docusaurus_keytar" transform="translate(670.271 615.768)">
<path id="Path_40" data-name="Path 40" d="M99,52h43.635V69.662H99Z" transform="translate(-49.132 -33.936)" fill="#fff" fill-rule="evenodd"/>
<path id="Path_41" data-name="Path 41" d="M13.389,158.195A10.377,10.377,0,0,1,4.4,153a10.377,10.377,0,0,0,8.988,15.584H23.779V158.195Z" transform="translate(-3 -82.47)" fill="#3ecc5f" fill-rule="evenodd"/>
<path id="Path_42" data-name="Path 42" d="M66.967,38.083l36.373-2.273V30.615A10.389,10.389,0,0,0,92.95,20.226H46.2l-1.3-2.249a1.5,1.5,0,0,0-2.6,0L41,20.226l-1.3-2.249a1.5,1.5,0,0,0-2.6,0l-1.3,2.249-1.3-2.249a1.5,1.5,0,0,0-2.6,0l-1.3,2.249-.034,0-2.152-2.151a1.5,1.5,0,0,0-2.508.672L25.21,21.4l-2.7-.723a1.5,1.5,0,0,0-1.836,1.837l.722,2.7-2.65.71a1.5,1.5,0,0,0-.673,2.509l2.152,2.152c0,.011,0,.022,0,.033l-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6L20.226,41l-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3-2.249,1.3a1.5,1.5,0,0,0,0,2.6l2.249,1.3A10.389,10.389,0,0,0,30.615,103.34H92.95A10.389,10.389,0,0,0,103.34,92.95V51.393L66.967,49.12a5.53,5.53,0,0,1,0-11.038" transform="translate(-9.836 -17.226)" fill="#3ecc5f" fill-rule="evenodd"/>
<path id="Path_43" data-name="Path 43" d="M143,163.779h15.584V143H143Z" transform="translate(-70.275 -77.665)" fill="#3ecc5f" fill-rule="evenodd"/>
<path id="Path_44" data-name="Path 44" d="M173.779,148.389a2.582,2.582,0,0,0-.332.033c-.02-.078-.038-.156-.06-.234a2.594,2.594,0,1,0-2.567-4.455q-.086-.088-.174-.175a2.593,2.593,0,1,0-4.461-2.569c-.077-.022-.154-.04-.231-.06a2.6,2.6,0,1,0-5.128,0c-.077.02-.154.038-.231.06a2.594,2.594,0,1,0-4.461,2.569,10.384,10.384,0,1,0,17.314,9.992,2.592,2.592,0,1,0,.332-5.161" transform="translate(-75.08 -75.262)" fill="#44d860" fill-rule="evenodd"/>
<path id="Path_45" data-name="Path 45" d="M153,113.389h15.584V103H153Z" transform="translate(-75.08 -58.444)" fill="#3ecc5f" fill-rule="evenodd"/>
<path id="Path_46" data-name="Path 46" d="M183.389,108.944a1.3,1.3,0,1,0,0-2.6,1.336,1.336,0,0,0-.166.017c-.01-.039-.019-.078-.03-.117a1.3,1.3,0,0,0-.5-2.5,1.285,1.285,0,0,0-.783.269q-.043-.044-.087-.087a1.285,1.285,0,0,0,.263-.776,1.3,1.3,0,0,0-2.493-.509,5.195,5.195,0,1,0,0,10,1.3,1.3,0,0,0,2.493-.509,1.285,1.285,0,0,0-.263-.776q.044-.043.087-.087a1.285,1.285,0,0,0,.783.269,1.3,1.3,0,0,0,.5-2.5c.011-.038.02-.078.03-.117a1.337,1.337,0,0,0,.166.017" transform="translate(-84.691 -57.894)" fill="#44d860" fill-rule="evenodd"/>
<path id="Path_47" data-name="Path 47" d="M52.188,48.292a1.3,1.3,0,0,1-1.3-1.3,3.9,3.9,0,0,0-7.792,0,1.3,1.3,0,1,1-2.6,0,6.493,6.493,0,0,1,12.987,0,1.3,1.3,0,0,1-1.3,1.3" transform="translate(-21.02 -28.41)" fill-rule="evenodd"/>
<path id="Path_48" data-name="Path 48" d="M103,139.752h31.168a10.389,10.389,0,0,0,10.389-10.389V93H113.389A10.389,10.389,0,0,0,103,103.389Z" transform="translate(-51.054 -53.638)" fill="#ffff50" fill-rule="evenodd"/>
<path id="Path_49" data-name="Path 49" d="M141.1,94.017H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0,10.389H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0,10.389H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0-25.877H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0,10.293H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m0,10.389H115.106a.519.519,0,1,1,0-1.039H141.1a.519.519,0,0,1,0,1.039m7.782-47.993c-.006,0-.011,0-.018,0-1.605.055-2.365,1.66-3.035,3.077-.7,1.48-1.24,2.443-2.126,2.414-.981-.035-1.542-1.144-2.137-2.317-.683-1.347-1.462-2.876-3.1-2.819-1.582.054-2.344,1.451-3.017,2.684-.715,1.313-1.2,2.112-2.141,2.075-1-.036-1.533-.938-2.149-1.981-.686-1.162-1.479-2.467-3.084-2.423-1.555.053-2.319,1.239-2.994,2.286-.713,1.106-1.213,1.781-2.164,1.741-1.025-.036-1.554-.784-2.167-1.65-.688-.973-1.463-2.074-3.062-2.021a3.815,3.815,0,0,0-2.959,1.879c-.64.812-1.14,1.456-2.2,1.415a.52.52,0,0,0-.037,1.039,3.588,3.588,0,0,0,3.05-1.811c.611-.777,1.139-1.448,2.178-1.483,1-.043,1.47.579,2.179,1.582.674.953,1.438,2.033,2.977,2.089,1.612.054,2.387-1.151,3.074-2.217.614-.953,1.144-1.775,2.156-1.81.931-.035,1.438.7,2.153,1.912.674,1.141,1.437,2.434,3.006,2.491,1.623.056,2.407-1.361,3.09-2.616.592-1.085,1.15-2.109,2.14-2.143.931-.022,1.417.829,2.135,2.249.671,1.326,1.432,2.828,3.026,2.886l.088,0c1.592,0,2.347-1.6,3.015-3.01.592-1.252,1.152-2.431,2.113-2.479Z" transform="translate(-55.378 -38.552)" fill-rule="evenodd"/>
<path id="Path_50" data-name="Path 50" d="M83,163.779h20.779V143H83Z" transform="translate(-41.443 -77.665)" fill="#3ecc5f" fill-rule="evenodd"/>
<g id="Group_8" data-name="Group 8" transform="matrix(0.966, -0.259, 0.259, 0.966, 51.971, 43.3)">
<rect id="Rectangle_3" data-name="Rectangle 3" width="43.906" height="17.333" rx="2" transform="translate(0 0)" fill="#d8d8d8"/>
<g id="Group_2" data-name="Group 2" transform="translate(0.728 10.948)">
<rect id="Rectangle_4" data-name="Rectangle 4" width="2.537" height="2.537" rx="1" transform="translate(7.985 0)" fill="#4a4a4a"/>
<rect id="Rectangle_5" data-name="Rectangle 5" width="2.537" height="2.537" rx="1" transform="translate(10.991 0)" fill="#4a4a4a"/>
<rect id="Rectangle_6" data-name="Rectangle 6" width="2.537" height="2.537" rx="1" transform="translate(13.997 0)" fill="#4a4a4a"/>
<rect id="Rectangle_7" data-name="Rectangle 7" width="2.537" height="2.537" rx="1" transform="translate(17.003 0)" fill="#4a4a4a"/>
<rect id="Rectangle_8" data-name="Rectangle 8" width="2.537" height="2.537" rx="1" transform="translate(20.009 0)" fill="#4a4a4a"/>
<rect id="Rectangle_9" data-name="Rectangle 9" width="2.537" height="2.537" rx="1" transform="translate(23.015 0)" fill="#4a4a4a"/>
<rect id="Rectangle_10" data-name="Rectangle 10" width="2.537" height="2.537" rx="1" transform="translate(26.021 0)" fill="#4a4a4a"/>
<rect id="Rectangle_11" data-name="Rectangle 11" width="2.537" height="2.537" rx="1" transform="translate(29.028 0)" fill="#4a4a4a"/>
<rect id="Rectangle_12" data-name="Rectangle 12" width="2.537" height="2.537" rx="1" transform="translate(32.034 0)" fill="#4a4a4a"/>
<path id="Path_51" data-name="Path 51" d="M.519,0H6.9A.519.519,0,0,1,7.421.52v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.519A.519.519,0,0,1,.519,0ZM35.653,0h6.383a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H35.652a.519.519,0,0,1-.519-.519V.519A.519.519,0,0,1,35.652,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
</g>
<g id="Group_3" data-name="Group 3" transform="translate(0.728 4.878)">
<path id="Path_52" data-name="Path 52" d="M.519,0H2.956a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.519A.519.519,0,0,1,.519,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
<rect id="Rectangle_13" data-name="Rectangle 13" width="2.537" height="2.537" rx="1" transform="translate(3.945 0)" fill="#4a4a4a"/>
<rect id="Rectangle_14" data-name="Rectangle 14" width="2.537" height="2.537" rx="1" transform="translate(6.951 0)" fill="#4a4a4a"/>
<rect id="Rectangle_15" data-name="Rectangle 15" width="2.537" height="2.537" rx="1" transform="translate(9.958 0)" fill="#4a4a4a"/>
<rect id="Rectangle_16" data-name="Rectangle 16" width="2.537" height="2.537" rx="1" transform="translate(12.964 0)" fill="#4a4a4a"/>
<rect id="Rectangle_17" data-name="Rectangle 17" width="2.537" height="2.537" rx="1" transform="translate(15.97 0)" fill="#4a4a4a"/>
<rect id="Rectangle_18" data-name="Rectangle 18" width="2.537" height="2.537" rx="1" transform="translate(18.976 0)" fill="#4a4a4a"/>
<rect id="Rectangle_19" data-name="Rectangle 19" width="2.537" height="2.537" rx="1" transform="translate(21.982 0)" fill="#4a4a4a"/>
<rect id="Rectangle_20" data-name="Rectangle 20" width="2.537" height="2.537" rx="1" transform="translate(24.988 0)" fill="#4a4a4a"/>
<rect id="Rectangle_21" data-name="Rectangle 21" width="2.537" height="2.537" rx="1" transform="translate(27.994 0)" fill="#4a4a4a"/>
<rect id="Rectangle_22" data-name="Rectangle 22" width="2.537" height="2.537" rx="1" transform="translate(31 0)" fill="#4a4a4a"/>
<rect id="Rectangle_23" data-name="Rectangle 23" width="2.537" height="2.537" rx="1" transform="translate(34.006 0)" fill="#4a4a4a"/>
<rect id="Rectangle_24" data-name="Rectangle 24" width="2.537" height="2.537" rx="1" transform="translate(37.012 0)" fill="#4a4a4a"/>
<rect id="Rectangle_25" data-name="Rectangle 25" width="2.537" height="2.537" rx="1" transform="translate(40.018 0)" fill="#4a4a4a"/>
</g>
<g id="Group_4" data-name="Group 4" transform="translate(43.283 4.538) rotate(180)">
<path id="Path_53" data-name="Path 53" d="M.519,0H2.956a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.519A.519.519,0,0,1,.519,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
<rect id="Rectangle_26" data-name="Rectangle 26" width="2.537" height="2.537" rx="1" transform="translate(3.945 0)" fill="#4a4a4a"/>
<rect id="Rectangle_27" data-name="Rectangle 27" width="2.537" height="2.537" rx="1" transform="translate(6.951 0)" fill="#4a4a4a"/>
<rect id="Rectangle_28" data-name="Rectangle 28" width="2.537" height="2.537" rx="1" transform="translate(9.958 0)" fill="#4a4a4a"/>
<rect id="Rectangle_29" data-name="Rectangle 29" width="2.537" height="2.537" rx="1" transform="translate(12.964 0)" fill="#4a4a4a"/>
<rect id="Rectangle_30" data-name="Rectangle 30" width="2.537" height="2.537" rx="1" transform="translate(15.97 0)" fill="#4a4a4a"/>
<rect id="Rectangle_31" data-name="Rectangle 31" width="2.537" height="2.537" rx="1" transform="translate(18.976 0)" fill="#4a4a4a"/>
<rect id="Rectangle_32" data-name="Rectangle 32" width="2.537" height="2.537" rx="1" transform="translate(21.982 0)" fill="#4a4a4a"/>
<rect id="Rectangle_33" data-name="Rectangle 33" width="2.537" height="2.537" rx="1" transform="translate(24.988 0)" fill="#4a4a4a"/>
<rect id="Rectangle_34" data-name="Rectangle 34" width="2.537" height="2.537" rx="1" transform="translate(27.994 0)" fill="#4a4a4a"/>
<rect id="Rectangle_35" data-name="Rectangle 35" width="2.537" height="2.537" rx="1" transform="translate(31.001 0)" fill="#4a4a4a"/>
<rect id="Rectangle_36" data-name="Rectangle 36" width="2.537" height="2.537" rx="1" transform="translate(34.007 0)" fill="#4a4a4a"/>
<rect id="Rectangle_37" data-name="Rectangle 37" width="2.537" height="2.537" rx="1" transform="translate(37.013 0)" fill="#4a4a4a"/>
<rect id="Rectangle_38" data-name="Rectangle 38" width="2.537" height="2.537" rx="1" transform="translate(40.018 0)" fill="#4a4a4a"/>
<rect id="Rectangle_39" data-name="Rectangle 39" width="2.537" height="2.537" rx="1" transform="translate(3.945 0)" fill="#4a4a4a"/>
<rect id="Rectangle_40" data-name="Rectangle 40" width="2.537" height="2.537" rx="1" transform="translate(6.951 0)" fill="#4a4a4a"/>
<rect id="Rectangle_41" data-name="Rectangle 41" width="2.537" height="2.537" rx="1" transform="translate(9.958 0)" fill="#4a4a4a"/>
<rect id="Rectangle_42" data-name="Rectangle 42" width="2.537" height="2.537" rx="1" transform="translate(12.964 0)" fill="#4a4a4a"/>
<rect id="Rectangle_43" data-name="Rectangle 43" width="2.537" height="2.537" rx="1" transform="translate(15.97 0)" fill="#4a4a4a"/>
<rect id="Rectangle_44" data-name="Rectangle 44" width="2.537" height="2.537" rx="1" transform="translate(18.976 0)" fill="#4a4a4a"/>
<rect id="Rectangle_45" data-name="Rectangle 45" width="2.537" height="2.537" rx="1" transform="translate(21.982 0)" fill="#4a4a4a"/>
<rect id="Rectangle_46" data-name="Rectangle 46" width="2.537" height="2.537" rx="1" transform="translate(24.988 0)" fill="#4a4a4a"/>
<rect id="Rectangle_47" data-name="Rectangle 47" width="2.537" height="2.537" rx="1" transform="translate(27.994 0)" fill="#4a4a4a"/>
<rect id="Rectangle_48" data-name="Rectangle 48" width="2.537" height="2.537" rx="1" transform="translate(31.001 0)" fill="#4a4a4a"/>
<rect id="Rectangle_49" data-name="Rectangle 49" width="2.537" height="2.537" rx="1" transform="translate(34.007 0)" fill="#4a4a4a"/>
<rect id="Rectangle_50" data-name="Rectangle 50" width="2.537" height="2.537" rx="1" transform="translate(37.013 0)" fill="#4a4a4a"/>
<rect id="Rectangle_51" data-name="Rectangle 51" width="2.537" height="2.537" rx="1" transform="translate(40.018 0)" fill="#4a4a4a"/>
</g>
<g id="Group_6" data-name="Group 6" transform="translate(0.728 7.883)">
<path id="Path_54" data-name="Path 54" d="M.519,0h3.47a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.52A.519.519,0,0,1,.519,0Z" transform="translate(0 0)" fill="#4a4a4a" fill-rule="evenodd"/>
<g id="Group_5" data-name="Group 5" transform="translate(5.073 0)">
<rect id="Rectangle_52" data-name="Rectangle 52" width="2.537" height="2.537" rx="1" transform="translate(0 0)" fill="#4a4a4a"/>
<rect id="Rectangle_53" data-name="Rectangle 53" width="2.537" height="2.537" rx="1" transform="translate(3.006 0)" fill="#4a4a4a"/>
<rect id="Rectangle_54" data-name="Rectangle 54" width="2.537" height="2.537" rx="1" transform="translate(6.012 0)" fill="#4a4a4a"/>
<rect id="Rectangle_55" data-name="Rectangle 55" width="2.537" height="2.537" rx="1" transform="translate(9.018 0)" fill="#4a4a4a"/>
<rect id="Rectangle_56" data-name="Rectangle 56" width="2.537" height="2.537" rx="1" transform="translate(12.025 0)" fill="#4a4a4a"/>
<rect id="Rectangle_57" data-name="Rectangle 57" width="2.537" height="2.537" rx="1" transform="translate(15.031 0)" fill="#4a4a4a"/>
<rect id="Rectangle_58" data-name="Rectangle 58" width="2.537" height="2.537" rx="1" transform="translate(18.037 0)" fill="#4a4a4a"/>
<rect id="Rectangle_59" data-name="Rectangle 59" width="2.537" height="2.537" rx="1" transform="translate(21.042 0)" fill="#4a4a4a"/>
<rect id="Rectangle_60" data-name="Rectangle 60" width="2.537" height="2.537" rx="1" transform="translate(24.049 0)" fill="#4a4a4a"/>
<rect id="Rectangle_61" data-name="Rectangle 61" width="2.537" height="2.537" rx="1" transform="translate(27.055 0)" fill="#4a4a4a"/>
<rect id="Rectangle_62" data-name="Rectangle 62" width="2.537" height="2.537" rx="1" transform="translate(30.061 0)" fill="#4a4a4a"/>
</g>
<path id="Path_55" data-name="Path 55" d="M.52,0H3.8a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.017V.52A.519.519,0,0,1,.519,0Z" transform="translate(38.234 0)" fill="#4a4a4a" fill-rule="evenodd"/>
</g>
<g id="Group_7" data-name="Group 7" transform="translate(0.728 14.084)">
<rect id="Rectangle_63" data-name="Rectangle 63" width="2.537" height="2.537" rx="1" transform="translate(0 0)" fill="#4a4a4a"/>
<rect id="Rectangle_64" data-name="Rectangle 64" width="2.537" height="2.537" rx="1" transform="translate(3.006 0)" fill="#4a4a4a"/>
<rect id="Rectangle_65" data-name="Rectangle 65" width="2.537" height="2.537" rx="1" transform="translate(6.012 0)" fill="#4a4a4a"/>
<rect id="Rectangle_66" data-name="Rectangle 66" width="2.537" height="2.537" rx="1" transform="translate(9.018 0)" fill="#4a4a4a"/>
<path id="Path_56" data-name="Path 56" d="M.519,0H14.981A.519.519,0,0,1,15.5.519v1.5a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,2.018V.519A.519.519,0,0,1,.519,0Zm15.97,0h1.874a.519.519,0,0,1,.519.519v1.5a.519.519,0,0,1-.519.519H16.489a.519.519,0,0,1-.519-.519V.519A.519.519,0,0,1,16.489,0Z" transform="translate(12.024 0)" fill="#4a4a4a" fill-rule="evenodd"/>
<rect id="Rectangle_67" data-name="Rectangle 67" width="2.537" height="2.537" rx="1" transform="translate(31.376 0)" fill="#4a4a4a"/>
<rect id="Rectangle_68" data-name="Rectangle 68" width="2.537" height="2.537" rx="1" transform="translate(34.382 0)" fill="#4a4a4a"/>
<rect id="Rectangle_69" data-name="Rectangle 69" width="2.537" height="2.537" rx="1" transform="translate(40.018 0)" fill="#4a4a4a"/>
<path id="Path_57" data-name="Path 57" d="M2.537,0V.561a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,.561V0Z" transform="translate(39.736 1.08) rotate(180)" fill="#4a4a4a"/>
<path id="Path_58" data-name="Path 58" d="M2.537,0V.561a.519.519,0,0,1-.519.519H.519A.519.519,0,0,1,0,.561V0Z" transform="translate(37.2 1.456)" fill="#4a4a4a"/>
</g>
<rect id="Rectangle_70" data-name="Rectangle 70" width="42.273" height="1.127" rx="0.564" transform="translate(0.915 0.556)" fill="#4a4a4a"/>
<rect id="Rectangle_71" data-name="Rectangle 71" width="2.37" height="0.752" rx="0.376" transform="translate(1.949 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_72" data-name="Rectangle 72" width="2.37" height="0.752" rx="0.376" transform="translate(5.193 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_73" data-name="Rectangle 73" width="2.37" height="0.752" rx="0.376" transform="translate(7.688 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_74" data-name="Rectangle 74" width="2.37" height="0.752" rx="0.376" transform="translate(10.183 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_75" data-name="Rectangle 75" width="2.37" height="0.752" rx="0.376" transform="translate(12.679 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_76" data-name="Rectangle 76" width="2.37" height="0.752" rx="0.376" transform="translate(15.797 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_77" data-name="Rectangle 77" width="2.37" height="0.752" rx="0.376" transform="translate(18.292 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_78" data-name="Rectangle 78" width="2.37" height="0.752" rx="0.376" transform="translate(20.788 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_79" data-name="Rectangle 79" width="2.37" height="0.752" rx="0.376" transform="translate(23.283 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_80" data-name="Rectangle 80" width="2.37" height="0.752" rx="0.376" transform="translate(26.402 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_81" data-name="Rectangle 81" width="2.37" height="0.752" rx="0.376" transform="translate(28.897 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_82" data-name="Rectangle 82" width="2.37" height="0.752" rx="0.376" transform="translate(31.393 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_83" data-name="Rectangle 83" width="2.37" height="0.752" rx="0.376" transform="translate(34.512 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_84" data-name="Rectangle 84" width="2.37" height="0.752" rx="0.376" transform="translate(37.007 0.744)" fill="#d8d8d8" opacity="0.136"/>
<rect id="Rectangle_85" data-name="Rectangle 85" width="2.37" height="0.752" rx="0.376" transform="translate(39.502 0.744)" fill="#d8d8d8" opacity="0.136"/>
</g>
<path id="Path_59" data-name="Path 59" d="M123.779,148.389a2.583,2.583,0,0,0-.332.033c-.02-.078-.038-.156-.06-.234a2.594,2.594,0,1,0-2.567-4.455q-.086-.088-.174-.175a2.593,2.593,0,1,0-4.461-2.569c-.077-.022-.154-.04-.231-.06a2.6,2.6,0,1,0-5.128,0c-.077.02-.154.038-.231.06a2.594,2.594,0,1,0-4.461,2.569,10.384,10.384,0,1,0,17.314,9.992,2.592,2.592,0,1,0,.332-5.161" transform="translate(-51.054 -75.262)" fill="#44d860" fill-rule="evenodd"/>
<path id="Path_60" data-name="Path 60" d="M83,113.389h20.779V103H83Z" transform="translate(-41.443 -58.444)" fill="#3ecc5f" fill-rule="evenodd"/>
<path id="Path_61" data-name="Path 61" d="M123.389,108.944a1.3,1.3,0,1,0,0-2.6,1.338,1.338,0,0,0-.166.017c-.01-.039-.019-.078-.03-.117a1.3,1.3,0,0,0-.5-2.5,1.285,1.285,0,0,0-.783.269q-.043-.044-.087-.087a1.285,1.285,0,0,0,.263-.776,1.3,1.3,0,0,0-2.493-.509,5.195,5.195,0,1,0,0,10,1.3,1.3,0,0,0,2.493-.509,1.285,1.285,0,0,0-.263-.776q.044-.043.087-.087a1.285,1.285,0,0,0,.783.269,1.3,1.3,0,0,0,.5-2.5c.011-.038.02-.078.03-.117a1.335,1.335,0,0,0,.166.017" transform="translate(-55.859 -57.894)" fill="#44d860" fill-rule="evenodd"/>
<path id="Path_62" data-name="Path 62" d="M141.8,38.745a1.41,1.41,0,0,1-.255-.026,1.309,1.309,0,0,1-.244-.073,1.349,1.349,0,0,1-.224-.119,1.967,1.967,0,0,1-.2-.161,1.52,1.52,0,0,1-.161-.2,1.282,1.282,0,0,1-.218-.722,1.41,1.41,0,0,1,.026-.255,1.5,1.5,0,0,1,.072-.244,1.364,1.364,0,0,1,.12-.223,1.252,1.252,0,0,1,.358-.358,1.349,1.349,0,0,1,.224-.119,1.309,1.309,0,0,1,.244-.073,1.2,1.2,0,0,1,.509,0,1.262,1.262,0,0,1,.468.192,1.968,1.968,0,0,1,.2.161,1.908,1.908,0,0,1,.161.2,1.322,1.322,0,0,1,.12.223,1.361,1.361,0,0,1,.1.5,1.317,1.317,0,0,1-.379.919,1.968,1.968,0,0,1-.2.161,1.346,1.346,0,0,1-.223.119,1.332,1.332,0,0,1-.5.1m10.389-.649a1.326,1.326,0,0,1-.92-.379,1.979,1.979,0,0,1-.161-.2,1.282,1.282,0,0,1-.218-.722,1.326,1.326,0,0,1,.379-.919,1.967,1.967,0,0,1,.2-.161,1.351,1.351,0,0,1,.224-.119,1.308,1.308,0,0,1,.244-.073,1.2,1.2,0,0,1,.509,0,1.262,1.262,0,0,1,.468.192,1.967,1.967,0,0,1,.2.161,1.326,1.326,0,0,1,.379.919,1.461,1.461,0,0,1-.026.255,1.323,1.323,0,0,1-.073.244,1.847,1.847,0,0,1-.119.223,1.911,1.911,0,0,1-.161.2,1.967,1.967,0,0,1-.2.161,1.294,1.294,0,0,1-.722.218" transform="translate(-69.074 -26.006)" fill-rule="evenodd"/>
</g>
<g id="React-icon" transform="translate(906.3 541.56)">
<path id="Path_330" data-name="Path 330" d="M263.668,117.179c0-5.827-7.3-11.35-18.487-14.775,2.582-11.4,1.434-20.477-3.622-23.382a7.861,7.861,0,0,0-4.016-1v4a4.152,4.152,0,0,1,2.044.466c2.439,1.4,3.5,6.724,2.672,13.574-.2,1.685-.52,3.461-.914,5.272a86.9,86.9,0,0,0-11.386-1.954,87.469,87.469,0,0,0-7.459-8.965c5.845-5.433,11.332-8.41,15.062-8.41V78h0c-4.931,0-11.386,3.514-17.913,9.611-6.527-6.061-12.982-9.539-17.913-9.539v4c3.712,0,9.216,2.959,15.062,8.356a84.687,84.687,0,0,0-7.405,8.947,83.732,83.732,0,0,0-11.4,1.972c-.412-1.793-.717-3.532-.932-5.2-.843-6.85.2-12.175,2.618-13.592a3.991,3.991,0,0,1,2.062-.466v-4h0a8,8,0,0,0-4.052,1c-5.039,2.9-6.168,11.96-3.568,23.328-11.153,3.443-18.415,8.947-18.415,14.757,0,5.828,7.3,11.35,18.487,14.775-2.582,11.4-1.434,20.477,3.622,23.382a7.882,7.882,0,0,0,4.034,1c4.931,0,11.386-3.514,17.913-9.611,6.527,6.061,12.982,9.539,17.913,9.539a8,8,0,0,0,4.052-1c5.039-2.9,6.168-11.96,3.568-23.328C256.406,128.511,263.668,122.988,263.668,117.179Zm-23.346-11.96c-.663,2.313-1.488,4.7-2.421,7.083-.735-1.434-1.506-2.869-2.349-4.3-.825-1.434-1.7-2.833-2.582-4.2C235.517,104.179,237.974,104.645,240.323,105.219Zm-8.212,19.1c-1.4,2.421-2.833,4.716-4.321,6.85-2.672.233-5.379.359-8.1.359-2.708,0-5.415-.126-8.069-.341q-2.232-3.2-4.339-6.814-2.044-3.523-3.73-7.136c1.112-2.4,2.367-4.805,3.712-7.154,1.4-2.421,2.833-4.716,4.321-6.85,2.672-.233,5.379-.359,8.1-.359,2.708,0,5.415.126,8.069.341q2.232,3.2,4.339,6.814,2.044,3.523,3.73,7.136C234.692,119.564,233.455,121.966,232.11,124.315Zm5.792-2.331c.968,2.4,1.793,4.805,2.474,7.136-2.349.574-4.823,1.058-7.387,1.434.879-1.381,1.757-2.8,2.582-4.25C236.4,124.871,237.167,123.419,237.9,121.984ZM219.72,141.116a73.921,73.921,0,0,1-4.985-5.738c1.614.072,3.263.126,4.931.126,1.685,0,3.353-.036,4.985-.126A69.993,69.993,0,0,1,219.72,141.116ZM206.38,130.555c-2.546-.377-5-.843-7.352-1.417.663-2.313,1.488-4.7,2.421-7.083.735,1.434,1.506,2.869,2.349,4.3S205.5,129.192,206.38,130.555ZM219.63,93.241a73.924,73.924,0,0,1,4.985,5.738c-1.614-.072-3.263-.126-4.931-.126-1.686,0-3.353.036-4.985.126A69.993,69.993,0,0,1,219.63,93.241ZM206.362,103.8c-.879,1.381-1.757,2.8-2.582,4.25-.825,1.434-1.6,2.869-2.331,4.3-.968-2.4-1.793-4.805-2.474-7.136C201.323,104.663,203.8,104.179,206.362,103.8Zm-16.227,22.449c-6.348-2.708-10.454-6.258-10.454-9.073s4.106-6.383,10.454-9.073c1.542-.663,3.228-1.255,4.967-1.811a86.122,86.122,0,0,0,4.034,10.92,84.9,84.9,0,0,0-3.981,10.866C193.38,127.525,191.694,126.915,190.134,126.252Zm9.647,25.623c-2.439-1.4-3.5-6.724-2.672-13.574.2-1.686.52-3.461.914-5.272a86.9,86.9,0,0,0,11.386,1.954,87.465,87.465,0,0,0,7.459,8.965c-5.845,5.433-11.332,8.41-15.062,8.41A4.279,4.279,0,0,1,199.781,151.875Zm42.532-13.663c.843,6.85-.2,12.175-2.618,13.592a3.99,3.99,0,0,1-2.062.466c-3.712,0-9.216-2.959-15.062-8.356a84.689,84.689,0,0,0,7.405-8.947,83.731,83.731,0,0,0,11.4-1.972A50.194,50.194,0,0,1,242.313,138.212Zm6.9-11.96c-1.542.663-3.228,1.255-4.967,1.811a86.12,86.12,0,0,0-4.034-10.92,84.9,84.9,0,0,0,3.981-10.866c1.775.556,3.461,1.165,5.039,1.829,6.348,2.708,10.454,6.258,10.454,9.073C259.67,119.994,255.564,123.562,249.216,126.252Z" fill="#61dafb"/>
<path id="Path_331" data-name="Path 331" d="M320.8,78.4Z" transform="translate(-119.082 -0.328)" fill="#61dafb"/>
<circle id="Ellipse_112" data-name="Ellipse 112" cx="8.194" cy="8.194" r="8.194" transform="translate(211.472 108.984)" fill="#61dafb"/>
<path id="Path_332" data-name="Path 332" d="M520.5,78.1Z" transform="translate(-282.975 -0.082)" fill="#61dafb"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 35 KiB

@@ -0,0 +1,40 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1129" height="663" viewBox="0 0 1129 663">
<title>Focus on What Matters</title>
<circle cx="321" cy="321" r="321" fill="#f2f2f2" />
<ellipse cx="559" cy="635.49998" rx="514" ry="27.50002" fill="#3f3d56" />
<ellipse cx="558" cy="627" rx="460" ry="22" opacity="0.2" />
<rect x="131" y="152.5" width="840" height="50" fill="#3f3d56" />
<path d="M166.5,727.3299A21.67009,21.67009,0,0,0,188.1701,749H984.8299A21.67009,21.67009,0,0,0,1006.5,727.3299V296h-840Z" transform="translate(-35.5 -118.5)" fill="#3f3d56" />
<path d="M984.8299,236H188.1701A21.67009,21.67009,0,0,0,166.5,257.6701V296h840V257.6701A21.67009,21.67009,0,0,0,984.8299,236Z" transform="translate(-35.5 -118.5)" fill="#3f3d56" />
<path d="M984.8299,236H188.1701A21.67009,21.67009,0,0,0,166.5,257.6701V296h840V257.6701A21.67009,21.67009,0,0,0,984.8299,236Z" transform="translate(-35.5 -118.5)" opacity="0.2" />
<circle cx="181" cy="147.5" r="13" fill="#3f3d56" />
<circle cx="217" cy="147.5" r="13" fill="#3f3d56" />
<circle cx="253" cy="147.5" r="13" fill="#3f3d56" />
<rect x="168" y="213.5" width="337" height="386" rx="5.33505" fill="#606060" />
<rect x="603" y="272.5" width="284" height="22" rx="5.47638" fill="#2e8555" />
<rect x="537" y="352.5" width="416" height="15" rx="5.47638" fill="#2e8555" />
<rect x="537" y="396.5" width="416" height="15" rx="5.47638" fill="#2e8555" />
<rect x="537" y="440.5" width="416" height="15" rx="5.47638" fill="#2e8555" />
<rect x="537" y="484.5" width="416" height="15" rx="5.47638" fill="#2e8555" />
<rect x="865" y="552.5" width="88" height="26" rx="7.02756" fill="#3ecc5f" />
<path d="M1088.60287,624.61594a30.11371,30.11371,0,0,0,3.98291-15.266c0-13.79652-8.54358-24.98081-19.08256-24.98081s-19.08256,11.18429-19.08256,24.98081a30.11411,30.11411,0,0,0,3.98291,15.266,31.248,31.248,0,0,0,0,30.53213,31.248,31.248,0,0,0,0,30.53208,31.248,31.248,0,0,0,0,30.53208,30.11408,30.11408,0,0,0-3.98291,15.266c0,13.79652,8.54353,24.98081,19.08256,24.98081s19.08256-11.18429,19.08256-24.98081a30.11368,30.11368,0,0,0-3.98291-15.266,31.248,31.248,0,0,0,0-30.53208,31.248,31.248,0,0,0,0-30.53208,31.248,31.248,0,0,0,0-30.53213Z" transform="translate(-35.5 -118.5)" fill="#3f3d56" />
<ellipse cx="1038.00321" cy="460.31783" rx="19.08256" ry="24.9808" fill="#3f3d56" />
<ellipse cx="1038.00321" cy="429.78574" rx="19.08256" ry="24.9808" fill="#3f3d56" />
<path d="M1144.93871,339.34489a91.61081,91.61081,0,0,0,7.10658-10.46092l-50.141-8.23491,54.22885.4033a91.566,91.566,0,0,0,1.74556-72.42605l-72.75449,37.74139,67.09658-49.32086a91.41255,91.41255,0,1,0-150.971,102.29805,91.45842,91.45842,0,0,0-10.42451,16.66946l65.0866,33.81447-69.40046-23.292a91.46011,91.46011,0,0,0,14.73837,85.83669,91.40575,91.40575,0,1,0,143.68892,0,91.41808,91.41808,0,0,0,0-113.02862Z" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
<path d="M981.6885,395.8592a91.01343,91.01343,0,0,0,19.56129,56.51431,91.40575,91.40575,0,1,0,143.68892,0C1157.18982,436.82067,981.6885,385.60008,981.6885,395.8592Z" transform="translate(-35.5 -118.5)" opacity="0.1" />
<path d="M365.62,461.43628H477.094v45.12043H365.62Z" transform="translate(-35.5 -118.5)" fill="#fff" fill-rule="evenodd" />
<path d="M264.76252,608.74122a26.50931,26.50931,0,0,1-22.96231-13.27072,26.50976,26.50976,0,0,0,22.96231,39.81215H291.304V608.74122Z" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
<path d="M384.17242,468.57061l92.92155-5.80726V449.49263a26.54091,26.54091,0,0,0-26.54143-26.54143H331.1161l-3.31768-5.74622a3.83043,3.83043,0,0,0-6.63536,0l-3.31768,5.74622-3.31767-5.74622a3.83043,3.83043,0,0,0-6.63536,0l-3.31768,5.74622L301.257,417.205a3.83043,3.83043,0,0,0-6.63536,0L291.304,422.9512c-.02919,0-.05573.004-.08625.004l-5.49674-5.49541a3.8293,3.8293,0,0,0-6.4071,1.71723l-1.81676,6.77338L270.607,424.1031a3.82993,3.82993,0,0,0-4.6912,4.69253l1.84463,6.89148-6.77072,1.81411a3.8315,3.8315,0,0,0-1.71988,6.40975l5.49673,5.49673c0,.02787-.004.05574-.004.08493l-5.74622,3.31768a3.83043,3.83043,0,0,0,0,6.63536l5.74621,3.31768L259.0163,466.081a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768-5.74622,3.31767a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768-5.74622,3.31768a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768-5.74622,3.31767a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768-5.74622,3.31768a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768-5.74622,3.31768a3.83042,3.83042,0,0,0,0,6.63535l5.74622,3.31768-5.74622,3.31768a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768L259.0163,558.976a3.83042,3.83042,0,0,0,0,6.63535l5.74622,3.31768-5.74622,3.31768a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768-5.74622,3.31768a3.83042,3.83042,0,0,0,0,6.63535l5.74622,3.31768-5.74622,3.31768a3.83043,3.83043,0,0,0,0,6.63536l5.74622,3.31768A26.54091,26.54091,0,0,0,291.304,635.28265H450.55254A26.5409,26.5409,0,0,0,477.094,608.74122V502.5755l-92.92155-5.80727a14.12639,14.12639,0,0,1,0-28.19762" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
<path d="M424.01111,635.28265h39.81214V582.19979H424.01111Z" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
<path d="M490.36468,602.10586a6.60242,6.60242,0,0,0-.848.08493c-.05042-.19906-.09821-.39945-.15393-.59852A6.62668,6.62668,0,1,0,482.80568,590.21q-.2203-.22491-.44457-.44589a6.62391,6.62391,0,1,0-11.39689-6.56369c-.1964-.05575-.39414-.10218-.59056-.15262a6.63957,6.63957,0,1,0-13.10086,0c-.1964.05042-.39414.09687-.59056.15262a6.62767,6.62767,0,1,0-11.39688,6.56369,26.52754,26.52754,0,1,0,44.23127,25.52756,6.6211,6.6211,0,1,0,.848-13.18579" transform="translate(-35.5 -118.5)" fill="#44d860" fill-rule="evenodd" />
<path d="M437.28182,555.65836H477.094V529.11693H437.28182Z" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
<path d="M490.36468,545.70532a3.31768,3.31768,0,0,0,0-6.63536,3.41133,3.41133,0,0,0-.42333.04247c-.02655-.09953-.04911-.19907-.077-.29859a3.319,3.319,0,0,0-1.278-6.37923,3.28174,3.28174,0,0,0-2.00122.68742q-.10947-.11346-.22294-.22295a3.282,3.282,0,0,0,.67149-1.98265,3.31768,3.31768,0,0,0-6.37-1.2992,13.27078,13.27078,0,1,0,0,25.54082,3.31768,3.31768,0,0,0,6.37-1.2992,3.282,3.282,0,0,0-.67149-1.98265q.11347-.10947.22294-.22294a3.28174,3.28174,0,0,0,2.00122.68742,3.31768,3.31768,0,0,0,1.278-6.37923c.02786-.0982.05042-.19907.077-.29859a3.41325,3.41325,0,0,0,.42333.04246" transform="translate(-35.5 -118.5)" fill="#44d860" fill-rule="evenodd" />
<path d="M317.84538,466.081a3.31768,3.31768,0,0,1-3.31767-3.31768,9.953,9.953,0,1,0-19.90608,0,3.31768,3.31768,0,1,1-6.63535,0,16.58839,16.58839,0,1,1,33.17678,0,3.31768,3.31768,0,0,1-3.31768,3.31768" transform="translate(-35.5 -118.5)" fill-rule="evenodd" />
<path d="M370.92825,635.28265h79.62429A26.5409,26.5409,0,0,0,477.094,608.74122v-92.895H397.46968a26.54091,26.54091,0,0,0-26.54143,26.54143Z" transform="translate(-35.5 -118.5)" fill="#ffff50" fill-rule="evenodd" />
<path d="M457.21444,556.98543H390.80778a1.32707,1.32707,0,0,1,0-2.65414h66.40666a1.32707,1.32707,0,0,1,0,2.65414m0,26.54143H390.80778a1.32707,1.32707,0,1,1,0-2.65414h66.40666a1.32707,1.32707,0,0,1,0,2.65414m0,26.54143H390.80778a1.32707,1.32707,0,1,1,0-2.65414h66.40666a1.32707,1.32707,0,0,1,0,2.65414m0-66.10674H390.80778a1.32707,1.32707,0,0,1,0-2.65414h66.40666a1.32707,1.32707,0,0,1,0,2.65414m0,26.29459H390.80778a1.32707,1.32707,0,0,1,0-2.65414h66.40666a1.32707,1.32707,0,0,1,0,2.65414m0,26.54143H390.80778a1.32707,1.32707,0,0,1,0-2.65414h66.40666a1.32707,1.32707,0,0,1,0,2.65414M477.094,474.19076c-.01592,0-.0292-.008-.04512-.00663-4.10064.13934-6.04083,4.24132-7.75274,7.86024-1.78623,3.78215-3.16771,6.24122-5.43171,6.16691-2.50685-.09024-3.94007-2.92222-5.45825-5.91874-1.74377-3.44243-3.73438-7.34667-7.91333-7.20069-4.04227.138-5.98907,3.70784-7.70631,6.857-1.82738,3.35484-3.07084,5.39455-5.46887,5.30033-2.55727-.09289-3.91619-2.39536-5.48877-5.06013-1.75306-2.96733-3.77951-6.30359-7.8775-6.18946-3.97326.13669-5.92537,3.16507-7.64791,5.83912-1.82207,2.82666-3.09872,4.5492-5.52725,4.447-2.61832-.09289-3.9706-2.00388-5.53522-4.21611-1.757-2.4856-3.737-5.299-7.82308-5.16231-3.88567.13271-5.83779,2.61434-7.559,4.80135-1.635,2.07555-2.9116,3.71846-5.61218,3.615a1.32793,1.32793,0,1,0-.09555,2.65414c4.00377.134,6.03154-2.38873,7.79257-4.6275,1.562-1.9853,2.91027-3.69855,5.56441-3.78879,2.55594-.10882,3.75429,1.47968,5.56707,4.04093,1.7212,2.43385,3.67465,5.19416,7.60545,5.33616,4.11789.138,6.09921-2.93946,7.8536-5.66261,1.56861-2.43385,2.92221-4.53461,5.50734-4.62352,2.37944-.08892,3.67466,1.79154,5.50072,4.885,1.72121,2.91557,3.67069,6.21865,7.67977,6.36463,4.14709.14332,6.14965-3.47693,7.89475-6.68181,1.51155-2.77092,2.93814-5.38791,5.46621-5.4755,2.37944-.05573,3.62025,2.11668,5.45558,5.74622,1.71459,3.388,3.65875,7.22591,7.73019,7.37321l.22429.004c4.06614,0,5.99571-4.08074,7.70364-7.68905,1.51154-3.19825,2.94211-6.21069,5.3972-6.33411Z" transform="translate(-35.5 -118.5)" fill-rule="evenodd" />
<path d="M344.38682,635.28265h53.08286V582.19979H344.38682Z" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
<path d="M424.01111,602.10586a6.60242,6.60242,0,0,0-.848.08493c-.05042-.19906-.09821-.39945-.15394-.59852A6.62667,6.62667,0,1,0,416.45211,590.21q-.2203-.22491-.44458-.44589a6.62391,6.62391,0,1,0-11.39689-6.56369c-.1964-.05575-.39413-.10218-.59054-.15262a6.63957,6.63957,0,1,0-13.10084,0c-.19641.05042-.39414.09687-.59055.15262a6.62767,6.62767,0,1,0-11.39689,6.56369,26.52755,26.52755,0,1,0,44.2313,25.52756,6.6211,6.6211,0,1,0,.848-13.18579" transform="translate(-35.5 -118.5)" fill="#44d860" fill-rule="evenodd" />
<path d="M344.38682,555.65836h53.08286V529.11693H344.38682Z" transform="translate(-35.5 -118.5)" fill="#3ecc5f" fill-rule="evenodd" />
<path d="M410.74039,545.70532a3.31768,3.31768,0,1,0,0-6.63536,3.41133,3.41133,0,0,0-.42333.04247c-.02655-.09953-.04911-.19907-.077-.29859a3.319,3.319,0,0,0-1.278-6.37923,3.28174,3.28174,0,0,0-2.00122.68742q-.10947-.11346-.22294-.22295a3.282,3.282,0,0,0,.67149-1.98265,3.31768,3.31768,0,0,0-6.37-1.2992,13.27078,13.27078,0,1,0,0,25.54082,3.31768,3.31768,0,0,0,6.37-1.2992,3.282,3.282,0,0,0-.67149-1.98265q.11347-.10947.22294-.22294a3.28174,3.28174,0,0,0,2.00122.68742,3.31768,3.31768,0,0,0,1.278-6.37923c.02786-.0982.05042-.19907.077-.29859a3.41325,3.41325,0,0,0,.42333.04246" transform="translate(-35.5 -118.5)" fill="#44d860" fill-rule="evenodd" />
<path d="M424.01111,447.8338a3.60349,3.60349,0,0,1-.65028-.06636,3.34415,3.34415,0,0,1-.62372-.18579,3.44679,3.44679,0,0,1-.572-.30522,5.02708,5.02708,0,0,1-.50429-.4114,3.88726,3.88726,0,0,1-.41007-.50428,3.27532,3.27532,0,0,1-.55737-1.84463,3.60248,3.60248,0,0,1,.06636-.65027,3.82638,3.82638,0,0,1,.18447-.62373,3.48858,3.48858,0,0,1,.30656-.57064,3.197,3.197,0,0,1,.91436-.91568,3.44685,3.44685,0,0,1,.572-.30523,3.344,3.344,0,0,1,.62372-.18578,3.06907,3.06907,0,0,1,1.30053,0,3.22332,3.22332,0,0,1,1.19436.491,5.02835,5.02835,0,0,1,.50429.41139,4.8801,4.8801,0,0,1,.41139.50429,3.38246,3.38246,0,0,1,.30522.57064,3.47806,3.47806,0,0,1,.25215,1.274A3.36394,3.36394,0,0,1,426.36,446.865a5.02708,5.02708,0,0,1-.50429.4114,3.3057,3.3057,0,0,1-1.84463.55737m26.54143-1.65884a3.38754,3.38754,0,0,1-2.35024-.96877,5.04185,5.04185,0,0,1-.41007-.50428,3.27532,3.27532,0,0,1-.55737-1.84463,3.38659,3.38659,0,0,1,.96744-2.34892,5.02559,5.02559,0,0,1,.50429-.41139,3.44685,3.44685,0,0,1,.572-.30523,3.3432,3.3432,0,0,1,.62373-.18579,3.06952,3.06952,0,0,1,1.30052,0,3.22356,3.22356,0,0,1,1.19436.491,5.02559,5.02559,0,0,1,.50429.41139,3.38792,3.38792,0,0,1,.96876,2.34892,3.72635,3.72635,0,0,1-.06636.65026,3.37387,3.37387,0,0,1-.18579.62373,4.71469,4.71469,0,0,1-.30522.57064,4.8801,4.8801,0,0,1-.41139.50429,5.02559,5.02559,0,0,1-.50429.41139,3.30547,3.30547,0,0,1-1.84463.55737" transform="translate(-35.5 -118.5)" fill-rule="evenodd" />
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,13 @@
---
sidebar_position: 8
---
# Contributing
- Fork the project and clone it locally.
- Create branches for each separate topic. Any standard you are used to follow for [semantic commit messages](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716) will be highly appreciated.
- Comment your code as if you are going to maintain it in the future.
- Use the rich set of unit tests as an example and add your unit tests as well. This will not only enable you to programatically reproduce your fix faster than setting up an application, but it will also make you super cool! :)
- Push to your changes to the origin of your repository and create a new pull request towards the upstream master.
Thank you!
@@ -0,0 +1,17 @@
---
sidebar_position: 9
title: Report Issues
---
### Reporting issues
Before submitting new issues, please make sure you first search for existing such. It is quite possible that the topic you would like to bring up has been discussed already.
In case of an issue which hasn't been considered yet, please include as much information as possible about the issue. This will help maintainers and other users relate to your problem at hand.
For instance:
- Describe what you were doing when the issue appeared.
- Add a set of steps to reproduce your issue.
- Include screenshots.
- Give examples on expected vs actual behavior.
@@ -0,0 +1,66 @@
---
sidebar_position: 5
title: CLI
---
# Command line interface
The CLI is a thin wrapper around the library Node API. It's available with the same name of the package when installed globally:
```bash
swagger-jsdoc
```
Or through the standard ways provided by your package manager:
```bash
yarn swagger-jsdoc
```
## Usage
Print the help menu:
```bash
swagger-jsdoc -h
```
### Definition file
Set with `--definition` (or `-d`) flag:
```bash
swagger-jsdoc -d swaggerDefinition.js
```
Acceptable file extensions: `.cjs`, `.json`, `.yml`, `.yaml`.
### Input files
Set through arguments.
One by one:
```bash
swagger-jsdoc -d swaggerDefinition.cjs route1.js route2.js component1.yaml component2.yaml
```
Multiple with a pattern:
```bash
swagger-jsdoc -d swaggerDefinition.cjs route*.js component*.yaml
```
[Glob patterns](https://github.com/isaacs/node-glob) are acceptable to match multiple files with same extension `*.js`, `*.php`, etc. or patterns selecting files in nested folders as `**/*.js`, `**/*.php`, etc.
Paths are relative to the current working directory.
### Output file (optional)
The output is `swagger.json` by default, but can be changed:
```bash
swagger-jsdoc -d swaggerDefinition.cjs route1.js -o my_spec.json
```
When output file extension is `.yaml` or `.yml`, the specification will be parsed and saved in YAML format.
@@ -0,0 +1,82 @@
---
sidebar_position: 3
title: Fundamental Concepts
---
# Fundamental concepts
Before you start writing your specification and/or documentation, please keep in mind that there are two fundamental concepts you need to wrap your head around when working with `swagger-jsdoc` - definition object and input APIs.
Definition object maps to [OpenAPI object](https://swagger.io/specification/#oasObject). This is where you would add information about your API and any root-level properties. Definition object is a required parameter.
Input APIs are any files which you pass as arguments to the program in order to extract information about your API. For instance, these could be `.js` files with JSDoc comments or `.yaml` files directly. This parameter is also required.
There are a few ways by which you can pass these 2 required arguments:
When using the CLI:
- Through `apis` property in your definition object.
- Through arguments
When using the Node API:
- Through `apis` in your `options` object.
For example, given the following module export for a definition object:
```javascript
// Taken from example/v2/swaggerDef.js
module.exports = {
info: {
// API informations (required)
title: 'Hello World', // Title (required)
version: '1.0.0', // Version (required)
description: 'A sample API', // Description (optional)
},
host, // Host (optional)
basePath: '/', // Base path (optional)
};
```
One way you can make use of this definition is by using the CLI as following:
```sh
$ swagger-jsdoc -d example/v2/swaggerDef.js example/v2/route*.js
```
If you, however, want to skip the arguments and still use the CLI, you will need to update the definition object as following:
```javascript
// Taken from example/v2/swaggerDef.js
module.exports = {
...
apis: ['example/v2/route*.js'] // <-- We add this property:
basePath: '/', // Base path (optional)
};
```
And then you will be able to use the CLI as following:
```sh
$ swagger-jsdoc -d example/v2/swaggerDef.js
```
When using the Node API, input APIs come in in the following way:
```javascript
const swaggerJSDoc = require('swagger-jsdoc');
const swaggerDefinition = {
...
basePath: '/', // Base path (optional)
};
const options = {
swaggerDefinition,
apis: ['./example/v2/routes*.js'], // <-- not in the definition, but in the options
};
const swaggerSpec = swaggerJSDoc(options);
```
@@ -0,0 +1,16 @@
---
sidebar_position: 2
title: Installation
---
# Installation
```bash
$ npm install swagger-jsdoc --save
```
Or using [`yarn`](https://yarnpkg.com/en/)
```bash
$ yarn add swagger-jsdoc
```
@@ -0,0 +1,40 @@
---
sidebar_position: 1
title: Overview
---
# swagger-jsdoc
Document your code and keep a live and reusable OpenAPI (Swagger) specification. This specification can be the core of your API-driven project: generate
documentation, servers, clients, tests and much more based on the rich [OpenAPI ecosystem of tools](http://swagger.io/).
[![npm Downloads](https://img.shields.io/npm/dm/swagger-jsdoc.svg)](https://www.npmjs.com/package/swagger-jsdoc)
![CI](https://github.com/Surnet/swagger-jsdoc/workflows/CI/badge.svg)
## Goals
**swagger-jsdoc** enables you to integrate [Swagger](http://swagger.io)
using [`JSDoc`](https://jsdoc.app/) comments in your code. Just add `@swagger` (or `@openapi`) on top of your DocBlock and declare the meaning of your code in YAML complying to the OpenAPI specification. If you prefer to keep some parts of your specification aside your code in order to keep it lighter/cleaner, you can also pass these parts as separate input YAML files.
`swagger-jsdoc` will parse the above-mentioned and output an OpenAPI specification. You can use it to integrate any server and client technology as long as both sides comply with the specification.
Thus, the `swagger-jsdoc` project assumes that you want document your existing/living/working code in a way to "give life" to it, generating a specification which can then be fed into other Swagger tools, and not the vice-versa.
If you prefer to write the OpenAPI specification first and separately, you might check other projects facilitating this, such as
- [swagger-editor](http://swagger.io/swagger-editor/)
- [swagger-node](https://github.com/swagger-api/swagger-node)
### Webpack integration
You can use this package with a webpack plugin to keep your swagger documentation up-to-date when building your app:
- [swagger-jsdoc-webpack-plugin](https://github.com/patsimm/swagger-jsdoc-webpack-plugin) - Rebuild the swagger definition based on a predefined list of files on each webpack build.
- [swagger-jsdoc-sync-webpack-plugin](https://github.com/gautier-lefebvre/swagger-jsdoc-sync-webpack-plugin) - Rebuild the swagger definition based on the files imported in your app on each webpack build.
## Supported versions
- OpenAPI 3.x
- Swagger 2.0
To make sure your end specification is valid, do read the most up-to date official [OpenAPI specification](https://github.com/OAI/OpenAPI-Specification).
@@ -0,0 +1,22 @@
---
sidebar_position: 4
title: Quick Start
---
# Quick Start
Note that `swagger-jsdoc` uses [node glob](https://github.com/isaacs/node-glob) module in the background when taking your files. This means that you can use patterns such as `*.js` to select all javascript files or `**/*.js` to select all javascript files in sub-folders recursively.
Paths provided are relative to the current directory from which you execute the program.
### Examples
There are plenty of examples you can use to start off:
- `example`: contains an example app with version 2 of the specification. It will give you an idea how to annotate your comments in order to include them in the output specification.
- `test/cli`: CLI tests you can read to get ideas about the available functionalities of the CLI. (apart from the obvious help menu)
- `test/example`: various assets for tests you can also re-use for starting definitions, routes, etc.
### CLI
On top of the Node API, there is also a [command line interface](./cli).
@@ -0,0 +1,24 @@
---
sidebar_position: 7
title: Validation
---
# Validation
By default `swagger-jsdoc` tries to parse all docs to it's best capabilities. If you'd like to you can instruct an Error to be thrown instead if validation failed by setting the options flag `failOnErrors` to `true`. This is for instance useful if you want to verify that your swagger docs validate using a unit test.
```javascript
const swaggerJsdoc = require('swagger-jsdoc');
const options = {
failOnErrors: true, // Whether or not to throw when parsing errors. Defaults to false.
definition: {
openapi: '3.0.0',
info: {
title: 'Hello World',
version: '1.0.0',
},
},
apis: ['./src/routes*.js'],
};
const openapiSpecification = swaggerJsdoc(options);
```
@@ -0,0 +1,8 @@
{
"label": "Contributing",
"position": 3,
"link": {
"type": "generated-index",
"description": "Guides for contributing to the project"
}
}
@@ -0,0 +1,51 @@
---
sidebar_position: 5
---
# Fundamental concepts
Please pay attention to the following shared information as it's based on recurring questions from the issue queue. Reading the following paragraphs carefully will save your time for the fun part: creating your API.
## Definition and `apis`
There are two fundamental concepts in `swagger-jsdoc` - definition object and input APIs.
The definition object maps to [OpenAPI object](https://swagger.io/specification/#oasObject) and the input APIs are split source code parts which form the end specification.
Parts of the specification can be placed in annotated JSDoc comments in non-compiled logical files. These specification parts stand close to their implementation.
Other parts of the specification can be directly written in YAML files. These are usually parts containing static definitions which are referenced from jsDoc comments parameters, components, anchors, etc. which are not so relevant to the API implementation.
Given the following definition `swaggerDefinition.cjs`:
```javascript
module.exports = {
info: {
title: 'Hello World',
version: '1.0.0',
description: 'A sample API',
},
};
```
The end `swaggerSpecification` will be a result of following:
```javascript
const swaggerJsdoc = require('swagger-jsdoc');
const swaggerDefinition = require('./swaggerDefinition');
const options = {
swaggerDefinition,
apis: ['./src/routes*.js'],
};
const swaggerSpecification = swaggerJsdoc(options);
```
## File selection patterns
`swagger-jsdoc` uses [node glob](https://github.com/isaacs/node-glob) for discovering your input files. You can use patterns such as `*.js` to select all javascript files or `**/*.js` to select all javascript files in sub-folders recursively.
Paths are relative to the current working directory.
[Tests](https://github.com/Surnet/swagger-jsdoc/tree/v6/test)
@@ -0,0 +1,21 @@
---
sidebar_position: 4
title: Project Goals
---
# Project Goals
**swagger-jsdoc** enables you to integrate [Swagger](http://swagger.io) using [`JSDoc`](https://jsdoc.app/) comments in your code. Just add `@swagger` (or `@openapi`) on top of an API-related annotation and and describe the given API part in YAML syntax. It's possible to pass YAML files directly outside the annotated source code.
`swagger-jsdoc` will parse the above-mentioned parts of your desired specification and will output a single file. You can use it to integrate any server and client technology as long as both sides comply with the specification.
Thus, the `swagger-jsdoc` library helps you document existing/living/working code in a way to "give life" to it, generating a specification which can then be fed into other Swagger tools, and not the vice-versa.
If you prefer to write the OpenAPI specification first and separately, you might check other projects facilitating this, such as
- [swagger-editor](http://swagger.io/swagger-editor/)
- [swagger-node](https://github.com/swagger-api/swagger-node)
## What swagger-jsdoc is NOT (doing)
The library does not add logic (implementation) to your specification. It is based on code annotations or static YAML files, but not the logic itself. If you use [Swagger UI](https://swagger.io/tools/swagger-ui/) or a similar tools to test your API and you receive errors, unexpected results and mystical data, it's not because of swagger-jsdoc library. It works only with what you put around your logic, not the contents of the logic.
@@ -0,0 +1,29 @@
---
sidebar_position: 7
---
# Reporting issues
Before starting a new issue, please [check whether there is an existing one](https://github.com/Surnet/swagger-jsdoc/issues). It is quite possible that the topic you would like to bring up has been discussed already in the past.
In case of an issue which hasn't been considered yet, please include as much information as possible. This will help maintainers and other users relate to your problem and possibly solve it.
Guidelines:
- Describe what you were doing when the issue appeared.
- Add a set of steps to reproduce your issue.
- Include screenshots.
- Give examples on expected vs actual behavior.
- Share your failed attempts: what you have tried and what you have considered.
# Contributing
The project exists thanks to the [many contributors](https://github.com/Surnet/swagger-jsdoc/graphs/contributors) who shared their use cases, questions, comments and suggestions for improvements.
Here's how to jump in and contribute yourself:
- Fork the project and clone it locally.
- Create a branch for each separate topic. [Semantic commit messages](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716) will be highly appreciated.
- Comment your code as if you are going to maintain it in the future.
- Use the rich set of unit tests as an example and add more for the new use cases. This will not only enable you to programatically reproduce your fix faster than setting up an application, but it will also make you super cool! :)
- Push to your changes to the origin of your repository and create a new pull request towards the upstream master. (this repository)
@@ -0,0 +1,21 @@
---
sidebar_position: 6
---
# Typescript
## Types
Please see [`@types/swagger-jsdoc`](https://www.npmjs.com/package/@types/swagger-jsdoc). The package has been created and maintained by one of the original creators of `swagger-jsdoc` [drGrove](https://github.com/drGrove).
## The library
It's currently written in Vanilla JavaScript compatible with Node.js 12 or higher. There are no compilation, transpilation or bundling steps. JSDoc comments and annotations have been maintained and published for intelligent editors.
No types definitions are managed or published from this repository.
## Re-using interfaces from source code
`swagger-jsdoc` is only taking into account JSDoc comments and pure YAML files. The library does not work with source code at all: no reading, no parsing, no modifications.
For scenarios in which you want the source code to be taken into account in your specification, use an alternative such as [`tsoa`](https://github.com/lukeautry/tsoa).
@@ -0,0 +1,9 @@
{
"label": "Quick Start",
"position": 2,
"link": {
"type": "generated-index",
"description": "Getting started with swagger-jsdoc."
}
}
@@ -0,0 +1,66 @@
---
sidebar_position: 3
title: CLI
---
# Command line interface
The CLI is a thin wrapper around the library Node API. It's available with the same name of the package when installed globally:
```bash
swagger-jsdoc
```
Or through the standard ways provided by your package manager:
```bash
yarn swagger-jsdoc
```
## Usage
Print the help menu:
```bash
swagger-jsdoc -h
```
### Definition file
Set with `--definition` (or `-d`) flag:
```bash
swagger-jsdoc -d swaggerDefinition.js
```
Acceptable file extensions: `.cjs`, `.json`, `.yml`, `.yaml`.
### Input files
Set through arguments.
One by one:
```bash
swagger-jsdoc -d swaggerDefinition.cjs route1.js route2.js component1.yaml component2.yaml
```
Multiple with a pattern:
```bash
swagger-jsdoc -d swaggerDefinition.cjs route*.js component*.yaml
```
[Glob patterns](https://github.com/isaacs/node-glob) are acceptable to match multiple files with same extension `*.js`, `*.php`, etc. or patterns selecting files in nested folders as `**/*.js`, `**/*.php`, etc.
Paths are relative to the current working directory.
### Output file (optional)
The output is `swagger.json` by default, but can be changed:
```bash
swagger-jsdoc -d swaggerDefinition.cjs route1.js -o my_spec.json
```
When output file extension is `.yaml` or `.yml`, the specification will be parsed and saved in YAML format.
@@ -0,0 +1,125 @@
---
sidebar_position: 2
title: First Steps
---
# First Steps
## Specification version
`swagger-jsdoc` was created in 2015. The OpenAPI as a concept did not exist, and thus the naming of the package itself.
The default target specification is 2.0. This provides backwards compatibility for many APIs written in the last couple of years.
In order to create a specification compatibile with 3.0 or higher, i.e. the so called OpenAPI, set this information in the `swaggerDefinition`:
```diff
const swaggerJsdoc = require('swagger-jsdoc');
const options = {
swaggerDefinition: {
+ openapi: '3.0.0',
info: {
title: 'Hello World',
version: '1.0.0',
},
},
apis: ['./src/routes*.js'],
};
const swaggerSpecification = swaggerJsdoc(options);
```
## Annotating source code
Place `@swagger` or `@openapi` on top of YAML-formatted specification parts:
```javascript
/**
* @swagger
*
* /login:
* post:
* produces:
* - application/json
* parameters:
* - name: username
* in: formData
* required: true
* type: string
* - name: password
* in: formData
* required: true
* type: string
*/
app.post('/login', (req, res) => {
// Your implementation comes here ...
});
```
## Using YAML
It's possible to source parts of your specification through YAML files.
Imagine having a file `x-amazon-apigateway-integrations.yaml` with the following contents:
```yaml
x-amazon-apigateway-integrations:
default-integration: &default-integration
type: object
x-amazon-apigateway-integration:
httpMethod: POST
passthroughBehavior: when_no_match
type: aws_proxy
uri: 'arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:123456789:function:helloworldlambda/invocations'
```
The following is an acceptable reference to information from `x-amazon-apigateway-integrations.yaml` when it's defined within the `apis` input array.
```javascript
/**
* @swagger
* /aws:
* get:
* description: contains a reference outside this file
* x-amazon-apigateway-integration: *default-integration
*/
app.get('/aws', (req, res) => {
// Your implementation comes here ...
});
};
```
## Further resources
Additional materials to inspire you:
- [Document your Javascript code with JSDoc](https://dev.to/paulasantamaria/document-your-javascript-code-with-jsdoc-2fbf) - 20/08/2019
- [Swagger: Time to document that Express API you built!](https://levelup.gitconnected.com/swagger-time-to-document-that-express-api-you-built-9b8faaeae563) - 25/05/2019
[Express API with autogenerated OpenAPI doc through Swagger](https://www.acuriousanimal.com/blog/2018/10/20/express-swagger-doc) - 20/10/2018
- [Express에 Swagger 붙이기](https://gongzza.github.io/javascript/nodejs/swagger-node-express/) - 18/07/2018
- [Swaggerize your API Documentation](http://imaginativethinking.ca/swaggerize-your-api-documentation/) - 01/06/2018
- [Swagger and NodeJS](https://mherman.org/blog/swagger-and-nodejs/) 20/11/2017
- [Agile documentation for your API-driven project](https://kalinchernev.github.io/agile-documentation-api-driven-project) - 21/01/2017
Suggestions for extending this helpful list are welcome! [Submit your article](https://github.com/Surnet/swagger-jsdoc/issues/new)
## Examples
Here's a list of example public open-source usages of the package:
- [godaddy/gasket](https://github.com/godaddy/gasket)
- [godaddy/warehouse.ai-status-api](https://github.com/godaddy/warehouse.ai-status-api)
- [hana-developer-cli-tool-example](https://github.com/SAP-samples/hana-developer-cli-tool-example)
- [studiohyperdrive/api-docs](https://github.com/studiohyperdrive/api-docs)
- [More Examples](https://github.com/Surnet/swagger-jsdoc/tree/v6/examples)
## Related projects
- [godaddy/swagger-jsdoc-deref](https://github.com/godaddy/swagger-jsdoc-deref)
- [slanatech/swagger-stats](https://github.com/slanatech/swagger-stats)
- [weseek/growi](https://github.com/weseek/growi)
- [linagora/openpaas-esn](https://github.com/linagora/openpaas-esn)
- [Tiemma/sonic-express](https://github.com/Tiemma/sonic-express)
- [kevoj/nodetomic-api-swagger](https://github.com/kevoj/nodetomic-api-swagger)
- [node-express-mongoose-boilerplate](https://github.com/hagopj13/node-express-mongoose-boilerplate)
@@ -0,0 +1,40 @@
---
sidebar_position: 1
title: Intro
---
# swagger-jsdoc
Document your code and keep a live and reusable OpenAPI (Swagger) specification. This specification can be the core of your API-driven project: generate
documentation, servers, clients, tests and much more based on the rich [OpenAPI ecosystem of tools](http://swagger.io/).
[![npm Downloads](https://img.shields.io/npm/dm/swagger-jsdoc.svg)](https://www.npmjs.com/package/swagger-jsdoc)
![CI](https://github.com/Surnet/swagger-jsdoc/workflows/CI/badge.svg)
## Goals
**swagger-jsdoc** enables you to integrate [Swagger](http://swagger.io)
using [`JSDoc`](https://jsdoc.app/) comments in your code. Just add `@swagger` (or `@openapi`) on top of your DocBlock and declare the meaning of your code in YAML complying to the OpenAPI specification. If you prefer to keep some parts of your specification aside your code in order to keep it lighter/cleaner, you can also pass these parts as separate input YAML files.
`swagger-jsdoc` will parse the above-mentioned and output an OpenAPI specification. You can use it to integrate any server and client technology as long as both sides comply with the specification.
Thus, the `swagger-jsdoc` project assumes that you want document your existing/living/working code in a way to "give life" to it, generating a specification which can then be fed into other Swagger tools, and not the vice-versa.
If you prefer to write the OpenAPI specification first and separately, you might check other projects facilitating this, such as
- [swagger-editor](http://swagger.io/swagger-editor/)
- [swagger-node](https://github.com/swagger-api/swagger-node)
### Webpack integration
You can use this package with a webpack plugin to keep your swagger documentation up-to-date when building your app:
- [swagger-jsdoc-webpack-plugin](https://github.com/patsimm/swagger-jsdoc-webpack-plugin) - Rebuild the swagger definition based on a predefined list of files on each webpack build.
- [swagger-jsdoc-sync-webpack-plugin](https://github.com/gautier-lefebvre/swagger-jsdoc-sync-webpack-plugin) - Rebuild the swagger definition based on the files imported in your app on each webpack build.
## Supported versions
- OpenAPI 3.x
- Swagger 2.0
To make sure your end specification is valid, do read the most up-to date official [OpenAPI specification](https://github.com/OAI/OpenAPI-Specification).
@@ -0,0 +1,8 @@
{
"label": "Contributing",
"position": 3,
"link": {
"type": "generated-index",
"description": "Guides for contributing to the project"
}
}
@@ -0,0 +1,51 @@
---
sidebar_position: 5
---
# Fundamental concepts
Please pay attention to the following shared information as it's based on recurring questions from the issue queue. Reading the following paragraphs carefully will save your time for the fun part: creating your API.
## Definition and `apis`
There are two fundamental concepts in `swagger-jsdoc` - definition object and input APIs.
The definition object maps to [OpenAPI object](https://swagger.io/specification/#oasObject) and the input APIs are split source code parts which form the end specification.
Parts of the specification can be placed in annotated JSDoc comments in non-compiled logical files. These specification parts stand close to their implementation.
Other parts of the specification can be directly written in YAML files. These are usually parts containing static definitions which are referenced from jsDoc comments parameters, components, anchors, etc. which are not so relevant to the API implementation.
Given the following definition `swaggerDefinition.cjs`:
```javascript
module.exports = {
info: {
title: 'Hello World',
version: '1.0.0',
description: 'A sample API',
},
};
```
The end `swaggerSpecification` will be a result of following:
```javascript
const swaggerJsdoc = require('swagger-jsdoc');
const swaggerDefinition = require('./swaggerDefinition');
const options = {
swaggerDefinition,
apis: ['./src/routes*.js'],
};
const swaggerSpecification = swaggerJsdoc(options);
```
## File selection patterns
`swagger-jsdoc` uses [node glob](https://github.com/isaacs/node-glob) for discovering your input files. You can use patterns such as `*.js` to select all javascript files or `**/*.js` to select all javascript files in sub-folders recursively.
Paths are relative to the current working directory.
[Tests](https://github.com/Surnet/swagger-jsdoc/tree/v6/test)
@@ -0,0 +1,21 @@
---
sidebar_position: 4
title: Project Goals
---
# Project Goals
**swagger-jsdoc** enables you to integrate [Swagger](http://swagger.io) using [`JSDoc`](https://jsdoc.app/) comments in your code. Just add `@swagger` (or `@openapi`) on top of an API-related annotation and and describe the given API part in YAML syntax. It's possible to pass YAML files directly outside the annotated source code.
`swagger-jsdoc` will parse the above-mentioned parts of your desired specification and will output a single file. You can use it to integrate any server and client technology as long as both sides comply with the specification.
Thus, the `swagger-jsdoc` library helps you document existing/living/working code in a way to "give life" to it, generating a specification which can then be fed into other Swagger tools, and not the vice-versa.
If you prefer to write the OpenAPI specification first and separately, you might check other projects facilitating this, such as
- [swagger-editor](http://swagger.io/swagger-editor/)
- [swagger-node](https://github.com/swagger-api/swagger-node)
## What swagger-jsdoc is NOT (doing)
The library does not add logic (implementation) to your specification. It is based on code annotations or static YAML files, but not the logic itself. If you use [Swagger UI](https://swagger.io/tools/swagger-ui/) or a similar tools to test your API and you receive errors, unexpected results and mystical data, it's not because of swagger-jsdoc library. It works only with what you put around your logic, not the contents of the logic.
@@ -0,0 +1,29 @@
---
sidebar_position: 7
---
# Reporting issues
Before starting a new issue, please [check whether there is an existing one](https://github.com/Surnet/swagger-jsdoc/issues). It is quite possible that the topic you would like to bring up has been discussed already in the past.
In case of an issue which hasn't been considered yet, please include as much information as possible. This will help maintainers and other users relate to your problem and possibly solve it.
Guidelines:
- Describe what you were doing when the issue appeared.
- Add a set of steps to reproduce your issue.
- Include screenshots.
- Give examples on expected vs actual behavior.
- Share your failed attempts: what you have tried and what you have considered.
# Contributing
The project exists thanks to the [many contributors](https://github.com/Surnet/swagger-jsdoc/graphs/contributors) who shared their use cases, questions, comments and suggestions for improvements.
Here's how to jump in and contribute yourself:
- Fork the project and clone it locally.
- Create a branch for each separate topic. [Semantic commit messages](https://gist.github.com/joshbuchea/6f47e86d2510bce28f8e7f42ae84c716) will be highly appreciated.
- Comment your code as if you are going to maintain it in the future.
- Use the rich set of unit tests as an example and add more for the new use cases. This will not only enable you to programatically reproduce your fix faster than setting up an application, but it will also make you super cool! :)
- Push to your changes to the origin of your repository and create a new pull request towards the upstream master. (this repository)
@@ -0,0 +1,21 @@
---
sidebar_position: 6
---
# Typescript
## Types
Please see [`@types/swagger-jsdoc`](https://www.npmjs.com/package/@types/swagger-jsdoc). The package has been created and maintained by one of the original creators of `swagger-jsdoc` [drGrove](https://github.com/drGrove).
## The library
It's currently written in Vanilla JavaScript compatible with Node.js 12 or higher. There are no compilation, transpilation or bundling steps. JSDoc comments and annotations have been maintained and published for intelligent editors.
No types definitions are managed or published from this repository.
## Re-using interfaces from source code
`swagger-jsdoc` is only taking into account JSDoc comments and pure YAML files. The library does not work with source code at all: no reading, no parsing, no modifications.
For scenarios in which you want the source code to be taken into account in your specification, use an alternative such as [`tsoa`](https://github.com/lukeautry/tsoa).
@@ -0,0 +1,40 @@
---
sidebar_position: 1
title: Intro
---
# swagger-jsdoc
Document your code and keep a live and reusable OpenAPI (Swagger) specification. This specification can be the core of your API-driven project: generate
documentation, servers, clients, tests and much more based on the rich [OpenAPI ecosystem of tools](http://swagger.io/).
[![npm Downloads](https://img.shields.io/npm/dm/swagger-jsdoc.svg)](https://www.npmjs.com/package/swagger-jsdoc)
![CI](https://github.com/Surnet/swagger-jsdoc/workflows/CI/badge.svg)
## Goals
**swagger-jsdoc** enables you to integrate [Swagger](http://swagger.io)
using [`JSDoc`](https://jsdoc.app/) comments in your code. Just add `@swagger` (or `@openapi`) on top of your DocBlock and declare the meaning of your code in YAML complying to the OpenAPI specification. If you prefer to keep some parts of your specification aside your code in order to keep it lighter/cleaner, you can also pass these parts as separate input YAML files.
`swagger-jsdoc` will parse the above-mentioned and output an OpenAPI specification. You can use it to integrate any server and client technology as long as both sides comply with the specification.
Thus, the `swagger-jsdoc` project assumes that you want document your existing/living/working code in a way to "give life" to it, generating a specification which can then be fed into other Swagger tools, and not the vice-versa.
If you prefer to write the OpenAPI specification first and separately, you might check other projects facilitating this, such as
- [swagger-editor](http://swagger.io/swagger-editor/)
- [swagger-node](https://github.com/swagger-api/swagger-node)
### Webpack integration
You can use this package with a webpack plugin to keep your swagger documentation up-to-date when building your app:
- [swagger-jsdoc-webpack-plugin](https://github.com/patsimm/swagger-jsdoc-webpack-plugin) - Rebuild the swagger definition based on a predefined list of files on each webpack build.
- [swagger-jsdoc-sync-webpack-plugin](https://github.com/gautier-lefebvre/swagger-jsdoc-sync-webpack-plugin) - Rebuild the swagger definition based on the files imported in your app on each webpack build.
## Supported versions
- OpenAPI 3.x
- Swagger 2.0
To make sure your end specification is valid, do read the most up-to date official [OpenAPI specification](https://github.com/OAI/OpenAPI-Specification).
@@ -0,0 +1,8 @@
{
"label": "Quick Start",
"position": 2,
"link": {
"type": "generated-index",
"description": "Getting started with swagger-jsdoc"
}
}
@@ -0,0 +1,122 @@
---
title: First Steps
---
## Specification version
`swagger-jsdoc` was created in 2015. The OpenAPI as a concept did not exist, and thus the naming of the package itself.
The default target specification is 2.0. This provides backwards compatibility for many APIs written in the last couple of years.
In order to create a specification compatibile with 3.0 or higher, i.e. the so called OpenAPI, set this information in the `swaggerDefinition`:
```diff
import swaggerJsdoc from 'swagger-jsdoc';
const options = {
definition: {
+ openapi: '3.0.0',
info: {
title: 'Hello World',
version: '1.0.0',
},
},
apis: ['./src/routes*.js'],
};
const openapiSpecification = await swaggerJsdoc(options);
```
## Annotating source code
Place `@swagger` or `@openapi` on top of YAML-formatted specification parts:
```javascript
/**
* @swagger
*
* /login:
* post:
* produces:
* - application/json
* parameters:
* - name: username
* in: formData
* required: true
* type: string
* - name: password
* in: formData
* required: true
* type: string
*/
app.post('/login', (req, res) => {
// Your implementation comes here ...
});
```
## Using YAML
It's possible to source parts of your specification through YAML files.
Imagine having a file `x-amazon-apigateway-integrations.yaml` with the following contents:
```yaml
x-amazon-apigateway-integrations:
default-integration: &default-integration
type: object
x-amazon-apigateway-integration:
httpMethod: POST
passthroughBehavior: when_no_match
type: aws_proxy
uri: 'arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:123456789:function:helloworldlambda/invocations'
```
The following is an acceptable reference to information from `x-amazon-apigateway-integrations.yaml` when it's defined within the `apis` input array.
```javascript
/**
* @swagger
* /aws:
* get:
* description: contains a reference outside this file
* x-amazon-apigateway-integration: *default-integration
*/
app.get('/aws', (req, res) => {
// Your implementation comes here ...
});
};
```
## Further resources
Additional materials to inspire you:
- [De-duping the Duplication in Services Featuring: Swagger/OpenAPI and AJV](https://medium.com/geekculture/de-duping-the-duplication-in-services-featuring-swagger-openapi-and-ajv-abd22c8c764e) - 09/03/2021
- [How to implement and use Swagger in Node.js](https://js.plainenglish.io/how-to-implement-and-use-swagger-in-nodejs-d0b95e765245) - 24/02/2021
- [Document your Javascript code with JSDoc](https://dev.to/paulasantamaria/document-your-javascript-code-with-jsdoc-2fbf) - 20/08/2019
- [Express API with autogenerated OpenAPI doc through Swagger](https://www.acuriousanimal.com/blog/2018/10/20/express-swagger-doc) - 20/10/2018
- [Swaggerize your API Documentation](http://imaginativethinking.ca/swaggerize-your-api-documentation/) - 01/06/2018
- [Swagger and NodeJS](https://mherman.org/blog/swagger-and-nodejs/) 20/11/2017
- [Agile documentation for your API-driven project](https://kalinchernev.github.io/agile-documentation-api-driven-project) - 21/01/2017
Suggestions for extending this helpful list are welcome! [Submit your article](https://github.com/Surnet/swagger-jsdoc/issues/new)
## Examples
Here's a list of example public open-source usages of the package:
- [godaddy/gasket](https://github.com/godaddy/gasket)
- [godaddy/warehouse.ai-status-api](https://github.com/godaddy/warehouse.ai-status-api)
- [hana-developer-cli-tool-example](https://github.com/SAP-samples/hana-developer-cli-tool-example)
- [studiohyperdrive/api-docs](https://github.com/studiohyperdrive/api-docs)
- [More Examples](https://github.com/Surnet/swagger-jsdoc/tree/v7/examples)
## Related projects
- [godaddy/swagger-jsdoc-deref](https://github.com/godaddy/swagger-jsdoc-deref)
- [slanatech/swagger-stats](https://github.com/slanatech/swagger-stats)
- [weseek/growi](https://github.com/weseek/growi)
- [linagora/openpaas-esn](https://github.com/linagora/openpaas-esn)
- [Tiemma/sonic-express](https://github.com/Tiemma/sonic-express)
- [kevoj/nodetomic-api-swagger](https://github.com/kevoj/nodetomic-api-swagger)
- [node-express-mongoose-boilerplate](https://github.com/hagopj13/node-express-mongoose-boilerplate)
@@ -0,0 +1,8 @@
{
"tutorialSidebar": [
{
"type": "autogenerated",
"dirName": "."
}
]
}
@@ -0,0 +1,8 @@
{
"tutorialSidebar": [
{
"type": "autogenerated",
"dirName": "."
}
]
}
@@ -0,0 +1,8 @@
{
"tutorialSidebar": [
{
"type": "autogenerated",
"dirName": "."
}
]
}
@@ -0,0 +1,5 @@
[
"7.x",
"6.x",
"5.x"
]
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
module.exports = require('./src/lib');
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
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,129 @@
# brace-expansion
[Brace expansion](https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html),
as known from sh/bash, in JavaScript.
[![build status](https://secure.travis-ci.org/juliangruber/brace-expansion.svg)](http://travis-ci.org/juliangruber/brace-expansion)
[![downloads](https://img.shields.io/npm/dm/brace-expansion.svg)](https://www.npmjs.org/package/brace-expansion)
[![Greenkeeper badge](https://badges.greenkeeper.io/juliangruber/brace-expansion.svg)](https://greenkeeper.io/)
[![testling badge](https://ci.testling.com/juliangruber/brace-expansion.png)](https://ci.testling.com/juliangruber/brace-expansion)
## Example
```js
var expand = require('brace-expansion');
expand('file-{a,b,c}.jpg')
// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg']
expand('-v{,,}')
// => ['-v', '-v', '-v']
expand('file{0..2}.jpg')
// => ['file0.jpg', 'file1.jpg', 'file2.jpg']
expand('file-{a..c}.jpg')
// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg']
expand('file{2..0}.jpg')
// => ['file2.jpg', 'file1.jpg', 'file0.jpg']
expand('file{0..4..2}.jpg')
// => ['file0.jpg', 'file2.jpg', 'file4.jpg']
expand('file-{a..e..2}.jpg')
// => ['file-a.jpg', 'file-c.jpg', 'file-e.jpg']
expand('file{00..10..5}.jpg')
// => ['file00.jpg', 'file05.jpg', 'file10.jpg']
expand('{{A..C},{a..c}}')
// => ['A', 'B', 'C', 'a', 'b', 'c']
expand('ppp{,config,oe{,conf}}')
// => ['ppp', 'pppconfig', 'pppoe', 'pppoeconf']
```
## API
```js
var expand = require('brace-expansion');
```
### var expanded = expand(str)
Return an array of all possible and valid expansions of `str`. If none are
found, `[str]` is returned.
Valid expansions are:
```js
/^(.*,)+(.+)?$/
// {a,b,...}
```
A comma separated list of options, like `{a,b}` or `{a,{b,c}}` or `{,a,}`.
```js
/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/
// {x..y[..incr]}
```
A numeric sequence from `x` to `y` inclusive, with optional increment.
If `x` or `y` start with a leading `0`, all the numbers will be padded
to have equal length. Negative numbers and backwards iteration work too.
```js
/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/
// {x..y[..incr]}
```
An alphabetic sequence from `x` to `y` inclusive, with optional increment.
`x` and `y` must be exactly one character, and if given, `incr` must be a
number.
For compatibility reasons, the string `${` is not eligible for brace expansion.
## Installation
With [npm](https://npmjs.org) do:
```bash
npm install brace-expansion
```
## Contributors
- [Julian Gruber](https://github.com/juliangruber)
- [Isaac Z. Schlueter](https://github.com/isaacs)
## Sponsors
This module is proudly supported by my [Sponsors](https://github.com/juliangruber/sponsors)!
Do you want to support modules like this to improve their quality, stability and weigh in on new features? Then please consider donating to my [Patreon](https://www.patreon.com/juliangruber). Not sure how much of my modules you're using? Try [feross/thanks](https://github.com/feross/thanks)!
## License
(MIT)
Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
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,201 @@
var concatMap = require('concat-map');
var balanced = require('balanced-match');
module.exports = expandTop;
var escSlash = '\0SLASH'+Math.random()+'\0';
var escOpen = '\0OPEN'+Math.random()+'\0';
var escClose = '\0CLOSE'+Math.random()+'\0';
var escComma = '\0COMMA'+Math.random()+'\0';
var escPeriod = '\0PERIOD'+Math.random()+'\0';
function numeric(str) {
return parseInt(str, 10) == str
? parseInt(str, 10)
: str.charCodeAt(0);
}
function escapeBraces(str) {
return str.split('\\\\').join(escSlash)
.split('\\{').join(escOpen)
.split('\\}').join(escClose)
.split('\\,').join(escComma)
.split('\\.').join(escPeriod);
}
function unescapeBraces(str) {
return str.split(escSlash).join('\\')
.split(escOpen).join('{')
.split(escClose).join('}')
.split(escComma).join(',')
.split(escPeriod).join('.');
}
// Basically just str.split(","), but handling cases
// where we have nested braced sections, which should be
// treated as individual members, like {a,{b,c},d}
function parseCommaParts(str) {
if (!str)
return [''];
var parts = [];
var m = balanced('{', '}', str);
if (!m)
return str.split(',');
var pre = m.pre;
var body = m.body;
var post = m.post;
var p = pre.split(',');
p[p.length-1] += '{' + body + '}';
var postParts = parseCommaParts(post);
if (post.length) {
p[p.length-1] += postParts.shift();
p.push.apply(p, postParts);
}
parts.push.apply(parts, p);
return parts;
}
function expandTop(str) {
if (!str)
return [];
// I don't know why Bash 4.3 does this, but it does.
// Anything starting with {} will have the first two bytes preserved
// but *only* at the top level, so {},a}b will not expand to anything,
// but a{},b}c will be expanded to [a}c,abc].
// One could argue that this is a bug in Bash, but since the goal of
// this module is to match Bash's rules, we escape a leading {}
if (str.substr(0, 2) === '{}') {
str = '\\{\\}' + str.substr(2);
}
return expand(escapeBraces(str), true).map(unescapeBraces);
}
function identity(e) {
return e;
}
function embrace(str) {
return '{' + str + '}';
}
function isPadded(el) {
return /^-?0\d/.test(el);
}
function lte(i, y) {
return i <= y;
}
function gte(i, y) {
return i >= y;
}
function expand(str, isTop) {
var expansions = [];
var m = balanced('{', '}', str);
if (!m || /\$$/.test(m.pre)) return [str];
var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
var isSequence = isNumericSequence || isAlphaSequence;
var isOptions = m.body.indexOf(',') >= 0;
if (!isSequence && !isOptions) {
// {a},b}
if (m.post.match(/,(?!,).*\}/)) {
str = m.pre + '{' + m.body + escClose + m.post;
return expand(str);
}
return [str];
}
var n;
if (isSequence) {
n = m.body.split(/\.\./);
} else {
n = parseCommaParts(m.body);
if (n.length === 1) {
// x{{a,b}}y ==> x{a}y x{b}y
n = expand(n[0], false).map(embrace);
if (n.length === 1) {
var post = m.post.length
? expand(m.post, false)
: [''];
return post.map(function(p) {
return m.pre + n[0] + p;
});
}
}
}
// at this point, n is the parts, and we know it's not a comma set
// with a single entry.
// no need to expand pre, since it is guaranteed to be free of brace-sets
var pre = m.pre;
var post = m.post.length
? expand(m.post, false)
: [''];
var N;
if (isSequence) {
var x = numeric(n[0]);
var y = numeric(n[1]);
var width = Math.max(n[0].length, n[1].length)
var incr = n.length == 3
? Math.abs(numeric(n[2]))
: 1;
var test = lte;
var reverse = y < x;
if (reverse) {
incr *= -1;
test = gte;
}
var pad = n.some(isPadded);
N = [];
for (var i = x; test(i, y); i += incr) {
var c;
if (isAlphaSequence) {
c = String.fromCharCode(i);
if (c === '\\')
c = '';
} else {
c = String(i);
if (pad) {
var need = width - c.length;
if (need > 0) {
var z = new Array(need + 1).join('0');
if (i < 0)
c = '-' + z + c.slice(1);
else
c = z + c;
}
}
}
N.push(c);
}
} else {
N = concatMap(n, function(el) { return expand(el, false) });
}
for (var j = 0; j < N.length; j++) {
for (var k = 0; k < post.length; k++) {
var expansion = pre + N[j] + post[k];
if (!isTop || isSequence || expansion)
expansions.push(expansion);
}
}
return expansions;
}
@@ -0,0 +1,50 @@
{
"name": "brace-expansion",
"description": "Brace expansion as known from sh/bash",
"version": "1.1.12",
"repository": {
"type": "git",
"url": "git://github.com/juliangruber/brace-expansion.git"
},
"homepage": "https://github.com/juliangruber/brace-expansion",
"main": "index.js",
"scripts": {
"test": "tape test/*.js",
"gentest": "bash test/generate.sh",
"bench": "matcha test/perf/bench.js"
},
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
},
"devDependencies": {
"matcha": "^0.7.0",
"tape": "^4.6.0"
},
"keywords": [],
"author": {
"name": "Julian Gruber",
"email": "mail@juliangruber.com",
"url": "http://juliangruber.com"
},
"license": "MIT",
"testling": {
"files": "test/*.js",
"browsers": [
"ie/8..latest",
"firefox/20..latest",
"firefox/nightly",
"chrome/25..latest",
"chrome/canary",
"opera/12..latest",
"opera/next",
"safari/5.1..latest",
"ipad/6.0..latest",
"iphone/6.0..latest",
"android-browser/4.2..latest"
]
},
"publishConfig": {
"tag": "1.x"
}
}
@@ -0,0 +1,21 @@
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
## Glob Logo
Glob's logo created by Tanya Brassie <http://tanyabrassie.com/>, licensed
under a Creative Commons Attribution-ShareAlike 4.0 International License
https://creativecommons.org/licenses/by-sa/4.0/
@@ -0,0 +1,375 @@
# Glob
Match files using the patterns the shell uses, like stars and stuff.
[![Build Status](https://travis-ci.org/isaacs/node-glob.svg?branch=master)](https://travis-ci.org/isaacs/node-glob/) [![Build Status](https://ci.appveyor.com/api/projects/status/kd7f3yftf7unxlsx?svg=true)](https://ci.appveyor.com/project/isaacs/node-glob) [![Coverage Status](https://coveralls.io/repos/isaacs/node-glob/badge.svg?branch=master&service=github)](https://coveralls.io/github/isaacs/node-glob?branch=master)
This is a glob implementation in JavaScript. It uses the `minimatch`
library to do its matching.
![](logo/glob.png)
## Usage
Install with npm
```
npm i glob
```
```javascript
var glob = require("glob")
// options is optional
glob("**/*.js", options, function (er, files) {
// files is an array of filenames.
// If the `nonull` option is set, and nothing
// was found, then files is ["**/*.js"]
// er is an error object or null.
})
```
## Glob Primer
"Globs" are the patterns you type when you do stuff like `ls *.js` on
the command line, or put `build/*` in a `.gitignore` file.
Before parsing the path part patterns, braced sections are expanded
into a set. Braced sections start with `{` and end with `}`, with any
number of comma-delimited sections within. Braced sections may contain
slash characters, so `a{/b/c,bcd}` would expand into `a/b/c` and `abcd`.
The following characters have special magic meaning when used in a
path portion:
* `*` Matches 0 or more characters in a single path portion
* `?` Matches 1 character
* `[...]` Matches a range of characters, similar to a RegExp range.
If the first character of the range is `!` or `^` then it matches
any character not in the range.
* `!(pattern|pattern|pattern)` Matches anything that does not match
any of the patterns provided.
* `?(pattern|pattern|pattern)` Matches zero or one occurrence of the
patterns provided.
* `+(pattern|pattern|pattern)` Matches one or more occurrences of the
patterns provided.
* `*(a|b|c)` Matches zero or more occurrences of the patterns provided
* `@(pattern|pat*|pat?erN)` Matches exactly one of the patterns
provided
* `**` If a "globstar" is alone in a path portion, then it matches
zero or more directories and subdirectories searching for matches.
It does not crawl symlinked directories.
### Dots
If a file or directory path portion has a `.` as the first character,
then it will not match any glob pattern unless that pattern's
corresponding path part also has a `.` as its first character.
For example, the pattern `a/.*/c` would match the file at `a/.b/c`.
However the pattern `a/*/c` would not, because `*` does not start with
a dot character.
You can make glob treat dots as normal characters by setting
`dot:true` in the options.
### Basename Matching
If you set `matchBase:true` in the options, and the pattern has no
slashes in it, then it will seek for any file anywhere in the tree
with a matching basename. For example, `*.js` would match
`test/simple/basic.js`.
### Empty Sets
If no matching files are found, then an empty array is returned. This
differs from the shell, where the pattern itself is returned. For
example:
$ echo a*s*d*f
a*s*d*f
To get the bash-style behavior, set the `nonull:true` in the options.
### See Also:
* `man sh`
* `man bash` (Search for "Pattern Matching")
* `man 3 fnmatch`
* `man 5 gitignore`
* [minimatch documentation](https://github.com/isaacs/minimatch)
## glob.hasMagic(pattern, [options])
Returns `true` if there are any special characters in the pattern, and
`false` otherwise.
Note that the options affect the results. If `noext:true` is set in
the options object, then `+(a|b)` will not be considered a magic
pattern. If the pattern has a brace expansion, like `a/{b/c,x/y}`
then that is considered magical, unless `nobrace:true` is set in the
options.
## glob(pattern, [options], cb)
* `pattern` `{String}` Pattern to be matched
* `options` `{Object}`
* `cb` `{Function}`
* `err` `{Error | null}`
* `matches` `{Array<String>}` filenames found matching the pattern
Perform an asynchronous glob search.
## glob.sync(pattern, [options])
* `pattern` `{String}` Pattern to be matched
* `options` `{Object}`
* return: `{Array<String>}` filenames found matching the pattern
Perform a synchronous glob search.
## Class: glob.Glob
Create a Glob object by instantiating the `glob.Glob` class.
```javascript
var Glob = require("glob").Glob
var mg = new Glob(pattern, options, cb)
```
It's an EventEmitter, and starts walking the filesystem to find matches
immediately.
### new glob.Glob(pattern, [options], [cb])
* `pattern` `{String}` pattern to search for
* `options` `{Object}`
* `cb` `{Function}` Called when an error occurs, or matches are found
* `err` `{Error | null}`
* `matches` `{Array<String>}` filenames found matching the pattern
Note that if the `sync` flag is set in the options, then matches will
be immediately available on the `g.found` member.
### Properties
* `minimatch` The minimatch object that the glob uses.
* `options` The options object passed in.
* `aborted` Boolean which is set to true when calling `abort()`. There
is no way at this time to continue a glob search after aborting, but
you can re-use the statCache to avoid having to duplicate syscalls.
* `cache` Convenience object. Each field has the following possible
values:
* `false` - Path does not exist
* `true` - Path exists
* `'FILE'` - Path exists, and is not a directory
* `'DIR'` - Path exists, and is a directory
* `[file, entries, ...]` - Path exists, is a directory, and the
array value is the results of `fs.readdir`
* `statCache` Cache of `fs.stat` results, to prevent statting the same
path multiple times.
* `symlinks` A record of which paths are symbolic links, which is
relevant in resolving `**` patterns.
* `realpathCache` An optional object which is passed to `fs.realpath`
to minimize unnecessary syscalls. It is stored on the instantiated
Glob object, and may be re-used.
### Events
* `end` When the matching is finished, this is emitted with all the
matches found. If the `nonull` option is set, and no match was found,
then the `matches` list contains the original pattern. The matches
are sorted, unless the `nosort` flag is set.
* `match` Every time a match is found, this is emitted with the specific
thing that matched. It is not deduplicated or resolved to a realpath.
* `error` Emitted when an unexpected error is encountered, or whenever
any fs error occurs if `options.strict` is set.
* `abort` When `abort()` is called, this event is raised.
### Methods
* `pause` Temporarily stop the search
* `resume` Resume the search
* `abort` Stop the search forever
### Options
All the options that can be passed to Minimatch can also be passed to
Glob to change pattern matching behavior. Also, some have been added,
or have glob-specific ramifications.
All options are false by default, unless otherwise noted.
All options are added to the Glob object, as well.
If you are running many `glob` operations, you can pass a Glob object
as the `options` argument to a subsequent operation to shortcut some
`stat` and `readdir` calls. At the very least, you may pass in shared
`symlinks`, `statCache`, `realpathCache`, and `cache` options, so that
parallel glob operations will be sped up by sharing information about
the filesystem.
* `cwd` The current working directory in which to search. Defaults
to `process.cwd()`.
* `root` The place where patterns starting with `/` will be mounted
onto. Defaults to `path.resolve(options.cwd, "/")` (`/` on Unix
systems, and `C:\` or some such on Windows.)
* `dot` Include `.dot` files in normal matches and `globstar` matches.
Note that an explicit dot in a portion of the pattern will always
match dot files.
* `nomount` By default, a pattern starting with a forward-slash will be
"mounted" onto the root setting, so that a valid filesystem path is
returned. Set this flag to disable that behavior.
* `mark` Add a `/` character to directory matches. Note that this
requires additional stat calls.
* `nosort` Don't sort the results.
* `stat` Set to true to stat *all* results. This reduces performance
somewhat, and is completely unnecessary, unless `readdir` is presumed
to be an untrustworthy indicator of file existence.
* `silent` When an unusual error is encountered when attempting to
read a directory, a warning will be printed to stderr. Set the
`silent` option to true to suppress these warnings.
* `strict` When an unusual error is encountered when attempting to
read a directory, the process will just continue on in search of
other matches. Set the `strict` option to raise an error in these
cases.
* `cache` See `cache` property above. Pass in a previously generated
cache object to save some fs calls.
* `statCache` A cache of results of filesystem information, to prevent
unnecessary stat calls. While it should not normally be necessary
to set this, you may pass the statCache from one glob() call to the
options object of another, if you know that the filesystem will not
change between calls. (See "Race Conditions" below.)
* `symlinks` A cache of known symbolic links. You may pass in a
previously generated `symlinks` object to save `lstat` calls when
resolving `**` matches.
* `sync` DEPRECATED: use `glob.sync(pattern, opts)` instead.
* `nounique` In some cases, brace-expanded patterns can result in the
same file showing up multiple times in the result set. By default,
this implementation prevents duplicates in the result set. Set this
flag to disable that behavior.
* `nonull` Set to never return an empty set, instead returning a set
containing the pattern itself. This is the default in glob(3).
* `debug` Set to enable debug logging in minimatch and glob.
* `nobrace` Do not expand `{a,b}` and `{1..3}` brace sets.
* `noglobstar` Do not match `**` against multiple filenames. (Ie,
treat it as a normal `*` instead.)
* `noext` Do not match `+(a|b)` "extglob" patterns.
* `nocase` Perform a case-insensitive match. Note: on
case-insensitive filesystems, non-magic patterns will match by
default, since `stat` and `readdir` will not raise errors.
* `matchBase` Perform a basename-only match if the pattern does not
contain any slash characters. That is, `*.js` would be treated as
equivalent to `**/*.js`, matching all js files in all directories.
* `nodir` Do not match directories, only files. (Note: to match
*only* directories, simply put a `/` at the end of the pattern.)
* `ignore` Add a pattern or an array of glob patterns to exclude matches.
Note: `ignore` patterns are *always* in `dot:true` mode, regardless
of any other settings.
* `follow` Follow symlinked directories when expanding `**` patterns.
Note that this can result in a lot of duplicate references in the
presence of cyclic links.
* `realpath` Set to true to call `fs.realpath` on all of the results.
In the case of a symlink that cannot be resolved, the full absolute
path to the matched entry is returned (though it will usually be a
broken symlink)
* `absolute` Set to true to always receive absolute paths for matched
files. Unlike `realpath`, this also affects the values returned in
the `match` event.
## Comparisons to other fnmatch/glob implementations
While strict compliance with the existing standards is a worthwhile
goal, some discrepancies exist between node-glob and other
implementations, and are intentional.
The double-star character `**` is supported by default, unless the
`noglobstar` flag is set. This is supported in the manner of bsdglob
and bash 4.3, where `**` only has special significance if it is the only
thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but
`a/**b` will not.
Note that symlinked directories are not crawled as part of a `**`,
though their contents may match against subsequent portions of the
pattern. This prevents infinite loops and duplicates and the like.
If an escaped pattern has no matches, and the `nonull` flag is set,
then glob returns the pattern as-provided, rather than
interpreting the character escapes. For example,
`glob.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than
`"*a?"`. This is akin to setting the `nullglob` option in bash, except
that it does not resolve escaped pattern characters.
If brace expansion is not disabled, then it is performed before any
other interpretation of the glob pattern. Thus, a pattern like
`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded
**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are
checked for validity. Since those two are valid, matching proceeds.
### Comments and Negation
Previously, this module let you mark a pattern as a "comment" if it
started with a `#` character, or a "negated" pattern if it started
with a `!` character.
These options were deprecated in version 5, and removed in version 6.
To specify things that should not match, use the `ignore` option.
## Windows
**Please only use forward-slashes in glob expressions.**
Though windows uses either `/` or `\` as its path separator, only `/`
characters are used by this glob implementation. You must use
forward-slashes **only** in glob expressions. Back-slashes will always
be interpreted as escape characters, not path separators.
Results from absolute patterns such as `/foo/*` are mounted onto the
root setting using `path.join`. On windows, this will by default result
in `/foo/*` matching `C:\foo\bar.txt`.
## Race Conditions
Glob searching, by its very nature, is susceptible to race conditions,
since it relies on directory walking and such.
As a result, it is possible that a file that exists when glob looks for
it may have been deleted or modified by the time it returns the result.
As part of its internal implementation, this program caches all stat
and readdir calls that it makes, in order to cut down on system
overhead. However, this also makes it even more susceptible to races,
especially if the cache or statCache objects are reused between glob
calls.
Users are thus advised not to use a glob result as a guarantee of
filesystem state in the face of rapid changes. For the vast majority
of operations, this is never a problem.
## Glob Logo
Glob's logo was created by [Tanya Brassie](http://tanyabrassie.com/). Logo files can be found [here](https://github.com/isaacs/node-glob/tree/master/logo).
The logo is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/).
## Contributing
Any change to behavior (including bugfixes) must come with a test.
Patches that fail tests or reduce performance will be rejected.
```
# to run tests
npm test
# to re-generate test fixtures
npm run test-regen
# to benchmark against bash/zsh
npm run bench
# to profile javascript
npm run prof
```
![](oh-my-glob.gif)
@@ -0,0 +1,67 @@
## 7.0
- Raise error if `options.cwd` is specified, and not a directory
## 6.0
- Remove comment and negation pattern support
- Ignore patterns are always in `dot:true` mode
## 5.0
- Deprecate comment and negation patterns
- Fix regression in `mark` and `nodir` options from making all cache
keys absolute path.
- Abort if `fs.readdir` returns an error that's unexpected
- Don't emit `match` events for ignored items
- Treat ENOTSUP like ENOTDIR in readdir
## 4.5
- Add `options.follow` to always follow directory symlinks in globstar
- Add `options.realpath` to call `fs.realpath` on all results
- Always cache based on absolute path
## 4.4
- Add `options.ignore`
- Fix handling of broken symlinks
## 4.3
- Bump minimatch to 2.x
- Pass all tests on Windows
## 4.2
- Add `glob.hasMagic` function
- Add `options.nodir` flag
## 4.1
- Refactor sync and async implementations for performance
- Throw if callback provided to sync glob function
- Treat symbolic links in globstar results the same as Bash 4.3
## 4.0
- Use `^` for dependency versions (bumped major because this breaks
older npm versions)
- Ensure callbacks are only ever called once
- switch to ISC license
## 3.x
- Rewrite in JavaScript
- Add support for setting root, cwd, and windows support
- Cache many fs calls
- Add globstar support
- emit match events
## 2.x
- Use `glob.h` and `fnmatch.h` from NetBSD
## 1.x
- `glob.h` static binding.
@@ -0,0 +1,240 @@
exports.alphasort = alphasort
exports.alphasorti = alphasorti
exports.setopts = setopts
exports.ownProp = ownProp
exports.makeAbs = makeAbs
exports.finish = finish
exports.mark = mark
exports.isIgnored = isIgnored
exports.childrenIgnored = childrenIgnored
function ownProp (obj, field) {
return Object.prototype.hasOwnProperty.call(obj, field)
}
var path = require("path")
var minimatch = require("minimatch")
var isAbsolute = require("path-is-absolute")
var Minimatch = minimatch.Minimatch
function alphasorti (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase())
}
function alphasort (a, b) {
return a.localeCompare(b)
}
function setupIgnores (self, options) {
self.ignore = options.ignore || []
if (!Array.isArray(self.ignore))
self.ignore = [self.ignore]
if (self.ignore.length) {
self.ignore = self.ignore.map(ignoreMap)
}
}
// ignore patterns are always in dot:true mode.
function ignoreMap (pattern) {
var gmatcher = null
if (pattern.slice(-3) === '/**') {
var gpattern = pattern.replace(/(\/\*\*)+$/, '')
gmatcher = new Minimatch(gpattern, { dot: true })
}
return {
matcher: new Minimatch(pattern, { dot: true }),
gmatcher: gmatcher
}
}
function setopts (self, pattern, options) {
if (!options)
options = {}
// base-matching: just use globstar for that.
if (options.matchBase && -1 === pattern.indexOf("/")) {
if (options.noglobstar) {
throw new Error("base matching requires globstar")
}
pattern = "**/" + pattern
}
self.silent = !!options.silent
self.pattern = pattern
self.strict = options.strict !== false
self.realpath = !!options.realpath
self.realpathCache = options.realpathCache || Object.create(null)
self.follow = !!options.follow
self.dot = !!options.dot
self.mark = !!options.mark
self.nodir = !!options.nodir
if (self.nodir)
self.mark = true
self.sync = !!options.sync
self.nounique = !!options.nounique
self.nonull = !!options.nonull
self.nosort = !!options.nosort
self.nocase = !!options.nocase
self.stat = !!options.stat
self.noprocess = !!options.noprocess
self.absolute = !!options.absolute
self.maxLength = options.maxLength || Infinity
self.cache = options.cache || Object.create(null)
self.statCache = options.statCache || Object.create(null)
self.symlinks = options.symlinks || Object.create(null)
setupIgnores(self, options)
self.changedCwd = false
var cwd = process.cwd()
if (!ownProp(options, "cwd"))
self.cwd = cwd
else {
self.cwd = path.resolve(options.cwd)
self.changedCwd = self.cwd !== cwd
}
self.root = options.root || path.resolve(self.cwd, "/")
self.root = path.resolve(self.root)
if (process.platform === "win32")
self.root = self.root.replace(/\\/g, "/")
// TODO: is an absolute `cwd` supposed to be resolved against `root`?
// e.g. { cwd: '/test', root: __dirname } === path.join(__dirname, '/test')
self.cwdAbs = isAbsolute(self.cwd) ? self.cwd : makeAbs(self, self.cwd)
if (process.platform === "win32")
self.cwdAbs = self.cwdAbs.replace(/\\/g, "/")
self.nomount = !!options.nomount
// disable comments and negation in Minimatch.
// Note that they are not supported in Glob itself anyway.
options.nonegate = true
options.nocomment = true
self.minimatch = new Minimatch(pattern, options)
self.options = self.minimatch.options
}
function finish (self) {
var nou = self.nounique
var all = nou ? [] : Object.create(null)
for (var i = 0, l = self.matches.length; i < l; i ++) {
var matches = self.matches[i]
if (!matches || Object.keys(matches).length === 0) {
if (self.nonull) {
// do like the shell, and spit out the literal glob
var literal = self.minimatch.globSet[i]
if (nou)
all.push(literal)
else
all[literal] = true
}
} else {
// had matches
var m = Object.keys(matches)
if (nou)
all.push.apply(all, m)
else
m.forEach(function (m) {
all[m] = true
})
}
}
if (!nou)
all = Object.keys(all)
if (!self.nosort)
all = all.sort(self.nocase ? alphasorti : alphasort)
// at *some* point we statted all of these
if (self.mark) {
for (var i = 0; i < all.length; i++) {
all[i] = self._mark(all[i])
}
if (self.nodir) {
all = all.filter(function (e) {
var notDir = !(/\/$/.test(e))
var c = self.cache[e] || self.cache[makeAbs(self, e)]
if (notDir && c)
notDir = c !== 'DIR' && !Array.isArray(c)
return notDir
})
}
}
if (self.ignore.length)
all = all.filter(function(m) {
return !isIgnored(self, m)
})
self.found = all
}
function mark (self, p) {
var abs = makeAbs(self, p)
var c = self.cache[abs]
var m = p
if (c) {
var isDir = c === 'DIR' || Array.isArray(c)
var slash = p.slice(-1) === '/'
if (isDir && !slash)
m += '/'
else if (!isDir && slash)
m = m.slice(0, -1)
if (m !== p) {
var mabs = makeAbs(self, m)
self.statCache[mabs] = self.statCache[abs]
self.cache[mabs] = self.cache[abs]
}
}
return m
}
// lotta situps...
function makeAbs (self, f) {
var abs = f
if (f.charAt(0) === '/') {
abs = path.join(self.root, f)
} else if (isAbsolute(f) || f === '') {
abs = f
} else if (self.changedCwd) {
abs = path.resolve(self.cwd, f)
} else {
abs = path.resolve(f)
}
if (process.platform === 'win32')
abs = abs.replace(/\\/g, '/')
return abs
}
// Return true, if pattern ends with globstar '**', for the accompanying parent directory.
// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents
function isIgnored (self, path) {
if (!self.ignore.length)
return false
return self.ignore.some(function(item) {
return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path))
})
}
function childrenIgnored (self, path) {
if (!self.ignore.length)
return false
return self.ignore.some(function(item) {
return !!(item.gmatcher && item.gmatcher.match(path))
})
}
@@ -0,0 +1,790 @@
// Approach:
//
// 1. Get the minimatch set
// 2. For each pattern in the set, PROCESS(pattern, false)
// 3. Store matches per-set, then uniq them
//
// PROCESS(pattern, inGlobStar)
// Get the first [n] items from pattern that are all strings
// Join these together. This is PREFIX.
// If there is no more remaining, then stat(PREFIX) and
// add to matches if it succeeds. END.
//
// If inGlobStar and PREFIX is symlink and points to dir
// set ENTRIES = []
// else readdir(PREFIX) as ENTRIES
// If fail, END
//
// with ENTRIES
// If pattern[n] is GLOBSTAR
// // handle the case where the globstar match is empty
// // by pruning it out, and testing the resulting pattern
// PROCESS(pattern[0..n] + pattern[n+1 .. $], false)
// // handle other cases.
// for ENTRY in ENTRIES (not dotfiles)
// // attach globstar + tail onto the entry
// // Mark that this entry is a globstar match
// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true)
//
// else // not globstar
// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot)
// Test ENTRY against pattern[n]
// If fails, continue
// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $])
//
// Caveat:
// Cache all stats and readdirs results to minimize syscall. Since all
// we ever care about is existence and directory-ness, we can just keep
// `true` for files, and [children,...] for directories, or `false` for
// things that don't exist.
module.exports = glob
var fs = require('fs')
var rp = require('fs.realpath')
var minimatch = require('minimatch')
var Minimatch = minimatch.Minimatch
var inherits = require('inherits')
var EE = require('events').EventEmitter
var path = require('path')
var assert = require('assert')
var isAbsolute = require('path-is-absolute')
var globSync = require('./sync.js')
var common = require('./common.js')
var alphasort = common.alphasort
var alphasorti = common.alphasorti
var setopts = common.setopts
var ownProp = common.ownProp
var inflight = require('inflight')
var util = require('util')
var childrenIgnored = common.childrenIgnored
var isIgnored = common.isIgnored
var once = require('once')
function glob (pattern, options, cb) {
if (typeof options === 'function') cb = options, options = {}
if (!options) options = {}
if (options.sync) {
if (cb)
throw new TypeError('callback provided to sync glob')
return globSync(pattern, options)
}
return new Glob(pattern, options, cb)
}
glob.sync = globSync
var GlobSync = glob.GlobSync = globSync.GlobSync
// old api surface
glob.glob = glob
function extend (origin, add) {
if (add === null || typeof add !== 'object') {
return origin
}
var keys = Object.keys(add)
var i = keys.length
while (i--) {
origin[keys[i]] = add[keys[i]]
}
return origin
}
glob.hasMagic = function (pattern, options_) {
var options = extend({}, options_)
options.noprocess = true
var g = new Glob(pattern, options)
var set = g.minimatch.set
if (!pattern)
return false
if (set.length > 1)
return true
for (var j = 0; j < set[0].length; j++) {
if (typeof set[0][j] !== 'string')
return true
}
return false
}
glob.Glob = Glob
inherits(Glob, EE)
function Glob (pattern, options, cb) {
if (typeof options === 'function') {
cb = options
options = null
}
if (options && options.sync) {
if (cb)
throw new TypeError('callback provided to sync glob')
return new GlobSync(pattern, options)
}
if (!(this instanceof Glob))
return new Glob(pattern, options, cb)
setopts(this, pattern, options)
this._didRealPath = false
// process each pattern in the minimatch set
var n = this.minimatch.set.length
// The matches are stored as {<filename>: true,...} so that
// duplicates are automagically pruned.
// Later, we do an Object.keys() on these.
// Keep them as a list so we can fill in when nonull is set.
this.matches = new Array(n)
if (typeof cb === 'function') {
cb = once(cb)
this.on('error', cb)
this.on('end', function (matches) {
cb(null, matches)
})
}
var self = this
this._processing = 0
this._emitQueue = []
this._processQueue = []
this.paused = false
if (this.noprocess)
return this
if (n === 0)
return done()
var sync = true
for (var i = 0; i < n; i ++) {
this._process(this.minimatch.set[i], i, false, done)
}
sync = false
function done () {
--self._processing
if (self._processing <= 0) {
if (sync) {
process.nextTick(function () {
self._finish()
})
} else {
self._finish()
}
}
}
}
Glob.prototype._finish = function () {
assert(this instanceof Glob)
if (this.aborted)
return
if (this.realpath && !this._didRealpath)
return this._realpath()
common.finish(this)
this.emit('end', this.found)
}
Glob.prototype._realpath = function () {
if (this._didRealpath)
return
this._didRealpath = true
var n = this.matches.length
if (n === 0)
return this._finish()
var self = this
for (var i = 0; i < this.matches.length; i++)
this._realpathSet(i, next)
function next () {
if (--n === 0)
self._finish()
}
}
Glob.prototype._realpathSet = function (index, cb) {
var matchset = this.matches[index]
if (!matchset)
return cb()
var found = Object.keys(matchset)
var self = this
var n = found.length
if (n === 0)
return cb()
var set = this.matches[index] = Object.create(null)
found.forEach(function (p, i) {
// If there's a problem with the stat, then it means that
// one or more of the links in the realpath couldn't be
// resolved. just return the abs value in that case.
p = self._makeAbs(p)
rp.realpath(p, self.realpathCache, function (er, real) {
if (!er)
set[real] = true
else if (er.syscall === 'stat')
set[p] = true
else
self.emit('error', er) // srsly wtf right here
if (--n === 0) {
self.matches[index] = set
cb()
}
})
})
}
Glob.prototype._mark = function (p) {
return common.mark(this, p)
}
Glob.prototype._makeAbs = function (f) {
return common.makeAbs(this, f)
}
Glob.prototype.abort = function () {
this.aborted = true
this.emit('abort')
}
Glob.prototype.pause = function () {
if (!this.paused) {
this.paused = true
this.emit('pause')
}
}
Glob.prototype.resume = function () {
if (this.paused) {
this.emit('resume')
this.paused = false
if (this._emitQueue.length) {
var eq = this._emitQueue.slice(0)
this._emitQueue.length = 0
for (var i = 0; i < eq.length; i ++) {
var e = eq[i]
this._emitMatch(e[0], e[1])
}
}
if (this._processQueue.length) {
var pq = this._processQueue.slice(0)
this._processQueue.length = 0
for (var i = 0; i < pq.length; i ++) {
var p = pq[i]
this._processing--
this._process(p[0], p[1], p[2], p[3])
}
}
}
}
Glob.prototype._process = function (pattern, index, inGlobStar, cb) {
assert(this instanceof Glob)
assert(typeof cb === 'function')
if (this.aborted)
return
this._processing++
if (this.paused) {
this._processQueue.push([pattern, index, inGlobStar, cb])
return
}
//console.error('PROCESS %d', this._processing, pattern)
// Get the first [n] parts of pattern that are all strings.
var n = 0
while (typeof pattern[n] === 'string') {
n ++
}
// now n is the index of the first one that is *not* a string.
// see if there's anything else
var prefix
switch (n) {
// if not, then this is rather simple
case pattern.length:
this._processSimple(pattern.join('/'), index, cb)
return
case 0:
// pattern *starts* with some non-trivial item.
// going to readdir(cwd), but not include the prefix in matches.
prefix = null
break
default:
// pattern has some string bits in the front.
// whatever it starts with, whether that's 'absolute' like /foo/bar,
// or 'relative' like '../baz'
prefix = pattern.slice(0, n).join('/')
break
}
var remain = pattern.slice(n)
// get the list of entries.
var read
if (prefix === null)
read = '.'
else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) {
if (!prefix || !isAbsolute(prefix))
prefix = '/' + prefix
read = prefix
} else
read = prefix
var abs = this._makeAbs(read)
//if ignored, skip _processing
if (childrenIgnored(this, read))
return cb()
var isGlobStar = remain[0] === minimatch.GLOBSTAR
if (isGlobStar)
this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb)
else
this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb)
}
Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) {
var self = this
this._readdir(abs, inGlobStar, function (er, entries) {
return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb)
})
}
Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) {
// if the abs isn't a dir, then nothing can match!
if (!entries)
return cb()
// It will only match dot entries if it starts with a dot, or if
// dot is set. Stuff like @(.foo|.bar) isn't allowed.
var pn = remain[0]
var negate = !!this.minimatch.negate
var rawGlob = pn._glob
var dotOk = this.dot || rawGlob.charAt(0) === '.'
var matchedEntries = []
for (var i = 0; i < entries.length; i++) {
var e = entries[i]
if (e.charAt(0) !== '.' || dotOk) {
var m
if (negate && !prefix) {
m = !e.match(pn)
} else {
m = e.match(pn)
}
if (m)
matchedEntries.push(e)
}
}
//console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries)
var len = matchedEntries.length
// If there are no matched entries, then nothing matches.
if (len === 0)
return cb()
// if this is the last remaining pattern bit, then no need for
// an additional stat *unless* the user has specified mark or
// stat explicitly. We know they exist, since readdir returned
// them.
if (remain.length === 1 && !this.mark && !this.stat) {
if (!this.matches[index])
this.matches[index] = Object.create(null)
for (var i = 0; i < len; i ++) {
var e = matchedEntries[i]
if (prefix) {
if (prefix !== '/')
e = prefix + '/' + e
else
e = prefix + e
}
if (e.charAt(0) === '/' && !this.nomount) {
e = path.join(this.root, e)
}
this._emitMatch(index, e)
}
// This was the last one, and no stats were needed
return cb()
}
// now test all matched entries as stand-ins for that part
// of the pattern.
remain.shift()
for (var i = 0; i < len; i ++) {
var e = matchedEntries[i]
var newPattern
if (prefix) {
if (prefix !== '/')
e = prefix + '/' + e
else
e = prefix + e
}
this._process([e].concat(remain), index, inGlobStar, cb)
}
cb()
}
Glob.prototype._emitMatch = function (index, e) {
if (this.aborted)
return
if (isIgnored(this, e))
return
if (this.paused) {
this._emitQueue.push([index, e])
return
}
var abs = isAbsolute(e) ? e : this._makeAbs(e)
if (this.mark)
e = this._mark(e)
if (this.absolute)
e = abs
if (this.matches[index][e])
return
if (this.nodir) {
var c = this.cache[abs]
if (c === 'DIR' || Array.isArray(c))
return
}
this.matches[index][e] = true
var st = this.statCache[abs]
if (st)
this.emit('stat', e, st)
this.emit('match', e)
}
Glob.prototype._readdirInGlobStar = function (abs, cb) {
if (this.aborted)
return
// follow all symlinked directories forever
// just proceed as if this is a non-globstar situation
if (this.follow)
return this._readdir(abs, false, cb)
var lstatkey = 'lstat\0' + abs
var self = this
var lstatcb = inflight(lstatkey, lstatcb_)
if (lstatcb)
fs.lstat(abs, lstatcb)
function lstatcb_ (er, lstat) {
if (er && er.code === 'ENOENT')
return cb()
var isSym = lstat && lstat.isSymbolicLink()
self.symlinks[abs] = isSym
// If it's not a symlink or a dir, then it's definitely a regular file.
// don't bother doing a readdir in that case.
if (!isSym && lstat && !lstat.isDirectory()) {
self.cache[abs] = 'FILE'
cb()
} else
self._readdir(abs, false, cb)
}
}
Glob.prototype._readdir = function (abs, inGlobStar, cb) {
if (this.aborted)
return
cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb)
if (!cb)
return
//console.error('RD %j %j', +inGlobStar, abs)
if (inGlobStar && !ownProp(this.symlinks, abs))
return this._readdirInGlobStar(abs, cb)
if (ownProp(this.cache, abs)) {
var c = this.cache[abs]
if (!c || c === 'FILE')
return cb()
if (Array.isArray(c))
return cb(null, c)
}
var self = this
fs.readdir(abs, readdirCb(this, abs, cb))
}
function readdirCb (self, abs, cb) {
return function (er, entries) {
if (er)
self._readdirError(abs, er, cb)
else
self._readdirEntries(abs, entries, cb)
}
}
Glob.prototype._readdirEntries = function (abs, entries, cb) {
if (this.aborted)
return
// if we haven't asked to stat everything, then just
// assume that everything in there exists, so we can avoid
// having to stat it a second time.
if (!this.mark && !this.stat) {
for (var i = 0; i < entries.length; i ++) {
var e = entries[i]
if (abs === '/')
e = abs + e
else
e = abs + '/' + e
this.cache[e] = true
}
}
this.cache[abs] = entries
return cb(null, entries)
}
Glob.prototype._readdirError = function (f, er, cb) {
if (this.aborted)
return
// handle errors, and cache the information
switch (er.code) {
case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205
case 'ENOTDIR': // totally normal. means it *does* exist.
var abs = this._makeAbs(f)
this.cache[abs] = 'FILE'
if (abs === this.cwdAbs) {
var error = new Error(er.code + ' invalid cwd ' + this.cwd)
error.path = this.cwd
error.code = er.code
this.emit('error', error)
this.abort()
}
break
case 'ENOENT': // not terribly unusual
case 'ELOOP':
case 'ENAMETOOLONG':
case 'UNKNOWN':
this.cache[this._makeAbs(f)] = false
break
default: // some unusual error. Treat as failure.
this.cache[this._makeAbs(f)] = false
if (this.strict) {
this.emit('error', er)
// If the error is handled, then we abort
// if not, we threw out of here
this.abort()
}
if (!this.silent)
console.error('glob error', er)
break
}
return cb()
}
Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) {
var self = this
this._readdir(abs, inGlobStar, function (er, entries) {
self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb)
})
}
Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) {
//console.error('pgs2', prefix, remain[0], entries)
// no entries means not a dir, so it can never have matches
// foo.txt/** doesn't match foo.txt
if (!entries)
return cb()
// test without the globstar, and with every child both below
// and replacing the globstar.
var remainWithoutGlobStar = remain.slice(1)
var gspref = prefix ? [ prefix ] : []
var noGlobStar = gspref.concat(remainWithoutGlobStar)
// the noGlobStar pattern exits the inGlobStar state
this._process(noGlobStar, index, false, cb)
var isSym = this.symlinks[abs]
var len = entries.length
// If it's a symlink, and we're in a globstar, then stop
if (isSym && inGlobStar)
return cb()
for (var i = 0; i < len; i++) {
var e = entries[i]
if (e.charAt(0) === '.' && !this.dot)
continue
// these two cases enter the inGlobStar state
var instead = gspref.concat(entries[i], remainWithoutGlobStar)
this._process(instead, index, true, cb)
var below = gspref.concat(entries[i], remain)
this._process(below, index, true, cb)
}
cb()
}
Glob.prototype._processSimple = function (prefix, index, cb) {
// XXX review this. Shouldn't it be doing the mounting etc
// before doing stat? kinda weird?
var self = this
this._stat(prefix, function (er, exists) {
self._processSimple2(prefix, index, er, exists, cb)
})
}
Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) {
//console.error('ps2', prefix, exists)
if (!this.matches[index])
this.matches[index] = Object.create(null)
// If it doesn't exist, then just mark the lack of results
if (!exists)
return cb()
if (prefix && isAbsolute(prefix) && !this.nomount) {
var trail = /[\/\\]$/.test(prefix)
if (prefix.charAt(0) === '/') {
prefix = path.join(this.root, prefix)
} else {
prefix = path.resolve(this.root, prefix)
if (trail)
prefix += '/'
}
}
if (process.platform === 'win32')
prefix = prefix.replace(/\\/g, '/')
// Mark this as a match
this._emitMatch(index, prefix)
cb()
}
// Returns either 'DIR', 'FILE', or false
Glob.prototype._stat = function (f, cb) {
var abs = this._makeAbs(f)
var needDir = f.slice(-1) === '/'
if (f.length > this.maxLength)
return cb()
if (!this.stat && ownProp(this.cache, abs)) {
var c = this.cache[abs]
if (Array.isArray(c))
c = 'DIR'
// It exists, but maybe not how we need it
if (!needDir || c === 'DIR')
return cb(null, c)
if (needDir && c === 'FILE')
return cb()
// otherwise we have to stat, because maybe c=true
// if we know it exists, but not what it is.
}
var exists
var stat = this.statCache[abs]
if (stat !== undefined) {
if (stat === false)
return cb(null, stat)
else {
var type = stat.isDirectory() ? 'DIR' : 'FILE'
if (needDir && type === 'FILE')
return cb()
else
return cb(null, type, stat)
}
}
var self = this
var statcb = inflight('stat\0' + abs, lstatcb_)
if (statcb)
fs.lstat(abs, statcb)
function lstatcb_ (er, lstat) {
if (lstat && lstat.isSymbolicLink()) {
// If it's a symlink, then treat it as the target, unless
// the target does not exist, then treat it as a file.
return fs.stat(abs, function (er, stat) {
if (er)
self._stat2(f, abs, null, lstat, cb)
else
self._stat2(f, abs, er, stat, cb)
})
} else {
self._stat2(f, abs, er, lstat, cb)
}
}
}
Glob.prototype._stat2 = function (f, abs, er, stat, cb) {
if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) {
this.statCache[abs] = false
return cb()
}
var needDir = f.slice(-1) === '/'
this.statCache[abs] = stat
if (abs.slice(-1) === '/' && stat && !stat.isDirectory())
return cb(null, false, stat)
var c = true
if (stat)
c = stat.isDirectory() ? 'DIR' : 'FILE'
this.cache[abs] = this.cache[abs] || c
if (needDir && c === 'FILE')
return cb()
return cb(null, c, stat)
}
@@ -0,0 +1,46 @@
{
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"name": "glob",
"description": "a little globber",
"version": "7.1.6",
"repository": {
"type": "git",
"url": "git://github.com/isaacs/node-glob.git"
},
"main": "glob.js",
"files": [
"glob.js",
"sync.js",
"common.js"
],
"engines": {
"node": "*"
},
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"devDependencies": {
"mkdirp": "0",
"rimraf": "^2.2.8",
"tap": "^12.0.1",
"tick": "0.0.6"
},
"scripts": {
"prepublish": "npm run benchclean",
"profclean": "rm -f v8.log profile.txt",
"test": "tap test/*.js --cov",
"test-regen": "npm run profclean && TEST_REGEN=1 node test/00-setup.js",
"bench": "bash benchmark.sh",
"prof": "bash prof.sh && cat profile.txt",
"benchclean": "node benchclean.js"
},
"license": "ISC",
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
}
@@ -0,0 +1,486 @@
module.exports = globSync
globSync.GlobSync = GlobSync
var fs = require('fs')
var rp = require('fs.realpath')
var minimatch = require('minimatch')
var Minimatch = minimatch.Minimatch
var Glob = require('./glob.js').Glob
var util = require('util')
var path = require('path')
var assert = require('assert')
var isAbsolute = require('path-is-absolute')
var common = require('./common.js')
var alphasort = common.alphasort
var alphasorti = common.alphasorti
var setopts = common.setopts
var ownProp = common.ownProp
var childrenIgnored = common.childrenIgnored
var isIgnored = common.isIgnored
function globSync (pattern, options) {
if (typeof options === 'function' || arguments.length === 3)
throw new TypeError('callback provided to sync glob\n'+
'See: https://github.com/isaacs/node-glob/issues/167')
return new GlobSync(pattern, options).found
}
function GlobSync (pattern, options) {
if (!pattern)
throw new Error('must provide pattern')
if (typeof options === 'function' || arguments.length === 3)
throw new TypeError('callback provided to sync glob\n'+
'See: https://github.com/isaacs/node-glob/issues/167')
if (!(this instanceof GlobSync))
return new GlobSync(pattern, options)
setopts(this, pattern, options)
if (this.noprocess)
return this
var n = this.minimatch.set.length
this.matches = new Array(n)
for (var i = 0; i < n; i ++) {
this._process(this.minimatch.set[i], i, false)
}
this._finish()
}
GlobSync.prototype._finish = function () {
assert(this instanceof GlobSync)
if (this.realpath) {
var self = this
this.matches.forEach(function (matchset, index) {
var set = self.matches[index] = Object.create(null)
for (var p in matchset) {
try {
p = self._makeAbs(p)
var real = rp.realpathSync(p, self.realpathCache)
set[real] = true
} catch (er) {
if (er.syscall === 'stat')
set[self._makeAbs(p)] = true
else
throw er
}
}
})
}
common.finish(this)
}
GlobSync.prototype._process = function (pattern, index, inGlobStar) {
assert(this instanceof GlobSync)
// Get the first [n] parts of pattern that are all strings.
var n = 0
while (typeof pattern[n] === 'string') {
n ++
}
// now n is the index of the first one that is *not* a string.
// See if there's anything else
var prefix
switch (n) {
// if not, then this is rather simple
case pattern.length:
this._processSimple(pattern.join('/'), index)
return
case 0:
// pattern *starts* with some non-trivial item.
// going to readdir(cwd), but not include the prefix in matches.
prefix = null
break
default:
// pattern has some string bits in the front.
// whatever it starts with, whether that's 'absolute' like /foo/bar,
// or 'relative' like '../baz'
prefix = pattern.slice(0, n).join('/')
break
}
var remain = pattern.slice(n)
// get the list of entries.
var read
if (prefix === null)
read = '.'
else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) {
if (!prefix || !isAbsolute(prefix))
prefix = '/' + prefix
read = prefix
} else
read = prefix
var abs = this._makeAbs(read)
//if ignored, skip processing
if (childrenIgnored(this, read))
return
var isGlobStar = remain[0] === minimatch.GLOBSTAR
if (isGlobStar)
this._processGlobStar(prefix, read, abs, remain, index, inGlobStar)
else
this._processReaddir(prefix, read, abs, remain, index, inGlobStar)
}
GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) {
var entries = this._readdir(abs, inGlobStar)
// if the abs isn't a dir, then nothing can match!
if (!entries)
return
// It will only match dot entries if it starts with a dot, or if
// dot is set. Stuff like @(.foo|.bar) isn't allowed.
var pn = remain[0]
var negate = !!this.minimatch.negate
var rawGlob = pn._glob
var dotOk = this.dot || rawGlob.charAt(0) === '.'
var matchedEntries = []
for (var i = 0; i < entries.length; i++) {
var e = entries[i]
if (e.charAt(0) !== '.' || dotOk) {
var m
if (negate && !prefix) {
m = !e.match(pn)
} else {
m = e.match(pn)
}
if (m)
matchedEntries.push(e)
}
}
var len = matchedEntries.length
// If there are no matched entries, then nothing matches.
if (len === 0)
return
// if this is the last remaining pattern bit, then no need for
// an additional stat *unless* the user has specified mark or
// stat explicitly. We know they exist, since readdir returned
// them.
if (remain.length === 1 && !this.mark && !this.stat) {
if (!this.matches[index])
this.matches[index] = Object.create(null)
for (var i = 0; i < len; i ++) {
var e = matchedEntries[i]
if (prefix) {
if (prefix.slice(-1) !== '/')
e = prefix + '/' + e
else
e = prefix + e
}
if (e.charAt(0) === '/' && !this.nomount) {
e = path.join(this.root, e)
}
this._emitMatch(index, e)
}
// This was the last one, and no stats were needed
return
}
// now test all matched entries as stand-ins for that part
// of the pattern.
remain.shift()
for (var i = 0; i < len; i ++) {
var e = matchedEntries[i]
var newPattern
if (prefix)
newPattern = [prefix, e]
else
newPattern = [e]
this._process(newPattern.concat(remain), index, inGlobStar)
}
}
GlobSync.prototype._emitMatch = function (index, e) {
if (isIgnored(this, e))
return
var abs = this._makeAbs(e)
if (this.mark)
e = this._mark(e)
if (this.absolute) {
e = abs
}
if (this.matches[index][e])
return
if (this.nodir) {
var c = this.cache[abs]
if (c === 'DIR' || Array.isArray(c))
return
}
this.matches[index][e] = true
if (this.stat)
this._stat(e)
}
GlobSync.prototype._readdirInGlobStar = function (abs) {
// follow all symlinked directories forever
// just proceed as if this is a non-globstar situation
if (this.follow)
return this._readdir(abs, false)
var entries
var lstat
var stat
try {
lstat = fs.lstatSync(abs)
} catch (er) {
if (er.code === 'ENOENT') {
// lstat failed, doesn't exist
return null
}
}
var isSym = lstat && lstat.isSymbolicLink()
this.symlinks[abs] = isSym
// If it's not a symlink or a dir, then it's definitely a regular file.
// don't bother doing a readdir in that case.
if (!isSym && lstat && !lstat.isDirectory())
this.cache[abs] = 'FILE'
else
entries = this._readdir(abs, false)
return entries
}
GlobSync.prototype._readdir = function (abs, inGlobStar) {
var entries
if (inGlobStar && !ownProp(this.symlinks, abs))
return this._readdirInGlobStar(abs)
if (ownProp(this.cache, abs)) {
var c = this.cache[abs]
if (!c || c === 'FILE')
return null
if (Array.isArray(c))
return c
}
try {
return this._readdirEntries(abs, fs.readdirSync(abs))
} catch (er) {
this._readdirError(abs, er)
return null
}
}
GlobSync.prototype._readdirEntries = function (abs, entries) {
// if we haven't asked to stat everything, then just
// assume that everything in there exists, so we can avoid
// having to stat it a second time.
if (!this.mark && !this.stat) {
for (var i = 0; i < entries.length; i ++) {
var e = entries[i]
if (abs === '/')
e = abs + e
else
e = abs + '/' + e
this.cache[e] = true
}
}
this.cache[abs] = entries
// mark and cache dir-ness
return entries
}
GlobSync.prototype._readdirError = function (f, er) {
// handle errors, and cache the information
switch (er.code) {
case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205
case 'ENOTDIR': // totally normal. means it *does* exist.
var abs = this._makeAbs(f)
this.cache[abs] = 'FILE'
if (abs === this.cwdAbs) {
var error = new Error(er.code + ' invalid cwd ' + this.cwd)
error.path = this.cwd
error.code = er.code
throw error
}
break
case 'ENOENT': // not terribly unusual
case 'ELOOP':
case 'ENAMETOOLONG':
case 'UNKNOWN':
this.cache[this._makeAbs(f)] = false
break
default: // some unusual error. Treat as failure.
this.cache[this._makeAbs(f)] = false
if (this.strict)
throw er
if (!this.silent)
console.error('glob error', er)
break
}
}
GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) {
var entries = this._readdir(abs, inGlobStar)
// no entries means not a dir, so it can never have matches
// foo.txt/** doesn't match foo.txt
if (!entries)
return
// test without the globstar, and with every child both below
// and replacing the globstar.
var remainWithoutGlobStar = remain.slice(1)
var gspref = prefix ? [ prefix ] : []
var noGlobStar = gspref.concat(remainWithoutGlobStar)
// the noGlobStar pattern exits the inGlobStar state
this._process(noGlobStar, index, false)
var len = entries.length
var isSym = this.symlinks[abs]
// If it's a symlink, and we're in a globstar, then stop
if (isSym && inGlobStar)
return
for (var i = 0; i < len; i++) {
var e = entries[i]
if (e.charAt(0) === '.' && !this.dot)
continue
// these two cases enter the inGlobStar state
var instead = gspref.concat(entries[i], remainWithoutGlobStar)
this._process(instead, index, true)
var below = gspref.concat(entries[i], remain)
this._process(below, index, true)
}
}
GlobSync.prototype._processSimple = function (prefix, index) {
// XXX review this. Shouldn't it be doing the mounting etc
// before doing stat? kinda weird?
var exists = this._stat(prefix)
if (!this.matches[index])
this.matches[index] = Object.create(null)
// If it doesn't exist, then just mark the lack of results
if (!exists)
return
if (prefix && isAbsolute(prefix) && !this.nomount) {
var trail = /[\/\\]$/.test(prefix)
if (prefix.charAt(0) === '/') {
prefix = path.join(this.root, prefix)
} else {
prefix = path.resolve(this.root, prefix)
if (trail)
prefix += '/'
}
}
if (process.platform === 'win32')
prefix = prefix.replace(/\\/g, '/')
// Mark this as a match
this._emitMatch(index, prefix)
}
// Returns either 'DIR', 'FILE', or false
GlobSync.prototype._stat = function (f) {
var abs = this._makeAbs(f)
var needDir = f.slice(-1) === '/'
if (f.length > this.maxLength)
return false
if (!this.stat && ownProp(this.cache, abs)) {
var c = this.cache[abs]
if (Array.isArray(c))
c = 'DIR'
// It exists, but maybe not how we need it
if (!needDir || c === 'DIR')
return c
if (needDir && c === 'FILE')
return false
// otherwise we have to stat, because maybe c=true
// if we know it exists, but not what it is.
}
var exists
var stat = this.statCache[abs]
if (!stat) {
var lstat
try {
lstat = fs.lstatSync(abs)
} catch (er) {
if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) {
this.statCache[abs] = false
return false
}
}
if (lstat && lstat.isSymbolicLink()) {
try {
stat = fs.statSync(abs)
} catch (er) {
stat = lstat
}
} else {
stat = lstat
}
}
this.statCache[abs] = stat
var c = true
if (stat)
c = stat.isDirectory() ? 'DIR' : 'FILE'
this.cache[abs] = this.cache[abs] || c
if (needDir && c === 'FILE')
return false
return c
}
GlobSync.prototype._mark = function (p) {
return common.mark(this, p)
}
GlobSync.prototype._makeAbs = function (f) {
return common.makeAbs(this, f)
}
@@ -0,0 +1,15 @@
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,230 @@
# minimatch
A minimal matching utility.
[![Build Status](https://travis-ci.org/isaacs/minimatch.svg?branch=master)](http://travis-ci.org/isaacs/minimatch)
This is the matching library used internally by npm.
It works by converting glob expressions into JavaScript `RegExp`
objects.
## Usage
```javascript
var minimatch = require("minimatch")
minimatch("bar.foo", "*.foo") // true!
minimatch("bar.foo", "*.bar") // false!
minimatch("bar.foo", "*.+(bar|foo)", { debug: true }) // true, and noisy!
```
## Features
Supports these glob features:
* Brace Expansion
* Extended glob matching
* "Globstar" `**` matching
See:
* `man sh`
* `man bash`
* `man 3 fnmatch`
* `man 5 gitignore`
## Minimatch Class
Create a minimatch object by instantiating the `minimatch.Minimatch` class.
```javascript
var Minimatch = require("minimatch").Minimatch
var mm = new Minimatch(pattern, options)
```
### Properties
* `pattern` The original pattern the minimatch object represents.
* `options` The options supplied to the constructor.
* `set` A 2-dimensional array of regexp or string expressions.
Each row in the
array corresponds to a brace-expanded pattern. Each item in the row
corresponds to a single path-part. For example, the pattern
`{a,b/c}/d` would expand to a set of patterns like:
[ [ a, d ]
, [ b, c, d ] ]
If a portion of the pattern doesn't have any "magic" in it
(that is, it's something like `"foo"` rather than `fo*o?`), then it
will be left as a string rather than converted to a regular
expression.
* `regexp` Created by the `makeRe` method. A single regular expression
expressing the entire pattern. This is useful in cases where you wish
to use the pattern somewhat like `fnmatch(3)` with `FNM_PATH` enabled.
* `negate` True if the pattern is negated.
* `comment` True if the pattern is a comment.
* `empty` True if the pattern is `""`.
### Methods
* `makeRe` Generate the `regexp` member if necessary, and return it.
Will return `false` if the pattern is invalid.
* `match(fname)` Return true if the filename matches the pattern, or
false otherwise.
* `matchOne(fileArray, patternArray, partial)` Take a `/`-split
filename, and match it against a single row in the `regExpSet`. This
method is mainly for internal use, but is exposed so that it can be
used by a glob-walker that needs to avoid excessive filesystem calls.
All other methods are internal, and will be called as necessary.
### minimatch(path, pattern, options)
Main export. Tests a path against the pattern using the options.
```javascript
var isJS = minimatch(file, "*.js", { matchBase: true })
```
### minimatch.filter(pattern, options)
Returns a function that tests its
supplied argument, suitable for use with `Array.filter`. Example:
```javascript
var javascripts = fileList.filter(minimatch.filter("*.js", {matchBase: true}))
```
### minimatch.match(list, pattern, options)
Match against the list of
files, in the style of fnmatch or glob. If nothing is matched, and
options.nonull is set, then return a list containing the pattern itself.
```javascript
var javascripts = minimatch.match(fileList, "*.js", {matchBase: true}))
```
### minimatch.makeRe(pattern, options)
Make a regular expression object from the pattern.
## Options
All options are `false` by default.
### debug
Dump a ton of stuff to stderr.
### nobrace
Do not expand `{a,b}` and `{1..3}` brace sets.
### noglobstar
Disable `**` matching against multiple folder names.
### dot
Allow patterns to match filenames starting with a period, even if
the pattern does not explicitly have a period in that spot.
Note that by default, `a/**/b` will **not** match `a/.d/b`, unless `dot`
is set.
### noext
Disable "extglob" style patterns like `+(a|b)`.
### nocase
Perform a case-insensitive match.
### nonull
When a match is not found by `minimatch.match`, return a list containing
the pattern itself if this option is set. When not set, an empty list
is returned if there are no matches.
### matchBase
If set, then patterns without slashes will be matched
against the basename of the path if it contains slashes. For example,
`a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`.
### nocomment
Suppress the behavior of treating `#` at the start of a pattern as a
comment.
### nonegate
Suppress the behavior of treating a leading `!` character as negation.
### flipNegate
Returns from negate expressions the same as if they were not negated.
(Ie, true on a hit, false on a miss.)
### partial
Compare a partial path to a pattern. As long as the parts of the path that
are present are not contradicted by the pattern, it will be treated as a
match. This is useful in applications where you're walking through a
folder structure, and don't yet have the full path, but want to ensure that
you do not walk down paths that can never be a match.
For example,
```js
minimatch('/a/b', '/a/*/c/d', { partial: true }) // true, might be /a/b/c/d
minimatch('/a/b', '/**/d', { partial: true }) // true, might be /a/b/.../d
minimatch('/x/y/z', '/a/**/z', { partial: true }) // false, because x !== a
```
### allowWindowsEscape
Windows path separator `\` is by default converted to `/`, which
prohibits the usage of `\` as a escape character. This flag skips that
behavior and allows using the escape character.
## Comparisons to other fnmatch/glob implementations
While strict compliance with the existing standards is a worthwhile
goal, some discrepancies exist between minimatch and other
implementations, and are intentional.
If the pattern starts with a `!` character, then it is negated. Set the
`nonegate` flag to suppress this behavior, and treat leading `!`
characters normally. This is perhaps relevant if you wish to start the
pattern with a negative extglob pattern like `!(a|B)`. Multiple `!`
characters at the start of a pattern will negate the pattern multiple
times.
If a pattern starts with `#`, then it is treated as a comment, and
will not match anything. Use `\#` to match a literal `#` at the
start of a line, or set the `nocomment` flag to suppress this behavior.
The double-star character `**` is supported by default, unless the
`noglobstar` flag is set. This is supported in the manner of bsdglob
and bash 4.1, where `**` only has special significance if it is the only
thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but
`a/**b` will not.
If an escaped pattern has no matches, and the `nonull` flag is set,
then minimatch.match returns the pattern as-provided, rather than
interpreting the character escapes. For example,
`minimatch.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than
`"*a?"`. This is akin to setting the `nullglob` option in bash, except
that it does not resolve escaped pattern characters.
If brace expansion is not disabled, then it is performed before any
other interpretation of the glob pattern. Thus, a pattern like
`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded
**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are
checked for validity. Since those two are valid, matching proceeds.
@@ -0,0 +1,947 @@
module.exports = minimatch
minimatch.Minimatch = Minimatch
var path = (function () { try { return require('path') } catch (e) {}}()) || {
sep: '/'
}
minimatch.sep = path.sep
var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
var expand = require('brace-expansion')
var plTypes = {
'!': { open: '(?:(?!(?:', close: '))[^/]*?)'},
'?': { open: '(?:', close: ')?' },
'+': { open: '(?:', close: ')+' },
'*': { open: '(?:', close: ')*' },
'@': { open: '(?:', close: ')' }
}
// any single thing other than /
// don't need to escape / when using new RegExp()
var qmark = '[^/]'
// * => any number of characters
var star = qmark + '*?'
// ** when dots are allowed. Anything goes, except .. and .
// not (^ or / followed by one or two dots followed by $ or /),
// followed by anything, any number of times.
var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?'
// not a ^ or / followed by a dot,
// followed by anything, any number of times.
var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?'
// characters that need to be escaped in RegExp.
var reSpecials = charSet('().*{}+?[]^$\\!')
// "abc" -> { a:true, b:true, c:true }
function charSet (s) {
return s.split('').reduce(function (set, c) {
set[c] = true
return set
}, {})
}
// normalizes slashes.
var slashSplit = /\/+/
minimatch.filter = filter
function filter (pattern, options) {
options = options || {}
return function (p, i, list) {
return minimatch(p, pattern, options)
}
}
function ext (a, b) {
b = b || {}
var t = {}
Object.keys(a).forEach(function (k) {
t[k] = a[k]
})
Object.keys(b).forEach(function (k) {
t[k] = b[k]
})
return t
}
minimatch.defaults = function (def) {
if (!def || typeof def !== 'object' || !Object.keys(def).length) {
return minimatch
}
var orig = minimatch
var m = function minimatch (p, pattern, options) {
return orig(p, pattern, ext(def, options))
}
m.Minimatch = function Minimatch (pattern, options) {
return new orig.Minimatch(pattern, ext(def, options))
}
m.Minimatch.defaults = function defaults (options) {
return orig.defaults(ext(def, options)).Minimatch
}
m.filter = function filter (pattern, options) {
return orig.filter(pattern, ext(def, options))
}
m.defaults = function defaults (options) {
return orig.defaults(ext(def, options))
}
m.makeRe = function makeRe (pattern, options) {
return orig.makeRe(pattern, ext(def, options))
}
m.braceExpand = function braceExpand (pattern, options) {
return orig.braceExpand(pattern, ext(def, options))
}
m.match = function (list, pattern, options) {
return orig.match(list, pattern, ext(def, options))
}
return m
}
Minimatch.defaults = function (def) {
return minimatch.defaults(def).Minimatch
}
function minimatch (p, pattern, options) {
assertValidPattern(pattern)
if (!options) options = {}
// shortcut: comments match nothing.
if (!options.nocomment && pattern.charAt(0) === '#') {
return false
}
return new Minimatch(pattern, options).match(p)
}
function Minimatch (pattern, options) {
if (!(this instanceof Minimatch)) {
return new Minimatch(pattern, options)
}
assertValidPattern(pattern)
if (!options) options = {}
pattern = pattern.trim()
// windows support: need to use /, not \
if (!options.allowWindowsEscape && path.sep !== '/') {
pattern = pattern.split(path.sep).join('/')
}
this.options = options
this.set = []
this.pattern = pattern
this.regexp = null
this.negate = false
this.comment = false
this.empty = false
this.partial = !!options.partial
// make the set of regexps etc.
this.make()
}
Minimatch.prototype.debug = function () {}
Minimatch.prototype.make = make
function make () {
var pattern = this.pattern
var options = this.options
// empty patterns and comments match nothing.
if (!options.nocomment && pattern.charAt(0) === '#') {
this.comment = true
return
}
if (!pattern) {
this.empty = true
return
}
// step 1: figure out negation, etc.
this.parseNegate()
// step 2: expand braces
var set = this.globSet = this.braceExpand()
if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) }
this.debug(this.pattern, set)
// step 3: now we have a set, so turn each one into a series of path-portion
// matching patterns.
// These will be regexps, except in the case of "**", which is
// set to the GLOBSTAR object for globstar behavior,
// and will not contain any / characters
set = this.globParts = set.map(function (s) {
return s.split(slashSplit)
})
this.debug(this.pattern, set)
// glob --> regexps
set = set.map(function (s, si, set) {
return s.map(this.parse, this)
}, this)
this.debug(this.pattern, set)
// filter out everything that didn't compile properly.
set = set.filter(function (s) {
return s.indexOf(false) === -1
})
this.debug(this.pattern, set)
this.set = set
}
Minimatch.prototype.parseNegate = parseNegate
function parseNegate () {
var pattern = this.pattern
var negate = false
var options = this.options
var negateOffset = 0
if (options.nonegate) return
for (var i = 0, l = pattern.length
; i < l && pattern.charAt(i) === '!'
; i++) {
negate = !negate
negateOffset++
}
if (negateOffset) this.pattern = pattern.substr(negateOffset)
this.negate = negate
}
// Brace expansion:
// a{b,c}d -> abd acd
// a{b,}c -> abc ac
// a{0..3}d -> a0d a1d a2d a3d
// a{b,c{d,e}f}g -> abg acdfg acefg
// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg
//
// Invalid sets are not expanded.
// a{2..}b -> a{2..}b
// a{b}c -> a{b}c
minimatch.braceExpand = function (pattern, options) {
return braceExpand(pattern, options)
}
Minimatch.prototype.braceExpand = braceExpand
function braceExpand (pattern, options) {
if (!options) {
if (this instanceof Minimatch) {
options = this.options
} else {
options = {}
}
}
pattern = typeof pattern === 'undefined'
? this.pattern : pattern
assertValidPattern(pattern)
// Thanks to Yeting Li <https://github.com/yetingli> for
// improving this regexp to avoid a ReDOS vulnerability.
if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) {
// shortcut. no need to expand.
return [pattern]
}
return expand(pattern)
}
var MAX_PATTERN_LENGTH = 1024 * 64
var assertValidPattern = function (pattern) {
if (typeof pattern !== 'string') {
throw new TypeError('invalid pattern')
}
if (pattern.length > MAX_PATTERN_LENGTH) {
throw new TypeError('pattern is too long')
}
}
// parse a component of the expanded set.
// At this point, no pattern may contain "/" in it
// so we're going to return a 2d array, where each entry is the full
// pattern, split on '/', and then turned into a regular expression.
// A regexp is made at the end which joins each array with an
// escaped /, and another full one which joins each regexp with |.
//
// Following the lead of Bash 4.1, note that "**" only has special meaning
// when it is the *only* thing in a path portion. Otherwise, any series
// of * is equivalent to a single *. Globstar behavior is enabled by
// default, and can be disabled by setting options.noglobstar.
Minimatch.prototype.parse = parse
var SUBPARSE = {}
function parse (pattern, isSub) {
assertValidPattern(pattern)
var options = this.options
// shortcuts
if (pattern === '**') {
if (!options.noglobstar)
return GLOBSTAR
else
pattern = '*'
}
if (pattern === '') return ''
var re = ''
var hasMagic = !!options.nocase
var escaping = false
// ? => one single character
var patternListStack = []
var negativeLists = []
var stateChar
var inClass = false
var reClassStart = -1
var classStart = -1
// . and .. never match anything that doesn't start with .,
// even when options.dot is set.
var patternStart = pattern.charAt(0) === '.' ? '' // anything
// not (start or / followed by . or .. followed by / or end)
: options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))'
: '(?!\\.)'
var self = this
function clearStateChar () {
if (stateChar) {
// we had some state-tracking character
// that wasn't consumed by this pass.
switch (stateChar) {
case '*':
re += star
hasMagic = true
break
case '?':
re += qmark
hasMagic = true
break
default:
re += '\\' + stateChar
break
}
self.debug('clearStateChar %j %j', stateChar, re)
stateChar = false
}
}
for (var i = 0, len = pattern.length, c
; (i < len) && (c = pattern.charAt(i))
; i++) {
this.debug('%s\t%s %s %j', pattern, i, re, c)
// skip over any that are escaped.
if (escaping && reSpecials[c]) {
re += '\\' + c
escaping = false
continue
}
switch (c) {
/* istanbul ignore next */
case '/': {
// completely not allowed, even escaped.
// Should already be path-split by now.
return false
}
case '\\':
clearStateChar()
escaping = true
continue
// the various stateChar values
// for the "extglob" stuff.
case '?':
case '*':
case '+':
case '@':
case '!':
this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c)
// all of those are literals inside a class, except that
// the glob [!a] means [^a] in regexp
if (inClass) {
this.debug(' in class')
if (c === '!' && i === classStart + 1) c = '^'
re += c
continue
}
// if we already have a stateChar, then it means
// that there was something like ** or +? in there.
// Handle the stateChar, then proceed with this one.
self.debug('call clearStateChar %j', stateChar)
clearStateChar()
stateChar = c
// if extglob is disabled, then +(asdf|foo) isn't a thing.
// just clear the statechar *now*, rather than even diving into
// the patternList stuff.
if (options.noext) clearStateChar()
continue
case '(':
if (inClass) {
re += '('
continue
}
if (!stateChar) {
re += '\\('
continue
}
patternListStack.push({
type: stateChar,
start: i - 1,
reStart: re.length,
open: plTypes[stateChar].open,
close: plTypes[stateChar].close
})
// negation is (?:(?!js)[^/]*)
re += stateChar === '!' ? '(?:(?!(?:' : '(?:'
this.debug('plType %j %j', stateChar, re)
stateChar = false
continue
case ')':
if (inClass || !patternListStack.length) {
re += '\\)'
continue
}
clearStateChar()
hasMagic = true
var pl = patternListStack.pop()
// negation is (?:(?!js)[^/]*)
// The others are (?:<pattern>)<type>
re += pl.close
if (pl.type === '!') {
negativeLists.push(pl)
}
pl.reEnd = re.length
continue
case '|':
if (inClass || !patternListStack.length || escaping) {
re += '\\|'
escaping = false
continue
}
clearStateChar()
re += '|'
continue
// these are mostly the same in regexp and glob
case '[':
// swallow any state-tracking char before the [
clearStateChar()
if (inClass) {
re += '\\' + c
continue
}
inClass = true
classStart = i
reClassStart = re.length
re += c
continue
case ']':
// a right bracket shall lose its special
// meaning and represent itself in
// a bracket expression if it occurs
// first in the list. -- POSIX.2 2.8.3.2
if (i === classStart + 1 || !inClass) {
re += '\\' + c
escaping = false
continue
}
// handle the case where we left a class open.
// "[z-a]" is valid, equivalent to "\[z-a\]"
// split where the last [ was, make sure we don't have
// an invalid re. if so, re-walk the contents of the
// would-be class to re-translate any characters that
// were passed through as-is
// TODO: It would probably be faster to determine this
// without a try/catch and a new RegExp, but it's tricky
// to do safely. For now, this is safe and works.
var cs = pattern.substring(classStart + 1, i)
try {
RegExp('[' + cs + ']')
} catch (er) {
// not a valid class!
var sp = this.parse(cs, SUBPARSE)
re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
hasMagic = hasMagic || sp[1]
inClass = false
continue
}
// finish up the class.
hasMagic = true
inClass = false
re += c
continue
default:
// swallow any state char that wasn't consumed
clearStateChar()
if (escaping) {
// no need
escaping = false
} else if (reSpecials[c]
&& !(c === '^' && inClass)) {
re += '\\'
}
re += c
} // switch
} // for
// handle the case where we left a class open.
// "[abc" is valid, equivalent to "\[abc"
if (inClass) {
// split where the last [ was, and escape it
// this is a huge pita. We now have to re-walk
// the contents of the would-be class to re-translate
// any characters that were passed through as-is
cs = pattern.substr(classStart + 1)
sp = this.parse(cs, SUBPARSE)
re = re.substr(0, reClassStart) + '\\[' + sp[0]
hasMagic = hasMagic || sp[1]
}
// handle the case where we had a +( thing at the *end*
// of the pattern.
// each pattern list stack adds 3 chars, and we need to go through
// and escape any | chars that were passed through as-is for the regexp.
// Go through and escape them, taking care not to double-escape any
// | chars that were already escaped.
for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
var tail = re.slice(pl.reStart + pl.open.length)
this.debug('setting tail', re, pl)
// maybe some even number of \, then maybe 1 \, followed by a |
tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) {
if (!$2) {
// the | isn't already escaped, so escape it.
$2 = '\\'
}
// need to escape all those slashes *again*, without escaping the
// one that we need for escaping the | character. As it works out,
// escaping an even number of slashes can be done by simply repeating
// it exactly after itself. That's why this trick works.
//
// I am sorry that you have to see this.
return $1 + $1 + $2 + '|'
})
this.debug('tail=%j\n %s', tail, tail, pl, re)
var t = pl.type === '*' ? star
: pl.type === '?' ? qmark
: '\\' + pl.type
hasMagic = true
re = re.slice(0, pl.reStart) + t + '\\(' + tail
}
// handle trailing things that only matter at the very end.
clearStateChar()
if (escaping) {
// trailing \\
re += '\\\\'
}
// only need to apply the nodot start if the re starts with
// something that could conceivably capture a dot
var addPatternStart = false
switch (re.charAt(0)) {
case '[': case '.': case '(': addPatternStart = true
}
// Hack to work around lack of negative lookbehind in JS
// A pattern like: *.!(x).!(y|z) needs to ensure that a name
// like 'a.xyz.yz' doesn't match. So, the first negative
// lookahead, has to look ALL the way ahead, to the end of
// the pattern.
for (var n = negativeLists.length - 1; n > -1; n--) {
var nl = negativeLists[n]
var nlBefore = re.slice(0, nl.reStart)
var nlFirst = re.slice(nl.reStart, nl.reEnd - 8)
var nlLast = re.slice(nl.reEnd - 8, nl.reEnd)
var nlAfter = re.slice(nl.reEnd)
nlLast += nlAfter
// Handle nested stuff like *(*.js|!(*.json)), where open parens
// mean that we should *not* include the ) in the bit that is considered
// "after" the negated section.
var openParensBefore = nlBefore.split('(').length - 1
var cleanAfter = nlAfter
for (i = 0; i < openParensBefore; i++) {
cleanAfter = cleanAfter.replace(/\)[+*?]?/, '')
}
nlAfter = cleanAfter
var dollar = ''
if (nlAfter === '' && isSub !== SUBPARSE) {
dollar = '$'
}
var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast
re = newRe
}
// if the re is not "" at this point, then we need to make sure
// it doesn't match against an empty path part.
// Otherwise a/* will match a/, which it should not.
if (re !== '' && hasMagic) {
re = '(?=.)' + re
}
if (addPatternStart) {
re = patternStart + re
}
// parsing just a piece of a larger pattern.
if (isSub === SUBPARSE) {
return [re, hasMagic]
}
// skip the regexp for non-magical patterns
// unescape anything in it, though, so that it'll be
// an exact match against a file etc.
if (!hasMagic) {
return globUnescape(pattern)
}
var flags = options.nocase ? 'i' : ''
try {
var regExp = new RegExp('^' + re + '$', flags)
} catch (er) /* istanbul ignore next - should be impossible */ {
// If it was an invalid regular expression, then it can't match
// anything. This trick looks for a character after the end of
// the string, which is of course impossible, except in multi-line
// mode, but it's not a /m regex.
return new RegExp('$.')
}
regExp._glob = pattern
regExp._src = re
return regExp
}
minimatch.makeRe = function (pattern, options) {
return new Minimatch(pattern, options || {}).makeRe()
}
Minimatch.prototype.makeRe = makeRe
function makeRe () {
if (this.regexp || this.regexp === false) return this.regexp
// at this point, this.set is a 2d array of partial
// pattern strings, or "**".
//
// It's better to use .match(). This function shouldn't
// be used, really, but it's pretty convenient sometimes,
// when you just want to work with a regex.
var set = this.set
if (!set.length) {
this.regexp = false
return this.regexp
}
var options = this.options
var twoStar = options.noglobstar ? star
: options.dot ? twoStarDot
: twoStarNoDot
var flags = options.nocase ? 'i' : ''
var re = set.map(function (pattern) {
return pattern.map(function (p) {
return (p === GLOBSTAR) ? twoStar
: (typeof p === 'string') ? regExpEscape(p)
: p._src
}).join('\\\/')
}).join('|')
// must match entire pattern
// ending in a * or ** will make it less strict.
re = '^(?:' + re + ')$'
// can match anything, as long as it's not this.
if (this.negate) re = '^(?!' + re + ').*$'
try {
this.regexp = new RegExp(re, flags)
} catch (ex) /* istanbul ignore next - should be impossible */ {
this.regexp = false
}
return this.regexp
}
minimatch.match = function (list, pattern, options) {
options = options || {}
var mm = new Minimatch(pattern, options)
list = list.filter(function (f) {
return mm.match(f)
})
if (mm.options.nonull && !list.length) {
list.push(pattern)
}
return list
}
Minimatch.prototype.match = function match (f, partial) {
if (typeof partial === 'undefined') partial = this.partial
this.debug('match', f, this.pattern)
// short-circuit in the case of busted things.
// comments, etc.
if (this.comment) return false
if (this.empty) return f === ''
if (f === '/' && partial) return true
var options = this.options
// windows: need to use /, not \
if (path.sep !== '/') {
f = f.split(path.sep).join('/')
}
// treat the test path as a set of pathparts.
f = f.split(slashSplit)
this.debug(this.pattern, 'split', f)
// just ONE of the pattern sets in this.set needs to match
// in order for it to be valid. If negating, then just one
// match means that we have failed.
// Either way, return on the first hit.
var set = this.set
this.debug(this.pattern, 'set', set)
// Find the basename of the path by looking for the last non-empty segment
var filename
var i
for (i = f.length - 1; i >= 0; i--) {
filename = f[i]
if (filename) break
}
for (i = 0; i < set.length; i++) {
var pattern = set[i]
var file = f
if (options.matchBase && pattern.length === 1) {
file = [filename]
}
var hit = this.matchOne(file, pattern, partial)
if (hit) {
if (options.flipNegate) return true
return !this.negate
}
}
// didn't get any hits. this is success if it's a negative
// pattern, failure otherwise.
if (options.flipNegate) return false
return this.negate
}
// set partial to true to test if, for example,
// "/a/b" matches the start of "/*/b/*/d"
// Partial means, if you run out of file before you run
// out of pattern, then that's fine, as long as all
// the parts match.
Minimatch.prototype.matchOne = function (file, pattern, partial) {
var options = this.options
this.debug('matchOne',
{ 'this': this, file: file, pattern: pattern })
this.debug('matchOne', file.length, pattern.length)
for (var fi = 0,
pi = 0,
fl = file.length,
pl = pattern.length
; (fi < fl) && (pi < pl)
; fi++, pi++) {
this.debug('matchOne loop')
var p = pattern[pi]
var f = file[fi]
this.debug(pattern, p, f)
// should be impossible.
// some invalid regexp stuff in the set.
/* istanbul ignore if */
if (p === false) return false
if (p === GLOBSTAR) {
this.debug('GLOBSTAR', [pattern, p, f])
// "**"
// a/**/b/**/c would match the following:
// a/b/x/y/z/c
// a/x/y/z/b/c
// a/b/x/b/x/c
// a/b/c
// To do this, take the rest of the pattern after
// the **, and see if it would match the file remainder.
// If so, return success.
// If not, the ** "swallows" a segment, and try again.
// This is recursively awful.
//
// a/**/b/**/c matching a/b/x/y/z/c
// - a matches a
// - doublestar
// - matchOne(b/x/y/z/c, b/**/c)
// - b matches b
// - doublestar
// - matchOne(x/y/z/c, c) -> no
// - matchOne(y/z/c, c) -> no
// - matchOne(z/c, c) -> no
// - matchOne(c, c) yes, hit
var fr = fi
var pr = pi + 1
if (pr === pl) {
this.debug('** at the end')
// a ** at the end will just swallow the rest.
// We have found a match.
// however, it will not swallow /.x, unless
// options.dot is set.
// . and .. are *never* matched by **, for explosively
// exponential reasons.
for (; fi < fl; fi++) {
if (file[fi] === '.' || file[fi] === '..' ||
(!options.dot && file[fi].charAt(0) === '.')) return false
}
return true
}
// ok, let's see if we can swallow whatever we can.
while (fr < fl) {
var swallowee = file[fr]
this.debug('\nglobstar while', file, fr, pattern, pr, swallowee)
// XXX remove this slice. Just pass the start index.
if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
this.debug('globstar found match!', fr, fl, swallowee)
// found a match.
return true
} else {
// can't swallow "." or ".." ever.
// can only swallow ".foo" when explicitly asked.
if (swallowee === '.' || swallowee === '..' ||
(!options.dot && swallowee.charAt(0) === '.')) {
this.debug('dot detected!', file, fr, pattern, pr)
break
}
// ** swallows a segment, and continue.
this.debug('globstar swallow a segment, and continue')
fr++
}
}
// no match was found.
// However, in partial mode, we can't say this is necessarily over.
// If there's more *pattern* left, then
/* istanbul ignore if */
if (partial) {
// ran out of file
this.debug('\n>>> no match, partial?', file, fr, pattern, pr)
if (fr === fl) return true
}
return false
}
// something other than **
// non-magic patterns just have to match exactly
// patterns with magic have been turned into regexps.
var hit
if (typeof p === 'string') {
hit = f === p
this.debug('string match', p, f, hit)
} else {
hit = f.match(p)
this.debug('pattern match', p, f, hit)
}
if (!hit) return false
}
// Note: ending in / means that we'll get a final ""
// at the end of the pattern. This can only match a
// corresponding "" at the end of the file.
// If the file ends in /, then it can only match a
// a pattern that ends in /, unless the pattern just
// doesn't have any more for it. But, a/b/ should *not*
// match "a/b/*", even though "" matches against the
// [^/]*? pattern, except in partial mode, where it might
// simply not be reached yet.
// However, a/b/ should still satisfy a/*
// now either we fell off the end of the pattern, or we're done.
if (fi === fl && pi === pl) {
// ran out of pattern and filename at the same time.
// an exact hit!
return true
} else if (fi === fl) {
// ran out of file, but still had pattern left.
// this is ok if we're doing the match as part of
// a glob fs traversal.
return partial
} else /* istanbul ignore else */ if (pi === pl) {
// ran out of pattern, still have file left.
// this is only acceptable if we're on the very last
// empty segment of a file with a trailing slash.
// a/* should match a/b/
return (fi === fl - 1) && (file[fi] === '')
}
// should be unreachable.
/* istanbul ignore next */
throw new Error('wtf?')
}
// replace stuff like \* with *
function globUnescape (s) {
return s.replace(/\\(.)/g, '$1')
}
function regExpEscape (s) {
return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
}
@@ -0,0 +1,33 @@
{
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
"name": "minimatch",
"description": "a glob matcher in javascript",
"version": "3.1.2",
"publishConfig": {
"tag": "v3-legacy"
},
"repository": {
"type": "git",
"url": "git://github.com/isaacs/minimatch.git"
},
"main": "minimatch.js",
"scripts": {
"test": "tap",
"preversion": "npm test",
"postversion": "npm publish",
"postpublish": "git push origin --all; git push origin --tags"
},
"engines": {
"node": "*"
},
"dependencies": {
"brace-expansion": "^1.1.7"
},
"devDependencies": {
"tap": "^15.1.6"
},
"license": "ISC",
"files": [
"minimatch.js"
]
}
+72
View File
@@ -0,0 +1,72 @@
{
"name": "swagger-jsdoc",
"description": "Generates swagger doc based on JSDoc",
"version": "6.2.8",
"engines": {
"node": ">=12.0.0"
},
"scripts": {
"start": "node examples/app/app.js",
"lint": "eslint .",
"test:lint": "eslint .",
"test:js": "jest --verbose",
"test": "run-p test:* -cn"
},
"main": "index.js",
"bin": {
"swagger-jsdoc": "./bin/swagger-jsdoc.js"
},
"dependencies": {
"commander": "6.2.0",
"doctrine": "3.0.0",
"glob": "7.1.6",
"lodash.mergewith": "^4.6.2",
"swagger-parser": "^10.0.3",
"yaml": "2.0.0-1"
},
"devDependencies": {
"body-parser": "1.19.0",
"eslint": "8.9.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-prettier": "6.15.0",
"eslint-loader": "4.0.2",
"eslint-plugin-import": "2.25.4",
"eslint-plugin-jest": "26.1.1",
"eslint-plugin-prettier": "3.1.4",
"express": "4.17.1",
"husky": "7.0.4",
"jest": "^26.6.1",
"lint-staged": "10.5.2",
"npm-run-all": "4.1.5",
"prettier": "2.2.0",
"supertest": "6.0.1"
},
"license": "MIT",
"homepage": "https://github.com/Surnet/swagger-jsdoc",
"repository": {
"type": "git",
"url": "https://github.com/Surnet/swagger-jsdoc.git"
},
"keywords": [
"swagger",
"openapi",
"jsdoc"
],
"author": "https://github.com/Surnet/swagger-jsdoc/graphs/contributors",
"bugs": {
"url": "https://github.com/Surnet/swagger-jsdoc/issues"
},
"resolutions": {
"minimist": ">=1.2.3"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,json,md,yml,yaml}": [
"prettier --write"
]
}
}
+33
View File
@@ -0,0 +1,33 @@
const { build } = require('./specification');
/**
* Generates the specification.
* @param {object} options - Configuration options
* @param {string} options.encoding Optional, passed to readFileSync options. Defaults to 'utf8'.
* @param {boolean} options.failOnErrors Whether or not to throw when parsing errors. Defaults to false.
* @param {boolean} options.verbose Whether the swagger snippet containing each error should be included in print/throws. Defaults to false.
* @param {string} options.format Optional, defaults to '.json' - target file format '.yml' or '.yaml'.
* @param {object} options.swaggerDefinition
* @param {object} options.definition
* @param {array} options.apis
* @returns {object} Output specification
*/
module.exports = (options) => {
if (!options) {
throw new Error(`Missing or invalid input: 'options' is required`);
}
if (!options.swaggerDefinition && !options.definition) {
throw new Error(
`Missing or invalid input: 'options.swaggerDefinition' or 'options.definition' is required`
);
}
if (!options.apis || !Array.isArray(options.apis)) {
throw new Error(
`Missing or invalid input: 'options.apis' is required and it should be an array.`
);
}
return build(options);
};
+327
View File
@@ -0,0 +1,327 @@
const doctrine = require('doctrine');
const parser = require('swagger-parser');
const YAML = require('yaml');
const {
hasEmptyProperty,
convertGlobPaths,
extractAnnotations,
mergeDeep,
extractYamlFromJsDoc,
isTagPresentInTags,
} = require('./utils');
/**
* Prepare the swagger/openapi specification object.
* @see https://github.com/OAI/OpenAPI-Specification/tree/master/versions
* @param {object} definition - The `definition` or `swaggerDefinition` from options.
* @returns {object} swaggerObject
*/
function prepare(definition) {
const swaggerObject = JSON.parse(JSON.stringify(definition));
const specificationTemplate = {
v2: [
'paths',
'definitions',
'responses',
'parameters',
'securityDefinitions',
],
v3: [
'paths',
'definitions',
'responses',
'parameters',
'securityDefinitions',
'components',
],
v4: ['components', 'channels'],
};
const getVersion = () => {
if (swaggerObject.asyncapi) {
return 'v4';
}
if (swaggerObject.openapi) {
return 'v3';
}
if (swaggerObject.swagger) {
return 'v2';
}
swaggerObject.swagger = '2.0';
return 'v2';
};
const version = getVersion();
specificationTemplate[version].forEach((property) => {
swaggerObject[property] = swaggerObject[property] || {};
});
swaggerObject.tags = swaggerObject.tags || [];
return swaggerObject;
}
/**
* @param {object} obj
* @param {string} ext
*/
function format(swaggerObject, ext) {
if (ext === '.yml' || ext === '.yaml') {
return YAML.stringify(swaggerObject);
}
return swaggerObject;
}
/**
* OpenAPI specification validator does not accept empty values for a few properties.
* Solves validator error: "Schema error should NOT have additional properties"
* @param {object} swaggerObject
* @returns {object} swaggerObject
*/
function clean(swaggerObject) {
for (const prop of [
'definitions',
'responses',
'parameters',
'securityDefinitions',
]) {
if (hasEmptyProperty(swaggerObject[prop])) {
delete swaggerObject[prop];
}
}
return swaggerObject;
}
/**
* Parse the swagger object and remove useless properties if necessary.
*
* @param {object} swaggerObject - Swagger object from parsing the api files.
* @returns {object} The specification.
*/
function finalize(swaggerObject, options) {
let specification = swaggerObject;
parser.parse(swaggerObject, (err, api) => {
if (!err) {
specification = api;
}
});
if (specification.openapi) {
specification = clean(specification);
}
return format(specification, options.format);
}
/**
* @param {object} swaggerObject
* @param {object} annotation
* @param {string} property
*/
function organize(swaggerObject, annotation, property) {
// Root property on purpose.
// @see https://github.com/OAI/OpenAPI-Specification/blob/master/proposals/002_Webhooks.md#proposed-solution
if (property === 'x-webhooks') {
swaggerObject[property] = mergeDeep(
swaggerObject[property],
annotation[property]
);
}
// Other extensions can be in varying places depending on different vendors and opinions.
// The following return makes it so that they are not put in `paths` in the last case.
// New specific extensions will need to be handled on case-by-case if to be included in `paths`.
if (property.startsWith('x-')) return;
const commonProperties = [
'components',
'consumes',
'produces',
'paths',
'schemas',
'securityDefinitions',
'responses',
'parameters',
'definitions',
'channels',
];
if (commonProperties.includes(property)) {
for (const definition of Object.keys(annotation[property])) {
swaggerObject[property][definition] = mergeDeep(
swaggerObject[property][definition],
annotation[property][definition]
);
}
} else if (property === 'tags') {
const { tags } = annotation;
if (Array.isArray(tags)) {
for (const tag of tags) {
if (!isTagPresentInTags(tag, swaggerObject.tags)) {
swaggerObject.tags.push(tag);
}
}
} else if (!isTagPresentInTags(tags, swaggerObject.tags)) {
swaggerObject.tags.push(tags);
}
} else {
// Paths which are not defined as "paths" property, starting with a slash "/"
swaggerObject.paths[property] = mergeDeep(
swaggerObject.paths[property],
annotation[property]
);
}
}
/**
* @param {object} options
* @returns {object} swaggerObject
*/
function build(options) {
YAML.defaultOptions.keepCstNodes = true;
// Get input definition and prepare the specification's skeleton
const definition = options.swaggerDefinition || options.definition;
const specification = prepare(definition);
const yamlDocsAnchors = new Map();
const yamlDocsErrors = [];
const yamlDocsReady = [];
for (const filePath of convertGlobPaths(options.apis)) {
const {
yaml: yamlAnnotations,
jsdoc: jsdocAnnotations,
} = extractAnnotations(filePath, options.encoding);
if (yamlAnnotations.length) {
for (const annotation of yamlAnnotations) {
const parsed = Object.assign(YAML.parseDocument(annotation), {
filePath,
});
const anchors = parsed.anchors.getNames();
if (anchors.length) {
for (const anchor of anchors) {
yamlDocsAnchors.set(anchor, parsed);
}
} else if (parsed.errors && parsed.errors.length) {
// Attach the relevent yaml section to the error for verbose logging
parsed.errors.forEach((err) => {
err.annotation = annotation;
});
yamlDocsErrors.push(parsed);
} else {
yamlDocsReady.push(parsed);
}
}
}
if (jsdocAnnotations.length) {
for (const annotation of jsdocAnnotations) {
const jsDocComment = doctrine.parse(annotation, { unwrap: true });
for (const doc of extractYamlFromJsDoc(jsDocComment)) {
const parsed = Object.assign(YAML.parseDocument(doc), { filePath });
const anchors = parsed.anchors.getNames();
if (anchors.length) {
for (const anchor of anchors) {
yamlDocsAnchors.set(anchor, parsed);
}
} else if (parsed.errors && parsed.errors.length) {
// Attach the relevent yaml section to the error for verbose logging
parsed.errors.forEach((err) => {
err.annotation = doc;
});
yamlDocsErrors.push(parsed);
} else {
yamlDocsReady.push(parsed);
}
}
}
}
}
if (yamlDocsErrors.length) {
for (const docWithErr of yamlDocsErrors) {
const errsToDelete = [];
docWithErr.errors.forEach((error, index) => {
if (error.name === 'YAMLReferenceError') {
// This should either be a smart regex or ideally a YAML library method using the error.range.
// The following works with both pretty and not pretty errors.
const refErr = error.message
.split('Aliased anchor not found: ')
.filter((a) => a)
.join('')
.split(' at line')[0];
const anchor = yamlDocsAnchors.get(refErr);
const anchorString = anchor.cstNode.toString();
const originalString = docWithErr.cstNode.toString();
const readyDocument = YAML.parseDocument(
`${anchorString}\n${originalString}`
);
yamlDocsReady.push(readyDocument);
errsToDelete.push(index);
}
});
// reverse sort the deletion array so we always delete from the end
errsToDelete.sort((a, b) => b - a);
// Cleanup solved errors in order to allow for parser to pass through.
for (const errIndex of errsToDelete) {
docWithErr.errors.splice(errIndex, 1);
}
}
// Format errors into a printable/throwable string
const errReport = yamlDocsErrors
.filter((doc) => doc.errors.length)
.map(({ errors, filePath }) => {
let str = `Error in ${filePath} :\n`;
if (options.verbose) {
str += errors
.map(
(e) =>
`${e.toString()}\nImbedded within:\n\`\`\`\n ${e.annotation.replace(
/\n/g,
'\n '
)}\n\`\`\``
)
.join('\n');
} else {
str += errors.map((e) => e.toString()).join('\n');
}
return str;
})
.filter((error) => !!error);
if (errReport.length) {
if (options.failOnErrors) {
throw new Error(errReport);
}
// Place to provide feedback for errors. Previously throwing, now reporting only.
console.info(
'Not all input has been taken into account at your final specification.'
);
console.error(`Here's the report: \n\n\n ${errReport}`);
}
}
for (const document of yamlDocsReady) {
const parsedDoc = document.toJSON();
for (const property in parsedDoc) {
organize(specification, parsedDoc, property);
}
}
return finalize(specification, options);
}
module.exports = { prepare, build, organize, finalize, format };
+150
View File
@@ -0,0 +1,150 @@
const fs = require('fs');
const path = require('path');
const glob = require('glob');
const mergeWith = require('lodash.mergewith');
/**
* Converts an array of globs to full paths
* @param {array} globs - Array of globs and/or normal paths
* @return {array} Array of fully-qualified paths
*/
function convertGlobPaths(globs) {
return globs
.map((globString) => glob.sync(globString))
.reduce((previous, current) => previous.concat(current), []);
}
/**
* Checks if there is any properties of the input object which are an empty object
* @param {object} obj - the object to check
* @returns {boolean}
*/
function hasEmptyProperty(obj) {
return Object.keys(obj)
.map((key) => obj[key])
.every(
(keyObject) =>
typeof keyObject === 'object' &&
Object.keys(keyObject).every((key) => !(key in keyObject))
);
}
/**
* Extracts the YAML description from JSDoc comments with `@swagger`/`@openapi` annotation.
* @param {object} jsDocComment - Single item of JSDoc comments from doctrine.parse
* @returns {array} YAML parts
*/
function extractYamlFromJsDoc(jsDocComment) {
const yamlParts = [];
for (const tag of jsDocComment.tags) {
if (tag.title === 'swagger' || tag.title === 'openapi') {
yamlParts.push(tag.description);
}
}
return yamlParts;
}
/**
* @param {string} filePath
* @returns {{jsdoc: array, yaml: array}} JSDoc comments and Yaml files
*/
function extractAnnotations(filePath, encoding = 'utf8') {
const fileContent = fs.readFileSync(filePath, { encoding });
const ext = path.extname(filePath);
const jsDocRegex = /\/\*\*([\s\S]*?)\*\//gm;
const csDocRegex = /###([\s\S]*?)###/gm;
const yaml = [];
const jsdoc = [];
let regexResults = null;
switch (ext) {
case '.yml':
case '.yaml':
yaml.push(fileContent);
break;
case '.coffee':
regexResults = fileContent.match(csDocRegex) || [];
for (const result of regexResults) {
let part = result.split('###');
part[0] = `/**`;
part[part.length - 1] = '*/';
part = part.join('');
jsdoc.push(part);
}
break;
default: {
regexResults = fileContent.match(jsDocRegex) || [];
for (const result of regexResults) {
jsdoc.push(result);
}
}
}
return { yaml, jsdoc };
}
/**
* @param {object} tag
* @param {array} tags
* @returns {boolean}
*/
function isTagPresentInTags(tag, tags) {
const match = tags.find((targetTag) => tag.name === targetTag.name);
if (match) return true;
return false;
}
/**
* Get an object of the definition file configuration.
* @param {string} defPath
* @param {object} swaggerDefinition
*/
function loadDefinition(defPath, swaggerDefinition) {
const resolvedPath = path.resolve(defPath);
const extName = path.extname(resolvedPath);
// eslint-disable-next-line
const loadCjs = () => require(resolvedPath);
const loadJson = () => JSON.parse(swaggerDefinition);
// eslint-disable-next-line
const loadYaml = () => require('yaml').parse(swaggerDefinition);
const LOADERS = {
'.js': loadCjs, // on purpose, to allow throwing by nodejs and .cjs suggestion
'.cjs': loadCjs,
'.json': loadJson,
'.yml': loadYaml,
'.yaml': loadYaml,
};
const loader = LOADERS[extName];
if (loader === undefined) {
throw new Error('Definition file should be .cjs, .json, .yml or .yaml');
}
return loader();
}
/**
* A recursive deep-merge that ignores null values when merging.
* This returns the merged object and does not mutate.
* @param {object} first the first object to get merged
* @param {object} second the second object to get merged
*/
function mergeDeep(first, second) {
return mergeWith({}, first, second, (a, b) => (b === null ? a : undefined));
}
module.exports.mergeDeep = mergeDeep;
module.exports.convertGlobPaths = convertGlobPaths;
module.exports.hasEmptyProperty = hasEmptyProperty;
module.exports.extractYamlFromJsDoc = extractYamlFromJsDoc;
module.exports.extractAnnotations = extractAnnotations;
module.exports.isTagPresentInTags = isTagPresentInTags;
module.exports.loadDefinition = loadDefinition;