mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2026-01-24 04:37:09 +00:00
Compare commits
70 Commits
prepare.7.
...
vertx-upda
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32961165f7 | ||
|
|
9f62822de7 | ||
|
|
2b67b00996 | ||
|
|
4559cad6db | ||
|
|
28904f850f | ||
|
|
84692d8155 | ||
|
|
f78c465bdd | ||
|
|
60e3e405a5 | ||
|
|
7f96a4a0a3 | ||
|
|
396c4c61eb | ||
|
|
428d483f1e | ||
|
|
10d5aa7f56 | ||
|
|
756bed0be0 | ||
|
|
49e3626e26 | ||
|
|
701d1f5443 | ||
|
|
ae5848b215 | ||
|
|
87d1df3eeb | ||
|
|
92e1593bc0 | ||
|
|
de464cea30 | ||
|
|
e7287d1cdb | ||
|
|
06a511df31 | ||
|
|
4d6d8a1edc | ||
|
|
8e0e429231 | ||
|
|
e0b27485db | ||
|
|
643138321b | ||
|
|
b1b556ad63 | ||
|
|
7671288210 | ||
|
|
287eadf4f6 | ||
|
|
4534e8d1a0 | ||
|
|
a40dc56d38 | ||
|
|
7af1d025f9 | ||
|
|
848aecccda | ||
|
|
e8faf7c46b | ||
|
|
4ec77dd283 | ||
|
|
c51253c40f | ||
|
|
ae42568b26 | ||
|
|
58b12baed2 | ||
|
|
eb65e93e1d | ||
|
|
d90bfe093c | ||
|
|
08367def47 | ||
|
|
450215c4b8 | ||
|
|
99baae676b | ||
|
|
f2a6b6d8b4 | ||
|
|
2b1f61874e | ||
|
|
17f2e4634c | ||
|
|
b3c4c49430 | ||
|
|
dff00c86d6 | ||
|
|
0da98b06f8 | ||
|
|
a2883f3d20 | ||
|
|
d2556d453b | ||
|
|
b2254b9b94 | ||
|
|
f1322a0c5a | ||
|
|
23dae2bcd8 | ||
|
|
46c2c30f47 | ||
|
|
73a24f02d9 | ||
|
|
ae8352d9f9 | ||
|
|
32aa36d821 | ||
|
|
944533826b | ||
|
|
753330dd99 | ||
|
|
8a82a3eeb2 | ||
|
|
570915e028 | ||
|
|
83f712467a | ||
|
|
b2ef09b7fd | ||
|
|
d39e015487 | ||
|
|
cd01ba9bc1 | ||
|
|
97af5d1f52 | ||
|
|
873e27233b | ||
|
|
80be730dcd | ||
|
|
19945d909f | ||
|
|
23eff6672f |
@@ -13,7 +13,7 @@
|
||||
"ghcr.io/snebjorn/devcontainer-feature/chromium:latest": {},
|
||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {
|
||||
"version": "latest",
|
||||
"moby": true
|
||||
"moby": false
|
||||
}
|
||||
},
|
||||
// Configure tool-specific properties.
|
||||
|
||||
69
.github/workflows/mill-plugin-tests.yaml
vendored
Normal file
69
.github/workflows/mill-plugin-tests.yaml
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
name: Mill plugin tests
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- modules/openapi-generator-mill-plugin/**
|
||||
pull_request:
|
||||
paths:
|
||||
- modules/openapi-generator-mill-plugin/**
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Mill plugin tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: 'temurin'
|
||||
- name: Restore cache (read-only)
|
||||
# only use restore keys, no save key because we need to clear the cache before running the examples
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: |
|
||||
~/.m2/repository
|
||||
~/.gradle
|
||||
~/.cache/coursier
|
||||
!~/.gradle/caches/*/plugin-resolution/
|
||||
!~/.m2/repository/org/openapitools/
|
||||
!~/.cache/coursier/v1/https/repo1.maven.org/maven2/org/openapitools/
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/pom.xml') }}
|
||||
|
||||
- name: Maven Clean Install
|
||||
env:
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
|
||||
run: |
|
||||
./mvnw clean install -DskipTests -Dmaven.javadoc.skip=true
|
||||
|
||||
# This is needed because of differences in how Maven and Coursier download artifacts
|
||||
# Maven will only download the pom when the transitive dependency is not needed in the current projects compile classpath
|
||||
# whereas Coursier expects the artifact (jar) to be present in a Maven repository. When Coursier encounters a
|
||||
# artifact folder with a pom it considers the artifact to be available and will then crash when the jar is missing.
|
||||
- name: Clear m2 cache except openapitools (because otherwise coursier will fail to resolve artifacts where only poms are downloaded)
|
||||
run: |
|
||||
mv ~/.m2/repository/org/openapitools /tmp/openapitools-backup || true
|
||||
rm -rf ~/.m2/repository/*
|
||||
mkdir -p ~/.m2/repository/org
|
||||
mv /tmp/openapitools-backup ~/.m2/repository/org/openapitools || true
|
||||
|
||||
- name: Mill Example - Test Validation Command
|
||||
env:
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
|
||||
run: |
|
||||
(cd modules/openapi-generator-mill-plugin/example/ && ./mill validateOpenapiSpec $(pwd)/api/petstore-invalid.yaml)
|
||||
|
||||
- name: Mill Example - Test Validation Task
|
||||
env:
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
|
||||
run: |
|
||||
(cd modules/openapi-generator-mill-plugin/example/ && ./mill openapi.validate)
|
||||
|
||||
- name: Mill Example - Test Compile Task
|
||||
env:
|
||||
GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }}
|
||||
run: |
|
||||
(cd modules/openapi-generator-mill-plugin/example/ && ./mill __.compile)
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
- samples/server/petstore/aspnet/fastendpoints-useValidators
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-dotnet@v5.0.1
|
||||
- uses: actions/setup-dotnet@v5.1.0
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Build
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
- samples/client/petstore/csharp/restsharp/standard2.0/Petstore/
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-dotnet@v5.0.1
|
||||
- uses: actions/setup-dotnet@v5.1.0
|
||||
with:
|
||||
dotnet-version: '7.0.x'
|
||||
- name: Build
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
# - samples/client/petstore/csharp/unityWebRequest/standard2.0/Petstore/
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-dotnet@v5.0.1
|
||||
- uses: actions/setup-dotnet@v5.1.0
|
||||
with:
|
||||
dotnet-version: 3.1.*
|
||||
- name: Build
|
||||
|
||||
2
.github/workflows/samples-dotnet10.yaml
vendored
2
.github/workflows/samples-dotnet10.yaml
vendored
@@ -48,7 +48,7 @@ jobs:
|
||||
# - samples/client/petstore/csharp/unityWebRequest/net10/Petstore
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-dotnet@v5.0.0
|
||||
- uses: actions/setup-dotnet@v5.1.0
|
||||
with:
|
||||
dotnet-version: '10.x'
|
||||
- name: Build
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
- samples/server/petstore/aspnetcore-6.0-useSwashBuckle
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-dotnet@v5.0.1
|
||||
- uses: actions/setup-dotnet@v5.1.0
|
||||
with:
|
||||
dotnet-version: '6.0.x'
|
||||
- name: Build
|
||||
|
||||
2
.github/workflows/samples-dotnet7-client.yml
vendored
2
.github/workflows/samples-dotnet7-client.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
- samples/client/petstore/csharp/restsharp/standard2.0/ConditionalSerialization/
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-dotnet@v5.0.1
|
||||
- uses: actions/setup-dotnet@v5.1.0
|
||||
with:
|
||||
dotnet-version: '7.0.x'
|
||||
- name: Build
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- samples/client/echo_api/csharp/restsharp/net8/EchoApi
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-dotnet@v5.0.1
|
||||
- uses: actions/setup-dotnet@v5.1.0
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Run echo server
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- samples/client/petstore/csharp/restsharp/net8/useVirtualForHooks/
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-dotnet@v5.0.1
|
||||
- uses: actions/setup-dotnet@v5.1.0
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Build
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
- samples/server/petstore/aspnetcore-8.0-use-centralized-package-version-management
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-dotnet@v5.0.1
|
||||
- uses: actions/setup-dotnet@v5.1.0
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Build
|
||||
|
||||
2
.github/workflows/samples-dotnet8.yaml
vendored
2
.github/workflows/samples-dotnet8.yaml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- samples/client/petstore/csharp/generichost/net8/UseDateTimeForDate
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-dotnet@v5.0.1
|
||||
- uses: actions/setup-dotnet@v5.1.0
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
- name: Build
|
||||
|
||||
2
.github/workflows/samples-dotnet9.yaml
vendored
2
.github/workflows/samples-dotnet9.yaml
vendored
@@ -41,7 +41,7 @@ jobs:
|
||||
#- samples/client/petstore/csharp/unityWebRequest/net9/Petstore
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-dotnet@v5.0.1
|
||||
- uses: actions/setup-dotnet@v5.1.0
|
||||
with:
|
||||
dotnet-version: '9.0.x'
|
||||
- name: Build
|
||||
|
||||
@@ -7,6 +7,7 @@ on:
|
||||
- samples/client/petstore/java/webclient-jakarta/**
|
||||
- samples/client/petstore/java/restclient-*/**
|
||||
- samples/client/others/java/webclient-sealedInterface/**
|
||||
- samples/client/others/java/webclient-sealedInterface_3_1/**
|
||||
- samples/client/petstore/java/webclient-useSingleRequestParameter/**
|
||||
- samples/client/others/java/restclient-enum-in-multipart/**
|
||||
pull_request:
|
||||
@@ -15,6 +16,7 @@ on:
|
||||
- samples/client/petstore/java/webclient-jakarta/**
|
||||
- samples/client/petstore/java/restclient-*/**
|
||||
- samples/client/others/java/webclient-sealedInterface/**
|
||||
- samples/client/others/java/webclient-sealedInterface_3_1/**
|
||||
- samples/client/petstore/java/webclient-useSingleRequestParameter/**
|
||||
- samples/client/others/java/restclient-enum-in-multipart/**
|
||||
jobs:
|
||||
@@ -34,6 +36,7 @@ jobs:
|
||||
- samples/client/petstore/java/restclient-useSingleRequestParameter
|
||||
- samples/client/petstore/java/restclient-useSingleRequestParameter-static
|
||||
- samples/client/others/java/webclient-sealedInterface
|
||||
- samples/client/others/java/webclient-sealedInterface_3_1
|
||||
- samples/client/petstore/java/webclient-useSingleRequestParameter
|
||||
- samples/client/others/java/restclient-enum-in-multipart
|
||||
steps:
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
- samples/server/petstore/java-play-framework-fake-endpoints
|
||||
- samples/server/petstore/java-play-framework-fake-endpoints-with-security
|
||||
- samples/server/petstore/java-play-framework-no-bean-validation
|
||||
- samples/server/petstore/java-play-framework-no-exception-handling
|
||||
- samples/server/petstore/java-play-framework-no-excp-handling
|
||||
- samples/server/petstore/java-play-framework-no-interface
|
||||
- samples/server/petstore/java-play-framework-no-nullable
|
||||
- samples/server/petstore/java-play-framework-no-swagger-ui
|
||||
|
||||
69
.github/workflows/samples-r.yaml
vendored
Normal file
69
.github/workflows/samples-r.yaml
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
name: Samples R clients
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- samples/client/petstore/R/**
|
||||
- samples/client/petstore/R-httr2/**
|
||||
- samples/client/petstore/R-httr2-wrapper/**
|
||||
pull_request:
|
||||
paths:
|
||||
- samples/client/petstore/R/**
|
||||
- samples/client/petstore/R-httr2/**
|
||||
- samples/client/petstore/R-httr2-wrapper/**
|
||||
jobs:
|
||||
build:
|
||||
name: Build R projects
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
sample:
|
||||
# clients
|
||||
- samples/client/petstore/R/
|
||||
- samples/client/petstore/R-httr2/
|
||||
- samples/client/petstore/R-httr2-wrapper/
|
||||
services:
|
||||
petstore-api:
|
||||
image: swaggerapi/petstore
|
||||
ports:
|
||||
- 80:8080
|
||||
env:
|
||||
SWAGGER_HOST: http://petstore.swagger.io
|
||||
SWAGGER_BASE_PATH: /v2
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Add hosts to /etc/hosts
|
||||
run: |
|
||||
sudo echo "127.0.0.1 petstore.swagger.io" | sudo tee -a /etc/hosts
|
||||
- uses: r-lib/actions/setup-r@v2
|
||||
with:
|
||||
use-public-rspm: true
|
||||
|
||||
- name: Install devtools
|
||||
run: install.packages("devtools")
|
||||
shell: Rscript {0}
|
||||
working-directory: ${{ matrix.sample }}
|
||||
|
||||
- name: Build
|
||||
run: devtools::build()
|
||||
shell: Rscript {0}
|
||||
working-directory: ${{ matrix.sample }}
|
||||
|
||||
- uses: r-lib/actions/setup-r-dependencies@v2
|
||||
with:
|
||||
working-directory: ${{ matrix.sample }}
|
||||
extra-packages: any::rcmdcheck
|
||||
needs: check
|
||||
|
||||
- uses: r-lib/actions/check-r-package@v2
|
||||
with:
|
||||
working-directory: ${{ matrix.sample }}
|
||||
upload-snapshots: true
|
||||
build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")'
|
||||
error-on: '"error"'
|
||||
|
||||
- name: Install local package
|
||||
run: R CMD INSTALL .
|
||||
shell: bash # Ensure correct shell for command execution
|
||||
working-directory: ${{ matrix.sample }}
|
||||
2
.github/workflows/samples-spring.yaml
vendored
2
.github/workflows/samples-spring.yaml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
- samples/openapi3/server/petstore/springboot-delegate
|
||||
- samples/openapi3/server/petstore/spring-boot-oneof
|
||||
- samples/server/petstore/spring-boot-nullable-set
|
||||
- samples/server/petstore/spring-boot-defaultInterface-unhandledException
|
||||
- samples/server/petstore/spring-boot-defaultInterface-unhandledExcp
|
||||
- samples/server/petstore/springboot
|
||||
- samples/server/petstore/springboot-beanvalidation
|
||||
- samples/server/petstore/springboot-builtin-validation
|
||||
|
||||
@@ -15,6 +15,7 @@ on:
|
||||
- samples/client/petstore/typescript-angular-v18-provided-in-root/**
|
||||
- samples/client/petstore/typescript-angular-v19-provided-in-root/**
|
||||
- samples/client/petstore/typescript-angular-v20-provided-in-root/**
|
||||
- samples/client/petstore/typescript-angular-v21-provided-in-root/**
|
||||
- samples/openapi3/client/petstore/typescript/builds/default/**
|
||||
# comment out due to build failure
|
||||
#- samples/openapi3/client/petstore/typescript/tests/default/**
|
||||
@@ -54,6 +55,7 @@ on:
|
||||
- samples/client/petstore/typescript-angular-v18-provided-in-root/**
|
||||
- samples/client/petstore/typescript-angular-v19-provided-in-root/**
|
||||
- samples/client/petstore/typescript-angular-v20-provided-in-root/**
|
||||
- samples/client/petstore/typescript-angular-v21-provided-in-root/**
|
||||
- samples/openapi3/client/petstore/typescript/builds/default/**
|
||||
#- samples/openapi3/client/petstore/typescript/tests/default/**
|
||||
- samples/openapi3/client/petstore/typescript/builds/jquery/**
|
||||
@@ -104,6 +106,7 @@ jobs:
|
||||
- samples/client/petstore/typescript-angular-v18-provided-in-root/
|
||||
- samples/client/petstore/typescript-angular-v19-provided-in-root/
|
||||
- samples/client/petstore/typescript-angular-v20-provided-in-root/
|
||||
- samples/client/petstore/typescript-angular-v21-provided-in-root/
|
||||
- samples/openapi3/client/petstore/typescript/builds/default/
|
||||
#- samples/openapi3/client/petstore/typescript/tests/default/
|
||||
- samples/openapi3/client/petstore/typescript/builds/jquery/
|
||||
|
||||
@@ -13,6 +13,7 @@ COPY ./google_checkstyle.xml ${GEN_DIR}
|
||||
# All poms are copied, then we go offline, to allow for better caching of code changes without fetching all dependencies each time
|
||||
COPY ./modules/openapi-generator-gradle-plugin/pom.xml ${GEN_DIR}/modules/openapi-generator-gradle-plugin/
|
||||
COPY ./modules/openapi-generator-maven-plugin/pom.xml ${GEN_DIR}/modules/openapi-generator-maven-plugin/
|
||||
COPY ./modules/openapi-generator-mill-plugin/pom.xml ${GEN_DIR}/modules/openapi-generator-mill-plugin/
|
||||
COPY ./modules/openapi-generator-online/pom.xml ${GEN_DIR}/modules/openapi-generator-online/
|
||||
COPY ./modules/openapi-generator-cli/pom.xml ${GEN_DIR}/modules/openapi-generator-cli/
|
||||
COPY ./modules/openapi-generator-core/pom.xml ${GEN_DIR}/modules/openapi-generator-core/
|
||||
@@ -23,6 +24,7 @@ RUN mvn dependency:go-offline
|
||||
# Modules are copied individually here to allow for caching of docker layers between major.minor versions
|
||||
COPY ./modules/openapi-generator-gradle-plugin ${GEN_DIR}/modules/openapi-generator-gradle-plugin
|
||||
COPY ./modules/openapi-generator-maven-plugin ${GEN_DIR}/modules/openapi-generator-maven-plugin
|
||||
COPY ./modules/openapi-generator-mill-plugin ${GEN_DIR}/modules/openapi-generator-mill-plugin
|
||||
COPY ./modules/openapi-generator-online ${GEN_DIR}/modules/openapi-generator-online
|
||||
COPY ./modules/openapi-generator-cli ${GEN_DIR}/modules/openapi-generator-cli
|
||||
COPY ./modules/openapi-generator-core ${GEN_DIR}/modules/openapi-generator-core
|
||||
|
||||
@@ -757,6 +757,7 @@ Here are some companies/projects (alphabetical order) using OpenAPI Generator in
|
||||
- [REST United](https://restunited.com)
|
||||
- [Robocorp](https://www.robocorp.com)
|
||||
- [Robotinfra](https://www.robotinfra.com)
|
||||
- [Sarvika Technologies Pvt. Ltd.](https://www.sarvika.com)
|
||||
- [SearchApi](https://www.searchapi.io/)
|
||||
- [SmartHR](https://smarthr.co.jp/)
|
||||
- [Sony Interactive Entertainment](https://www.sie.com/en/index.html)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
generatorName: go
|
||||
outputDir: samples/client/others/go/allof_multiple_ref_and_discriminator
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/go/allof_multiple_ref_and_discriminator.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/go
|
||||
additionalProperties:
|
||||
hideGenerationTimestamp: "true"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
generatorName: go
|
||||
outputDir: samples/client/others/go/oneof-anyof-required
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/go/spec-with-oneof-anyof-required.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/go
|
||||
additionalProperties:
|
||||
hideGenerationTimestamp: "true"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
generatorName: go
|
||||
outputDir: samples/client/others/go/oneof-discriminator-lookup
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/go/spec-with-oneof-discriminator.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/go
|
||||
additionalProperties:
|
||||
useOneOfDiscriminatorLookup: "true"
|
||||
hideGenerationTimestamp: "true"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
generatorName: java-play-framework
|
||||
outputDir: samples/server/petstore/java-play-framework-no-exception-handling
|
||||
outputDir: samples/server/petstore/java-play-framework-no-excp-handling
|
||||
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/JavaPlayFramework
|
||||
additionalProperties:
|
||||
10
bin/configs/java-webclient-sealedInterface-3.1.yaml
Normal file
10
bin/configs/java-webclient-sealedInterface-3.1.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
generatorName: java
|
||||
outputDir: samples/client/others/java/webclient-sealedInterface_3_1
|
||||
library: webclient
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_1/oneof_polymorphism_and_inheritance.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/Java
|
||||
additionalProperties:
|
||||
artifactId: sealed-interface-webclient
|
||||
hideGenerationTimestamp: "true"
|
||||
useOneOfInterfaces: true
|
||||
useSealedOneOfInterfaces: true
|
||||
9
bin/configs/rust-reqwest-multipart-async.yaml
Normal file
9
bin/configs/rust-reqwest-multipart-async.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
generatorName: rust
|
||||
outputDir: samples/client/others/rust/reqwest/multipart-async
|
||||
library: reqwest
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/rust/multipart-file-upload.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/rust
|
||||
additionalProperties:
|
||||
supportAsync: true
|
||||
useSingleRequestParameter: true
|
||||
packageName: multipart-upload-reqwest-async
|
||||
@@ -1,5 +1,5 @@
|
||||
generatorName: spring
|
||||
outputDir: samples/server/petstore/spring-boot-defaultInterface-unhandledException
|
||||
outputDir: samples/server/petstore/spring-boot-defaultInterface-unhandledExcp
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/spring/petstore-with-fake-endpoints-models-for-testing.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/JavaSpring
|
||||
additionalProperties:
|
||||
@@ -1,6 +0,0 @@
|
||||
generatorName: typescript-angular
|
||||
outputDir: samples/client/petstore/typescript-angular-v12-oneOf/builds/default
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/oneOfArrayMapImport.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
|
||||
additionalProperties:
|
||||
ngVersion: 12.2.0
|
||||
@@ -1,7 +0,0 @@
|
||||
generatorName: typescript-angular
|
||||
outputDir: samples/client/petstore/typescript-angular-v12-provided-in-any/builds/default
|
||||
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
|
||||
additionalProperties:
|
||||
ngVersion: 12.2.0
|
||||
providedIn: any
|
||||
@@ -1,10 +0,0 @@
|
||||
generatorName: typescript-angular
|
||||
outputDir: samples/client/petstore/typescript-angular-v12-provided-in-root/builds/with-npm
|
||||
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
|
||||
additionalProperties:
|
||||
ngVersion: 12.2.0
|
||||
npmVersion: 1.0.0
|
||||
npmName: '@openapitools/typescript-angular-petstore'
|
||||
npmRepository: https://skimdb.npmjs.com/registry
|
||||
snapshot: false
|
||||
@@ -1,6 +0,0 @@
|
||||
generatorName: typescript-angular
|
||||
outputDir: samples/client/petstore/typescript-angular-v12-provided-in-root/builds/default
|
||||
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
|
||||
additionalProperties:
|
||||
ngVersion: 12.2.0
|
||||
@@ -1,6 +0,0 @@
|
||||
generatorName: typescript-angular
|
||||
outputDir: samples/client/petstore/typescript-angular-v13-oneOf/builds/default
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/oneOfArrayMapImport.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
|
||||
additionalProperties:
|
||||
ngVersion: 13.0.1
|
||||
@@ -1,7 +0,0 @@
|
||||
generatorName: typescript-angular
|
||||
outputDir: samples/client/petstore/typescript-angular-v13-provided-in-any/builds/default
|
||||
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
|
||||
additionalProperties:
|
||||
ngVersion: 13.0.1
|
||||
providedIn: any
|
||||
@@ -1,11 +0,0 @@
|
||||
generatorName: typescript-angular
|
||||
outputDir: samples/client/petstore/typescript-angular-v13-provided-in-root/builds/with-npm
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
|
||||
additionalProperties:
|
||||
ngVersion: 13.0.1
|
||||
npmVersion: 1.0.0
|
||||
npmName: '@openapitools/typescript-angular-petstore'
|
||||
npmRepository: https://skimdb.npmjs.com/registry
|
||||
snapshot: false
|
||||
supportsES6: true
|
||||
@@ -1,8 +0,0 @@
|
||||
generatorName: typescript-angular
|
||||
outputDir: samples/client/petstore/typescript-angular-v14-query-param-object-format
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
|
||||
additionalProperties:
|
||||
ngVersion: 14.0.5
|
||||
supportsES6: true
|
||||
queryParamObjectFormat: json
|
||||
@@ -1,7 +0,0 @@
|
||||
generatorName: typescript-angular
|
||||
outputDir: samples/client/petstore/typescript-angular-v15-provided-in-root/builds/default
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
|
||||
additionalProperties:
|
||||
ngVersion: 15.0.3
|
||||
supportsES6: true
|
||||
@@ -1,7 +1,10 @@
|
||||
generatorName: typescript-angular
|
||||
outputDir: samples/client/petstore/typescript-angular-v13-provided-in-root/builds/default
|
||||
outputDir: samples/client/petstore/typescript-angular-v21-provided-in-root/builds/default
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
|
||||
additionalProperties:
|
||||
ngVersion: 13.0.1
|
||||
ngVersion: 21.0.0
|
||||
supportsES6: true
|
||||
ngVersion21: true
|
||||
enumNameMappings:
|
||||
delivered: SHIPPED
|
||||
@@ -1,7 +1,9 @@
|
||||
generatorName: typescript-angular
|
||||
outputDir: samples/client/petstore/typescript-angular-v14-provided-in-root/builds/default
|
||||
outputDir: samples/client/petstore/typescript-angular-v21/builds/default
|
||||
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/typescript-angular
|
||||
additionalProperties:
|
||||
ngVersion: 14.0.5
|
||||
ngVersion: 21.0.0
|
||||
npmName: sample-angular-21-0-0
|
||||
supportsES6: true
|
||||
ngVersion21: true
|
||||
@@ -60,6 +60,13 @@ else
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
# shellcheck disable=SC2068
|
||||
java ${JAVA_OPTS} -jar "$executable" batch ${BATCH_OPTS} --includes-base-dir "${root}" --fail-fast -- ${files[@]}
|
||||
if java ${JAVA_OPTS} -jar "$executable" batch ${BATCH_OPTS} --includes-base-dir "${root}" --fail-fast -- ${files[@]} 2>&1 | tee /dev/pts/0 | grep -q -i "exception"; then
|
||||
echo "Found exception(s) when running the generator(s) to update the samples."
|
||||
export GENERATE_ERROR=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "$GENERATE_ERROR" ]]; then
|
||||
echo "Found exception(s) when running the generator(s) to update the samples."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -93,6 +93,7 @@ declare -a xml_files=(
|
||||
declare -a properties_files=(
|
||||
"${root}/modules/openapi-generator-gradle-plugin/gradle.properties"
|
||||
"${root}/modules/openapi-generator-gradle-plugin/samples/local-spec/gradle.properties"
|
||||
"${root}/modules/openapi-generator-mill-plugin/example/mill-build/version.properties"
|
||||
)
|
||||
|
||||
${cwd}/bump.sh -f ${version} -i ${inc} ${xml_files[@]}
|
||||
|
||||
@@ -62,3 +62,7 @@
|
||||
sha256: b2093528aac971193f2863a70f46eea45cf8bda79120b133a614599e80d8b46d
|
||||
- filename: "samples/server/petstore/rust-axum/output/openapi-v3/tests/oneof_untagged.rs"
|
||||
sha256: 1d3fb01f65e98290b1d3eece28014c7d3e3f2fdf18e7110249d3c591cc4642ab
|
||||
- filename: "samples/client/petstore/kotlin-jvm-spring-3-restclient/src/test/kotlin/org/openapitools/integration/PetApiTest.kt"
|
||||
sha256: 82a6be39c1ed3dada96dfa1833a6709834cb3f9f9d50a19cbd9d49699e46df4f
|
||||
- filename: "samples/client/petstore/kotlin-jvm-spring-3-restclient/src/test/kotlin/org/openapitools/integration/UserApiTest.kt"
|
||||
sha256: bc64fb94857a3598e1332f1278307c3078ea9ec4b4aa75690e6eda86e9729a8d
|
||||
|
||||
@@ -48,4 +48,4 @@ workflows:
|
||||
|
||||
meta:
|
||||
bitrise.io:
|
||||
stack: osx-xcode-16.3.x
|
||||
stack: osx-xcode-26.2.x
|
||||
|
||||
@@ -94,7 +94,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
<li>if</li>
|
||||
<li>in</li>
|
||||
<li>include</li>
|
||||
<li>instance</li>
|
||||
<li>instance_sizeof</li>
|
||||
<li>is_a?</li>
|
||||
<li>lib</li>
|
||||
<li>macro</li>
|
||||
@@ -102,9 +102,11 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
<li>next</li>
|
||||
<li>nil</li>
|
||||
<li>nil?</li>
|
||||
<li>object_id</li>
|
||||
<li>of</li>
|
||||
<li>out</li>
|
||||
<li>pointerof</li>
|
||||
<li>previous_def</li>
|
||||
<li>private</li>
|
||||
<li>protected</li>
|
||||
<li>require</li>
|
||||
|
||||
@@ -11,7 +11,7 @@ title: Documentation for the typescript-angular Generator
|
||||
| generator type | CLIENT | |
|
||||
| generator language | Typescript | |
|
||||
| generator default templating engine | mustache | |
|
||||
| helpTxt | Generates a TypeScript Angular (9.x - 20.x) client library. | |
|
||||
| helpTxt | Generates a TypeScript Angular (9.x - 21.x) client library. | |
|
||||
|
||||
## CONFIG OPTIONS
|
||||
These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
|
||||
@@ -34,7 +34,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|
||||
|modelPropertyNaming|Naming convention for the property: 'camelCase', 'PascalCase', 'snake_case' and 'original', which keeps the original name. Only change it if you provide your own run-time code for (de-)serialization of models| |original|
|
||||
|modelSuffix|The suffix of the generated model.| |null|
|
||||
|ngPackagrVersion|The version of ng-packagr compatible with Angular (see ngVersion option).| |null|
|
||||
|ngVersion|The version of Angular. (At least 9.0.0)| |20.0.0|
|
||||
|ngVersion|The version of Angular. (At least 9.0.0)| |21.0.0|
|
||||
|npmName|The name under which you want to publish generated npm package. Required to generate a full package| |null|
|
||||
|npmRepository|Use this property to set an url your private npmRepo in the package.json| |null|
|
||||
|npmVersion|The version of your npm package. If not provided, using the version from the OpenAPI specification file.| |1.0.0|
|
||||
|
||||
@@ -120,3 +120,56 @@ openApiGenerate {
|
||||
```
|
||||
|
||||
*If you want to create separate tasks (for example when you have more than one api spec and require different parameters for each), this is how to do so in Gradle 7+: `tasks.register('taskName', org.openapitools.generator.gradle.plugin.tasks.GenerateTask) { ... }`.*
|
||||
|
||||
## Mill
|
||||
|
||||
This Mill library provides a Mill module that can be used to generate code from OpenAPI specifications.
|
||||
|
||||
### Example
|
||||
|
||||
```scala
|
||||
//| mill-version: 1.0.6
|
||||
//| mvnDeps:
|
||||
//| - org.openapitools:openapi-generator-mill-plugin:7.19.0 # 1.
|
||||
|
||||
import mill.*
|
||||
|
||||
import org.openapitools.generator.mill.OpenApiModule // 2.
|
||||
|
||||
object `package` extends JavaModule with MavenModule with OpenApiModule { // 3.
|
||||
|
||||
// other Mill config...
|
||||
|
||||
object openapi extends OpenApiConfig { // 4.
|
||||
def inputSpec: T[PathRef] = Task.Source(BuildCtx.workspaceRoot / "api" / "petstore.yaml")
|
||||
// other config options...
|
||||
}
|
||||
|
||||
override def generatedSources: T[Seq[PathRef]] = Seq(
|
||||
PathRef(Task.dest),
|
||||
openapi.generate(), // 5.
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
1. Add the plugin to your `build.mill` as `mvnDeps` in the header section
|
||||
2. import `org.openapitools.generator.mill.OpenApiModule`
|
||||
3. add `OpenApiModule` to the module definition
|
||||
4. configure 1-n `OpenApiConfig` as sub-modules
|
||||
5. run the generation as part of the `compile` task
|
||||
|
||||
This gives access to the following tasks:
|
||||
|
||||
| Task | Description |
|
||||
|---------------------------|---------------------------------------------------------------------------------------------|
|
||||
| <configName>.generate | Generate code via Open API Tools Generator for Open API 2.0 or 3.x specification documents. |
|
||||
| <configName>.validateSpec | Validates the configured spec |
|
||||
|
||||
and a command
|
||||
|
||||
| Command | Description |
|
||||
|---------------------|------------------------------------------------|
|
||||
| validateOpenapiSpec | Takes the path to a spec file and validates it |
|
||||
|
||||
|
||||
For full details of all options, see the [plugin README](https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-mill-plugin).
|
||||
|
||||
173
modules/openapi-generator-mill-plugin/README.md
Normal file
173
modules/openapi-generator-mill-plugin/README.md
Normal file
@@ -0,0 +1,173 @@
|
||||
openapi-generator-mill-plugin
|
||||
============================
|
||||
|
||||
A [Mill](https://mill-build.org) library to support the OpenAPI generator project.
|
||||
|
||||
Usage
|
||||
============================
|
||||
|
||||
1. Add the plugin to your `build.mill` as `mvnDeps` in the header section
|
||||
2. import `org.openapitools.generator.mill.OpenApiModule`
|
||||
3. add `OpenApiModule` to the module definition
|
||||
4. configure 1-n `OpenApiConfig` as sub-modules
|
||||
|
||||
```scala
|
||||
//| mill-version: 1.0.6
|
||||
//| mvnDeps:
|
||||
//| - org.openapitools:openapi-generator-mill-plugin:7.19.0 # 1.
|
||||
|
||||
import mill.*
|
||||
|
||||
import org.openapitools.generator.mill.OpenApiModule // 2.
|
||||
|
||||
object `package` extends JavaModule with MavenModule with OpenApiModule { // 3.
|
||||
|
||||
override def mvnDeps = Seq(
|
||||
mvn"jakarta.platform:jakarta.jakartaee-api:11.0.0",
|
||||
mvn"com.fasterxml.jackson.core:jackson-databind:2.20.0",
|
||||
)
|
||||
|
||||
object openapi extends OpenApiConfig { // 4.
|
||||
def inputSpec: T[PathRef] = Task.Source(BuildCtx.workspaceRoot / "api" / "petstore.yaml")
|
||||
def apiPackage: T[String] = "com.acme.foo.boundary.web.api"
|
||||
def modelPackage: T[String] = "com.acme.foo.boundary.web.model"
|
||||
def generatorName: T[String] = "jaxrs-spec"
|
||||
def sourceFolder: T[String] = "src/main/java"
|
||||
|
||||
def additionalProperties: T[Map[String, String]] = Map(
|
||||
"dateLibrary" -> "java8",
|
||||
"useJakartaEe" -> "true",
|
||||
"useSwaggerAnnotations" -> "false",
|
||||
"interfaceOnly" -> "true",
|
||||
"useTags" -> "true",
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Followed by:
|
||||
|
||||
```bash
|
||||
mill openapi.generate
|
||||
```
|
||||
|
||||
Usually you want to include the generation to the `compile` phase and have the sources in your source-tree which can
|
||||
be achieved by adding the generation task to the `generatedSources`.
|
||||
|
||||
```scala
|
||||
override def generatedSources: T[Seq[PathRef]] = Seq(
|
||||
PathRef(Task.dest),
|
||||
openapi.generate(),
|
||||
)
|
||||
```
|
||||
|
||||
Followed by:
|
||||
|
||||
```bash
|
||||
mill __.compile
|
||||
```
|
||||
|
||||
This works because `generatedSources` expects a list of `PathRef`s which constitute all folders that contain additional
|
||||
(generated) sources and the `generate` task from each `OpenApiConfig` returns a `PathRef` to the folder where it put the sources.
|
||||
|
||||
|
||||
### General Configuration parameters for OpenApiConfig
|
||||
|
||||
| Option | Description |
|
||||
|------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `verbose` | verbose mode (`false` by default) |
|
||||
| `inputSpec` | OpenAPI Spec file path |
|
||||
| `inputSpecRootDirectory` | Local root folder with spec file(s) |
|
||||
| `mergedFileName` | Name of the file that will contain all merged specs |
|
||||
| `generatorName` | target generator name |
|
||||
| `cleanupOutput` | Defines whether the output directory should be cleaned up before generating the output (`false` by default). |
|
||||
| `cleanup` | Defines a task which contains an `Option[Path => Unit]` which is called after the generation completed. Useful for instance to delete generated Types which are already replaced by import/type-mappings. |
|
||||
| `gitSettings` | sets Git information of the project (with `host`, `userId` and `repoId`) |
|
||||
| `templateDirectory` | directory with mustache templates |
|
||||
| `engine` | The name of templating engine to use, "mustache" (default) or "handlebars" (beta) |
|
||||
| `auth` | adds authorization headers when fetching the OpenAPI definitions remotely. Pass in a URL-encoded string of `name:header` with a comma separating multiple values |
|
||||
| `skipOverwrite` | Specifies if the existing files should be overwritten during the generation. (`false` by default) |
|
||||
| `apiPackage` | the package to use for generated api objects/classes |
|
||||
| `modelPackage` | the package to use for generated model objects/classes |
|
||||
| `invokerPackage` | the package to use for the generated invoker objects |
|
||||
| `packageName` | the default package name to use for the generated objects |
|
||||
| `artifactSettings` | sets project information in generated pom.xml/build.gradle or other build script. Language-specific conversions occur in non-jvm generators |
|
||||
| `library` | library template (sub-template) |
|
||||
| `modelNamePrefix` | Sets the prefix for model classes and enums |
|
||||
| `modelNameSuffix` | Sets the suffix for model classes and enums |
|
||||
| `apiNameSuffix` | Sets the suffix for api classes |
|
||||
| `ignoreFileOverride` | specifies the full path to a `.openapi-generator-ignore` used for pattern based overrides of generated outputs |
|
||||
| `httpUserAgent` | Sets custom User-Agent header value |
|
||||
| `removeOperationIdPrefix` | remove operationId prefix (e.g. user_getName => getName) |
|
||||
| `skipOperationExample` | skip examples defined in the operation |
|
||||
| `logToStderr` | write all log messages (not just errors) to STDERR |
|
||||
| `enablePostProcessFile` | post-processing hook |
|
||||
| `skipValidateSpec` | Whether or not to skip validating the input spec prior to generation. By default, invalid specifications will result in an error. |
|
||||
| `strictSpec` | Whether or not to treat an input document strictly against the spec. 'MUST' and 'SHALL' wording in OpenAPI spec is strictly adhered to. e.g. when false, no fixes will be applied to documents which pass validation but don't follow the spec. |
|
||||
| `openapiNormalizer` | specifies the rules to be enabled in OpenAPI normalizer in the form of RULE_1=true,RULE_2=original. |
|
||||
| `generateAliasAsModel` | generate alias (array, map) as model |
|
||||
| `configOptions` | N/A | a **map** of generator-specific parameters. To show a full list of generator-specified parameters (options), please use `configHelp` (explained below)
|
||||
| `importMappings` | specifies mappings between a given class and the import that should be used for that class in the format of type=import,type=import. You can also have multiple occurrences of this option |
|
||||
| `typeMappings` | sets mappings between OpenAPI spec types and generated code types in the format of OpenAPIType=generatedType,OpenAPIType=generatedType. For example: `array=List,map=Map,string=String`. You can also have multiple occurrences of this option. To map a specified format, use type+format, e.g. string+password=EncryptedString will map `type: string, format: password` to `EncryptedString`. |
|
||||
| `schemaMappings` | specifies mappings between the schema and the new name in the format of schema_a=Cat,schema_b=Bird. https://openapi-generator.tech/docs/customization/#schema-mapping |
|
||||
| `nameMappings` | specifies mappings between the property name and the new name in the format of property_a=firstProperty,property_b=secondProperty. https://openapi-generator.tech/docs/customization/#name-mapping |
|
||||
| `modelNameMappings` | specifies mappings between the model name and the new name in the format of model_a=FirstModel,model_b=SecondModel. https://openapi-generator.tech/docs/customization/#name-mapping |
|
||||
| `parameterNameMappings` | specifies mappings between the parameter name and the new name in the format of param_a=first_parameter,param_b=second_parameter. https://openapi-generator.tech/docs/customization/#name-mapping |
|
||||
| `inlineSchemaNameMappings` | specifies mappings between the inline schema name and the new name in the format of inline_object_2=Cat,inline_object_5=Bird. |
|
||||
| `inlineSchemaOptions` | specifies the options used when naming inline schema in inline model resolver |
|
||||
| `languageSpecificPrimitives` | specifies additional language specific primitive types in the format of type1,type2,type3,type3. For example: `String,boolean,Boolean,Double`. You can also have multiple occurrences of this option |
|
||||
| `additionalProperties` | sets additional properties that can be referenced by the mustache templates in the format of name=value,name=value. You can also have multiple occurrences of this option |
|
||||
| `reservedWordsMappings` | specifies how a reserved name should be escaped to. Otherwise, the default `_<name>` is used. For example `id=identifier`. You can also have multiple occurrences of this option |
|
||||
| `generateApis` | generate the apis (`true` by default). To generate only a subset, define via `apiFilesConstrainedTo`. |
|
||||
| `apiFilesConstrainedTo` | A comma separated list of apis to generate. All apis is the default. |
|
||||
| `generateModels` | generate the models (`true` by default). To generate only a subset, define via `modelFilesConstrainedTo`. |
|
||||
| `modelFilesConstrainedTo` | A comma separated list of models to generate. All models is the default. |
|
||||
| `generateRecursiveDependentModels` | Enables dependent Models to be generated when `modelFilesConstrainedTo` is used. Default depends on `modelFilesConstrainedTo` (true when nonEmpty) |
|
||||
| `generateSupportingFiles` | generate the supporting files (`true` by default). To generate only a subset, define via `supportingFilesConstrainedTo`. |
|
||||
| `supportingFilesConstrainedTo` | A list of supporting files to generate. When not defined, all files will be generated. |
|
||||
| `generateModelTests` | generate the model tests (currently disabled) |
|
||||
| `generateModelDocumentation` | generate the model documentation (`true` by default) |
|
||||
| `generateApiTests` | generate the api tests (currently disabled) |
|
||||
| `generateApiDocumentation` | generate the api documentation (`true` by default) |
|
||||
| `dryRun` | Defines whether the generator should run in dry-run mode. In dry-run mode no files are written and a summary about file states is output ( `false` by default). |
|
||||
|
||||
### Type and import mappings
|
||||
|
||||
To override the mappings between OpenAPI spec types and the types used in the generated code, set `typeMappings`.
|
||||
|
||||
```scala
|
||||
def typeMappings: T[Map[String, String]] = Map(
|
||||
"time" -> "LocalTime"
|
||||
)
|
||||
```
|
||||
|
||||
For types that are not already included in the generator configuration, you may need to add a corresponding `importMapping` too.
|
||||
|
||||
```scala
|
||||
def typeMappings: T[Map[String, String]] = Map(
|
||||
"binary" -> "StreamingOutput",
|
||||
"file" -> "StreamingOutput"
|
||||
)
|
||||
def importMappings: T[Map[String, String]] = Map(
|
||||
"StreamingOutput" -> "javax.ws.rs.core.StreamingOutput",
|
||||
)
|
||||
```
|
||||
|
||||
### Validate Command
|
||||
|
||||
You can validate any OpenAPI spec file by calling `validateOpenapiSpec` on the `OpenApiModule`.
|
||||
|
||||
```bash
|
||||
mill validateOpenapiSpec $(pwd)/api/petstore-v3.0-invalid.yaml
|
||||
```
|
||||
|
||||
This command has two additional parameters:
|
||||
* `--failOnWarnings true` enable failing the check already on warnings
|
||||
* `--recommend false`
|
||||
|
||||
You can also validate your `OpenApiConfig` object by calling `validate` on it.
|
||||
|
||||
```bash
|
||||
mill yourConfigObject.validate
|
||||
```
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
openapi: "3.0.0"
|
||||
servers:
|
||||
- url: http://petstore.swagger.io/v1
|
||||
paths:
|
||||
/pets:
|
||||
get:
|
||||
summary: List all pets
|
||||
operationId: listPets
|
||||
tags:
|
||||
- pets
|
||||
parameters:
|
||||
- name: limit
|
||||
in: query
|
||||
description: How many items to return at one time (max 100)
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
responses:
|
||||
'200':
|
||||
description: A paged array of pets
|
||||
headers:
|
||||
x-next:
|
||||
description: A link to the next page of responses
|
||||
schema:
|
||||
type: string
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Pets"
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
post:
|
||||
summary: Create a pet
|
||||
tags:
|
||||
- pets
|
||||
responses:
|
||||
'201':
|
||||
description: Null response
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/pets/{petId}:
|
||||
get:
|
||||
summary: Info for a specific pet
|
||||
operationId: showPetById
|
||||
tags:
|
||||
- pets
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
required: true
|
||||
description: The id of the pet to retrieve
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Expected response to a valid request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Pets"
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
components:
|
||||
schemas:
|
||||
Pet:
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
Pets:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Pet"
|
||||
Error:
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
message:
|
||||
type: string
|
||||
736
modules/openapi-generator-mill-plugin/example/api/petstore.yaml
Normal file
736
modules/openapi-generator-mill-plugin/example/api/petstore.yaml
Normal file
@@ -0,0 +1,736 @@
|
||||
openapi: 3.0.0
|
||||
servers:
|
||||
- url: 'http://petstore.swagger.io/v2'
|
||||
info:
|
||||
description: >-
|
||||
This is a sample server Petstore server. For this sample, you can use the api key
|
||||
`special-key` to test the authorization filters.
|
||||
version: 1.0.0
|
||||
title: OpenAPI Petstore
|
||||
license:
|
||||
name: Apache-2.0
|
||||
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
|
||||
tags:
|
||||
- name: pet
|
||||
description: Everything about your Pets
|
||||
- name: store
|
||||
description: Access to Petstore orders
|
||||
- name: user
|
||||
description: Operations about user
|
||||
paths:
|
||||
/pet:
|
||||
post:
|
||||
tags:
|
||||
- pet
|
||||
summary: Add a new pet to the store
|
||||
description: ''
|
||||
operationId: addPet
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'405':
|
||||
description: Invalid input
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/Pet'
|
||||
put:
|
||||
tags:
|
||||
- pet
|
||||
summary: Update an existing pet
|
||||
description: ''
|
||||
operationId: updatePet
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'400':
|
||||
description: Invalid ID supplied
|
||||
'404':
|
||||
description: Pet not found
|
||||
'405':
|
||||
description: Validation exception
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/Pet'
|
||||
/pet/findByStatus:
|
||||
get:
|
||||
tags:
|
||||
- pet
|
||||
summary: Finds Pets by status
|
||||
description: Multiple status values can be provided with comma separated strings
|
||||
operationId: findPetsByStatus
|
||||
parameters:
|
||||
- name: status
|
||||
in: query
|
||||
description: Status values that need to be considered for filter
|
||||
required: true
|
||||
style: form
|
||||
explode: false
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
enum:
|
||||
- available
|
||||
- pending
|
||||
- sold
|
||||
default: available
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'400':
|
||||
description: Invalid status value
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'read:pets'
|
||||
/pet/findByTags:
|
||||
get:
|
||||
tags:
|
||||
- pet
|
||||
summary: Finds Pets by tags
|
||||
description: >-
|
||||
Multiple tags can be provided with comma separated strings. Use tag1,
|
||||
tag2, tag3 for testing.
|
||||
operationId: findPetsByTags
|
||||
parameters:
|
||||
- name: tags
|
||||
in: query
|
||||
description: Tags to filter by
|
||||
required: true
|
||||
style: form
|
||||
explode: false
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'400':
|
||||
description: Invalid tag value
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'read:pets'
|
||||
deprecated: true
|
||||
'/pet/{petId}':
|
||||
get:
|
||||
tags:
|
||||
- pet
|
||||
summary: Find pet by ID
|
||||
description: Returns a single pet
|
||||
operationId: getPetById
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
description: ID of pet to return
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
'400':
|
||||
description: Invalid ID supplied
|
||||
'404':
|
||||
description: Pet not found
|
||||
security:
|
||||
- api_key: []
|
||||
post:
|
||||
tags:
|
||||
- pet
|
||||
summary: Updates a pet in the store with form data
|
||||
description: ''
|
||||
operationId: updatePetWithForm
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
description: ID of pet that needs to be updated
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
'405':
|
||||
description: Invalid input
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
requestBody:
|
||||
content:
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: Updated name of the pet
|
||||
type: string
|
||||
status:
|
||||
description: Updated status of the pet
|
||||
type: string
|
||||
delete:
|
||||
tags:
|
||||
- pet
|
||||
summary: Deletes a pet
|
||||
description: ''
|
||||
operationId: deletePet
|
||||
parameters:
|
||||
- name: api_key
|
||||
in: header
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
- name: petId
|
||||
in: path
|
||||
description: Pet id to delete
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
'400':
|
||||
description: Invalid pet value
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
'/pet/{petId}/uploadImage':
|
||||
post:
|
||||
tags:
|
||||
- pet
|
||||
summary: uploads an image
|
||||
description: ''
|
||||
operationId: uploadFile
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
description: ID of pet to update
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiResponse'
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
requestBody:
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
additionalMetadata:
|
||||
description: Additional data to pass to server
|
||||
type: string
|
||||
file:
|
||||
description: file to upload
|
||||
type: string
|
||||
format: binary
|
||||
/store/inventory:
|
||||
get:
|
||||
tags:
|
||||
- store
|
||||
summary: Returns pet inventories by status
|
||||
description: Returns a map of status codes to quantities
|
||||
operationId: getInventory
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: integer
|
||||
format: int32
|
||||
security:
|
||||
- api_key: []
|
||||
/store/order:
|
||||
post:
|
||||
tags:
|
||||
- store
|
||||
summary: Place an order for a pet
|
||||
description: ''
|
||||
operationId: placeOrder
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
'400':
|
||||
description: Invalid Order
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
description: order placed for purchasing the pet
|
||||
required: true
|
||||
'/store/order/{orderId}':
|
||||
get:
|
||||
tags:
|
||||
- store
|
||||
summary: Find purchase order by ID
|
||||
description: >-
|
||||
For valid response try integer IDs with value <= 5 or > 10. Other values
|
||||
will generate exceptions
|
||||
operationId: getOrderById
|
||||
parameters:
|
||||
- name: orderId
|
||||
in: path
|
||||
description: ID of pet that needs to be fetched
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 1
|
||||
maximum: 5
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
'400':
|
||||
description: Invalid ID supplied
|
||||
'404':
|
||||
description: Order not found
|
||||
delete:
|
||||
tags:
|
||||
- store
|
||||
summary: Delete purchase order by ID
|
||||
description: >-
|
||||
For valid response try integer IDs with value < 1000. Anything above
|
||||
1000 or nonintegers will generate API errors
|
||||
operationId: deleteOrder
|
||||
parameters:
|
||||
- name: orderId
|
||||
in: path
|
||||
description: ID of the order that needs to be deleted
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'400':
|
||||
description: Invalid ID supplied
|
||||
'404':
|
||||
description: Order not found
|
||||
/user:
|
||||
post:
|
||||
tags:
|
||||
- user
|
||||
summary: Create user
|
||||
description: This can only be done by the logged in user.
|
||||
operationId: createUser
|
||||
responses:
|
||||
default:
|
||||
description: successful operation
|
||||
security:
|
||||
- api_key: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
description: Created user object
|
||||
required: true
|
||||
/user/createWithArray:
|
||||
post:
|
||||
tags:
|
||||
- user
|
||||
summary: Creates list of users with given input array
|
||||
description: ''
|
||||
operationId: createUsersWithArrayInput
|
||||
responses:
|
||||
default:
|
||||
description: successful operation
|
||||
security:
|
||||
- api_key: []
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/UserArray'
|
||||
/user/createWithList:
|
||||
post:
|
||||
tags:
|
||||
- user
|
||||
summary: Creates list of users with given input array
|
||||
description: ''
|
||||
operationId: createUsersWithListInput
|
||||
responses:
|
||||
default:
|
||||
description: successful operation
|
||||
security:
|
||||
- api_key: []
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/UserArray'
|
||||
/user/login:
|
||||
get:
|
||||
tags:
|
||||
- user
|
||||
summary: Logs user into the system
|
||||
description: ''
|
||||
operationId: loginUser
|
||||
parameters:
|
||||
- name: username
|
||||
in: query
|
||||
description: The user name for login
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$'
|
||||
- name: password
|
||||
in: query
|
||||
description: The password for login in clear text
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
headers:
|
||||
Set-Cookie:
|
||||
description: >-
|
||||
Cookie authentication key for use with the `api_key`
|
||||
apiKey authentication.
|
||||
schema:
|
||||
type: string
|
||||
example: AUTH_KEY=abcde12345; Path=/; HttpOnly
|
||||
X-Rate-Limit:
|
||||
description: calls per hour allowed by the user
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
X-Expires-After:
|
||||
description: date in UTC when token expires
|
||||
schema:
|
||||
type: string
|
||||
format: date-time
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
type: string
|
||||
application/json:
|
||||
schema:
|
||||
type: string
|
||||
'400':
|
||||
description: Invalid username/password supplied
|
||||
/user/logout:
|
||||
get:
|
||||
tags:
|
||||
- user
|
||||
summary: Logs out current logged in user session
|
||||
description: ''
|
||||
operationId: logoutUser
|
||||
responses:
|
||||
default:
|
||||
description: successful operation
|
||||
security:
|
||||
- api_key: []
|
||||
'/user/{username}':
|
||||
get:
|
||||
tags:
|
||||
- user
|
||||
summary: Get user by user name
|
||||
description: ''
|
||||
operationId: getUserByName
|
||||
parameters:
|
||||
- name: username
|
||||
in: path
|
||||
description: The name that needs to be fetched. Use user1 for testing.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
'400':
|
||||
description: Invalid username supplied
|
||||
'404':
|
||||
description: User not found
|
||||
put:
|
||||
tags:
|
||||
- user
|
||||
summary: Updated user
|
||||
description: This can only be done by the logged in user.
|
||||
operationId: updateUser
|
||||
parameters:
|
||||
- name: username
|
||||
in: path
|
||||
description: name that need to be deleted
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'400':
|
||||
description: Invalid user supplied
|
||||
'404':
|
||||
description: User not found
|
||||
security:
|
||||
- api_key: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
description: Updated user object
|
||||
required: true
|
||||
delete:
|
||||
tags:
|
||||
- user
|
||||
summary: Delete user
|
||||
description: This can only be done by the logged in user.
|
||||
operationId: deleteUser
|
||||
parameters:
|
||||
- name: username
|
||||
in: path
|
||||
description: The name that needs to be deleted
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'400':
|
||||
description: Invalid username supplied
|
||||
'404':
|
||||
description: User not found
|
||||
security:
|
||||
- api_key: []
|
||||
externalDocs:
|
||||
description: Find out more about Swagger
|
||||
url: 'http://swagger.io'
|
||||
components:
|
||||
requestBodies:
|
||||
UserArray:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
description: List of user object
|
||||
required: true
|
||||
Pet:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
application/xml:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
description: Pet object that needs to be added to the store
|
||||
required: true
|
||||
securitySchemes:
|
||||
petstore_auth:
|
||||
type: oauth2
|
||||
flows:
|
||||
implicit:
|
||||
authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog'
|
||||
scopes:
|
||||
'write:pets': modify pets in your account
|
||||
'read:pets': read your pets
|
||||
api_key:
|
||||
type: apiKey
|
||||
name: api_key
|
||||
in: header
|
||||
schemas:
|
||||
Order:
|
||||
title: Pet Order
|
||||
description: An order for a pets from the pet store
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
petId:
|
||||
type: integer
|
||||
format: int64
|
||||
quantity:
|
||||
type: integer
|
||||
format: int32
|
||||
shipDate:
|
||||
type: string
|
||||
format: date-time
|
||||
status:
|
||||
type: string
|
||||
description: Order Status
|
||||
enum:
|
||||
- placed
|
||||
- approved
|
||||
- delivered
|
||||
complete:
|
||||
type: boolean
|
||||
default: false
|
||||
xml:
|
||||
name: Order
|
||||
Category:
|
||||
title: Pet category
|
||||
description: A category for a pet
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$'
|
||||
xml:
|
||||
name: Category
|
||||
User:
|
||||
title: a User
|
||||
description: A User who is purchasing from the pet store
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
username:
|
||||
type: string
|
||||
firstName:
|
||||
type: string
|
||||
lastName:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
phone:
|
||||
type: string
|
||||
userStatus:
|
||||
type: integer
|
||||
format: int32
|
||||
description: User Status
|
||||
xml:
|
||||
name: User
|
||||
Tag:
|
||||
title: Pet Tag
|
||||
description: A tag for a pet
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
xml:
|
||||
name: Tag
|
||||
Pet:
|
||||
title: a Pet
|
||||
description: A pet for sale in the pet store
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- photoUrls
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
category:
|
||||
$ref: '#/components/schemas/Category'
|
||||
name:
|
||||
type: string
|
||||
example: doggie
|
||||
photoUrls:
|
||||
type: array
|
||||
xml:
|
||||
name: photoUrl
|
||||
wrapped: true
|
||||
items:
|
||||
type: string
|
||||
tags:
|
||||
type: array
|
||||
xml:
|
||||
name: tag
|
||||
wrapped: true
|
||||
items:
|
||||
$ref: '#/components/schemas/Tag'
|
||||
status:
|
||||
type: string
|
||||
description: pet status in the store
|
||||
enum:
|
||||
- available
|
||||
- pending
|
||||
- sold
|
||||
xml:
|
||||
name: Pet
|
||||
ApiResponse:
|
||||
title: An uploaded response
|
||||
description: Describes the result of uploading an image resource
|
||||
type: object
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
type:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
51
modules/openapi-generator-mill-plugin/example/build.mill
Normal file
51
modules/openapi-generator-mill-plugin/example/build.mill
Normal file
@@ -0,0 +1,51 @@
|
||||
//| mill-version: 1.0.6
|
||||
//| # usually you would add the plugin dependency like the following,
|
||||
//| # but for testing with SNAPSHOT versions, the plugin dependency is added in the meta-build
|
||||
//| # mvnDeps:
|
||||
//| # - org.openapitools:openapi-generator-mill-plugin:$MILL_OPENAPITOOLS_PLUGIN_VERSION
|
||||
//|
|
||||
package build
|
||||
|
||||
import mill.*
|
||||
import mill.api.BuildCtx
|
||||
import mill.javalib.publish.{Developer, License, VersionControl}
|
||||
import mill.scalalib.publish.PomSettings
|
||||
import mill.util.BuildInfo.{millBinPlatform, millVersion}
|
||||
import javalib.*
|
||||
|
||||
import org.openapitools.generator.mill.OpenApiModule
|
||||
|
||||
object `package` extends JavaModule with MavenModule with OpenApiModule {
|
||||
|
||||
override def mvnDeps = Seq(
|
||||
mvn"jakarta.platform:jakarta.jakartaee-api:10.0.0",
|
||||
mvn"com.fasterxml.jackson.core:jackson-databind:2.20.0",
|
||||
mvn"org.openapitools:jackson-databind-nullable:0.2.8"
|
||||
)
|
||||
|
||||
object openapi extends OpenApiConfig {
|
||||
override def inputSpec: T[PathRef] = Task.Source(BuildCtx.workspaceRoot / "api" / "petstore.yaml")
|
||||
override def apiPackage: T[String] = "com.acme.foo.boundary.web.api"
|
||||
override def modelPackage: T[String] = "com.acme.foo.boundary.web.model"
|
||||
override def generatorName: T[String] = "jaxrs-spec"
|
||||
override def sourceFolder: T[String] = "src/gen/java"
|
||||
|
||||
override def gitSettings: T[Option[GitSettings]] = Some(GitSettings("host", "userid", "repoid"))
|
||||
override def artifactSettings: T[Option[ArtifactSettings]] = Some(ArtifactSettings("groupid", "artifactid", None))
|
||||
|
||||
override def cleanupOutput: T[Boolean] = true
|
||||
|
||||
def additionalProperties: T[Map[String, String]] = Map(
|
||||
"dateLibrary" -> "java8",
|
||||
"useJakartaEe" -> "true",
|
||||
"useSwaggerAnnotations" -> "false",
|
||||
"interfaceOnly" -> "true",
|
||||
"useTags" -> "true",
|
||||
)
|
||||
}
|
||||
|
||||
override def generatedSources: T[Seq[PathRef]] = Seq(
|
||||
PathRef(Task.dest),
|
||||
openapi.generate(),
|
||||
)
|
||||
}
|
||||
333
modules/openapi-generator-mill-plugin/example/mill
Executable file
333
modules/openapi-generator-mill-plugin/example/mill
Executable file
@@ -0,0 +1,333 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# This is a wrapper script, that automatically selects or downloads Mill from Maven Central or GitHub release pages.
|
||||
#
|
||||
# This script determines the Mill version to use by trying these sources
|
||||
# - env-variable `MILL_VERSION`
|
||||
# - local file `.mill-version`
|
||||
# - local file `.config/mill-version`
|
||||
# - `mill-version` from YAML fronmatter of current buildfile
|
||||
# - if accessible, find the latest stable version available on Maven Central (https://repo1.maven.org/maven2)
|
||||
# - env-variable `DEFAULT_MILL_VERSION`
|
||||
#
|
||||
# If a version has the suffix '-native' a native binary will be used.
|
||||
# If a version has the suffix '-jvm' an executable jar file will be used, requiring an already installed Java runtime.
|
||||
# If no such suffix is found, the script will pick a default based on version and platform.
|
||||
#
|
||||
# Once a version was determined, it tries to use either
|
||||
# - a system-installed mill, if found and it's version matches
|
||||
# - an already downloaded version under ~/.cache/mill/download
|
||||
#
|
||||
# If no working mill version was found on the system,
|
||||
# this script downloads a binary file from Maven Central or Github Pages (this is version dependent)
|
||||
# into a cache location (~/.cache/mill/download).
|
||||
#
|
||||
# Mill Project URL: https://github.com/com-lihaoyi/mill
|
||||
# Script Version: 1.0.0-M1-21-7b6fae-DIRTY892b63e8
|
||||
#
|
||||
# If you want to improve this script, please also contribute your changes back!
|
||||
# This script was generated from: dist/scripts/src/mill.sh
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$1" = "--setup-completions" ] ; then
|
||||
# Need to preserve the first position of those listed options
|
||||
MILL_FIRST_ARG=$1
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ -z "${DEFAULT_MILL_VERSION}" ] ; then
|
||||
DEFAULT_MILL_VERSION="0.12.10"
|
||||
fi
|
||||
|
||||
|
||||
if [ -z "${GITHUB_RELEASE_CDN}" ] ; then
|
||||
GITHUB_RELEASE_CDN=""
|
||||
fi
|
||||
|
||||
|
||||
MILL_REPO_URL="https://github.com/com-lihaoyi/mill"
|
||||
|
||||
if [ -z "${CURL_CMD}" ] ; then
|
||||
CURL_CMD=curl
|
||||
fi
|
||||
|
||||
# Explicit commandline argument takes precedence over all other methods
|
||||
if [ "$1" = "--mill-version" ] ; then
|
||||
echo "The --mill-version option is no longer supported." 1>&2
|
||||
fi
|
||||
|
||||
MILL_BUILD_SCRIPT=""
|
||||
|
||||
if [ -f "build.mill" ] ; then
|
||||
MILL_BUILD_SCRIPT="build.mill"
|
||||
elif [ -f "build.mill.scala" ] ; then
|
||||
MILL_BUILD_SCRIPT="build.mill.scala"
|
||||
elif [ -f "build.sc" ] ; then
|
||||
MILL_BUILD_SCRIPT="build.sc"
|
||||
fi
|
||||
|
||||
# Please note, that if a MILL_VERSION is already set in the environment,
|
||||
# We reuse it's value and skip searching for a value.
|
||||
|
||||
# If not already set, read .mill-version file
|
||||
if [ -z "${MILL_VERSION}" ] ; then
|
||||
if [ -f ".mill-version" ] ; then
|
||||
MILL_VERSION="$(tr '\r' '\n' < .mill-version | head -n 1 2> /dev/null)"
|
||||
elif [ -f ".config/mill-version" ] ; then
|
||||
MILL_VERSION="$(tr '\r' '\n' < .config/mill-version | head -n 1 2> /dev/null)"
|
||||
elif [ -n "${MILL_BUILD_SCRIPT}" ] ; then
|
||||
MILL_VERSION="$(cat ${MILL_BUILD_SCRIPT} | grep '//[|] *mill-version: *' | sed 's;//| *mill-version: *;;')"
|
||||
fi
|
||||
fi
|
||||
|
||||
MILL_USER_CACHE_DIR="${XDG_CACHE_HOME:-${HOME}/.cache}/mill"
|
||||
|
||||
if [ -z "${MILL_DOWNLOAD_PATH}" ] ; then
|
||||
MILL_DOWNLOAD_PATH="${MILL_USER_CACHE_DIR}/download"
|
||||
fi
|
||||
|
||||
# If not already set, try to fetch newest from Github
|
||||
if [ -z "${MILL_VERSION}" ] ; then
|
||||
# TODO: try to load latest version from release page
|
||||
echo "No mill version specified." 1>&2
|
||||
echo "You should provide a version via a '//| mill-version: ' comment or a '.mill-version' file." 1>&2
|
||||
|
||||
mkdir -p "${MILL_DOWNLOAD_PATH}"
|
||||
LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" 2>/dev/null || (
|
||||
# we might be on OSX or BSD which don't have -d option for touch
|
||||
# but probably a -A [-][[hh]mm]SS
|
||||
touch "${MILL_DOWNLOAD_PATH}/.expire_latest"; touch -A -010000 "${MILL_DOWNLOAD_PATH}/.expire_latest"
|
||||
) || (
|
||||
# in case we still failed, we retry the first touch command with the intention
|
||||
# to show the (previously suppressed) error message
|
||||
LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest"
|
||||
)
|
||||
|
||||
# POSIX shell variant of bash's -nt operator, see https://unix.stackexchange.com/a/449744/6993
|
||||
# if [ "${MILL_DOWNLOAD_PATH}/.latest" -nt "${MILL_DOWNLOAD_PATH}/.expire_latest" ] ; then
|
||||
if [ -n "$(find -L "${MILL_DOWNLOAD_PATH}/.latest" -prune -newer "${MILL_DOWNLOAD_PATH}/.expire_latest")" ]; then
|
||||
# we know a current latest version
|
||||
MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null)
|
||||
fi
|
||||
|
||||
if [ -z "${MILL_VERSION}" ] ; then
|
||||
# we don't know a current latest version
|
||||
echo "Retrieving latest mill version ..." 1>&2
|
||||
LANG=C ${CURL_CMD} -s -i -f -I ${MILL_REPO_URL}/releases/latest 2> /dev/null | grep --ignore-case Location: | sed s'/^.*tag\///' | tr -d '\r\n' > "${MILL_DOWNLOAD_PATH}/.latest"
|
||||
MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null)
|
||||
fi
|
||||
|
||||
if [ -z "${MILL_VERSION}" ] ; then
|
||||
# Last resort
|
||||
MILL_VERSION="${DEFAULT_MILL_VERSION}"
|
||||
echo "Falling back to hardcoded mill version ${MILL_VERSION}" 1>&2
|
||||
else
|
||||
echo "Using mill version ${MILL_VERSION}" 1>&2
|
||||
fi
|
||||
fi
|
||||
|
||||
MILL_NATIVE_SUFFIX="-native"
|
||||
MILL_JVM_SUFFIX="-jvm"
|
||||
FULL_MILL_VERSION=$MILL_VERSION
|
||||
ARTIFACT_SUFFIX=""
|
||||
set_artifact_suffix(){
|
||||
if [ "$(expr substr $(uname -s) 1 5 2>/dev/null)" = "Linux" ]; then
|
||||
if [ "$(uname -m)" = "aarch64" ]; then
|
||||
ARTIFACT_SUFFIX="-native-linux-aarch64"
|
||||
else
|
||||
ARTIFACT_SUFFIX="-native-linux-amd64"
|
||||
fi
|
||||
elif [ "$(uname)" = "Darwin" ]; then
|
||||
if [ "$(uname -m)" = "arm64" ]; then
|
||||
ARTIFACT_SUFFIX="-native-mac-aarch64"
|
||||
else
|
||||
ARTIFACT_SUFFIX="-native-mac-amd64"
|
||||
fi
|
||||
else
|
||||
echo "This native mill launcher supports only Linux and macOS." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
case "$MILL_VERSION" in
|
||||
*"$MILL_NATIVE_SUFFIX")
|
||||
MILL_VERSION=${MILL_VERSION%"$MILL_NATIVE_SUFFIX"}
|
||||
set_artifact_suffix
|
||||
;;
|
||||
|
||||
*"$MILL_JVM_SUFFIX")
|
||||
MILL_VERSION=${MILL_VERSION%"$MILL_JVM_SUFFIX"}
|
||||
;;
|
||||
|
||||
*)
|
||||
case "$MILL_VERSION" in
|
||||
0.1.*) ;;
|
||||
0.2.*) ;;
|
||||
0.3.*) ;;
|
||||
0.4.*) ;;
|
||||
0.5.*) ;;
|
||||
0.6.*) ;;
|
||||
0.7.*) ;;
|
||||
0.8.*) ;;
|
||||
0.9.*) ;;
|
||||
0.10.*) ;;
|
||||
0.11.*) ;;
|
||||
0.12.*) ;;
|
||||
*)
|
||||
set_artifact_suffix
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
MILL="${MILL_DOWNLOAD_PATH}/$MILL_VERSION$ARTIFACT_SUFFIX"
|
||||
|
||||
try_to_use_system_mill() {
|
||||
if [ "$(uname)" != "Linux" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
MILL_IN_PATH="$(command -v mill || true)"
|
||||
|
||||
if [ -z "${MILL_IN_PATH}" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
SYSTEM_MILL_FIRST_TWO_BYTES=$(head --bytes=2 "${MILL_IN_PATH}")
|
||||
if [ "${SYSTEM_MILL_FIRST_TWO_BYTES}" = "#!" ]; then
|
||||
# MILL_IN_PATH is (very likely) a shell script and not the mill
|
||||
# executable, ignore it.
|
||||
return 0
|
||||
fi
|
||||
|
||||
SYSTEM_MILL_PATH=$(readlink -e "${MILL_IN_PATH}")
|
||||
SYSTEM_MILL_SIZE=$(stat --format=%s "${SYSTEM_MILL_PATH}")
|
||||
SYSTEM_MILL_MTIME=$(stat --format=%y "${SYSTEM_MILL_PATH}")
|
||||
|
||||
if [ ! -d "${MILL_USER_CACHE_DIR}" ]; then
|
||||
mkdir -p "${MILL_USER_CACHE_DIR}"
|
||||
fi
|
||||
|
||||
SYSTEM_MILL_INFO_FILE="${MILL_USER_CACHE_DIR}/system-mill-info"
|
||||
if [ -f "${SYSTEM_MILL_INFO_FILE}" ]; then
|
||||
parseSystemMillInfo() {
|
||||
LINE_NUMBER="${1}"
|
||||
# Select the line number of the SYSTEM_MILL_INFO_FILE, cut the
|
||||
# variable definition in that line in two halves and return
|
||||
# the value, and finally remove the quotes.
|
||||
sed -n "${LINE_NUMBER}p" "${SYSTEM_MILL_INFO_FILE}" |\
|
||||
cut -d= -f2 |\
|
||||
sed 's/"\(.*\)"/\1/'
|
||||
}
|
||||
|
||||
CACHED_SYSTEM_MILL_PATH=$(parseSystemMillInfo 1)
|
||||
CACHED_SYSTEM_MILL_VERSION=$(parseSystemMillInfo 2)
|
||||
CACHED_SYSTEM_MILL_SIZE=$(parseSystemMillInfo 3)
|
||||
CACHED_SYSTEM_MILL_MTIME=$(parseSystemMillInfo 4)
|
||||
|
||||
if [ "${SYSTEM_MILL_PATH}" = "${CACHED_SYSTEM_MILL_PATH}" ] \
|
||||
&& [ "${SYSTEM_MILL_SIZE}" = "${CACHED_SYSTEM_MILL_SIZE}" ] \
|
||||
&& [ "${SYSTEM_MILL_MTIME}" = "${CACHED_SYSTEM_MILL_MTIME}" ]; then
|
||||
if [ "${CACHED_SYSTEM_MILL_VERSION}" = "${MILL_VERSION}" ]; then
|
||||
MILL="${SYSTEM_MILL_PATH}"
|
||||
return 0
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
SYSTEM_MILL_VERSION=$(${SYSTEM_MILL_PATH} --version | head -n1 | sed -n 's/^Mill.*version \(.*\)/\1/p')
|
||||
|
||||
cat <<EOF > "${SYSTEM_MILL_INFO_FILE}"
|
||||
CACHED_SYSTEM_MILL_PATH="${SYSTEM_MILL_PATH}"
|
||||
CACHED_SYSTEM_MILL_VERSION="${SYSTEM_MILL_VERSION}"
|
||||
CACHED_SYSTEM_MILL_SIZE="${SYSTEM_MILL_SIZE}"
|
||||
CACHED_SYSTEM_MILL_MTIME="${SYSTEM_MILL_MTIME}"
|
||||
EOF
|
||||
|
||||
if [ "${SYSTEM_MILL_VERSION}" = "${MILL_VERSION}" ]; then
|
||||
MILL="${SYSTEM_MILL_PATH}"
|
||||
fi
|
||||
}
|
||||
try_to_use_system_mill
|
||||
|
||||
# If not already downloaded, download it
|
||||
if [ ! -s "${MILL}" ] || [ "$MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT" = "1" ] ; then
|
||||
case $MILL_VERSION in
|
||||
0.0.* | 0.1.* | 0.2.* | 0.3.* | 0.4.* )
|
||||
DOWNLOAD_SUFFIX=""
|
||||
DOWNLOAD_FROM_MAVEN=0
|
||||
;;
|
||||
0.5.* | 0.6.* | 0.7.* | 0.8.* | 0.9.* | 0.10.* | 0.11.0-M* )
|
||||
DOWNLOAD_SUFFIX="-assembly"
|
||||
DOWNLOAD_FROM_MAVEN=0
|
||||
;;
|
||||
*)
|
||||
DOWNLOAD_SUFFIX="-assembly"
|
||||
DOWNLOAD_FROM_MAVEN=1
|
||||
;;
|
||||
esac
|
||||
case $MILL_VERSION in
|
||||
0.12.0 | 0.12.1 | 0.12.2 | 0.12.3 | 0.12.4 | 0.12.5 | 0.12.6 | 0.12.7 | 0.12.8 | 0.12.9 | 0.12.10 | 0.12.11 )
|
||||
DOWNLOAD_EXT="jar"
|
||||
;;
|
||||
0.12.* )
|
||||
DOWNLOAD_EXT="exe"
|
||||
;;
|
||||
0.* )
|
||||
DOWNLOAD_EXT="jar"
|
||||
;;
|
||||
*)
|
||||
DOWNLOAD_EXT="exe"
|
||||
;;
|
||||
esac
|
||||
|
||||
DOWNLOAD_FILE=$(mktemp mill.XXXXXX)
|
||||
if [ "$DOWNLOAD_FROM_MAVEN" = "1" ] ; then
|
||||
DOWNLOAD_URL="https://repo1.maven.org/maven2/com/lihaoyi/mill-dist${ARTIFACT_SUFFIX}/${MILL_VERSION}/mill-dist${ARTIFACT_SUFFIX}-${MILL_VERSION}.${DOWNLOAD_EXT}"
|
||||
else
|
||||
MILL_VERSION_TAG=$(echo "$MILL_VERSION" | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/')
|
||||
DOWNLOAD_URL="${GITHUB_RELEASE_CDN}${MILL_REPO_URL}/releases/download/${MILL_VERSION_TAG}/${MILL_VERSION}${DOWNLOAD_SUFFIX}"
|
||||
unset MILL_VERSION_TAG
|
||||
fi
|
||||
|
||||
if [ "$MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT" = "1" ] ; then
|
||||
echo $DOWNLOAD_URL
|
||||
echo $MILL
|
||||
exit 0
|
||||
fi
|
||||
# TODO: handle command not found
|
||||
echo "Downloading mill ${MILL_VERSION} from ${DOWNLOAD_URL} ..." 1>&2
|
||||
${CURL_CMD} -f -L -o "${DOWNLOAD_FILE}" "${DOWNLOAD_URL}"
|
||||
chmod +x "${DOWNLOAD_FILE}"
|
||||
mkdir -p "${MILL_DOWNLOAD_PATH}"
|
||||
mv "${DOWNLOAD_FILE}" "${MILL}"
|
||||
|
||||
unset DOWNLOAD_FILE
|
||||
unset DOWNLOAD_SUFFIX
|
||||
fi
|
||||
|
||||
if [ -z "$MILL_MAIN_CLI" ] ; then
|
||||
MILL_MAIN_CLI="${0}"
|
||||
fi
|
||||
|
||||
MILL_FIRST_ARG=""
|
||||
if [ "$1" = "--bsp" ] || [ "${1#"-i"}" != "$1" ] || [ "$1" = "--interactive" ] || [ "$1" = "--no-server" ] || [ "$1" = "--no-daemon" ] || [ "$1" = "--repl" ] || [ "$1" = "--help" ] ; then
|
||||
# Need to preserve the first position of those listed options
|
||||
MILL_FIRST_ARG=$1
|
||||
shift
|
||||
fi
|
||||
|
||||
unset MILL_DOWNLOAD_PATH
|
||||
unset MILL_OLD_DOWNLOAD_PATH
|
||||
unset OLD_MILL
|
||||
unset MILL_VERSION
|
||||
unset MILL_REPO_URL
|
||||
|
||||
# -D mill.main.cli is for compatibility with Mill 0.10.9 - 0.13.0-M2
|
||||
# We don't quote MILL_FIRST_ARG on purpose, so we can expand the empty value without quotes
|
||||
# shellcheck disable=SC2086
|
||||
exec "${MILL}" $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@"
|
||||
@@ -0,0 +1,36 @@
|
||||
|
||||
import coursier.LocalRepositories.Dangerous
|
||||
import coursier.Repositories
|
||||
import mill.scalalib.DepSyntax
|
||||
import mill.*
|
||||
import mill.api.Task
|
||||
import mill.meta.MillBuildRootModule
|
||||
import java.util.Properties
|
||||
import java.io.FileInputStream
|
||||
import scala.util.Using
|
||||
|
||||
object `package` extends MillBuildRootModule {
|
||||
|
||||
override def repositories = Task {
|
||||
Seq(
|
||||
// central needed for default deps
|
||||
Repositories.central.root,
|
||||
// the previously installed snapshot is in local maven
|
||||
// see docs on Coursier, why m2 is considered dangerous
|
||||
Dangerous.maven2Local.root)
|
||||
}
|
||||
|
||||
def propsFile = Task.Source("version.properties")
|
||||
|
||||
def readOpenapiSnapshotVersion: Task[String] = Task {
|
||||
val props = new Properties()
|
||||
Using(new FileInputStream(propsFile().path.toIO)) { fis =>
|
||||
props.load(fis)
|
||||
props.getProperty("openApiGeneratorVersion")
|
||||
}.get
|
||||
}
|
||||
|
||||
override def mvnDeps = Seq(
|
||||
mvn"org.openapitools:openapi-generator-mill-plugin:${readOpenapiSnapshotVersion()}"
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# RELEASE_VERSION
|
||||
openApiGeneratorVersion=7.19.0-SNAPSHOT
|
||||
# /RELEASE_VERSION
|
||||
299
modules/openapi-generator-mill-plugin/example/mill.bat
Normal file
299
modules/openapi-generator-mill-plugin/example/mill.bat
Normal file
@@ -0,0 +1,299 @@
|
||||
@echo off
|
||||
|
||||
rem This is a wrapper script, that automatically selects or downloads Mill from Maven Central or GitHub release pages.
|
||||
rem
|
||||
rem This script determines the Mill version to use by trying these sources
|
||||
rem - env-variable `MILL_VERSION`
|
||||
rem - local file `.mill-version`
|
||||
rem - local file `.config/mill-version`
|
||||
rem - `mill-version` from YAML fronmatter of current buildfile
|
||||
rem - if accessible, find the latest stable version available on Maven Central (https://repo1.maven.org/maven2)
|
||||
rem - env-variable `DEFAULT_MILL_VERSION`
|
||||
rem
|
||||
rem If a version has the suffix '-native' a native binary will be used.
|
||||
rem If a version has the suffix '-jvm' an executable jar file will be used, requiring an already installed Java runtime.
|
||||
rem If no such suffix is found, the script will pick a default based on version and platform.
|
||||
rem
|
||||
rem Once a version was determined, it tries to use either
|
||||
rem - a system-installed mill, if found and it's version matches
|
||||
rem - an already downloaded version under %USERPROFILE%\.mill\download
|
||||
rem
|
||||
rem If no working mill version was found on the system,
|
||||
rem this script downloads a binary file from Maven Central or Github Pages (this is version dependent)
|
||||
rem into a cache location (%USERPROFILE%\.mill\download).
|
||||
rem
|
||||
rem Mill Project URL: https://github.com/com-lihaoyi/mill
|
||||
rem Script Version: 1.0.0-M1-21-7b6fae-DIRTY892b63e8
|
||||
rem
|
||||
rem If you want to improve this script, please also contribute your changes back!
|
||||
rem This script was generated from: dist/scripts/src/mill.bat
|
||||
rem
|
||||
rem Licensed under the Apache License, Version 2.0
|
||||
|
||||
rem setlocal seems to be unavailable on Windows 95/98/ME
|
||||
rem but I don't think we need to support them in 2019
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
if [!DEFAULT_MILL_VERSION!]==[] ( set "DEFAULT_MILL_VERSION=0.12.10" )
|
||||
|
||||
if [!MILL_GITHUB_RELEASE_CDN!]==[] ( set "MILL_GITHUB_RELEASE_CDN=" )
|
||||
|
||||
if [!MILL_MAIN_CLI!]==[] ( set "MILL_MAIN_CLI=%~f0" )
|
||||
|
||||
set "MILL_REPO_URL=https://github.com/com-lihaoyi/mill"
|
||||
|
||||
SET MILL_BUILD_SCRIPT=
|
||||
|
||||
if exist "build.mill" (
|
||||
set MILL_BUILD_SCRIPT=build.mill
|
||||
) else (
|
||||
if exist "build.mill.scala" (
|
||||
set MILL_BUILD_SCRIPT=build.mill.scala
|
||||
) else (
|
||||
if exist "build.sc" (
|
||||
set MILL_BUILD_SCRIPT=build.sc
|
||||
) else (
|
||||
rem no-op
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if [!MILL_VERSION!]==[] (
|
||||
if exist .mill-version (
|
||||
set /p MILL_VERSION=<.mill-version
|
||||
) else (
|
||||
if exist .config\mill-version (
|
||||
set /p MILL_VERSION=<.config\mill-version
|
||||
) else (
|
||||
if not "%MILL_BUILD_SCRIPT%"=="" (
|
||||
for /f "tokens=1-2*" %%a in ('findstr /C:"//| mill-version:" %MILL_BUILD_SCRIPT%') do (
|
||||
set "MILL_VERSION=%%c"
|
||||
)
|
||||
) else (
|
||||
rem no-op
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if [!MILL_VERSION!]==[] set MILL_VERSION=%DEFAULT_MILL_VERSION%
|
||||
|
||||
if [!MILL_DOWNLOAD_PATH!]==[] set MILL_DOWNLOAD_PATH=%USERPROFILE%\.mill\download
|
||||
|
||||
rem without bat file extension, cmd doesn't seem to be able to run it
|
||||
|
||||
set "MILL_NATIVE_SUFFIX=-native"
|
||||
set "MILL_JVM_SUFFIX=-jvm"
|
||||
set "FULL_MILL_VERSION=%MILL_VERSION%"
|
||||
set "MILL_EXT=.bat"
|
||||
set "ARTIFACT_SUFFIX="
|
||||
REM Check if MILL_VERSION contains MILL_NATIVE_SUFFIX
|
||||
echo !MILL_VERSION! | findstr /C:"%MILL_NATIVE_SUFFIX%" >nul
|
||||
if !errorlevel! equ 0 (
|
||||
set "MILL_VERSION=%MILL_VERSION:-native=%"
|
||||
REM -native images compiled with graal do not support windows-arm
|
||||
REM https://github.com/oracle/graal/issues/9215
|
||||
IF /I NOT "%PROCESSOR_ARCHITECTURE%"=="ARM64" (
|
||||
set "ARTIFACT_SUFFIX=-native-windows-amd64"
|
||||
set "MILL_EXT=.exe"
|
||||
) else (
|
||||
rem no-op
|
||||
)
|
||||
) else (
|
||||
echo !MILL_VERSION! | findstr /C:"%MILL_JVM_SUFFIX%" >nul
|
||||
if !errorlevel! equ 0 (
|
||||
set "MILL_VERSION=%MILL_VERSION:-jvm=%"
|
||||
) else (
|
||||
set "SKIP_VERSION=false"
|
||||
set "MILL_PREFIX=%MILL_VERSION:~0,4%"
|
||||
if "!MILL_PREFIX!"=="0.1." set "SKIP_VERSION=true"
|
||||
if "!MILL_PREFIX!"=="0.2." set "SKIP_VERSION=true"
|
||||
if "!MILL_PREFIX!"=="0.3." set "SKIP_VERSION=true"
|
||||
if "!MILL_PREFIX!"=="0.4." set "SKIP_VERSION=true"
|
||||
if "!MILL_PREFIX!"=="0.5." set "SKIP_VERSION=true"
|
||||
if "!MILL_PREFIX!"=="0.6." set "SKIP_VERSION=true"
|
||||
if "!MILL_PREFIX!"=="0.7." set "SKIP_VERSION=true"
|
||||
if "!MILL_PREFIX!"=="0.8." set "SKIP_VERSION=true"
|
||||
if "!MILL_PREFIX!"=="0.9." set "SKIP_VERSION=true"
|
||||
set "MILL_PREFIX=%MILL_VERSION:~0,5%"
|
||||
if "!MILL_PREFIX!"=="0.10." set "SKIP_VERSION=true"
|
||||
if "!MILL_PREFIX!"=="0.11." set "SKIP_VERSION=true"
|
||||
if "!MILL_PREFIX!"=="0.12." set "SKIP_VERSION=true"
|
||||
|
||||
if "!SKIP_VERSION!"=="false" (
|
||||
IF /I NOT "%PROCESSOR_ARCHITECTURE%"=="ARM64" (
|
||||
set "ARTIFACT_SUFFIX=-native-windows-amd64"
|
||||
set "MILL_EXT=.exe"
|
||||
)
|
||||
) else (
|
||||
rem no-op
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
set MILL=%MILL_DOWNLOAD_PATH%\!FULL_MILL_VERSION!!MILL_EXT!
|
||||
|
||||
set MILL_RESOLVE_DOWNLOAD=
|
||||
|
||||
if not exist "%MILL%" (
|
||||
set MILL_RESOLVE_DOWNLOAD=true
|
||||
) else (
|
||||
if defined MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT (
|
||||
set MILL_RESOLVE_DOWNLOAD=true
|
||||
) else (
|
||||
rem no-op
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if [!MILL_RESOLVE_DOWNLOAD!]==[true] (
|
||||
set MILL_VERSION_PREFIX=%MILL_VERSION:~0,4%
|
||||
set MILL_SHORT_VERSION_PREFIX=%MILL_VERSION:~0,2%
|
||||
rem Since 0.5.0
|
||||
set MILL_DOWNLOAD_SUFFIX=-assembly
|
||||
rem Since 0.11.0
|
||||
set MILL_DOWNLOAD_FROM_MAVEN=1
|
||||
if [!MILL_VERSION_PREFIX!]==[0.0.] (
|
||||
set MILL_DOWNLOAD_SUFFIX=
|
||||
set MILL_DOWNLOAD_FROM_MAVEN=0
|
||||
)
|
||||
if [!MILL_VERSION_PREFIX!]==[0.1.] (
|
||||
set MILL_DOWNLOAD_SUFFIX=
|
||||
set MILL_DOWNLOAD_FROM_MAVEN=0
|
||||
)
|
||||
if [!MILL_VERSION_PREFIX!]==[0.2.] (
|
||||
set MILL_DOWNLOAD_SUFFIX=
|
||||
set MILL_DOWNLOAD_FROM_MAVEN=0
|
||||
)
|
||||
if [!MILL_VERSION_PREFIX!]==[0.3.] (
|
||||
set MILL_DOWNLOAD_SUFFIX=
|
||||
set MILL_DOWNLOAD_FROM_MAVEN=0
|
||||
)
|
||||
if [!MILL_VERSION_PREFIX!]==[0.4.] (
|
||||
set MILL_DOWNLOAD_SUFFIX=
|
||||
set MILL_DOWNLOAD_FROM_MAVEN=0
|
||||
)
|
||||
if [!MILL_VERSION_PREFIX!]==[0.5.] set MILL_DOWNLOAD_FROM_MAVEN=0
|
||||
if [!MILL_VERSION_PREFIX!]==[0.6.] set MILL_DOWNLOAD_FROM_MAVEN=0
|
||||
if [!MILL_VERSION_PREFIX!]==[0.7.] set MILL_DOWNLOAD_FROM_MAVEN=0
|
||||
if [!MILL_VERSION_PREFIX!]==[0.8.] set MILL_DOWNLOAD_FROM_MAVEN=0
|
||||
if [!MILL_VERSION_PREFIX!]==[0.9.] set MILL_DOWNLOAD_FROM_MAVEN=0
|
||||
|
||||
set MILL_VERSION_PREFIX=%MILL_VERSION:~0,5%
|
||||
if [!MILL_VERSION_PREFIX!]==[0.10.] set MILL_DOWNLOAD_FROM_MAVEN=0
|
||||
|
||||
set MILL_VERSION_PREFIX=%MILL_VERSION:~0,8%
|
||||
if [!MILL_VERSION_PREFIX!]==[0.11.0-M] set MILL_DOWNLOAD_FROM_MAVEN=0
|
||||
|
||||
set MILL_VERSION_PREFIX=%MILL_VERSION:~0,5%
|
||||
set DOWNLOAD_EXT=exe
|
||||
if [!MILL_SHORT_VERSION_PREFIX!]==[0.] set DOWNLOAD_EXT=jar
|
||||
if [!MILL_VERSION_PREFIX!]==[0.12.] set DOWNLOAD_EXT=exe
|
||||
if [!MILL_VERSION!]==[0.12.0] set DOWNLOAD_EXT=jar
|
||||
if [!MILL_VERSION!]==[0.12.1] set DOWNLOAD_EXT=jar
|
||||
if [!MILL_VERSION!]==[0.12.2] set DOWNLOAD_EXT=jar
|
||||
if [!MILL_VERSION!]==[0.12.3] set DOWNLOAD_EXT=jar
|
||||
if [!MILL_VERSION!]==[0.12.4] set DOWNLOAD_EXT=jar
|
||||
if [!MILL_VERSION!]==[0.12.5] set DOWNLOAD_EXT=jar
|
||||
if [!MILL_VERSION!]==[0.12.6] set DOWNLOAD_EXT=jar
|
||||
if [!MILL_VERSION!]==[0.12.7] set DOWNLOAD_EXT=jar
|
||||
if [!MILL_VERSION!]==[0.12.8] set DOWNLOAD_EXT=jar
|
||||
if [!MILL_VERSION!]==[0.12.9] set DOWNLOAD_EXT=jar
|
||||
if [!MILL_VERSION!]==[0.12.10] set DOWNLOAD_EXT=jar
|
||||
if [!MILL_VERSION!]==[0.12.11] set DOWNLOAD_EXT=jar
|
||||
|
||||
set MILL_VERSION_PREFIX=
|
||||
set MILL_SHORT_VERSION_PREFIX=
|
||||
|
||||
for /F "delims=- tokens=1" %%A in ("!MILL_VERSION!") do set MILL_VERSION_BASE=%%A
|
||||
set MILL_VERSION_MILESTONE=
|
||||
for /F "delims=- tokens=2" %%A in ("!MILL_VERSION!") do set MILL_VERSION_MILESTONE=%%A
|
||||
set MILL_VERSION_MILESTONE_START=!MILL_VERSION_MILESTONE:~0,1!
|
||||
if [!MILL_VERSION_MILESTONE_START!]==[M] (
|
||||
set MILL_VERSION_TAG=!MILL_VERSION_BASE!-!MILL_VERSION_MILESTONE!
|
||||
) else (
|
||||
set MILL_VERSION_TAG=!MILL_VERSION_BASE!
|
||||
)
|
||||
if [!MILL_DOWNLOAD_FROM_MAVEN!]==[1] (
|
||||
set MILL_DOWNLOAD_URL=https://repo1.maven.org/maven2/com/lihaoyi/mill-dist!ARTIFACT_SUFFIX!/!MILL_VERSION!/mill-dist!ARTIFACT_SUFFIX!-!MILL_VERSION!.!DOWNLOAD_EXT!
|
||||
) else (
|
||||
set MILL_DOWNLOAD_URL=!MILL_GITHUB_RELEASE_CDN!%MILL_REPO_URL%/releases/download/!MILL_VERSION_TAG!/!MILL_VERSION!!MILL_DOWNLOAD_SUFFIX!
|
||||
)
|
||||
|
||||
if defined MILL_TEST_DRY_RUN_LAUNCHER_SCRIPT (
|
||||
echo !MILL_DOWNLOAD_URL!
|
||||
echo !MILL!
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
rem there seems to be no way to generate a unique temporary file path (on native Windows)
|
||||
set MILL_DOWNLOAD_FILE=%MILL%.tmp
|
||||
|
||||
echo Downloading mill !MILL_VERSION! from !MILL_DOWNLOAD_URL! ... 1>&2
|
||||
|
||||
if not exist "%MILL_DOWNLOAD_PATH%" mkdir "%MILL_DOWNLOAD_PATH%"
|
||||
rem curl is bundled with recent Windows 10
|
||||
rem but I don't think we can expect all the users to have it in 2019
|
||||
where /Q curl
|
||||
if !ERRORLEVEL! EQU 0 (
|
||||
curl -f -L "!MILL_DOWNLOAD_URL!" -o "!MILL_DOWNLOAD_FILE!"
|
||||
) else (
|
||||
rem bitsadmin seems to be available on Windows 7
|
||||
rem without /dynamic, github returns 403
|
||||
rem bitsadmin is sometimes needlessly slow but it looks better with /priority foreground
|
||||
bitsadmin /transfer millDownloadJob /dynamic /priority foreground "!MILL_DOWNLOAD_URL!" "!MILL_DOWNLOAD_FILE!"
|
||||
)
|
||||
if not exist "!MILL_DOWNLOAD_FILE!" (
|
||||
echo Could not download mill !MILL_VERSION! 1>&2
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
move /y "!MILL_DOWNLOAD_FILE!" "%MILL%"
|
||||
|
||||
set MILL_DOWNLOAD_FILE=
|
||||
set MILL_DOWNLOAD_SUFFIX=
|
||||
)
|
||||
|
||||
set MILL_DOWNLOAD_PATH=
|
||||
set MILL_VERSION=
|
||||
set MILL_REPO_URL=
|
||||
|
||||
rem Need to preserve the first position of those listed options
|
||||
set MILL_FIRST_ARG=
|
||||
if [%~1%]==[--bsp] (
|
||||
set MILL_FIRST_ARG=%1%
|
||||
) else (
|
||||
if [%~1%]==[-i] (
|
||||
set MILL_FIRST_ARG=%1%
|
||||
) else (
|
||||
if [%~1%]==[--interactive] (
|
||||
set MILL_FIRST_ARG=%1%
|
||||
) else (
|
||||
if [%~1%]==[--no-server] (
|
||||
set MILL_FIRST_ARG=%1%
|
||||
) else (
|
||||
if [%~1%]==[--no-daemon] (
|
||||
set MILL_FIRST_ARG=%1%
|
||||
) else (
|
||||
if [%~1%]==[--repl] (
|
||||
set MILL_FIRST_ARG=%1%
|
||||
) else (
|
||||
if [%~1%]==[--help] (
|
||||
set MILL_FIRST_ARG=%1%
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
set "MILL_PARAMS=%*%"
|
||||
|
||||
if not [!MILL_FIRST_ARG!]==[] (
|
||||
for /f "tokens=1*" %%a in ("%*") do (
|
||||
set "MILL_PARAMS=%%b"
|
||||
)
|
||||
)
|
||||
|
||||
rem -D mill.main.cli is for compatibility with Mill 0.10.9 - 0.13.0-M2
|
||||
"%MILL%" %MILL_FIRST_ARG% -D "mill.main.cli=%MILL_MAIN_CLI%" %MILL_PARAMS%
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.acme.foo.boundary.web;
|
||||
|
||||
import com.acme.foo.boundary.web.api.PetApi;
|
||||
import com.acme.foo.boundary.web.model.ModelApiResponse;
|
||||
import com.acme.foo.boundary.web.model.Pet;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
@RequestScoped
|
||||
public class TestController implements PetApi {
|
||||
@Override
|
||||
public Pet addPet(Pet pet) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePet(Long petId, String apiKey) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Pet> findPetsByStatus(List<String> status) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Pet> findPetsByTags(List<String> tags) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pet getPetById(Long petId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pet updatePet(Pet pet) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePetWithForm(Long petId, String name, String status) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelApiResponse uploadFile(Long petId, String additionalMetadata, InputStream _fileInputStream) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
180
modules/openapi-generator-mill-plugin/pom.xml
Normal file
180
modules/openapi-generator-mill-plugin/pom.xml
Normal file
@@ -0,0 +1,180 @@
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.openapitools</groupId>
|
||||
<artifactId>openapi-generator-project</artifactId>
|
||||
<!-- RELEASE_VERSION -->
|
||||
<version>7.19.0-SNAPSHOT</version>
|
||||
<!-- /RELEASE_VERSION -->
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>openapi-generator-mill-plugin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>openapi-generator-mill-plugin</name>
|
||||
<description>Mill module to build modules from OpenAPI Generator</description>
|
||||
|
||||
|
||||
<repositories>
|
||||
<!-- enable central, to find Scala and Mill deps -->
|
||||
<repository>
|
||||
<id>central</id>
|
||||
<name>Central Repository OSSRH</name>
|
||||
<url>https://repo1.maven.org/maven2/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<properties>
|
||||
<scala-plugin.version>4.9.5</scala-plugin.version>
|
||||
<scala.version>3.7.4</scala.version>
|
||||
<mill.version>1.0.6</mill.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.scala-lang</groupId>
|
||||
<artifactId>scala3-library_3</artifactId>
|
||||
<version>${scala.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lihaoyi</groupId>
|
||||
<artifactId>mill-libs_3</artifactId>
|
||||
<version>${mill.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openapitools</groupId>
|
||||
<artifactId>openapi-generator</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lihaoyi</groupId>
|
||||
<artifactId>mill-testkit_3</artifactId>
|
||||
<version>${mill.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- using ScalaTest as it integrates best with TestNG -->
|
||||
<dependency>
|
||||
<groupId>org.scalatest</groupId>
|
||||
<artifactId>scalatest_3</artifactId>
|
||||
<version>3.2.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.scalatestplus</groupId>
|
||||
<artifactId>testng-7-10_3</artifactId>
|
||||
<version>3.2.19.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- The following dependencies are needed to run Mill in a Unit-Test -->
|
||||
<dependency>
|
||||
<groupId>org.virtuslab.scala-cli</groupId>
|
||||
<artifactId>config_3</artifactId>
|
||||
<version>1.11.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.alexarchambault</groupId>
|
||||
<artifactId>concurrent-reference-hash-map</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src/main/scala</sourceDirectory>
|
||||
<testSourceDirectory>src/test/scala</testSourceDirectory>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<configuration>
|
||||
<configLocation>${project.parent.basedir}${file.separator}google_checkstyle.xml</configLocation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-scala-sources</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>src/main/scala</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>add-scala-test-sources</id>
|
||||
<phase>generate-test-sources</phase>
|
||||
<goals>
|
||||
<goal>add-test-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>src/test/java</source>
|
||||
<source>src/test/scala</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>net.alchim31.maven</groupId>
|
||||
<artifactId>scala-maven-plugin</artifactId>
|
||||
<version>${scala-plugin.version}</version>
|
||||
<configuration>
|
||||
<scalaVersion>${scala.version}</scalaVersion>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<environmentVariables>
|
||||
<MILL_TEST_RESOURCE_DIR>${project.basedir}/src/test/resources</MILL_TEST_RESOURCE_DIR>
|
||||
</environmentVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>static-analysis</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludeFilterFile>${project.parent.basedir}${file.separator}spotbugs-exclude.xml</excludeFilterFile>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>se.bjurr.violations</groupId>
|
||||
<artifactId>violations-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -0,0 +1,624 @@
|
||||
/*
|
||||
* Original code copied from https://github.com/mikybars/openapi-generator-mill-plugin
|
||||
* Original code published under the MIT License
|
||||
* Original Copyright Miguel Ibars
|
||||
*/
|
||||
package org.openapitools.generator.mill
|
||||
|
||||
import io.swagger.parser.OpenAPIParser
|
||||
import io.swagger.v3.parser.core.models.ParseOptions
|
||||
import mainargs.arg
|
||||
import mill.T
|
||||
import mill.api.{PathRef, Result, Task}
|
||||
import org.openapitools.codegen.CodegenConstants
|
||||
import org.openapitools.codegen.DefaultGenerator
|
||||
import org.openapitools.codegen.config.CodegenConfigurator
|
||||
import org.openapitools.codegen.config.GlobalSettings
|
||||
import org.openapitools.codegen.validations.oas.{OpenApiEvaluator, RuleConfiguration}
|
||||
import os.{Path, RelPath}
|
||||
import upickle.ReadWriter as RW
|
||||
|
||||
import scala.jdk.CollectionConverters.*
|
||||
import scala.jdk.javaapi.CollectionConverters
|
||||
|
||||
/**
|
||||
* Usage:
|
||||
* {{{
|
||||
* object myModule extends JavaModule with OpenApiModule {
|
||||
*
|
||||
* object openApiServer extends OpenApiConfig {
|
||||
* def inputSpec: T[PathRef] = Task.Source(BuildCtx.workspaceRoot / "api" / "server-api.yaml")
|
||||
* def apiPackage: T[String] = "com.acme.foo.boundary.web.api"
|
||||
* def modelPackage: T[String] = "com.acme.foo.boundary.web.model"
|
||||
* def generatorName: T[String] = "spring"
|
||||
* def sourceFolder: T[String] = "src/main/java"
|
||||
* def additionalProperties: T[Map[String, String]] = Map(
|
||||
* "useSpringBoot3" -> "true",
|
||||
* "dateLibrary" -> "java8",
|
||||
* "interfaceOnly" -> "true",
|
||||
* "performBeanValidation" -> "true",
|
||||
* "useBeanValidation" -> "false",
|
||||
* "skipDefaultInterface" -> "true",
|
||||
* "useTags" -> "true",
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* object openApiClient extends OpenApiConfig {
|
||||
* def inputSpec = T[PathRef] = Task.Source(BuildCtx.workspaceRoot / "api" / "some-client-api.yaml")
|
||||
* def apiPackage: T[String] = "com.acme.foo.boundary.client.some.api"
|
||||
* def modelPackage: T[String] = "com.acme.foo.boundary.client.some.model"
|
||||
* def generatorName: T[String] = "java"
|
||||
* def modelNameSuffix: T[String] = "Dto"
|
||||
* def sourceFolder: T[String] = "src/main/java"
|
||||
* def additionalProperties: T[Map[String, String]] = Map(
|
||||
* "useTags" -> "true",
|
||||
* "dateLibrary" -> "java8",
|
||||
* "library" -> "webclient",
|
||||
* "useJakartaEe" -> "true",
|
||||
* "useOneOfInterfaces" -> "true",
|
||||
* "useAbstractionForFiles" -> "true",
|
||||
* )
|
||||
* }
|
||||
*
|
||||
* override def generatedSources: T[Seq[PathRef]] = Seq(
|
||||
* PathRef(Task.dest),
|
||||
* openApiServer.generate(),
|
||||
* openApiClient.generate(),
|
||||
* )
|
||||
* }
|
||||
* }}}
|
||||
*/
|
||||
trait OpenApiModule extends mill.api.Module {
|
||||
|
||||
trait OpenApiConfig extends mill.api.Module {
|
||||
|
||||
case class ArtifactSettings(
|
||||
groupId: String,
|
||||
artifactId: String,
|
||||
artifactVersion: Option[String] = None
|
||||
) derives RW
|
||||
|
||||
case class GitSettings(
|
||||
host: String,
|
||||
userId: String,
|
||||
repoId: String
|
||||
) derives RW
|
||||
|
||||
|
||||
/** The Open API 2.0/3.x specification location. */
|
||||
def inputSpec: T[PathRef]
|
||||
|
||||
/** The name of the generator which will handle codegen. */
|
||||
def generatorName: T[String]
|
||||
|
||||
/** Package for generated api classes. */
|
||||
def apiPackage: T[String]
|
||||
|
||||
/**
|
||||
* The additional folder passed to the generator. Usually this is done via the [[additionalProperties]] but since
|
||||
* some generators also use different defaults while others use none, this property needs to be set and will
|
||||
* override anything set in [[additionalProperties]].
|
||||
*
|
||||
* This is necessary so the plugin can construct the correct source folder structure.
|
||||
*/
|
||||
def sourceFolder: T[String]
|
||||
|
||||
/**
|
||||
* Suffix that will be appended to all api names. Default is the empty string.
|
||||
*/
|
||||
def apiNameSuffix: T[String] = ""
|
||||
|
||||
/**
|
||||
* Adds authorization headers when fetching the OpenAPI definitions remotely.
|
||||
* Pass in a URL-encoded string of name:header with a comma separating multiple values
|
||||
*/
|
||||
def auth: T[Option[String]] = None
|
||||
|
||||
/**
|
||||
* Sets custom User-Agent header value
|
||||
*/
|
||||
def httpUserAgent: T[Option[String]] = None
|
||||
|
||||
/** Package for generated model classes. */
|
||||
def modelPackage: T[String]
|
||||
|
||||
/**
|
||||
* Prefix that will be prepended to all model names. Default is the empty string.
|
||||
*/
|
||||
def modelNamePrefix: T[String] = ""
|
||||
|
||||
/**
|
||||
* Suffix that will be appended to all model names. Default is the empty string.
|
||||
*/
|
||||
def modelNameSuffix: T[String] = ""
|
||||
|
||||
/** Sets additional properties that can be referenced by the mustache templates. */
|
||||
def additionalProperties: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/**
|
||||
* Defines the user's target type.
|
||||
* {{{ "OffsetDateTime" -> "java.time.Instant" }}}
|
||||
*
|
||||
* @see [[https://openapi-generator.tech/docs/usage/#type-mappings-and-import-mappings]]
|
||||
* */
|
||||
def typeMappings: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/**
|
||||
* Informs the template of the type to be imported. Needed when type mappings are used.
|
||||
* {{{ "OffsetDateTime" -> "java.time.Instant" }}}
|
||||
* Since the [[typeMappings]] are used to change the default types, the import mappings are used to map the imports.
|
||||
*
|
||||
* @see [[https://openapi-generator.tech/docs/usage/#type-mappings-and-import-mappings]]
|
||||
* */
|
||||
def importMappings: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/**
|
||||
* Specifies mappings between a given schema and the new one.
|
||||
*/
|
||||
def schemaMappings: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/** Specify if the spec should be validated. Default is true. */
|
||||
def validateSpec: T[Boolean] = true
|
||||
|
||||
/**
|
||||
* Specifies an override location for the .openapi-generator-ignore file.
|
||||
*/
|
||||
def ignoreFileOverride: T[Option[Path]] = None
|
||||
|
||||
/**
|
||||
* Specifies how a reserved name should be escaped to.
|
||||
*/
|
||||
def reservedWordsMappings: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/**
|
||||
* Remove examples defined in the operation
|
||||
*/
|
||||
def skipOperationExample: T[Boolean] = false
|
||||
|
||||
/**
|
||||
* Defines which API-related files should be generated. This allows you to create a subset of generated files (or none at all).
|
||||
*
|
||||
* This option enables/disables generation of ALL api-related files.
|
||||
*
|
||||
* NOTE: Configuring any one of [[apiFilesConstrainedTo]], [[modelFilesConstrainedTo]], or [[supportingFilesConstrainedTo]] results
|
||||
* in others being disabled. That is, OpenAPI Generator considers any one of these to define a subset of generation.
|
||||
* For more control over the generation of individual files, configure an ignored file and refer to it via [[ignoreFileOverride]].
|
||||
*/
|
||||
def apiFilesConstrainedTo: T[Seq[String]] = Seq.empty[String]
|
||||
|
||||
/**
|
||||
* Defines which model-related files should be generated. This allows you to create a subset of generated files (or none at all).
|
||||
*
|
||||
* NOTE: Configuring any one of [[apiFilesConstrainedTo]], [[modelFilesConstrainedTo]], or [[supportingFilesConstrainedTo]] results
|
||||
* in others being disabled. That is, OpenAPI Generator considers any one of these to define a subset of generation.
|
||||
* For more control over the generation of individual files, configure an ignored file and refer to it via [[ignoreFileOverride]].
|
||||
*/
|
||||
def modelFilesConstrainedTo: T[Seq[String]] = Seq.empty[String]
|
||||
|
||||
/**
|
||||
* Defines which supporting files should be generated. This allows you to create a subset of generated files (or none at all).
|
||||
*
|
||||
* Supporting files are those related to `projects/frameworks` which may be modified
|
||||
* by consumers.
|
||||
*
|
||||
* NOTE: Configuring any one of [[apiFilesConstrainedTo]], [[modelFilesConstrainedTo]], or [[supportingFilesConstrainedTo]] results
|
||||
* in others being disabled. That is, OpenAPI Generator considers any one of these to define a subset of generation.
|
||||
* For more control over the generation of individual files, configure an ignored file and refer to it via [[ignoreFileOverride]].
|
||||
*/
|
||||
def supportingFilesConstrainedTo: T[Seq[String]] = Seq.empty[String]
|
||||
|
||||
/**
|
||||
* Generate the APIs. Default is true.
|
||||
*/
|
||||
def generateApis: T[Boolean] = true
|
||||
|
||||
/**
|
||||
* Defines whether api-related _documentation_ files should be generated.
|
||||
*
|
||||
* This option enables/disables generation of ALL api-related _documentation_ files.
|
||||
*
|
||||
* For more control over generation of individual files, configure an ignored file and
|
||||
* refer to it via [[ignoreFileOverride]].
|
||||
*/
|
||||
def generateApiDocs: T[Boolean] = true
|
||||
|
||||
/**
|
||||
* Defines whether api-related _test_ files should be generated.
|
||||
*
|
||||
* This option is currently disabled because Mill does not distinguish between normal- and test-sources.
|
||||
*/
|
||||
// TODO figure out a clean way to support this
|
||||
final def generateApiTests: T[Boolean] = false
|
||||
|
||||
/**
|
||||
* Generate the Models. Default is true.
|
||||
*/
|
||||
def generateModels: T[Boolean] = true
|
||||
|
||||
/**
|
||||
* Defines whether model-related _documentation_ files should be generated.
|
||||
*
|
||||
* This option enables/disables generation of ALL model-related _documentation_ files.
|
||||
*
|
||||
* For more control over generation of individual files, configure an ignored file and
|
||||
* refer to it via [[ignoreFileOverride]].
|
||||
*/
|
||||
def generateModelDocs: T[Boolean] = true
|
||||
|
||||
/**
|
||||
* Defines whether model-related _test_ files should be generated.
|
||||
*
|
||||
* This option is currently disabled because Mill does not distinguish between normal- and test-sources.
|
||||
*/
|
||||
// TODO figure out a clean way to support this
|
||||
def generateModelTests: T[Boolean] = false
|
||||
|
||||
/**
|
||||
* Generate the supporting files. Default is true.
|
||||
*/
|
||||
def generateSupportingFiles: T[Boolean] = true
|
||||
|
||||
/**
|
||||
* Generate the models recursively if models should generate selectively (see [[modelFilesConstrainedTo]]) and all
|
||||
* dependent models are to generate.
|
||||
* Is enabled by default when [[modelFilesConstrainedTo]] is not empty for convenience.
|
||||
*/
|
||||
def generateRecursiveDependentModels: T[Boolean] = modelFilesConstrainedTo().nonEmpty
|
||||
|
||||
/**
|
||||
* Templating engine: "mustache" (default) or "handlebars" (beta)
|
||||
*/
|
||||
def engine: T[Option[String]] = None
|
||||
|
||||
/**
|
||||
* Specifies mappings between the inline scheme name and the new name
|
||||
*/
|
||||
def inlineSchemaNameMappings: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/**
|
||||
* Specifies options for inline schemas
|
||||
*/
|
||||
def inlineSchemaOptions: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/**
|
||||
* Specifies mappings between the property name and the new name
|
||||
*/
|
||||
def nameMappings: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/**
|
||||
* Specifies mappings between the parameter name and the new name
|
||||
*/
|
||||
def parameterNameMappings: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/**
|
||||
* Specifies mappings between the model name and the new name
|
||||
*/
|
||||
def modelNameMappings: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/**
|
||||
* Specifies mappings between the enum name and the new name
|
||||
*/
|
||||
def enumNameMappings: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/**
|
||||
* Specifies mappings between the operation id name and the new name
|
||||
*/
|
||||
def operationIdNameMappings: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/**
|
||||
* Specifies mappings (rules) in OpenAPI normalizer
|
||||
*/
|
||||
def openapiNormalizer: T[Map[String, String]] = Map.empty[String, String]
|
||||
|
||||
/**
|
||||
* Root package for generated code.
|
||||
*/
|
||||
def invokerPackage: T[Option[String]] = None
|
||||
|
||||
/**
|
||||
* Artifact coordinates/packages used in generated build files.
|
||||
*/
|
||||
def artifactSettings: T[Option[ArtifactSettings]] = None
|
||||
|
||||
/**
|
||||
* Reference the library template (sub-template) of a generator.
|
||||
*/
|
||||
def library: T[Option[String]] = None
|
||||
|
||||
/**
|
||||
* To write all log messages (not just errors) to STDOUT
|
||||
*/
|
||||
def logToStderr: T[Boolean] = false
|
||||
|
||||
/**
|
||||
* To enable the file post-processing hook. This enables executing an external post-processor (usually a linter program).
|
||||
* This only enables the post-processor. To define the post-processing command, define an environment variable such as
|
||||
* LANG_POST_PROCESS_FILE (e.g. GO_POST_PROCESS_FILE, SCALA_POST_PROCESS_FILE). Please open an issue if your target
|
||||
* generator does not support this functionality.
|
||||
*/
|
||||
def enablePostProcessFile: T[Boolean] = false
|
||||
|
||||
/**
|
||||
* Folder containing the template files.
|
||||
*/
|
||||
def templateDirectory: T[Option[Path]] = None
|
||||
|
||||
/**
|
||||
* To remove operationId prefix (e.g. user_getName => getName)
|
||||
*/
|
||||
def removeOperationIdPrefix: T[Boolean] = false
|
||||
|
||||
/**
|
||||
* To treat a document strictly against the spec. Default is true.
|
||||
*/
|
||||
def strictSpec: T[Boolean] = true
|
||||
|
||||
/**
|
||||
* Specifies additional language-specific primitive types in the format of type1,type2,type3,type3. For example, `String,boolean,Boolean,Double`.
|
||||
*/
|
||||
def languageSpecificPrimitives: T[Set[String]] = Set.empty[String]
|
||||
|
||||
/**
|
||||
* Git repository used in generated documentation.
|
||||
*/
|
||||
def gitSettings: T[Option[GitSettings]] = None
|
||||
|
||||
/**
|
||||
* Sets specified global properties.
|
||||
*/
|
||||
def globalProperties: T[Map[String, String]] = Map.empty[String, String]
|
||||
/**
|
||||
* To skip spec validation. When true, we will skip the default behavior of validating a spec before generation.
|
||||
*/
|
||||
def skipValidateSpec: T[Boolean] = false
|
||||
|
||||
/**
|
||||
* To generate alias (array, list, map) as model. When false, top-level objects defined as array, list, or map will result in those
|
||||
* definitions generated as top-level Array-of-items, List-of-items, Map-of-items definitions.
|
||||
* When true, A model representation either containing or extending the array,list,map (depending on specific generator implementation) will be generated.
|
||||
*/
|
||||
def generateAliasAsModel: T[Boolean] = false
|
||||
|
||||
/**
|
||||
* Defines whether the output dir should be cleaned up before generating the output.
|
||||
*/
|
||||
def cleanupOutput: T[Boolean] = false
|
||||
|
||||
/**
|
||||
* Specifies if the existing files should be overwritten during the generation.
|
||||
*/
|
||||
def skipOverwrite: T[Boolean] = false
|
||||
|
||||
/**
|
||||
* Defines whether the generator should run in dry-run mode.
|
||||
*/
|
||||
def dryRun: T[Boolean] = false
|
||||
|
||||
|
||||
/**
|
||||
* An additional Task, which can be run after the generation phase.
|
||||
*
|
||||
* For instance, in case you have a shared type which is defined in your importMappings,
|
||||
* the generator will still generate the type even though it is not used. The following
|
||||
* cleanup will remove all files which are are not used.
|
||||
* {{{
|
||||
* override def cleanup: Task[Option[Path => Unit]] = Task.Anon {
|
||||
* Some(
|
||||
* (path: Path) => {
|
||||
* val filenames = (for {
|
||||
* (_, fqn) <- importMappings()
|
||||
* if fqn.startsWith("my.relevant.package.")
|
||||
* } yield fqn.split('.').last).toSeq
|
||||
*
|
||||
* os.walk(path)
|
||||
* .filter { p => os.isFile(p) && filenames.contains(p.baseName) }
|
||||
* .foreach { p => os.remove(p) }
|
||||
* })
|
||||
* }
|
||||
* }}}
|
||||
* This will match all full-qualified-names against the provided package and delete the matches.
|
||||
* Note: this sample requires that custom type packages are completely separate.
|
||||
*/
|
||||
def cleanup: Task[Option[Path => Unit]] = Task.Anon {
|
||||
None
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the OpenAPI generator with the given configuration.
|
||||
*/
|
||||
def generate: T[PathRef] = Task {
|
||||
val configurator = CodegenConfigurator()
|
||||
// don't call setAdditionalProperties with an immutable Scala Map, because the Setters after this one
|
||||
// might add to the attributes as well (which will then cause an Exception)
|
||||
additionalProperties().foreach((k, v) => configurator.addAdditionalProperty(k, v))
|
||||
|
||||
configurator.setApiNameSuffix(apiNameSuffix())
|
||||
.setApiPackage(apiPackage())
|
||||
.setEnumNameMappings(enumNameMappings().asJava)
|
||||
.setGeneratorName(generatorName())
|
||||
.setGlobalProperties(globalProperties().asJava)
|
||||
.setInputSpec(inputSpec().path.toString())
|
||||
.setInlineSchemaNameMappings(inlineSchemaNameMappings().asJava)
|
||||
.setInlineSchemaOptions(inlineSchemaOptions().asJava)
|
||||
.setImportMappings(importMappings().asJava)
|
||||
.setLanguageSpecificPrimitives(languageSpecificPrimitives().asJava)
|
||||
.setModelNameMappings(modelNameMappings().asJava)
|
||||
.setModelNamePrefix(modelNamePrefix())
|
||||
.setModelNameSuffix(modelNameSuffix())
|
||||
.setModelPackage(modelPackage())
|
||||
.setNameMappings(nameMappings().asJava)
|
||||
.setOperationIdNameMappings(operationIdNameMappings().asJava)
|
||||
.setOpenapiNormalizer(openapiNormalizer().asJava)
|
||||
// should output-dir be configurable like in Gradle (don't think so)
|
||||
.setOutputDir(Task.dest.toString())
|
||||
.setParameterNameMappings(parameterNameMappings().asJava)
|
||||
.setReservedWordsMappings(reservedWordsMappings().asJava)
|
||||
.setSchemaMappings(schemaMappings().asJava)
|
||||
.setTypeMappings(typeMappings().asJava)
|
||||
.setValidateSpec(validateSpec())
|
||||
|
||||
if(generateApis()){
|
||||
GlobalSettings.setProperty(CodegenConstants.APIS, apiFilesConstrainedTo().mkString(","))
|
||||
}
|
||||
if(generateModels()){
|
||||
GlobalSettings.setProperty(CodegenConstants.MODELS, modelFilesConstrainedTo().mkString(","))
|
||||
}
|
||||
GlobalSettings.setProperty(CodegenConstants.GENERATE_RECURSIVE_DEPENDENT_MODELS, generateRecursiveDependentModels().toString)
|
||||
if(generateSupportingFiles()){
|
||||
GlobalSettings.setProperty(CodegenConstants.SUPPORTING_FILES, supportingFilesConstrainedTo().mkString(","))
|
||||
}
|
||||
|
||||
GlobalSettings.setProperty(CodegenConstants.API_DOCS, generateApiDocs().toString)
|
||||
GlobalSettings.setProperty(CodegenConstants.API_TESTS, generateApiTests().toString)
|
||||
GlobalSettings.setProperty(CodegenConstants.MODEL_DOCS, generateModelDocs().toString)
|
||||
GlobalSettings.setProperty(CodegenConstants.MODEL_TESTS, generateModelTests().toString)
|
||||
|
||||
engine() match {
|
||||
case Some(s) if s.equalsIgnoreCase("handlebars") => configurator.setTemplatingEngineName("handlebars")
|
||||
case Some(s) => configurator.setTemplatingEngineName(s) // in case other engines are supported
|
||||
case None => () // use default
|
||||
}
|
||||
|
||||
auth().filter(_.nonEmpty).foreach(authUrl => configurator.setAuth(authUrl))
|
||||
httpUserAgent().foreach(userAgent => configurator.setHttpUserAgent(userAgent))
|
||||
ignoreFileOverride().foreach(file => configurator.setIgnoreFileOverride(file.toNIO.toAbsolutePath.toString))
|
||||
invokerPackage().foreach(value => configurator.setInvokerPackage(value))
|
||||
artifactSettings().foreach(settings =>
|
||||
configurator.setGroupId(settings.groupId)
|
||||
configurator.setArtifactId(settings.artifactId)
|
||||
settings.artifactVersion.foreach(value => configurator.setArtifactVersion(value))
|
||||
)
|
||||
library().foreach(value => configurator.setLibrary(value))
|
||||
templateDirectory().foreach(file => configurator.setTemplateDir(file.toNIO.toAbsolutePath.toString))
|
||||
gitSettings().foreach(git =>
|
||||
configurator.setGitHost(git.host)
|
||||
configurator.setGitUserId(git.userId)
|
||||
configurator.setGitRepoId(git.repoId)
|
||||
)
|
||||
if (logToStderr()) {
|
||||
configurator.setLogToStderr(true)
|
||||
}
|
||||
if (enablePostProcessFile()) {
|
||||
configurator.setEnablePostProcessFile(true)
|
||||
}
|
||||
if (skipValidateSpec()) {
|
||||
configurator.setValidateSpec(false)
|
||||
}
|
||||
if (generateAliasAsModel()) {
|
||||
configurator.setGenerateAliasAsModel(true)
|
||||
}
|
||||
if (removeOperationIdPrefix()) {
|
||||
configurator.setRemoveOperationIdPrefix(true)
|
||||
}
|
||||
if (skipOperationExample()) {
|
||||
configurator.setSkipOperationExample(true)
|
||||
}
|
||||
if (strictSpec()) {
|
||||
configurator.setStrictSpecBehavior(true)
|
||||
}
|
||||
if (skipOverwrite()) {
|
||||
configurator.setSkipOverwrite(true)
|
||||
}
|
||||
|
||||
if (cleanupOutput()) {
|
||||
os.remove.all(Task.dest)
|
||||
os.makeDir.all(Task.dest)
|
||||
Task.log.info(s"Cleaned up output directory ${Task.dest} before code generation (cleanupOutput set to true).")
|
||||
}
|
||||
val dryRunSetting = dryRun()
|
||||
|
||||
// set source-folder as last to override potential duplicate
|
||||
configurator.addAdditionalProperty("sourceFolder", sourceFolder())
|
||||
|
||||
DefaultGenerator(dryRunSetting).opts(configurator.toClientOptInput).generate()
|
||||
Task.log.info(s"Successfully generated code to ${Task.dest}")
|
||||
cleanup() match {
|
||||
case Some(f) => f(Task.dest)
|
||||
case None => // no-op
|
||||
}
|
||||
|
||||
PathRef(Task.dest / RelPath(sourceFolder()))
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates currently configured [[inputSpec]]. This task outputs a list of validation issues and errors.
|
||||
*
|
||||
* @param recommend prints warnings for recommended fixes. Default is true.
|
||||
* @param failOnWarnings fails the call when there are warnings. Default is false.
|
||||
* @return
|
||||
*/
|
||||
def validate(
|
||||
recommend: Boolean = true,
|
||||
failOnWarnings: Boolean = false
|
||||
): Task.Command[Unit] = Task.Command {
|
||||
given log: mill.api.Logger = Task.log
|
||||
runValidation(inputSpec().path, recommend, failOnWarnings)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command which checks a passed OpenAPI definition.
|
||||
* This task outputs a list of validation issues and errors.
|
||||
*
|
||||
* @param spec the path to the file to be validated.
|
||||
* @param recommend prints warnings for recommended fixes. Default is true.
|
||||
* @param failOnWarnings fails the call when there are warnings. Default is false.
|
||||
*/
|
||||
def validateOpenapiSpec(
|
||||
@arg(positional = true)
|
||||
spec: String,
|
||||
recommend: Boolean = true,
|
||||
failOnWarnings: Boolean = false
|
||||
): Task.Command[Unit] = Task.Command {
|
||||
given log: mill.api.Logger = Task.log
|
||||
runValidation(os.Path(spec), recommend, failOnWarnings)
|
||||
}
|
||||
|
||||
private def runValidation(spec: Path, recommend: Boolean, failOnWarnings: Boolean)(using log: mill.api.Logger) = {
|
||||
log.info(s"Validating spec $spec")
|
||||
|
||||
val options = ParseOptions()
|
||||
options.setResolve(true)
|
||||
|
||||
val result = OpenAPIParser().readLocation(spec.toNIO.toAbsolutePath.toString, null, options)
|
||||
val messages = CollectionConverters.asScala(result.getMessages).toSet
|
||||
|
||||
val ruleConfiguration = RuleConfiguration()
|
||||
ruleConfiguration.setEnableRecommendations(recommend)
|
||||
|
||||
val evaluator = OpenApiEvaluator(ruleConfiguration)
|
||||
val validationResult = evaluator.validate(result.getOpenAPI)
|
||||
val warnings = CollectionConverters.asScala(validationResult.getWarnings)
|
||||
val errors = CollectionConverters.asScala(validationResult.getErrors)
|
||||
|
||||
if (warnings.nonEmpty) {
|
||||
val sb = StringBuilder("Spec has issues or recommendations.\nIssues:\n")
|
||||
warnings.foreach(w => {
|
||||
sb.append(s"\t${w.getMessage}\n")
|
||||
log.debug(s"WARNING: ${w.getMessage}|${w.getDetails}")
|
||||
})
|
||||
log.info(sb.toString())
|
||||
}
|
||||
|
||||
if (messages.nonEmpty || errors.nonEmpty) {
|
||||
val sb = new StringBuilder("Spec is invalid.\nIssues:\n")
|
||||
|
||||
messages.foreach(m => {
|
||||
sb.append(s"\t$m\n")
|
||||
log.debug(s"ERROR: $m")
|
||||
})
|
||||
errors.foreach(e => {
|
||||
sb.append(s"\t$e\n")
|
||||
log.debug(s"ERROR: ${e.getMessage}|${e.getDetails}")
|
||||
})
|
||||
log.error(sb.toString())
|
||||
Result.Failure("Validation failed.")
|
||||
} else if (failOnWarnings && warnings.nonEmpty) {
|
||||
log.error("Warnings found in the spec and 'treatWarningsAsErrors' is enabled.\nFailing validation.\n")
|
||||
Result.Failure("Validation failed due to warnings (treatWarningsAsErrors = true).")
|
||||
} else {
|
||||
log.info("No error validations from swagger-parser or internal validations.")
|
||||
Result.Success("Spec is valid.")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
openapi: "3.0.0"
|
||||
servers:
|
||||
- url: http://petstore.swagger.io/v1
|
||||
paths:
|
||||
/pets:
|
||||
get:
|
||||
summary: List all pets
|
||||
operationId: listPets
|
||||
tags:
|
||||
- pets
|
||||
parameters:
|
||||
- name: limit
|
||||
in: query
|
||||
description: How many items to return at one time (max 100)
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
responses:
|
||||
'200':
|
||||
description: A paged array of pets
|
||||
headers:
|
||||
x-next:
|
||||
description: A link to the next page of responses
|
||||
schema:
|
||||
type: string
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Pets"
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
post:
|
||||
summary: Create a pet
|
||||
tags:
|
||||
- pets
|
||||
responses:
|
||||
'201':
|
||||
description: Null response
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/pets/{petId}:
|
||||
get:
|
||||
summary: Info for a specific pet
|
||||
operationId: showPetById
|
||||
tags:
|
||||
- pets
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
required: true
|
||||
description: The id of the pet to retrieve
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Expected response to a valid request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Pets"
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
components:
|
||||
schemas:
|
||||
Pet:
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
Pets:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Pet"
|
||||
Error:
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
message:
|
||||
type: string
|
||||
@@ -0,0 +1,109 @@
|
||||
openapi: "3.0.0"
|
||||
info:
|
||||
version: 1.0.0
|
||||
title: Swagger Petstore
|
||||
license:
|
||||
name: MIT
|
||||
servers:
|
||||
- url: http://petstore.swagger.io/v1
|
||||
paths:
|
||||
/v3/pets:
|
||||
get:
|
||||
summary: List all pets
|
||||
operationId: listPets
|
||||
tags:
|
||||
- pets
|
||||
parameters:
|
||||
- name: limit
|
||||
in: query
|
||||
description: How many items to return at one time (max 100)
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
responses:
|
||||
'200':
|
||||
description: A paged array of pets
|
||||
headers:
|
||||
x-next:
|
||||
description: A link to the next page of responses
|
||||
schema:
|
||||
type: string
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Pets"
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
post:
|
||||
summary: Create a pet
|
||||
operationId: createPets
|
||||
tags:
|
||||
- pets
|
||||
responses:
|
||||
'201':
|
||||
description: Null response
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/v3/pets/{petId}:
|
||||
get:
|
||||
summary: Info for a specific pet
|
||||
operationId: showPetById
|
||||
tags:
|
||||
- pets
|
||||
parameters:
|
||||
- name: petId
|
||||
in: path
|
||||
required: true
|
||||
description: The id of the pet to retrieve
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Expected response to a valid request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Pets"
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
components:
|
||||
schemas:
|
||||
Pet:
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
Pets:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Pet"
|
||||
Error:
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
message:
|
||||
type: string
|
||||
@@ -0,0 +1,109 @@
|
||||
package org.openapitools.generator.mill
|
||||
|
||||
import mill.*
|
||||
import mill.api.{BuildCtx, Discover}
|
||||
import mill.javalib.{Dep, JavaModule}
|
||||
import mill.testkit.{TestRootModule, UnitTester}
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.testng.annotations.Test
|
||||
import scala.language.postfixOps
|
||||
|
||||
object MillOpenapiModuleTestRoot extends TestRootModule {
|
||||
|
||||
lazy val millDiscover = Discover[this.type]
|
||||
|
||||
/** a project definition for Mill which should generate and compile */
|
||||
object petstoreMicroprofile extends JavaModule with OpenApiModule {
|
||||
|
||||
override def mvnDeps: T[Seq[Dep]] = Seq(
|
||||
Dep.parse("jakarta.ws.rs:jakarta.ws.rs-api:3.1.0"),
|
||||
Dep.parse("jakarta.json.bind:jakarta.json.bind-api:3.0.0"),
|
||||
Dep.parse("jakarta.json:jakarta.json-api:2.1.0"),
|
||||
Dep.parse("org.eclipse.microprofile.rest.client:microprofile-rest-client-api:3.0.1"),
|
||||
)
|
||||
|
||||
object openapi extends OpenApiConfig {
|
||||
|
||||
override def inputSpec: T[PathRef] = Task.Source(BuildCtx.workspaceRoot / "petstore-v3.1.yaml")
|
||||
override def generatorName: T[String] = "java-microprofile"
|
||||
override def apiPackage: T[String] = "com.acme.foo.boundary.web.api"
|
||||
override def modelPackage: T[String] = "com.acme.foo.boundary.web.model"
|
||||
override def sourceFolder: T[String] = "src/gen/java"
|
||||
override def additionalProperties: T[Map[String, String]] = Map(
|
||||
"microprofileRestClientVersion" -> "3.0",
|
||||
"library" -> "microprofile",
|
||||
"dateLibrary" -> "java8",
|
||||
"interfaceOnly" -> "true",
|
||||
"performBeanValidation" -> "true",
|
||||
"useBeanValidation" -> "false",
|
||||
"skipDefaultInterface" -> "true",
|
||||
"useTags" -> "true",
|
||||
)
|
||||
}
|
||||
|
||||
override def generatedSources: T[Seq[PathRef]] = Seq(
|
||||
PathRef(Task.dest),
|
||||
openapi.generate(),
|
||||
)
|
||||
}
|
||||
|
||||
/** a project definition for Mill with an invalid openapi-spec */
|
||||
object petstoreInvalid extends JavaModule with OpenApiModule {
|
||||
|
||||
override def mvnDeps: T[Seq[Dep]] = Seq(
|
||||
Dep.parse("jakarta.ws.rs:jakarta.ws.rs-api:3.1.0"),
|
||||
Dep.parse("jakarta.json.bind:jakarta.json.bind-api:3.0.0"),
|
||||
Dep.parse("jakarta.json:jakarta.json-api:2.1.0"),
|
||||
Dep.parse("org.eclipse.microprofile.rest.client:microprofile-rest-client-api:3.0.1"),
|
||||
)
|
||||
|
||||
object openapi extends OpenApiConfig {
|
||||
|
||||
override def inputSpec: T[PathRef] = Task.Source(BuildCtx.workspaceRoot / "petstore-v3.0-invalid-due-to-missing-info-attribute.yaml")
|
||||
override def generatorName: T[String] = "java-microprofile"
|
||||
override def apiPackage: T[String] = "com.acme.foo.boundary.web.api"
|
||||
override def modelPackage: T[String] = "com.acme.foo.boundary.web.model"
|
||||
override def sourceFolder: T[String] = "src/gen/java"
|
||||
override def additionalProperties: T[Map[String, String]] = Map(
|
||||
"microprofileRestClientVersion" -> "3.0",
|
||||
"library" -> "microprofile",
|
||||
"dateLibrary" -> "java8",
|
||||
"interfaceOnly" -> "true",
|
||||
"performBeanValidation" -> "true",
|
||||
"useBeanValidation" -> "false",
|
||||
"skipDefaultInterface" -> "true",
|
||||
"useTags" -> "true",
|
||||
)
|
||||
}
|
||||
|
||||
override def generatedSources: T[Seq[PathRef]] = Seq(
|
||||
PathRef(Task.dest),
|
||||
openapi.generate(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class MillOpenapiModuleTest extends Matchers {
|
||||
|
||||
private val resourcePath = os.Path(sys.env("MILL_TEST_RESOURCE_DIR")) / "specs"
|
||||
private def testEval() = UnitTester(MillOpenapiModuleTestRoot, resourcePath)
|
||||
|
||||
@Test
|
||||
def petstoreMicroprofileGeneratesAndCompiles(): Unit = {
|
||||
val result = testEval().scoped{ eval =>
|
||||
// execute 'compile` task
|
||||
eval.apply(MillOpenapiModuleTestRoot.petstoreMicroprofile.compile)
|
||||
}
|
||||
|
||||
result shouldBe a[Right[_, _]]
|
||||
}
|
||||
|
||||
@Test
|
||||
def petstoreMicroprofileInvalidSpec(): Unit = {
|
||||
val result = testEval().scoped { eval =>
|
||||
// execute 'compile` task
|
||||
eval.apply(MillOpenapiModuleTestRoot.petstoreInvalid.compile)
|
||||
}
|
||||
result shouldBe a[Left[_, _]]
|
||||
}
|
||||
}
|
||||
@@ -3301,7 +3301,7 @@ public class DefaultCodegen implements CodegenConfig {
|
||||
}
|
||||
|
||||
if (refSchema.getProperties() != null && refSchema.getProperties().get(discPropName) != null) {
|
||||
Schema discSchema = ModelUtils.getReferencedSchema(openAPI, (Schema) refSchema.getProperties().get(discPropName));
|
||||
Schema discSchema = ModelUtils.getReferencedSchema(openAPI, getDiscriminatorSchema(refSchema, discPropName));
|
||||
CodegenProperty cp = new CodegenProperty();
|
||||
if (ModelUtils.isStringSchema(discSchema)) {
|
||||
cp.isString = true;
|
||||
@@ -3632,14 +3632,7 @@ public class DefaultCodegen implements CodegenConfig {
|
||||
// FIXME: there are other ways to define the type of the discriminator property (inline
|
||||
// for example). Handling those scenarios is too complicated for me, I'm leaving it for
|
||||
// the future..
|
||||
String propertyType =
|
||||
Optional.ofNullable(schema.getProperties())
|
||||
.map(p -> (Schema<?>) p.get(discriminatorPropertyName))
|
||||
.map(Schema::get$ref)
|
||||
.map(ModelUtils::getSimpleRef)
|
||||
.map(this::toModelName)
|
||||
.orElseGet(() -> typeMapping.get("string"));
|
||||
discriminator.setPropertyType(propertyType);
|
||||
discriminator.setPropertyType(getDiscriminatorPropertyType(schema, discriminatorPropertyName));
|
||||
|
||||
// check to see if the discriminator property is an enum string
|
||||
boolean isEnum = Optional
|
||||
@@ -3703,6 +3696,39 @@ public class DefaultCodegen implements CodegenConfig {
|
||||
return discriminator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Schema for the discriminator type. Requires special handling due to siblings from OAS 3.1.
|
||||
* An example of a sibling is an enum-ref that has its own description. This will lead to the enum being
|
||||
* referenced as an allOf that in turn has a ref, rather than a regular ref directly to the enum.
|
||||
*
|
||||
* @param schema The input OAS schema.
|
||||
* @param discriminatorName The name of the discriminator property.
|
||||
*/
|
||||
protected Schema getDiscriminatorSchema(Schema schema, String discriminatorName) {
|
||||
if (schema.getProperties() == null) {
|
||||
return null;
|
||||
}
|
||||
Schema discSchema = (Schema) schema.getProperties().get(discriminatorName);
|
||||
if (ModelUtils.isAllOf(discSchema)) {
|
||||
discSchema = (Schema) discSchema.getAllOf().get(0);
|
||||
}
|
||||
return discSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the property type for the discriminator
|
||||
*
|
||||
* @param schema The input OAS schema.
|
||||
* @param discriminatorPropertyName The name of the discriminator property.
|
||||
*/
|
||||
protected String getDiscriminatorPropertyType(Schema schema, String discriminatorPropertyName) {
|
||||
return Optional.ofNullable(getDiscriminatorSchema(schema, discriminatorPropertyName))
|
||||
.map(Schema::get$ref)
|
||||
.map(ModelUtils::getSimpleRef)
|
||||
.map(this::toModelName)
|
||||
.orElseGet(() -> typeMapping.get("string"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the model for the 'additionalProperties' keyword in the OAS schema.
|
||||
*
|
||||
@@ -5323,9 +5349,6 @@ public class DefaultCodegen implements CodegenConfig {
|
||||
if (parameter.getExtensions() != null && !parameter.getExtensions().isEmpty()) {
|
||||
codegenParameter.vendorExtensions.putAll(parameter.getExtensions());
|
||||
}
|
||||
if (parameter.getSchema() != null && parameter.getSchema().getExtensions() != null && !parameter.getSchema().getExtensions().isEmpty()) {
|
||||
codegenParameter.vendorExtensions.putAll(parameter.getSchema().getExtensions());
|
||||
}
|
||||
|
||||
Schema parameterSchema;
|
||||
|
||||
@@ -5360,6 +5383,10 @@ public class DefaultCodegen implements CodegenConfig {
|
||||
parameterSchema = null;
|
||||
}
|
||||
|
||||
if (parameterSchema != null && parameterSchema.getExtensions() != null && !parameterSchema.getExtensions().isEmpty()) {
|
||||
codegenParameter.vendorExtensions.putAll(parameterSchema.getExtensions());
|
||||
}
|
||||
|
||||
if (parameter instanceof QueryParameter || "query".equalsIgnoreCase(parameter.getIn())) {
|
||||
codegenParameter.isQueryParam = true;
|
||||
codegenParameter.isAllowEmptyValue = parameter.getAllowEmptyValue() != null && parameter.getAllowEmptyValue();
|
||||
|
||||
@@ -356,6 +356,7 @@ public class OpenAPINormalizer {
|
||||
normalizeComponentsSecuritySchemes();
|
||||
normalizeComponentsSchemas();
|
||||
normalizeComponentsResponses();
|
||||
normalizeComponentsHeaders();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -558,8 +559,21 @@ public class OpenAPINormalizer {
|
||||
|
||||
for (String headerKey : headers.keySet()) {
|
||||
Header h = headers.get(headerKey);
|
||||
Schema updatedHeader = normalizeSchema(h.getSchema(), new HashSet<>());
|
||||
h.setSchema(updatedHeader);
|
||||
if (h.getSchema() != null) { // not a $ref header
|
||||
// example of header class
|
||||
// description: null
|
||||
// required: null
|
||||
// deprecated: null
|
||||
// style: null
|
||||
// explode: null
|
||||
// schema: null
|
||||
// examples: null
|
||||
// example: null
|
||||
// content: null
|
||||
// $ref: #/components/headers/Location
|
||||
Schema updatedHeader = normalizeSchema(h.getSchema(), new HashSet<>());
|
||||
h.setSchema(updatedHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -638,6 +652,18 @@ public class OpenAPINormalizer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes schemas in component's headers.
|
||||
*/
|
||||
protected void normalizeComponentsHeaders() {
|
||||
Map<String, Header> headers = openAPI.getComponents().getHeaders();
|
||||
if (headers == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
normalizeHeaders(headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto fix a self referencing schema using any type to replace the self-referencing sub-item.
|
||||
*
|
||||
@@ -696,7 +722,7 @@ public class OpenAPINormalizer {
|
||||
*/
|
||||
public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
|
||||
// normalize reference schema
|
||||
if (StringUtils.isNotEmpty(schema.get$ref())) {
|
||||
if (schema != null && StringUtils.isNotEmpty(schema.get$ref())) {
|
||||
normalizeReferenceSchema(schema);
|
||||
}
|
||||
|
||||
@@ -860,7 +886,7 @@ public class OpenAPINormalizer {
|
||||
}
|
||||
for (Map.Entry<String, Schema> propertiesEntry : properties.entrySet()) {
|
||||
Schema property = propertiesEntry.getValue();
|
||||
|
||||
|
||||
// remove x-internal if needed (same logic as normalizeComponentsSchemas)
|
||||
if (property.getExtensions() != null && getRule(REMOVE_X_INTERNAL)) {
|
||||
Object xInternalValue = property.getExtensions().get(X_INTERNAL);
|
||||
@@ -1777,6 +1803,7 @@ public class OpenAPINormalizer {
|
||||
ArraySchema as = new ArraySchema();
|
||||
as.setDescription(schema.getDescription());
|
||||
as.setDefault(schema.getDefault());
|
||||
as.setTitle(schema.getTitle());
|
||||
if (schema.getExample() != null) {
|
||||
as.setExample(schema.getExample());
|
||||
}
|
||||
|
||||
@@ -176,6 +176,22 @@ public abstract class CppQtAbstractCodegen extends AbstractCppCodegen implements
|
||||
return "#include \"" + folder + name + ".h\"";
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a schema reference. If the schema has a $ref, return the referenced schema.
|
||||
* This is for nested maps.
|
||||
*/
|
||||
private Schema resolveSchema(Schema schema) {
|
||||
if (schema == null) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.isNotEmpty(schema.get$ref())) {
|
||||
String ref = ModelUtils.getSimpleRef(schema.get$ref());
|
||||
Schema resolved = ModelUtils.getSchema(openAPI, ref);
|
||||
return resolved != null ? resolved : schema;
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional - type declaration. This is a String which is used by the templates to instantiate your
|
||||
* types. There is typically special handling for different property types
|
||||
@@ -185,15 +201,22 @@ public abstract class CppQtAbstractCodegen extends AbstractCppCodegen implements
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public String getTypeDeclaration(Schema p) {
|
||||
String openAPIType = getSchemaType(p);
|
||||
// Resolve the schema to check for nested maps/arrays - refs that point to map schemas
|
||||
Schema resolved = resolveSchema(p);
|
||||
|
||||
if (ModelUtils.isArraySchema(p)) {
|
||||
Schema inner = ModelUtils.getSchemaItems(p);
|
||||
if (ModelUtils.isArraySchema(resolved)) {
|
||||
Schema inner = ModelUtils.getSchemaItems(resolved);
|
||||
return getSchemaType(p) + "<" + getTypeDeclaration(inner) + ">";
|
||||
} else if (ModelUtils.isMapSchema(p)) {
|
||||
Schema inner = ModelUtils.getAdditionalProperties(p);
|
||||
return getSchemaType(p) + "<QString, " + getTypeDeclaration(inner) + ">";
|
||||
} else if (ModelUtils.isBinarySchema(p)) {
|
||||
} else if (ModelUtils.isMapSchema(resolved)) {
|
||||
Schema inner = ModelUtils.getAdditionalProperties(resolved);
|
||||
// inner can be null if additionalProperties is a boolean or not present
|
||||
String innerType = inner != null ? getTypeDeclaration(inner) : PREFIX + "Object";
|
||||
return getSchemaType(p) + "<QString, " + innerType + ">";
|
||||
}
|
||||
|
||||
// For non-containers, use the original schema to preserve model names
|
||||
String openAPIType = getSchemaType(p);
|
||||
if (ModelUtils.isBinarySchema(p)) {
|
||||
return getSchemaType(p);
|
||||
} else if (ModelUtils.isFileSchema(p)) {
|
||||
return getSchemaType(p);
|
||||
@@ -210,29 +233,32 @@ public abstract class CppQtAbstractCodegen extends AbstractCppCodegen implements
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public String toDefaultValue(Schema p) {
|
||||
if (ModelUtils.isBooleanSchema(p)) {
|
||||
Schema schema = resolveSchema(p);
|
||||
if (ModelUtils.isBooleanSchema(schema)) {
|
||||
return "false";
|
||||
} else if (ModelUtils.isDateSchema(p)) {
|
||||
} else if (ModelUtils.isDateSchema(schema)) {
|
||||
return "NULL";
|
||||
} else if (ModelUtils.isDateTimeSchema(p)) {
|
||||
} else if (ModelUtils.isDateTimeSchema(schema)) {
|
||||
return "NULL";
|
||||
} else if (ModelUtils.isNumberSchema(p)) {
|
||||
if (SchemaTypeUtil.FLOAT_FORMAT.equals(p.getFormat())) {
|
||||
} else if (ModelUtils.isNumberSchema(schema)) {
|
||||
if (SchemaTypeUtil.FLOAT_FORMAT.equals(schema.getFormat())) {
|
||||
return "0.0f";
|
||||
}
|
||||
return "0.0";
|
||||
} else if (ModelUtils.isIntegerSchema(p)) {
|
||||
if (SchemaTypeUtil.INTEGER64_FORMAT.equals(p.getFormat())) {
|
||||
} else if (ModelUtils.isIntegerSchema(schema)) {
|
||||
if (SchemaTypeUtil.INTEGER64_FORMAT.equals(schema.getFormat())) {
|
||||
return "0L";
|
||||
}
|
||||
return "0";
|
||||
} else if (ModelUtils.isMapSchema(p)) {
|
||||
Schema inner = ModelUtils.getAdditionalProperties(p);
|
||||
return "QMap<QString, " + getTypeDeclaration(inner) + ">()";
|
||||
} else if (ModelUtils.isArraySchema(p)) {
|
||||
Schema inner = ModelUtils.getSchemaItems(p);
|
||||
} else if (ModelUtils.isMapSchema(schema)) {
|
||||
Schema inner = ModelUtils.getAdditionalProperties(schema);
|
||||
// inner can be null if additionalProperties is a boolean or not present
|
||||
String innerType = inner != null ? getTypeDeclaration(inner) : PREFIX + "Object";
|
||||
return "QMap<QString, " + innerType + ">()";
|
||||
} else if (ModelUtils.isArraySchema(schema)) {
|
||||
Schema inner = ModelUtils.getSchemaItems(schema);
|
||||
return "QList<" + getTypeDeclaration(inner) + ">()";
|
||||
} else if (ModelUtils.isStringSchema(p)) {
|
||||
} else if (ModelUtils.isStringSchema(schema)) {
|
||||
return "QString(\"\")";
|
||||
} else if (!StringUtils.isEmpty(p.get$ref())) {
|
||||
return toModelName(ModelUtils.getSimpleRef(p.get$ref())) + "()";
|
||||
|
||||
@@ -291,6 +291,15 @@ public class CppRestSdkClientCodegen extends AbstractCppCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle additionalProperties for models that have both properties and additionalProperties
|
||||
Schema addlProps = ModelUtils.getAdditionalProperties(model);
|
||||
if (addlProps != null && model.getProperties() != null && !model.getProperties().isEmpty()) {
|
||||
// This model has both defined properties AND additionalProperties
|
||||
codegenModel.additionalPropertiesType = getTypeDeclaration(addlProps);
|
||||
// Add import for web::json::value which is used to store additional properties
|
||||
codegenModel.imports.add("#include <cpprest/json.h>");
|
||||
}
|
||||
|
||||
return codegenModel;
|
||||
}
|
||||
|
||||
@@ -362,6 +371,34 @@ public class CppRestSdkClientCodegen extends AbstractCppCodegen {
|
||||
return toApiName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a schema reference. If the schema has a $ref, return the referenced schema.
|
||||
* This is for nested maps.
|
||||
*/
|
||||
private Schema resolveSchema(Schema schema) {
|
||||
if (schema == null) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.isNotEmpty(schema.get$ref())) {
|
||||
String ref = ModelUtils.getSimpleRef(schema.get$ref());
|
||||
Schema resolved = ModelUtils.getSchema(openAPI, ref);
|
||||
return resolved != null ? resolved : schema;
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a schema is a pure map (has additionalProperties but no defined properties).
|
||||
* Schemas with both properties and additionalProperties should be treated as models, not maps.
|
||||
*/
|
||||
private boolean isPureMapSchema(Schema schema) {
|
||||
if (!ModelUtils.isMapSchema(schema)) {
|
||||
return false;
|
||||
}
|
||||
// If the schema has defined properties, it's not a pure map
|
||||
return schema.getProperties() == null || schema.getProperties().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional - type declaration. This is a String which is used by the
|
||||
* templates to instantiate your types. There is typically special handling
|
||||
@@ -372,15 +409,23 @@ public class CppRestSdkClientCodegen extends AbstractCppCodegen {
|
||||
*/
|
||||
@Override
|
||||
public String getTypeDeclaration(Schema p) {
|
||||
String openAPIType = getSchemaType(p);
|
||||
// Resolve the schema to check for nested maps/arrays - refs that point to map schemas
|
||||
Schema resolved = resolveSchema(p);
|
||||
|
||||
if (ModelUtils.isArraySchema(p)) {
|
||||
Schema inner = ModelUtils.getSchemaItems(p);
|
||||
if (ModelUtils.isArraySchema(resolved)) {
|
||||
Schema inner = ModelUtils.getSchemaItems(resolved);
|
||||
return getSchemaType(p) + "<" + getTypeDeclaration(inner) + ">";
|
||||
} else if (ModelUtils.isMapSchema(p)) {
|
||||
Schema inner = ModelUtils.getAdditionalProperties(p);
|
||||
return getSchemaType(p) + "<utility::string_t, " + getTypeDeclaration(inner) + ">";
|
||||
} else if (ModelUtils.isFileSchema(p) || ModelUtils.isBinarySchema(p)) {
|
||||
} else if (isPureMapSchema(resolved)) {
|
||||
// Only treat as map if it has additionalProperties but NO defined properties
|
||||
Schema inner = ModelUtils.getAdditionalProperties(resolved);
|
||||
// inner can be null if additionalProperties is a boolean or not present
|
||||
String innerType = inner != null ? getTypeDeclaration(inner) : "std::shared_ptr<Object>";
|
||||
return getSchemaType(p) + "<utility::string_t, " + innerType + ">";
|
||||
}
|
||||
|
||||
// For non-containers, use the original schema to preserve model names
|
||||
String openAPIType = getSchemaType(p);
|
||||
if (ModelUtils.isFileSchema(p) || ModelUtils.isBinarySchema(p)) {
|
||||
return "std::shared_ptr<" + openAPIType + ">";
|
||||
} else if (ModelUtils.isStringSchema(p)
|
||||
|| ModelUtils.isDateSchema(p) || ModelUtils.isDateTimeSchema(p)
|
||||
@@ -414,8 +459,10 @@ public class CppRestSdkClientCodegen extends AbstractCppCodegen {
|
||||
return "0L";
|
||||
}
|
||||
return "0";
|
||||
} else if (ModelUtils.isMapSchema(p)) {
|
||||
String inner = getSchemaType(ModelUtils.getAdditionalProperties(p));
|
||||
} else if (isPureMapSchema(p)) {
|
||||
Schema innerSchema = ModelUtils.getAdditionalProperties(p);
|
||||
// innerSchema can be null if additionalProperties is a boolean or not present
|
||||
String inner = innerSchema != null ? getSchemaType(innerSchema) : "std::shared_ptr<Object>";
|
||||
return "std::map<utility::string_t, " + inner + ">()";
|
||||
} else if (ModelUtils.isArraySchema(p)) {
|
||||
String inner = getSchemaType(ModelUtils.getSchemaItems(p));
|
||||
|
||||
@@ -208,9 +208,23 @@ public class CppTinyClientCodegen extends AbstractCppCodegen implements CodegenC
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a schema reference. If the schema has a $ref, return the referenced schema.
|
||||
* This is for nested maps.
|
||||
*/
|
||||
private Schema resolveSchema(Schema schema) {
|
||||
if (schema == null) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.isNotEmpty(schema.get$ref())) {
|
||||
String ref = ModelUtils.getSimpleRef(schema.get$ref());
|
||||
Schema resolved = ModelUtils.getSchema(openAPI, ref);
|
||||
return resolved != null ? resolved : schema;
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
private void makeTypeMappings() {
|
||||
// Types
|
||||
String cpp_array_type = "std::list";
|
||||
typeMapping = new HashMap<>();
|
||||
|
||||
typeMapping.put("string", "std::string");
|
||||
@@ -219,7 +233,8 @@ public class CppTinyClientCodegen extends AbstractCppCodegen implements CodegenC
|
||||
typeMapping.put("long", "long");
|
||||
typeMapping.put("boolean", "bool");
|
||||
typeMapping.put("double", "double");
|
||||
typeMapping.put("array", cpp_array_type);
|
||||
typeMapping.put("array", "std::list");
|
||||
typeMapping.put("map", "std::map");
|
||||
typeMapping.put("number", "long");
|
||||
typeMapping.put("binary", "std::string");
|
||||
typeMapping.put("password", "std::string");
|
||||
@@ -255,6 +270,19 @@ public class CppTinyClientCodegen extends AbstractCppCodegen implements CodegenC
|
||||
|
||||
@Override
|
||||
public String getTypeDeclaration(Schema p) {
|
||||
// Only resolve for nested maps - check if a $ref points to a map schema
|
||||
Schema resolved = resolveSchema(p);
|
||||
|
||||
// Handle nested maps: if a $ref resolves to a map schema, build the nested type
|
||||
if (ModelUtils.isMapSchema(resolved)) {
|
||||
Schema inner = ModelUtils.getAdditionalProperties(resolved);
|
||||
// inner can be null if additionalProperties is a boolean or not present
|
||||
String innerType = inner != null ? getTypeDeclaration(inner) : "std::string";
|
||||
return getSchemaType(p) + "<std::string, " + innerType + ">";
|
||||
}
|
||||
|
||||
// For everything else (including arrays), use the original behavior
|
||||
// The templates handle adding array item types themselves
|
||||
String openAPIType = getSchemaType(p);
|
||||
if (languageSpecificPrimitives.contains(openAPIType)) {
|
||||
return toModelName(openAPIType);
|
||||
@@ -296,7 +324,7 @@ public class CppTinyClientCodegen extends AbstractCppCodegen implements CodegenC
|
||||
return "#include <string>";
|
||||
} else if (name.equals("std::list")) {
|
||||
return "#include <list>";
|
||||
} else if (name.equals("Map")) {
|
||||
} else if (name.equals("Map") || name.equals("std::map")) {
|
||||
return "#include <map>";
|
||||
}
|
||||
return "#include \"" + name + ".h\"";
|
||||
|
||||
@@ -29,8 +29,7 @@ import org.openapitools.codegen.model.ModelsMap;
|
||||
import org.openapitools.codegen.model.OperationMap;
|
||||
import org.openapitools.codegen.model.OperationsMap;
|
||||
import org.openapitools.codegen.templating.mustache.PrefixWithHashLambda;
|
||||
import org.openapitools.codegen.templating.mustache.UppercaseLambda;
|
||||
import org.openapitools.codegen.templating.mustache.TitlecaseLambda;
|
||||
import org.openapitools.codegen.templating.mustache.PascalCaseLambda;
|
||||
import org.openapitools.codegen.utils.ModelUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -85,28 +84,32 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
SecurityFeature.BasicAuth,
|
||||
SecurityFeature.BearerToken,
|
||||
SecurityFeature.ApiKey,
|
||||
SecurityFeature.OAuth2_Implicit))
|
||||
SecurityFeature.OAuth2_Implicit
|
||||
))
|
||||
.excludeGlobalFeatures(
|
||||
GlobalFeature.XMLStructureDefinitions,
|
||||
GlobalFeature.Callbacks,
|
||||
GlobalFeature.LinkObjects,
|
||||
GlobalFeature.ParameterStyling,
|
||||
GlobalFeature.ParameterizedServer,
|
||||
GlobalFeature.MultiServer)
|
||||
GlobalFeature.MultiServer
|
||||
)
|
||||
.includeSchemaSupportFeatures(
|
||||
SchemaSupportFeature.Polymorphism)
|
||||
SchemaSupportFeature.Polymorphism
|
||||
)
|
||||
.excludeParameterFeatures(
|
||||
ParameterFeature.Cookie)
|
||||
ParameterFeature.Cookie
|
||||
)
|
||||
.includeClientModificationFeatures(
|
||||
ClientModificationFeature.BasePath,
|
||||
ClientModificationFeature.UserAgent));
|
||||
|
||||
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
|
||||
.stability(Stability.BETA)
|
||||
.build();
|
||||
ClientModificationFeature.UserAgent
|
||||
)
|
||||
);
|
||||
|
||||
supportsInheritance = true;
|
||||
|
||||
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata).stability(Stability.BETA).build();
|
||||
|
||||
// clear import mapping (from default generator) as crystal does not use it
|
||||
// at the moment
|
||||
importMapping.clear();
|
||||
@@ -130,19 +133,24 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
hideGenerationTimestamp = Boolean.TRUE;
|
||||
|
||||
// reserved word. Ref:
|
||||
// https://github.com/crystal-lang/crystal/wiki/Crystal-for-Rubyists#available-keywords
|
||||
// https://crystal-lang.org/reference/1.18/crystal_for_rubyists/index.html#available-keywords
|
||||
// https://crystal-lang.org/api/1.18.2/Reference.html
|
||||
reservedWords = new HashSet<>(
|
||||
Arrays.asList(
|
||||
"abstract", "annotation", "do", "if", "nil?", "select", "union",
|
||||
"alias", "else", "in", "of", "self", "unless",
|
||||
"as", "elsif", "include", "out", "sizeof", "until",
|
||||
"as?", "end", "instance", "sizeof", "pointerof", "struct", "verbatim",
|
||||
"asm", "ensure", "is_a?", "private", "super", "when",
|
||||
"begin", "enum", "lib", "protected", "then", "while",
|
||||
"break", "extend", "macro", "require", "true", "with",
|
||||
"case", "false", "module", "rescue", "type", "yield",
|
||||
"class", "for", "next", "responds_to?", "typeof",
|
||||
"def", "fun", "nil", "return", "uninitialized"));
|
||||
// language reserved words (keywords)
|
||||
"abstract", "do", "if", "nil?", "return", "uninitialized",
|
||||
"alias", "else", "in", "of", "select", "union",
|
||||
"as", "elsif", "include", "out", "self", "unless",
|
||||
"as?", "end", "instance_sizeof", "pointerof", "sizeof", "until",
|
||||
"asm", "ensure", "is_a?", "previous_def", "struct", "verbatim",
|
||||
"begin", "enum", "lib", "private", "super", "when",
|
||||
"break", "extend", "macro", "protected", "then", "while",
|
||||
"case", "false", "module", "require", "true", "with",
|
||||
"class", "for", "next", "rescue", "type", "yield",
|
||||
"def", "fun", "nil", "responds_to?", "typeof",
|
||||
// additional reserved words (methods)
|
||||
"annotation", "object_id"
|
||||
));
|
||||
|
||||
languageSpecificPrimitives.clear();
|
||||
languageSpecificPrimitives.add("String");
|
||||
@@ -174,8 +182,8 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
typeMapping.put("List", "Array");
|
||||
typeMapping.put("set", "Set");
|
||||
typeMapping.put("map", "Hash");
|
||||
typeMapping.put("object", "Object");
|
||||
typeMapping.put("AnyType", "Object");
|
||||
typeMapping.put("object", "JSON::Any");
|
||||
typeMapping.put("AnyType", "JSON::Any");
|
||||
typeMapping.put("file", "::File");
|
||||
typeMapping.put("binary", "String");
|
||||
typeMapping.put("ByteArray", "String");
|
||||
@@ -188,31 +196,18 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
primitiveTypes = new ArrayList<String>(typeMapping.values());
|
||||
|
||||
// remove modelPackage and apiPackage added by default
|
||||
cliOptions.removeIf(opt -> CodegenConstants.MODEL_PACKAGE.equals(opt.getOpt()) ||
|
||||
CodegenConstants.API_PACKAGE.equals(opt.getOpt()));
|
||||
cliOptions.removeIf(opt -> CodegenConstants.MODEL_PACKAGE.equals(opt.getOpt()) || CodegenConstants.API_PACKAGE.equals(opt.getOpt()));
|
||||
|
||||
cliOptions.add(new CliOption(SHARD_NAME, "shard name (e.g. twitter_client").defaultValue("openapi_client"));
|
||||
|
||||
cliOptions.add(new CliOption(MODULE_NAME, "module name (e.g. TwitterClient").defaultValue("OpenAPIClient"));
|
||||
|
||||
cliOptions.add(new CliOption(SHARD_VERSION, "shard version.").defaultValue("1.0.0"));
|
||||
|
||||
cliOptions.add(new CliOption(SHARD_LICENSE, "shard license.").defaultValue("unlicense"));
|
||||
|
||||
cliOptions.add(new CliOption(SHARD_HOMEPAGE, "shard homepage.").defaultValue("http://org.openapitools"));
|
||||
|
||||
cliOptions.add(new CliOption(SHARD_DESCRIPTION, "shard description.").defaultValue("This shard maps to a REST API"));
|
||||
|
||||
cliOptions.add(new CliOption(SHARD_AUTHOR, "shard author (only one is supported)."));
|
||||
|
||||
cliOptions.add(new CliOption(SHARD_AUTHOR_EMAIL, "shard author email (only one is supported)."));
|
||||
|
||||
cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP,
|
||||
CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC).defaultValue(Boolean.TRUE.toString()));
|
||||
|
||||
cliOptions.add(new CliOption(PARAMS_ENCODER,
|
||||
"params_encoder setting (e.g. Crest::NestedParamsEncoder, Crest::EnumeratedFlatParamsEncoder, Crest::ZeroEnumeratedFlatParamsEncoder").
|
||||
defaultValue("Crest::NestedParamsEncoder"));
|
||||
cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC).defaultValue(Boolean.TRUE.toString()));
|
||||
cliOptions.add(new CliOption(PARAMS_ENCODER, "params_encoder setting (e.g. Crest::NestedParamsEncoder, Crest::EnumeratedFlatParamsEncoder, Crest::ZeroEnumeratedFlatParamsEncoder").defaultValue("Crest::NestedParamsEncoder"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -220,51 +215,63 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
super.processOpts();
|
||||
|
||||
if (StringUtils.isEmpty(System.getenv("CRYSTAL_POST_PROCESS_FILE"))) {
|
||||
LOGGER.info(
|
||||
"Hint: Environment variable 'CRYSTAL_POST_PROCESS_FILE' (optional) not defined. E.g. to format the source code, please try 'export CRYSTAL_POST_PROCESS_FILE=\"/usr/local/bin/crystal tool format\"' (Linux/Mac)");
|
||||
LOGGER.info("Hint: Environment variable 'CRYSTAL_POST_PROCESS_FILE' (optional) not defined. E.g. to format the source code, please try 'export CRYSTAL_POST_PROCESS_FILE=\"/usr/local/bin/crystal tool format\"' (Linux/Mac)");
|
||||
} else if (!this.isEnablePostProcessFile()) {
|
||||
LOGGER.info("Warning: Environment variable 'CRYSTAL_POST_PROCESS_FILE' is set but file post-processing is not enabled. To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(SHARD_NAME)) {
|
||||
setShardName((String) additionalProperties.get(SHARD_NAME));
|
||||
} else {
|
||||
additionalProperties.put(SHARD_NAME, shardName);
|
||||
}
|
||||
additionalProperties.put(SHARD_NAME, shardName);
|
||||
|
||||
if (additionalProperties.containsKey(MODULE_NAME)) {
|
||||
setModuleName((String) additionalProperties.get(MODULE_NAME));
|
||||
} else {
|
||||
additionalProperties.put(MODULE_NAME, moduleName);
|
||||
}
|
||||
additionalProperties.put(MODULE_NAME, moduleName);
|
||||
|
||||
if (additionalProperties.containsKey(SHARD_VERSION)) {
|
||||
setShardVersion((String) additionalProperties.get(SHARD_VERSION));
|
||||
} else {
|
||||
// not set, pass the default value to template
|
||||
additionalProperties.put(SHARD_VERSION, shardVersion);
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(SHARD_LICENSE)) {
|
||||
setShardLicense((String) additionalProperties.get(SHARD_LICENSE));
|
||||
} else {
|
||||
additionalProperties.put(SHARD_LICENSE, shardLicense);
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(SHARD_HOMEPAGE)) {
|
||||
setShardHomepage((String) additionalProperties.get(SHARD_HOMEPAGE));
|
||||
} else {
|
||||
additionalProperties.put(SHARD_HOMEPAGE, shardHomepage);
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(SHARD_SUMMARY)) {
|
||||
setShardSummary((String) additionalProperties.get(SHARD_SUMMARY));
|
||||
} else {
|
||||
additionalProperties.put(SHARD_SUMMARY, shardSummary);
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(SHARD_DESCRIPTION)) {
|
||||
setShardDescription((String) additionalProperties.get(SHARD_DESCRIPTION));
|
||||
} else {
|
||||
additionalProperties.put(SHARD_DESCRIPTION, shardDescription);
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(SHARD_AUTHOR)) {
|
||||
setShardAuthor((String) additionalProperties.get(SHARD_AUTHOR));
|
||||
} else {
|
||||
additionalProperties.put(SHARD_AUTHOR, shardAuthor);
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(SHARD_AUTHOR_EMAIL)) {
|
||||
setShardAuthorEmail((String) additionalProperties.get(SHARD_AUTHOR_EMAIL));
|
||||
} else {
|
||||
additionalProperties.put(SHARD_AUTHOR_EMAIL, shardAuthorEmail);
|
||||
}
|
||||
|
||||
if (additionalProperties.containsKey(PARAMS_ENCODER)) {
|
||||
@@ -290,18 +297,14 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
|
||||
supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh"));
|
||||
supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore"));
|
||||
supportingFiles.add(new SupportingFile("travis.mustache", "", ".travis.yml"));
|
||||
supportingFiles.add(new SupportingFile("shard.mustache", "", "shard.yml"));
|
||||
|
||||
// crystal spec files
|
||||
supportingFiles.add(new SupportingFile("spec_helper.mustache", specFolder, "spec_helper.cr")
|
||||
.doNotOverwrite());
|
||||
supportingFiles.add(new SupportingFile("spec_helper.mustache", specFolder, "spec_helper.cr").doNotOverwrite());
|
||||
|
||||
// add lambda for mustache templates
|
||||
additionalProperties.put("lambdaPrefixWithHash", new PrefixWithHashLambda());
|
||||
additionalProperties.put("lambdaUppercase", new UppercaseLambda());
|
||||
additionalProperties.put("lambdaTitlecase", new TitlecaseLambda());
|
||||
|
||||
additionalProperties.put("lambdaPascalcase", new PascalCaseLambda());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -321,14 +324,12 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
|
||||
@Override
|
||||
public String apiFileFolder() {
|
||||
return outputFolder + File.separator + srcFolder + File.separator + shardName + File.separator
|
||||
+ apiPackage.replace("/", File.separator);
|
||||
return outputFolder + File.separator + srcFolder + File.separator + shardName + File.separator + apiPackage.replace("/", File.separator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String modelFileFolder() {
|
||||
return outputFolder + File.separator + srcFolder + File.separator + shardName + File.separator
|
||||
+ modelPackage.replace("/", File.separator);
|
||||
return outputFolder + File.separator + srcFolder + File.separator + shardName + File.separator + modelPackage.replace("/", File.separator);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -407,9 +408,9 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
|
||||
// model name starts with number
|
||||
if (modelName.matches("^\\d.*")) {
|
||||
LOGGER.warn("{} (model name starts with number) cannot be used as model name. Renamed to {}", modelName,
|
||||
camelize("model_" + modelName));
|
||||
modelName = "model_" + modelName; // e.g. 200Response => Model200Response (after camelize)
|
||||
LOGGER.warn("{} (model name starts with number) cannot be used as model name. Renamed to {}", modelName, camelize("model_" + modelName));
|
||||
// e.g. 200Response => Model200Response (after camelize)
|
||||
modelName = "model_" + modelName;
|
||||
}
|
||||
|
||||
// camelize the model name
|
||||
@@ -548,8 +549,7 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
|
||||
// operationId starts with a number
|
||||
if (operationId.matches("^\\d.*")) {
|
||||
LOGGER.warn("{} (starting with a number) cannot be used as method name. Renamed to {}", operationId,
|
||||
underscore(sanitizeName("call_" + operationId)));
|
||||
LOGGER.warn("{} (starting with a number) cannot be used as method name. Renamed to {}", operationId, underscore(sanitizeName("call_" + operationId)));
|
||||
operationId = "call_" + operationId;
|
||||
}
|
||||
|
||||
@@ -576,6 +576,7 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
if (isSkipOperationExample()) {
|
||||
return objs;
|
||||
}
|
||||
|
||||
OperationMap operations = objs.getOperations();
|
||||
HashMap<String, CodegenModel> modelMaps = ModelMap.toCodegenModelMap(allModels);
|
||||
HashMap<String, Integer> processedModelMaps = new HashMap<>();
|
||||
@@ -607,8 +608,7 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
return objs;
|
||||
}
|
||||
|
||||
private String constructExampleCode(CodegenParameter codegenParameter, HashMap<String, CodegenModel> modelMaps,
|
||||
HashMap<String, Integer> processedModelMap) {
|
||||
private String constructExampleCode(CodegenParameter codegenParameter, HashMap<String, CodegenModel> modelMaps, HashMap<String, Integer> processedModelMap) {
|
||||
if (codegenParameter.isArray) { // array
|
||||
if (codegenParameter.items == null) {
|
||||
return "[]";
|
||||
@@ -675,8 +675,7 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private String constructExampleCode(CodegenProperty codegenProperty, HashMap<String, CodegenModel> modelMaps,
|
||||
HashMap<String, Integer> processedModelMap) {
|
||||
private String constructExampleCode(CodegenProperty codegenProperty, HashMap<String, CodegenModel> modelMaps, HashMap<String, Integer> processedModelMap) {
|
||||
if (codegenProperty.isArray) { // array
|
||||
return "[" + constructExampleCode(codegenProperty.items, modelMaps, processedModelMap) + "]";
|
||||
} else if (codegenProperty.isMap) {
|
||||
@@ -743,8 +742,7 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private String constructExampleCode(CodegenModel codegenModel, HashMap<String, CodegenModel> modelMaps,
|
||||
HashMap<String, Integer> processedModelMap) {
|
||||
private String constructExampleCode(CodegenModel codegenModel, HashMap<String, CodegenModel> modelMaps, HashMap<String, Integer> processedModelMap) {
|
||||
// break infinite recursion. Return, in case a model is already processed in the
|
||||
// current context.
|
||||
String model = codegenModel.name;
|
||||
@@ -758,15 +756,24 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
throw new RuntimeException("Invalid count when constructing example: " + count);
|
||||
}
|
||||
} else if (codegenModel.isEnum) {
|
||||
List<Map<String, String>> enumVars = (List<Map<String, String>>) codegenModel.allowableValues
|
||||
.get("enumVars");
|
||||
List<Map<String, String>> enumVars = (List<Map<String, String>>) codegenModel.allowableValues.get("enumVars");
|
||||
return moduleName + "::" + codegenModel.classname + "::" + enumVars.get(0).get("name");
|
||||
} else if (codegenModel.oneOf != null && !codegenModel.oneOf.isEmpty()) {
|
||||
String subModel = (String) codegenModel.oneOf.toArray()[0];
|
||||
if (modelMaps.get(subModel) == null) {
|
||||
LOGGER.warn("Cannot find codegen for SubModel: {} (model: {})", subModel, model);
|
||||
return "";
|
||||
if (subModel.startsWith("Array(")) {
|
||||
subModel = StringUtils.removeEnd(subModel.substring(6), ")");
|
||||
if (modelMaps.get(subModel) == null) {
|
||||
LOGGER.warn("Cannot find codegen for SubModel: {} (model: {})", subModel, model);
|
||||
return "";
|
||||
} else {
|
||||
LOGGER.info("Found Array codegen for SubModel: {} (model: {})", subModel, model);
|
||||
String oneOf = "[" + constructExampleCode(modelMaps.get(subModel), modelMaps, processedModelMap) + "]";
|
||||
return oneOf;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOGGER.info("Found codegen for SubModel: {} (model: {})", subModel, model);
|
||||
String oneOf = constructExampleCode(modelMaps.get(subModel), modelMaps, processedModelMap);
|
||||
return oneOf;
|
||||
}
|
||||
@@ -781,7 +788,7 @@ public class CrystalClientCodegen extends DefaultCodegen {
|
||||
}
|
||||
String example = moduleName + "::" + toModelName(model) + ".new";
|
||||
if (!propertyExamples.isEmpty()) {
|
||||
example += "({" + StringUtils.join(propertyExamples, ", ") + "})";
|
||||
example += "(" + StringUtils.join(propertyExamples, ", ") + ")";
|
||||
}
|
||||
return example;
|
||||
}
|
||||
|
||||
@@ -446,10 +446,28 @@ public class GoClientCodegen extends AbstractGoCodegen {
|
||||
Object defaultValues = p.getDefault();
|
||||
if (defaultValues instanceof ArrayNode) {
|
||||
for (var value : (ArrayNode) defaultValues) {
|
||||
joinedDefaultValues.add(value.toString());
|
||||
if (value.isNull()) {
|
||||
joinedDefaultValues.add("nil");
|
||||
} else if (value.isTextual()) {
|
||||
joinedDefaultValues.add("\"" + escapeText(value.asText()) + "\"");
|
||||
} else {
|
||||
joinedDefaultValues.add(value.toString());
|
||||
}
|
||||
}
|
||||
return "{" + joinedDefaultValues + "}";
|
||||
} else if (defaultValues instanceof List<?>) {
|
||||
for (var value : (List<?>) defaultValues) {
|
||||
if (value == null) {
|
||||
joinedDefaultValues.add("nil");
|
||||
} else if (value instanceof String) {
|
||||
joinedDefaultValues.add("\"" + escapeText((String) value) + "\"");
|
||||
} else {
|
||||
joinedDefaultValues.add(value.toString());
|
||||
}
|
||||
}
|
||||
return "{" + joinedDefaultValues + "}";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return super.toDefaultValue(p);
|
||||
|
||||
@@ -458,10 +458,13 @@ public class NimClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
name = normalizeSchemaName(name);
|
||||
CodegenModel mdl = super.fromModel(name, schema);
|
||||
|
||||
// Detect integer enums - check both the schema type and the dataType
|
||||
// Detect numeric enums - check both the schema type and the dataType
|
||||
// Note: "number" type in OpenAPI can include integer values in enums
|
||||
if (mdl.isEnum) {
|
||||
String schemaType = schema != null ? schema.getType() : null;
|
||||
if ("integer".equals(schemaType) || "int".equals(mdl.dataType) || "int64".equals(mdl.dataType)) {
|
||||
if ("integer".equals(schemaType) || "number".equals(schemaType) ||
|
||||
"int".equals(mdl.dataType) || "int64".equals(mdl.dataType) ||
|
||||
"float".equals(mdl.dataType) || "float64".equals(mdl.dataType)) {
|
||||
mdl.vendorExtensions.put("x-is-integer-enum", true);
|
||||
}
|
||||
}
|
||||
@@ -606,22 +609,38 @@ public class NimClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
return objs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a schema reference to its target schema.
|
||||
* This is needed to properly detect nested maps/arrays when the schema is a $ref.
|
||||
*/
|
||||
private Schema resolveSchema(Schema schema) {
|
||||
if (schema != null && schema.get$ref() != null) {
|
||||
Schema resolved = ModelUtils.getReferencedSchema(this.openAPI, schema);
|
||||
return resolved != null ? resolved : schema;
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeDeclaration(Schema p) {
|
||||
if (ModelUtils.isArraySchema(p)) {
|
||||
Schema inner = ModelUtils.getSchemaItems(p);
|
||||
// Resolve the schema to check for nested maps/arrays - refs that point to map/array schemas
|
||||
Schema resolved = resolveSchema(p);
|
||||
|
||||
if (ModelUtils.isArraySchema(resolved)) {
|
||||
Schema inner = ModelUtils.getSchemaItems(resolved);
|
||||
if (inner == null) {
|
||||
return null;
|
||||
}
|
||||
return "seq[" + getTypeDeclaration(inner) + "]";
|
||||
} else if (ModelUtils.isMapSchema(p)) {
|
||||
Schema inner = ModelUtils.getAdditionalProperties(p);
|
||||
} else if (ModelUtils.isMapSchema(resolved)) {
|
||||
Schema inner = ModelUtils.getAdditionalProperties(resolved);
|
||||
if (inner == null) {
|
||||
inner = new StringSchema();
|
||||
}
|
||||
return "Table[string, " + getTypeDeclaration(inner) + "]";
|
||||
}
|
||||
|
||||
// For non-containers, use the original schema to preserve model names
|
||||
String schemaType = getSchemaType(p);
|
||||
if (typeMapping.containsKey(schemaType)) {
|
||||
return typeMapping.get(schemaType);
|
||||
@@ -719,10 +738,17 @@ public class NimClientCodegen extends DefaultCodegen implements CodegenConfig {
|
||||
|
||||
@Override
|
||||
public String toEnumVarName(String name, String datatype) {
|
||||
// Handle negative numbers by prefixing with "Neg" to avoid collisions
|
||||
// e.g., -1 and 1 would both become `1` without this, causing invalid syntax
|
||||
if (name.startsWith("-")) {
|
||||
name = "Neg" + name.substring(1);
|
||||
}
|
||||
|
||||
name = name.replace(" ", "_");
|
||||
name = StringUtils.camelize(name);
|
||||
|
||||
// starts with number or contains any character not allowed,see
|
||||
// starts with number or contains any character not allowed, see
|
||||
// https://nim-lang.org/docs/manual.html#lexical-analysis-identifiers-amp-keywords
|
||||
if (isValidIdentifier(name)) {
|
||||
return name;
|
||||
} else {
|
||||
|
||||
@@ -368,6 +368,45 @@ public class RustClientCodegen extends AbstractRustCodegen implements CodegenCon
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute documentation type for each property
|
||||
// This matches the actual generated code type, including HashSet for uniqueItems
|
||||
for (CodegenProperty cp : cm.vars) {
|
||||
String docType;
|
||||
|
||||
if (cp.datatypeWithEnum != null && !cp.datatypeWithEnum.isEmpty()) {
|
||||
// Use enum type if available (e.g., Vec<UniqueItemArray> instead of Vec<String>)
|
||||
docType = cp.datatypeWithEnum;
|
||||
} else {
|
||||
// Use regular dataType
|
||||
docType = cp.dataType;
|
||||
}
|
||||
|
||||
// Apply uniqueItems logic (matching model.mustache lines 139, 161)
|
||||
// Arrays with uniqueItems=true use HashSet instead of Vec in the generated code
|
||||
if (Boolean.TRUE.equals(cp.getUniqueItems()) && docType.startsWith("Vec<")) {
|
||||
docType = docType.replace("Vec<", "HashSet<");
|
||||
}
|
||||
|
||||
cp.vendorExtensions.put("x-doc-type", docType);
|
||||
|
||||
// Determine if this type should have a doc link
|
||||
// Only local models should link, not external types from std lib or crates
|
||||
boolean shouldLink = false;
|
||||
if (cp.complexType != null && !cp.complexType.isEmpty()) {
|
||||
// Check if it's an external type by looking for known prefixes
|
||||
String[] externalPrefixes = {"std::", "serde_json::", "uuid::", "chrono::", "url::"};
|
||||
boolean isExternal = false;
|
||||
for (String prefix : externalPrefixes) {
|
||||
if (cp.complexType.startsWith(prefix)) {
|
||||
isExternal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
shouldLink = !isExternal;
|
||||
}
|
||||
cp.vendorExtensions.put("x-should-link", shouldLink);
|
||||
}
|
||||
}
|
||||
// process enum in models
|
||||
return postProcessModelsEnum(objs);
|
||||
@@ -741,7 +780,7 @@ public class RustClientCodegen extends AbstractRustCodegen implements CodegenCon
|
||||
}
|
||||
|
||||
// If we use a file body parameter, we need to include the imports and crates for it
|
||||
// But they should be added only once per file
|
||||
// But they should be added only once per file
|
||||
for (var param: operation.bodyParams) {
|
||||
if (param.isFile && supportAsync && !useAsyncFileStream) {
|
||||
useAsyncFileStream = true;
|
||||
@@ -751,6 +790,18 @@ public class RustClientCodegen extends AbstractRustCodegen implements CodegenCon
|
||||
}
|
||||
}
|
||||
|
||||
// Also check form params for file uploads (multipart)
|
||||
if (!useAsyncFileStream) {
|
||||
for (var param: operation.formParams) {
|
||||
if (param.isFile && supportAsync) {
|
||||
useAsyncFileStream = true;
|
||||
additionalProperties.put("useAsyncFileStream", Boolean.TRUE);
|
||||
operation.vendorExtensions.put("useAsyncFileStream", Boolean.TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// http method verb conversion, depending on client library (e.g. Hyper: PUT => Put, Reqwest: PUT => put)
|
||||
if (HYPER_LIBRARY.equals(getLibrary())) {
|
||||
operation.httpMethod = StringUtils.camelize(operation.httpMethod.toLowerCase(Locale.ROOT));
|
||||
|
||||
@@ -84,7 +84,7 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
|
||||
public static final String NGPACKAGR_VERSION = "ngPackagrVersion";
|
||||
public static final String ZONEJS_VERSION = "zonejsVersion";
|
||||
|
||||
protected String ngVersion = "20.0.0";
|
||||
protected String ngVersion = "21.0.0";
|
||||
@Getter @Setter
|
||||
protected String npmRepository = null;
|
||||
@Setter(AccessLevel.PRIVATE) private boolean useSingleRequestParameter = false;
|
||||
@@ -170,7 +170,7 @@ public class TypeScriptAngularClientCodegen extends AbstractTypeScriptClientCode
|
||||
|
||||
@Override
|
||||
public String getHelp() {
|
||||
return "Generates a TypeScript Angular (9.x - 20.x) client library.";
|
||||
return "Generates a TypeScript Angular (9.x - 21.x) client library.";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.openapitools.codegen.templating.mustache;
|
||||
|
||||
import com.samskivert.mustache.Mustache;
|
||||
import com.samskivert.mustache.Template;
|
||||
import org.openapitools.codegen.utils.CamelizeOption;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
import static org.openapitools.codegen.utils.StringUtils.camelize;
|
||||
|
||||
/**
|
||||
* Converts text in a fragment to PascalCase.
|
||||
* <p>
|
||||
* Register:
|
||||
* <pre>
|
||||
* additionalProperties.put("pascalcase", new PascalCaseLambda());
|
||||
* </pre>
|
||||
* <p>
|
||||
* Use:
|
||||
* <pre>
|
||||
* {{#pascalcase}}{{name}}{{/pascalcase}}
|
||||
* </pre>
|
||||
*/
|
||||
public class PascalCaseLambda implements Mustache.Lambda {
|
||||
public PascalCaseLambda() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
|
||||
String text = fragment.execute();
|
||||
text = camelize(text);
|
||||
writer.write(text);
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,11 @@ public class ApiUtil {
|
||||
public static void setExampleResponse(NativeWebRequest req, String contentType, String example) {
|
||||
try {
|
||||
HttpServletResponse res = req.getNativeResponse(HttpServletResponse.class);
|
||||
res.setCharacterEncoding("UTF-8");
|
||||
res.addHeader("Content-Type", contentType);
|
||||
res.getWriter().print(example);
|
||||
if (res != null) {
|
||||
res.setCharacterEncoding("UTF-8");
|
||||
res.addHeader("Content-Type", contentType);
|
||||
res.getWriter().print(example);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ public {{>sealed}}class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}
|
||||
* Convert the given object to string with each line indented by 4 spaces
|
||||
* (except the first line).
|
||||
*/
|
||||
private String toIndentedString(Object o) {
|
||||
private String toIndentedString({{>nullableAnnotation}}Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
@@ -261,6 +261,23 @@ public:
|
||||
{{/isInherited}}
|
||||
|
||||
{{/vars}}
|
||||
{{#additionalPropertiesType}}
|
||||
|
||||
/// <summary>
|
||||
/// Get additional properties (properties not defined in the schema)
|
||||
/// </summary>
|
||||
std::map<utility::string_t, web::json::value> getAdditionalProperties() const;
|
||||
bool additionalPropertiesIsSet() const;
|
||||
void unsetAdditionalProperties();
|
||||
/// <summary>
|
||||
/// Set additional properties
|
||||
/// </summary>
|
||||
void setAdditionalProperties(const std::map<utility::string_t, web::json::value>& value);
|
||||
/// <summary>
|
||||
/// Add a single additional property
|
||||
/// </summary>
|
||||
void addAdditionalProperty(const utility::string_t& key, const web::json::value& value);
|
||||
{{/additionalPropertiesType}}
|
||||
|
||||
protected:
|
||||
{{#vars}}
|
||||
@@ -285,6 +302,10 @@ protected:
|
||||
{{/isInherited}}
|
||||
|
||||
{{/vars}}
|
||||
{{#additionalPropertiesType}}
|
||||
std::map<utility::string_t, web::json::value> m_AdditionalProperties;
|
||||
bool m_AdditionalPropertiesIsSet;
|
||||
{{/additionalPropertiesType}}
|
||||
};
|
||||
|
||||
{{/isEnum}}
|
||||
|
||||
@@ -207,6 +207,9 @@ void {{classname}}::setValue({{classname}}::e{{classname}} const value)
|
||||
{{/isNullable}}
|
||||
{{/isInherited}}
|
||||
{{/vars}}
|
||||
{{#additionalPropertiesType}}
|
||||
m_AdditionalPropertiesIsSet = false;
|
||||
{{/additionalPropertiesType}}
|
||||
}
|
||||
|
||||
{{classname}}::~{{classname}}()
|
||||
@@ -262,6 +265,16 @@ web::json::value {{classname}}::toJson() const
|
||||
{{/isNullable}}
|
||||
{{/isInherited}}
|
||||
{{/vars}}
|
||||
{{#additionalPropertiesType}}
|
||||
// Serialize additional properties
|
||||
if(m_AdditionalPropertiesIsSet)
|
||||
{
|
||||
for(const auto& item : m_AdditionalProperties)
|
||||
{
|
||||
val[item.first] = item.second;
|
||||
}
|
||||
}
|
||||
{{/additionalPropertiesType}}
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -295,6 +308,24 @@ bool {{classname}}::fromJson(const web::json::value& val)
|
||||
}
|
||||
{{/isInherited}}
|
||||
{{/vars}}
|
||||
{{#additionalPropertiesType}}
|
||||
// Capture additional properties (keys not defined in the schema)
|
||||
if(val.is_object())
|
||||
{
|
||||
for(const auto& item : val.as_object())
|
||||
{
|
||||
// Skip known properties
|
||||
{{#vars}}
|
||||
{{^isInherited}}
|
||||
if(item.first == utility::conversions::to_string_t(_XPLATSTR("{{baseName}}"))) continue;
|
||||
{{/isInherited}}
|
||||
{{/vars}}
|
||||
// This is an additional property
|
||||
m_AdditionalProperties[item.first] = item.second;
|
||||
m_AdditionalPropertiesIsSet = true;
|
||||
}
|
||||
}
|
||||
{{/additionalPropertiesType}}
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -515,6 +546,36 @@ void {{classname}}::unset{{name}}()
|
||||
{{/isNullable}}
|
||||
}
|
||||
{{/isInherited}}{{/vars}}
|
||||
{{#additionalPropertiesType}}
|
||||
|
||||
std::map<utility::string_t, web::json::value> {{classname}}::getAdditionalProperties() const
|
||||
{
|
||||
return m_AdditionalProperties;
|
||||
}
|
||||
|
||||
void {{classname}}::setAdditionalProperties(const std::map<utility::string_t, web::json::value>& value)
|
||||
{
|
||||
m_AdditionalProperties = value;
|
||||
m_AdditionalPropertiesIsSet = true;
|
||||
}
|
||||
|
||||
void {{classname}}::addAdditionalProperty(const utility::string_t& key, const web::json::value& value)
|
||||
{
|
||||
m_AdditionalProperties[key] = value;
|
||||
m_AdditionalPropertiesIsSet = true;
|
||||
}
|
||||
|
||||
bool {{classname}}::additionalPropertiesIsSet() const
|
||||
{
|
||||
return m_AdditionalPropertiesIsSet;
|
||||
}
|
||||
|
||||
void {{classname}}::unsetAdditionalProperties()
|
||||
{
|
||||
m_AdditionalProperties.clear();
|
||||
m_AdditionalPropertiesIsSet = false;
|
||||
}
|
||||
{{/additionalPropertiesType}}
|
||||
{{/isEnum}}
|
||||
{{/oneOf}}
|
||||
{{#modelNamespaceDeclarations}}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <cpprest/json.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -141,14 +141,14 @@ bourne::json
|
||||
}
|
||||
|
||||
{{#vars}}
|
||||
{{dataType}}{{#isContainer}}{{#isMap}}<string, string>{{/isMap}}{{^isMap}}<{{#items}}{{dataType}}{{/items}}>{{/isMap}}{{/isContainer}}
|
||||
{{#isMap}}{{{dataType}}}{{/isMap}}{{^isMap}}{{dataType}}{{#isArray}}<{{#items}}{{dataType}}{{/items}}>{{/isArray}}{{/isMap}}
|
||||
{{classname}}::{{getter}}()
|
||||
{
|
||||
return {{name}};
|
||||
}
|
||||
|
||||
void
|
||||
{{classname}}::{{setter}}({{dataType}} {{#isContainer}}{{#isMap}}<string, string>{{/isMap}}{{^isMap}}<{{#items}}{{dataType}}{{/items}}>{{/isMap}}{{/isContainer}} {{name}})
|
||||
{{classname}}::{{setter}}({{#isMap}}{{{dataType}}}{{/isMap}}{{^isMap}}{{dataType}}{{#isArray}}<{{#items}}{{dataType}}{{/items}}>{{/isArray}}{{/isMap}} {{name}})
|
||||
{
|
||||
this->{{name}} = {{name}};
|
||||
}
|
||||
|
||||
@@ -51,27 +51,32 @@ public:
|
||||
{{#vars}}
|
||||
/*! \brief Get {{{description}}}
|
||||
*/
|
||||
{{dataType}}{{#isContainer}}{{#isMap}}<std::string, std::string>{{/isMap}}{{^isMap}}<{{#items}}{{dataType}}{{/items}}>{{/isMap}}{{/isContainer}} {{getter}}();
|
||||
{{#isMap}}{{{dataType}}}{{/isMap}}{{^isMap}}{{dataType}}{{#isArray}}<{{#items}}{{dataType}}{{/items}}>{{/isArray}}{{/isMap}} {{getter}}();
|
||||
|
||||
/*! \brief Set {{{description}}}
|
||||
*/
|
||||
void {{setter}}({{dataType}} {{#isContainer}}{{#isMap}}<std::string, std::string>{{/isMap}}{{^isMap}}<{{#items}}{{dataType}}{{/items}}>{{/isMap}}{{/isContainer}} {{name}});
|
||||
void {{setter}}({{#isMap}}{{{dataType}}}{{/isMap}}{{^isMap}}{{dataType}}{{#isArray}}<{{#items}}{{dataType}}{{/items}}>{{/isArray}}{{/isMap}} {{name}});
|
||||
{{/vars}}
|
||||
|
||||
|
||||
private:
|
||||
{{#vars}}
|
||||
{{^isContainer}}
|
||||
{{#isMap}}
|
||||
{{{dataType}}} {{name}};
|
||||
{{/isMap}}
|
||||
{{^isMap}}
|
||||
{{#isArray}}
|
||||
{{dataType}}<{{#items}}{{dataType}}{{/items}}> {{name}};
|
||||
{{/isArray}}
|
||||
{{^isArray}}
|
||||
{{#isPrimitiveType}}
|
||||
{{dataType}} {{name}}{};
|
||||
{{/isPrimitiveType}}
|
||||
{{^isPrimitiveType}}
|
||||
{{dataType}} {{name}};
|
||||
{{/isPrimitiveType}}
|
||||
{{/isContainer}}
|
||||
{{#isContainer}}
|
||||
{{dataType}}{{#isMap}}<std::string, std::string>{{/isMap}}{{^isMap}}<{{#items}}{{dataType}}{{/items}}>{{/isMap}} {{name}};
|
||||
{{/isContainer}}
|
||||
{{/isArray}}
|
||||
{{/isMap}}
|
||||
{{/vars}}
|
||||
};
|
||||
{{/model}}
|
||||
|
||||
@@ -159,25 +159,25 @@ module {{moduleName}}
|
||||
# http body (model)
|
||||
post_body = {{#bodyParam}}{{{paramName}}}.to_json{{/bodyParam}}{{^bodyParam}}nil{{/bodyParam}}
|
||||
|
||||
# return_type
|
||||
return_type = {{#returnType}}"{{{.}}}"{{/returnType}}{{^returnType}}nil{{/returnType}}
|
||||
|
||||
# auth_names
|
||||
auth_names = {{#authMethods}}{{#-first}}[{{/-first}}"{{name}}"{{^-last}}, {{/-last}}{{#-last}}]{{/-last}}{{/authMethods}}{{^authMethods}}[] of String{{/authMethods}}
|
||||
|
||||
data, status_code, headers = @api_client.call_api(:{{httpMethod}},
|
||||
local_var_path,
|
||||
:"{{classname}}.{{operationId}}",
|
||||
return_type,
|
||||
post_body,
|
||||
auth_names,
|
||||
header_params,
|
||||
query_params,
|
||||
cookie_params,
|
||||
form_params)
|
||||
data, status_code, headers = @api_client.call_api(
|
||||
http_method: :{{httpMethod}},
|
||||
path: local_var_path,
|
||||
operation: :"{{classname}}.{{operationId}}",
|
||||
post_body: post_body,
|
||||
auth_names: auth_names,
|
||||
header_params: header_params,
|
||||
query_params: query_params,
|
||||
cookie_params: cookie_params,
|
||||
form_params: form_params
|
||||
)
|
||||
|
||||
if @api_client.config.debugging
|
||||
Log.debug {"API called: {{classname}}#{{operationId}}\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"}
|
||||
end
|
||||
|
||||
return {{#returnType}}{{{.}}}.from_json(data){{/returnType}}{{^returnType}}nil{{/returnType}}, status_code, headers
|
||||
end
|
||||
{{^-last}}
|
||||
|
||||
@@ -119,7 +119,7 @@ module {{moduleName}}
|
||||
#
|
||||
# @return [Array<(Object, Integer, Hash)>] an array of 3 elements:
|
||||
# the data deserialized from response body (could be nil), response status code and response headers.
|
||||
def call_api(http_method : Symbol, path : String, operation : Symbol, return_type : String?, post_body : String?, auth_names = [] of String, header_params = {} of String => String, query_params = {} of String => String, cookie_params = {} of String => String, form_params = {} of Symbol => (String | ::File))
|
||||
def call_api(http_method : Symbol, path : String, operation : Symbol, post_body : String?, auth_names = [] of String, header_params = {} of String => String, query_params = {} of String => String, cookie_params = {} of String => String, form_params = {} of Symbol => (String | ::File))
|
||||
#ssl_options = {
|
||||
# :ca_file => @config.ssl_ca_file,
|
||||
# :verify => @config.ssl_verify,
|
||||
@@ -139,8 +139,9 @@ module {{moduleName}}
|
||||
form_or_body = form_params
|
||||
end
|
||||
|
||||
request = Crest::Request.new(http_method,
|
||||
build_request_url(path, operation),
|
||||
request = Crest::Request.new(
|
||||
method: http_method,
|
||||
url: build_request_url(path, operation),
|
||||
params: query_params,
|
||||
headers: header_params,
|
||||
cookies: cookie_params,
|
||||
|
||||
@@ -1,78 +1,3 @@
|
||||
# Builds the object from hash
|
||||
# @param [Hash] attributes Model attributes in the form of hash
|
||||
# @return [Object] Returns the model itself
|
||||
def self.build_from_hash(attributes)
|
||||
new.build_from_hash(attributes)
|
||||
end
|
||||
|
||||
# Builds the object from hash
|
||||
# @param [Hash] attributes Model attributes in the form of hash
|
||||
# @return [Object] Returns the model itself
|
||||
def build_from_hash(attributes)
|
||||
return nil unless attributes.is_a?(Hash)
|
||||
{{#parent}}
|
||||
super(attributes)
|
||||
{{/parent}}
|
||||
self.class.openapi_types.each_pair do |key, type|
|
||||
if !attributes[self.class.attribute_map[key]]? && self.class.openapi_nullable.includes?(key)
|
||||
self.send("#{key}=", nil)
|
||||
elsif type =~ /\AArray<(.*)>/i
|
||||
# check to ensure the input is an array given that the attribute
|
||||
# is documented as an array but the input is not
|
||||
if attributes[self.class.attribute_map[key]].is_a?(Array)
|
||||
self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) })
|
||||
end
|
||||
elsif !attributes[self.class.attribute_map[key]].nil?
|
||||
self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
|
||||
end
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Deserializes the data based on type
|
||||
# @param string type Data type
|
||||
# @param string value Value to be deserialized
|
||||
# @return [Object] Deserialized data
|
||||
def _deserialize(type, value)
|
||||
case type.to_sym
|
||||
when :Time
|
||||
Time.parse(value)
|
||||
when :Date
|
||||
Date.parse(value)
|
||||
when :String
|
||||
value.to_s
|
||||
when :Integer
|
||||
value.to_i
|
||||
when :Float
|
||||
value.to_f
|
||||
when :Boolean
|
||||
if value.to_s =~ /\A(true|t|yes|y|1)\z/i
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
when :Object
|
||||
# generic object (usually a Hash), return directly
|
||||
value
|
||||
when /\AArray<(?<inner_type>.+)>\z/
|
||||
inner_type = Regexp.last_match[:inner_type]
|
||||
value.map { |v| _deserialize(inner_type, v) }
|
||||
when /\AHash<(?<k_type>.+?), (?<v_type>.+)>\z/
|
||||
k_type = Regexp.last_match[:k_type]
|
||||
v_type = Regexp.last_match[:v_type]
|
||||
({} of Symbol => String).tap do |hash|
|
||||
value.each do |k, v|
|
||||
hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
|
||||
end
|
||||
end
|
||||
else # model
|
||||
# models (e.g. Pet) or oneOf
|
||||
klass = {{moduleName}}.const_get(type)
|
||||
klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value)
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the string representation of the object
|
||||
# @return [String] String presentation of the object
|
||||
def to_s
|
||||
@@ -100,6 +25,8 @@
|
||||
# @param [Object] value Any valid value
|
||||
# @return [Hash] Returns the value in the form of hash
|
||||
private def _to_h(value)
|
||||
return nil if value.nil?
|
||||
|
||||
if value.is_a?(Hash)
|
||||
hash = NetboxClient::RecursiveHash.new
|
||||
value.each { |k, v| hash[k] = _to_h(v) }
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
|
||||
|
||||
require "big"
|
||||
require "json"
|
||||
require "yaml"
|
||||
require "time"
|
||||
|
||||
module {{moduleName}}
|
||||
{{#models}}
|
||||
{{#model}}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
{{#vars}}
|
||||
{{#isEnum}}
|
||||
{{^isContainer}}
|
||||
class EnumAttributeValidatorFor{{#lambdaTitlecase}}{{{name}}}{{/lambdaTitlecase}} < EnumAttributeValidator
|
||||
class EnumAttributeValidatorFor{{#lambdaPascalcase}}{{{name}}}{{/lambdaPascalcase}} < EnumAttributeValidator
|
||||
@attribute : String
|
||||
@allowable_values : Array(Int32 | Int64 | Float32 | Float64 | String)
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
{{#vars}}
|
||||
{{#isEnum}}
|
||||
{{^isContainer}}
|
||||
{{{name}}}_validator = EnumAttributeValidatorFor{{#lambdaTitlecase}}{{{name}}}{{/lambdaTitlecase}}.new
|
||||
{{{name}}}_validator = EnumAttributeValidatorFor{{#lambdaPascalcase}}{{{name}}}{{/lambdaPascalcase}}.new
|
||||
if !{{{name}}}_validator.valid?(@{{{name}}})
|
||||
message = {{{name}}}_validator.message
|
||||
invalid_properties.push(message)
|
||||
@@ -181,7 +181,7 @@
|
||||
{{#vars}}
|
||||
{{#isEnum}}
|
||||
{{^isContainer}}
|
||||
{{{name}}}_validator = EnumAttributeValidatorFor{{#lambdaTitlecase}}{{{name}}}{{/lambdaTitlecase}}.new
|
||||
{{{name}}}_validator = EnumAttributeValidatorFor{{#lambdaPascalcase}}{{{name}}}{{/lambdaPascalcase}}.new
|
||||
return false unless {{{name}}}_validator.valid?(@{{{name}}})
|
||||
{{/isContainer}}
|
||||
{{/isEnum}}
|
||||
@@ -234,7 +234,7 @@
|
||||
# Custom attribute writer method checking allowed values (enum).
|
||||
# @param [Object] {{{name}}} Object to be assigned
|
||||
def {{{name}}}=({{{name}}})
|
||||
validator = EnumAttributeValidatorFor{{#lambdaTitlecase}}{{{name}}}{{/lambdaTitlecase}}.new
|
||||
validator = EnumAttributeValidatorFor{{#lambdaPascalcase}}{{{name}}}{{/lambdaPascalcase}}.new
|
||||
unless validator.valid?({{{name}}})
|
||||
raise ArgumentError.new(validator.message)
|
||||
end
|
||||
|
||||
@@ -1,135 +1,104 @@
|
||||
{{#description}}
|
||||
# {{{.}}}
|
||||
{{/description}}
|
||||
module {{classname}}
|
||||
class {{classname}}
|
||||
include JSON::Serializable
|
||||
include YAML::Serializable
|
||||
|
||||
class SchemaMismatchError < Exception
|
||||
end
|
||||
|
||||
{{#oneOf}}
|
||||
{{#-first}}
|
||||
# List of class defined in oneOf (OpenAPI v3)
|
||||
def self.openapi_one_of
|
||||
[
|
||||
{{/-first}}
|
||||
:"{{{.}}}"{{^-last}},{{/-last}}
|
||||
{{{.}}}{{^-last}},{{/-last}}
|
||||
{{#-last}}
|
||||
]
|
||||
end
|
||||
|
||||
{{/-last}}
|
||||
{{/oneOf}}
|
||||
|
||||
{{#discriminator}}
|
||||
{{#propertyName}}
|
||||
# Discriminator's property name (OpenAPI v3)
|
||||
def self.openapi_discriminator_name
|
||||
:"{{{.}}}"
|
||||
end
|
||||
|
||||
{{/propertyName}}
|
||||
{{#mappedModels}}
|
||||
{{#-first}}
|
||||
# Discriminator's mapping (OpenAPI v3)
|
||||
def self.openapi_discriminator_mapping
|
||||
{
|
||||
{{/-first}}
|
||||
:"{{{mappingName}}}" => :"{{{modelName}}}"{{^-last}},{{/-last}}
|
||||
{{#-last}}
|
||||
}
|
||||
end
|
||||
|
||||
{{/-last}}
|
||||
{{/mappedModels}}
|
||||
use_yaml_discriminator {{#propertyName}}"{{{.}}}"{{/propertyName}}, {
|
||||
{{#mappedModels}}{{{mappingName}}}: {{{modelName}}}{{^-last}},{{/-last}}{{/mappedModels}}
|
||||
}
|
||||
{{/discriminator}}
|
||||
# Builds the object
|
||||
# @param [Mixed] Data to be matched against the list of oneOf items
|
||||
# @return [Object] Returns the model or the data itself
|
||||
|
||||
def self.build(data)
|
||||
{{#discriminator}}
|
||||
discriminator_value = data[openapi_discriminator_name]
|
||||
return nil unless discriminator_value
|
||||
{{#mappedModels}}
|
||||
{{#-first}}
|
||||
|
||||
klass = openapi_discriminator_mapping[discriminator_value.to_sym]
|
||||
return nil unless klass
|
||||
|
||||
{{moduleName}}.const_get(klass).build_from_hash(data)
|
||||
{{/-first}}
|
||||
{{/mappedModels}}
|
||||
{{^mappedModels}}
|
||||
{{moduleName}}.const_get(discriminator_value).build_from_hash(data)
|
||||
{{/mappedModels}}
|
||||
{{/discriminator}}
|
||||
{{^discriminator}}
|
||||
# Go through the list of oneOf items and attempt to identify the appropriate one.
|
||||
# Note:
|
||||
# - We do not attempt to check whether exactly one item matches.
|
||||
# - No advanced validation of types in some cases (e.g. "x: { type: string }" will happily match { x: 123 })
|
||||
# due to the way the deserialization is made in the base_object template (it just casts without verifying).
|
||||
# - TODO: scalar values are de facto behaving as if they were nullable.
|
||||
# - TODO: logging when debugging is set.
|
||||
openapi_one_of.each do |klass|
|
||||
begin
|
||||
next if klass == :AnyType # "nullable: true"
|
||||
typed_data = find_and_cast_into_type(klass, data)
|
||||
return typed_data if typed_data
|
||||
rescue # rescue all errors so we keep iterating even if the current item lookup raises
|
||||
rescue ex
|
||||
# rescue all errors so we keep iterating even if the current item lookup raises
|
||||
Log.trace { ex.message }
|
||||
end
|
||||
end
|
||||
|
||||
openapi_one_of.includes?(:AnyType) ? data : nil
|
||||
{{/discriminator}}
|
||||
nil
|
||||
end
|
||||
{{^discriminator}}
|
||||
|
||||
SchemaMismatchError = Class.new(StandardError)
|
||||
|
||||
# Note: 'File' is missing here because in the regular case we get the data _after_ a call to JSON.parse.
|
||||
private def self.find_and_cast_into_type(klass, data)
|
||||
{{#oneOf}}
|
||||
private def self.find_and_cast_into_type(klass : {{{.}}}.class, data)
|
||||
return if data.nil?
|
||||
|
||||
begin
|
||||
case klass.to_s
|
||||
when "Boolean"
|
||||
return data if data.instance_of?(TrueClass) || data.instance_of?(FalseClass)
|
||||
when "Float"
|
||||
return data if data.instance_of?(Float)
|
||||
when "Integer"
|
||||
return data if data.instance_of?(Integer)
|
||||
when "Time"
|
||||
return Time.parse(data)
|
||||
when "Date"
|
||||
return Date.parse(data)
|
||||
when "String"
|
||||
return data if data.instance_of?(String)
|
||||
when "Object" # "type: object"
|
||||
return data if data.instance_of?(Hash)
|
||||
when /\AArray<(?<sub_type>.+)>\z/ # "type: array"
|
||||
if data.instance_of?(Array)
|
||||
sub_type = Regexp.last_match[:sub_type]
|
||||
return data.map { |item| find_and_cast_into_type(sub_type, item) }
|
||||
end
|
||||
when /\AHash<String, (?<sub_type>.+)>\z/ # "type: object" with "additionalProperties: { ... }"
|
||||
if data.instance_of?(Hash) && data.keys.all? { |k| k.instance_of?(Symbol) || k.instance_of?(String) }
|
||||
sub_type = Regexp.last_match[:sub_type]
|
||||
return data.each_with_object({} of String | Symbol => Bool | Float | Integer | Time | Date | String | Array | Hash) { |(k, v), hsh| hsh[k] = find_and_cast_into_type(sub_type, v) }
|
||||
end
|
||||
else # model
|
||||
const = {{moduleName}}.const_get(klass)
|
||||
if const
|
||||
if const.respond_to?(:openapi_one_of) # nested oneOf model
|
||||
model = const.build(data)
|
||||
return model if model
|
||||
else
|
||||
# raise if data contains keys that are not known to the model
|
||||
raise unless (data.keys - const.acceptable_attributes).empty?
|
||||
model = const.build_from_hash(data)
|
||||
return model if model && model.valid?
|
||||
end
|
||||
end
|
||||
end
|
||||
Log.trace { "INSPECTING DATA" }
|
||||
Log.trace { data.inspect }
|
||||
|
||||
raise # if no match by now, raise
|
||||
rescue
|
||||
raise SchemaMismatchError, "#{data} doesn't match the #{klass} type"
|
||||
case data
|
||||
when NetboxClient::RecursiveHash
|
||||
if value = cast_value(array_data: false, array_class: array_class?(klass), klass: klass, data: data)
|
||||
return new(value)
|
||||
end
|
||||
when Array(NetboxClient::RecursiveHash)
|
||||
if value = cast_value(array_data: true, array_class: array_class?(klass), klass: klass, data: data)
|
||||
return new(value)
|
||||
end
|
||||
else
|
||||
raise SchemaMismatchError.new("#{data} doesn't match the #{klass} type")
|
||||
end
|
||||
end
|
||||
{{/oneOf}}
|
||||
|
||||
private def self.cast_value(array_data : Bool, array_class : Bool, klass, data)
|
||||
if array_class == true && array_data == true
|
||||
Log.debug { "Building array of classes: #{klass} / #{data}" }
|
||||
|
||||
klass.from_json(data.to_json)
|
||||
elsif array_class == false && array_data == false
|
||||
Log.debug { "Building single class: #{klass} / #{data}" }
|
||||
|
||||
klass.from_json(data.to_json)
|
||||
end
|
||||
end
|
||||
|
||||
private def self.array_class?(klass)
|
||||
klass.name.starts_with?("Array(")
|
||||
end
|
||||
|
||||
{{#oneOf}}
|
||||
def initialize(@value : {{{.}}})
|
||||
end
|
||||
|
||||
{{/oneOf}}
|
||||
|
||||
delegate :to_yaml, to: @value
|
||||
delegate :to_json, to: @value
|
||||
|
||||
def to_any_h
|
||||
{"value" => to_h}
|
||||
end
|
||||
|
||||
def to_h
|
||||
val = @value
|
||||
if val.is_a?(Int32)
|
||||
val
|
||||
else
|
||||
val.to_h
|
||||
end
|
||||
end
|
||||
{{/discriminator}}
|
||||
end
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
name: {{{shardName}}}
|
||||
|
||||
version: {{{shardVersion}}}
|
||||
|
||||
authors:
|
||||
- {{{shardAuthors}}}
|
||||
|
||||
description: |
|
||||
- {{{ shardDescription}}}
|
||||
|
||||
crystal: ">= 0.35.1"
|
||||
|
||||
dependencies:
|
||||
any_hash:
|
||||
github: Sija/any_hash.cr
|
||||
@@ -13,9 +18,6 @@ dependencies:
|
||||
version: ~> 1.3.13
|
||||
|
||||
development_dependencies:
|
||||
kemal:
|
||||
github: kemalcr/kemal
|
||||
version: ~>1.5.0
|
||||
ameba:
|
||||
github: crystal-ameba/ameba
|
||||
spectator:
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
|
||||
|
||||
# Dependencies
|
||||
# Stdlib dependencies
|
||||
require "big"
|
||||
require "json"
|
||||
require "log"
|
||||
require "time"
|
||||
require "yaml"
|
||||
|
||||
# External dependencies
|
||||
require "any_hash"
|
||||
require "crest"
|
||||
require "log"
|
||||
|
||||
module {{moduleName}}
|
||||
Log = ::Log.for("{{moduleName}}") # => Log for {{moduleName}} source
|
||||
|
||||
@@ -2,14 +2,4 @@
|
||||
|
||||
# load modules
|
||||
require "spectator"
|
||||
require "json"
|
||||
require "time"
|
||||
require "../src/{{{shardName}}}"
|
||||
|
||||
def assert_compilation_error(path : String, message : String) : Nil
|
||||
buffer = IO::Memory.new
|
||||
result = Process.run("crystal", ["run", "--no-color", "--no-codegen", path], error: buffer)
|
||||
result.success?.should be_false
|
||||
buffer.to_s.should contain message
|
||||
buffer.close
|
||||
end
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}}
|
||||
|
||||
language: crystal
|
||||
|
||||
script:
|
||||
- crystal spec
|
||||
# uncomment below to check the code format
|
||||
# - crystal tool format --check
|
||||
@@ -85,7 +85,8 @@ namespace {{packageName}}.{{clientPackage}}
|
||||
}
|
||||
}
|
||||
|
||||
internal override async System.Threading.Tasks.ValueTask<TTokenBase> GetAsync(string header = "", System.Threading.CancellationToken cancellation = default{{^netstandard20OrLater}}(global::System.Threading.CancellationToken){{/netstandard20OrLater}})
|
||||
/// <inheritdoc/>
|
||||
protected internal override async System.Threading.Tasks.ValueTask<TTokenBase> GetAsync(string header = "", System.Threading.CancellationToken cancellation = default{{^netstandard20OrLater}}(global::System.Threading.CancellationToken){{/netstandard20OrLater}})
|
||||
{
|
||||
if (!AvailableTokens.TryGetValue(header, out global::System.Threading.Channels.Channel<TTokenBase>{{nrt?}} tokens))
|
||||
throw new KeyNotFoundException($"Could not locate a token for header '{header}'.");
|
||||
|
||||
@@ -22,7 +22,12 @@ namespace {{packageName}}
|
||||
/// </summary>
|
||||
protected TTokenBase[] _tokens;
|
||||
|
||||
internal abstract System.Threading.Tasks.ValueTask<TTokenBase> GetAsync(string header = "", System.Threading.CancellationToken cancellation = default{{^netstandard20OrLater}}(global::System.Threading.CancellationToken){{/netstandard20OrLater}});
|
||||
/// <summary>
|
||||
/// Gets an authentication token to be used in request authorization.
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <param name="cancellation"></param>
|
||||
protected internal abstract System.Threading.Tasks.ValueTask<TTokenBase> GetAsync(string header = "", System.Threading.CancellationToken cancellation = default{{^netstandard20OrLater}}(global::System.Threading.CancellationToken){{/netstandard20OrLater}});
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a TokenProvider.
|
||||
@@ -31,9 +36,6 @@ namespace {{packageName}}
|
||||
public TokenProvider(IEnumerable<TTokenBase> tokens)
|
||||
{
|
||||
_tokens = tokens.ToArray();
|
||||
|
||||
if (_tokens.Length == 0)
|
||||
throw new ArgumentException("You did not provide any tokens.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,16 +217,16 @@ func (a *{{{classname}}}Service) {{nickname}}Execute(r {{#structPrefix}}{{&class
|
||||
parameterAddToHeaderOrQuery(localVarQueryParams, "{{{baseName}}}", r.{{paramName}}, "{{style}}", "{{collectionFormat}}")
|
||||
{{/isCollectionFormatMulti}}
|
||||
{{#defaultValue}}} else {
|
||||
{{#isArray}}
|
||||
var defaultValue {{{dataType}}} = {{{dataType}}}{{{.}}}
|
||||
parameterAddToHeaderOrQuery(localVarQueryParams, "{{{baseName}}}", defaultValue, "{{style}}", "{{collectionFormat}}")
|
||||
r.{{paramName}} = &defaultValue
|
||||
{{/isArray}}
|
||||
{{^isArray}}
|
||||
var defaultValue {{{dataType}}} = {{{.}}}
|
||||
parameterAddToHeaderOrQuery(localVarQueryParams, "{{{baseName}}}", defaultValue, "{{style}}", "{{collectionFormat}}")
|
||||
r.{{paramName}} = &defaultValue
|
||||
{{/isArray}}
|
||||
{{#isArray}}
|
||||
var defaultValue {{{dataType}}} = {{{dataType}}}{{{.}}}
|
||||
parameterAddToHeaderOrQuery(localVarQueryParams, "{{{baseName}}}", defaultValue, "{{style}}", "{{collectionFormat}}")
|
||||
r.{{paramName}} = &defaultValue
|
||||
{{/isArray}}
|
||||
{{^isArray}}
|
||||
var defaultValue {{{dataType}}} = {{{.}}}
|
||||
parameterAddToHeaderOrQuery(localVarQueryParams, "{{{baseName}}}", defaultValue, "{{style}}", "{{collectionFormat}}")
|
||||
r.{{paramName}} = &defaultValue
|
||||
{{/isArray}}
|
||||
{{/defaultValue}}}
|
||||
{{/required}}
|
||||
{{/queryParams}}
|
||||
|
||||
@@ -592,10 +592,7 @@ func addFile(w *multipart.Writer, fieldName, path string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
part, err := w.CreateFormFile(fieldName, filepath.Base(path))
|
||||
if err != nil {
|
||||
|
||||
@@ -108,14 +108,16 @@ kotlin {
|
||||
explicitApi()
|
||||
}
|
||||
{{/explicitApi}}
|
||||
{{#jvm-spring-webclient}}{{#useSpringBoot3}}
|
||||
{{#jvm-spring-webclient}}
|
||||
{{#useSpringBoot3}}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(17))
|
||||
}
|
||||
}
|
||||
{{/useSpringBoot3}}{{/jvm-spring-webclient}}
|
||||
{{/useSpringBoot3}}
|
||||
{{/jvm-spring-webclient}}
|
||||
{{#jvm-spring-restclient}}
|
||||
|
||||
kotlin {
|
||||
@@ -219,7 +221,6 @@ dependencies {
|
||||
{{/jackson}}
|
||||
implementation "com.squareup.retrofit2:converter-scalars:$retrofitVersion"
|
||||
{{/jvm-retrofit2}}
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
{{#jvm-vertx}}
|
||||
implementation "io.vertx:vertx-web-client:$vertx_version"
|
||||
implementation "io.vertx:vertx-core:$vertx_version"
|
||||
@@ -229,6 +230,10 @@ dependencies {
|
||||
implementation "io.vertx:vertx-lang-kotlin-coroutines:$vertx_version"
|
||||
{{/useCoroutines}}
|
||||
{{/jvm-vertx}}
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
{{#jvm-spring}}
|
||||
testImplementation "org.springframework.boot:spring-boot-test:$spring_boot_version"
|
||||
{{/jvm-spring}}
|
||||
}
|
||||
{{#kotlinx_serialization}}
|
||||
|
||||
|
||||
@@ -106,14 +106,34 @@ import kotlinx.serialization.*
|
||||
/**
|
||||
* Returns a valid [{{classname}}] for [data], null otherwise.
|
||||
*/
|
||||
{{#jackson}}@JvmStatic
|
||||
@JsonCreator
|
||||
{{/jackson}}{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}fun decode(data: kotlin.Any?): {{classname}}? = data?.let {
|
||||
{{^jackson}}
|
||||
{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}fun decode(data: kotlin.Any?): {{classname}}? = data?.let {
|
||||
val normalizedData = "$it".lowercase()
|
||||
values().firstOrNull { value ->
|
||||
it == value || normalizedData == "$value".lowercase()
|
||||
}
|
||||
}
|
||||
{{/jackson}}
|
||||
{{#jackson}}
|
||||
@JvmStatic
|
||||
@JsonCreator
|
||||
{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}fun decode(data: kotlin.Any?): {{classname}}{{#isNullable}}?{{/isNullable}} {
|
||||
if (data == null) {
|
||||
{{#isNullable}}
|
||||
return null
|
||||
{{/isNullable}}
|
||||
{{^isNullable}}
|
||||
throw IllegalArgumentException("Value for {{classname}} cannot be null")
|
||||
{{/isNullable}}
|
||||
}
|
||||
val normalizedData = "$data".lowercase()
|
||||
return values().firstOrNull { value ->
|
||||
data == value || normalizedData == "$value".lowercase()
|
||||
}{{#isNullable}}{{/isNullable}}{{^isNullable}}{{#enumUnknownDefaultCase}}
|
||||
?: {{#allowableValues}}{{#enumVars}}{{#-last}}{{&name}}{{/-last}}{{/enumVars}}{{/allowableValues}}{{/enumUnknownDefaultCase}}{{^enumUnknownDefaultCase}}
|
||||
?: throw IllegalArgumentException("Unknown {{classname}} value: $data"){{/enumUnknownDefaultCase}}{{/isNullable}}
|
||||
}
|
||||
{{/jackson}}
|
||||
}
|
||||
}
|
||||
{{#kotlinx_serialization}}{{#enumUnknownDefaultCase}}
|
||||
|
||||
@@ -4,9 +4,8 @@ import org.springframework.core.ParameterizedTypeReference
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.client.RestClient
|
||||
import org.springframework.web.util.UriComponentsBuilder
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.util.LinkedMultiValueMap
|
||||
|
||||
{{^nonPublicApi}}{{#explicitApi}}public {{/explicitApi}}{{/nonPublicApi}}open class ApiClient(protected val client: RestClient) {
|
||||
@@ -36,13 +35,12 @@ import org.springframework.util.LinkedMultiValueMap
|
||||
private fun <I> RestClient.method(requestConfig: RequestConfig<I>)=
|
||||
method(HttpMethod.valueOf(requestConfig.method.name))
|
||||
|
||||
private fun <I> RestClient.RequestBodyUriSpec.uri(requestConfig: RequestConfig<I>): RestClient.RequestBodySpec {
|
||||
val uriComponentsBuilder = UriComponentsBuilder.fromPath(requestConfig.path)
|
||||
requestConfig.query.forEach { key, values ->
|
||||
uriComponentsBuilder.queryParam(key, "{$key}")
|
||||
private fun <I> RestClient.RequestBodyUriSpec.uri(requestConfig: RequestConfig<I>) =
|
||||
uri(requestConfig.path) { builder ->
|
||||
builder
|
||||
.queryParams(LinkedMultiValueMap(requestConfig.query))
|
||||
.build(requestConfig.params)
|
||||
}
|
||||
return uri(uriComponentsBuilder.encode().buildAndExpand(requestConfig.query + requestConfig.params).toUri())
|
||||
}
|
||||
|
||||
private fun <I> RestClient.RequestBodySpec.headers(requestConfig: RequestConfig<I>) =
|
||||
apply { requestConfig.headers.forEach { (name, value) -> header(name, value) } }
|
||||
|
||||
@@ -30,9 +30,6 @@ import org.springframework.validation.annotation.Validated
|
||||
{{/useBeanValidation}}
|
||||
import org.springframework.web.context.request.NativeWebRequest
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
{{#useRequestMappingOnController}}
|
||||
import {{#apiPackage}}{{.}}.{{/apiPackage}}{{classname}}Controller.Companion.BASE_PATH
|
||||
{{/useRequestMappingOnController}}
|
||||
|
||||
{{#useBeanValidation}}
|
||||
import {{javaxPackage}}.validation.Valid
|
||||
@@ -60,9 +57,7 @@ import kotlin.collections.Map
|
||||
@Api(value = "{{{baseName}}}", description = "The {{{baseName}}} API")
|
||||
{{/swagger1AnnotationLibrary}}
|
||||
{{#useRequestMappingOnController}}
|
||||
{{=<% %>=}}
|
||||
@RequestMapping("\${openapi.<%title%>.base-path:\${api.base-path:$BASE_PATH}}")
|
||||
<%={{ }}=%>
|
||||
@RequestMapping("\${api.base-path:{{contextPath}}}")
|
||||
{{/useRequestMappingOnController}}
|
||||
{{#operations}}
|
||||
class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) val service: {{classname}}Service{{/serviceInterface}}) {
|
||||
|
||||
@@ -3,17 +3,12 @@ package {{package}}
|
||||
import org.springframework.stereotype.Controller
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import java.util.Optional
|
||||
{{#useRequestMappingOnController}}
|
||||
import {{#apiPackage}}{{.}}.{{/apiPackage}}{{classname}}Controller.Companion.BASE_PATH
|
||||
{{/useRequestMappingOnController}}
|
||||
|
||||
{{>generatedAnnotation}}
|
||||
|
||||
@Controller{{#beanQualifiers}}("{{package}}.{{classname}}Controller"){{/beanQualifiers}}
|
||||
{{#useRequestMappingOnController}}
|
||||
{{=<% %>=}}
|
||||
@RequestMapping("\${openapi.<%title%>.base-path:\${api.base-path:$BASE_PATH}}")
|
||||
<%={{ }}=%>
|
||||
@RequestMapping("\${api.base-path:{{contextPath}}}")
|
||||
{{/useRequestMappingOnController}}
|
||||
{{#operations}}
|
||||
class {{classname}}Controller(
|
||||
|
||||
@@ -35,9 +35,6 @@ import org.springframework.validation.annotation.Validated
|
||||
{{/useBeanValidation}}
|
||||
import org.springframework.web.context.request.NativeWebRequest
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
{{#useRequestMappingOnInterface}}
|
||||
import {{#apiPackage}}{{.}}.{{/apiPackage}}{{classname}}.Companion.BASE_PATH
|
||||
{{/useRequestMappingOnInterface}}
|
||||
|
||||
{{#useBeanValidation}}
|
||||
import {{javaxPackage}}.validation.constraints.DecimalMax
|
||||
@@ -67,9 +64,7 @@ import kotlin.collections.Map
|
||||
@Api(value = "{{{baseName}}}", description = "The {{{baseName}}} API")
|
||||
{{/swagger1AnnotationLibrary}}
|
||||
{{#useRequestMappingOnInterface}}
|
||||
{{=<% %>=}}
|
||||
@RequestMapping("\${openapi.<%title%>.base-path:\${api.base-path:$BASE_PATH}}")
|
||||
<%={{ }}=%>
|
||||
@RequestMapping("\${api.base-path:{{contextPath}}}")
|
||||
{{/useRequestMappingOnInterface}}
|
||||
{{#operations}}
|
||||
interface {{classname}} {
|
||||
|
||||
@@ -6,9 +6,6 @@ package {{package}}
|
||||
|
||||
{{#imports}}import {{import}}
|
||||
{{/imports}}
|
||||
{{#useRequestMappingOnInterface}}
|
||||
import {{#apiPackage}}{{.}}.{{/apiPackage}}{{classname}}.Companion.BASE_PATH
|
||||
{{/useRequestMappingOnInterface}}
|
||||
|
||||
{{#swagger2AnnotationLibrary}}
|
||||
import io.swagger.v3.oas.annotations.*
|
||||
@@ -51,9 +48,7 @@ import kotlin.collections.List
|
||||
import kotlin.collections.Map
|
||||
|
||||
{{#useRequestMappingOnInterface}}
|
||||
{{=<% %>=}}
|
||||
@HttpExchange("\${openapi.<%title%>.base-path:\${api.base-path:$BASE_PATH}}")
|
||||
<%={{ }}=%>
|
||||
@HttpExchange("\${api.base-path:{{contextPath}}}")
|
||||
{{/useRequestMappingOnInterface}}
|
||||
{{#useBeanValidation}}
|
||||
@Validated
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<jakarta-annotation-version>1.3.5</jakarta-annotation-version>
|
||||
{{/useJakartaEe}}
|
||||
<junit.version>4.13.2</junit.version>
|
||||
<vertx.version>4.5.22</vertx.version>
|
||||
<vertx.version>4.5.24</vertx.version>
|
||||
<maven-compiler-plugin.version>3.10.0</maven-compiler-plugin.version>
|
||||
<vertx-openapi-router.version>1.0.2</vertx-openapi-router.version>
|
||||
<maven-shade-plugin.version>3.2.4</maven-shade-plugin.version>
|
||||
|
||||
@@ -131,10 +131,10 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
* {{.}}
|
||||
*
|
||||
{{/description}}
|
||||
{{#vendorExtensions.x-group-parameters}}
|
||||
{{#exts.x-group-parameters}}
|
||||
* Note: the input parameter is an associative array with the keys listed as the parameter name below
|
||||
*
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
* This operation contains host(s) defined in the OpenAPI spec. Use 'hostIndex' to select the host.
|
||||
@@ -156,7 +156,7 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/-last}}
|
||||
{{/servers}}
|
||||
{{#allParams}}
|
||||
* @param {{{dataType}}}{{^required}}|null{{/required}} ${{paramName}}{{#description}} {{.}}{{/description}}{{^description}} {{paramName}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#isDeprecated}} (deprecated){{/isDeprecated}}
|
||||
* @param {{{dataType}}}{{#notRequiredOrIsNullable}}|null{{/notRequiredOrIsNullable}} ${{paramName}}{{#description}} {{.}}{{/description}}{{^description}} {{paramName}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#isDeprecated}} (deprecated){{/isDeprecated}}
|
||||
{{/allParams}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
@@ -168,15 +168,15 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
*
|
||||
* @throws ApiException on non-2xx response or if the response body is not in the expected format
|
||||
* @throws InvalidArgumentException
|
||||
* @return {{{vendorExtensions.x-php-doc-return-type}}}
|
||||
* @return {{{exts.x-php-doc-return-type}}}
|
||||
{{#isDeprecated}}
|
||||
* @deprecated
|
||||
{{/isDeprecated}}
|
||||
*/
|
||||
public function {{operationId}}(
|
||||
{{^vendorExtensions.x-group-parameters}}
|
||||
{{^exts.x-group-parameters}}
|
||||
{{#allParams}}
|
||||
{{vendorExtensions.x-php-param-type}} ${{paramName}}{{^required}} = {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}},
|
||||
{{exts.x-php-param-type}} ${{paramName}}{{^required}} = {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}},
|
||||
{{/allParams}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
@@ -185,14 +185,14 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/-first}}
|
||||
{{/servers}}
|
||||
string $contentType = self::contentTypes['{{{operationId}}}'][0]
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{#vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
{{#exts.x-group-parameters}}
|
||||
array $associative_array
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
): {{{vendorExtensions.x-php-return-type}}}
|
||||
{{/exts.x-group-parameters}}
|
||||
): {{{exts.x-php-return-type}}}
|
||||
{
|
||||
{{^vendorExtensions.x-php-return-type-is-void}}list($response) = {{/vendorExtensions.x-php-return-type-is-void}}$this->{{operationId}}WithHttpInfo({{^vendorExtensions.x-group-parameters}}{{#allParams}}${{paramName}}, {{/allParams}}{{#servers}}{{#-first}}$hostIndex, $variables, {{/-first}}{{/servers}}$contentType{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}$associative_array{{/vendorExtensions.x-group-parameters}});{{^vendorExtensions.x-php-return-type-is-void}}
|
||||
return $response;{{/vendorExtensions.x-php-return-type-is-void}}
|
||||
{{^exts.x-php-return-type-is-void}}list($response) = {{/exts.x-php-return-type-is-void}}$this->{{operationId}}WithHttpInfo({{^exts.x-group-parameters}}{{#allParams}}${{paramName}}, {{/allParams}}{{#servers}}{{#-first}}$hostIndex, $variables, {{/-first}}{{/servers}}$contentType{{/exts.x-group-parameters}}{{#exts.x-group-parameters}}$associative_array{{/exts.x-group-parameters}});{{^exts.x-php-return-type-is-void}}
|
||||
return $response;{{/exts.x-php-return-type-is-void}}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,10 +206,10 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
* {{.}}
|
||||
*
|
||||
{{/description}}
|
||||
{{#vendorExtensions.x-group-parameters}}
|
||||
{{#exts.x-group-parameters}}
|
||||
* Note: the input parameter is an associative array with the keys listed as the parameter name below
|
||||
*
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
* This operation contains host(s) defined in the OpenAPI spec. Use 'hostIndex' to select the host.
|
||||
@@ -231,7 +231,7 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/-last}}
|
||||
{{/servers}}
|
||||
{{#allParams}}
|
||||
* @param {{{dataType}}}{{^required}}|null{{/required}} ${{paramName}}{{#description}} {{.}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#isDeprecated}} (deprecated){{/isDeprecated}}
|
||||
* @param {{{dataType}}}{{#notRequiredOrIsNullable}}|null{{/notRequiredOrIsNullable}} ${{paramName}}{{#description}} {{.}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#isDeprecated}} (deprecated){{/isDeprecated}}
|
||||
{{/allParams}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
@@ -249,9 +249,9 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/isDeprecated}}
|
||||
*/
|
||||
public function {{operationId}}WithHttpInfo(
|
||||
{{^vendorExtensions.x-group-parameters}}
|
||||
{{^exts.x-group-parameters}}
|
||||
{{#allParams}}
|
||||
{{vendorExtensions.x-php-param-type}} ${{paramName}}{{^required}} = {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}},
|
||||
{{exts.x-php-param-type}} ${{paramName}}{{^required}} = {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}},
|
||||
{{/allParams}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
@@ -260,13 +260,13 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/-first}}
|
||||
{{/servers}}
|
||||
string $contentType = self::contentTypes['{{{operationId}}}'][0]
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{#vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
{{#exts.x-group-parameters}}
|
||||
array $associative_array
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
): array
|
||||
{
|
||||
$request = $this->{{operationId}}Request({{^vendorExtensions.x-group-parameters}}{{#allParams}}${{paramName}}, {{/allParams}}{{#servers}}{{#-first}}$hostIndex, $variables, {{/-first}}{{/servers}}$contentType{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}$associative_array{{/vendorExtensions.x-group-parameters}});
|
||||
$request = $this->{{operationId}}Request({{^exts.x-group-parameters}}{{#allParams}}${{paramName}}, {{/allParams}}{{#servers}}{{#-first}}$hostIndex, $variables, {{/-first}}{{/servers}}$contentType{{/exts.x-group-parameters}}{{#exts.x-group-parameters}}$associative_array{{/exts.x-group-parameters}});
|
||||
|
||||
try {
|
||||
$options = $this->createHttpClientOption();
|
||||
@@ -379,10 +379,10 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
* {{.}}
|
||||
*
|
||||
{{/description}}
|
||||
{{#vendorExtensions.x-group-parameters}}
|
||||
{{#exts.x-group-parameters}}
|
||||
* Note: the input parameter is an associative array with the keys listed as the parameter name below
|
||||
*
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
* This operation contains host(s) defined in the OpenAPI spec. Use 'hostIndex' to select the host.
|
||||
@@ -404,7 +404,7 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/-last}}
|
||||
{{/servers}}
|
||||
{{#allParams}}
|
||||
* @param {{{dataType}}}{{^required}}|null{{/required}} ${{paramName}}{{#description}} {{.}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#isDeprecated}} (deprecated){{/isDeprecated}}
|
||||
* @param {{{dataType}}}{{#notRequiredOrIsNullable}}|null{{/notRequiredOrIsNullable}} ${{paramName}}{{#description}} {{.}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#isDeprecated}} (deprecated){{/isDeprecated}}
|
||||
{{/allParams}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
@@ -421,9 +421,9 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/isDeprecated}}
|
||||
*/
|
||||
public function {{operationId}}Async(
|
||||
{{^vendorExtensions.x-group-parameters}}
|
||||
{{^exts.x-group-parameters}}
|
||||
{{#allParams}}
|
||||
{{vendorExtensions.x-php-param-type}} ${{paramName}}{{^required}} = {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}},
|
||||
{{exts.x-php-param-type}} ${{paramName}}{{^required}} = {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}},
|
||||
{{/allParams}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
@@ -432,13 +432,13 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/-first}}
|
||||
{{/servers}}
|
||||
string $contentType = self::contentTypes['{{{operationId}}}'][0]
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{#vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
{{#exts.x-group-parameters}}
|
||||
array $associative_array
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
): PromiseInterface
|
||||
{
|
||||
return $this->{{operationId}}AsyncWithHttpInfo({{^vendorExtensions.x-group-parameters}}{{#allParams}}${{paramName}}, {{/allParams}}{{#servers}}{{#-first}}$hostIndex, $variables, {{/-first}}{{/servers}}$contentType{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}$associative_array{{/vendorExtensions.x-group-parameters}})
|
||||
return $this->{{operationId}}AsyncWithHttpInfo({{^exts.x-group-parameters}}{{#allParams}}${{paramName}}, {{/allParams}}{{#servers}}{{#-first}}$hostIndex, $variables, {{/-first}}{{/servers}}$contentType{{/exts.x-group-parameters}}{{#exts.x-group-parameters}}$associative_array{{/exts.x-group-parameters}})
|
||||
->then(
|
||||
function ($response) {
|
||||
return $response[0];
|
||||
@@ -457,10 +457,10 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
* {{.}}
|
||||
*
|
||||
{{/description}}
|
||||
{{#vendorExtensions.x-group-parameters}}
|
||||
{{#exts.x-group-parameters}}
|
||||
* Note: the input parameter is an associative array with the keys listed as the parameter name below
|
||||
*
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
* This operation contains host(s) defined in the OpenAPI spec. Use 'hostIndex' to select the host.
|
||||
@@ -482,7 +482,7 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/-last}}
|
||||
{{/servers}}
|
||||
{{#allParams}}
|
||||
* @param {{{dataType}}}{{^required}}|null{{/required}} ${{paramName}}{{#description}} {{.}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#isDeprecated}} (deprecated){{/isDeprecated}}
|
||||
* @param {{{dataType}}}{{#notRequiredOrIsNullable}}|null{{/notRequiredOrIsNullable}} ${{paramName}}{{#description}} {{.}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#isDeprecated}} (deprecated){{/isDeprecated}}
|
||||
{{/allParams}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
@@ -499,9 +499,9 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/isDeprecated}}
|
||||
*/
|
||||
public function {{operationId}}AsyncWithHttpInfo(
|
||||
{{^vendorExtensions.x-group-parameters}}
|
||||
{{^exts.x-group-parameters}}
|
||||
{{#allParams}}
|
||||
{{vendorExtensions.x-php-param-type}} ${{paramName}}{{^required}} = {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}},
|
||||
{{exts.x-php-param-type}} ${{paramName}}{{^required}} = {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}},
|
||||
{{/allParams}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
@@ -510,14 +510,14 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/-first}}
|
||||
{{/servers}}
|
||||
string $contentType = self::contentTypes['{{{operationId}}}'][0]
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{#vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
{{#exts.x-group-parameters}}
|
||||
array $associative_array
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
): PromiseInterface
|
||||
{
|
||||
$returnType = '{{{returnType}}}';
|
||||
$request = $this->{{operationId}}Request({{^vendorExtensions.x-group-parameters}}{{#allParams}}${{paramName}}, {{/allParams}}{{#servers}}{{#-first}}$hostIndex, $variables, {{/-first}}{{/servers}}$contentType{{/vendorExtensions.x-group-parameters}}{{#vendorExtensions.x-group-parameters}}$associative_array{{/vendorExtensions.x-group-parameters}});
|
||||
$request = $this->{{operationId}}Request({{^exts.x-group-parameters}}{{#allParams}}${{paramName}}, {{/allParams}}{{#servers}}{{#-first}}$hostIndex, $variables, {{/-first}}{{/servers}}$contentType{{/exts.x-group-parameters}}{{#exts.x-group-parameters}}$associative_array{{/exts.x-group-parameters}});
|
||||
|
||||
return $this->client
|
||||
->sendAsync($request, $this->createHttpClientOption())
|
||||
@@ -563,10 +563,10 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
/**
|
||||
* Create request for operation '{{{operationId}}}'
|
||||
*
|
||||
{{#vendorExtensions.x-group-parameters}}
|
||||
{{#exts.x-group-parameters}}
|
||||
* Note: the input parameter is an associative array with the keys listed as the parameter name below
|
||||
*
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
* This operation contains host(s) defined in the OpenAPI spec. Use 'hostIndex' to select the host.
|
||||
@@ -588,7 +588,7 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/-last}}
|
||||
{{/servers}}
|
||||
{{#allParams}}
|
||||
* @param {{{dataType}}}{{^required}}|null{{/required}} ${{paramName}}{{#description}} {{.}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#isDeprecated}} (deprecated){{/isDeprecated}}
|
||||
* @param {{{dataType}}}{{#notRequiredOrIsNullable}}|null{{/notRequiredOrIsNullable}} ${{paramName}}{{#description}} {{.}}{{/description}} {{#required}}(required){{/required}}{{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}{{#isDeprecated}} (deprecated){{/isDeprecated}}
|
||||
{{/allParams}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
@@ -605,9 +605,9 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/isDeprecated}}
|
||||
*/
|
||||
public function {{operationId}}Request(
|
||||
{{^vendorExtensions.x-group-parameters}}
|
||||
{{^exts.x-group-parameters}}
|
||||
{{#allParams}}
|
||||
{{vendorExtensions.x-php-param-type}} ${{paramName}}{{^required}} = {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}},
|
||||
{{exts.x-php-param-type}} ${{paramName}}{{^required}} = {{#defaultValue}}{{{.}}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}}{{/required}},
|
||||
{{/allParams}}
|
||||
{{#servers}}
|
||||
{{#-first}}
|
||||
@@ -616,13 +616,13 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
{{/-first}}
|
||||
{{/servers}}
|
||||
string $contentType = self::contentTypes['{{{operationId}}}'][0]
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{#vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
{{#exts.x-group-parameters}}
|
||||
array $associative_array
|
||||
{{/vendorExtensions.x-group-parameters}}
|
||||
{{/exts.x-group-parameters}}
|
||||
): Request
|
||||
{
|
||||
{{#vendorExtensions.x-group-parameters}}
|
||||
{{#exts.x-group-parameters}}
|
||||
// unbox the parameters from the associative array
|
||||
{{#allParams}}
|
||||
${{paramName}} = array_key_exists('{{paramName}}', $associative_array) ? $associative_array['{{paramName}}'] : {{{defaultValue}}}{{^defaultValue}}null{{/defaultValue}};
|
||||
@@ -631,7 +631,7 @@ use {{invokerPackage}}\ObjectSerializer;
|
||||
$variables = array_key_exists('variables', $associative_array) ? $associative_array['variables'] : [];
|
||||
{{/servers.0}}
|
||||
$contentType = $associative_array['contentType'] ?? self::contentTypes['{{{operationId}}}'][0];
|
||||
{{/vendorExtensions.x-group-parameters}}{{#allParams}}
|
||||
{{/exts.x-group-parameters}}{{#allParams}}
|
||||
{{#required}}
|
||||
// verify the required parameter '{{paramName}}' is set
|
||||
if (${{paramName}} === null || (is_array(${{paramName}}) && count(${{paramName}}) === 0)) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user