diff --git a/.github/workflows/publish-website.yml b/.github/workflows/publish-website.yml index 28abb68cbd..09e2ccd26d 100644 --- a/.github/workflows/publish-website.yml +++ b/.github/workflows/publish-website.yml @@ -11,23 +11,25 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-java@v4 + - uses: olafurpg/setup-scala@v14 with: - distribution: zulu - java-version: 14 - - uses: ruby/setup-ruby@v1.162.0 - with: - bundler-cache: true - - name: Install microsite deps - run: | - bundle install --jobs 4 --retry 3 --system + java-version: zulu@1.14 - name: Print versions run: | java -version - gpg --version - ruby --version - bundle exec jekyll --version - name: Update website env: MICROSITE_PUBLISH_TOKEN: ${{ secrets.MICROSITE_PUBLISH_TOKEN }} - run: bundle exec sbt microsite/makeMicrosite microsite/publishMicrosite + run: | + git clone "https://git:$MICROSITE_PUBLISH_TOKEN@github.com/guardrail-dev/guardrail.git" --branch=gh-pages gh-pages && \ + pushd gh-pages && \ + git rm -rf . && \ + git config user.email "hello@guardrail.dev" && \ + git config user.name "guardrail website builder" && \ + popd && \ + sbt microsite/mdoc && \ + tar -cC modules/microsite/target/mdoc/ . | tar -vxC gh-pages && \ + pushd gh-pages && \ + git add . && \ + git commit -m "Updating ${{ github.ref_name }}" && \ + git push diff --git a/.gitignore b/.gitignore index 2999e7148f..f36eb9eafc 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ vendor/ .bundle/ metals.sbt .sbtopts +node_modules/ diff --git a/Gemfile b/Gemfile deleted file mode 100644 index 5a35f02d50..0000000000 --- a/Gemfile +++ /dev/null @@ -1,6 +0,0 @@ -# frozen_string_literal: true - -source "https://rubygems.org" - -gem 'jekyll', '4.3.2' -gem 'sass' diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index acc4295692..0000000000 --- a/Gemfile.lock +++ /dev/null @@ -1,80 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - addressable (2.8.5) - public_suffix (>= 2.0.2, < 6.0) - colorator (1.1.0) - concurrent-ruby (1.2.2) - em-websocket (0.5.3) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0) - eventmachine (1.2.7) - ffi (1.16.3) - forwardable-extended (2.6.0) - google-protobuf (3.25.0-arm64-darwin) - google-protobuf (3.25.0-x86_64-linux) - http_parser.rb (0.8.0) - i18n (1.14.1) - concurrent-ruby (~> 1.0) - jekyll (4.3.2) - addressable (~> 2.4) - colorator (~> 1.0) - em-websocket (~> 0.5) - i18n (~> 1.0) - jekyll-sass-converter (>= 2.0, < 4.0) - jekyll-watch (~> 2.0) - kramdown (~> 2.3, >= 2.3.1) - kramdown-parser-gfm (~> 1.0) - liquid (~> 4.0) - mercenary (>= 0.3.6, < 0.5) - pathutil (~> 0.9) - rouge (>= 3.0, < 5.0) - safe_yaml (~> 1.0) - terminal-table (>= 1.8, < 4.0) - webrick (~> 1.7) - jekyll-sass-converter (3.0.0) - sass-embedded (~> 1.54) - jekyll-watch (2.2.1) - listen (~> 3.0) - kramdown (2.4.0) - rexml - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - liquid (4.0.4) - listen (3.8.0) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - mercenary (0.4.0) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (5.0.3) - rb-fsevent (0.11.2) - rb-inotify (0.10.1) - ffi (~> 1.0) - rexml (3.2.6) - rouge (4.2.0) - safe_yaml (1.0.5) - sass (3.7.4) - sass-listen (~> 4.0.0) - sass-embedded (1.69.5-arm64-darwin) - google-protobuf (~> 3.23) - sass-embedded (1.69.5-x86_64-linux-gnu) - google-protobuf (~> 3.23) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - terminal-table (3.0.2) - unicode-display_width (>= 1.1.1, < 3) - unicode-display_width (2.5.0) - webrick (1.8.1) - -PLATFORMS - arm64-darwin-22 - x86_64-linux - -DEPENDENCIES - jekyll (= 4.3.2) - sass - -BUNDLED WITH - 2.4.20 diff --git a/build.sbt b/build.sbt index c66312a5bd..6bf2767aeb 100644 --- a/build.sbt +++ b/build.sbt @@ -182,6 +182,7 @@ lazy val scalaDropwizard = modules.scalaDropwizard.project .customDependsOn("scala-support", scalaSupport) lazy val microsite = baseModule("microsite", "microsite", file("modules/microsite")) + .enablePlugins(MdocPlugin) .settings( publish / skip := true, mdocExtraArguments += "--no-link-hygiene", diff --git a/modules/microsite/docs/docs/scalajs/index.md b/docs/.nojekyll similarity index 100% rename from modules/microsite/docs/docs/scalajs/index.md rename to docs/.nojekyll diff --git a/modules/microsite/docs/CNAME b/docs/CNAME similarity index 100% rename from modules/microsite/docs/CNAME rename to docs/CNAME diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..a2e1bc4510 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,27 @@ +Introduction +=== + +[![Build Status](https://github.com/guardrail-dev/guardrail/workflows/CI/badge.svg)](https://github.com/guardrail-dev/guardrail/actions?query=workflow%3A%22CI%22) | [![codecov](https://codecov.io/gh/guardrail-dev/guardrail/branch/master/graph/badge.svg?token=ssLYYkVBgv)](https://codecov.io/gh/guardrail-dev/guardrail) | [![Matrix chat](https://img.shields.io/matrix/guardrail:matrix.org.svg?label=matrix&server_fqdn=matrix.org)](https://matrix.to/#/#guardrail:matrix.org) | [![Join the chat at https://gitter.im/guardrail-dev/guardrail](https://badges.gitter.im/guardrail-dev/guardrail.svg)](https://gitter.im/guardrail-dev/guardrail?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | [![Scala Steward badge](https://img.shields.io/badge/Scala_Steward-helping-blue.svg?style=flat&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAMAAAARSr4IAAAAVFBMVEUAAACHjojlOy5NWlrKzcYRKjGFjIbp293YycuLa3pYY2LSqql4f3pCUFTgSjNodYRmcXUsPD/NTTbjRS+2jomhgnzNc223cGvZS0HaSD0XLjbaSjElhIr+AAAAAXRSTlMAQObYZgAAAHlJREFUCNdNyosOwyAIhWHAQS1Vt7a77/3fcxxdmv0xwmckutAR1nkm4ggbyEcg/wWmlGLDAA3oL50xi6fk5ffZ3E2E3QfZDCcCN2YtbEWZt+Drc6u6rlqv7Uk0LdKqqr5rk2UCRXOk0vmQKGfc94nOJyQjouF9H/wCc9gECEYfONoAAAAASUVORK5CYII=)](https://scala-steward.org) + +[`guardrail`](https://github.com/guardrail-dev/guardrail) is a code generation tool, capable of reading from OpenAPI/Swagger specification files and generating high quality source code for a variety of languages and frameworks. + +Getting started +=== + +The following build tool plugins are available: + +- [`sbt-guardrail`](https://github.com/guardrail-dev/sbt-guardrail) +- [`guardrail-maven-plugin`](https://github.com/guardrail-dev/guardrail-maven-plugin) +- [`guardrail-gradle-plugin`](https://github.com/guardrail-dev/guardrail-gradle-plugin) +- as well as a manual CLI runner available via [coursier](cli.md) + +New plugins are straightforward, simply call one of the exposed functions from +[`GuardrailRunner`](https://github.com/guardrail-dev/guardrail/blob/master/modules/core/src/main/scala/dev/guardrail/runner/GuardrailRunner.scala) +with appropriate arguments in order to get a sequence of generated files. + +**NB:** Ensure either you or your build tool deduplicates the file sequence, as +they are not guaranteed to be unique across multiple runs of the guardrail core. + +Additionally, check out the [`guardrail-sample`](https://github.com/topics/guardrail-sample) topic on GitHub for more examples. + +**Consulting**: If you need help getting started, getting migrated, or adding features, please contact [hello@guardrail.dev](mailto:hello@guardrail.dev). diff --git a/docs/_sidebar.md b/docs/_sidebar.md new file mode 100644 index 0000000000..5d56d3848e --- /dev/null +++ b/docs/_sidebar.md @@ -0,0 +1,6 @@ +- [Home](/) +- [What is guardrail?](about.md) +- [Sample API Specification](sample-spec.md) +- [Scala](scala/README.md) +- [Java](java/README.md) +- [Extensions](extensions.md) diff --git a/modules/microsite/docs/docs/scala/http4s/what-is-guardrail.md b/docs/about.md similarity index 58% rename from modules/microsite/docs/docs/scala/http4s/what-is-guardrail.md rename to docs/about.md index 3bd4d53b2d..a2fccaf761 100644 --- a/modules/microsite/docs/docs/scala/http4s/what-is-guardrail.md +++ b/docs/about.md @@ -1,12 +1,7 @@ ---- -layout: docs -title: "What is guardrail? - http4s - scala - guardrail" ---- - What is guardrail? ================== -guardrail is a code generation tool, capable of reading from OpenAPI/Swagger specification files and generating Scala source code, primarily targeting the akka-http and http4s web frameworks, using circe for JSON encoding/decoding. +guardrail is a code generation tool, capable of reading from OpenAPI/Swagger specification files and generating source code in different languages with a focus on type safety and ergonomics in each target language. guardrail has three primary goals: @@ -21,28 +16,42 @@ Single Point of Truth By describing the shape of an API statically, there are far fewer variables to worry about. HTTP is a _very_ flexible protocol, with many features. By constraining that protocol to a subset that expresses the interface to our server (or service, or microservice), we drastically reduce the burden of handling the entirety of HTTP to the core terms of our API. Focus on semantics of APIs once the basics (routing, data validation) are figured out. -A secondary benefit of static specifications lies in tooling. Hand-written routing logic can hide security holes, miss best practices, and obscure intent if written incorrectly. This problem is multipled across as many different languages as are supported inside any given company, manifesting as wasted effort implementing the same feature in different languages, or a bug that only occurs 10 percent of the time due to a buggy golang client. +A secondary benefit of static specifications lies in tooling. Hand-written routing logic can hide security holes, miss best practices, and obscure intent if written incorrectly. This problem is multipled across as many different languages as are supported inside any given company, manifesting as wasted effort implementing the same feature in different languages, or a bug that only occurs 10 percent of the time due to a buggy hand-written client. Attempting to derive what the attack surface of a server is from the implementation is often the job of entire teams in large companies, and even that may not be enough. Conversely, with a static specification, those teams can build intelligent traffic analysis tools to detect anomalies or intentionally malicious clients built to inject bad data to find bugs. Unexpected API changes are compiler errors ------------------------------------------ -Once we have a specification, generating traits (or abstract classes) with unimplemented members gives us another powerful tool: New or changed parameters become compiler errors. +Once we have a specification, generating traits (or abstract classes) with unimplemented members gives us another powerful tool: New or changed parameters become compiler (or linting) errors. + +After constraining our vocabulary to a subset of HTTP that serves our business need, even saying "This parameter is optional" forces us to contend with the appearance of optional parameters in our generated `Handler` methods. + +Once specified, turning on "unused" warnings helpfully points out that we've forgotten to reflect this most recent change in our tests. A win on both fronts! + +Separation of business logic +---------------------------- + +Providing an implementation of a function with a well-defined set of inputs and outputs is natural for any developer. By reducing the scope of the interface a developer writes against, implementations are more clear and concise. -After constraining our vocabulary to a subset of HTTP that serves our business need, even saying "This parameter is optional" forces us to contend with the sudden appearance of `Option[T]` parameters in our generated `Handler` methods. +Furthermore, by providing business logic as an implementation of an abstract class, unit tests can test the routing layer and business logic independently, by design. -Once specified, `-Ywarn-unused` helpfully points out that we've forgotten to reflect this most recent change in our tests. A win on both fronts! +API structure slip is impossible +-------------------------------- + +As parameters are explicitly provided as arguments to functions in `Handler`s, any alteration to parameters constitute a new function interface that must be implemented. As a result, if providing an implementation for an externally managed specification, the compiler informs when a previously written function is no longer sufficient. + +By representing different response codes and structures as members of an enumeration of valid choices, it's impossible to return a structure that violates the specification, even for less frequently used responses. + +Finally, describing an endpoint in your specification without providing an implementation for it is an error. This prevents reduction of functionality due to refactors, human error, or miscommunication with other teams. Fewer binary dependencies ---------------------- -Traditionally written and maintained client libraries invariably accumulate cruft. In many cases, this is intended to be helpful: papering over a poorly designed API by providing custom logic, renaming parameters to be more convenient, or including properly configured HTTP clients that express retry and backoff semantics the library author provided based on the business requirements known at the time of writing. +Bespoke, hand-written and maintained client libraries invariably accumulate cruft. In many cases, this is intended to be helpful: papering over a poorly designed API by providing custom logic, renaming parameters to be more convenient, or including properly configured HTTP clients that express retry and backoff semantics the library author provided based on the business requirements known at the time of writing. -Altering the shape of an API by providing a thick HTTP client reduces the shared terminology between service maintainers and their consumers, or even between consumers coming from different languages. +This alters the shape of an API, reducing the shared terminology between service maintainers and their consumers, or even between consumers coming from different languages. -Additionally, by hardcoding even a well-behaved HTTP client into a client library, now consumers are forced to work around that dependency. This may manifest as learning how to use and configure a brand new HTTP client under time pressure, or writing and maintaining brittle [Application Binary Interface (ABI)](https://en.wikipedia.org/wiki/Application_binary_interface)-compatible adapter layers that attempt to use the configuration already present in the rest of the codebase. +Additionally, by hardcoding even a well-behaved HTTP client into a client library, now consumers are forced to work around that dependency. In the worst case, this could result in a misconfigured underlying library silently falling back to default parameters, or writing and maintaining brittle [Application Binary Interface (ABI)](https://en.wikipedia.org/wiki/Application_binary_interface)-compatible adapter layers that attempt to use the configuration already present in the rest of the codebase. Once these bespoke HTTP client configurations are built, both they and their dependencies are now added to the grab bag of dependency versions that must be maintained through the life of any given piece of infrastructure. This presents hidden barriers for upgrading all dependencies, as the possibility of transitive dependency conflicts increase as dependency trees become deeper. - -[Next: Installation](installation) diff --git a/docs/cli.md b/docs/cli.md new file mode 100644 index 0000000000..c8dc7e18b2 --- /dev/null +++ b/docs/cli.md @@ -0,0 +1,3 @@ +## CLI runner + +TODO diff --git a/docs/docs/index.html b/docs/docs/index.html new file mode 100644 index 0000000000..568fd767a1 --- /dev/null +++ b/docs/docs/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/java/dropwizard/generating-a-server.html b/docs/docs/java/dropwizard/generating-a-server.html new file mode 100644 index 0000000000..2316952a35 --- /dev/null +++ b/docs/docs/java/dropwizard/generating-a-server.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/java/dropwizard/generating-clients.html b/docs/docs/java/dropwizard/generating-clients.html new file mode 100644 index 0000000000..b9d919b3f9 --- /dev/null +++ b/docs/docs/java/dropwizard/generating-clients.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/java/dropwizard/index.html b/docs/docs/java/dropwizard/index.html new file mode 100644 index 0000000000..bebb8dd10b --- /dev/null +++ b/docs/docs/java/dropwizard/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/java/dropwizard/installation.html b/docs/docs/java/dropwizard/installation.html new file mode 100644 index 0000000000..0c88802e26 --- /dev/null +++ b/docs/docs/java/dropwizard/installation.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/java/dropwizard/sample-api-specification.html b/docs/docs/java/dropwizard/sample-api-specification.html new file mode 100644 index 0000000000..c90f02ec77 --- /dev/null +++ b/docs/docs/java/dropwizard/sample-api-specification.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/java/dropwizard/what-is-guardrail.html b/docs/docs/java/dropwizard/what-is-guardrail.html new file mode 100644 index 0000000000..c0c867ba11 --- /dev/null +++ b/docs/docs/java/dropwizard/what-is-guardrail.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/java/index.html b/docs/docs/java/index.html new file mode 100644 index 0000000000..c2afc991f4 --- /dev/null +++ b/docs/docs/java/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/java/spring-mvc/index.html b/docs/docs/java/spring-mvc/index.html new file mode 100644 index 0000000000..bde8dfb994 --- /dev/null +++ b/docs/docs/java/spring-mvc/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/akka-http-jackson/index.html b/docs/docs/scala/akka-http-jackson/index.html new file mode 100644 index 0000000000..cd9292f4d4 --- /dev/null +++ b/docs/docs/scala/akka-http-jackson/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/akka-http/dtos.html b/docs/docs/scala/akka-http/dtos.html new file mode 100644 index 0000000000..568fd767a1 --- /dev/null +++ b/docs/docs/scala/akka-http/dtos.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/akka-http/generating-a-server.html b/docs/docs/scala/akka-http/generating-a-server.html new file mode 100644 index 0000000000..b344164f83 --- /dev/null +++ b/docs/docs/scala/akka-http/generating-a-server.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/akka-http/generating-clients.html b/docs/docs/scala/akka-http/generating-clients.html new file mode 100644 index 0000000000..bedd7a1808 --- /dev/null +++ b/docs/docs/scala/akka-http/generating-clients.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/akka-http/guardrail-extensions.html b/docs/docs/scala/akka-http/guardrail-extensions.html new file mode 100644 index 0000000000..01bc86aab7 --- /dev/null +++ b/docs/docs/scala/akka-http/guardrail-extensions.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/akka-http/index.html b/docs/docs/scala/akka-http/index.html new file mode 100644 index 0000000000..9b08813c3d --- /dev/null +++ b/docs/docs/scala/akka-http/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/akka-http/installation.html b/docs/docs/scala/akka-http/installation.html new file mode 100644 index 0000000000..3906f083ec --- /dev/null +++ b/docs/docs/scala/akka-http/installation.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/akka-http/sample-api-specification.html b/docs/docs/scala/akka-http/sample-api-specification.html new file mode 100644 index 0000000000..c90f02ec77 --- /dev/null +++ b/docs/docs/scala/akka-http/sample-api-specification.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/akka-http/what-is-guardrail.html b/docs/docs/scala/akka-http/what-is-guardrail.html new file mode 100644 index 0000000000..c0c867ba11 --- /dev/null +++ b/docs/docs/scala/akka-http/what-is-guardrail.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/dropwizard/index.html b/docs/docs/scala/dropwizard/index.html new file mode 100644 index 0000000000..3a2f00dc49 --- /dev/null +++ b/docs/docs/scala/dropwizard/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/http4s/dtos.html b/docs/docs/scala/http4s/dtos.html new file mode 100644 index 0000000000..568fd767a1 --- /dev/null +++ b/docs/docs/scala/http4s/dtos.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/http4s/generating-a-server.html b/docs/docs/scala/http4s/generating-a-server.html new file mode 100644 index 0000000000..d108582558 --- /dev/null +++ b/docs/docs/scala/http4s/generating-a-server.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/http4s/generating-clients.html b/docs/docs/scala/http4s/generating-clients.html new file mode 100644 index 0000000000..b40c26dcf5 --- /dev/null +++ b/docs/docs/scala/http4s/generating-clients.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/http4s/guardrail-extensions.html b/docs/docs/scala/http4s/guardrail-extensions.html new file mode 100644 index 0000000000..13c89fa987 --- /dev/null +++ b/docs/docs/scala/http4s/guardrail-extensions.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/http4s/index.html b/docs/docs/scala/http4s/index.html new file mode 100644 index 0000000000..791fd16ac4 --- /dev/null +++ b/docs/docs/scala/http4s/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/http4s/installation.html b/docs/docs/scala/http4s/installation.html new file mode 100644 index 0000000000..3906f083ec --- /dev/null +++ b/docs/docs/scala/http4s/installation.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/http4s/sample-api-specification.html b/docs/docs/scala/http4s/sample-api-specification.html new file mode 100644 index 0000000000..c8f88a8ac1 --- /dev/null +++ b/docs/docs/scala/http4s/sample-api-specification.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/http4s/what-is-guardrail.html b/docs/docs/scala/http4s/what-is-guardrail.html new file mode 100644 index 0000000000..c0c867ba11 --- /dev/null +++ b/docs/docs/scala/http4s/what-is-guardrail.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/docs/scala/index.html b/docs/docs/scala/index.html new file mode 100644 index 0000000000..75767dcf7d --- /dev/null +++ b/docs/docs/scala/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/modules/microsite/docs/docs/scala/akka-http/guardrail-extensions.md b/docs/extensions.md similarity index 97% rename from modules/microsite/docs/docs/scala/akka-http/guardrail-extensions.md rename to docs/extensions.md index 7fab6fd38f..03a8f25d18 100644 --- a/modules/microsite/docs/docs/scala/akka-http/guardrail-extensions.md +++ b/docs/extensions.md @@ -1,8 +1,3 @@ ---- -layout: docs -title: "guardrail extensions - akka-http - scala - guardrail" ---- - guardrail Extensions ==================== @@ -187,5 +182,3 @@ guardrail has [a number of vendor extensions](https://github.com/guardrail-dev/g - -[Prev: Generating clients](generating-clients) diff --git a/modules/microsite/docs/img/favicon.png b/docs/img/favicon.png similarity index 100% rename from modules/microsite/docs/img/favicon.png rename to docs/img/favicon.png diff --git a/modules/microsite/docs/img/favicon114x114.png b/docs/img/favicon114x114.png similarity index 100% rename from modules/microsite/docs/img/favicon114x114.png rename to docs/img/favicon114x114.png diff --git a/modules/microsite/docs/img/favicon120x120.png b/docs/img/favicon120x120.png similarity index 100% rename from modules/microsite/docs/img/favicon120x120.png rename to docs/img/favicon120x120.png diff --git a/modules/microsite/docs/img/favicon128x128.png b/docs/img/favicon128x128.png similarity index 100% rename from modules/microsite/docs/img/favicon128x128.png rename to docs/img/favicon128x128.png diff --git a/modules/microsite/docs/img/favicon144x144.png b/docs/img/favicon144x144.png similarity index 100% rename from modules/microsite/docs/img/favicon144x144.png rename to docs/img/favicon144x144.png diff --git a/modules/microsite/docs/img/favicon150x150.png b/docs/img/favicon150x150.png similarity index 100% rename from modules/microsite/docs/img/favicon150x150.png rename to docs/img/favicon150x150.png diff --git a/modules/microsite/docs/img/favicon152x152.png b/docs/img/favicon152x152.png similarity index 100% rename from modules/microsite/docs/img/favicon152x152.png rename to docs/img/favicon152x152.png diff --git a/modules/microsite/docs/img/favicon16x16.png b/docs/img/favicon16x16.png similarity index 100% rename from modules/microsite/docs/img/favicon16x16.png rename to docs/img/favicon16x16.png diff --git a/modules/microsite/docs/img/favicon196x196.png b/docs/img/favicon196x196.png similarity index 100% rename from modules/microsite/docs/img/favicon196x196.png rename to docs/img/favicon196x196.png diff --git a/modules/microsite/docs/img/favicon24x24.png b/docs/img/favicon24x24.png similarity index 100% rename from modules/microsite/docs/img/favicon24x24.png rename to docs/img/favicon24x24.png diff --git a/modules/microsite/docs/img/favicon310x150.png b/docs/img/favicon310x150.png similarity index 100% rename from modules/microsite/docs/img/favicon310x150.png rename to docs/img/favicon310x150.png diff --git a/modules/microsite/docs/img/favicon310x310.png b/docs/img/favicon310x310.png similarity index 100% rename from modules/microsite/docs/img/favicon310x310.png rename to docs/img/favicon310x310.png diff --git a/modules/microsite/docs/img/favicon32x32.png b/docs/img/favicon32x32.png similarity index 100% rename from modules/microsite/docs/img/favicon32x32.png rename to docs/img/favicon32x32.png diff --git a/modules/microsite/docs/img/favicon48x48.png b/docs/img/favicon48x48.png similarity index 100% rename from modules/microsite/docs/img/favicon48x48.png rename to docs/img/favicon48x48.png diff --git a/modules/microsite/docs/img/favicon57x57.png b/docs/img/favicon57x57.png similarity index 100% rename from modules/microsite/docs/img/favicon57x57.png rename to docs/img/favicon57x57.png diff --git a/modules/microsite/docs/img/favicon60x60.png b/docs/img/favicon60x60.png similarity index 100% rename from modules/microsite/docs/img/favicon60x60.png rename to docs/img/favicon60x60.png diff --git a/modules/microsite/docs/img/favicon64x64.png b/docs/img/favicon64x64.png similarity index 100% rename from modules/microsite/docs/img/favicon64x64.png rename to docs/img/favicon64x64.png diff --git a/modules/microsite/docs/img/favicon70x70.png b/docs/img/favicon70x70.png similarity index 100% rename from modules/microsite/docs/img/favicon70x70.png rename to docs/img/favicon70x70.png diff --git a/modules/microsite/docs/img/favicon72x72.png b/docs/img/favicon72x72.png similarity index 100% rename from modules/microsite/docs/img/favicon72x72.png rename to docs/img/favicon72x72.png diff --git a/modules/microsite/docs/img/favicon76x76.png b/docs/img/favicon76x76.png similarity index 100% rename from modules/microsite/docs/img/favicon76x76.png rename to docs/img/favicon76x76.png diff --git a/modules/microsite/docs/img/favicon96x96.png b/docs/img/favicon96x96.png similarity index 100% rename from modules/microsite/docs/img/favicon96x96.png rename to docs/img/favicon96x96.png diff --git a/modules/microsite/docs/img/first_icon.png b/docs/img/first_icon.png similarity index 100% rename from modules/microsite/docs/img/first_icon.png rename to docs/img/first_icon.png diff --git a/modules/microsite/docs/img/first_icon2x.png b/docs/img/first_icon2x.png similarity index 100% rename from modules/microsite/docs/img/first_icon2x.png rename to docs/img/first_icon2x.png diff --git a/modules/microsite/docs/img/first_icon_raw.png b/docs/img/first_icon_raw.png similarity index 100% rename from modules/microsite/docs/img/first_icon_raw.png rename to docs/img/first_icon_raw.png diff --git a/modules/microsite/docs/img/light_navbar_brand.png b/docs/img/light_navbar_brand.png similarity index 100% rename from modules/microsite/docs/img/light_navbar_brand.png rename to docs/img/light_navbar_brand.png diff --git a/modules/microsite/docs/img/light_navbar_brand2x.png b/docs/img/light_navbar_brand2x.png similarity index 100% rename from modules/microsite/docs/img/light_navbar_brand2x.png rename to docs/img/light_navbar_brand2x.png diff --git a/modules/microsite/docs/img/navbar_brand.png b/docs/img/navbar_brand.png similarity index 100% rename from modules/microsite/docs/img/navbar_brand.png rename to docs/img/navbar_brand.png diff --git a/modules/microsite/docs/img/navbar_brand2x.png b/docs/img/navbar_brand2x.png similarity index 100% rename from modules/microsite/docs/img/navbar_brand2x.png rename to docs/img/navbar_brand2x.png diff --git a/modules/microsite/docs/img/second_icon.png b/docs/img/second_icon.png similarity index 100% rename from modules/microsite/docs/img/second_icon.png rename to docs/img/second_icon.png diff --git a/modules/microsite/docs/img/second_icon2x.png b/docs/img/second_icon2x.png similarity index 100% rename from modules/microsite/docs/img/second_icon2x.png rename to docs/img/second_icon2x.png diff --git a/modules/microsite/docs/img/second_icon_raw.png b/docs/img/second_icon_raw.png similarity index 100% rename from modules/microsite/docs/img/second_icon_raw.png rename to docs/img/second_icon_raw.png diff --git a/modules/microsite/docs/img/sidebar_brand.png b/docs/img/sidebar_brand.png similarity index 100% rename from modules/microsite/docs/img/sidebar_brand.png rename to docs/img/sidebar_brand.png diff --git a/modules/microsite/docs/img/sidebar_brand2x.png b/docs/img/sidebar_brand2x.png similarity index 100% rename from modules/microsite/docs/img/sidebar_brand2x.png rename to docs/img/sidebar_brand2x.png diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000000..6a94e1f842 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,30 @@ + + + + + guardrail + + + + + + + +
+ + + + + + + diff --git a/docs/java/README.md b/docs/java/README.md new file mode 100644 index 0000000000..7ec7a48c89 --- /dev/null +++ b/docs/java/README.md @@ -0,0 +1,103 @@ +Installation +--- + +guardrail is available as a modular core, with [Maven](https://github.com/guardrail-dev/guardrail-maven-plugin) and [Gradle](https://github.com/guardrail-dev/guardrail-gradle-plugin) integration. The core can also be run as a stand-alone [CLI](cli.md) application, with full support for all features. + +| module | version | depends on | +|-----|-----|-----| +| guardrail-core | [![guardrail-core](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/guardrail-core_2.12/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:guardrail-core_2.12) | | +| guardrail-java-support | [![guardrail-java-support](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/guardrail-java-support_2.12/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:guardrail-java-support_2.12) | core | +| guardrail-java-async-http | [![guardrail-java-async-http](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/guardrail-java-async-http_2.12/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:guardrail-java-async-http_2.12) | java-support | +| guardrail-java-dropwizard | [![guardrail-java-dropwizard](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/guardrail-java-dropwizard_2.12/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:guardrail-java-dropwizard_2.12) | java-support, java-async-http | +| guardrail-java-spring-mvc | [![guardrail-java-spring-mvc](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/guardrail-java-spring-mvc_2.12/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:guardrail-java-spring-mvc_2.12) | java-support | +| guardrail-cli | [![guardrail-cli](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/guardrail-cli_2.12/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:guardrail-cli_2.12) | guardrail-core | + +### Example Maven configuration + +Latest [`guardrail-maven-plugin`](https://github.com/guardrail-dev/guardrail-maven-plugin) version [![guardrail-maven-plugin](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/guardrail-maven-plugin/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:guardrail-maven-plugin) ([Other releases](https://github.com/guardrail-dev/guardrail-maven-plugin/releases)) + +guardrail for Dropwizard is generally set up using the maven plugin. This will generate your server or client at build time. +The following is an example invocation in a `pom.xml` file: + +```xml + + + + dev.guardrail + guardrail-maven-plugin_2.12 + + + + generate-app-server + + generate-sources + + + java + dropwizard + server + server-spec.yaml + example.generated + + + + + (...) + + +``` + +For JDK9+ you also need to add [`javax.annotation:javax.annotation-api`](https://repo1.maven.org/maven2/javax/annotation/javax.annotation-api/) dependency: + +```xml + + + javax.annotation + javax.annotation-api + 1.3.2 + + +``` + +## Vavr Support + +In addition, the Java generation backend supports use of either standard +Java collections types (such as `java.util.Optional` and +`java.util.Map`), or [Vavr](https://vavr.io/) collections types (such as +`io.vavr.control.Option` and `io.vavr.collection.Vector`). Vavr's +collection types are more internally consistent and attempt to provide +an interface familiar to functional programmers. Scala developers will +find their APIs especially familiar. + +To make use of the Vavr generation, you need to instead use guardrail's +module system. Instead of specifying a `framework`, instead specify a +series of `module`s that describe the framework, protocol, and +collections library generators to use. + +For example, to use Vavr with Dropwizard, the following +`` can be used: + +```xml + + java-vavr + jackson + dropwizard + +``` + +Currently, Vavr is only supported with the `dropwizard` framework. + +Frameworks +--- + +Configuration for the following libraries is available: + +- [Dropwizard](java/dropwizard/README.md) +- [spring-mvc](java/spring-mvc/README.md) + +Sample repositories +--- + +There's a GitHub topic [here](https://github.com/topics/guardrail-sample), but a selection of those have been reproduced here: + +- [guardrail-dev/guardrail-sample-gradle-springmvc](https://github.com/guardrail-dev/guardrail-sample-gradle-springmvc) diff --git a/docs/java/_sidebar.md b/docs/java/_sidebar.md new file mode 100644 index 0000000000..f1f7f006a3 --- /dev/null +++ b/docs/java/_sidebar.md @@ -0,0 +1,8 @@ +- [Home](/) +- [What is guardrail?](about.md) +- [Sample API Specification](sample-spec.md) +- [Scala](scala/README.md) +- [Java](java/README.md) + - [dropwizard](java/dropwizard/README.md) + - [spring-mvc](java/spring-mvc/README.md) +- [Extensions](extensions.md) diff --git a/modules/microsite/docs/docs/java/dropwizard/generating-a-server.md b/docs/java/dropwizard/README.md similarity index 69% rename from modules/microsite/docs/docs/java/dropwizard/generating-a-server.md rename to docs/java/dropwizard/README.md index decfb16a0c..a7abb9dff5 100644 --- a/modules/microsite/docs/docs/java/dropwizard/generating-a-server.md +++ b/docs/java/dropwizard/README.md @@ -1,15 +1,8 @@ ---- -layout: docs -title: "Generating a Server - java - dropwizard - guardrail" ---- +## Generating a Server -Generating a Server -=================== +## Setup -Setup ------ - -As we saw in [Installation](installation), guardrail is run as part of maven. It hooks into the `generate-sources` goal. This means our generated server and client is always up-to-date with the specfificaion file. +As we saw in [Installation](java/README.md#Installation), guardrail is run as part of maven. It hooks into the `generate-sources` goal. This means our generated server and client is always up-to-date with the specfificaion file. Lets take another look at the maven config for guardrail: @@ -39,8 +32,7 @@ Lets take another look at the maven config for guardrail: Once configured, you can manually invoke guardrail with `mvn generate-sources`. -Server Handlers, Resources --------------------------- +### Server Handlers, Resources guardrail-generated servers come in two parts: a `Resource` and a `Handler`. The `Resource` contains all the JAX-RS routing logic, accepting a `Handler` as a definion of the logic to perform for the routes. The `Handler` is generated as an interface. You will write the implementation of the `Handler` and pass it to the `Resource` in the bootstrapping of the Dropwizard service. @@ -89,21 +81,47 @@ This illistrates that while guardrail has helped us with much of the setup relat (See it in action: [guardrail-dev/guardrail-sample-maven-dropwizard](https://github.com/guardrail-dev/guardrail-sample-maven-dropwizard)) -Separation of business logic ----------------------------- - -Providing an implementating of a function with a well-defined set of inputs and outputs is natural for any developer. By reducing the scope of the interface a developer writes against, implementations are more clear and concise. - -Furthermore, by providing business logic as an implementation of an abstract class, unit tests can test the routing layer and business logic independently, by design. +## Generating clients -API structure slip is impossible --------------------------------- - -As parameters are explicitly provided as arguments to functions in `Handler`s, any alteration to parameters constitute a new function interface that must be implemented. As a result, if providing an implementation for an externally managed specification, the compiler informs when a previously written function is no longer sufficient. +To generate client code with maven please include following plugin to your pom.xml: +```xml + + + + dev.guardrail + guardrail-maven-plugin_2.12 + 0.62.0 + + + generate-app-server + + generate-sources + + + java + dropwizard + client + spec.oas3.yaml + demowizard.client.generated + + + + + (...) + + +``` -By representing different response codes and structures as members of a sealed trait, it's impossible to return a structure that violates the specification, even for less frequently used response codes. +For JDK9+ you also need to add [`javax.annotation:javax.annotation-api`](https://repo1.maven.org/maven2/javax/annotation/javax.annotation-api/) dependency: -Finally, describing an endpoint in your specification without providing an implementation for it is a compiler error. This prevents reduction of functionality due to refactors, human error, or miscommunication with other teams. +```xml + + + javax.annotation + javax.annotation-api + 1.3.2 + + +``` -[Prev: Sample API specification](sample-api-specification) -[Next: Generating clients](generating-clients) +(See it in action: [guardrail-dev/guardrail-sample-maven-dropwizard](https://github.com/guardrail-dev/guardrail-sample-maven-dropwizard)) diff --git a/docs/java/dropwizard/_sidebar.md b/docs/java/dropwizard/_sidebar.md new file mode 100644 index 0000000000..8665c3a749 --- /dev/null +++ b/docs/java/dropwizard/_sidebar.md @@ -0,0 +1,7 @@ +- [Home](/) +- [What is guardrail?](about.md) +- [Sample API Specification](sample-spec.md) +- [Scala](scala/README.md) +- [Java](java/README.md) + - [dropwizard](java/dropwizard/README.md) +- [Extensions](extensions.md) diff --git a/docs/java/dropwizard/generating-a-server.html b/docs/java/dropwizard/generating-a-server.html new file mode 100644 index 0000000000..2316952a35 --- /dev/null +++ b/docs/java/dropwizard/generating-a-server.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/java/dropwizard/generating-clients.html b/docs/java/dropwizard/generating-clients.html new file mode 100644 index 0000000000..b9d919b3f9 --- /dev/null +++ b/docs/java/dropwizard/generating-clients.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/java/dropwizard/index.html b/docs/java/dropwizard/index.html new file mode 100644 index 0000000000..bebb8dd10b --- /dev/null +++ b/docs/java/dropwizard/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/java/dropwizard/installation.html b/docs/java/dropwizard/installation.html new file mode 100644 index 0000000000..0c88802e26 --- /dev/null +++ b/docs/java/dropwizard/installation.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/java/dropwizard/sample-api-specification.html b/docs/java/dropwizard/sample-api-specification.html new file mode 100644 index 0000000000..c90f02ec77 --- /dev/null +++ b/docs/java/dropwizard/sample-api-specification.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/java/dropwizard/what-is-guardrail.html b/docs/java/dropwizard/what-is-guardrail.html new file mode 100644 index 0000000000..c0c867ba11 --- /dev/null +++ b/docs/java/dropwizard/what-is-guardrail.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/java/index.html b/docs/java/index.html new file mode 100644 index 0000000000..c2afc991f4 --- /dev/null +++ b/docs/java/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/modules/microsite/docs/docs/java/spring-mvc/index.md b/docs/java/spring-mvc/README.md similarity index 83% rename from modules/microsite/docs/docs/java/spring-mvc/index.md rename to docs/java/spring-mvc/README.md index 498042600f..8029a3417e 100644 --- a/modules/microsite/docs/docs/java/spring-mvc/index.md +++ b/docs/java/spring-mvc/README.md @@ -1,7 +1,4 @@ ---- -layout: docs -title: "Spring MVC - java - guardrail" ---- +## Spring MVC These docs are under construction! diff --git a/docs/java/spring-mvc/_sidebar.md b/docs/java/spring-mvc/_sidebar.md new file mode 100644 index 0000000000..0e3e515418 --- /dev/null +++ b/docs/java/spring-mvc/_sidebar.md @@ -0,0 +1,7 @@ +- [Home](/) +- [What is guardrail?](about.md) +- [Sample API Specification](sample-spec.md) +- [Scala](scala/README.md) +- [Java](java/README.md) + - [spring-mvc](java/spring-mvc/README.md) +- [Extensions](extensions.md) diff --git a/docs/java/spring-mvc/index.html b/docs/java/spring-mvc/index.html new file mode 100644 index 0000000000..bde8dfb994 --- /dev/null +++ b/docs/java/spring-mvc/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/modules/microsite/docs/docs/scala/akka-http/sample-api-specification.md b/docs/sample-spec.md similarity index 96% rename from modules/microsite/docs/docs/scala/akka-http/sample-api-specification.md rename to docs/sample-spec.md index 1d741d643f..cd954b3c3c 100644 --- a/modules/microsite/docs/docs/scala/akka-http/sample-api-specification.md +++ b/docs/sample-spec.md @@ -1,12 +1,7 @@ ---- -layout: docs -title: "Sample API Specification - akka-http - scala - guardrail" ---- - Sample API specification ======================== -The following is a complete, annotated OpenAPI specification file: (guardrail extensions are documented in [guardrail Extensions](#guardrail-extensions)) +The following is a complete, annotated OpenAPI specification file: (guardrail extensions are documented in [guardrail Extensions](extensions.md)) ```yaml swagger: "2.0" # Which version of the OpenAPI/Swagger specification we are following @@ -126,6 +121,3 @@ definitions: # All non-primitive structures are d line3: type: string ``` - -[Prev: Installation](installation) -[Next: Generating a Server](generating-a-server) diff --git a/docs/scala/README.md b/docs/scala/README.md new file mode 100644 index 0000000000..1b43c3c3f7 --- /dev/null +++ b/docs/scala/README.md @@ -0,0 +1,80 @@ +Scala +=== + +Installation +--- + +guardrail is available as a modular core, with both [sbt](https://github.com/guardrail-dev/sbt-guardrail) and [Maven](https://github.com/guardrail-dev/guardrail-maven-plugin) integration. The core can also be run as a stand-alone [CLI](cli.md) application, with full support for all features. + +| module | version | depends on | +|-----|-----|-----| +| guardrail-scala-support | [![guardrail-scala-support](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/guardrail-scala-support_2.12/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:guardrail-scala-support_2.12) | core | +| guardrail-scala-akka-http | [![guardrail-scala-akka-http](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/guardrail-scala-akka-http_2.12/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:guardrail-scala-akka-http_2.12) | scala-support | +| guardrail-scala-dropwizard | [![guardrail-scala-dropwizard](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/guardrail-scala-dropwizard_2.12/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:guardrail-scala-dropwizard_2.12) | scala-support | +| guardrail-scala-http4s | [![guardrail-scala-http4s](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/guardrail-scala-http4s_2.12/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:guardrail-scala-http4s_2.12) | scala-support | +| guardrail-cli | [![guardrail-cli](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/guardrail-cli_2.12/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:guardrail-cli_2.12) | guardrail-core | + +### Example SBT configuration + +Latest [`sbt-guardrail`](https://github.com/guardrail-dev/sbt-guardrail) version [![sbt-guardrail](https://maven-badges.herokuapp.com/maven-central/dev.guardrail/sbt-guardrail/badge.svg)](https://search.maven.org/search?q=g:dev.guardrail%20a:sbt-guardrail) ([Other releases](https://github.com/guardrail-dev/sbt-guardrail/releases)) + +Put the following in `project/guardrail.sbt`: + +```scala +addSbtPlugin("dev.guardrail" % "sbt-guardrail" % "") +libraryDependencies += "dev.guardrail" %% "guardrail-scala-http4s" % "" +``` + +... as well as the following in `build.sbt` +```scala +guardrailTasks in Compile := List( + ScalaClient(file("github.yaml"), pkg="com.example.clients.github", framework="http4s"), +) +``` + +More configuration options available [here](https://github.com/guardrail-dev/sbt-guardrail). + +
+If compiling with Scala < 2.13.x... you'll need to enable `-Ypartial-unification`: + +```scala +scalacOptions += "-Ypartial-unification" +``` +
+ +
+If compiling with Scala < 2.12.x... you'll additionally need the `-Xexperimental` flag: + +```scala +scalacOptions += "-Xexperimental" +``` +
+ +Frameworks +--- + +Configuration for the following libraries is available: + +- [Akka-Http](scala/akka-http/README.md) +- [Http4s](scala/http4s/README.md) +- [Dropwizard](scala/dropwizard/README.md) + +Sample repositories +--- + +There's a GitHub topic [here](https://github.com/topics/guardrail-sample), but a selection of those have been reproduced here: + +- [guardrail-dev/guardrail-sample-sbt-akkahttp](https://github.com/guardrail-dev/guardrail-sample-sbt-akkahttp) +- [guardrail-dev/guardrail-sample-sbt-http4s](https://github.com/guardrail-dev/guardrail-sample-sbt-http4s) +- [guardrail-dev/guardrail-sample-sbt-http4s-zio](https://github.com/guardrail-dev/guardrail-sample-sbt-http4s-zio) + + +TODO: Figure out what to do with this +Additionally, you will need to manually include dependencies in your project for the following packages: +- `http4s`, dsl, server, and client dependencies +- `http4s-circe` for JSON decoding and encoding support +- `circe-generic` for JSON decoding and encoding support +- `cats-effect` for http4s integration +- `cats-core` for http4s integration + +Versions of these libraries should be picked by checking out the [Compatibility Matrix](https://github.com/guardrail-dev/guardrail/blob/master/COMPATIBILITY.md). diff --git a/docs/scala/_sidebar.md b/docs/scala/_sidebar.md new file mode 100644 index 0000000000..4a1e2191ce --- /dev/null +++ b/docs/scala/_sidebar.md @@ -0,0 +1,9 @@ +- [Home](/) +- [What is guardrail?](about.md) +- [Sample API Specification](sample-spec.md) +- [Scala](scala/README.md) + - [akka-http](scala/akka-http/README.md) + - [http4s](scala/http4s/README.md) + - [pekko-http](scala/pekko-http/README.md) +- [Java](java/README.md) +- [Extensions](extensions.md) diff --git a/docs/scala/akka-http-jackson/index.html b/docs/scala/akka-http-jackson/index.html new file mode 100644 index 0000000000..78273a3bff --- /dev/null +++ b/docs/scala/akka-http-jackson/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/modules/microsite/docs/docs/scala/akka-http/generating-a-server.md b/docs/scala/akka-http/README.md similarity index 71% rename from modules/microsite/docs/docs/scala/akka-http/generating-a-server.md rename to docs/scala/akka-http/README.md index 92a3d4a488..f9c7ffd871 100644 --- a/modules/microsite/docs/docs/scala/akka-http/generating-a-server.md +++ b/docs/scala/akka-http/README.md @@ -1,10 +1,6 @@ ---- -layout: docs -title: "Generating a Server - akka-http - scala - guardrail" ---- +# Akka-Http -Generating a Server -=================== +## Generating a Server guardrail-generated servers come in two parts: a `Resource` and a `Handler`. The `Resource` contains all the routing logic, accepting a `Handler` as an argument to the `route` function in order to provide an HTTP service in whichever supported HTTP framework you're hosting your service in. @@ -26,24 +22,7 @@ As all parameters are provided as arguments to the function stubs in the trait, (See it in action: [guardrail-dev/guardrail-sample-sbt-akkahttp](https://github.com/guardrail-dev/guardrail-sample-sbt-akkahttp)) -Separation of business logic ----------------------------- - -Providing an implementation of a function with a well-defined set of inputs and outputs is natural for any developer. By reducing the scope of the interface a developer writes against, implementations are more clear and concise. - -Furthermore, by providing business logic as an implementation of an abstract class, unit tests can test the routing layer and business logic independently, by design. - -API structure slip is impossible --------------------------------- - -As parameters are explicitly provided as arguments to functions in `Handler`s, any alteration to parameters constitute a new function interface that must be implemented. As a result, if providing an implementation for an externally managed specification, the compiler informs when a previously written function is no longer sufficient. - -By representing different response codes and structures as members of a sealed trait, it's impossible to return a structure that violates the specification, even for less frequently used response codes. - -Finally, describing an endpoint in your specification without providing an implementation for it is a compiler error. This prevents reduction of functionality due to refactors, human error, or miscommunication with other teams. - -Extracting custom data from a request -------------------------------------- +### Extracting custom data from a request In some cases, you may wish to extract data from a request and inject it into your handler, without specifying the extracted data in the OpenAPI definition. Common use cases include integrating with existing `Directive`s, accessing underlying data provided by akka-http but without a direct analog in OpenAPI, as well as providing an escape hatch to inject functionality expressed via akka-http's `Directive` directly into the Akka HTTP routes generated by guardrail. @@ -86,8 +65,7 @@ val userRoutes = UserResource.routes(new UserApi, extractXUserId) Because `E` is an arbitrary type, you may extract anything, including the full `HttpRequest` itself. Multiple values may be extracted using tuples. If you do not wish to extract anything, perhaps because the `Directive` acts as a gate which `pass`es some requests and `reject`s others, simply provide `String => Directive1[Unit]` and write your handler implementation to extend `Handler[Unit]`. -Generating test-only (real) server mocks for unit tests -------------------------------------------------------- +## Generating test-only (real) server mocks for unit tests Often, we'll also want to have mock HTTP clients for use in unit tests. Mocking requires stringent adherence to the specification, otherwise our mock clients are unrepresentative of the production systems they are intending to mock. The following is an example of a "mock" HTTP Client generated by guardrail; it speaks real HTTP, though doesn't need to bind to a port in order to run. This permits parallelized tests to be run without concern of port contention. @@ -120,10 +98,7 @@ val binding: ServerBinding = binding.unbind().futureValue ``` -A note about scalatest integration ----------------------------------- - -### akka-http +### A note about scalatest integration The default `ExceptionHandler` in akka-http swallows exceptions, so if you intend to `fail()` tests from inside guardrail-generated HTTP Servers, you'll likely want to have the following implicit in scope: @@ -147,5 +122,54 @@ val user: User = getUserResponse.map(_.fold(user => user)).value.futureValue.rig `futureValue` will raise the `TestFailedException` with the relevant stack trace. -[Prev: Sample API specification](sample-api-specification) -[Next: Generating clients](generating-clients) +## Generating clients + +As we've seen in [Generating a Server](scala/akka-http/README.md#generating-a-server), guardrail-generated servers establish a mapping between our business logic and a cordoned off subset of HTTP. This permits us to focus on our business logic, without getting overloaded with the complexities of managing such a large protocol. The same is true with guardrail generated HTTP Clients: from a consumer's standpoint, HTTP calls should look like regular function calls, accepting domain-specific arguments and producing domain-specific results. + +By generating minimal clients that only have enough business knowledge to map domain types to and from HTTP, opportunities for logical errors are effectively removed. While this does not eliminate logical errors entirely, establishing a firm boundary between the underlying protocol and hand-written code drastically reduces the scope of possible bugs. + +The following is an example from the [akka-http](https://github.com/akka/akka-http) client generator: + +```scala mdoc:passthrough +import dev.guardrail.docs._ +DocsHelpers.renderScalaSnippet("akka-http", GeneratingClients)( + """|// Two constructors are provided, one accepting the `httpClient`, + |// `ExecutionContext`, and `Materializer` implicitly, the other accepting + |// an explicit `httpClient`, but still accepting the `ExecutionContext` and + |// `Materializer` as implicits. + """.stripMargin, + "" +) +``` + +(See it in action: [guardrail-dev/guardrail-sample-sbt-akkahttp](https://github.com/guardrail-dev/guardrail-sample-sbt-akkahttp)) + +### Separation of protocol-concerns from API-level concerns + +As guardrail clients are built on top of the function type `HttpRequest => Future[HttpResponse]`, client configuration is reduced to function composition. Some ideas: + +```scala +val singleRequestHttpClient = { (req: HttpRequest) => + Http().singleRequest(req) +} + +val retryingHttpClient = { nextClient: (HttpRequest => Future[HttpResponse]) => + req: HttpRequest => nextClient(req).flatMap(resp => if (resp.status.intValue >= 500) nextClient(req) else Future.successful(resp)) +} + +val metricsHttpClient = { nextClient: (HttpRequest => Future[HttpResponse]) => + req: HttpRequest => { + val resp = nextClient(req) + resp.onSuccess { _resp => + trackMetrics(req.uri.path, _resp.status) + } + resp + } +} + +// Track metrics for every request, even retries +val retryingMetricsClient1: HttpRequest => Future[HttpResponse] = retryingHttpClient(metricsHttpClient(singleRequestHttpClient)) + +// Only track metrics for requests we didn't have to retry +val retryingMetricsClient2: HttpRequest => Future[HttpResponse] = metricsHttpClient(retryingHttpClient(singleRequestHttpClient)) +``` diff --git a/docs/scala/akka-http/_sidebar.md b/docs/scala/akka-http/_sidebar.md new file mode 100644 index 0000000000..f03fec360f --- /dev/null +++ b/docs/scala/akka-http/_sidebar.md @@ -0,0 +1,8 @@ +- [Home](/) +- [What is guardrail?](about.md) +- [Sample API Specification](sample-spec.md) +- [Scala](scala/README.md) + - [akka-http](scala/akka-http/README.md) + - [akka-http-jackson](scala/akka-http/jackson.md) +- [Java](java/README.md) +- [Extensions](extensions.md) diff --git a/docs/scala/akka-http/dtos.html b/docs/scala/akka-http/dtos.html new file mode 100644 index 0000000000..568fd767a1 --- /dev/null +++ b/docs/scala/akka-http/dtos.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/akka-http/generating-a-server.html b/docs/scala/akka-http/generating-a-server.html new file mode 100644 index 0000000000..b344164f83 --- /dev/null +++ b/docs/scala/akka-http/generating-a-server.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/akka-http/generating-clients.html b/docs/scala/akka-http/generating-clients.html new file mode 100644 index 0000000000..bedd7a1808 --- /dev/null +++ b/docs/scala/akka-http/generating-clients.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/akka-http/guardrail-extensions.html b/docs/scala/akka-http/guardrail-extensions.html new file mode 100644 index 0000000000..01bc86aab7 --- /dev/null +++ b/docs/scala/akka-http/guardrail-extensions.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/akka-http/index.html b/docs/scala/akka-http/index.html new file mode 100644 index 0000000000..9b08813c3d --- /dev/null +++ b/docs/scala/akka-http/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/akka-http/installation.html b/docs/scala/akka-http/installation.html new file mode 100644 index 0000000000..3906f083ec --- /dev/null +++ b/docs/scala/akka-http/installation.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/modules/microsite/docs/docs/scala/akka-http-jackson/index.md b/docs/scala/akka-http/jackson.md similarity index 80% rename from modules/microsite/docs/docs/scala/akka-http-jackson/index.md rename to docs/scala/akka-http/jackson.md index f0af04d490..38c208204f 100644 --- a/modules/microsite/docs/docs/scala/akka-http-jackson/index.md +++ b/docs/scala/akka-http/jackson.md @@ -1,21 +1,18 @@ ---- -layout: docs -title: "akka-http-jackson - scala - guardrail" ---- +## akka-http Jackson The `akka-http-jackson` framework generates the same server and client -APIs as the [akka-http](../akka-http) framework, except that Jackson is +APIs as the [akka-http](scala/akka-http/README.md) framework, except that Jackson is used for serialization and deserialization (instead of Circe). Usage-wise, it is very similar to `akka-http`. Extra information specific to this framework can be found below. -## guardrail Configuration +### guardrail Configuration -You can either specify the `akka-http-jackson` framework, or the +You can either specify the `akka-http-jackson` framework, or select the `akka-http` and `jackson` modules. -## Prerequisites +### Prerequisites In addition to the akka-http dependencies, you'll need the following: @@ -32,7 +29,7 @@ While testing has been done with Jackson 2.11.x, older 2.x versions should work as well. Hibernate Validator 5.4.x and 6.0.x have been tested and appear to work. -## Server and Client Construction +### Server and Client Construction When constructing your server routes or client instances, you'll need implicit `ObjectMapper` (Jackson) and `Validator` (Hibernate) instances @@ -46,8 +43,7 @@ spec uses date or date-time string formats, you must also register ### `Validator` -The validator can [be -constructed](https://docs.jboss.org/hibernate/validator/5.4/reference/en-US/html_single/#section-retrieving-validator-factory-validator) +The validator can [be constructed](https://docs.jboss.org/hibernate/validator/5.4/reference/en-US/html_single/#section-retrieving-validator-factory-validator) in whatever manner you desire. Hibernate is recommended, but guardrail does not currently use any Hibernate-specific annotations; however, it may do so in the future as more strict validations are implemented. diff --git a/docs/scala/akka-http/sample-api-specification.html b/docs/scala/akka-http/sample-api-specification.html new file mode 100644 index 0000000000..c90f02ec77 --- /dev/null +++ b/docs/scala/akka-http/sample-api-specification.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/akka-http/what-is-guardrail.html b/docs/scala/akka-http/what-is-guardrail.html new file mode 100644 index 0000000000..c0c867ba11 --- /dev/null +++ b/docs/scala/akka-http/what-is-guardrail.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/modules/microsite/docs/docs/scala/dropwizard/index.md b/docs/scala/dropwizard/README.md similarity index 96% rename from modules/microsite/docs/docs/scala/dropwizard/index.md rename to docs/scala/dropwizard/README.md index 10dd8b5d5e..a0bc8d5a0e 100644 --- a/modules/microsite/docs/docs/scala/dropwizard/index.md +++ b/docs/scala/dropwizard/README.md @@ -1,7 +1,4 @@ ---- -layout: docs -title: "dropwizard - scala - guardrail" ---- +# Dropwizard The `dropwizard` framework generates Scala code for Dropwizard, using Jackson for serialization. @@ -28,7 +25,7 @@ with Jersey in your application's `run()` method using ### Usage Server usage follows the same pattern as the Scala -[akka-http](../akka-http) framework. You must implement a `Handler` +[akka-http](scala/akka-http/README.md) framework. You must implement a `Handler` class for each resource. Each handler method takes a `respond` parameter, which allows you to easily construct response instances, plus all parameters specified for the method's underlying operation. The diff --git a/docs/scala/dropwizard/index.html b/docs/scala/dropwizard/index.html new file mode 100644 index 0000000000..3a2f00dc49 --- /dev/null +++ b/docs/scala/dropwizard/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/http4s/README.md b/docs/scala/http4s/README.md new file mode 100644 index 0000000000..1c4f9c6f1d --- /dev/null +++ b/docs/scala/http4s/README.md @@ -0,0 +1,71 @@ +## Generating a Server + +guardrail-generated servers come in two parts: a `Resource` and a `Handler`. The `Resource` contains all the routing logic, accepting a `Handler` as an argument to the `route` function in order to provide an HTTP service in whichever supported HTTP framework you're hosting your service in. + +The following is an example from the [http4s](https://github.com/http4s/http4s) server generator: + +```scala mdoc:passthrough +import dev.guardrail.docs._ +DocsHelpers.renderScalaSnippet("http4s", GeneratingAServer)(""" + |// The `Handler` trait is fully abstracted from the underlying http framework. As a result, with the exception of some + |// structural alterations (`F[_]` instead of `Future[_]` as the return type) the same handlers can be used with + |// different `Resource` implementations from different framework generators. This permits greater compatibility between + |// different frameworks without changing your business logic. + """.stripMargin, + "" +) +``` + +As all parameters are provided as arguments to the function stubs in the trait, there's no concern of forgetting to extract a query string parameter or introducing a typo in a form parameter name. + +The routes and resources generated by guardrail can be hooked up into your HTTP4s server like so: + +```scala +import org.http4s.ember.server.EmberServerBuilder + +class UserImpl extends UserHandler[IO] { /* Your code here */ } +val userHandler: UserHandler[IO] = new UserImpl +val usersService = new UsersResource[IO]().routes(userHandler) +val httpApp = usersService.orNotFound + +// Same basic server setup as in the http4s quickstart +EmberServerBuilder.default[IO] + .withHttpApp(httpApp) + .build + .use(_ => IO.never) + .as(ExitCode.Success) +``` + +(See it in action: [guardrail-dev/guardrail-sample-http4s](https://github.com/guardrail-dev/guardrail-sample-http4s), [guardrail-dev/guardrail-sample-sbt-http4s-zio](https://github.com/guardrail-dev/guardrail-sample-sbt-http4s-zio)) + +Generating clients +================== + +As we've seen in [Generating a Server](scala/http4s/README.md#generating-a-server), guardrail-generated servers establish a mapping between our business logic and a cordoned off subset of HTTP. This permits us to focus on our business logic, without getting overloaded with the complexities of managing such a large protocol. The same is true with guardrail generated HTTP Clients: from a consumer's standpoint, HTTP calls should look like regular function calls, accepting domain-specific arguments and producing domain-specific results. + +By generating minimal clients that only have enough business knowledge to map domain types to and from HTTP, opportunities for logical errors are effectively removed. While this does not eliminate logical errors entirely, establishing a firm boundary between the underlying protocol and hand-written code drastically reduces the scope of possible bugs. + +The following is an example from the [http4s](https://github.com/http4s/http4s) client generator: + +```scala mdoc:passthrough +import dev.guardrail.docs._ +DocsHelpers.renderScalaSnippet("http4s", GeneratingClients)( + """|// Two constructors are provided, one accepting the `httpClient` and `Async` + |// implicitly, the other accepting an explicit `httpClient`, but still + |// accepting the `Async` implicitly + """.stripMargin, + "" +) +``` + +(See it in action: [guardrail-dev/guardrail-sample-http4s](https://github.com/guardrail-dev/guardrail-sample-http4s), [guardrail-dev/guardrail-sample-sbt-http4s-zio](https://github.com/guardrail-dev/guardrail-sample-sbt-http4s-zio)) + +Separation of protocol-concerns from API-level concerns +------------------------------------------------------- + +As guardrail clients are built on top of any Http4s client type, client configuration is done the same way as you are +already familiar with when using Http4s. + +Check out the docs for [Http4s Clients](https://http4s.org/v0.23/client/). + +[Prev: Generating a Server](generating-a-server) diff --git a/docs/scala/http4s/_sidebar.md b/docs/scala/http4s/_sidebar.md new file mode 100644 index 0000000000..0d56e52fe1 --- /dev/null +++ b/docs/scala/http4s/_sidebar.md @@ -0,0 +1,7 @@ +- [Home](/) +- [What is guardrail?](about.md) +- [Sample API Specification](sample-spec.md) +- [Scala](scala/README.md) + - [http](scala/http4s/README.md) +- [Java](java/README.md) +- [Extensions](extensions.md) diff --git a/docs/scala/http4s/dtos.html b/docs/scala/http4s/dtos.html new file mode 100644 index 0000000000..568fd767a1 --- /dev/null +++ b/docs/scala/http4s/dtos.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/http4s/generating-a-server.html b/docs/scala/http4s/generating-a-server.html new file mode 100644 index 0000000000..d108582558 --- /dev/null +++ b/docs/scala/http4s/generating-a-server.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/http4s/generating-clients.html b/docs/scala/http4s/generating-clients.html new file mode 100644 index 0000000000..b40c26dcf5 --- /dev/null +++ b/docs/scala/http4s/generating-clients.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/http4s/guardrail-extensions.html b/docs/scala/http4s/guardrail-extensions.html new file mode 100644 index 0000000000..13c89fa987 --- /dev/null +++ b/docs/scala/http4s/guardrail-extensions.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/http4s/index.html b/docs/scala/http4s/index.html new file mode 100644 index 0000000000..791fd16ac4 --- /dev/null +++ b/docs/scala/http4s/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/http4s/installation.html b/docs/scala/http4s/installation.html new file mode 100644 index 0000000000..3906f083ec --- /dev/null +++ b/docs/scala/http4s/installation.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/http4s/sample-api-specification.html b/docs/scala/http4s/sample-api-specification.html new file mode 100644 index 0000000000..c8f88a8ac1 --- /dev/null +++ b/docs/scala/http4s/sample-api-specification.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/http4s/what-is-guardrail.html b/docs/scala/http4s/what-is-guardrail.html new file mode 100644 index 0000000000..c0c867ba11 --- /dev/null +++ b/docs/scala/http4s/what-is-guardrail.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/index.html b/docs/scala/index.html new file mode 100644 index 0000000000..75767dcf7d --- /dev/null +++ b/docs/scala/index.html @@ -0,0 +1,14 @@ + + + + + + + Page Redirection + + + If you are not redirected automatically, follow this link to example. + + diff --git a/docs/scala/pekko-http/README.md b/docs/scala/pekko-http/README.md new file mode 100644 index 0000000000..5de0c10057 --- /dev/null +++ b/docs/scala/pekko-http/README.md @@ -0,0 +1,3 @@ +## pekko-http + +Pekko HTTP support is still in prerelease, though you can try it out following the example [here](https://github.com/guardrail-dev/guardrail-sample-sbt-pekkohttp/pull/1), with the full sample project here: [guardrail-dev/guardrail-sample-sbt-pekkohttp](https://github.com/guardrail-dev/guardrail-sample-sbt-pekkohttp) diff --git a/docs/scala/pekko-http/_sidebar.md b/docs/scala/pekko-http/_sidebar.md new file mode 100644 index 0000000000..e6491d9931 --- /dev/null +++ b/docs/scala/pekko-http/_sidebar.md @@ -0,0 +1,7 @@ +- [Home](/) +- [What is guardrail?](about.md) +- [Sample API Specification](sample-spec.md) +- [Scala](scala/README.md) + - [pekko-http](scala/pekko-http/README.md) +- [Java](java/README.md) +- [Extensions](extensions.md) diff --git a/modules/core/src/main/scala/dev/guardrail/runner/GuardrailRunner.scala b/modules/core/src/main/scala/dev/guardrail/runner/GuardrailRunner.scala index 972c4d54b9..9bb96a7475 100644 --- a/modules/core/src/main/scala/dev/guardrail/runner/GuardrailRunner.scala +++ b/modules/core/src/main/scala/dev/guardrail/runner/GuardrailRunner.scala @@ -24,4 +24,7 @@ abstract class GuardrailRunner { .productL(Target.pushLogger(StructuredLogger.reset)) ) } yield result + + def unsafeGuardrailRunner(language: String, args: Array[Args]): Array[Path] = + Target.unsafeExtract(guardrailRunner(language, args)).toArray } diff --git a/modules/microsite/build.sbt b/modules/microsite/build.sbt deleted file mode 100644 index b1c7597c6f..0000000000 --- a/modules/microsite/build.sbt +++ /dev/null @@ -1,54 +0,0 @@ -enablePlugins(MicrositesPlugin) -micrositePushSiteWith := GitHub4s -micrositeGithubToken := Option(System.getenv("MICROSITE_PUBLISH_TOKEN")) - -micrositeName := "guardrail" -micrositeDescription := "Principled code generation from OpenAPI specifications" -micrositeUrl := "https://guardrail.dev/" -micrositeAuthor := "guardrail.dev" -micrositeOrganizationHomepage := "https://guardrail.dev/" -micrositeTwitter := "@guardrail_code" -micrositeTwitterCreator := "@guardrail_dev" -micrositeGithubOwner := "guardrail-dev" -micrositeGithubRepo := "guardrail" -micrositeHighlightLanguages ++= Seq("yaml", "scala") -micrositeGitterChannel := false -micrositeAnalyticsToken := "UA-154175369-1" -micrositeGoogleAnalytics4Token := "G-L51EVMQF15" -micrositeTheme := "light" -mdocIn := baseDirectory.value / "docs" -//micrositeDataDirectory := baseDirectory.value / "docs" / "data" -//micrositeImgDirectory := baseDirectory.value / "docs" / "images" - -micrositeDocumentationLabelDescription := "Documentation" -micrositeDocumentationUrl := "docs" -micrositeHomeButtonTarget := "docs" -micrositeBaseUrl := "." - -// micrositeCssDirectory -// micrositeExternalIncludesDirectory -// micrositeExternalLayoutsDirectory -// micrositeJsDirectory -// micrositePluginsDirectory -// micrositeStaticDirectory - -// micrositeCDNDirectives -// micrositeConfig -// micrositeConfigYaml -// micrositeEditButton -// micrositeExtraMdFiles -// micrositeExtraMdFilesOutput -// micrositeFavicons -// micrositeFooterText -// micrositeGitHostingService -// micrositeGitHostingUrl -// micrositeGithubLinks -// micrositeGitterChannelUrl -// micrositeHighlightTheme -// micrositeHomepage -// micrositeMakeExtraMdFiles -// micrositeOrganizationHomepage -// micrositePalette -// micrositeShareOnSocial -// micrositeTutExtraMdFiles -// micrositeTwitter diff --git a/modules/microsite/docs/docs/index.md b/modules/microsite/docs/docs/index.md deleted file mode 100644 index 8e8ac53074..0000000000 --- a/modules/microsite/docs/docs/index.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -layout: docs -title: Getting started -section: page ---- - -Getting started: -- Scala - - [akka-http](scala/akka-http) - - [akka-http-jackson](scala/akka-http-jackson) - - [http4s](scala/http4s) - - [dropwizard](scala/dropwizard) -- Java - - [dropwizard](java/dropwizard) - - [spring-mvc](java/spring-mvc) diff --git a/modules/microsite/docs/docs/java/dropwizard/generating-clients.md b/modules/microsite/docs/docs/java/dropwizard/generating-clients.md deleted file mode 100644 index 6ebc3ce06a..0000000000 --- a/modules/microsite/docs/docs/java/dropwizard/generating-clients.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -layout: docs -title: "Generating Clients - java - dropwizard - guardrail" ---- - -To generate client code with maven please include following plugin to your pom.xml: -```xml - - - - dev.guardrail - guardrail-maven-plugin_2.12 - 0.62.0 - - - generate-app-server - - generate-sources - - - java - dropwizard - client - spec.oas3.yaml - demowizard.client.generated - - - - - (...) - - -``` - -For JDK9+ you also need to add [`javax.annotation:javax.annotation-api`](https://repo1.maven.org/maven2/javax/annotation/javax.annotation-api/) dependency: - -```xml - - - javax.annotation - javax.annotation-api - 1.3.2 - - -``` - -(See it in action: [guardrail-dev/guardrail-sample-maven-dropwizard](https://github.com/guardrail-dev/guardrail-sample-maven-dropwizard)) diff --git a/modules/microsite/docs/docs/java/dropwizard/index.md b/modules/microsite/docs/docs/java/dropwizard/index.md deleted file mode 100644 index d4259ea061..0000000000 --- a/modules/microsite/docs/docs/java/dropwizard/index.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -layout: docs -title: "dropwizard - java - guardrail" ---- - -Table of Contents -================= - -1. [What is guardrail](what-is-guardrail) - 1. [Single Point of Truth](what-is-guardrail#single-point-of-truth) - 1. [Unexpected API changes are compiler errors](what-is-guardrail#unexpected-api-changes-are-compiler-errors) - 1. [Fewer binary dependencies](what-is-guardrail#fewer-binary-dependencies) -1. [Installation](installation) -1. [Sample API specification](sample-api-specification) -1. [Generating a Server](generating-a-server) - 1. [Setup](generating-a-server#setup) - 1. [Server Handlers, Resources](generating-a-server#server-handlers-resources) - 1. [Separation of business logic](generating-a-server#separation-of-business-logic) - 1. [API structure slip is impossible](generating-a-server#api-structure-slip-is-impossible) -1. [Generating clients](generating-clients) - -Java Dropwizard ---------------- - -Support for Dropwizard 1.3 has been available since guardrail v0.45.0. - -Using guardrail you can generate server definions and http clients. diff --git a/modules/microsite/docs/docs/java/dropwizard/installation.md b/modules/microsite/docs/docs/java/dropwizard/installation.md deleted file mode 100644 index df037761c2..0000000000 --- a/modules/microsite/docs/docs/java/dropwizard/installation.md +++ /dev/null @@ -1,55 +0,0 @@ ---- -layout: docs -title: "Installation - java - dropwizard - guardrail" ---- - -Installation -============ - -guardrail is available as a modular core, with both [sbt](https://github.com/guardrail-dev/sbt-guardrail) and [Maven](https://github.com/guardrail-dev/guardrail-maven-plugin) integration. The core can also be run as a stand-alone [CLI](https://github.com/guardrail-dev/guardrail/blob/978a92db3dd46812aa19f05050995f864cbb5bb3/build.sbt#L33-L48) application, with full support for all features. - -guardrail for Dropwizard is generally set up using the maven plugin. This will generate your server or client at build time. -The following is an example invocation in a `pom.xml` file: - -```xml - - - - dev.guardrail - guardrail-maven-plugin_2.12 - 0.62.0 - - - generate-app-server - - generate-sources - - - java - dropwizard - server - server-spec.yaml - demowizard.generated - - - - - (...) - - -``` - -For JDK9+ you also need to add [`javax.annotation:javax.annotation-api`](https://repo1.maven.org/maven2/javax/annotation/javax.annotation-api/) dependency: - -```xml - - - javax.annotation - javax.annotation-api - 1.3.2 - - -``` - -[Prev: What is guardrail?](what-is-guardrail) -[Next: Sample API specification](sample-api-specification) diff --git a/modules/microsite/docs/docs/java/dropwizard/sample-api-specification.md b/modules/microsite/docs/docs/java/dropwizard/sample-api-specification.md deleted file mode 100644 index a47bd74108..0000000000 --- a/modules/microsite/docs/docs/java/dropwizard/sample-api-specification.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -layout: docs -title: "Sample API Specification - java - dropwizard - guardrail" ---- - -Sample API specification -======================== - -The following is a complete, annotated OpenAPI specification file: (guardrail extensions are documented in [guardrail Extensions](../../scala/akka-http/guardrail-extensions)) - - -```yaml -openapi: 3.0.0 # Version of Swagger/OpenAPI of this file -info: # Primarily for consumption by documentation generation tools - title: My Service - version: 0.1.0 -servers: # List of hosts (and ports) where generated clients should connect to - - url: http://localhost:1234 -paths: # All HTTP Paths are children of this `paths` field - "/user/{id}": # Paths can have variables in them - get: # HTTP Method - operationId: getUser # Friendly name, will be the method name in generated clients and servers - x-jvm-package: users # Relative package for this client to live in - parameters: # All parameters (including path parameters) are listed here. - - name: id # Field name, case sensitive - in: path # where the parameter will be found. - description: The ID of the user # description of the parameter. Not used in guardrail, but other tools may consume it - required: true # required fields can not be missing. Optional fields will become `Optional` - schema: - type: string # One of the primitive types supported in the OpenAPI specification. - x-java-type: CustomString # Escape hatch to explicitly introduce a custom type. This is an - # advanced technique to introduce completely custom - # marshalling/unmarshalling/validation logic. Keep in mind, everyone - # else will just see a plain string! - - responses: # All response codes that are possible for this path are listed here - "200": # Each HTTP status code is mapped to the corresponding textual representation - description: "" - content: - "application/json": # the Content-Type of the return value. Java guardrail will use jackson for converting json - schema: - $ref: "#/components/schemas/User" # a reference to elsewhere in this spec for a definition of the response body - "404": # failure responses must be declared - description: Not found # description isn't used by guardrail but is useful to indiciate we return no body for this response -components: # reusable sections of the spec can be described under `components` - schemas: - User: # This identifies a symbolic structure name. Not all names are - # translated into classes when rendered, depending on whether they - # identify classes with structure, or defer to standard classes - # like `Vector` for `type: array`. - type: object # will generate a `User` case class in the `definitions` package - required: # A list of which parameters are required. This is enforced for - # clients by having non-optional parameters, and for servers by - # ensuring all submitted data to the endpoint validates the schema - # before getting to your `Handler` function. - - id # These names must match the `properties` names exactly - - user_addresses - properties: - id: # Case matters for `properties`! A heuristic determines whether it's - # possible to translate a property name into a unique, non-reserved - # camelCase identifier. - type: string # One of the primitive types supported in the OpenAPI specification. - user_addresses: # Similar to `id`, though `user_addresses` can be safely transformed into - # `userAddress`, so this is done to expose idiomatic Java. The underlying - # marshallers and unmarshallers maintain this mapping for you though, - # so no chance of protocol violations. - $ref: "#/components/schemas/UserAddresses" # Ensures that the type of `userAddress` will be `List` - UserAddresses: - type: array - items: - $ref: "#/components/schemas/UserAddress" # `items` is a special key for `type: array`, identifying the structure of the - # sequence members - UserAddress: - type: object - properties: - line1: - type: string - line2: - type: string - line3: - type: string - -``` - - -[Prev: Installation](installation) -[Next: Generating a Server](generating-a-server) diff --git a/modules/microsite/docs/docs/java/dropwizard/what-is-guardrail.md b/modules/microsite/docs/docs/java/dropwizard/what-is-guardrail.md deleted file mode 100644 index 4472c4639e..0000000000 --- a/modules/microsite/docs/docs/java/dropwizard/what-is-guardrail.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -layout: docs -title: "What is guardrail? - java - dropwizard - guardrail" ---- - -What is guardrail? -================== - -guardrail is a code generation tool, capable of reading from OpenAPI/Swagger specification files and generating Java source code for HTTP clients and backend frameworks like Dropwizard and Sprint MVC. - -guardrail has three primary goals: - -- Documentation: Single point of truth for the interface to a software system -- Better Servers: Unexpected API changes surface as compiler errors via server routing layer code generation -- Better Clients: Fewer binary dependencies via client library code generation - -Describing software is tricky. Incomplete specifications, slippage between specification and implementation, or even additional semantics of infrastructure that aren't easily communicated through static documents; these are only a few challenges you'll face when attempting to write a specification for your API. A reasonable question you may be asking is what motivations are there for going through these cumbersome and often frustrating tasks? We'll investigate some answers to this question in the following sections. - -Single Point of Truth ---------------------- - -By describing the shape of an API statically, there are far fewer variables to worry about. HTTP is a _very_ flexible protocol, with many features. By constraining that protocol to a subset that expresses the interface to our server (or service, or microservice), we drastically reduce the burden of handling the entirety of HTTP to the core terms of our API. Focus on semantics of APIs once the basics (routing, data validation) are figured out. - -A secondary benefit of static specifications lies in tooling. Hand-written routing logic can hide security holes, miss best practices, and obscure intent if written incorrectly. This problem is multipled across as many different languages as are supported inside any given company, manifesting as wasted effort implementing the same feature in different languages, or a bug that only occurs 10 percent of the time due to a buggy golang client. - -Attempting to derive what the attack surface of a server is from the implementation is often the job of entire teams in large companies, and even that may not be enough. Conversely, with a static specification, those teams can build intelligent traffic analysis tools to detect anomalies or intentionally malicious clients built to inject bad data to find bugs. - -Unexpected API changes are compiler errors ------------------------------------------- - -Once we have a specification, generating traits (or abstract classes) with unimplemented members gives us another powerful tool: New or changed parameters become compiler errors. - -After constraining our vocabulary to a subset of HTTP that serves our business need, even saying "This parameter is optional" forces us to contend with the sudden appearance of `Optional` parameters in our generated `Handler` methods. - -Once specified, `-Werror` helpfully points out that we've forgotten to reflect this most recent change in our tests. A win on both fronts! - -Fewer binary dependencies ----------------------- - -Traditionally written and maintained client libraries invariably accumulate cruft. In many cases, this is intended to be helpful: papering over a poorly designed API by providing custom logic, renaming parameters to be more convenient, or including properly configured HTTP clients that express retry and backoff semantics the library author provided based on the business requirements known at the time of writing. - -Altering the shape of an API by providing a thick HTTP client reduces the shared terminology between service maintainers and their consumers, or even between consumers coming from different languages. - -Additionally, by hardcoding even a well-behaved HTTP client into a client library, now consumers are forced to work around that dependency. This may manifest as learning how to use and configure a brand new HTTP client under time pressure, or writing and maintaining brittle [Application Binary Interface (ABI)](https://en.wikipedia.org/wiki/Application_binary_interface)-compatible adapter layers that attempt to use the configuration already present in the rest of the codebase. - -Once these bespoke HTTP client configurations are built, both they and their dependencies are now added to the grab bag of dependency versions that must be maintained through the life of any given piece of infrastructure. This presents hidden barriers for upgrading all dependencies, as the possibility of transitive dependency conflicts increase as dependency trees become deeper. - -[Next: Installation](installation) diff --git a/modules/microsite/docs/docs/java/index.md b/modules/microsite/docs/docs/java/index.md deleted file mode 100644 index 98cc8c92a8..0000000000 --- a/modules/microsite/docs/docs/java/index.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -layout: docs -title: "java - guardrail" ---- - -guardrail can generate Java clients and servers for the following -frameworks: - -* [`dropwizard`](dropwizard/) -* [`spring-mvc`](spring-mvc/) - -In addition, the Java generation backend supports use of either standard -Java collections types (such as `java.util.Optional` and -`java.util.Map`), or [Vavr](https://vavr.io/) collections types (such as -`io.vavr.control.Option` and `io.vavr.collection.Vector`). Vavr's -collection types are more internally consistent and attempt to provide -an interface familiar to functional programmers. Scala developers will -find their APIs especially familiar. - -To make use of the Vavr generation, you need to instead use guardrail's -module system. Instead of specifying a `framework`, instead specify a -series of `module`s that describe the framework, protocol, and -collectsions library generators to use. For example, if I were using -the guardrail Maven plugin, and wanted to use Vavr with Dropwizard, I'd -include in my ``: - -```xml - - java-vavr - jackson - dropwizard - -``` - -Currently, Vavr is only supported with the `dropwizard` framework. diff --git a/modules/microsite/docs/docs/scala/akka-http/dtos.md b/modules/microsite/docs/docs/scala/akka-http/dtos.md deleted file mode 100644 index abb9646780..0000000000 --- a/modules/microsite/docs/docs/scala/akka-http/dtos.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -layout: docs -title: "Encoding - akka-http - scala - guardrail" ---- - -guardrail will generate data transfer objects with encoders and decoders for entity bodies of requests and responses, as long as they're specified by a `$ref` reference to either in a components section or in a separate file. - -Data transfer objects will be represented as case classes, while encoders and decoders depend on the framework used. For dropwizard for example, guardrail will generate jackson encoders and decoders, while for http4s, guardrail will create encoders and decoders for circe. - -When your schemas are defined inline however, guardrail will not build typed DTOs for the schemas, but fall back to a generic json representation. One scenario where this can happen is when your api specification is built as a bundle with swagger-cli. Fortunately, guardrail understands the unbundled representation with ref elements to separate files. diff --git a/modules/microsite/docs/docs/scala/akka-http/generating-clients.md b/modules/microsite/docs/docs/scala/akka-http/generating-clients.md deleted file mode 100644 index 810a6fae73..0000000000 --- a/modules/microsite/docs/docs/scala/akka-http/generating-clients.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -layout: docs -title: "Generating Clients - akka-http - scala - guardrail" ---- - -Generating clients -================== - -As we've seen in [Generating a Server](generating-a-server), guardrail-generated servers establish a mapping between our business logic and a cordoned off subset of HTTP. This permits us to focus on our business logic, without getting overloaded with the complexities of managing such a large protocol. The same is true with guardrail generated HTTP Clients: from a consumer's standpoint, HTTP calls should look like regular function calls, accepting domain-specific arguments and producing domain-specific results. - -By generating minimal clients that only have enough business knowledge to map domain types to and from HTTP, opportunities for logical errors are effectively removed. While this does not eliminate logical errors entirely, establishing a firm boundary between the underlying protocol and hand-written code drastically reduces the scope of possible bugs. - -The following is an example from the [akka-http](https://github.com/akka/akka-http) client generator: - -```scala mdoc:passthrough -import dev.guardrail.docs._ -DocsHelpers.renderScalaSnippet("akka-http", GeneratingClients)( - """|// Two constructors are provided, one accepting the `httpClient`, - |// `ExecutionContext`, and `Materializer` implicitly, the other accepting - |// an explicit `httpClient`, but still accepting the `ExecutionContext` and - |// `Materializer` as implicits. - """.stripMargin, - "" -) -``` - -(See it in action: [guardrail-dev/guardrail-sample-sbt-akkahttp](https://github.com/guardrail-dev/guardrail-sample-sbt-akkahttp)) - -Separation of protocol-concerns from API-level concerns -------------------------------------------------------- - -As guardrail clients are built on top of the function type `HttpRequest => Future[HttpResponse]`, client configuration is reduced to function composition. Some ideas: - -```scala -val singleRequestHttpClient = { (req: HttpRequest) => - Http().singleRequest(req) -} - -val retryingHttpClient = { nextClient: (HttpRequest => Future[HttpResponse]) => - req: HttpRequest => nextClient(req).flatMap(resp => if (resp.status.intValue >= 500) nextClient(req) else Future.successful(resp)) -} - -val metricsHttpClient = { nextClient: (HttpRequest => Future[HttpResponse]) => - req: HttpRequest => { - val resp = nextClient(req) - resp.onSuccess { _resp => - trackMetrics(req.uri.path, _resp.status) - } - resp - } -} - -// Track metrics for every request, even retries -val retryingMetricsClient1: HttpRequest => Future[HttpResponse] = retryingHttpClient(metricsHttpClient(singleRequestHttpClient)) - -// Only track metrics for requests we didn't have to retry -val retryingMetricsClient2: HttpRequest => Future[HttpResponse] = metricsHttpClient(retryingHttpClient(singleRequestHttpClient)) -``` - -[Prev: Generating a Server](generating-a-server) -[Next: guardrail Extensions](guardrail-extensions) diff --git a/modules/microsite/docs/docs/scala/akka-http/index.md b/modules/microsite/docs/docs/scala/akka-http/index.md deleted file mode 100644 index 2ce8bf4263..0000000000 --- a/modules/microsite/docs/docs/scala/akka-http/index.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -layout: docs -title: "akka-http - scala - guardrail" ---- - -Table of Contents -================= - -1. [What is guardrail](what-is-guardrail) - 1. [Single Point of Truth](what-is-guardrail#single-point-of-truth) - 1. [Unexpected API changes are compiler errors](what-is-guardrail#unexpected-api-changes-are-compiler-errors) - 1. [Fewer binary dependencies](what-is-guardrail#fewer-binary-dependencies) -1. [Installation](installation) -1. [Sample API specification](sample-api-specification) -1. [Generating Domain Objects](dtos) -1. [Generating a Server](generating-a-server) - 1. [Separation of business logic](generating-a-server#separation-of-business-logic) - 1. [API structure slip is impossible](generating-a-server#api-structure-slip-is-impossible) - 1. [Generating test-only (real) server mocks for unit tests](generating-a-server#generating-test-only-real-server-mocks-for-unit-tests) - 1. [A note about scalatest integration](generating-a-server#a-note-about-scalatest-integration) -1. [Generating clients](generating-clients) - 1. [Separation of protocol-concerns from API-level concerns](generating-clients#separation-of-protocol-concerns-from-api-level-concerns) -1. [guardrail Extensions](guardrail-extensions) diff --git a/modules/microsite/docs/docs/scala/akka-http/installation.md b/modules/microsite/docs/docs/scala/akka-http/installation.md deleted file mode 100644 index 1cd7529384..0000000000 --- a/modules/microsite/docs/docs/scala/akka-http/installation.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -layout: docs -title: "Installation - akka-http - scala - guardrail" ---- - -Installation -============ - -guardrail is available as a modular core, with both [sbt](https://github.com/guardrail-dev/sbt-guardrail) and [Maven](https://github.com/guardrail-dev/guardrail-maven-plugin) integration. The core can also be run as a stand-alone [CLI](https://github.com/guardrail-dev/guardrail/blob/978a92db3dd46812aa19f05050995f864cbb5bb3/build.sbt#L33-L48) application, with full support for all features. - -If compiling with Scala < 2.13.x, you'll need to enable `-Ypartial-unification`: - -```scala -scalacOptions += "-Ypartial-unification" -``` - -If compiling with Scala < 2.12.x, you'll additionally need the `-Xexperimental` flag: - -```scala -scalacOptions += "-Xexperimental" -``` - -[Prev: What is guardrail?](what-is-guardrail) -[Next: Sample API specification](sample-api-specification) diff --git a/modules/microsite/docs/docs/scala/akka-http/what-is-guardrail.md b/modules/microsite/docs/docs/scala/akka-http/what-is-guardrail.md deleted file mode 100644 index eeefcc51c2..0000000000 --- a/modules/microsite/docs/docs/scala/akka-http/what-is-guardrail.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -layout: docs -title: "What is guardrail? - akka-http - scala - guardrail" ---- - -What is guardrail? -================== - -guardrail is a code generation tool, capable of reading from OpenAPI/Swagger specification files and generating Scala source code, primarily targeting the akka-http and http4s web frameworks, using circe for JSON encoding/decoding. - -guardrail has three primary goals: - -- Documentation: Single point of truth for the interface to a software system -- Better Servers: Unexpected API changes surface as compiler errors via server routing layer code generation -- Better Clients: Fewer binary dependencies via client library code generation - -Describing software is tricky. Incomplete specifications, slippage between specification and implementation, or even additional semantics of infrastructure that aren't easily communicated through static documents; these are only a few challenges you'll face when attempting to write a specification for your API. A reasonable question you may be asking is what motivations are there for going through these cumbersome and often frustrating tasks? We'll investigate some answers to this question in the following sections. - -Single Point of Truth ---------------------- - -By describing the shape of an API statically, there are far fewer variables to worry about. HTTP is a _very_ flexible protocol, with many features. By constraining that protocol to a subset that expresses the interface to our server (or service, or microservice), we drastically reduce the burden of handling the entirety of HTTP to the core terms of our API. Focus on semantics of APIs once the basics (routing, data validation) are figured out. - -A secondary benefit of static specifications lies in tooling. Hand-written routing logic can hide security holes, miss best practices, and obscure intent if written incorrectly. This problem is multipled across as many different languages as are supported inside any given company, manifesting as wasted effort implementing the same feature in different languages, or a bug that only occurs 10 percent of the time due to a buggy golang client. - -Attempting to derive what the attack surface of a server is from the implementation is often the job of entire teams in large companies, and even that may not be enough. Conversely, with a static specification, those teams can build intelligent traffic analysis tools to detect anomalies or intentionally malicious clients built to inject bad data to find bugs. - -Unexpected API changes are compiler errors ------------------------------------------- - -Once we have a specification, generating traits (or abstract classes) with unimplemented members gives us another powerful tool: New or changed parameters become compiler errors. - -After constraining our vocabulary to a subset of HTTP that serves our business need, even saying "This parameter is optional" forces us to contend with the sudden appearance of `Option[T]` parameters in our generated `Handler` methods. - -Once specified, `-Ywarn-unused` helpfully points out that we've forgotten to reflect this most recent change in our tests. A win on both fronts! - -Fewer binary dependencies ----------------------- - -Traditionally written and maintained client libraries invariably accumulate cruft. In many cases, this is intended to be helpful: papering over a poorly designed API by providing custom logic, renaming parameters to be more convenient, or including properly configured HTTP clients that express retry and backoff semantics the library author provided based on the business requirements known at the time of writing. - -Altering the shape of an API by providing a thick HTTP client reduces the shared terminology between service maintainers and their consumers, or even between consumers coming from different languages. - -Additionally, by hardcoding even a well-behaved HTTP client into a client library, now consumers are forced to work around that dependency. This may manifest as learning how to use and configure a brand new HTTP client under time pressure, or writing and maintaining brittle [Application Binary Interface (ABI)](https://en.wikipedia.org/wiki/Application_binary_interface)-compatible adapter layers that attempt to use the configuration already present in the rest of the codebase. - -Once these bespoke HTTP client configurations are built, both they and their dependencies are now added to the grab bag of dependency versions that must be maintained through the life of any given piece of infrastructure. This presents hidden barriers for upgrading all dependencies, as the possibility of transitive dependency conflicts increase as dependency trees become deeper. - -[Next: Installation](installation) diff --git a/modules/microsite/docs/docs/scala/http4s/dtos.md b/modules/microsite/docs/docs/scala/http4s/dtos.md deleted file mode 100644 index da5cd4ffd6..0000000000 --- a/modules/microsite/docs/docs/scala/http4s/dtos.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -layout: docs -title: "Encoding - http4s - scala - guardrail" ---- - -guardrail will generate data transfer objects with encoders and decoders for entity bodies of requests and responses, as long as they're specified by a `$ref` reference to either in a components section or in a separate file. - -Data transfer objects will be represented as case classes, while encoders and decoders depend on the framework used. For dropwizard for example, guardrail will generate jackson encoders and decoders, while for http4s, guardrail will create encoders and decoders for circe. - -When your schemas are defined inline however, guardrail will not build typed DTOs for the schemas, but fall back to a generic json representation. One scenario where this can happen is when your api specification is built as a bundle with swagger-cli. Fortunately, guardrail understands the unbundled representation with ref elements to separate files. diff --git a/modules/microsite/docs/docs/scala/http4s/generating-a-server.md b/modules/microsite/docs/docs/scala/http4s/generating-a-server.md deleted file mode 100644 index 7877cef581..0000000000 --- a/modules/microsite/docs/docs/scala/http4s/generating-a-server.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -layout: docs -title: "Generating a Server - http4s - scala - guardrail" ---- - -Generating a Server -=================== - -guardrail-generated servers come in two parts: a `Resource` and a `Handler`. The `Resource` contains all the routing logic, accepting a `Handler` as an argument to the `route` function in order to provide an HTTP service in whichever supported HTTP framework you're hosting your service in. - -The following is an example from the [http4s](https://github.com/http4s/http4s) server generator: - -```scala mdoc:passthrough -import dev.guardrail.docs._ -DocsHelpers.renderScalaSnippet("http4s", GeneratingAServer)(""" - |// The `Handler` trait is fully abstracted from the underlying http framework. As a result, with the exception of some - |// structural alterations (`F[_]` instead of `Future[_]` as the return type) the same handlers can be used with - |// different `Resource` implementations from different framework generators. This permits greater compatibility between - |// different frameworks without changing your business logic. - """.stripMargin, - "" -) -``` - -As all parameters are provided as arguments to the function stubs in the trait, there's no concern of forgetting to extract a query string parameter or introducing a typo in a form parameter name. - -The routes and resources generated by guardrail can be hooked up into your HTTP4s server like so: - -```scala -import org.http4s.ember.server.EmberServerBuilder - -class UserImpl extends UserHandler[IO] { /* Your code here */ } -val userHandler: UserHandler[IO] = new UserImpl -val usersService = new UsersResource[IO]().routes(userHandler) -val httpApp = usersService.orNotFound - -// Same basic server setup as in the http4s quickstart -EmberServerBuilder.default[IO] - .withHttpApp(httpApp) - .build - .use(_ => IO.never) - .as(ExitCode.Success) -``` - -(See it in action: [guardrail-dev/guardrail-sample-http4s](https://github.com/guardrail-dev/guardrail-sample-http4s), [guardrail-dev/guardrail-sample-sbt-http4s-zio](https://github.com/guardrail-dev/guardrail-sample-sbt-http4s-zio)) - -Separation of business logic ----------------------------- - -Providing an implementation of a function with a well-defined set of inputs and outputs is natural for any developer. By reducing the scope of the interface a developer writes against, implementations are more clear and concise. - -Furthermore, by providing business logic as an implementation of an abstract class, unit tests can test the routing layer and business logic independently, by design. - -API structure slip is impossible --------------------------------- - -As parameters are explicitly provided as arguments to functions in `Handler`s, any alteration to parameters constitute a new function interface that must be implemented. As a result, if providing an implementation for an externally managed specification, the compiler informs when a previously written function is no longer sufficient. - -By representing different response codes and structures as members of a sealed trait, it's impossible to return a structure that violates the specification, even for less frequently used response codes. - -Finally, describing an endpoint in your specification without providing an implementation for it is a compiler error. This prevents reduction of functionality due to refactors, human error, or miscommunication with other teams. - -[Prev: Sample API specification](sample-api-specification) -[Next: Generating clients](generating-clients) diff --git a/modules/microsite/docs/docs/scala/http4s/generating-clients.md b/modules/microsite/docs/docs/scala/http4s/generating-clients.md deleted file mode 100644 index 97ee3b0c41..0000000000 --- a/modules/microsite/docs/docs/scala/http4s/generating-clients.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -layout: docs -title: "Generating Clients - http4s - scala - guardrail" ---- - -Generating clients -================== - -As we've seen in [Generating a Server](generating-a-server), guardrail-generated servers establish a mapping between our business logic and a cordoned off subset of HTTP. This permits us to focus on our business logic, without getting overloaded with the complexities of managing such a large protocol. The same is true with guardrail generated HTTP Clients: from a consumer's standpoint, HTTP calls should look like regular function calls, accepting domain-specific arguments and producing domain-specific results. - -By generating minimal clients that only have enough business knowledge to map domain types to and from HTTP, opportunities for logical errors are effectively removed. While this does not eliminate logical errors entirely, establishing a firm boundary between the underlying protocol and hand-written code drastically reduces the scope of possible bugs. - -The following is an example from the [http4s](https://github.com/http4s/http4s) client generator: - -```scala mdoc:passthrough -import dev.guardrail.docs._ -DocsHelpers.renderScalaSnippet("http4s", GeneratingClients)( - """|// Two constructors are provided, one accepting the `httpClient` and `Async` - |// implicitly, the other accepting an explicit `httpClient`, but still - |// accepting the `Async` implicitly - """.stripMargin, - "" -) -``` - -(See it in action: [guardrail-dev/guardrail-sample-http4s](https://github.com/guardrail-dev/guardrail-sample-http4s), [guardrail-dev/guardrail-sample-sbt-http4s-zio](https://github.com/guardrail-dev/guardrail-sample-sbt-http4s-zio)) - -Separation of protocol-concerns from API-level concerns -------------------------------------------------------- - -As guardrail clients are built on top of any Http4s client type, client configuration is done the same way as you are -already familiar with when using Http4s. - -Check out the docs for [Http4s Clients](https://http4s.org/v0.23/client/). - -[Prev: Generating a Server](generating-a-server) diff --git a/modules/microsite/docs/docs/scala/http4s/guardrail-extensions.md b/modules/microsite/docs/docs/scala/http4s/guardrail-extensions.md deleted file mode 100644 index d4182dfa65..0000000000 --- a/modules/microsite/docs/docs/scala/http4s/guardrail-extensions.md +++ /dev/null @@ -1,191 +0,0 @@ ---- -layout: docs -title: "guardrail extensions - http4s - scala - guardrail" ---- - -guardrail Extensions -==================== - -guardrail has [a number of vendor extensions](https://github.com/twilio/guardrail/blob/cbf9acd9e8ff226cc0f4bbf2f278669071126d5e/modules/codegen/src/main/scala/com/twilio/guardrail/extract/package.scala) designed to enhance safety and provide more idiomatic generated code. The following table lists all vendor extensions, contexts where they are applicable, and a short description of how to use them effectively. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ExtensionTypeContextsDescription
x-empty-is-nullbooleanclients/servers, definitions - Instructs the JSON decoder to convert empty strings to null before - decoding, causing empty strings to not satisfy the required directive, - or being represented as None instead of Some(""). -
x-file-hashstringservers, parameters, file - During a streaming file upload, keep track of the file hash in one of - the supported file hash types. -
x-scala-packagestringclients/servers, paths - A dot-separated package segment concatenated to the end of the supplied - packageName when generating Scala code. This permits - splitting up large specifications into smaller, domain-specific - Handlers. See also x-jvm-package. -
x-java-packagestringclients/servers, paths - A dot-separated package segment concatenated to the end of the supplied - packageName when generating Java code. This permits - splitting up large specifications into smaller, domain-specific - Handlers. See also x-jvm-package. -
x-jvm-packagestringclients/servers, paths - A dot-separated package segment concatenated to the end of the supplied - packageName when generating JVM code. This permits - splitting up large specifications into smaller, domain-specific - Handlers. Note that x-scala-package and - x-java-package take precedence over this property. -
x-server-raw-responsebooleanservers, paths - Exposes the underlying HTTP framework's response-building - infrastructure. Type-safe `respond` wrappers are still generated - and supplied, though this escape-hatch is intended to work around - bugs in guardrail itself. This is not recommended for long-term use, - as no guarantees around compile-time-safe protocol adherence can be - made. -
x-tracing-labelstringclients/servers, paths - When tracing is enabled, override the provided function - label with a custom string. This string will be supplied to your - supplied trace function in your servers and your supplied - traceBuilder in your clients. -
x-scala-typestringdefinitions, parameters - Override the primitive types specified in the OpenAPI specification - with a domain-specific type for generated Scala code. This requires the - type to have either serializers/deserializers in the underlying JSON - framework or HTTP framework. As this is an advanced feature, it may - require use of custom imports provided via build tool - plugins or at the CLI. -
x-java-typestringdefinitions, parameters - Override the primitive types specified in the OpenAPI specification - with a domain-specific type for generated Java code. This requires the - type to have either serializers/deserializers in the underlying JSON - framework or HTTP framework. As this is an advanced feature, it may - require use of custom imports provided via build tool - plugins or at the CLI. -
x-jvm-typestringdefinitions, parameters - Override the primitive types specified in the OpenAPI specification - with a domain-specific type for generated JVM (Scala and Java) code. - This requires the type to have either serializers/deserializers in the - underlying JSON framework or HTTP framework. As this is an advanced - feature, it may require use of custom imports provided via - build tool plugins or at the CLI. -
x-scala-array-type, x-java-array-typestringdefinitions, parameters - Override the generated array type from `Vector` to some custom type. - This requires the type to have either serializers/deserializers in the - underlying JSON framework or HTTP framework. As this is an advanced - feature, it may require use of custom imports provided via - build tool plugins or at the CLI. -
x-scala-map-type, x-java-map-typestringdefinitions, parameters - Override the generated map type from `Map` to some custom type. - This requires the type to have either serializers/deserializers in the - underlying JSON framework or HTTP framework. As this is an advanced - feature, it may require use of custom imports provided via - build tool plugins or at the CLI. -
x-scala-class-prefixstringclients/servers - An arbitrary class name prefix that overrides the default class name - when generating Scala code. See also x-jvm-class-prefix. -
x-java-class-prefixstringclients/servers - An arbitrary class name prefix that overrides the default class name - when generating Java code. See also x-jvm-class-prefix. -
x-jvm-class-prefixstringclients/servers - An arbitrary class name prefix that overrides the default class name - when generating JVM code. See also x-scala-class-prefix. -
- -[Prev: Generating clients](generating-clients) diff --git a/modules/microsite/docs/docs/scala/http4s/index.md b/modules/microsite/docs/docs/scala/http4s/index.md deleted file mode 100644 index 53d946dbf5..0000000000 --- a/modules/microsite/docs/docs/scala/http4s/index.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -layout: docs -title: "http4s - scala - guardrail" ---- - -Table of Contents -================= - -1. [What is guardrail](what-is-guardrail) - 1. [Single Point of Truth](what-is-guardrail#single-point-of-truth) - 1. [Unexpected API changes are compiler errors](what-is-guardrail#unexpected-api-changes-are-compiler-errors) - 1. [Fewer binary dependencies](what-is-guardrail#fewer-binary-dependencies) -1. [Installation](installation) -1. [Sample API specification](sample-api-specification) -1. [Generating Domain Objects](dtos) -1. [Generating a Server](generating-a-server) - 1. [Separation of business logic](generating-a-server#separation-of-business-logic) - 1. [API structure slip is impossible](generating-a-server#api-structure-slip-is-impossible) - 1. [Generating test-only (real) server mocks for unit tests](generating-a-server#generating-test-only-real-server-mocks-for-unit-tests) - 1. [A note about scalatest integration](generating-a-server#a-note-about-scalatest-integration) -1. [Generating clients](generating-clients) - 1. [Separation of protocol-concerns from API-level concerns](generating-clients#separation-of-protocol-concerns-from-api-level-concerns) -1. [guardrail Extensions](guardrail-extensions) diff --git a/modules/microsite/docs/docs/scala/http4s/installation.md b/modules/microsite/docs/docs/scala/http4s/installation.md deleted file mode 100644 index 11a3380592..0000000000 --- a/modules/microsite/docs/docs/scala/http4s/installation.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -layout: docs -title: "Installation - http4s - scala - guardrail" ---- - -Installation -============ - -guardrail is available as a modular core, with both [sbt](https://github.com/twilio/sbt-guardrail) and [Maven](https://github.com/twilio/guardrail-maven-plugin) integration. The core can also be run as a stand-alone [CLI](https://github.com/twilio/guardrail/blob/978a92db3dd46812aa19f05050995f864cbb5bb3/build.sbt#L33-L48) application, with full support for all features. - -To generate servers or clients using the `http4s` framework, set `http4s` as the framework in the generation configuration in either sbt or maven. - -If compiling with Scala < 2.13.x, you'll need to enable `-Ypartial-unification`: - -```scala -scalacOptions += "-Ypartial-unification" -``` - -If compiling with Scala < 2.12.x, you'll additionally need the `-Xexperimental` flag: - -```scala -scalacOptions += "-Xexperimental" -``` - -Additionally, you will need to manually include dependencies in your project for the following packages: -- `http4s`, dsl, server, and client dependencies -- `http4s-circe` for JSON decoding and encoding support -- `circe-generic` for JSON decoding and encoding support -- `cats-effect` for http4s integration -- `cats-core` for http4s integration - -Versions of these libraries should be picked by checking out the [Compatibility Matrix](https://github.com/guardrail-dev/guardrail/blob/master/COMPATIBILITY.md). - -[Prev: What is guardrail?](what-is-guardrail) -[Next: Sample API specification](sample-api-specification) diff --git a/modules/microsite/docs/docs/scala/http4s/sample-api-specification.md b/modules/microsite/docs/docs/scala/http4s/sample-api-specification.md deleted file mode 100644 index 043b0c7a4f..0000000000 --- a/modules/microsite/docs/docs/scala/http4s/sample-api-specification.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -layout: docs -title: "Sample API Specification - http4s - scala - guardrail" ---- - -Sample API specification -======================== - -The following is a complete, annotated OpenAPI specification file: (guardrail extensions are documented in [guardrail Extensions](#guardrail-extensions)) - -```yaml -swagger: "2.0" # Which version of the OpenAPI/Swagger specification we are following -info: # Primarily for consumption by documentation generation tools - title: My Service - version: 0.1.0 -host: localhost:1234 # Default host (and optional port) to connect to for generated clients -schemes: - - http -paths: # All HTTP paths are direct children of the `paths` field - - /user/{id}: # Paths can have variable patterns in paths - - get: # HTTP method - - operationId: getUser # Friendly name, ends up as the function name (in clients and servers) - - x-jvm-package: users # Relative package for this client to live in. For convenience, the - # last package parameter is turned into a class name for clients and - # servers. In this case, `UsersClient`. - - parameters: # All parameters (including path parameters) are listed here. - - - name: id # The field name (case matters!), used to both identify the correct - # field to match, as well as generate a best-guess idiomatic Scala - # parameter name. - - in: path # Where to look for the parameter - - description: The ID of the user # The optional `description` parameter is not used in guardrail, - # but is useful for providing a detailed explanation on what is - # expected as a value for the parameter. For example: - # `description: User IDs are strings comprised of the concatenation - # of the two upper-case letters ID and a UUID stripped of any dashes - # i.e. ID4d9b1c54e4664c9d92aba94151a7f59f` - - required: true # Required fields cannot be missing. `required: false` fields are - # represented as `Option[T]` - - type: string # One of the primitive types supported in the OpenAPI specification. - # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#dataTypes - - x-scala-type: CustomString # Escape hatch to explicitly introduce a custom type. This is an - # advanced technique to introduce completely custom - # marshalling/unmarshalling/validation logic. Keep in mind, everyone - # else will just see a plain string! - - responses: # All response codes that are possible are listed here - - 200: # Each HTTP status code is mapped to the corresponding textual - # representation in guardrail-generated servers. - - schema: # The optional `schema` parameter describes what's possible to return - # as the body of a response - - $ref: '#/definitions/User' # In the generated `UsersHandler` `getUser` function, we can call - # `respond.OK(user)`, where `user: definitions.User` - - 404: # We must represent our failure cases as well, otherwise we can - # never express failure! - - description: Not found # The optional `description` parameter is not used in guardrail, - # but is useful here as an indicator that we don't have a response - # body for `404 Not Found` responses. - -definitions: # All non-primitive structures are defined inside `definitions` - - User: # This identifies a symbolic structure name. Not all names are - # translated into classes when rendered, depending on whether they - # identify classes with structure, or defer to standard classes - # like `Vector` for `type: array`. - - type: object # will generate a `User` case class in the `definitions` package - - required: # A list of which parameters are required. This is enforced for - # clients by having non-optional parameters, and for servers by - # ensuring all submitted data to the endpoint validates the schema - # before getting to your `Handler` function. - - - id # These names must match the `properties` names exactly - - user_addresses - - properties: # `object`s are permitted to have `properties`. These are translated - # into fields in the generated case classes. - - id: # Case matters for `properties`! A heuristic determines whether it's - # possible to translate a property name into a unique, non-reserved - # camelCase identifier. - - type: string # One of the primitive types supported in the OpenAPI specification. - # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#dataTypes - - user_addresses: # Similar to `id`, though `user_addresses` can be safely transformed into - # `userAddress`, so this is done to expose idiomatic Scala. The underlying - # marshallers and unmarshallers maintain this mapping for you though, - # so no chance of protocol violations. - - $ref: '#/definitions/UserAddresses' # Ensures that the type of `userAddress` will be `Vector[UserAddress]` - - UserAddresses: - type: array - - items: # `items` is a special key for `type: array`, identifying the structure of the - # sequence members - - $ref: '#/definitions/UserAddress' # Primitive types could be listed here, but as we're referring to another class, - # we need to explicitly use a `$ref`. This may change in the future, - # see https://github.com/twilio/guardrail/issues/76 - - UserAddress: - type: object - properties: - line1: - type: string - line2: - type: string - line3: - type: string -``` - -[Prev: Installation](installation) -[Next: Generating a Server](generating-a-server) diff --git a/modules/microsite/docs/docs/scala/index.md b/modules/microsite/docs/docs/scala/index.md deleted file mode 100644 index 28e8f33f94..0000000000 --- a/modules/microsite/docs/docs/scala/index.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -layout: docs -title: "scala - guardrail" ---- - -guardrail can generate Scala clients and servers for the following -frameworks: - -* [`akka-http`](akka-http/) -* [`dropwizard`](dropwizard/) -* [`http4s`](http4s/) - -Additionally, there is support for Jackson serialization by way of [`akka-http-jackson`](akka-http-jackson/). diff --git a/modules/microsite/docs/index.md b/modules/microsite/docs/index.md deleted file mode 100644 index ee05845c15..0000000000 --- a/modules/microsite/docs/index.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -layout: home -title: "Home" -section: "home" -technologies: - - first: ['OpenAPI', "The OpenAPI Initiative is a consortium of industry experts with the focus on standardizing how REST APIs are described"] - - second: ['Twilio', "Communications APIs for SMS, Voice, Video, and Authentication"] ---- - -`guardrail` is a code generation tool, capable of reading from OpenAPI/Swagger specification files and generating high quality source code for a variety of languages and frameworks. - -There are plugins available for [`sbt`](https://github.com/guardrail-dev/sbt-guardrail), [`maven`](https://github.com/guardrail-dev/guardrail-maven-plugin), [`gradle`](https://github.com/guardrail-dev/guardrail-gradle-plugin), and there's a manual CLI driver. - -Additionally, check out the [`guardrail-sample`](https://github.com/topics/guardrail-sample) topic on GitHub for more examples. - -**Consulting**: If you need help getting started, getting migrated, or adding features, please contact [hello@guardrail.dev](mailto:hello@guardrail.dev). diff --git a/modules/microsite/src/main/resources/microsite/data/menu.yml b/modules/microsite/src/main/resources/microsite/data/menu.yml deleted file mode 100644 index e81976b98f..0000000000 --- a/modules/microsite/src/main/resources/microsite/data/menu.yml +++ /dev/null @@ -1,24 +0,0 @@ -options: - - title: Getting Started - url: "docs/" - - - title: Java - url: docs/java/ - nested_options: - - title: Dropwizard - url: docs/java/dropwizard/ - - - title: Spring-MVC - url: docs/java/spring-mvc/ - - - title: Scala - url: docs/scala/ - nested_options: - - title: akka-http - url: docs/scala/akka-http - - - title: akka-http-jackson - url: docs/scala/akka-http-jackson - - - title: http4s - url: docs/scala/http4s diff --git a/modules/microsite/docs/sample-user.json b/modules/microsite/src/main/resources/sample-user.json similarity index 100% rename from modules/microsite/docs/sample-user.json rename to modules/microsite/src/main/resources/sample-user.json diff --git a/modules/microsite/src/main/scala/DocsHelpers.scala b/modules/microsite/src/main/scala/DocsHelpers.scala index 9974580c8b..455b11a731 100644 --- a/modules/microsite/src/main/scala/DocsHelpers.scala +++ b/modules/microsite/src/main/scala/DocsHelpers.scala @@ -19,7 +19,7 @@ case object GeneratingClients extends SnippetComponent @SuppressWarnings(Array("org.wartremover.warts.EitherProjectionPartial", "org.wartremover.warts.TraversableOps")) object DocsHelpers { - def sampleSpec = "modules/microsite/docs/sample-user.json" + def sampleSpec = "modules/microsite/src/main/resources/sample-user.json" def renderScalaSnippet(framework: String, identifier: SnippetComponent)(prefix: String, suffix: String): Unit = { val generator: Framework[ScalaLanguage, Target] = Target.unsafeExtract(for { modules <- ModuleMapperLoader.load[ScalaLanguage](framework) diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..7ba935b59f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2026 @@ +{ + "name": "guardrail", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "docsify-cli": "^4.4.4" + } + }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/boxen/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/boxen/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect-livereload": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.6.1.tgz", + "integrity": "sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==", + "engines": { + "node": "*" + } + }, + "node_modules/cp-file": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz", + "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==", + "dependencies": { + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "nested-error-stacks": "^2.0.0", + "p-event": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/docsify": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/docsify/-/docsify-4.13.1.tgz", + "integrity": "sha512-BsDypTBhw0mfslw9kZgAspCMZSM+sUIIDg5K/t1hNLkvbem9h64ZQc71e1IpY+iWsi/KdeqfazDfg52y2Lmm0A==", + "hasInstallScript": true, + "dependencies": { + "marked": "^1.2.9", + "medium-zoom": "^1.0.6", + "opencollective-postinstall": "^2.0.2", + "prismjs": "^1.27.0", + "strip-indent": "^3.0.0", + "tinydate": "^1.3.0", + "tweezer.js": "^1.4.0" + } + }, + "node_modules/docsify-cli": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/docsify-cli/-/docsify-cli-4.4.4.tgz", + "integrity": "sha512-NAZgg6b0BsDuq/Pe+P19Qb2J1d+ZVbS0eGkeCNxyu4F9/CQSsRqZqAvPJ9/0I+BCHn4sgftA2jluqhQVzKzrSA==", + "dependencies": { + "chalk": "^2.4.2", + "connect": "^3.6.0", + "connect-history-api-fallback": "^1.6.0", + "connect-livereload": "^0.6.0", + "cp-file": "^7.0.0", + "docsify": "^4.12.2", + "docsify-server-renderer": ">=4.10.0", + "enquirer": "^2.3.6", + "fs-extra": "^8.1.0", + "get-port": "^5.0.0", + "livereload": "^0.9.2", + "lru-cache": "^5.1.1", + "open": "^6.4.0", + "serve-static": "^1.12.1", + "update-notifier": "^4.1.0", + "yargonaut": "^1.1.2", + "yargs": "^15.3.0" + }, + "bin": { + "docsify": "bin/docsify" + }, + "engines": { + "node": ">= 10", + "npm": ">= 6" + } + }, + "node_modules/docsify-server-renderer": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/docsify-server-renderer/-/docsify-server-renderer-4.13.1.tgz", + "integrity": "sha512-XNJeCK3zp+mVO7JZFn0bH4hNBAMMC1MbuCU7CBsjLHYn4NHrjIgCBGmylzEan3/4Qm6kbSzQx8XzUK5T7GQxHw==", + "dependencies": { + "debug": "^4.3.3", + "docsify": "^4.12.4", + "node-fetch": "^2.6.6", + "resolve-pathname": "^3.0.0" + } + }, + "node_modules/docsify-server-renderer/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/docsify-server-renderer/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/figlet": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.7.0.tgz", + "integrity": "sha512-gO8l3wvqo0V7wEFLXPbkX83b7MVjRrk1oRLfYlZXol8nEpb/ON9pcKLI4qpBv5YtOTfrINtqb7b40iYY2FTWFg==", + "bin": { + "figlet": "bin/index.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "dependencies": { + "ini": "1.3.7" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dependencies": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/livereload": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz", + "integrity": "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==", + "dependencies": { + "chokidar": "^3.5.0", + "livereload-js": "^3.3.1", + "opts": ">= 1.2.0", + "ws": "^7.4.3" + }, + "bin": { + "livereload": "bin/livereload.js" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/livereload-js": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.4.1.tgz", + "integrity": "sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g==" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/marked": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.9.tgz", + "integrity": "sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==", + "bin": { + "marked": "bin/marked" + }, + "engines": { + "node": ">= 8.16.2" + } + }, + "node_modules/medium-zoom": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.1.0.tgz", + "integrity": "sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==" + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/nested-error-stacks": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", + "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", + "bin": { + "opencollective-postinstall": "index.js" + } + }, + "node_modules/opts": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz", + "integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==" + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-event": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", + "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "dependencies": { + "p-timeout": "^3.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/parent-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz", + "integrity": "sha512-2MXDNZC4aXdkkap+rBBMv0lUsfJqvX5/2FiYYnfCnorZt3Pk06/IOR5KeaoghgS2w07MLWgjbsnyaq6PdHn2LQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/registry-auth-token": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tinydate": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.3.0.tgz", + "integrity": "sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tweezer.js": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/tweezer.js/-/tweezer.js-1.5.0.tgz", + "integrity": "sha512-aSiJz7rGWNAQq7hjMK9ZYDuEawXupcCWgl3woQQSoDP2Oh8O4srWb/uO1PzzHIsrPEOqrjJ2sUb9FERfzuBabQ==" + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "dependencies": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/update-notifier/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/update-notifier/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yargonaut": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/yargonaut/-/yargonaut-1.1.4.tgz", + "integrity": "sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA==", + "dependencies": { + "chalk": "^1.1.1", + "figlet": "^1.1.1", + "parent-require": "^1.0.0" + } + }, + "node_modules/yargonaut/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yargonaut/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yargonaut/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yargonaut/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yargonaut/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000..11410655f1 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "docsify-cli": "^4.4.4" + } +} diff --git a/project/mdoc.sbt b/project/mdoc.sbt new file mode 100644 index 0000000000..ee1204172b --- /dev/null +++ b/project/mdoc.sbt @@ -0,0 +1 @@ +addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.5.1" ) diff --git a/project/microsite.sbt b/project/microsite.sbt deleted file mode 100644 index 1365b118e3..0000000000 --- a/project/microsite.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("com.47deg" % "sbt-microsites" % "1.4.4") diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000000..5ec2407193 --- /dev/null +++ b/shell.nix @@ -0,0 +1,17 @@ +{ pkgs ? import {} }: + let + docsifyCli = pkgs.writeShellScriptBin "docsify-cli" + '' + npx run docsify-cli + ''; + in + pkgs.mkShell { + packages = with pkgs; [ + docsifyCli + nodejs + ]; + + shellHook = '' + npm install docsify-cli + ''; + } diff --git a/support/generate-sidebars.sh b/support/generate-sidebars.sh new file mode 100644 index 0000000000..86af42e486 --- /dev/null +++ b/support/generate-sidebars.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + +render() { + local SCALA_TREE JAVA_TREE + section="$1" + case "$section" in + scala) + SCALA_TREE="$(cat < docs/_sidebar.md +render scala > docs/scala/_sidebar.md +render scala-akka-http > docs/scala/akka-http/_sidebar.md +render scala-pekko-http > docs/scala/pekko-http/_sidebar.md +render scala-http4s > docs/scala/http4s/_sidebar.md +render java > docs/java/_sidebar.md +render java-dropwizard > docs/java/dropwizard/_sidebar.md +render java-spring-mvc > docs/java/spring-mvc/_sidebar.md