├── .gitignore
├── LICENSE
├── NOTICE
├── README.md
├── build.gradle
├── docs
├── CNAME
├── gradle
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ ├── gradle-wrapper.properties
│ │ │ └── gradle-wrapper.properties.kotlin-dsl
│ ├── gradlew
│ └── gradlew.bat
├── index.html
├── jquery.js
├── kotlin.js
├── ktor-generator.js
├── ktor_logo_box.svg
├── lib
│ ├── bootstrap.bundle.min.js
│ ├── bootstrap.min.css
│ ├── jquery-3.3.1.min.js
│ └── require.min.js
├── maven
│ ├── mvnw
│ ├── mvnw.cmd
│ └── wrapper
│ │ ├── MavenWrapperDownloader.java
│ │ ├── maven-wrapper.jar
│ │ └── maven-wrapper.properties
├── output.js
├── static
│ └── ktor_logo.svg
├── styles.css
└── swagger
│ └── SwaggerUtils.kt.txt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── ktor-generator-website
├── build.gradle
├── resources
│ ├── index.html
│ ├── ktor_logo_box.svg
│ ├── lib
│ │ ├── bootstrap.bundle.min.js
│ │ ├── bootstrap.min.css
│ │ ├── jquery-3.3.1.min.js
│ │ └── require.min.js
│ └── styles.css
├── src
│ └── io
│ │ └── ktor
│ │ └── start
│ │ ├── JsUtils.kt
│ │ ├── Main.kt
│ │ └── MainEvents.kt
└── test
│ └── SampleTest.kt
├── ktor-generator
├── .gitignore
├── build.gradle
├── package.json
└── src
│ ├── commonMain
│ ├── kotlin
│ │ └── io
│ │ │ ├── dahgan
│ │ │ └── Yaml.kt
│ │ │ └── ktor
│ │ │ └── start
│ │ │ ├── BuildInfo.kt
│ │ │ ├── Feature.kt
│ │ │ ├── KtorEngine.kt
│ │ │ ├── ProjectTypes.kt
│ │ │ ├── Repos.kt
│ │ │ ├── Versions.kt
│ │ │ ├── features
│ │ │ ├── all.kt
│ │ │ ├── client
│ │ │ │ ├── ClientEngines.kt
│ │ │ │ └── ClientFeatures.kt
│ │ │ ├── server
│ │ │ │ ├── AuthBasicFeature.kt
│ │ │ │ ├── AuthDigestFeature.kt
│ │ │ │ ├── AuthFeature.kt
│ │ │ │ ├── AuthJwtFeature.kt
│ │ │ │ ├── AuthLdapFeature.kt
│ │ │ │ ├── AuthOauthFeature.kt
│ │ │ │ ├── AutoHeadResponseFeature.kt
│ │ │ │ ├── CORSFeature.kt
│ │ │ │ ├── CachingHeadersFeature.kt
│ │ │ │ ├── CallLoggingFeature.kt
│ │ │ │ ├── CompressionFeature.kt
│ │ │ │ ├── ConditionalHeadersFeature.kt
│ │ │ │ ├── ContentNegotiationFeature.kt
│ │ │ │ ├── CssDslFeature.kt
│ │ │ │ ├── DataConversionFeature.kt
│ │ │ │ ├── DefaultHeadersFeature.kt
│ │ │ │ ├── ForwardedHeaderSupportFeature.kt
│ │ │ │ ├── FreemarkerFeature.kt
│ │ │ │ ├── HSTSFeature.kt
│ │ │ │ ├── HtmlDslFeature.kt
│ │ │ │ ├── HttpsRedirectFeature.kt
│ │ │ │ ├── JsonGsonFeature.kt
│ │ │ │ ├── JsonJacksonFeature.kt
│ │ │ │ ├── LocationsFeature.kt
│ │ │ │ ├── MetricsFeature.kt
│ │ │ │ ├── MustacheFeature.kt
│ │ │ │ ├── PartialContentFeature.kt
│ │ │ │ ├── RoutingFeature.kt
│ │ │ │ ├── SessionsFeature.kt
│ │ │ │ ├── ShutdownUrlFeature.kt
│ │ │ │ ├── StaticContentFeature.kt
│ │ │ │ ├── StatusPagesFeature.kt
│ │ │ │ ├── ThymeleafFeature.kt
│ │ │ │ ├── VelocityFeature.kt
│ │ │ │ ├── WebjarsFeature.kt
│ │ │ │ └── WebsocketsFeature.kt
│ │ │ └── sockets
│ │ │ │ ├── RawSocketsFeature.kt
│ │ │ │ └── RawSocketsTlsFeature.kt
│ │ │ ├── http
│ │ │ └── HttpStatusCodes.kt
│ │ │ ├── project
│ │ │ ├── ApplicationConf.kt
│ │ │ ├── ApplicationKt.kt
│ │ │ ├── ApplicationTestKt.kt
│ │ │ ├── BuildFiles.kt
│ │ │ ├── BuildFilesGradle.kt
│ │ │ ├── BuildFilesMaven.kt
│ │ │ ├── GitIgnoreFile.kt
│ │ │ ├── LogBackXml.kt
│ │ │ └── Properties.kt
│ │ │ ├── swagger
│ │ │ ├── ContentType.kt
│ │ │ ├── JsonSchema.kt
│ │ │ ├── SwaggerGenerator.kt
│ │ │ ├── SwaggerGeneratorBase.kt
│ │ │ ├── SwaggerGeneratorCommon.kt
│ │ │ ├── SwaggerGeneratorInterface.kt
│ │ │ ├── SwaggerGeneratorRaw.kt
│ │ │ ├── SwaggerModel.kt
│ │ │ └── SwaggerModelExt.kt
│ │ │ └── util
│ │ │ ├── DateTime.kt
│ │ │ ├── Dynamic.kt
│ │ │ ├── FileMode.kt
│ │ │ ├── FormUrlEncoded.kt
│ │ │ ├── Json.kt
│ │ │ ├── MetaListIterator.kt
│ │ │ ├── Stack.kt
│ │ │ ├── StrReader.kt
│ │ │ ├── Template.kt
│ │ │ ├── baos.kt
│ │ │ ├── buildList.kt
│ │ │ ├── charset.kt
│ │ │ ├── crc32.kt
│ │ │ ├── ext.kt
│ │ │ ├── extra.kt
│ │ │ ├── hex.kt
│ │ │ ├── id.kt
│ │ │ ├── indenter.kt
│ │ │ ├── mvndependency.kt
│ │ │ ├── quote.kt
│ │ │ ├── semver.kt
│ │ │ └── zip.kt
│ └── resources
│ │ ├── gradle
│ │ ├── gradle
│ │ │ └── wrapper
│ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ ├── gradle-wrapper.properties
│ │ │ │ └── gradle-wrapper.properties.kotlin-dsl
│ │ ├── gradlew
│ │ └── gradlew.bat
│ │ ├── maven
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ └── wrapper
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ ├── maven-wrapper.jar
│ │ │ └── maven-wrapper.properties
│ │ ├── static
│ │ └── ktor_logo.svg
│ │ └── swagger
│ │ └── SwaggerUtils.kt.txt
│ ├── commonTest
│ └── kotlin
│ │ └── io
│ │ └── ktor
│ │ └── start
│ │ └── util
│ │ ├── MyCommonTest.kt
│ │ └── SemVerTest.kt
│ ├── jsMain
│ └── kotlin
│ │ └── io
│ │ └── ktor
│ │ └── start
│ │ └── util
│ │ └── DateTimeJs.kt
│ ├── jsTest
│ └── kotlin
│ │ └── io
│ │ └── ktor
│ │ └── start
│ │ └── MyJsTest.kt
│ ├── jvmMain
│ └── kotlin
│ │ └── io
│ │ └── ktor
│ │ └── start
│ │ └── util
│ │ └── DateTimeJvm.kt
│ └── jvmTest
│ ├── kotlin
│ └── io
│ │ └── ktor
│ │ ├── start
│ │ ├── GenerationTest.kt
│ │ ├── IntegrationTests.kt
│ │ ├── SwaggerGenerationTest.kt
│ │ ├── TestTools.kt
│ │ ├── Tools.kt
│ │ ├── WriteToFolderTest.kt
│ │ └── swagger
│ │ │ ├── GenerationSpike.kt
│ │ │ ├── JsonSchemaTest.kt
│ │ │ ├── ModelTest.kt
│ │ │ └── YamlSchemaTest.kt
│ │ └── util
│ │ ├── IdTest.kt
│ │ ├── IndenterTest.kt
│ │ └── JsonTest.kt
│ └── resources
│ ├── V30
│ ├── api-with-examples.yaml
│ ├── callback-example.yaml
│ ├── link-example.yaml
│ ├── petstore-expanded.yaml
│ ├── petstore.yaml
│ └── uspto.yaml
│ ├── empty.json
│ ├── openapi.yaml
│ ├── small-petstore3.json
│ ├── swagger.json
│ ├── swagger.yaml
│ └── uspto.json
├── ktor-intellij-plugin
├── build.gradle
├── resources
│ ├── META-INF
│ │ └── plugin.xml
│ └── icons
│ │ ├── ktor-icon.png
│ │ └── ktor-icon16.png
├── src
│ └── io
│ │ └── ktor
│ │ └── start
│ │ └── intellij
│ │ ├── FqNames.kt
│ │ ├── KtorArtifactWizardStep.kt
│ │ ├── KtorModuleBuilder.kt
│ │ ├── KtorModuleConfig.kt
│ │ ├── KtorModuleType.kt
│ │ ├── KtorModuleWizardStep.kt
│ │ ├── RoutingLineMarker.kt
│ │ ├── locations
│ │ ├── AddClassParameterQuickFix.kt
│ │ ├── AddOuterClassParameterQuickFix.kt
│ │ ├── CompletionInsertHandler.kt
│ │ ├── ConvertToClassQuickFix.kt
│ │ ├── ElementManipulators.kt
│ │ ├── LocationPatternBraceMatcher.kt
│ │ ├── LocationsLineMarker.kt
│ │ ├── LocationsParametersFindUsagesHandlerFactory.kt
│ │ ├── LocationsRefactoringsSupportProvider.kt
│ │ ├── LocationsReferenceContributor.kt
│ │ ├── MakeParameterOptionalQuickFix.kt
│ │ ├── MissingOwnerClassReferenceInspection.kt
│ │ ├── ParameterNameAnnotator.kt
│ │ ├── ParameterNameInPlaceRenameHandler.kt
│ │ ├── ParameterNameInspection.kt
│ │ ├── ParameterRenameProcessor.kt
│ │ ├── ParameterUsagesSearcher.kt
│ │ ├── Parser.kt
│ │ ├── ParserToPsi.kt
│ │ ├── PatternFileTypeFactory.kt
│ │ ├── PatternFindUsagesProvider.kt
│ │ ├── PatternLexer.kt
│ │ ├── PatternParameterBackReference.kt
│ │ ├── PatternParameterReference.kt
│ │ ├── PatternParser.kt
│ │ ├── PatternSyntaxHighlighter.kt
│ │ ├── PropertyNamesCompletionContributor.kt
│ │ └── QuickFixActions.kt
│ │ └── util
│ │ ├── UIExt.kt
│ │ └── Utils.kt
├── test
│ └── io
│ │ └── ktor
│ │ └── start
│ │ └── intellij
│ │ └── util
│ │ ├── ParsingTest.kt
│ │ └── PathInfoTest.kt
└── testresources
│ ├── Smoke.locationspattern
│ ├── Smoke.txt
│ └── swagger.json
├── settings.gradle
└── synchronize_versions.kt
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .gradle
3 | *.iml
4 | *.iws
5 | *.ipr
6 | *.DS_Store
7 | /build
8 | /docs/META-INF
9 | /docs/output
10 | /ktor-generator/build
11 | /ktor-generator/common/build
12 | /ktor-generator/js/build
13 | /ktor-generator/jvm/build
14 | /ktor-generator-website/build
15 | /ktor-intellij-plugin/build
16 | package-lock.json
17 |
18 | *.js.map
19 | *.meta.js
20 |
21 | local.properties
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | YAML Parsing
18 | https://github.com/kareez/dahgan
19 |
20 | Released under Apache 2.0:
21 | https://github.com/kareez/dahgan/blob/dee63dcf0c26097e9078b79770cd6dd1799fde0d/LICENSE
22 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | =========================================================================
2 | == NOTICE file corresponding to the section 4 d of ==
3 | == the Apache License, Version 2.0, ==
4 | == in this case for the ktor-init-tools. ==
5 | =========================================================================
6 |
7 | ktor-init-tools.
8 | Copyright 2018 JetBrains s.r.o and respective authors and developers
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ktor-init-tools
2 |
3 | A set of tools for creating Ktor projects.
4 |
5 | This includes:
6 | * A MPP library shared for Ktor project generation.
7 | * A Website for generating Ktor projects as ZIP files client-side *(Kotlin-JS)*.
8 | * A IntelliJ plugin generating Ktor projects *(Kotlin-JVM)*.
9 |
10 | The code generation features:
11 | * Maven and Gradle support including wrappers.
12 | * Backend engine selection.
13 | * Ktor version selection.
14 | * GroupId/ArtifactId/Version definition.
15 | * Feature selection with sample code generation.
16 | * Code generation from swagger models.
17 | * Easy to modify and add new things.
18 |
19 | ## Project Generation Website
20 |
21 | The website is generated in the `/docs` folder as plain static files.
22 | You can serve it locally with any webserver like `hs docs/`.
23 | Once pushed, it will be available in its domain via github's pages.
24 |
25 | You can compile it continuously on change with the following command:
26 |
27 | ```bash
28 | ./gradlew -t :ktor-generator-website:buildAndCopy
29 | ```
30 |
31 | ## IntelliJ plugin
32 |
33 | To run an IDE with the plugin for development:
34 |
35 | ```bash
36 | ./gradlew :ktor-intellij-plugin:runIde
37 | ```
38 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.web_dir = 'docs'
3 |
4 | repositories {
5 | mavenLocal()
6 | maven { url "https://plugins.gradle.org/m2/" }
7 | mavenCentral()
8 | }
9 | dependencies {
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | classpath 'com.moowork.gradle:gradle-node-plugin:1.2.0'
12 | }
13 | }
14 |
15 | plugins {
16 | id 'kotlin-multiplatform' version '1.3.61'
17 | }
18 |
19 | group 'io.ktor.start'
20 | version '1.0-SNAPSHOT'
21 |
22 | apply plugin: 'idea'
23 |
24 | allprojects {
25 | repositories {
26 | mavenLocal()
27 | mavenCentral()
28 | maven { url "https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven" }
29 | maven { url "https://plugins.gradle.org/m2/" }
30 | }
31 | }
32 |
33 | idea {
34 | module {
35 | excludeDirs = [".gradle", ".idea", "build", "gradle", "docs", "resources/lib"].collect { new File(it) }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | start.ktor.io
--------------------------------------------------------------------------------
/docs/gradle/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ktorio/ktor-init-tools/790e8b389ae9aed630eea72a73181a3a5b725977/docs/gradle/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/docs/gradle/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/docs/gradle/gradle/wrapper/gradle-wrapper.properties.kotlin-dsl:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/docs/gradle/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/docs/jquery.js:
--------------------------------------------------------------------------------
1 | (function (root, factory) {
2 | if (typeof define === 'function' && define.amd)
3 | define(['exports', 'kotlin'], factory);
4 | else if (typeof exports === 'object')
5 | factory(module.exports, require('kotlin'));
6 | else {
7 | if (typeof kotlin === 'undefined') {
8 | throw new Error("Error loading module 'jquery'. Its dependency 'kotlin' was not found. Please, check whether 'kotlin' is loaded prior to 'jquery'.");
9 | }
10 | root.jquery = factory(typeof jquery === 'undefined' ? {} : jquery, kotlin);
11 | }
12 | }(this, function (_, Kotlin) {
13 | 'use strict';
14 | Kotlin.defineModule('jquery', _);
15 | return _;
16 | }));
17 |
18 | //# sourceMappingURL=jquery.js.map
19 |
--------------------------------------------------------------------------------
/docs/ktor_logo_box.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
--------------------------------------------------------------------------------
/docs/maven/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ktorio/ktor-init-tools/790e8b389ae9aed630eea72a73181a3a5b725977/docs/maven/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/docs/maven/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip
--------------------------------------------------------------------------------
/docs/static/ktor_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
--------------------------------------------------------------------------------
/docs/styles.css:
--------------------------------------------------------------------------------
1 | .loading {
2 | color: #aaa;
3 | }
4 |
5 | .loaded {
6 | display: none;
7 | }
8 |
9 | label.artifact {
10 | display: block;
11 | padding: 0 8px;
12 | }
13 |
14 | .artifact-group {
15 | padding: 3px 8px;
16 | font: 18px Arial;
17 | background: #aaa;
18 | color: white;
19 | }
20 |
21 | label.artifact .subtitle {
22 | }
23 |
24 | .artifact .subtitle {
25 | font-size: 0.75em;
26 | color: #777;
27 | }
28 |
29 | .artifact .artifact-name {
30 | font-size: 0.75em;
31 | color: #aaa;
32 | }
33 |
34 | .artifact:hover {
35 | background: #fafafa;
36 | }
37 |
38 | .artifact.active {
39 | background: #f7f7f7;
40 | }
41 |
42 | .dependencies {
43 | border: 1px solid #ddd;
44 | }
45 |
46 | h2 {
47 | font-size: 1.7em;
48 | }
49 |
50 | label.selected {
51 | background: #e7e7ff !important;
52 | }
53 |
54 | label.indeterminate {
55 | background: #ffe7ff !important;
56 | color: #777;
57 | }
58 |
59 | label.artifact {
60 | margin: 0;
61 | }
62 |
63 | .dependencies h2 {
64 | margin: 0;
65 | }
66 |
67 | .dependencies {
68 | overflow:auto;
69 | margin-top: 8px;
70 | border-radius:6px;
71 |
72 | min-height: 100px;
73 | height: 287px; /* Fallback for older browsers */
74 | height: calc(100vh - 240px);
75 | }
76 |
77 | @media(max-width: 576px) {
78 | .dependencies {
79 | height: 20vh !important;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | version=1.5.4
2 | kotlin_version=1.3.70
3 | kotlin.code.style=official
4 | kotlinx_coroutines_version=1.3.4
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ktorio/ktor-init-tools/790e8b389ae9aed630eea72a73181a3a5b725977/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/ktor-generator-website/resources/ktor_logo_box.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
--------------------------------------------------------------------------------
/ktor-generator-website/resources/styles.css:
--------------------------------------------------------------------------------
1 | .loading {
2 | color: #aaa;
3 | }
4 |
5 | .loaded {
6 | display: none;
7 | }
8 |
9 | label.artifact {
10 | display: block;
11 | padding: 0 8px;
12 | }
13 |
14 | .artifact-group {
15 | padding: 3px 8px;
16 | font: 18px Arial;
17 | background: #aaa;
18 | color: white;
19 | }
20 |
21 | label.artifact .subtitle {
22 | }
23 |
24 | .artifact .subtitle {
25 | font-size: 0.75em;
26 | color: #777;
27 | }
28 |
29 | .artifact .artifact-name {
30 | font-size: 0.75em;
31 | color: #aaa;
32 | }
33 |
34 | .artifact:hover {
35 | background: #fafafa;
36 | }
37 |
38 | .artifact.active {
39 | background: #f7f7f7;
40 | }
41 |
42 | .dependencies {
43 | border: 1px solid #ddd;
44 | }
45 |
46 | h2 {
47 | font-size: 1.7em;
48 | }
49 |
50 | label.selected {
51 | background: #e7e7ff !important;
52 | }
53 |
54 | label.indeterminate {
55 | background: #ffe7ff !important;
56 | color: #777;
57 | }
58 |
59 | label.artifact {
60 | margin: 0;
61 | }
62 |
63 | .dependencies h2 {
64 | margin: 0;
65 | }
66 |
67 | .dependencies {
68 | overflow:auto;
69 | margin-top: 8px;
70 | border-radius:6px;
71 |
72 | min-height: 100px;
73 | height: 287px; /* Fallback for older browsers */
74 | height: calc(100vh - 240px);
75 | }
76 |
77 | @media(max-width: 576px) {
78 | .dependencies {
79 | height: 20vh !important;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/ktor-generator-website/src/io/ktor/start/MainEvents.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start
2 |
3 | import js.externals.jquery.*
4 | import org.w3c.dom.*
5 | import org.w3c.dom.events.*
6 | import kotlin.browser.*
7 |
8 | fun registerKeyboardUsability() {
9 | document.addEventListener("keydown", { be ->
10 | val e = be as KeyboardEvent
11 | val active = document.activeElement
12 | for (filterId in listOf("dependency-filter-client", "dependency-filter-server")) {
13 | val dependencyFilter = document.getElementById(filterId)
14 |
15 | if ((active?.tagName != "INPUT") && (active?.tagName != "TEXTAREA") && (e.key in listOf("f", "s", "c"))) {
16 | if (
17 | ((e.key === "f" || e.key === "s") && filterId.contains("server")) || (e.key === "c" && filterId.contains("client"))
18 | ) {
19 | dependencyFilter.asDynamic()?.focus()
20 | e.preventDefault()
21 | }
22 | }
23 |
24 | if (active === dependencyFilter) {
25 | val current = jq(".artifact.active:visible")
26 | when (e.key) {
27 | "Escape" -> {
28 | dependencyFilter.asDynamic()?.blur()
29 | e.preventDefault()
30 | }
31 | "Enter" -> {
32 | val checkbox = current.find("[type=checkbox]")
33 | checkbox.prop("checked", !(checkbox.prop("checked").asDynamic()))
34 | e.preventDefault()
35 | }
36 | "ArrowUp", "ArrowDown" -> {
37 | val up = e.key === "ArrowUp"
38 | val count = current.length
39 | var next: JQuery
40 | if (count == 0) {
41 | next = jq(".artifact:visible").first()
42 | } else {
43 | next = current
44 |
45 | do {
46 | next = if (up) next.prev(".artifact") else next.next(".artifact")
47 | } while (next.length.toInt() >= 1 && !next.`is`(":visible"))
48 |
49 | if (next.length == 0) {
50 | next = if (up) jq(".artifact:visible").last() else jq(".artifact:visible").first()
51 | }
52 | }
53 |
54 | next.addClass("active")
55 | current.removeClass("active")
56 |
57 | if (next.length.toInt() >= 1) {
58 | next[0]?.scrollIntoView(
59 | jsObject(
60 | "behavior" to "instant",
61 | "block" to "center",
62 | "inline" to "center"
63 | )
64 | )
65 | }
66 |
67 | e.preventDefault()
68 | }
69 | }
70 | }
71 | }
72 | })
73 | }
74 |
--------------------------------------------------------------------------------
/ktor-generator-website/test/SampleTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | import kotlin.test.*
19 |
20 | class SampleTest {
21 | @Test
22 | fun name() {
23 | assertEquals(true, true)
24 | }
25 | }
--------------------------------------------------------------------------------
/ktor-generator/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 |
--------------------------------------------------------------------------------
/ktor-generator/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "mocha": "^8.3.2",
4 | "mocha-junit-reporter": "^2.0.0",
5 | "mocha-multi-reporters": "^1.5.1",
6 | "mocha-simple-html-reporter": "^2.0.0",
7 | "mochawesome": "^6.2.2",
8 | "source-map-support": "^0.5.19"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/BuildInfo.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start
19 |
20 | import io.ktor.start.swagger.*
21 | import io.ktor.start.util.*
22 |
23 | data class BuildInfo(
24 | val includeWrapper: Boolean = false,
25 | val projectType: ProjectType = ProjectType.Gradle,
26 | val ktorVersion: KtorVersion = Versions.LAST,
27 | val artifactName: String = "example",
28 | val artifactGroup: String = "com.example",
29 | val artifactVersion: String = "0.0.1-SNAPSHOT",
30 | val ktorEngine: KtorEngine = KtorEngine.Netty,
31 | val generateFeatureSample: Boolean = true,
32 | //val swaggerGenKind: SwaggerGenerator.Kind = SwaggerGenerator.Kind.INTERFACE,
33 | val swaggerGenKind: SwaggerGenerator.Kind = SwaggerGenerator.Kind.RAW,
34 | val fetch: suspend (path: String) -> ByteArray = { TODO("Must set fetch") }
35 | ) : BlockBuilder.Config() {
36 | val is100OrGreater = ktorVersion.semVersion >= SemVer("1.0.0")
37 |
38 | val developmentPackage = "io.ktor.server.${ktorEngine.id}"
39 | val developmentEngineFQ = when {
40 | is100OrGreater -> "$developmentPackage.EngineMain"
41 | else -> "$developmentPackage.DevelopmentEngine"
42 | }
43 | val kotlinVersion get() = ktorVersion.semKotlinVersion
44 |
45 | override fun transform(data: ByteArray, charset: Charset?): ByteArray {
46 | if (charset == null) return data
47 | val content = data.toString(charset)
48 | return if (is100OrGreater) {
49 | content
50 | .replace("kotlin.coroutines.experimental.", "kotlin.coroutines.")
51 | .replace("kotlinx.coroutines.experimental.", "kotlinx.coroutines.")
52 | .replace("// kotlinx.coroutines-1.0.0: // ", "")
53 | } else {
54 | content
55 | }.toByteArray(charset)
56 | }
57 | }
58 |
59 | typealias BuildInfoBlock = Block
60 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/Feature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start
19 |
20 | import io.ktor.start.project.*
21 | import io.ktor.start.util.*
22 |
23 | interface FileContainer {
24 | fun add(name: String, content: ByteArray, mode: FileMode = FileMode("644"))
25 | }
26 |
27 | fun FileContainer.add(name: String, content: String, charset: Charset = UTF8, mode: FileMode = FileMode("644")) {
28 | add(name, content.toByteArray(charset), mode = mode)
29 | }
30 |
31 | abstract class ServerFeature(vararg deps: Block) : Feature(*deps)
32 |
33 | abstract class ClientFeature(vararg deps: Block) : Feature(*deps)
34 |
35 | abstract class Feature(vararg deps: Block) : Block(*deps) {
36 | val featureDeps get() = blockDeps.filterIsInstance()
37 |
38 | open val group: String = "Features"
39 | open val tags = listOf()
40 | open val since: KtorVersion? = null
41 |
42 | open val repos: List = Repos.mavenCentral
43 | abstract val id: String
44 | open val artifacts: List by lazy { listOf("io.ktor:$id:\$ktor_version") }
45 | open val testArtifacts: List by lazy { listOf() }
46 | abstract val title: String
47 | abstract val description: String
48 | open val documentation: String? = null
49 |
50 | final override fun BlockBuilder.render(info: BuildInfo) {
51 | for (repo in repos) {
52 | addMavenRepository(repo)
53 | }
54 | for (artifact in artifacts) {
55 | addCompileDependency(MvnArtifact(artifact))
56 | }
57 | for (artifact in testArtifacts) {
58 | addTestDependency(MvnArtifact(artifact))
59 | }
60 | if (info.generateFeatureSample) {
61 | renderFeature(info)
62 | }
63 | }
64 |
65 | open fun BlockBuilder.renderFeature(info: BuildInfo) {
66 | }
67 |
68 | override fun toString(): String = "Feature($id)"
69 | }
70 |
71 | class FeatureSet(features: Iterable) {
72 | val direct = features.toSet()
73 | val all = direct.flatMap { it.getAllDependantBlocks().filterIsInstance() }.toSet()
74 | val transitive = all - direct
75 | }
76 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/KtorEngine.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start
19 |
20 | enum class KtorEngine(val id: String) {
21 | Netty("netty"),
22 | Jetty("jetty"),
23 | Tomcat("tomcat"),
24 | CIO("cio");
25 |
26 | companion object {
27 | val BY_ID = values().associateBy { it.id }
28 | val BY_NAME = values().associateBy { it.name }
29 | val BY = BY_ID + BY_NAME
30 |
31 | operator fun invoke(name: String) = BY[name] ?: error("Unknown engine $name")
32 | }
33 | }
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/ProjectTypes.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start
19 |
20 | enum class ProjectType(val id: String) {
21 | Gradle("gradle"),
22 | GradleKotlinDsl("gradle-kotlin-dsl"),
23 | Maven("maven");
24 |
25 | companion object {
26 | val BY_ID = values().associateBy { it.id }
27 | val BY_NAME = values().associateBy { it.name }
28 | val BY = BY_ID + BY_NAME
29 |
30 | operator fun invoke(name: String): ProjectType = BY[name] ?: error("Unknown project type $name")
31 | }
32 | }
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/Repos.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start
19 |
20 | object Repos {
21 | val local = listOf("local")
22 | val mavenCentral = listOf("mavenCentral")
23 | val kotlin_js_wrappers = listOf("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers")
24 | }
25 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/all.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.features.sockets.*
22 | import io.ktor.start.features.client.*
23 | import io.ktor.start.features.server.*
24 |
25 | val ALL_SERVER_FEATURES by lazy { ALL_FEATURES.filterIsInstance() }
26 | val ALL_CLIENT_FEATURES by lazy { ALL_FEATURES.filterIsInstance() }
27 |
28 | val ALL_FEATURES: List = listOf(
29 | // Client Features
30 | CoreClientEngine,
31 | ApacheClientEngine,
32 | CioClientEngine,
33 | JettyClientEngine,
34 | MockClientEngine,
35 | HttpTimeoutClientFeature,
36 | AuthBasicClientFeature,
37 | GsonClientFeature,
38 | WebSocketClientFeature,
39 | LoggingClientFeature,
40 | UserAgentClientFeature,
41 |
42 | // Server Features
43 | HtmlDslFeature,
44 | CssDslFeature,
45 | FreemarkerFeature,
46 | VelocityFeature,
47 | MustacheFeature,
48 | ThymeleafFeature,
49 | StaticContentFeature,
50 | AuthBasicFeature,
51 | AuthDigestFeature,
52 | AuthJwtFeature,
53 | AuthLdapFeature,
54 | AuthOauthFeature,
55 | AuthFeature,
56 | JsonGsonFeature,
57 | JsonJacksonFeature,
58 | LocationsFeature,
59 | MetricsFeature,
60 | SessionsFeature,
61 | CompressionFeature,
62 | CachingHeadersFeature,
63 | CallLoggingFeature,
64 | ConditionalHeadersFeature,
65 | CORSFeature,
66 | AutoHeadResponseFeature,
67 | DataConversionFeature,
68 | DefaultHeadersFeature,
69 | ForwardedHeaderSupportFeature,
70 | HSTSFeature,
71 | StatusPagesFeature,
72 | RoutingFeature,
73 | WebjarsFeature,
74 | ContentNegotiationFeature,
75 | HttpsRedirectFeature,
76 | ShutdownUrlFeature,
77 | WebsocketsFeature,
78 | RawSocketsFeature,
79 | PartialContentFeature,
80 | RawSocketsTlsFeature
81 | )
82 |
83 | val ALL_FEATURES_BY_ID = ALL_FEATURES.associateBy { it.id }
84 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/AuthBasicFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object AuthBasicFeature : ServerFeature(ApplicationKt, AuthFeature, RoutingFeature) {
25 | override val group: String = "Authentication"
26 | override val artifacts = listOf("io.ktor:ktor-auth:\$ktor_version")
27 | override val id = "auth-basic"
28 | override val title = "Authentication Basic"
29 | override val description = "Handle Basic authentication"
30 | override val documentation = "https://ktor.io/docs/basic.html"
31 |
32 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
33 | addImport("io.ktor.auth.*")
34 | addAuthProvider {
35 | "basic(\"myBasicAuth\")" {
36 | +"realm = \"Ktor Server\""
37 | +"validate { if (it.name == \"test\" && it.password == \"password\") UserIdPrincipal(it.name) else null }"
38 | }
39 | }
40 | addRoute {
41 | "authenticate(\"myBasicAuth\")" {
42 | "get(\"/protected/route/basic\")" {
43 | +"val principal = call.principal()!!"
44 | +"call.respondText(\"Hello \${principal.name}\")"
45 | }
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/AuthDigestFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object AuthDigestFeature : ServerFeature(ApplicationKt, AuthFeature, RoutingFeature) {
25 | override val group: String = "Authentication"
26 | override val artifacts = listOf("io.ktor:ktor-auth:\$ktor_version")
27 | override val id = "auth-digest"
28 | override val title = "Authentication Digest"
29 | override val description = "Handle Digest authentication"
30 | override val documentation = "https://ktor.io/docs/digest.html"
31 |
32 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
33 | addImport("io.ktor.util.*")
34 | addAuthProvider {
35 | +"val myRealm = \"MyRealm\""
36 | +"val usersInMyRealmToHA1: Map = mapOf("
37 | indent {
38 | +"// pass=\"test\", HA1=MD5(\"test:MyRealm:pass\")=\"fb12475e62dedc5c2744d98eb73b8877\""
39 | +"\"test\" to hex(\"fb12475e62dedc5c2744d98eb73b8877\")"
40 | }
41 | +")"
42 | +"digest(\"myDigestAuth\")" {
43 | lineNoOpen("userNameRealmPasswordDigestProvider = { userName, realm ->") {
44 | +"usersInMyRealmToHA1[userName]"
45 | }
46 | }
47 | }
48 | addRoute {
49 | "authenticate(\"myDigestAuth\")" {
50 | "get(\"/protected/route/digest\")" {
51 | +"val principal = call.principal()!!"
52 | +"call.respondText(\"Hello \${principal.name}\")"
53 | }
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/AuthFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object AuthFeature : ServerFeature(ApplicationKt, RoutingFeature) {
25 | override val group: String = "Authentication"
26 | override val artifacts = listOf("io.ktor:ktor-auth:\$ktor_version")
27 | override val id = "auth"
28 | override val title = "Authentication"
29 | override val description = "Handle Basic and Digest HTTP Auth, Form authentication and OAuth 1a and 2"
30 | override val documentation = "https://ktor.io/docs/features-authentication.html"
31 |
32 | val BLOCK = newSlot("BLOCK")
33 |
34 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
35 | addImport("io.ktor.auth.*")
36 | addFeatureInstall {
37 | "install(Authentication)" {
38 | block(BLOCK)
39 | }
40 | }
41 | }
42 | }
43 |
44 | fun BlockBuilder.addAuthProvider(callback: Indenter.() -> Unit) {
45 | appendSeparated(AuthFeature.BLOCK) {
46 | callback()
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/AuthJwtFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 |
23 | object AuthJwtFeature : ServerFeature(ApplicationKt, AuthFeature) {
24 | override val group: String = "Authentication"
25 | override val artifacts = listOf("io.ktor:ktor-auth-jwt:\$ktor_version")
26 | override val id = "auth-jwt"
27 | override val title = "Authentication JWT"
28 | override val description = "Handle JWT authentication"
29 | override val documentation = "https://ktor.io/docs/jwt.html"
30 | }
31 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/AuthLdapFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 |
23 | object AuthLdapFeature : ServerFeature(ApplicationKt, AuthFeature) {
24 | override val group: String = "Authentication"
25 | override val artifacts = listOf("io.ktor:ktor-auth-ldap:\$ktor_version")
26 | override val id = "auth-ldap"
27 | override val title = "Authentication LDAP"
28 | override val description = "Handle LDAP authentication"
29 | override val documentation = "https://ktor.io/docs/ldap.html"
30 | }
31 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/AuthOauthFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 |
23 | object AuthOauthFeature : ServerFeature(ApplicationKt, AuthFeature) {
24 | override val group: String = "Authentication"
25 | override val artifacts = listOf("io.ktor:ktor-auth:\$ktor_version")
26 | override val id = "auth-oauth"
27 | override val title = "Authentication OAuth"
28 | override val description = "Handle OAuth authentication"
29 | override val documentation = "https://ktor.io/docs/authentication-oauth.html"
30 | }
31 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/AutoHeadResponseFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object AutoHeadResponseFeature : ServerFeature(ApplicationKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "caching-headers"
27 | override val title = "CachingHeaders"
28 | override val description = "Send the headers Cache-Control and Expires used by clients and proxies to cache requests"
29 | override val documentation = "https://ktor.io/docs/caching-headers.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.features.*")
33 | addImport("io.ktor.http.*")
34 | addImport("io.ktor.http.content.*")
35 | addImport("io.ktor.util.date.*")
36 | addFeatureInstall {
37 | "install(CachingHeaders)" {
38 | +"options { outgoingContent ->"
39 | indent {
40 | "when (outgoingContent.contentType?.withoutParameters())" {
41 | +"ContentType.Text.CSS -> CachingOptions(CacheControl.MaxAge(maxAgeSeconds = 24 * 60 * 60), expires = null as? GMTDate?)"
42 | +"else -> null"
43 | }
44 | }
45 | +"}"
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/CORSFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object CORSFeature : ServerFeature(ApplicationKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "cors"
27 | override val title = "CORS"
28 | override val description = "Enable Cross-Origin Resource Sharing (CORS)"
29 | override val documentation = "https://ktor.io/docs/cors.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.features.*")
33 | addFeatureInstall {
34 | "install(CORS)" {
35 | +"method(HttpMethod.Options)"
36 | +"method(HttpMethod.Put)"
37 | +"method(HttpMethod.Delete)"
38 | +"method(HttpMethod.Patch)"
39 | +"header(HttpHeaders.Authorization)"
40 | +"header(\"MyCustomHeader\")"
41 | +"allowCredentials = true"
42 | +"anyHost() // @TODO: Don't do this in production if possible. Try to limit it."
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/CachingHeadersFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object CachingHeadersFeature : ServerFeature(ApplicationKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "auto-head-response"
27 | override val title = "AutoHeadResponse"
28 | override val description = "Provide responses to HEAD requests for existing routes that have the GET verb defined"
29 | override val documentation = "https://ktor.io/docs/autoheadresponse.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.features.*")
33 | addFeatureInstall {
34 | +"install(AutoHeadResponse)"
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/CallLoggingFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object CallLoggingFeature : ServerFeature(ApplicationKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "call-logging"
27 | override val title = "CallLogging"
28 | override val description = "Logs client requests"
29 | override val documentation = "https://ktor.io/docs/call-logging.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.features.*")
33 | addImport("org.slf4j.event.*")
34 | addFeatureInstall {
35 | "install(CallLogging)" {
36 | +"level = Level.INFO"
37 | +"filter { call -> call.request.path().startsWith(\"/\") }"
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/CompressionFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object CompressionFeature : ServerFeature(ApplicationKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "compression"
27 | override val title = "Compression"
28 | override val description = "Compress outgoing content using gzip, deflate or custom encoder and thus reduce the size of the response"
29 | override val documentation = "https://ktor.io/docs/compression.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.features.*")
33 | addFeatureInstall {
34 | "install(Compression)" {
35 | "gzip" {
36 | +"priority = 1.0"
37 | }
38 | "deflate" {
39 | +"priority = 10.0"
40 | +"minimumSize(1024) // condition"
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/ConditionalHeadersFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object ConditionalHeadersFeature : ServerFeature(ApplicationKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "conditional-headers"
27 | override val title = "ConditionalHeaders"
28 | override val description = "Avoids sending content if the client already has the same content using ETag or LastModified"
29 | override val documentation = "https://ktor.io/docs/conditional-headers.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.features.*")
33 | addFeatureInstall {
34 | +"install(ConditionalHeaders)"
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/ContentNegotiationFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object ContentNegotiationFeature : ServerFeature(ApplicationKt) {
25 | override val group: String = "Content Negotiation"
26 |
27 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
28 | override val id = "content-negotiation"
29 | override val title = "ContentNegotiation"
30 | override val description = "Provides automatic content conversion according to Content-Type and Accept headers."
31 | override val documentation = "https://ktor.io/docs/content-negotiation.html"
32 |
33 | val BLOCK = newSlot("BLOCK")
34 |
35 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
36 | addFeatureInstall {
37 | "install(ContentNegotiation)" {
38 | block(BLOCK)
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/CssDslFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object CssDslFeature : ServerFeature(ApplicationKt, RoutingFeature, HtmlDslFeature) {
25 | override val group: String = "Templating"
26 | override val repos = Repos.mavenCentral + Repos.kotlin_js_wrappers
27 | override val artifacts = listOf("org.jetbrains:kotlin-css-jvm:1.0.0-pre.31-kotlin-1.2.41")
28 | override val id = "css-dsl"
29 | override val title = "CSS DSL"
30 | override val description = "Generate CSS using Kotlin code"
31 | override val documentation = "https://github.com/JetBrains/kotlin-wrappers/tree/master/kotlin-css"
32 |
33 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
34 | addImport("kotlinx.html.*")
35 | addImport("kotlinx.css.*")
36 | addImport("io.ktor.http.*")
37 | addRoute {
38 | "get(\"/styles.css\")" {
39 | "call.respondCss" {
40 | "body" {
41 | +"backgroundColor = Color.red"
42 | }
43 | "p" {
44 | +"fontSize = 2.em"
45 | }
46 | "rule(\"p.myclass\")" {
47 | +"color = Color.blue"
48 | }
49 | }
50 | }
51 | }
52 | addExtensionMethods {
53 | "fun FlowOrMetaDataContent.styleCss(builder: CSSBuilder.() -> Unit)" {
54 | "style(type = ContentType.Text.CSS.toString())" {
55 | +"+CSSBuilder().apply(builder).toString()"
56 | }
57 | }
58 | }
59 | addExtensionMethods {
60 | "fun CommonAttributeGroupFacade.style(builder: CSSBuilder.() -> Unit)" {
61 | +"this.style = CSSBuilder().apply(builder).toString().trim()"
62 | }
63 | }
64 | addExtensionMethods {
65 | "suspend inline fun ApplicationCall.respondCss(builder: CSSBuilder.() -> Unit)" {
66 | +"this.respondText(CSSBuilder().apply(builder).toString(), ContentType.Text.CSS)"
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/DataConversionFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object DataConversionFeature : ServerFeature(ApplicationKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "data-conversion"
27 | override val title = "DataConversion"
28 | override val description = "Allows to serialize and deserialize a list of values (used by the Locations feature)"
29 | override val documentation = "https://ktor.io/docs/data-conversion.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.features.*")
33 | addFeatureInstall {
34 | +"install(DataConversion)"
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/DefaultHeadersFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object DefaultHeadersFeature : ServerFeature(ApplicationKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "default-headers"
27 | override val title = "DefaultHeaders"
28 | override val description = "This feature adds a default set of headers to HTTP responses"
29 | override val documentation = "https://ktor.io/docs/default-headers.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.features.*")
33 | addFeatureInstall {
34 | "install(DefaultHeaders)" {
35 | +"header(\"X-Engine\", \"Ktor\") // will send this header with each response"
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/ForwardedHeaderSupportFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object ForwardedHeaderSupportFeature : ServerFeature(ApplicationKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "forwarded-header-support"
27 | override val title = "ForwardedHeaderSupport"
28 | override val description = "This feature allows you to handle reverse proxy headers to get information about the original request when it’s behind a proxy."
29 | override val documentation = "https://ktor.io/docs/forward-headers.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.features.*")
33 | addFeatureInstall {
34 | +"install(ForwardedHeaderSupport) // WARNING: for security, do not include this if not behind a reverse proxy"
35 | +"install(XForwardedHeaderSupport) // WARNING: for security, do not include this if not behind a reverse proxy"
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/FreemarkerFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object FreemarkerFeature : ServerFeature(ApplicationKt, RoutingFeature) {
25 | override val group: String = "Templating"
26 | override val artifacts = listOf("io.ktor:ktor-freemarker:\$ktor_version")
27 | override val id = "freemarker"
28 | override val title = "Freemarker"
29 | override val description = "Serve HTML content using Apache's FreeMarker template engine"
30 | override val documentation = "https://ktor.io/docs/freemarker.html"
31 |
32 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
33 | addImport("freemarker.cache.*")
34 | addImport("io.ktor.freemarker.*")
35 | addApplicationClasses {
36 | +"data class IndexData(val items: List)"
37 | }
38 | addFeatureInstall {
39 | "install(FreeMarker)" {
40 | +"templateLoader = ClassTemplateLoader(this::class.java.classLoader, \"templates\")"
41 | }
42 | }
43 | addRoute {
44 | "get(\"/html-freemarker\")" {
45 | +"call.respond(FreeMarkerContent(\"index.ftl\", mapOf(\"data\" to IndexData(listOf(1, 2, 3))), \"\"))"
46 | }
47 | }
48 | fileText("resources/templates/index.ftl") {
49 | +"<#-- @ftlvariable name=\"data\" type=\"${info.artifactGroup}.IndexData\" -->"
50 | +""
51 | indent {
52 | +""
53 | indent {
54 | +""
55 | +"<#list data.items as item>"
56 | indent {
57 | +"- \${item}
"
58 | }
59 | +"#list>"
60 | +"
"
61 | }
62 | +""
63 | }
64 | +""
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/HSTSFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object HSTSFeature : ServerFeature(ApplicationKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "hsts"
27 | override val title = "HSTS"
28 | override val description = "Enable HTTP Strict Transport Security (HSTS)"
29 | override val documentation = "https://ktor.io/docs/hsts.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.features.*")
33 | addFeatureInstall {
34 | "install(HSTS)" {
35 | +"includeSubDomains = true"
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/HtmlDslFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object HtmlDslFeature : ServerFeature(ApplicationKt, RoutingFeature) {
25 | override val group: String = "Templating"
26 | override val repos = Repos.mavenCentral
27 | override val artifacts = listOf("io.ktor:ktor-html-builder:\$ktor_version")
28 | override val id = "html-dsl"
29 | override val title = "HTML DSL"
30 | override val description = "Generate HTML using Kotlin code like a pure-core template engine"
31 | override val documentation = "https://ktor.io/docs/html-dsl.html"
32 |
33 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
34 | addImport("io.ktor.html.*")
35 | addImport("kotlinx.html.*")
36 | addRoute {
37 | "get(\"/html-dsl\")" {
38 | "call.respondHtml" {
39 | "body" {
40 | +"h1 { +\"HTML\" }"
41 | "ul" {
42 | "for (n in 1..10)" {
43 | +"li { +\"\$n\" }"
44 | }
45 | }
46 | }
47 | }
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/HttpsRedirectFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object HttpsRedirectFeature : ServerFeature(ApplicationKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "https-redirect"
27 | override val title = "HttpsRedirect"
28 | override val description = "All the affected HTTP calls perform a redirect to its HTTPS counterpart before processing the call"
29 | override val documentation = "https://ktor.io/docs/https-redirect.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.features.*")
33 | addFeatureInstall {
34 | +"// https://ktor.io/servers/features/https-redirect.html#testing"
35 | +"if (!testing)" {
36 | +"install(HttpsRedirect)" {
37 | +"// The port to redirect to. By default 443, the default HTTPS port."
38 | +"sslPort = 443"
39 | +"// 301 Moved Permanently, or 302 Found redirect."
40 | +"permanentRedirect = true"
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/JsonGsonFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object JsonGsonFeature : ServerFeature(ApplicationKt,
25 | ContentNegotiationFeature,
26 | RoutingFeature
27 | ) {
28 | override val group: String = "Content Negotiation"
29 |
30 | override val artifacts = listOf("io.ktor:ktor-gson:\$ktor_version")
31 | override val id = "ktor-gson"
32 | override val title = "GSON"
33 | override val description = "Handles JSON serialization using GSON library"
34 | override val documentation = "https://ktor.io/docs/content-negotiation-gson.html"
35 |
36 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
37 | addImport("io.ktor.gson.*")
38 | addImport("io.ktor.features.*")
39 | appendSeparated(ContentNegotiationFeature.BLOCK) {
40 | "gson" {
41 | }
42 | }
43 | addRoute {
44 | "get(\"/json/gson\")" {
45 | +"call.respond(mapOf(\"hello\" to \"world\"))"
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/JsonJacksonFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object JsonJacksonFeature : ServerFeature(ApplicationKt,
25 | ContentNegotiationFeature,
26 | RoutingFeature
27 | ) {
28 | override val group: String = "Content Negotiation"
29 |
30 | override val artifacts = listOf("io.ktor:ktor-jackson:\$ktor_version")
31 | override val id = "ktor-jackson"
32 | override val title = "Jackson"
33 | override val description = "Handles JSON serialization using Jackson library"
34 | override val documentation = "https://ktor.io/docs/content-negotiation-jackson.html"
35 |
36 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
37 | addImport("com.fasterxml.jackson.databind.*")
38 | addImport("io.ktor.jackson.*")
39 | addImport("io.ktor.features.*")
40 | appendSeparated(ContentNegotiationFeature.BLOCK) {
41 | "jackson" {
42 | +"enable(SerializationFeature.INDENT_OUTPUT)"
43 | }
44 | }
45 | addRoute {
46 | "get(\"/json/jackson\")" {
47 | +"call.respond(mapOf(\"hello\" to \"world\"))"
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/LocationsFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object LocationsFeature : ServerFeature(ApplicationKt, RoutingFeature) {
25 | override val artifacts = listOf("io.ktor:ktor-locations:\$ktor_version")
26 | override val id = "ktor-locations"
27 | override val title = "Locations"
28 | override val description = "Allows to define route locations in a typed way"
29 | override val documentation = "https://ktor.io/docs/features-locations.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.locations.*")
33 |
34 | addApplicationClasses {
35 | SEPARATOR {
36 | +"@Location(\"/location/{name}\")"
37 | +"class MyLocation(val name: String, val arg1: Int = 42, val arg2: String = \"default\")"
38 | }
39 | SEPARATOR {
40 | +"@Location(\"/type/{name}\") data class Type(val name: String)" {
41 | SEPARATOR {
42 | +"@Location(\"/edit\")"
43 | +"data class Edit(val type: Type)"
44 | }
45 | SEPARATOR {
46 | +"@Location(\"/list/{page}\")"
47 | +"data class List(val type: Type, val page: Int)"
48 | }
49 | }
50 | }
51 | }
52 | addFeatureInstall {
53 | +"install(Locations)" {
54 | }
55 | }
56 | addRoute {
57 | +"get" {
58 | +"call.respondText(\"Location: name=\${it.name}, arg1=\${it.arg1}, arg2=\${it.arg2}\")"
59 | }
60 |
61 | +"// Register nested routes"
62 | +"get" {
63 | +"call.respondText(\"Inside \$it\")"
64 | }
65 | +"get" {
66 | +"call.respondText(\"Inside \$it\")"
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/MetricsFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 |
23 | object MetricsFeature : ServerFeature(ApplicationKt) {
24 | override val artifacts = listOf("io.ktor:ktor-metrics:\$ktor_version")
25 | override val id = "ktor-metrics"
26 | override val title = "Metrics"
27 | override val description = "Adds supports for monitoring several metrics"
28 | override val documentation = "https://ktor.io/docs/features-metrics.html"
29 | }
30 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/MustacheFeature.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.features.server
2 |
3 | import io.ktor.start.BuildInfo
4 | import io.ktor.start.Repos
5 | import io.ktor.start.ServerFeature
6 | import io.ktor.start.project.ApplicationKt
7 | import io.ktor.start.project.addApplicationClasses
8 | import io.ktor.start.project.addFeatureInstall
9 | import io.ktor.start.project.addImport
10 | import io.ktor.start.util.BlockBuilder
11 |
12 | object MustacheFeature : ServerFeature(ApplicationKt, RoutingFeature) {
13 | override val group: String = "Templating"
14 | override val artifacts = listOf("io.ktor:ktor-mustache:\$ktor_version")
15 | override val id = "mustache"
16 | override val title = "Mustache"
17 | override val description = "Serve HTML content using Mustache template engine"
18 | override val documentation = "https://ktor.io/docs/mustache.html"
19 |
20 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
21 | addImport("com.github.mustachejava.DefaultMustacheFactory")
22 | addImport("io.ktor.mustache.Mustache")
23 | addImport("io.ktor.mustache.MustacheContent")
24 | addApplicationClasses {
25 | +"data class MustacheUser(val id: Int, val name: String)"
26 | }
27 | addFeatureInstall {
28 | "install(Mustache)" {
29 | +"mustacheFactory = DefaultMustacheFactory(\"templates/mustache\")"
30 | }
31 | }
32 | addRoute {
33 | "get(\"/html-mustache\")" {
34 | +"call.respond(MustacheContent(\"index.hbs\", mapOf(\"user\" to MustacheUser(1, \"user1\"))))"
35 | }
36 | }
37 | fileText("resources/templates/mustache/index.hbs") {
38 | +""
39 | +""
40 | +"Hello, {{user.name}}
"
41 | +""
42 | +""
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/PartialContentFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object PartialContentFeature : ServerFeature(ApplicationKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "partial-content"
27 | override val title = "PartialContent"
28 | override val description = "Handles requests with the Range header. " +
29 | "Generating Accept-Ranges and the Content-Range headers and slicing the served content when required."
30 | override val documentation = "https://ktor.io/docs/partial-content.html"
31 |
32 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
33 | addImport("io.ktor.features.*")
34 | addFeatureInstall {
35 | "install(PartialContent)" {
36 | +"// Maximum number of ranges that will be accepted from a HTTP request."
37 | +"// If the HTTP request specifies more ranges, they will all be merged into a single range."
38 | +"maxRangeCount = 10"
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/RoutingFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object RoutingFeature : ServerFeature(ApplicationKt, ApplicationTestKt) {
25 | override val artifacts = listOf("io.ktor:ktor-server-core:\$ktor_version")
26 | override val id = "routing"
27 | override val title = "Routing"
28 | override val description = "Allows to define structured routes and associated handlers."
29 | override val documentation = "https://ktor.io/docs/routing.html"
30 | val BLOCK = newSlot("BLOCK")
31 |
32 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
33 | addImport("io.ktor.routing.*")
34 | addImport("io.ktor.http.*")
35 | appendSeparated(ApplicationKt.MODULE_POST) {
36 | "routing" {
37 | "get(\"/\")" {
38 | +"call.respondText(\"HELLO WORLD!\", contentType = ContentType.Text.Plain)"
39 | }
40 | block(BLOCK)
41 | }
42 | }
43 |
44 | addTestMethod("testRoot") {
45 | +"withTestApplication({ module(testing = true) })" {
46 | +"handleRequest(HttpMethod.Get, \"/\").apply" {
47 | +"assertEquals(HttpStatusCode.OK, response.status())"
48 | +"assertEquals(\"HELLO WORLD!\", response.content)"
49 | }
50 | }
51 | }
52 | }
53 | }
54 |
55 | fun BlockBuilder.addRoute(callback: Indenter.() -> Unit) {
56 | appendSeparated(RoutingFeature.BLOCK) {
57 | callback()
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/SessionsFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object SessionsFeature : ServerFeature(ApplicationKt, RoutingFeature) {
25 | override val artifacts = listOf(
26 | "io.ktor:ktor-server-sessions:\$ktor_version" // Only required for Cache and Directory storages
27 | )
28 | override val id = "ktor-sessions"
29 | override val title = "Sessions"
30 | override val description = "Adds supports for sessions: with the payload in the client or the server"
31 | override val documentation = "https://ktor.io/docs/sessions.html"
32 |
33 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
34 | addImport("io.ktor.sessions.*")
35 | addApplicationClasses {
36 | +"data class MySession(val count: Int = 0)"
37 | }
38 | addFeatureInstall {
39 | +"install(Sessions)" {
40 | +"cookie(\"MY_SESSION\")" {
41 | +"cookie.extensions[\"SameSite\"] = \"lax\""
42 | }
43 | }
44 | }
45 | addRoute {
46 | +"get(\"/session/increment\")" {
47 | +"val session = call.sessions.get() ?: MySession()"
48 | +"call.sessions.set(session.copy(count = session.count + 1))"
49 | +"call.respondText(\"Counter is \${session.count}. Refresh to increment.\")"
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/ShutdownUrlFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object ShutdownUrlFeature : ServerFeature(ApplicationKt, ApplicationConf) {
25 | override val artifacts = listOf("io.ktor:ktor-server-host-common:\$ktor_version")
26 | override val id = "shutdown-url"
27 | override val title = "Shutdown URL"
28 | override val description = "This feature enables a URL that when accessed, shutdowns the server."
29 | override val documentation = "https://ktor.io/docs/shutdown-url.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.server.engine.*")
33 | addHoconDeployment {
34 | +"shutdown.url = \"/ktor/application/shutdown\""
35 | }
36 | addFeatureInstall {
37 | "install(ShutDownUrl.ApplicationCallFeature)" {
38 | +"// The URL that will be intercepted (you can also use the application.conf's ktor.deployment.shutdown.url key)"
39 | +"shutDownUrl = \"/ktor/application/shutdown\""
40 | +"// A function that will be executed to get the exit code of the process"
41 | +"exitCodeSupplier = { 0 } // ApplicationCall.() -> Int"
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/StaticContentFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object StaticContentFeature : ServerFeature(ApplicationKt, RoutingFeature) {
25 | override val artifacts = listOf("io.ktor:ktor-server-host-common:\$ktor_version")
26 | override val id = "static-content"
27 | override val title = "Static Content"
28 | override val description = "Serves static files from defined locations."
29 | override val documentation = "https://ktor.io/docs/static-content.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.content.*")
33 | addImport("io.ktor.http.content.*")
34 | addRoute {
35 | +"// Static feature. Try to access `/static/ktor_logo.svg`"
36 | "static(\"/static\")" {
37 | +"resources(\"static\")"
38 | }
39 | }
40 | fileBinary("resources/static/ktor_logo.svg") {
41 | info.fetch("static/ktor_logo.svg")
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/StatusPagesFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object StatusPagesFeature : ServerFeature(ApplicationKt, RoutingFeature) {
25 | override val artifacts = listOf("io.ktor:ktor-server-host-common:\$ktor_version")
26 | override val id = "status-pages"
27 | override val title = "Status Pages"
28 | override val description = "Allow to respond to thrown exceptions."
29 | override val documentation = "https://ktor.io/docs/status-pages.html"
30 |
31 | val CUSTOM_STATUS_PAGES = newSlot("CUSTOM_STATUS_PAGES")
32 |
33 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
34 | addImport("io.ktor.features.*")
35 | addApplicationClasses {
36 | +"class AuthenticationException : RuntimeException()"
37 | +"class AuthorizationException : RuntimeException()"
38 | }
39 | addRoute {
40 | "install(StatusPages)" {
41 | lineNoOpen("exception { cause ->") {
42 | +"call.respond(HttpStatusCode.Unauthorized)"
43 | }
44 | lineNoOpen("exception { cause ->") {
45 | +"call.respond(HttpStatusCode.Forbidden)"
46 | }
47 | SEPARATOR {
48 | block(CUSTOM_STATUS_PAGES)
49 | }
50 | }
51 | }
52 | }
53 | }
54 |
55 | fun BlockBuilder.addCustomStatusPage(callback: Indenter.() -> Unit) {
56 | appendSeparated(StatusPagesFeature.CUSTOM_STATUS_PAGES) {
57 | callback()
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/ThymeleafFeature.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.features.server
2 |
3 | import io.ktor.start.BuildInfo
4 | import io.ktor.start.Repos
5 | import io.ktor.start.ServerFeature
6 | import io.ktor.start.project.ApplicationKt
7 | import io.ktor.start.project.addApplicationClasses
8 | import io.ktor.start.project.addFeatureInstall
9 | import io.ktor.start.project.addImport
10 | import io.ktor.start.util.BlockBuilder
11 |
12 | object ThymeleafFeature : ServerFeature(ApplicationKt, RoutingFeature) {
13 | override val group: String = "Templating"
14 | override val artifacts = listOf("io.ktor:ktor-thymeleaf:\$ktor_version")
15 | override val id = "thymeleaf"
16 | override val title = "Thymeleaf"
17 | override val description = "Serve HTML content using Thymeleaf template engine"
18 | override val documentation = "https://ktor.io/docs/thymeleaf.html"
19 |
20 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
21 | addImport("io.ktor.thymeleaf.Thymeleaf")
22 | addImport("io.ktor.thymeleaf.ThymeleafContent")
23 | addImport("org.thymeleaf.templateresolver.ClassLoaderTemplateResolver")
24 | addApplicationClasses {
25 | +"data class ThymeleafUser(val id: Int, val name: String)"
26 | }
27 | addFeatureInstall {
28 | "install(Thymeleaf)" {
29 | +"setTemplateResolver(ClassLoaderTemplateResolver().apply {"
30 | indent {
31 | +"prefix = \"templates/thymeleaf/\""
32 | +"suffix = \".html\""
33 | +"characterEncoding = \"utf-8\""
34 | }
35 | +"})"
36 | }
37 | }
38 | addRoute {
39 | "get(\"/html-thymeleaf\")" {
40 | +"call.respond(ThymeleafContent(\"index\", mapOf(\"user\" to ThymeleafUser(1, \"user1\"))))"
41 | }
42 | }
43 | fileText("resources/templates/thymeleaf/index.html") {
44 | +""
45 | +""
46 | +""
47 | +""
48 | +"Title"
49 | +""
50 | +""
51 | +""
52 | +""
53 | +""
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/VelocityFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 |
23 | object VelocityFeature : ServerFeature(ApplicationKt) {
24 | override val group: String = "Templating"
25 | override val artifacts = listOf("io.ktor:ktor-velocity:\$ktor_version")
26 | override val id = "velocity"
27 | override val title = "Velocity"
28 | override val description = "Serve HTML content using Apache's Velocity template engine"
29 | override val documentation = "https://ktor.io/docs/velocity.html"
30 | }
31 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/WebjarsFeature.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.features.server
2 |
3 | import io.ktor.start.*
4 | import io.ktor.start.project.*
5 | import io.ktor.start.util.*
6 |
7 | object WebjarsFeature : ServerFeature(ApplicationKt, RoutingFeature) {
8 | override val since = Versions.V094
9 | override val artifacts = listOf(
10 | "io.ktor:ktor-webjars:\$ktor_version",
11 | "org.webjars:jquery:3.2.1" // sample
12 | )
13 | override val id = "webjars"
14 | override val title = "Webjars"
15 | override val description = "Allows you to package your assets such as javascript libraries and css as part of your uber-jar."
16 | override val documentation = "https://ktor.io/docs/webjars.html"
17 |
18 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
19 | addImport("io.ktor.webjars.*")
20 | addImport("java.time.*")
21 |
22 | addFeatureInstall {
23 | +"install(Webjars)" {
24 | +"path = \"/webjars\" //defaults to /webjars"
25 | +"zone = ZoneId.systemDefault() //defaults to ZoneId.systemDefault()"
26 | }
27 | }
28 | addRoute {
29 | +"get(\"/webjars\")" {
30 | +"call.respondText(\"\", ContentType.Text.Html)"
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/server/WebsocketsFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.server
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object WebsocketsFeature : ServerFeature(ApplicationKt, RoutingFeature) {
25 | override val artifacts = listOf("io.ktor:ktor-websockets:\$ktor_version")
26 | override val id = "ktor-websockets"
27 | override val title = "WebSockets"
28 | override val description = "Adds WebSockets support for bidirectional communication with the client"
29 | override val documentation = "https://ktor.io/docs/clients-websockets.html"
30 |
31 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
32 | addImport("io.ktor.websocket.*")
33 | addImport("io.ktor.http.cio.websocket.*")
34 | addImport("java.time.*")
35 |
36 | addFeatureInstall {
37 | +"install(io.ktor.websocket.WebSockets)" {
38 | +"pingPeriod = Duration.ofSeconds(15)"
39 | +"timeout = Duration.ofSeconds(15)"
40 | +"maxFrameSize = Long.MAX_VALUE"
41 | +"masking = false"
42 | }
43 | }
44 |
45 | addRoute {
46 | +"webSocket(\"/myws/echo\")" {
47 | +"send(Frame.Text(\"Hi from server\"))"
48 | +"while (true)" {
49 | +"val frame = incoming.receive()"
50 | +"if (frame is Frame.Text)" {
51 | +"send(Frame.Text(\"Client said: \" + frame.readText()))"
52 | }
53 | }
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/features/sockets/RawSocketsTlsFeature.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.features.sockets
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.project.*
22 | import io.ktor.start.util.*
23 |
24 | object RawSocketsTlsFeature : ServerFeature(ApplicationKt, RawSocketsFeature) {
25 | override val group = "Sockets"
26 |
27 | override val id = "ktor-network-tls"
28 | override val title = "Raw Secure SSL/TLS Sockets"
29 | override val description =
30 | "Adds Raw Socket support for listening and connecting to tcp and udp sockets with secure sockets"
31 | override val documentation = "https://ktor.io/docs/servers-raw-sockets.html#secure"
32 |
33 | override fun BlockBuilder.renderFeature(info: BuildInfo) {
34 | addImport("io.ktor.network.tls.*")
35 | addImport("io.ktor.utils.io.core.*")
36 | addImport("kotlinx.coroutines.*")
37 |
38 | //replace(RawSocketsFeature.SERVER_SOCKET) {
39 | // +"val serverSocket = aSocket(selectorManager).tcp().bind(port = DefaultPort).tls()"
40 | //}
41 | //replace(RawSocketsFeature.CLIENT_SOCKET) {
42 | // +"val socket = aSocket(selectorManager).tcp().connect(\"127.0.0.1\", port = DefaultPort).tls()"
43 | //}
44 |
45 | if (info.ktorVersion >= Versions.V130) {
46 | addImport("io.ktor.utils.io.*")
47 | } else {
48 | addImport("kotlinx.io.core.*")
49 | }
50 |
51 | fileText("src/TlsRawSocket.kt") {
52 | +"package ${info.artifactGroup}"
53 | putImports(applicationKtImports)
54 | SEPARATOR {
55 | +"object TlsRawSocket" {
56 | +"@JvmStatic"
57 | +"fun main(args: Array)" {
58 | +"runBlocking" {
59 | +"val selectorManager = ActorSelectorManager(Dispatchers.IO)"
60 | +"val socket = aSocket(selectorManager).tcp().connect(\"www.google.com\", port = 443).tls(coroutineContext = coroutineContext)"
61 | +"val write = socket.openWriteChannel()"
62 | +"val EOL = \"\\r\\n\""
63 | +"write.writeStringUtf8(\"GET / HTTP/1.1\${EOL}Host: www.google.com\${EOL}Connection: close\${EOL}\${EOL}\")"
64 | +"write.flush()"
65 | +"println(socket.openReadChannel().readRemaining().readBytes().toString(Charsets.UTF_8))"
66 | }
67 | }
68 | }
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/http/HttpStatusCodes.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.http
2 |
3 | data class FreeHttpStatusCode(val code: Int, val description: String)
4 |
5 | enum class HttpStatusCode(val code: Int, val description: String) {
6 | Continue(100, "Continue"),
7 | SwitchingProtocols(101, "Switching Protocols"),
8 | Processing(102, "Processing"),
9 |
10 | OK(200, "OK"),
11 | Created(201, "Created"),
12 | Accepted(202, "Accepted"),
13 | NonAuthoritativeInformation(203, "Non-Authoritative Information"),
14 | NoContent(204, "No Content"),
15 | ResetContent(205, "Reset Content"),
16 | PartialContent(206, "Partial Content"),
17 |
18 | MultipleChoices(300, "Multiple Choices"),
19 | MovedPermanently(301, "Moved Permanently"),
20 | Found(302, "Found"),
21 | SeeOther(303, "See Other"),
22 | NotModified(304, "Not Modified"),
23 | UseProxy(305, "Use Proxy"),
24 | SwitchProxy(306, "Switch Proxy"),
25 | TemporaryRedirect(307, "Temporary Redirect"),
26 | PermanentRedirect(308, "Permanent Redirect"),
27 |
28 | BadRequest(400, "Bad Request"),
29 | Unauthorized(401, "Unauthorized"),
30 | PaymentRequired(402, "Payment Required"),
31 | Forbidden(403, "Forbidden"),
32 | NotFound(404, "Not Found"),
33 | MethodNotAllowed(405, "Method Not Allowed"),
34 | NotAcceptable(406, "Not Acceptable"),
35 | ProxyAuthenticationRequired(407, "Proxy Authentication Required"),
36 | RequestTimeout(408, "Request Timeout"),
37 | Conflict(409, "Conflict"),
38 | Gone(410, "Gone"),
39 | LengthRequired(411, "Length Required"),
40 | PreconditionFailed(412, "Precondition Failed"),
41 | PayloadTooLarge(413, "Payload Too Large"),
42 | RequestURITooLong(414, "Request-URI Too Long"),
43 |
44 | UnsupportedMediaType(415, "Unsupported Media Type"),
45 | RequestedRangeNotSatisfiable(416, "Requested Range Not Satisfiable"),
46 | ExceptionFailed(417, "Exception Failed"),
47 | UpgradeRequired(426, "Upgrade Required"),
48 | TooManyRequests(429, "Too Many Requests"),
49 | RequestHeaderFieldTooLarge(431, "Request Header Fields Too Large"),
50 |
51 | InternalServerError(500, "Internal Server Error"),
52 | NotImplemented(501, "Not Implemented"),
53 | BadGateway(502, "Bad Gateway"),
54 | ServiceUnavailable(503, "Service Unavailable"),
55 | GatewayTimeout(504, "Gateway Timeout"),
56 | VersionNotSupported(505, "HTTP Version Not Supported"),
57 | VariantAlsoNegotiates(506, "Variant Also Negotiates");
58 |
59 | val free = FreeHttpStatusCode(code, description)
60 |
61 | companion object {
62 | val byCode = values().associateBy { it.code }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/project/ApplicationConf.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.project
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.util.*
22 |
23 | object ApplicationConf : BuildInfoBlock() {
24 | val KTOR = newSlot("KTOR")
25 | val DEPLOYMENT = newSlot("DEPLOYMENT")
26 | val TOP = newSlot("CONF")
27 |
28 | override fun BlockBuilder.render(info: BuildInfo) {
29 | fileText("resources/application.conf") {
30 | "ktor" {
31 | "deployment" {
32 | +"port = 8080"
33 | +"port = \${?PORT}"
34 | block(DEPLOYMENT)
35 | }
36 |
37 | "application" {
38 | +"modules = [ ${info.artifactGroup}.ApplicationKt.module ]"
39 | }
40 |
41 | block(KTOR)
42 | }
43 | block(TOP)
44 | }
45 | }
46 | }
47 |
48 | fun BlockBuilder.addHoconDeployment(block: Indenter.() -> Unit) {
49 | appendSeparated(ApplicationConf.DEPLOYMENT) {
50 | block()
51 | }
52 | }
53 |
54 | fun BlockBuilder.addHoconKtor(block: Indenter.() -> Unit) {
55 | appendSeparated(ApplicationConf.KTOR) {
56 | block()
57 | }
58 | }
59 |
60 | fun BlockBuilder.addHoconTop(block: Indenter.() -> Unit) {
61 | appendSeparated(ApplicationConf.TOP) {
62 | block()
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/project/ApplicationTestKt.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.project
2 |
3 | import io.ktor.start.*
4 | import io.ktor.start.util.*
5 |
6 | object ApplicationTestKt : BuildInfoBlock(ApplicationKt) {
7 | val TESTS = newSlot("TESTS")
8 |
9 | override fun BlockBuilder.render(info: BuildInfo) {
10 | addTestImport("kotlin.test.*")
11 | addTestImport("io.ktor.server.testing.*")
12 |
13 | fileText("test/ApplicationTest.kt") {
14 | +"package ${info.artifactGroup}"
15 | SEPARATOR {
16 | linedeferred {
17 | for (import in applicationKtImports + applicationTestKtImports) {
18 | +"import $import"
19 | }
20 | }
21 | }
22 | SEPARATOR {
23 | "class ApplicationTest" {
24 | block(TESTS)
25 | }
26 | }
27 | }
28 | }
29 | }
30 |
31 | val BlockBuilder.applicationTestKtImports: LinkedHashSet by Extra.PropertyThis { LinkedHashSet() }
32 |
33 | fun BlockBuilder.addTestImport(import: String) {
34 | applicationTestKtImports += import
35 | }
36 |
37 | fun BlockBuilder.addTestMethod(name: String, block: Indenter.() -> Unit) {
38 | appendSeparated(ApplicationTestKt.TESTS) {
39 | +"@Test"
40 | "fun $name()" {
41 | block()
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/project/BuildFiles.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.project
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.util.*
22 |
23 | object BuildFiles : BuildInfoBlock() {
24 | override fun BlockBuilder.render(info: BuildInfo) {
25 | when (info.projectType) {
26 | ProjectType.Gradle -> BuildFilesGradle(kotlin = false).apply { render(info) }
27 | ProjectType.GradleKotlinDsl -> BuildFilesGradle(kotlin = true).apply { render(info) }
28 | ProjectType.Maven -> BuildFilesMaven.apply { render(info) }
29 | }
30 |
31 | addMavenRepository(Repos.local)
32 | addMavenRepository(Repos.mavenCentral)
33 | addCompileDependency(MvnArtifact("org.jetbrains.kotlin:kotlin-stdlib-jdk8:\$kotlin_version"))
34 |
35 | addCompileDependency(MvnArtifact("io.ktor:ktor-server-${info.ktorEngine.id}:\$ktor_version"))
36 | addCompileDependency(MvnArtifact("ch.qos.logback:logback-classic:\$logback_version"))
37 | addTestDependency(MvnArtifact("io.ktor:ktor-server-tests:\$ktor_version"))
38 | }
39 | }
40 |
41 | internal fun BlockBuilder.getAllReposToInclude(info: BuildInfo) = this.reposToInclude + info.ktorVersion.extraRepos.toSet()
42 |
43 | internal val BlockBuilder.reposToInclude: LinkedHashSet by Extra.PropertyThis { LinkedHashSet() }
44 | internal val BlockBuilder.compileDependencies: LinkedHashSet by Extra.PropertyThis { LinkedHashSet() }
45 | internal val BlockBuilder.testDependencies: LinkedHashSet by Extra.PropertyThis { LinkedHashSet() }
46 |
47 | fun BlockBuilder.addMavenRepository(repository: String) {
48 | reposToInclude += repository
49 | }
50 |
51 | fun BlockBuilder.addMavenRepository(repos: List) {
52 | reposToInclude += repos
53 | }
54 |
55 | fun BlockBuilder.addCompileDependency(dependency: MvnArtifact) {
56 | compileDependencies += dependency
57 | }
58 |
59 | fun BlockBuilder.addTestDependency(dependency: MvnArtifact) {
60 | testDependencies += dependency
61 | }
62 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/project/GitIgnoreFile.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.project
2 |
3 | import io.ktor.start.*
4 | import io.ktor.start.util.*
5 |
6 | object GitIgnoreFile : BuildInfoBlock() {
7 | override fun BlockBuilder.render(info: BuildInfo) {
8 | fileText(".gitignore") {
9 | +"/.gradle"
10 | +"/.idea"
11 | +"/out"
12 | +"/build"
13 | +"*.iml"
14 | +"*.ipr"
15 | +"*.iws"
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/project/LogBackXml.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.project
2 |
3 | import io.ktor.start.*
4 | import io.ktor.start.util.*
5 |
6 | internal object LogBackXml : BuildInfoBlock() {
7 | override fun BlockBuilder.render(info: BuildInfo) {
8 | fileText("resources/logback.xml") {
9 | xml {
10 | "" {
11 | "" {
12 | "" {
13 | +"%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
14 | }
15 | }
16 | "" {
17 | +""
18 | }
19 | +""
20 | +""
21 | }
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/project/Properties.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.project
2 |
3 | import io.ktor.start.*
4 |
5 | object Properties {
6 | fun getProperties(info: BuildInfo): Map {
7 | return HashMap().apply {
8 | this["kotlin.code.style"] = "official"
9 | this["kotlin_version"] = info.kotlinVersion.toString()
10 | this["ktor_version"] = info.ktorVersion.toString()
11 | this["logback_version"] = "1.2.1"
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/swagger/ContentType.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.swagger
2 |
3 | data class ContentType(val str: String) {
4 | companion object {
5 | val ApplicationJson = ContentType("application/json")
6 | val ApplicationXWwwFormUrlencoded = ContentType("application/x-www-form-urlencoded")
7 | }
8 |
9 | override fun toString(): String = str
10 | }
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/swagger/SwaggerGenerator.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.swagger
2 |
3 | import io.ktor.start.BuildInfo
4 | import io.ktor.start.features.server.addCustomStatusPage
5 | import io.ktor.start.project.*
6 | import io.ktor.start.util.*
7 |
8 | class SwaggerGenerator(
9 | val model: SwaggerModel,
10 | val generationKind: Kind
11 | ) : Block(*model.buildDepsFromModel().toTypedArray()) {
12 | enum class Kind { INTERFACE, RAW }
13 |
14 | override fun BlockBuilder.render(info: BuildInfo) {
15 | addImport("kotlin.reflect.*") // For KClass
16 | addImport("java.util.*") // For Date
17 |
18 | addCustomStatusPage {
19 | "exception"(suffix = " cause ->") {
20 | +"call.respond(cause.code, cause.description)"
21 | }
22 | }
23 |
24 | val arguments = SwaggerArguments(buildList {
25 | if (model.securityDefinitions.isNotEmpty()) {
26 | SwaggerGeneratorCommon.apply {
27 | addAll(generateJwt(model))
28 | }
29 | }
30 | })
31 |
32 | when (generationKind) {
33 | Kind.RAW -> {
34 | SwaggerGeneratorRaw.apply {
35 | registerRoutes(info, model, arguments)
36 | fileSwaggerDtos("src/${model.info.className}.kt", info, model)
37 | fileSwaggerBackendHandler("src/${model.info.classNameServer}.kt", info, model, arguments)
38 | fileSwaggerFrontendHandler("src/${model.info.classNameClient}.kt", info, model)
39 | }
40 | }
41 | Kind.INTERFACE -> {
42 | SwaggerGeneratorInterface.apply {
43 | registerRoutes(info, model, arguments)
44 | fileSwaggerCommonInterface("src/${model.info.className}.kt", info, model)
45 | fileSwaggerBackendHandler("src/${model.info.classNameServer}.kt", info, model, arguments)
46 | fileSwaggerFrontendHandler("src/${model.info.classNameClient}.kt", info, model)
47 | }
48 | }
49 | }
50 |
51 | SwaggerGeneratorCommon.apply {
52 | fileSwaggerBackendTests("test/${model.info.classNameServerTest}.kt", info, model)
53 | filesHttpApi(
54 | "api.http",
55 | "http-client.env.json",
56 | if (model.filename.endsWith(".json")) "api.json" else "api.yaml",
57 | info,
58 | model
59 | )
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/DateTime.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.util
19 |
20 | expect class DateTime
21 |
22 | expect fun NewDateTime(): DateTime
23 | expect fun NewDateTime(time: Long): DateTime
24 | expect val DateTime.time: Long
25 |
26 | expect val DateTime.fullYear: Int
27 | expect val DateTime.month: Int
28 | expect val DateTime.date: Int
29 | expect val DateTime.hours: Int
30 | expect val DateTime.minutes: Int
31 | expect val DateTime.seconds: Int
32 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/FileMode.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.util
2 |
3 | data class FileMode(val mode: Int) {
4 | constructor(octalMode: String) : this(octalMode.toInt(8))
5 |
6 | val isUserExecutable: Boolean
7 | get() = ((mode ushr 6) and 1) != 0
8 | }
9 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/FormUrlEncoded.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.util
2 |
3 | fun String.encodeURIComponent(): String {
4 | return buildString {
5 | for (v in this@encodeURIComponent) {
6 | when (v) {
7 | '&', ' ', '=', '/' -> {
8 | append('%')
9 | append(v.toInt().toString(16).padStart(2, '0'))
10 | }
11 | else -> append(v)
12 | }
13 | }
14 | }
15 | }
16 |
17 | //fun List>.formUrlEncode(): String =
18 | // joinToString("&") { it.first.encodeURIComponent() + "=" + it.second.encodeURIComponent() }
19 |
20 |
21 | // @TODO: Encode
22 | fun String.formUrlDecode(): Map> = this.split('&')
23 | .map { val (key, value) = it.split('=', limit = 2) + listOf(""); key to value }
24 | .groupBy { it.first }
25 | .map { it.key to it.value.map { it.second } }
26 | .toMap()
27 |
28 | fun List>.formUrlEncode(): String =
29 | this.joinToString("&") {
30 | when {
31 | it.second.isNotEmpty() -> "${it.first.encodeURIComponent()}=${it.second.encodeURIComponent()}"
32 | else -> it.first.encodeURIComponent()
33 | }
34 | }
35 |
36 | fun Map>.formUrlEncode(): String =
37 | entries.flatMap { entry -> entry.value.map { entry.key to it } }.formUrlEncode()
38 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/MetaListIterator.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.util
2 |
3 | class MetaListIterable(val items: List) : Iterable, T>> {
4 | override fun iterator() =
5 | items.withIndex().map { IteratorStepInfo(it.index, items.size, it.value) to it.value }.iterator()
6 | }
7 |
8 | val Iterable.metaIter get() = MetaListIterable(this.toList())
9 |
10 | data class IteratorStepInfo(
11 | val index0: Int,
12 | val length: Int,
13 | val item: T
14 | ) {
15 | val isFirst get() = index0 == 0
16 | val isLast get() = index0 >= length - 1
17 | }
18 |
19 | val IteratorStepInfo.optComma get() = if (this.isLast) "" else ","
20 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/Stack.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.util
2 |
3 | class Stack {
4 | private val items = arrayListOf()
5 |
6 | val size get() = items.size
7 | fun pop(): T = items.removeAt(items.size - 1)
8 | fun peek(): T = items[items.size - 1]
9 | fun push(value: T) = run { items.add(value) }
10 | }
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/StrReader.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.util
2 |
3 | import kotlin.math.*
4 |
5 |
6 | class StrReader(val str: String, val file: String = "file", var pos: Int = 0) {
7 | val length: Int = this.str.length
8 | val hasMore: Boolean get() = (this.pos < this.str.length)
9 |
10 | inline fun slice(action: () -> Unit): String? {
11 | val start = this.pos
12 | action()
13 | val end = this.pos
14 | return if (end > start) this.slice(start, end) else null
15 | }
16 |
17 | fun slice(start: Int, end: Int): String = this.str.substring(start, end)
18 | fun peek(count: Int): String = substr(this.pos, count)
19 | fun peekChar(): Char = if (hasMore) this.str[this.pos] else '\u0000'
20 | fun read(count: Int): String = this.peek(count).apply { skip(count) }
21 | inline fun skipWhile(filter: (Char) -> Boolean) = run { while (hasMore && filter(this.peekChar())) this.readChar() }
22 |
23 | inline fun readWhile(filter: (Char) -> Boolean) = this.slice { skipWhile(filter) } ?: ""
24 | fun unread(count: Int = 1) = this.apply { this.pos -= count; }
25 | fun readChar(): Char = if (hasMore) this.str[this.pos++] else '\u0000'
26 | fun read(): Char = if (hasMore) this.str[this.pos++] else '\u0000'
27 |
28 |
29 | fun readExpect(expected: String): String {
30 | val readed = this.read(expected.length)
31 | if (readed != expected) throw IllegalArgumentException("Expected '$expected' but found '$readed' at $pos")
32 | return readed
33 | }
34 |
35 | fun expect(expected: Char) = readExpect("$expected")
36 | fun skip(count: Int = 1) = this.apply { this.pos += count; }
37 | private fun substr(pos: Int, length: Int): String {
38 | return this.str.substring(min(pos, this.length), min(pos + length, this.length))
39 | }
40 |
41 | fun skipSpaces() = this.apply { this.skipWhile { it.isWhitespace() } }
42 |
43 | fun tryRead(str: String): Boolean {
44 | if (peek(str.length) == str) {
45 | skip(str.length)
46 | return true
47 | }
48 | return false
49 | }
50 | }
51 |
52 | fun StrReader.readStringLit(reportErrors: Boolean = true): String {
53 | val out = StringBuilder()
54 | val quotec = read()
55 | when (quotec) {
56 | '"', '\'' -> Unit
57 | else -> error("Invalid string literal")
58 | }
59 | var closed = false
60 | while (hasMore) {
61 | val c = read()
62 | if (c == '\\') {
63 | val cc = read()
64 | out.append(
65 | when (cc) {
66 | '\\' -> '\\'; '/' -> '/'; '\'' -> '\''; '"' -> '"'
67 | 'b' -> '\b'; 'f' -> '\u000c'; 'n' -> '\n'; 'r' -> '\r'; 't' -> '\t'
68 | 'u' -> read(4).toInt(0x10).toChar()
69 | else -> Json.invalidJson("Invalid char '$cc'")
70 | }
71 | )
72 | } else if (c == quotec) {
73 | closed = true
74 | break
75 | } else {
76 | out.append(c)
77 | }
78 | }
79 | if (!closed && reportErrors) {
80 | throw RuntimeException("String literal not closed! '${this.str}'")
81 | }
82 | return out.toString()
83 | }
84 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/baos.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.util
19 |
20 | import kotlin.math.*
21 |
22 | class ByteArrayOutputStream {
23 | private var pos = 0
24 | private var data = ByteArray(1024)
25 | val size get() = pos
26 |
27 | private fun ensure(count: Int): ByteArrayOutputStream {
28 | if (pos + count > data.size) {
29 | data = data.copyOf(max(pos + count, data.size * 2))
30 | }
31 | return this
32 | }
33 |
34 | private inline fun byte(v: Number) = run { data[pos++] = v.toByte() }
35 | fun u8(v: Int) = ensure(1).apply { byte(v) }
36 | fun u16_le(v: Int) = ensure(2).apply { byte(v shr 0); byte(v shr 8) }
37 | fun u32_le(v: Int) = ensure(4).apply { byte(v shr 0); byte(v shr 8); byte(v shr 16); byte(v shr 24) }
38 | fun bytes(data: ByteArray) = ensure(data.size).apply { for (n in 0 until data.size) byte(data[n]) }
39 |
40 | fun toByteArray(): ByteArray {
41 | return data.copyOf(pos)
42 | }
43 |
44 | inline fun build(builder: ByteArrayOutputStream.() -> Unit): ByteArray {
45 | builder(this)
46 | return toByteArray()
47 | }
48 | }
49 |
50 | inline fun buildByteArray(builder: ByteArrayOutputStream.() -> Unit): ByteArray = ByteArrayOutputStream().build(builder)
51 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/buildList.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.util
2 |
3 | inline fun buildList(callback: MutableList.() -> Unit): List = ArrayList().apply(callback)
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/crc32.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.util
19 |
20 | object CRC32 {
21 | val table = IntArray(256).apply {
22 | val POLY: Int = 0xEDB88320.toInt()
23 | for (n in 0 until 256) {
24 | var c = n
25 | for (k in 0 until 8) {
26 | c = if ((c and 1) != 0) {
27 | POLY xor (c ushr 1)
28 | } else {
29 | c ushr 1
30 | }
31 | }
32 | this[n] = c
33 | }
34 | }
35 |
36 | fun update(initial: Int, u: ByteArray): Int {
37 | var crc = initial xor (-1)
38 | for (i in 0 until u.size) {
39 | crc = table[(crc xor u[i].toInt()) and 0xFF] xor (crc ushr 8)
40 | }
41 | return crc xor (-1)
42 | }
43 | }
44 |
45 | fun ByteArray.crc32(): Int = CRC32.update(0, this)
46 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/ext.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.util
19 |
20 | val String.octal get() = toInt(8)
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/extra.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.util
19 |
20 | import kotlin.reflect.*
21 |
22 |
23 | interface Extra {
24 | var extra: LinkedHashMap?
25 |
26 | class Mixin(override var extra: LinkedHashMap? = null) : Extra
27 |
28 | @Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
29 |
30 | class Property(val name: String? = null, val defaultGen: () -> T) {
31 | inline operator fun getValue(thisRef: Extra, property: KProperty<*>): T {
32 | val res = (thisRef.extra?.get(name ?: property.name) as T?)
33 | if (res == null) {
34 | val r = defaultGen()
35 | setValue(thisRef, property, r)
36 | return r
37 | }
38 | return res
39 | }
40 |
41 | inline operator fun setValue(thisRef: Extra, property: KProperty<*>, value: T): Unit = run {
42 | //beforeSet(value)
43 | thisRef.setExtra(name ?: property.name, value as Any?)
44 | //afterSet(value)
45 | }
46 | }
47 |
48 | class PropertyThis(val name: String? = null, val defaultGen: T2.() -> T) {
49 | inline operator fun getValue(thisRef: T2, property: KProperty<*>): T {
50 | val res = (thisRef.extra?.get(name ?: property.name) as T?)
51 | if (res == null) {
52 | val r = defaultGen(thisRef)
53 | setValue(thisRef, property, r)
54 | return r
55 | }
56 | return res
57 | }
58 |
59 | inline operator fun setValue(thisRef: T2, property: KProperty<*>, value: T): Unit = run {
60 | //beforeSet(value)
61 | if (thisRef.extra == null) thisRef.extra = LinkedHashMap()
62 | thisRef.extra?.set(name ?: property.name, value as Any?)
63 | //afterSet(value)
64 | }
65 | }
66 | }
67 |
68 | fun Extra.getExtraTyped(name: String): T? = extra?.get(name) as T?
69 | fun Extra.getExtra(name: String): Any? = extra?.get(name)
70 | fun Extra.setExtra(name: String, value: Any?): Unit {
71 | if (extra == null) extra = LinkedHashMap()
72 | extra?.set(name, value)
73 | }
74 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/hex.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.util
2 |
3 | object Hex {
4 | private val DIGITS = "0123456789ABCDEF"
5 | private val DIGITS_UPPER = DIGITS.toUpperCase()
6 | private val DIGITS_LOWER = DIGITS.toLowerCase()
7 |
8 | fun decodeChar(c: Char): Int = when (c) {
9 | in '0'..'9' -> c - '0'
10 | in 'a'..'f' -> c - 'a' + 10
11 | in 'A'..'F' -> c - 'A' + 10
12 | else -> -1
13 | }
14 |
15 | fun encodeCharLower(v: Int): Char = DIGITS_LOWER[v]
16 | fun encodeCharUpper(v: Int): Char = DIGITS_UPPER[v]
17 |
18 | fun isHexDigit(c: Char): Boolean = decodeChar(c) >= 0
19 |
20 | fun decode(str: String): ByteArray {
21 | val out = ByteArray((str.length + 1) / 2)
22 | var opos = 0
23 | var nibbles = 0
24 | var value = 0
25 | for (c in str) {
26 | val vv = decodeChar(c)
27 | if (vv >= 0) {
28 | value = (value shl 4) or vv
29 | nibbles++
30 | }
31 | if (nibbles == 2) {
32 | out[opos++] = value.toByte()
33 | nibbles = 0
34 | value = 0
35 | }
36 | }
37 | return if (opos != out.size) out.copyOf(opos) else out
38 | }
39 |
40 | fun encodeLower(src: ByteArray): String = encodeBase(src, DIGITS_LOWER)
41 | fun encodeUpper(src: ByteArray): String = encodeBase(src, DIGITS_UPPER)
42 |
43 | private fun encodeBase(data: ByteArray, digits: String = DIGITS): String {
44 | val out = StringBuilder(data.size * 2)
45 | for (n in data.indices) {
46 | val v = data[n].toInt() and 0xFF
47 | out.append(digits[(v ushr 4) and 0xF])
48 | out.append(digits[(v ushr 0) and 0xF])
49 | }
50 | return out.toString()
51 | }
52 | }
53 |
54 | val List.unhexIgnoreSpaces get() = joinToString("").unhexIgnoreSpaces
55 | val String.unhexIgnoreSpaces get() = this.replace(" ", "").unhex
56 | val String.unhex get() = Hex.decode(this)
57 | val ByteArray.hex get() = Hex.encodeLower(this)
58 |
59 | val Int.hex: String get() = "0x$shex"
60 | val Int.shex: String
61 | get() {
62 | var out = ""
63 | for (n in 0 until 8) {
64 | val v = (this ushr ((7 - n) * 4)) and 0xF
65 | out += Hex.encodeCharUpper(v)
66 | }
67 | return out
68 | }
69 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/id.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.util
2 |
3 | object ID {
4 | fun normalizeMethodName(str: List): String = normalizeMethodName(str.joinToString("/"))
5 | fun normalizeClassName(str: List): String = normalizeClassName(str.joinToString("/"))
6 |
7 | fun normalizeMethodName(str: String): String = normalize(str).decapitalize()
8 | fun normalizeClassName(str: String): String = normalize(str).capitalize()
9 | fun normalize(str: String): String = Regex("\\w+").findAll(str).joinToString("") { it.value.capitalize() }
10 | }
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/mvndependency.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.util
19 |
20 | data class MvnArtifact(val dependency: String) {
21 | val parts = dependency.split(":")
22 | val group get() = parts.getOrNull(0)
23 | val name get() = parts.getOrNull(1)
24 | val version get() = parts.getOrNull(2)
25 | }
26 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/quote.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.util
2 |
3 | fun String.stripLineBreaks() = this.split('\n').joinToString(" ")
4 |
5 | fun String.escape(): String {
6 | val out = StringBuilder()
7 | for (n in 0 until this.length) {
8 | val c = this[n]
9 | when (c) {
10 | '\\' -> out.append("\\\\")
11 | '"' -> out.append("\\\"")
12 | '\n' -> out.append("\\n")
13 | '\r' -> out.append("\\r")
14 | '\t' -> out.append("\\t")
15 | else -> if (c in ' ' until '\u007f') {
16 | out.append(c)
17 | } else {
18 | out.append("\\u" + c.toInt().toString(16).padStart(4, '0'))
19 | }
20 | }
21 | }
22 | return out.toString()
23 | }
24 |
25 | fun String.unescape(): String {
26 | val out = StringBuilder()
27 | var n = 0
28 | while (n < this.length) {
29 | val c = this[n++]
30 | when (c) {
31 | '\\' -> {
32 | val c2 = this[n++]
33 | when (c2) {
34 | '\\' -> out.append('\\')
35 | '"' -> out.append('\"')
36 | 'n' -> out.append('\n')
37 | 'r' -> out.append('\r')
38 | 't' -> out.append('\t')
39 | 'u' -> {
40 | val chars = this.substring(n, n + 4)
41 | n += 4
42 | out.append(chars.toInt(16).toChar())
43 | }
44 | else -> {
45 | out.append("\\$c2")
46 | }
47 | }
48 | }
49 | else -> out.append(c)
50 | }
51 | }
52 | return out.toString()
53 | }
54 |
55 | fun String?.quote(): String = if (this != null) "\"${this.escape()}\"" else "null"
56 |
57 | fun String.isQuoted(): Boolean = this.startsWith('"') && this.endsWith('"')
58 |
59 | fun String.unquote(): String = if (isQuoted()) {
60 | this.substring(1, this.length - 1).unescape()
61 | } else {
62 | this
63 | }
64 |
65 | val Any?.kquoteLit: String get() {
66 | return when (this) {
67 | null -> "null"
68 | is Number -> "$this"
69 | is String -> this.quote()
70 | is Pair<*, *> -> this.first.kquoteLit + " to " + this.second.kquoteLit
71 | is List<*> -> "listOf(" + this.joinToString(", ") { it.kquoteLit } + ")"
72 | is Set<*> -> "setOf(" + this.joinToString(", ") { it.kquoteLit } + ")"
73 | is Map<*, *> ->
74 | "mapOf(" + this.entries.joinToString(", ") { it.key.kquoteLit + " to " + it.value.kquoteLit } + ")"
75 | is Regex -> "Regex(" + this.pattern.quote() + ")"
76 | else -> ""
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/kotlin/io/ktor/start/util/semver.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.util
19 |
20 | class SemVer(val version: String) : Comparable {
21 | private val parts1 = version.split('-', limit = 2)
22 | private val parts2 = parts1.first().split('.')
23 |
24 | val major = parts2.getOrNull(0)?.toIntOrNull() ?: 0
25 | val minor = parts2.getOrNull(1)?.toIntOrNull() ?: 0
26 | val patch = parts2.getOrNull(2)?.toIntOrNull() ?: 0
27 | val info = parts1.getOrNull(1) ?: ""
28 |
29 | override fun compareTo(other: SemVer): Int {
30 | return this.major.compareTo(other.major).takeIf { it != 0 }
31 | ?: this.minor.compareTo(other.minor).takeIf { it != 0 }
32 | ?: this.patch.compareTo(other.patch).takeIf { it != 0 }
33 | ?: this.info.compareTo(other.info).takeIf { it != 0 }
34 | ?: 0
35 | }
36 |
37 | override fun toString(): String = version
38 | }
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/resources/gradle/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ktorio/ktor-init-tools/790e8b389ae9aed630eea72a73181a3a5b725977/ktor-generator/src/commonMain/resources/gradle/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/resources/gradle/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/resources/gradle/gradle/wrapper/gradle-wrapper.properties.kotlin-dsl:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/resources/gradle/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/resources/maven/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ktorio/ktor-init-tools/790e8b389ae9aed630eea72a73181a3a5b725977/ktor-generator/src/commonMain/resources/maven/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/resources/maven/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip
--------------------------------------------------------------------------------
/ktor-generator/src/commonMain/resources/static/ktor_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
--------------------------------------------------------------------------------
/ktor-generator/src/commonTest/kotlin/io/ktor/start/util/MyCommonTest.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.util
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | class MyCommonTest {
7 | @Test
8 | fun commonTest() {
9 | assertEquals(1, 1)
10 | }
11 | }
--------------------------------------------------------------------------------
/ktor-generator/src/commonTest/kotlin/io/ktor/start/util/SemVerTest.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.util
2 |
3 | import kotlin.test.*
4 |
5 | class SemVerTest {
6 | @Test
7 | fun simple() {
8 | assertEquals(
9 | "0.9.4, 0.9.5, 1.0.0, 1.0.0-alpha-2",
10 | listOf(SemVer("1.0.0"), SemVer("0.9.4"), SemVer("1.0.0-alpha-2"), SemVer("0.9.5")).sorted().joinToString(", ")
11 | )
12 |
13 | assertEquals(+1, SemVer("1.0.0").compareTo(SemVer("0.9.5")))
14 | }
15 | }
--------------------------------------------------------------------------------
/ktor-generator/src/jsMain/kotlin/io/ktor/start/util/DateTimeJs.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.util
19 |
20 | import kotlin.js.*
21 |
22 | actual typealias DateTime = Date
23 |
24 | actual fun NewDateTime(): DateTime = Date()
25 | actual fun NewDateTime(time: Long): DateTime = Date(time)
26 |
27 | actual val DateTime.time: Long get() = (this as Date).getTime().toLong()
28 |
29 | actual val DateTime.fullYear: Int get() = (this as Date).getFullYear()
30 | actual val DateTime.month: Int get() = (this as Date).getMonth()
31 | actual val DateTime.date: Int get() = (this as Date).getDate()
32 | actual val DateTime.hours: Int get() = (this as Date).getHours()
33 | actual val DateTime.minutes: Int get() = (this as Date).getMinutes()
34 | actual val DateTime.seconds: Int get() = (this as Date).getSeconds()
35 |
--------------------------------------------------------------------------------
/ktor-generator/src/jsTest/kotlin/io/ktor/start/MyJsTest.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | class MyJsTest {
7 | @Test
8 | fun test1() {
9 | assertEquals(1, 1)
10 | }
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/ktor-generator/src/jvmMain/kotlin/io/ktor/start/util/DateTimeJvm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.util
19 |
20 | import java.util.*
21 |
22 | actual typealias DateTime = Date
23 |
24 | actual fun NewDateTime(): DateTime = Date()
25 | actual fun NewDateTime(time: Long): DateTime = Date(time)
26 |
27 | actual val DateTime.time: Long get() = (this as Date).time
28 |
29 | actual val DateTime.fullYear: Int get() = (this as Date).year
30 | actual val DateTime.month: Int get() = (this as Date).month
31 | actual val DateTime.date: Int get() = (this as Date).date
32 | actual val DateTime.hours: Int get() = (this as Date).hours
33 | actual val DateTime.minutes: Int get() = (this as Date).minutes
34 | actual val DateTime.seconds: Int get() = (this as Date).seconds
35 |
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/kotlin/io/ktor/start/TestTools.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start
2 |
3 | fun getResourceBytes(name: String) =
4 | null
5 | ?: SwaggerGenerationTest::class.java.getResourceAsStream(name)?.readBytes()
6 | ?: SwaggerGenerationTest::class.java.getResourceAsStream("/$name")?.readBytes()
7 | ?: ClassLoader.getSystemClassLoader().getResourceAsStream(name)?.readBytes()
8 | ?: ClassLoader.getSystemClassLoader().getResourceAsStream("/$name")?.readBytes()
9 |
10 | fun getResourceString(name: String) =
11 | getResourceBytes(name)?.toString(Charsets.UTF_8)
12 |
13 |
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/kotlin/io/ktor/start/Tools.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start
2 |
3 | import java.io.File
4 | import java.nio.charset.Charset
5 |
6 | fun File.updateTextIfExists(charset: Charset = Charsets.UTF_8, update: (String) -> String) {
7 | if (exists()) updateText(charset, update)
8 | }
9 |
10 | fun File.updateText(charset: Charset = Charsets.UTF_8, update: (String) -> String) {
11 | val oldContent = this.readText(charset)
12 | val newContent = update(oldContent)
13 | this.writeText(newContent, charset)
14 | }
15 |
16 | operator fun File.get(child: String) = File(this, child)
17 |
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/kotlin/io/ktor/start/WriteToFolderTest.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start
2 |
3 | import io.ktor.start.util.*
4 | import java.io.*
5 |
6 | fun Map.writeToFolder(folder: File, print: Boolean = false) {
7 | for (fileResult in this.values) {
8 | if (print && fileResult.charset != null) {
9 | println("${fileResult.name}:")
10 | println(fileResult.string)
11 | println()
12 | }
13 | val file = File(folder, fileResult.name)
14 | file.parentFile.mkdirs()
15 | file.writeBytes(fileResult.data)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/kotlin/io/ktor/start/swagger/GenerationSpike.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.swagger
2 |
3 | import io.ktor.start.*
4 | import io.ktor.start.util.*
5 | import kotlinx.coroutines.*
6 | import java.io.*
7 |
8 | object GenerationSpike {
9 | @JvmStatic
10 | fun main(args: Array) {
11 | val testProjectRoot = File("/tmp/swagger-gen")
12 |
13 | runBlocking {
14 | val swaggerJson = getResourceString("/swagger.json")
15 |
16 | val model = SwaggerModel.parseJson(swaggerJson)
17 | generate(info.copy(
18 | ktorVersion = Versions.LAST
19 | ), SwaggerGenerator(model, info.swaggerGenKind)).writeToFolder(testProjectRoot)
20 | //println("RESULT: ${result.tasks.joinToString(", ") { it.path }}")
21 | }
22 | }
23 |
24 | val info = BuildInfo(
25 | includeWrapper = false,
26 | projectType = ProjectType.Gradle,
27 | ktorVersion = Versions.LAST,
28 | artifactName = "example1",
29 | artifactGroup = "com.example",
30 | artifactVersion = "0.1.0-SNAPSHOT",
31 | ktorEngine = KtorEngine.Netty,
32 | swaggerGenKind = SwaggerGenerator.Kind.RAW,
33 | fetch = { getResourceBytes(it) }
34 | )
35 |
36 | fun getResourceBytes(name: String): ByteArray {
37 | //println(File("ktor-generator/src/commonMain/resources/$name").absoluteFile)
38 | return null
39 | // @TODO: Hacks because bad import
40 | ?: File("ktor-generator/src/jvmTest/resources/$name").takeIf { it.exists() }?.readBytes()
41 | ?: File("ktor-generator/src/jvmMain/resources/$name").takeIf { it.exists() }?.readBytes()
42 | ?: File("ktor-generator/src/commonMain/resources/$name").takeIf { it.exists() }?.readBytes()
43 | ?: GenerationSpike::class.java.getResourceAsStream(name)?.readBytes()
44 | ?: GenerationSpike::class.java.getResourceAsStream("/$name")?.readBytes()
45 | ?: ClassLoader.getSystemClassLoader().getResourceAsStream(name)?.readBytes()
46 | ?: ClassLoader.getSystemClassLoader().getResourceAsStream("/$name")?.readBytes()
47 | ?: error("Can't find resources '$name'")
48 | }
49 |
50 | fun getResourceString(name: String) =
51 | getResourceBytes(name)?.toString(Charsets.UTF_8)
52 |
53 | fun Map.writeToFolder(folder: File, print: Boolean = false) {
54 | for (fileResult in this.values) {
55 | if (print && fileResult.charset != null) {
56 | println("${fileResult.name}:")
57 | println(fileResult.string)
58 | println()
59 | }
60 | val file = File(folder, fileResult.name)
61 | file.parentFile.mkdirs()
62 | file.writeBytes(fileResult.data)
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/kotlin/io/ktor/start/swagger/JsonSchemaTest.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.swagger
2 |
3 | import org.junit.Test
4 | import kotlin.test.*
5 |
6 | class JsonSchemaTest {
7 | @Test
8 | fun name() {
9 | assertEquals("it <= 100", test(mapOf("maximum" to 100)))
10 | assertEquals("it < 100", test(mapOf("maximum" to 100, "exclusiveMaximum" to true)))
11 | assertEquals("it in 10 .. 100", test(mapOf("minimum" to 10, "maximum" to 100)))
12 | assertEquals("it in 10 until 100", test(mapOf("minimum" to 10, "maximum" to 100, "exclusiveMaximum" to true)))
13 | assertEquals("it > 10 && it < 100", test(mapOf("minimum" to 10, "exclusiveMinimum" to true, "maximum" to 100, "exclusiveMaximum" to true)))
14 | assertEquals("it > 10 && it <= 100", test(mapOf("minimum" to 10, "exclusiveMinimum" to true, "maximum" to 100, "exclusiveMaximum" to false)))
15 | }
16 |
17 | @Test
18 | fun length() {
19 | assertEquals("it.length >= 4", test(mapOf("minLength" to 4)))
20 | assertEquals("it.length <= 16", test(mapOf("maxLength" to 16)))
21 | assertEquals("it.length in 4..16", test(mapOf("minLength" to 4, "maxLength" to 16)))
22 | }
23 |
24 | private inline fun test(map: Map) = JsonRule.parse(map).toKotlin("it", T::class)
25 | }
26 |
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/kotlin/io/ktor/start/swagger/ModelTest.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.swagger
2 |
3 | import org.junit.Test
4 | import kotlin.test.assertEquals
5 |
6 | class ModelTest {
7 | @Test
8 | fun `support default value for float type`() {
9 | assertEquals(0.0f, SwaggerModel.FloatType.toDefaultUntyped())
10 | assertEquals(42.0f, SwaggerModel.FloatType.toDefaultUntyped(emptyList(), 42.0))
11 | }
12 | }
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/kotlin/io/ktor/start/swagger/YamlSchemaTest.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.swagger
2 |
3 | import io.ktor.start.util.*
4 | import kotlin.test.*
5 |
6 | class YamlSchemaTest {
7 | @Test
8 | fun openAPITest() {
9 | val openAPIStream = YamlSchemaTest::javaClass.javaClass.classLoader
10 | .getResourceAsStream("openapi.yaml")!!
11 | .readBytes()
12 | .toString(UTF8)
13 |
14 | val model = SwaggerModel.parseJsonOrYaml(openAPIStream, filename = "openapi.yaml")
15 |
16 | val windowHierarchyChildDef = model.definitions["WindowHierarchyChild"]
17 | ?: error("WindowHierarchyChild does not exist")
18 | val expectedOptions = listOf("id", "parent", "text", "package", "checkable", "clickable", "index",
19 | "contentDescription", "focusable", "resourceId", "enabled", "password", "longClickable", "longText",
20 | "clazz", "scrollable", "selected", "checked", "focused", "bounds", "children")
21 |
22 | for (requiredOption in expectedOptions) {
23 | assertTrue { windowHierarchyChildDef.props.contains(requiredOption) }
24 | }
25 |
26 | val prop = windowHierarchyChildDef.props["children"]
27 | assertEquals("List", prop!!.type.toString())
28 | }
29 | }
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/kotlin/io/ktor/util/IdTest.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.util
2 |
3 | import io.ktor.start.util.*
4 | import org.junit.Test
5 | import kotlin.test.*
6 |
7 | class IdTest {
8 | @Test
9 | fun name() {
10 | assertEquals("helloWorld", ID.normalizeMethodName("hello-world"))
11 | assertEquals("pathToHello", ID.normalizeMethodName("/path/to/{hello}"))
12 | }
13 | }
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/kotlin/io/ktor/util/IndenterTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.util
19 |
20 | import io.ktor.start.util.*
21 | import org.junit.Test
22 | import kotlin.test.*
23 |
24 | class IndenterTest {
25 | @Test
26 | fun name() {
27 | val indenter = Indenter {
28 | +"HELLO"
29 | +""
30 | +"WORLD"
31 | }
32 | assertEquals("HELLO\n\nWORLD\n", indenter.toString())
33 | }
34 |
35 | @Test
36 | fun testEmptyLineOnce1() {
37 | val indenter = Indenter {
38 | +"HELLO"
39 | EMPTY_LINE_ONCE()
40 | +"WORLD"
41 | }
42 | assertEquals("HELLO\n\nWORLD\n", indenter.toString())
43 | }
44 |
45 | @Test
46 | fun testEmptyLineOnce2() {
47 | val indenter = Indenter {
48 | +"HELLO"
49 | EMPTY_LINE_ONCE()
50 | EMPTY_LINE_ONCE()
51 | +"WORLD"
52 | }
53 | assertEquals("HELLO\n\nWORLD\n", indenter.toString())
54 | }
55 |
56 | @Test
57 | fun testBlock() {
58 | val indenter = Indenter {
59 | "hello" {
60 | +"world"
61 | }
62 | }
63 | assertEquals("hello {\n\tworld\n}\n", indenter.toString())
64 | }
65 | }
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/kotlin/io/ktor/util/JsonTest.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.util
2 |
3 | import io.ktor.start.util.*
4 | import org.junit.Test
5 | import kotlin.test.*
6 |
7 | class JsonTest {
8 | @Test
9 | fun testPrettyEmpty() {
10 | assertEquals("{}", Json.encodePrettyUntyped(mapOf()).trim())
11 | assertEquals("[]", Json.encodePrettyUntyped(listOf()).trim())
12 | assertEquals("{\n\t\"hello\": []\n}", Json.encodePrettyUntyped(mapOf("hello" to listOf())).trim())
13 | }
14 | }
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/resources/V30/callback-example.yaml:
--------------------------------------------------------------------------------
1 | openapi: 3.0.0
2 | info:
3 | title: Callback Example
4 | version: 1.0.0
5 | paths:
6 | /streams:
7 | post:
8 | description: subscribes a client to receive out-of-band data
9 | parameters:
10 | - name: callbackUrl
11 | in: query
12 | required: true
13 | description: |
14 | the location where data will be sent. Must be network accessible
15 | by the source server
16 | schema:
17 | type: string
18 | format: uri
19 | example: https://tonys-server.com
20 | responses:
21 | '201':
22 | description: subscription successfully created
23 | content:
24 | application/json:
25 | schema:
26 | description: subscription information
27 | required:
28 | - subscriptionId
29 | properties:
30 | subscriptionId:
31 | description: this unique identifier allows management of the subscription
32 | type: string
33 | example: 2531329f-fb09-4ef7-887e-84e648214436
34 | callbacks:
35 | # the name `onData` is a convenience locator
36 | onData:
37 | # when data is sent, it will be sent to the `callbackUrl` provided
38 | # when making the subscription PLUS the suffix `/data`
39 | '{$request.query.callbackUrl}/data':
40 | post:
41 | requestBody:
42 | description: subscription payload
43 | content:
44 | application/json:
45 | schema:
46 | properties:
47 | timestamp:
48 | type: string
49 | format: date-time
50 | userData:
51 | type: string
52 | responses:
53 | '202':
54 | description: |
55 | Your server implementation should return this HTTP status code
56 | if the data was received successfully
57 | '204':
58 | description: |
59 | Your server should return this HTTP status code if no longer interested
60 | in further updates
61 |
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/resources/V30/petstore.yaml:
--------------------------------------------------------------------------------
1 | openapi: "3.0.0"
2 | info:
3 | version: 1.0.0
4 | title: Swagger Petstore
5 | license:
6 | name: MIT
7 | servers:
8 | - url: http://petstore.swagger.io/v1
9 | paths:
10 | /pets:
11 | get:
12 | summary: List all pets
13 | operationId: listPets
14 | tags:
15 | - pets
16 | parameters:
17 | - name: limit
18 | in: query
19 | description: How many items to return at one time (max 100)
20 | required: false
21 | schema:
22 | type: integer
23 | format: int32
24 | responses:
25 | '200':
26 | description: A paged array of pets
27 | headers:
28 | x-next:
29 | description: A link to the next page of responses
30 | schema:
31 | type: string
32 | content:
33 | application/json:
34 | schema:
35 | $ref: "#/components/schemas/Pets"
36 | default:
37 | description: unexpected error
38 | content:
39 | application/json:
40 | schema:
41 | $ref: "#/components/schemas/Error"
42 | post:
43 | summary: Create a pet
44 | operationId: createPets
45 | tags:
46 | - pets
47 | responses:
48 | '201':
49 | description: Null response
50 | default:
51 | description: unexpected error
52 | content:
53 | application/json:
54 | schema:
55 | $ref: "#/components/schemas/Error"
56 | /pets/{petId}:
57 | get:
58 | summary: Info for a specific pet
59 | operationId: showPetById
60 | tags:
61 | - pets
62 | parameters:
63 | - name: petId
64 | in: path
65 | required: true
66 | description: The id of the pet to retrieve
67 | schema:
68 | type: string
69 | responses:
70 | '200':
71 | description: Expected response to a valid request
72 | content:
73 | application/json:
74 | schema:
75 | $ref: "#/components/schemas/Pets"
76 | default:
77 | description: unexpected error
78 | content:
79 | application/json:
80 | schema:
81 | $ref: "#/components/schemas/Error"
82 | components:
83 | schemas:
84 | Pet:
85 | required:
86 | - id
87 | - name
88 | properties:
89 | id:
90 | type: integer
91 | format: int64
92 | name:
93 | type: string
94 | tag:
95 | type: string
96 | Pets:
97 | type: array
98 | items:
99 | $ref: "#/components/schemas/Pet"
100 | Error:
101 | required:
102 | - code
103 | - message
104 | properties:
105 | code:
106 | type: integer
107 | format: int32
108 | message:
109 | type: string
110 |
--------------------------------------------------------------------------------
/ktor-generator/src/jvmTest/resources/empty.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/ktor-intellij-plugin/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "org.jetbrains.intellij" version "0.4.16"
3 | }
4 |
5 | apply plugin: "kotlin"
6 | apply plugin: "idea"
7 |
8 | sourceSets {
9 | main.kotlin.srcDirs += "src"
10 | main.resources.srcDirs += "resources"
11 | test.kotlin.srcDirs += "test"
12 | test.resources.srcDirs += "testresources"
13 | }
14 |
15 | dependencies {
16 | //compile project(":ktor-generator")
17 | compile project(path: ':ktor-generator', configuration: 'jvmRuntimeElements')
18 | }
19 |
20 | def intellijBaseVersion = "2018.3.6"
21 | //def intellijBaseVersion = "2019.3.3"
22 | def intellijVersion = "IC-$intellijBaseVersion"
23 | //def intellijVersion = "IU-$intellijBaseVersion"
24 |
25 | intellij {
26 | version intellijVersion
27 | //version 'LATEST-EAP-SNAPSHOT'
28 | updateSinceUntilBuild false
29 | plugins = [
30 | 'maven', 'gradle', 'Kotlin'//, 'java'
31 | ]
32 | pluginName 'ktor'
33 | downloadSources true
34 | }
35 |
36 | publishPlugin {
37 | if (rootProject.properties.jetbrainsUsername != null) {
38 | username rootProject.properties.jetbrainsUsername
39 | password rootProject.properties.jetbrainsPassword
40 | }
41 | }
42 |
43 | runIde {
44 | maxHeapSize = "2g"
45 | }
46 |
47 | repositories {
48 | maven { url "https://plugins.gradle.org/m2/" }
49 | mavenCentral()
50 | }
51 |
52 | [compileKotlin, compileTestKotlin].each {
53 | sourceCompatibility = JavaVersion.VERSION_1_8
54 | targetCompatibility = JavaVersion.VERSION_1_8
55 |
56 | it.kotlinOptions {
57 | freeCompilerArgs = ["-XXLanguage:+InlineClasses"]
58 | apiVersion = "1.3"
59 | languageVersion = "1.3"
60 | jvmTarget = "1.8"
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/resources/icons/ktor-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ktorio/ktor-init-tools/790e8b389ae9aed630eea72a73181a3a5b725977/ktor-intellij-plugin/resources/icons/ktor-icon.png
--------------------------------------------------------------------------------
/ktor-intellij-plugin/resources/icons/ktor-icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ktorio/ktor-init-tools/790e8b389ae9aed630eea72a73181a3a5b725977/ktor-intellij-plugin/resources/icons/ktor-icon16.png
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/FqNames.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij
2 |
3 | import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
4 | import org.jetbrains.kotlin.psi.KtAnnotationEntry
5 | import org.jetbrains.kotlin.psi.KtCallExpression
6 | import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
7 | import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
8 | import org.jetbrains.kotlinx.serialization.compiler.resolve.toClassDescriptor
9 |
10 | internal const val KTOR_LOCATIONS_ANNOTATION_FQNAME = "io.ktor.locations.Location"
11 | internal const val KTOR_ROUTING_FQNAME = "io.ktor.routing.routing"
12 |
13 | internal fun KtAnnotationEntry.isLocation(): Boolean = resolveToCall(BodyResolveMode.PARTIAL)
14 | ?.candidateDescriptor
15 | ?.returnType
16 | ?.toClassDescriptor
17 | ?.fqNameOrNull()
18 | ?.asString() == KTOR_LOCATIONS_ANNOTATION_FQNAME
19 |
20 | internal fun KtCallExpression.isRouteingInvocation(): Boolean = resolveToCall(BodyResolveMode.PARTIAL)
21 | ?.candidateDescriptor
22 | ?.fqNameOrNull()
23 | ?.asString() == KTOR_ROUTING_FQNAME
24 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/KtorModuleConfig.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.intellij
19 |
20 | import io.ktor.start.*
21 | import io.ktor.start.swagger.*
22 |
23 | class KtorModuleConfig {
24 | var artifactGroup = "com.example"
25 | var artifactId = "example"
26 | var artifactVersion = "0.0.1"
27 | var projectType = ProjectType.Gradle
28 | var featuresToInstall = listOf()
29 | var ktorVersion = Versions.LAST
30 | var wrapper = true
31 | var engine = KtorEngine.Netty
32 | var swaggerModules = listOf()
33 | var swaggerGenKind: SwaggerGenerator.Kind = SwaggerGenerator.Kind.RAW
34 | }
35 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/KtorModuleType.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 JetBrains s.r.o.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | */
17 |
18 | package io.ktor.start.intellij
19 |
20 | import com.intellij.openapi.module.*
21 | import com.intellij.openapi.util.*
22 | import javax.swing.*
23 |
24 | class KtorModuleType : ModuleType("ktor") {
25 | companion object {
26 | val NAME = "Ktor"
27 | val DESCRIPTION = "Ktor Quickstart"
28 | val KTOR_BIG_ICON by lazy { IconLoader.getIcon("/icons/ktor-icon.png") }
29 | val KTOR_ICON by lazy { IconLoader.getIcon("/icons/ktor-icon16.png") }
30 | val INSTANCE = KtorModuleType()
31 | }
32 |
33 | override fun createModuleBuilder(): KtorModuleBuilder = KtorModuleBuilder()
34 | override fun getName(): String = NAME
35 | override fun getDescription(): String = DESCRIPTION
36 | override fun getNodeIcon(isOpened: Boolean): Icon = KTOR_ICON
37 | override fun getIcon(): Icon = KTOR_BIG_ICON
38 | }
39 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/RoutingLineMarker.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij
2 |
3 | import com.intellij.codeInsight.daemon.LineMarkerInfo
4 | import com.intellij.codeInsight.daemon.LineMarkerProvider
5 | import com.intellij.icons.AllIcons
6 | import com.intellij.openapi.editor.markup.GutterIconRenderer
7 | import com.intellij.psi.PsiElement
8 | import com.intellij.psi.impl.source.tree.LeafPsiElement
9 | import com.intellij.psi.util.parentOfType
10 | import org.jetbrains.kotlin.idea.editor.fixers.range
11 | import org.jetbrains.kotlin.lexer.KtTokens
12 | import org.jetbrains.kotlin.psi.KtCallExpression
13 |
14 | class RoutingLineMarker : LineMarkerProvider {
15 | override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? {
16 | return null
17 | }
18 |
19 | override fun collectSlowLineMarkers(
20 | elements: MutableList,
21 | result: MutableCollection>
22 | ) {
23 | for (element in elements) {
24 | if (element is LeafPsiElement
25 | && element.elementType == KtTokens.IDENTIFIER
26 | && element.text == "routing"
27 | ) {
28 | val callExpression = element.parentOfType()
29 | if (callExpression != null && callExpression.isRouteingInvocation()) {
30 | result.add(LineMarkerInfo(
31 | element, element.range, AllIcons.Nodes.Weblistener,
32 | 11, null, null,
33 | GutterIconRenderer.Alignment.LEFT
34 | ))
35 | }
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/AddClassParameterQuickFix.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.codeInspection.*
4 | import com.intellij.openapi.project.*
5 | import org.jetbrains.kotlin.psi.*
6 |
7 | class AddClassParameterQuickFix(
8 | private val parameterName: String,
9 | private val optional: Boolean
10 | ) : LocalQuickFix {
11 | override fun getFamilyName(): String {
12 | return "Add path parameter to constructor."
13 | }
14 |
15 | override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
16 | val classElement = findClassOrObject(project, descriptor.psiElement) as? KtClass
17 | ?: error("No kotlin class found")
18 |
19 | addClassParameter(project, classElement, parameterName, optional)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/AddOuterClassParameterQuickFix.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.codeInspection.*
4 | import com.intellij.openapi.project.*
5 | import com.intellij.psi.util.*
6 | import org.jetbrains.kotlin.idea.core.*
7 | import org.jetbrains.kotlin.psi.*
8 | import org.jetbrains.kotlin.util.capitalizeDecapitalize.*
9 |
10 | class AddOuterClassParameterQuickFix(
11 | private val simpleClassName: String,
12 | private val convert: Boolean
13 | ) : LocalQuickFix {
14 | override fun getFamilyName(): String = when (convert) {
15 | false -> "Add constructor parameter for outer class"
16 | true -> "Convert object to class and add parameter"
17 | }
18 |
19 | override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
20 | var classElement = descriptor.psiElement.parentOfType()
21 | ?: error("Unable to lookup class element for ${descriptor.psiElement}")
22 | val factory = KtPsiFactory(project)
23 |
24 | if (classElement is KtObjectDeclaration) {
25 | classElement = convertToClass(project, classElement)
26 | }
27 |
28 | if (classElement is KtClass) {
29 | classElement.createPrimaryConstructorIfAbsent()
30 | val parametersList = classElement.createPrimaryConstructorParameterListIfAbsent()
31 | val existingNames = parametersList.parameters.mapNotNull { it.name }.toSet()
32 | val name = KotlinNameSuggester.suggestNameByName(simpleClassName.decapitalizeAsciiOnly()) { suggestion ->
33 | suggestion !in existingNames
34 | }
35 |
36 | val text = buildString {
37 | append("val ")
38 | append(name)
39 | append(": ")
40 | append(simpleClassName)
41 | }
42 |
43 | parametersList.addParameter(factory.createParameter(text))
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/CompletionInsertHandler.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.codeInsight.completion.*
4 | import com.intellij.codeInsight.lookup.*
5 | import com.intellij.psi.util.*
6 |
7 | object CompletionInsertHandler : InsertHandler {
8 | override fun handleInsert(context: InsertionContext, item: LookupElement) {
9 | val text = item.lookupString
10 |
11 | val element = PsiTreeUtil.findElementOfClassAtOffset(
12 | context.file,
13 | context.tailOffset - 1, LocationsPatternPsiElement::class.java, false
14 | ) ?: return
15 |
16 | context.document.replaceString(
17 | element.node.startOffset,
18 | element.node.startOffset + element.node.textLength, text
19 | )
20 |
21 | context.commitDocument()
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/ConvertToClassQuickFix.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.codeInspection.*
4 | import com.intellij.openapi.project.*
5 | import org.jetbrains.kotlin.psi.*
6 |
7 | class ConvertToClassQuickFix(
8 | private val parameterName: String,
9 | private val optional: Boolean
10 | ) : LocalQuickFix {
11 | override fun getFamilyName(): String = "Convert locations object to class"
12 |
13 | override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
14 | val objectElement = findClassOrObject(project, descriptor.psiElement)
15 | as? KtObjectDeclaration
16 | ?: error("Kotlin object not found.")
17 |
18 | val newClass = convertToClass(project, objectElement)
19 | addClassParameter(project, newClass, parameterName, optional)
20 | }
21 | }
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/ElementManipulators.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.openapi.util.TextRange
4 | import com.intellij.psi.AbstractElementManipulator
5 | import com.intellij.psi.PsiFileFactory
6 | import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
7 |
8 |
9 | class ManipulatorImpl : AbstractElementManipulator() {
10 | override fun handleContentChange(
11 | element: LocationsPatternPsiElement.ParameterNameElement,
12 | range: TextRange,
13 | newContent: String?
14 | ): LocationsPatternPsiElement.ParameterNameElement? {
15 | if (newContent == null) return null
16 |
17 | val dummy = PsiFileFactory.getInstance(element.project)
18 | .createFileFromText(LocationsPatternLanguage, "{$newContent}")
19 |
20 | val newElement =
21 | dummy.findDescendantOfType() ?: return null
22 |
23 | return element.replace(newElement) as LocationsPatternPsiElement.ParameterNameElement
24 | }
25 | }
26 |
27 | class SubstitutionManipulatorImpl : AbstractElementManipulator() {
28 | override fun handleContentChange(
29 | element: LocationsPatternPsiElement.SubstitutionElement,
30 | range: TextRange,
31 | newContent: String?
32 | ): LocationsPatternPsiElement.SubstitutionElement? {
33 | if (newContent == null) return null
34 | val parameterElement = element.parameterNameElement ?: return null
35 |
36 | val dummy = PsiFileFactory.getInstance(element.project)
37 | .createFileFromText(LocationsPatternLanguage, "{$newContent}")
38 |
39 | val newElement =
40 | dummy.findDescendantOfType() ?: return null
41 |
42 | parameterElement.replace(newElement)
43 | return element
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/LocationPatternBraceMatcher.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.lang.*
4 | import com.intellij.psi.*
5 | import com.intellij.psi.tree.*
6 | import com.intellij.psi.util.*
7 | import org.jetbrains.kotlin.psi.psiUtil.*
8 |
9 | class LocationPatternBraceMatcher : PairedBraceMatcher {
10 | override fun getCodeConstructStart(file: PsiFile?, openingBraceOffset: Int): Int {
11 | if (file == null) return 0
12 |
13 | return file.findElementAt(openingBraceOffset)?.parentOfType()
14 | ?.startOffset
15 | ?: openingBraceOffset
16 | }
17 |
18 | override fun getPairs(): Array {
19 | return arrayOf(BracePair(PatternLexer.TOKEN_SUB_OPEN, PatternLexer.TOKEN_SUB_CLOSE, false))
20 | }
21 |
22 | override fun isPairedBracesAllowedBeforeType(lbraceType: IElementType, contextType: IElementType?): Boolean {
23 | return true
24 | }
25 | }
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/LocationsLineMarker.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.codeInsight.daemon.LineMarkerInfo
4 | import com.intellij.codeInsight.daemon.LineMarkerProvider
5 | import com.intellij.icons.AllIcons
6 | import com.intellij.openapi.editor.markup.GutterIconRenderer
7 | import com.intellij.psi.PsiElement
8 | import com.intellij.psi.impl.source.tree.LeafPsiElement
9 | import com.intellij.psi.util.parentOfType
10 | import io.ktor.start.intellij.isLocation
11 | import org.jetbrains.kotlin.idea.editor.fixers.range
12 | import org.jetbrains.kotlin.lexer.KtTokens
13 | import org.jetbrains.kotlin.psi.KtClassOrObject
14 |
15 | class LocationsLineMarker : LineMarkerProvider {
16 | override fun getLineMarkerInfo(element: PsiElement): LineMarkerInfo<*>? {
17 | return null
18 | }
19 |
20 | override fun collectSlowLineMarkers(
21 | elements: MutableList,
22 | result: MutableCollection>
23 | ) {
24 | elements.filterIsInstance()
25 | .filter { it.elementType == KtTokens.IDENTIFIER }
26 | .mapNotNull { it.parentOfType()?.let { found -> Pair(it, found) } }
27 | .filter { it.second.annotationEntries.isNotEmpty() && it.second.nameIdentifier == it.first }
28 | .mapNotNullTo(result) { (element, classElement) ->
29 | val annotation = classElement.annotationEntries.firstOrNull { it.isLocation() }
30 |
31 | if (annotation != null) {
32 | LineMarkerInfo(
33 | element, element.range, AllIcons.Javaee.WebService,
34 | 11, null, null,
35 | GutterIconRenderer.Alignment.LEFT
36 | )
37 | } else {
38 | null
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/LocationsParametersFindUsagesHandlerFactory.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.find.findUsages.FindUsagesHandler
4 | import com.intellij.find.findUsages.FindUsagesHandlerFactory
5 | import com.intellij.psi.PsiElement
6 | import com.intellij.psi.util.parentOfType
7 |
8 | class LocationsParametersFindUsagesHandlerFactory : FindUsagesHandlerFactory() {
9 | override fun canFindUsages(element: PsiElement): Boolean {
10 | return element is LocationsPatternPsiElement.ParameterNameElement ||
11 | element is LocationsPatternPsiElement.SubstitutionElement
12 | }
13 |
14 | override fun createFindUsagesHandler(element: PsiElement, forHighlightUsages: Boolean): FindUsagesHandler? {
15 | return when (element) {
16 | is LocationsPatternPsiElement.ParameterNameElement -> DefaultFindUsagesHandler(element.parentOfType()!!)
17 | is LocationsPatternPsiElement.SubstitutionElement -> DefaultFindUsagesHandler(element)
18 | else -> null
19 | }
20 | }
21 |
22 | private class DefaultFindUsagesHandler(
23 | private val substitution: LocationsPatternPsiElement.SubstitutionElement
24 | ) : FindUsagesHandler(substitution) {
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/LocationsRefactoringsSupportProvider.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.lang.refactoring.RefactoringSupportProvider
4 | import com.intellij.psi.PsiElement
5 | import com.intellij.psi.util.parentOfType
6 | import com.intellij.refactoring.RefactoringActionHandler
7 | import org.jetbrains.kotlin.psi.KtNamedDeclaration
8 |
9 | class LocationsRefactoringsSupportProvider : RefactoringSupportProvider() {
10 | override fun isSafeDeleteAvailable(element: PsiElement): Boolean {
11 | return true
12 | }
13 |
14 | override fun isMemberInplaceRenameAvailable(element: PsiElement, context: PsiElement?): Boolean {
15 | return context != null &&
16 | (context.parentOfType() != null ||
17 | context.language == LocationsPatternLanguage) &&
18 | (element is LocationsPatternPsiElement.SubstitutionElement ||
19 | element is LocationsPatternPsiElement.ParameterNameElement)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/MakeParameterOptionalQuickFix.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.codeInspection.*
4 | import com.intellij.lang.injection.*
5 | import com.intellij.openapi.project.*
6 | import com.intellij.psi.util.*
7 | import org.jetbrains.kotlin.idea.core.*
8 | import org.jetbrains.kotlin.idea.inspections.*
9 | import org.jetbrains.kotlin.psi.*
10 | import org.jetbrains.kotlin.psi.psiUtil.*
11 |
12 | class MakeParameterOptionalQuickFix : LocalQuickFix {
13 | override fun getFamilyName(): String = "Make parameter nullable"
14 |
15 | override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
16 | val element = InjectedLanguageManager.getInstance(project)
17 | .getInjectionHost(descriptor.psiElement)
18 | ?: error("Unable to find injection host for element")
19 |
20 | val parameterNameElement = descriptor.psiElement
21 | .parentOfType()
22 | ?.getChildOfType()
23 | ?: error("Unable to find parameter name element")
24 |
25 | val propertyName = parameterNameElement.text.trim()
26 | val classElement = element.parentOfType() ?: error("Unable to find class element")
27 | val property = classElement.findPropertyByName(propertyName)
28 | ?: error("Unable to find property with name $propertyName")
29 |
30 | if (property is KtParameter) {
31 | val factory = KtPsiFactory(project)
32 | val oldType = property.typeReference ?: error("No type for property $propertyName")
33 | val newType = factory.createType(oldType.text + "?")
34 | oldType.replace(newType)
35 | property.setDefaultValue(factory.createExpression("null"))
36 | property.defaultValue?.endOffset?.let { endOffset ->
37 | property.findExistingEditor()?.moveCaret(endOffset)
38 | }
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/MissingOwnerClassReferenceInspection.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.codeInspection.*
4 | import com.intellij.psi.*
5 | import io.ktor.start.intellij.isLocation
6 | import org.jetbrains.kotlin.idea.search.usagesSearch.*
7 | import org.jetbrains.kotlin.psi.*
8 | import org.jetbrains.kotlin.psi.psiUtil.*
9 | import org.jetbrains.kotlin.resolve.descriptorUtil.*
10 |
11 | class MissingOwnerClassReferenceInspection : LocalInspectionTool() {
12 | override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
13 | return object : PsiElementVisitor() {
14 | override fun visitElement(element: PsiElement?) {
15 | if (element is KtClassOrObject) {
16 | processClassOrObject(element, holder)
17 | }
18 |
19 | super.visitElement(element)
20 | }
21 | }
22 | }
23 |
24 | private fun processClassOrObject(classElement: KtClassOrObject, holder: ProblemsHolder) {
25 | if (!classElement.isLocation()) return
26 | val parentClass = classElement.getParentOfType(true) ?: return
27 | if (!parentClass.isLocation()) return
28 |
29 | if (parentClass is KtObjectDeclaration && classElement is KtObjectDeclaration) {
30 | holder.registerProblem(
31 | classElement.getObjectKeyword() ?: classElement.navigationElement,
32 | "Nesting objects is no longer recommended. Convert the inner object into a class.",
33 | ProblemHighlightType.ERROR,
34 | AddOuterClassParameterQuickFix(
35 | parentClass.fqName?.shortName()?.asString()
36 | ?: parentClass.name?.substringAfterLast(".") ?: "?",
37 | convert = true
38 | )
39 | )
40 | } else if (classElement.primaryConstructorParameters.none { it.refersToClass(parentClass) }) {
41 | holder.registerProblem(
42 | classElement.nameIdentifier ?: classElement.navigationElement,
43 | "There is no property referencing outer class.",
44 | AddOuterClassParameterQuickFix(
45 | parentClass.fqName?.shortName()?.asString()
46 | ?: parentClass.name?.substringAfterLast(".") ?: "?",
47 | convert = false
48 | )
49 | )
50 | }
51 | }
52 |
53 | private fun KtClassOrObject.isLocation() = annotationEntries.any { it.isLocation() }
54 |
55 | private fun KtParameter.refersToClass(other: KtClassOrObject): Boolean {
56 | return descriptor?.type?.constructor?.declarationDescriptor?.fqNameOrNull() == other.fqName
57 | }
58 | }
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/ParameterNameAnnotator.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.lang.annotation.*
4 | import com.intellij.psi.*
5 | import org.jetbrains.kotlin.psi.KtAnnotationEntry
6 |
7 | class ParameterNameAnnotator : Annotator {
8 | override fun annotate(element: PsiElement, holder: AnnotationHolder) {
9 | if (element is LocationsPatternPsiElement.ParameterNameElement) {
10 | holder.createInfoAnnotation(element, null)
11 | .apply {
12 | tooltip = "Named path parameter"
13 | textAttributes = PatternSyntaxHighlighter.ParameterName
14 | }
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/ParameterNameInPlaceRenameHandler.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.openapi.editor.Editor
4 | import com.intellij.psi.PsiElement
5 | import com.intellij.psi.PsiNameIdentifierOwner
6 | import com.intellij.psi.PsiNamedElement
7 | import com.intellij.psi.util.parentOfType
8 | import com.intellij.refactoring.rename.inplace.MemberInplaceRenameHandler
9 | import com.intellij.refactoring.rename.inplace.MemberInplaceRenamer
10 | import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer
11 |
12 | class ParameterNameInPlaceRenameHandler : MemberInplaceRenameHandler() {
13 | override fun createMemberRenamer(
14 | element: PsiElement,
15 | elementToRename: PsiNameIdentifierOwner,
16 | editor: Editor
17 | ): MemberInplaceRenamer {
18 | return Renamer(elementToRename, element, editor)
19 | }
20 |
21 | override fun createRenamer(elementToRename: PsiElement, editor: Editor): VariableInplaceRenamer? {
22 | elementToRename.parentOfType()?.let {
23 | return Renamer(it, null, editor)
24 | }
25 |
26 | return super.createRenamer(elementToRename, editor)
27 | }
28 |
29 | private class Renamer(elementToRename: PsiNamedElement, substituted: PsiElement?, editor: Editor) :
30 | MemberInplaceRenamer(elementToRename, substituted, editor) {
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/ParameterUsagesSearcher.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.psi.PsiElement
4 | import com.intellij.psi.PsiReference
5 | import com.intellij.psi.search.searches.DefinitionsScopedSearch
6 | import com.intellij.psi.search.searches.ReferencesSearch
7 | import com.intellij.util.ProcessingContext
8 | import com.intellij.util.Processor
9 | import com.intellij.util.QueryExecutor
10 | import org.jetbrains.kotlin.idea.util.application.runReadAction
11 | import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
12 |
13 | class ParameterUsagesSearcher : QueryExecutor {
14 | override fun execute(
15 | queryParameters: DefinitionsScopedSearch.SearchParameters,
16 | consumer: Processor
17 | ): Boolean {
18 | val searchElement = queryParameters.element
19 | if (searchElement !is LocationsPatternPsiElement) {
20 | return true
21 | }
22 |
23 | var cancelled = false
24 | runReadAction {
25 | searchElement.collectDescendantsOfType()
26 | .forEach { element ->
27 | LocationsBackReferenceProvider().getReferencesByElement(element.firstChild, ProcessingContext())
28 | .map { it.element }.forEach { target ->
29 | if (!consumer.process(target)) {
30 | cancelled = true
31 | return@runReadAction
32 | }
33 | }
34 | }
35 | }
36 |
37 | return !cancelled
38 | }
39 | }
40 |
41 | class ParametersReferencesSearcher : QueryExecutor {
42 | override fun execute(
43 | queryParameters: ReferencesSearch.SearchParameters,
44 | consumer: Processor
45 | ): Boolean {
46 | val searchElement = queryParameters.elementToSearch
47 | if (searchElement !is LocationsPatternPsiElement) {
48 | return true
49 | }
50 |
51 | var cancelled = false
52 | runReadAction {
53 | searchElement.collectDescendantsOfType()
54 | .forEach { element ->
55 | LocationsBackReferenceProvider().getReferencesByElement(element.firstChild, ProcessingContext())
56 | .forEach { target ->
57 | if (!consumer.process(target)) {
58 | cancelled = true
59 | return@runReadAction
60 | }
61 | }
62 | }
63 | }
64 |
65 | return !cancelled
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/PatternFileTypeFactory.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.openapi.fileTypes.*
4 |
5 | class PatternFileTypeFactory : FileTypeFactory() {
6 | override fun createFileTypes(consumer: FileTypeConsumer) {
7 | consumer.consume(PatternFileType)
8 | }
9 | }
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/PatternFindUsagesProvider.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.lang.cacheBuilder.DefaultWordsScanner
4 | import com.intellij.lang.cacheBuilder.WordOccurrence
5 | import com.intellij.lang.cacheBuilder.WordsScanner
6 | import com.intellij.lang.findUsages.*
7 | import com.intellij.psi.*
8 | import com.intellij.psi.tree.TokenSet
9 | import com.intellij.util.Processor
10 |
11 | class PatternFindUsagesProvider : EmptyFindUsagesProvider() {
12 | override fun getWordsScanner(): WordsScanner? {
13 | return object : DefaultWordsScanner(
14 | PatternLexer(),
15 | TokenSet.create(PatternLexer.TOKEN_COMPONENT),
16 | TokenSet.EMPTY,
17 | TokenSet.EMPTY
18 | ) {}
19 | }
20 |
21 | override fun canFindUsagesFor(psiElement: PsiElement): Boolean {
22 | return psiElement is LocationsPatternPsiElement.ParameterNameElement
23 | || psiElement is LocationsPatternPsiElement.SubstitutionElement
24 | }
25 |
26 | override fun getType(element: PsiElement): String {
27 | return when (element) {
28 | is LocationsPatternPsiElement.ParameterNameElement -> "parameter"
29 | is LocationsPatternPsiElement.SubstitutionElement -> "parameter"
30 | else -> ""
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/PatternParameterBackReference.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.openapi.util.TextRange
4 | import com.intellij.psi.*
5 | import com.intellij.util.IncorrectOperationException
6 |
7 | internal class PatternParameterBackReference(
8 | private val componentElement: LocationsPatternPsiElement.ParameterNameElement,
9 | private val references: PsiElement
10 | ): PsiReferenceBase(references), PsiPolyVariantReference {
11 | override fun resolve(): PsiElement? {
12 | return references
13 | }
14 |
15 | override fun multiResolve(incompleteCode: Boolean): Array {
16 | return arrayOf(PsiElementResolveResult(references))
17 | }
18 |
19 | override fun getRangeInElement(): TextRange {
20 | return TextRange(0, element.textLength)
21 | }
22 |
23 | override fun handleElementRename(newElementName: String): PsiElement {
24 | val result = ManipulatorImpl().handleContentChange(componentElement, newElementName)
25 | ?: throw IncorrectOperationException("Failed to rename location parameter")
26 |
27 | return result
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/PatternParameterReference.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.lang.injection.*
4 | import com.intellij.openapi.util.*
5 | import com.intellij.psi.*
6 | import com.intellij.psi.util.*
7 | import org.jetbrains.kotlin.psi.*
8 | import org.jetbrains.kotlin.psi.psiUtil.*
9 |
10 | class PatternParameterReference(
11 | element: PsiNameIdentifierOwner,
12 | range: TextRange
13 | ) : PsiReferenceBase(element, range), PsiPolyVariantReference {
14 | override fun multiResolve(incompleteCode: Boolean): Array {
15 | val propertyName = element.name ?: return emptyArray()
16 | val classElement = element.parentOfType() ?: return emptyArray()
17 |
18 | val manager = InjectedLanguageManager.getInstance(element.project) ?: return emptyArray()
19 |
20 | return classElement.annotationEntries.flatMap { entry ->
21 | val file = entry.valueArguments.singleOrNull()
22 | ?.getArgumentExpression()
23 | ?.findDescendantOfType()
24 | ?.let { manager.getInjectedPsiFiles(it)?.singleOrNull()?.first as? PatternFileImpl }
25 |
26 | file?.parameterNames?.filter { it.text == propertyName }
27 | ?.mapNotNull { it.parentOfType() }
28 | .orEmpty()
29 | }.map { PsiElementResolveResult(it) }.toTypedArray()
30 | }
31 |
32 | override fun resolve(): PsiElement? {
33 | return multiResolve(false).singleOrNull()?.element
34 | }
35 |
36 | override fun isReferenceTo(element: PsiElement): Boolean {
37 | return super.isReferenceTo(element)
38 | }
39 |
40 | override fun getRangeInElement(): TextRange {
41 | val nameIdentifier = element.nameIdentifier ?: return TextRange(0, element.textLength)
42 | val startInside = nameIdentifier.getStartOffsetIn(element)
43 | val length = nameIdentifier.textLength
44 |
45 | if (startInside < 0 || length > element.textLength) {
46 | return TextRange(0, element.textLength)
47 | }
48 |
49 | return TextRange.from(startInside, length)
50 | }
51 |
52 | override fun handleElementRename(newElementName: String): PsiElement {
53 | return super.handleElementRename(newElementName)
54 | }
55 | }
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/PatternSyntaxHighlighter.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.lexer.*
4 | import com.intellij.openapi.editor.*
5 | import com.intellij.openapi.editor.colors.*
6 | import com.intellij.openapi.editor.colors.TextAttributesKey.*
7 | import com.intellij.openapi.fileTypes.*
8 | import com.intellij.openapi.project.*
9 | import com.intellij.openapi.vfs.*
10 | import com.intellij.psi.tree.*
11 |
12 | class PatternSyntaxHighlighter : SyntaxHighlighterBase() {
13 | override fun getTokenHighlights(tokenType: IElementType?): Array {
14 | return when (tokenType) {
15 | PatternLexer.TOKEN_COMPONENT -> arrayOf(DefaultLanguageHighlighterColors.CONSTANT)
16 | PatternLexer.TOKEN_SUB_OPEN, PatternLexer.TOKEN_SUB_CLOSE -> arrayOf(ParameterBraces)
17 | else -> emptyArray()
18 | }
19 | }
20 |
21 | override fun getHighlightingLexer(): Lexer {
22 | return PatternLexer()
23 | }
24 |
25 | companion object : SyntaxHighlighterFactory() {
26 | val ParameterName: TextAttributesKey =
27 | createTextAttributesKey("PARAMETER_NAME", DefaultLanguageHighlighterColors.IDENTIFIER)
28 |
29 | val ParameterBraces: TextAttributesKey =
30 | createTextAttributesKey("PARAMETER_BRACES", DefaultLanguageHighlighterColors.BRACES)
31 |
32 | override fun getSyntaxHighlighter(project: Project?, virtualFile: VirtualFile?): SyntaxHighlighter {
33 | return PatternSyntaxHighlighter()
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/ktor-intellij-plugin/src/io/ktor/start/intellij/locations/QuickFixActions.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.locations
2 |
3 | import com.intellij.lang.injection.*
4 | import com.intellij.openapi.project.*
5 | import com.intellij.psi.*
6 | import com.intellij.psi.util.*
7 | import org.jetbrains.kotlin.idea.inspections.*
8 | import org.jetbrains.kotlin.psi.*
9 | import org.jetbrains.kotlin.psi.psiUtil.*
10 |
11 | internal fun findClassOrObject(project: Project, psiElement: PsiElement): KtClassOrObject? {
12 | return InjectedLanguageManager.getInstance(project)
13 | .getInjectionHost(psiElement)
14 | ?.parentOfType()
15 | }
16 |
17 | internal fun convertToClass(
18 | project: Project,
19 | objectElement: KtObjectDeclaration
20 | ): KtClass {
21 | val objectKeyword = objectElement.getObjectKeyword()!!
22 | val editor = objectElement.findExistingEditor()!!
23 |
24 | val startOffset = objectKeyword.startOffset
25 | editor.document.replaceString(
26 | startOffset, objectKeyword.endOffset, "class"
27 | )
28 |
29 | PsiDocumentManager.getInstance(project).commitDocument(editor.document)
30 | val newElement = PsiDocumentManager.getInstance(project)
31 | .getPsiFile(editor.document)?.findElementAt(startOffset + 1)
32 | ?: error("Unable to lookup new class keyword element")
33 |
34 | return newElement.parentOfType() ?: error("Unable to lookup new class element")
35 | }
36 |
37 | internal fun addClassParameter(
38 | project: Project,
39 | classElement: KtClass,
40 | parameterName: String,
41 | optional: Boolean
42 | ) {
43 | classElement.createPrimaryConstructorIfAbsent()
44 | val parametersList = classElement.createPrimaryConstructorParameterListIfAbsent()
45 |
46 | val allVars = parametersList.parameters.isNotEmpty() && parametersList.parameters.all { it.isMutable }
47 |
48 | val text = buildString {
49 | if (allVars) {
50 | append("var ")
51 | } else {
52 | append("val ")
53 | }
54 |
55 | append(parameterName)
56 | append(": String")
57 | if (optional) {
58 | append("?")
59 | }
60 | }
61 |
62 | parametersList.addParameter(KtPsiFactory(project).createParameter(text))
63 | }
--------------------------------------------------------------------------------
/ktor-intellij-plugin/test/io/ktor/start/intellij/util/ParsingTest.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.util
2 |
3 | import com.intellij.testFramework.*
4 | import io.ktor.start.intellij.locations.PatternParserDefinition
5 | import org.junit.*
6 |
7 | class ParsingTest : ParsingTestCase("", "locationspattern",
8 | PatternParserDefinition()
9 | ) {
10 |
11 | @Test
12 | fun testSmoke() {
13 | doTest(true)
14 | }
15 |
16 | override fun skipSpaces(): Boolean {
17 | return false
18 | }
19 |
20 | override fun includeRanges(): Boolean {
21 | return true
22 | }
23 |
24 | override fun getTestDataPath(): String {
25 | return "testresources"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ktor-intellij-plugin/test/io/ktor/start/intellij/util/PathInfoTest.kt:
--------------------------------------------------------------------------------
1 | package io.ktor.start.intellij.util
2 |
3 | import org.junit.*
4 | import kotlin.test.*
5 |
6 | class PathInfoTest {
7 | @Test
8 | fun checks() {
9 | PathInfo("").let { info ->
10 | assertEquals(null, info.parent)
11 | assertEquals("", info.name)
12 | assertEquals("", info.path)
13 | }
14 |
15 | PathInfo("/").let { info ->
16 | assertEquals("", info.parent)
17 | assertEquals("", info.name)
18 | assertEquals("/", info.path)
19 | }
20 |
21 | PathInfo("test").let { info ->
22 | assertEquals(null, info.parent)
23 | assertEquals("test", info.name)
24 | assertEquals("test", info.path)
25 | }
26 |
27 | PathInfo("hello/world").let { info ->
28 | assertEquals("hello", info.parent)
29 | assertEquals("world", info.name)
30 | assertEquals("hello/world", info.path)
31 | }
32 |
33 | PathInfo("hello/world/42").let { info ->
34 | assertEquals("hello/world", info.parent)
35 | assertEquals("42", info.name)
36 | assertEquals("hello/world/42", info.path)
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/ktor-intellij-plugin/testresources/Smoke.locationspattern:
--------------------------------------------------------------------------------
1 | /a/b/c/{param}/{optional?}/{ellipsis...}
--------------------------------------------------------------------------------
/ktor-intellij-plugin/testresources/Smoke.txt:
--------------------------------------------------------------------------------
1 | FILE(0,40)
2 | SlashElement(TOKEN_SLASH)(0,1)
3 | PsiElement(TOKEN_SLASH)('/')(0,1)
4 | ComponentElement(TOKEN_COMPONENT)(1,2)
5 | PsiElement(TOKEN_COMPONENT)('a')(1,2)
6 | SlashElement(TOKEN_SLASH)(2,3)
7 | PsiElement(TOKEN_SLASH)('/')(2,3)
8 | ComponentElement(TOKEN_COMPONENT)(3,4)
9 | PsiElement(TOKEN_COMPONENT)('b')(3,4)
10 | SlashElement(TOKEN_SLASH)(4,5)
11 | PsiElement(TOKEN_SLASH)('/')(4,5)
12 | ComponentElement(TOKEN_COMPONENT)(5,6)
13 | PsiElement(TOKEN_COMPONENT)('c')(5,6)
14 | SlashElement(TOKEN_SLASH)(6,7)
15 | PsiElement(TOKEN_SLASH)('/')(6,7)
16 | SubstitutionElement(TOKEN_SUBSTITUTION)(7,14)
17 | OtherElement(TOKEN_SUB_OPEN)(7,8)
18 | PsiElement(TOKEN_SUB_OPEN)('{')(7,8)
19 | ParameterNameElement(TOKEN_COMPONENT)(8,13)
20 | PsiElement(TOKEN_COMPONENT)('param')(8,13)
21 | OtherElement(TOKEN_SUB_CLOSE)(13,14)
22 | PsiElement(TOKEN_SUB_CLOSE)('}')(13,14)
23 | SlashElement(TOKEN_SLASH)(14,15)
24 | PsiElement(TOKEN_SLASH)('/')(14,15)
25 | SubstitutionElement(TOKEN_SUBSTITUTION)(15,26)
26 | OtherElement(TOKEN_SUB_OPEN)(15,16)
27 | PsiElement(TOKEN_SUB_OPEN)('{')(15,16)
28 | ParameterNameElement(TOKEN_COMPONENT)(16,24)
29 | PsiElement(TOKEN_COMPONENT)('optional')(16,24)
30 | VarArgElement(TOKEN_OPTIONAL)(24,25)
31 | PsiElement(TOKEN_OPTIONAL)('?')(24,25)
32 | OtherElement(TOKEN_SUB_CLOSE)(25,26)
33 | PsiElement(TOKEN_SUB_CLOSE)('}')(25,26)
34 | SlashElement(TOKEN_SLASH)(26,27)
35 | PsiElement(TOKEN_SLASH)('/')(26,27)
36 | SubstitutionElement(TOKEN_SUBSTITUTION)(27,40)
37 | OtherElement(TOKEN_SUB_OPEN)(27,28)
38 | PsiElement(TOKEN_SUB_OPEN)('{')(27,28)
39 | ParameterNameElement(TOKEN_COMPONENT)(28,36)
40 | PsiElement(TOKEN_COMPONENT)('ellipsis')(28,36)
41 | VarArgElement(TOKEN_ELLIPSIS)(36,39)
42 | PsiElement(TOKEN_ELLIPSIS)('...')(36,39)
43 | OtherElement(TOKEN_SUB_CLOSE)(39,40)
44 | PsiElement(TOKEN_SUB_CLOSE)('}')(39,40)
45 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | resolutionStrategy {
3 | eachPlugin {
4 | if (requested.id.id == "kotlin-multiplatform") {
5 | useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}")
6 | }
7 | }
8 | }
9 |
10 | repositories {
11 | mavenLocal()
12 | mavenCentral()
13 | maven { url 'https://plugins.gradle.org/m2/' }
14 | }
15 | }
16 |
17 | rootProject.name = 'ktor-init-tools'
18 |
19 | enableFeaturePreview('GRADLE_METADATA')
20 |
21 | include "ktor-intellij-plugin"
22 | include "ktor-generator-website"
23 | include "ktor-generator"
24 |
--------------------------------------------------------------------------------
/synchronize_versions.kt:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env kscript
2 |
3 | import java.io.*
4 | import java.nio.charset.*
5 | import java.util.*
6 |
7 | fun main(args: Array) {
8 | val properties = Properties().apply { load(File("gradle.properties").readText().reader()) }
9 | val version = properties["version"]
10 |
11 | File("ktor-intellij-plugin/resources/META-INF/plugin.xml").updateFile(save = true) {
12 | it.replace(Regex("(.*?)"), "$version")
13 | }
14 |
15 | File("ktor-generator-website/resources/index.html").updateFile(save = true) {
16 | it.replace(Regex("""Ktor Project Generator \((.*?)\)"""), "Ktor Project Generator ($version)")
17 | }
18 | }
19 |
20 | fun File.updateFile(save: Boolean, charset: Charset = Charsets.UTF_8, callback: (String) -> String) {
21 | print("Processing $this...")
22 | val oldText = this.readText(charset)
23 | val newText = callback(oldText)
24 | if (save) {
25 | if (oldText != newText) {
26 | this.writeText(newText, charset)
27 | println("Saved")
28 | } else {
29 | println("Same content")
30 | }
31 | } else {
32 | println("Not saved")
33 | }
34 | }
--------------------------------------------------------------------------------