Compare commits

...

181 Commits

Author SHA1 Message Date
Vladimir Shefer d34a8734f3
Merge pull request #94 from TouchInstinct/feature/bugfix
Fix compile error in DateFactory
2020-09-28 14:07:40 +03:00
Vladimir Shefer 399c9f0abc Fix compile error in DateFactory 2020-09-28 13:32:08 +03:00
Vladimir Shefer c942c39307
Merge pull request #93 from TouchInstinct/feature/java-time
DafeFactory new generation for JavaTime
2020-09-22 13:15:24 +03:00
Vladimir Shefer 015b256631 Replace tabs with spaces 2020-09-17 14:29:23 +03:00
Vladimir Shefer 318fe3d491 DafeFactory new generation for JavaTime 2020-08-27 19:05:26 +03:00
Vladimir Shefer 206f13d4a9
Merge pull request #92 from TouchInstinct/feature/java-time
Fix DateFactory pattern search
2020-08-26 13:43:08 +03:00
Vladimir Shefer 6ac5219c96 Fix DateFactory pattern search 2020-08-24 19:31:34 +03:00
Vladimir Shefer 1f60055793
Merge pull request #91 from TouchInstinct/fix/replace-typename-with-canonicalName
Replace .typeName with .canonicalName
2020-08-18 13:48:31 +03:00
Vladimir Shefer 6213910a50 Replace MutableSet with Set parameter 2020-08-17 11:29:43 +03:00
Vladimir Shefer 26803fd6f6 Replace .typeName with .simpleName.
Method .typeName available since 28 api level, when 21+ api is used
2020-08-17 11:21:59 +03:00
Vladimir Shefer 3fd2ec9a4f
Merge pull request #90 from TouchInstinct/feature/return-list
Format response type in Swift
2020-07-17 13:51:59 +03:00
Vladimir Shefer 321e4021be Format response type in Swift
Now not only the class name could be the response type, but also array type. So `-> Single<A[]>` should be formated as -> Single<[A]>
2020-07-16 15:39:23 +03:00
Victor Shabanov 773bdecd72
Merge pull request #89 from TouchInstinct/feature/swift_module_generation
Add public visibility for swift module
2019-10-17 17:43:42 +03:00
Victor Shabanov 15a7ce9ed4 Fix protocol method declaration for swift module 2019-10-17 15:40:59 +03:00
Victor Shabanov b47d064fe9 Add public visibility for swift module 2019-10-17 15:19:04 +03:00
Oleg fec4299959
Merge pull request #88 from TouchInstinct/feature/color_type_patterns
feature/color_type_patterns
2019-10-14 14:49:27 +03:00
Oleg Kuznetsov c5272f2031 added ColorAdapter class 2019-10-11 21:06:08 +03:00
Oleg Kuznetsov 546113ca93 added HexColor annotation 2019-10-11 21:05:46 +03:00
Ivan Babkin e240e2de6c
Merge pull request #86 from TouchInstinct/fix/swift_date_templates
Update swift date templates
2019-09-10 14:25:01 +03:00
Ivan Babkin 714d68f4c4 Fix date field name 2019-09-09 16:43:41 +03:00
Ivan Babkin c2c853206f Finish dateFormats support 2019-09-09 16:40:04 +03:00
Ivan Babkin f6fc7c3dce Ignore dateFormat if dateFormats exists 2019-09-09 14:34:33 +03:00
Malik Khiraev 81e8ddcb87
Merge pull request #87 from TouchInstinct/feature/date-patterns
Feature/date patterns
2019-08-07 18:26:17 +03:00
Malik 06783d2ad3 Fix error message 2019-08-07 18:07:13 +03:00
Malik d7a1aad672 New line 2019-08-07 18:02:09 +03:00
Malik fd24198675 Review 2019-08-07 18:00:17 +03:00
Malik 04cf0d7c52 Fix a type 2019-08-01 18:02:15 +03:00
Ivan Babkin 3e196020d9 Update swift date templates 2019-08-01 16:33:19 +03:00
Malik 93995f8ce1 Add adapters, annotation and a factory to process date patterns 2019-08-01 14:46:31 +03:00
Alexander Buntakov 2cdfec1a6b
Merge pull request #85 from TouchInstinct/fix/optional_fields_check
kotlin-server: optional fields check first
2019-07-23 17:14:39 +03:00
Elena Bobkova 580ecda701 optional fields check first 2019-07-23 17:13:08 +03:00
Elena Bobkova 1d1fc57e5d
Merge pull request #84 from TouchInstinct/feature/date_formats
date formats updated
2019-07-22 16:29:18 +03:00
Elena Bobkova 12563ef313 date formats updated 2019-07-22 16:17:52 +03:00
Alexander Buntakov fd1b708930
Merge pull request #83 from TouchInstinct/feature/web_documentation_date
date template for web documentation
2019-07-22 13:32:38 +03:00
Elena Bobkova 2a6141d3f2 date template for web documentation 2019-07-22 13:31:21 +03:00
Alexander Buntakov f7e4d590f6
Merge pull request #82 from TouchInstinct/feature/kotli_server_local_date
Feature/kotlin server local date
2019-07-22 13:28:38 +03:00
Elena Bobkova b97fb00ea4 date format condition added 2019-07-22 13:26:15 +03:00
Elena Bobkova 0adb5c1ebe datetime check reverted 2019-07-22 13:23:50 +03:00
Elena Bobkova d5f4f3b21a imports fixed 2019-07-22 13:23:41 +03:00
Elena Bobkova 2f15259a60 date template added 2019-07-19 18:45:34 +03:00
Alexander Buntakov cab0843d42
Merge pull request #81 from TouchInstinct/fix/kotlin_server_templates
no description spacing fixed
2019-07-02 16:27:17 +03:00
Elena Bobkova 27d7215d0c no description spacing fixed 2019-07-02 15:49:47 +03:00
Alexander Buntakov 9a32858415
Merge pull request #80 from TouchInstinct/fix/kotlin_server_templates
Fix/kotlin server templates
2019-07-01 19:50:30 +03:00
Elena Bobkova b9f1c504d6 unused imports suppress added 2019-07-01 19:48:14 +03:00
Elena Bobkova dddb1d5806 extra spacing removed 2019-07-01 19:33:20 +03:00
Elena Bobkova cf16591a42
Merge pull request #79 from TouchInstinct/feature/add_ascape_func
Add escape filter for descriptions
2019-07-01 16:24:42 +03:00
Ekaterina fd49b2addc Add escape filter for descriptions 2019-07-01 16:19:06 +03:00
Elena Bobkova c784197def extra spacing removed 2019-06-28 17:47:30 +03:00
Alexander Buntakov 3c620f23e7
Merge pull request #78 from TouchInstinct/feature/api_prefix_fpr_kotlin_server_templates
package fixed in kotlin server templates
2019-06-28 15:19:50 +03:00
Elena Bobkova 082b5dde9d package fixed in kotlin server templates 2019-06-28 15:18:16 +03:00
Elena Bobkova db78be9a96
Merge pull request #76 from TouchInstinct/fix/issue_155_kotlin_and_web
Fix/issue 155 kotlin and web
2019-06-28 14:18:16 +03:00
Alexander Buntakov b7b7e7c449
Merge pull request #77 from TouchInstinct/fix/new_line_at_the_end_of_the_file
new line at the end of the file added
2019-06-27 14:49:28 +03:00
Elena Bobkova 7934ef50a7 new line at the end of the file added 2019-06-27 14:37:31 +03:00
Elena Bobkova f3283e3fcc web documentation fixed 2019-06-26 17:10:38 +03:00
Elena Bobkova b9ef35a772 kotlin server templates fixed 2019-06-26 16:34:41 +03:00
Alexander Buntakov 1c24bae47e
Merge pull request #75 from TouchInstinct/fix/kotlin_Server_templates
Fix/kotlin server templates
2019-05-23 18:46:32 +03:00
Elena Bobkova 8d2e5c1e77 timezone annotation updated 2019-05-23 18:40:15 +03:00
Elena Bobkova e4ff2ceb7f spacing fixed if no description is set 2019-05-23 18:28:49 +03:00
Ivan Babkin 1816c2e4b1
Merge pull request #74 from TouchInstinct/fix/bugs
Fixed copyWithout method and decimal encoding
2019-05-21 15:50:33 +03:00
Ivan Babkin 5032239132 Fixed copyWithout method and decimal encoding 2019-05-21 15:28:54 +03:00
Ivan Babkin d85e6e954b
Merge pull request #73 from TouchInstinct/feature/new_types
Feature/new types
2019-05-20 14:39:13 +03:00
Ivan Babkin 41fcf554fa Fixed date initialization from decoder 2019-05-20 13:16:19 +03:00
Ivan Babkin 59c2cb0ba0 Fixed error description for color decoding 2019-05-20 13:09:03 +03:00
Ivan Babkin 0916108075 Refactoring 2019-05-17 19:19:44 +03:00
Ivan Babkin 9b7643d087 Refactoring 2019-05-17 13:18:11 +03:00
Ivan Babkin dd0e0165e4 Fixed ApiNumberFormattingService bugs 2019-05-16 14:11:31 +03:00
Ivan Babkin e023fed90a Fixed NumberFormattingService, bugfix 2019-05-16 13:18:56 +03:00
Ivan Babkin 649089d79e Added ApiNumberFormattingService template, fixed complex field decoding 2019-04-29 17:11:12 +03:00
Ivan Babkin 0f8e26f39b Fixed indents 2019-04-26 16:27:47 +03:00
Ivan Babkin 7624fa7e27 Removed not optional fields from copyWithout and refactoring 2019-04-26 15:42:27 +03:00
Ivan Babkin 157799147c Refactoring 2019-04-26 13:22:30 +03:00
Ivan Babkin 7e67644c9f Added new field types 2019-04-25 22:12:08 +03:00
Ivan Babkin c644620e51
Merge pull request #72 from TouchInstinct/fix/static_method_params
Added additionalValidStatusCodes parameter to method calling
2019-04-23 17:51:06 +03:00
Ivan Babkin 8bf0208187 Added additionalValidStatusCodes parameter to method calling 2019-04-23 17:35:56 +03:00
Ivan Babkin ee4e43f47a
Merge pull request #71 from TouchInstinct/feature/status_codes
Added additional valid status codes parameter to request methods
2019-04-23 12:59:24 +03:00
Ivan Babkin fb309f5955 Added additional valid status codes parameter to request methods 2019-04-23 12:13:47 +03:00
ArturAzarau dc5bdc6b7f
Merge pull request #69 from TouchInstinct/fix/networkExtension
Extension fixed
2019-04-12 14:48:08 +03:00
Artur 03fba9bde1 Extension fixed 2019-04-12 14:47:01 +03:00
ArturAzarau 9aad096325
Merge pull request #68 from TouchInstinct/fix/deletingProtocolName
Protocol name was deleted and replaced with networkServiceName
2019-04-11 18:57:28 +03:00
Artur 7779e0389a Protocol name was deleted and replaced with networkServiceName 2019-04-11 18:54:26 +03:00
Alexander Buntakov 8892c9613e
Merge pull request #67 from TouchInstinct/fix/another_desc_update
another kotlin server desc update
2019-03-18 16:26:20 +03:00
Elena Bobkova 85637916ef another kotlin server desc update 2019-03-18 16:25:38 +03:00
Alexander Buntakov 5a7019259c
Merge pull request #66 from TouchInstinct/fix/kotlin_server_package
"api" removed from package name
2019-03-18 16:21:51 +03:00
Elena Bobkova 957dadaa5d "api" removed from package name 2019-03-18 16:18:02 +03:00
Alexander Buntakov ee8b8d9ee3
Merge pull request #65 from TouchInstinct/feature/enum_description_added
enum description added for kotlin server templates
2019-03-18 16:14:32 +03:00
Elena Bobkova d389a1e124 enum description added for kotlin server templates 2019-03-18 16:13:21 +03:00
Pavel c5b48a8510
Merge pull request #64 from TouchInstinct/fix/swift_generics_fix
Swift generics fix
2019-03-07 22:32:59 +03:00
Pavel Lukandiy 4d5dc00d95 Lines removed 2019-03-07 19:54:37 +03:00
Pavel Lukandiy d9c70d45f2 Swift generics fix 2019-03-07 18:12:39 +03:00
Elena Bobkova 8ad65e0cc7
Merge pull request #63 from TouchInstinct/feature/fix-btn-size
fix pdf button size
2019-01-31 19:02:57 +03:00
Alexander Buntakov 83307a1032 fix pdf button size 2019-01-31 19:01:13 +03:00
Elena Bobkova 508d76a12f
Merge pull request #62 from TouchInstinct/feature/fix-menu
fixed menu position
2019-01-31 17:31:06 +03:00
Alexander Buntakov 04950c5155 fixed menu position 2019-01-31 17:12:03 +03:00
Elena Bobkova 48fa353d7b
Merge pull request #61 from TouchInstinct/feature/fix-menu
fix menu, add pdf button
2019-01-31 16:13:50 +03:00
Alexander Buntakov d00122b5f0 fix menu, add pdf button 2019-01-31 16:10:42 +03:00
ArturAzarau 7d24672efb
Merge pull request #60 from TouchInstinct/feature/deferredApiParameters
Feature/deferred api parameters
2019-01-30 17:19:12 +03:00
Artur Azarau 3ab64ec7a9 "parameters" in protocol function apiRequest were renamed to "parametersSingle" 2019-01-30 17:15:31 +03:00
Artur Azarau 8ad8a3d4fd "parameters" in apiRequest were renamed to "parametersSingle" 2019-01-30 17:13:01 +03:00
Artur Azarau 5da7e8d448 api request fixed 2019-01-30 17:06:32 +03:00
Artur Azarau 63383938db deferredApiRequestParameters fixed 2019-01-30 17:03:19 +03:00
Artur Azarau ad97e4e110 fixes 2019-01-30 16:34:11 +03:00
Artur Azarau e7800f2f43 network requests were made deferred 2019-01-30 15:21:00 +03:00
Artur Azarau f999e87688 work in progress 2019-01-30 13:25:46 +03:00
Elena Bobkova fd313e1003
Merge pull request #59 from TouchInstinct/feature/build-version
add build version
2019-01-29 16:30:05 +03:00
Alexander Buntakov a92b5884a2 add build version 2019-01-29 16:21:05 +03:00
iON1k 78a5aba5b8
Merge pull request #58 from TouchInstinct/feature/network_service_deferred
Network service lazy request generation
2018-12-26 17:12:54 +03:00
Anton Popkov 36056b8d34 Network service lazy request generation 2018-12-26 16:12:52 +03:00
Ivan Vlasov 121ec4f611
Merge pull request #57 from TouchInstinct/fix/java_class_primary_keys
Multiple primary keys for Java classes fixed
2018-12-20 19:09:08 +03:00
Andrey Ovsyannikov 2abb3050e0
Merge pull request #56 from TouchInstinct/feature/network_protocol
Feature/network protocol
2018-12-20 19:04:06 +03:00
Ivan Vlasov f4d6aaa660 Multiple primary keys for Java classes fixed 2018-12-20 19:01:42 +03:00
Madhas ae58fc94e2 formatting 2018-12-20 17:52:03 +03:00
Madhas 0f8d1fc275 fix 2018-12-20 17:43:46 +03:00
Madhas 3e4da17a83 fix 2018-12-20 16:47:21 +03:00
Madhas 254516312a method declaration 2018-12-20 16:19:03 +03:00
Madhas cd8c08e29b fix 2018-12-20 16:04:46 +03:00
Madhas 6ad74c3e00 remove default arguments 2018-12-20 15:53:10 +03:00
Madhas 0c9cd2b9f7 add generated network protocol
generate methods in extension of the protocol
2018-12-20 14:44:11 +03:00
Denis Karmyshakov cffdf6ffcc
Merge pull request #55 from TouchInstinct/converters_fix
Converters fix
2018-12-19 14:23:59 +03:00
Denis Karmyshakov 3559fb0900 Converters fix 2018-12-18 13:14:13 +03:00
Denis Karmyshakov 4e11a513b7
Merge pull request #54 from TouchInstinct/fixes
TypeConverters annotation fix
2018-12-17 18:11:07 +03:00
Denis Karmyshakov fdc95430f1 TypeConverters annotation fix 2018-12-17 18:08:26 +03:00
Denis Karmyshakov e1ba769d89
Merge pull request #53 from TouchInstinct/fixes
Persistence templates update
2018-12-14 16:50:37 +03:00
Denis Karmyshakov f6f4519d50 Persistence templates update 2018-12-14 16:47:46 +03:00
Denis Karmyshakov 1482b2f814
Merge pull request #52 from TouchInstinct/primary_key_fix
Primary key fixes
2018-12-12 16:18:04 +03:00
Denis Karmyshakov 1efada9069 Primary key fixes 2018-12-12 15:09:25 +03:00
Ivan Smolin 79a291c441
Merge pull request #51 from TouchInstinct/feature/swift_case_iterable
use Swift 4.2 CaseIterable. escape "operator" keyword
2018-11-30 20:07:14 +03:00
Ivan Smolin d3f96b0e45 use Swift 4.2 CaseIterable. escape "operator" keyword 2018-11-30 20:00:50 +03:00
Elena Bobkova 28a533113f
Merge pull request #50 from TouchInstinct/fix/kotlin_server_templates
server templates order fixed
2018-11-29 14:11:58 +03:00
Elena Bobkova e16f6893cd date format updated 2018-11-29 12:54:47 +03:00
Elena Bobkova 06c2d329c6 server templates order fixed 2018-11-28 17:36:15 +03:00
Elena Bobkova 5d7517ef1f
Merge pull request #49 from TouchInstinct/feature/server_templates
Feature/server templates
2018-11-23 15:16:50 +03:00
Elena Bobkova 5cbbcce2f6 description added 2018-11-23 14:49:42 +03:00
Elena Bobkova fb8a1d4f7c TODO updated 2018-11-22 14:40:44 +03:00
Elena Bobkova c19a07be81 unused macros removed 2018-11-22 14:27:20 +03:00
Elena Bobkova fcc3cc5bdd dateformat templates added 2018-11-22 14:26:15 +03:00
Elena Bobkova a97be8fd65 fixed file extensions 2018-11-19 17:01:32 +03:00
Elena Bobkova 19e71f8df2 unused blocks removed 2018-11-19 16:59:26 +03:00
Elena Bobkova 46c0f736ac enum convertion added 2018-11-19 16:56:23 +03:00
Elena Bobkova 786b297972 enum update started 2018-11-19 16:21:45 +03:00
Elena Bobkova 619ab37721 added nullable annnotations 2018-11-19 16:03:14 +03:00
Elena Bobkova a6a2d95a27 methods generation removed 2018-11-19 15:05:16 +03:00
Elena Bobkova 2f19c95e90 types fixed 2018-11-19 15:04:47 +03:00
Elena Bobkova b55a5946c6 super init updated 2018-11-19 15:01:44 +03:00
Elena Bobkova 24cd12bac4 fixed null check 2018-11-19 14:55:11 +03:00
Elena Bobkova b1764bf5cf updated fields 2018-11-16 14:28:03 +03:00
Elena Bobkova ded0fba8a7 kotlin templates started 2018-11-16 14:03:15 +03:00
Ivan Smolin e2568de3cb
Merge pull request #48 from TouchInstinct/feature/swift_copy_without
add copyWithout method to classes
2018-10-30 16:07:00 +03:00
Ivan Smolin 81163c14b3 add copyWithout method to classes 2018-10-30 15:37:32 +03:00
PilotOfSparrow 7c24039a3d
Merge pull request #47 from TouchInstinct/androidx
Androidx packages
2018-10-22 10:53:14 +03:00
Denis Karmyshakov c0b427e209 Androidx packages 2018-10-20 13:09:53 +03:00
Denis Karmyshakov 2a4bcd183d
Merge pull request #46 from TouchInstinct/java_optional
java utils
2018-10-17 18:28:54 +03:00
Denis Karmyshakov 30c7030789 java utils 2018-10-17 18:00:31 +03:00
Denis Karmyshakov e59f073d51
Merge pull request #45 from TouchInstinct/java_optional
Java: nullable for all optional fields
2018-10-17 17:58:50 +03:00
Denis Karmyshakov bc38069cb5 nullable for all optional fields 2018-10-17 17:52:40 +03:00
Denis Karmyshakov 2b06c9e131
Merge pull request #43 from TouchInstinct/java_storage
Storage templates for Java
2018-10-17 13:40:23 +03:00
Alexey Gerasimov 8207654a5e
Merge pull request #44 from TouchInstinct/fix/optionalEncoding
Optional or nullable encoding fixed
2018-10-16 15:14:01 +03:00
Alexey Gerasimov a9c033605e Optional or nullable encoding fixed 2018-10-16 14:44:49 +03:00
Denis Karmyshakov d7037356db default value for serializeNulls 2018-10-16 14:10:36 +03:00
iON1k 7b47499624
Merge pull request #42 from TouchInstinct/feature/optional_date_fix
Optional date fix
2018-10-16 13:34:36 +03:00
Ivan Smolin bdeb5c8509 remove whitespaces 2018-10-16 13:20:48 +03:00
Anton Popkov 1f35019eff Optional date fix 2018-10-16 12:54:39 +03:00
Denis Karmyshakov 4d9cfd957d Getter fixes and formatting 2018-10-12 18:45:55 +03:00
Denis Karmyshakov 4ff3c8c8d6 Dao generating 2018-10-12 15:07:05 +03:00
Denis Karmyshakov 2599ca2411 Removed optional wrappers 2018-10-12 11:58:55 +03:00
Denis Karmyshakov 98099725e0 CONVERTERS 2018-10-05 20:36:44 +03:00
Denis Karmyshakov 46cbd04df0 List and map converters 2018-10-04 19:58:27 +03:00
Denis Karmyshakov 878953885d Enum converters 2018-10-03 19:56:05 +03:00
Denis Karmyshakov 22b487381c Enum converters 2018-10-03 16:45:03 +03:00
Denis Karmyshakov 9d88033a76 Merge remote-tracking branch 'origin/master' into java_storage 2018-09-26 23:15:59 +03:00
Denis Karmyshakov d5bc9e2ddf
Merge pull request #41 from TouchInstinct/validation_fix
Java: Validation fix
2018-09-26 14:01:16 +03:00
Denis Karmyshakov 122f9de754 Java: Validation fix 2018-09-26 14:00:25 +03:00
Denis Karmyshakov 10d2ea6be8
Merge pull request #40 from TouchInstinct/fix
Java: Validation fix
2018-09-26 13:45:30 +03:00
Denis Karmyshakov e15a432f44 Java: Validation fix 2018-09-26 13:43:01 +03:00
Denis Karmyshakov b6f316e55f wip: Storage 2018-09-26 12:48:29 +03:00
Denis Karmyshakov 0b767ab613 wip: Storage 2018-09-21 17:21:13 +03:00
Denis Karmyshakov b40e98d4bb
Merge pull request #39 from TouchInstinct/validation_fix
Java: Validation fix
2018-09-21 11:25:24 +03:00
Denis Karmyshakov 5181c2b0ef Java: Validation fix 2018-09-21 10:37:05 +03:00
Elena Bobkova f1fdcde2ad
Merge pull request #38 from TouchInstinct/dateFormat_in_doc
print dateFormat in doc
2018-09-06 14:05:41 +03:00
Arseniy Borisov d096b3bd79 print dateFormat in doc 2018-09-06 14:03:43 +03:00
Ivan Smolin 53ddf87777
Merge pull request #37 from TouchInstinct/fix/swift_optional_date_encoding
fix swift optional date encoding
2018-08-24 14:08:15 +03:00
Ivan Smolin 65674ad1bb fix swift optional date encoding 2018-08-24 13:55:58 +03:00
77 changed files with 1346 additions and 674 deletions

View File

@ -1,16 +1,30 @@
{%- set hasParent = parent is not null -%}
/**
/*
* This code is autogenerated by Touch Instinct tools
*/
package {{ packageName }}.api;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.ObjectsCompat;
{%- if (storageAttributes is not null) %}
import androidx.room.Delete;
import androidx.room.Entity;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import androidx.room.Transaction;
import androidx.room.TypeConverter;
import androidx.room.TypeConverters;
import androidx.room.PrimaryKey;
import androidx.room.Ignore;
import io.reactivex.Flowable;
import io.reactivex.Single;
{%- endif %}
import com.bluelinelabs.logansquare.LoganSquare;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.bluelinelabs.logansquare.JsonOptional;
import com.bluelinelabs.logansquare.NonNullJsonOptional;
import java.io.IOException;
import java.io.ObjectInputStream;
@ -27,75 +41,125 @@ import java.util.HashMap;
import org.joda.time.DateTime;
import ru.touchin.templates.ApiModel;
import ru.touchin.roboswag.core.utils.ObjectUtils;
import ru.touchin.templates.logansquare.LoganSquareJsonModel;
{% if (description is not empty) %}
{%- if (description is not empty) %}
/**
* {{ description }}
*/
{% endif -%}
@JsonObject(serializeNullObjects = true)
{%- endif %}
{%- if (storageAttributes is not null) %}
{%- set attributeWas = false %}
@Entity(
{%- if (storageAttributes.tableName is not null) -%}
{%- set attributeWas = true -%}
tableName = "{{ storageAttributes.tableName }}"
{%- endif -%}
{%- if attributeWas and storageAttributes.primaryKeys is not empty -%}, {% endif %}
{%- if (storageAttributes.primaryKeys is not empty) -%}
{%- set attributeWas = true -%}
primaryKeys = { {%- for key in storageAttributes.primaryKeys -%} "{{- key -}}" {%- if not (loop.last) %}, {% endif -%} {%- endfor -%} }
{%- endif -%}
)
{%- set haveConverters = false -%}
{%- for field in fields -%}
{%- if (field.type.type.baseTypeName == "Array")
or (field.type.type.baseTypeName == "Map")
or (field.type.type.baseTypeName != "Bool"
and field.type.type.baseTypeName != "Int"
and field.type.type.baseTypeName != "Long"
and field.type.type.baseTypeName != "Double"
and field.type.type.baseTypeName != "String"
and field.type.storable != true) %}
{%- set haveConverters = true -%}
{%- endif -%}
{%- endfor -%}
{%- if haveConverters %}
@TypeConverters({{ type.baseTypeName }}.class)
{%- endif -%}
{%- endif %}
@JsonObject(serializeNullObjects = {{ default(serializeNulls, false) }})
public class {% include 'blocks/class/classtype.twig' with { type: type } %} extends {% include 'blocks/class/supertype.twig' with { type: type, parent: parent } %} {
{%- include 'blocks/class/fields-converters.twig' -%}
{% include 'blocks/class/fields.twig' with { fields: fields } %}
public {{ type.baseTypeName }}() {
super();
}
{% if (allFieldsOrdered is not empty) %}
//TODO: if TItems instance of arrayList then new ArrayList
public {{ type.baseTypeName }}({%- include 'blocks/class/init-parameters-fields.twig' with { fields: allFieldsOrdered } -%}) {
{%- if (allFieldsOrdered is not empty) %}
//TODO: if TItems instance of arrayList then new ArrayList
{%- if (storageAttributes is not null) %}
@Ignore
{%- endif %}
public {{ type.baseTypeName }}(
{%- include 'blocks/class/init-parameters-fields.twig' with { fields: allFieldsOrdered } %}
) {
super({%- include 'blocks/class/fields-super-initialization.twig' with { fields: superclassesFields } -%});
{%- include 'blocks/class/fields-initialization.twig' with { fields: fields, object: "this" } %}
}
{% endif %}
{%- include 'blocks/class/fields-getters-setters.twig' with { fields: fields } %}
//TODO: add check for collection if TypeParameter
//TODO: do not validate enums as ApiModel
@Override
public void validate() throws ValidationException {
super.validate();
{%- include 'blocks/class/fields-validate.twig' with { fields: fields } %}
}
{%- endif %}
{% include 'blocks/class/fields-getters-setters.twig' with { fields: fields } %}
protected void copyTo(@NonNull final {% include 'blocks/class/classtype.twig' with { type: type } %} destination) {
{%- if parent is not null %}
super.copyTo(destination);
{%- endif %}
{%- include 'blocks/class/fields-initialization.twig' with { fields: fields, object: "destination" } %}
}
//TODO: add check for collection if TypeParameter
//TODO: do not validate enums as ApiModel
@Override
public void validate() throws ValidationException {
super.validate();
{%- include 'blocks/class/fields-validate.twig' with { fields: fields } %}
}
@NonNull
public {% include 'blocks/class/classtype.twig' with { type: type } %} copy() {
final {% include 'blocks/class/classtype.twig' with { type: type } %} result = new {% include 'blocks/class/classtype.twig' with { type: type } %}();
this.copyTo(result);
return result;
}
protected void copyTo(@NonNull final {% include 'blocks/class/classtype.twig' with { type: type } %} destination) {
{%- if parent is not null %}
super.copyTo(destination);
{%- endif %}
{%- include 'blocks/class/fields-initialization.twig' with { fields: fields, object: "destination" } %}
}
public int hashCode() {
return ObjectUtils.hashCode({%- if parent is not null -%}super.hashCode(), {% endif -%}{%- include 'blocks/class/fields-super-initialization.twig' with { fields: fields } -%});
}
@NonNull
public {% include 'blocks/class/classtype.twig' with { type: type } %} copy() {
final {% include 'blocks/class/classtype.twig' with { type: type } %} result = new {% include 'blocks/class/classtype.twig' with { type: type } %}();
this.copyTo(result);
return result;
}
{%- if (fields is not empty) %}
public int hashCode() {
return ObjectsCompat.hash({%- if parent is not null -%}super.hashCode(), {% endif -%}{%- include 'blocks/class/fields-super-initialization.twig' with { fields: fields } -%});
}
@SuppressWarnings("unchecked")
public boolean equals(@Nullable final Object object) {
if (this == object) {
return true;
}
if (object == null || getClass() != object.getClass()) {
return false;
}
final {% include 'blocks/class/classtype.twig' with { type: type } %} that = ({% include 'blocks/class/classtype.twig' with { type: type } %}) object;
return {% if parent is not null -%}super.equals(that)
&& {% endif -%}
{%- include 'blocks/class/fields-equals.twig' with { fields: fields } -%};
}
if (this == object) {
return true;
}
if (object == null || getClass() != object.getClass()) {
return false;
}
final {% include 'blocks/class/classtype.twig' with { type: type } %} that = ({% include 'blocks/class/classtype.twig' with { type: type } %}) object;
return {% if parent is not null -%}super.equals(that)
&& {% endif -%}
{%- include 'blocks/class/fields-equals.twig' with { fields: fields } -%};
}
private void writeObject(@NonNull final ObjectOutputStream outputStream) throws IOException {
{%- include 'blocks/class/fields-write-object.twig' with { fields: fields } %}
}
private void writeObject(@NonNull final ObjectOutputStream outputStream) throws IOException {
{%- include 'blocks/class/fields-write-object.twig' with { fields: fields } %}
}
@SuppressWarnings("unchecked")
private void readObject(@NonNull final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
{%- include 'blocks/class/fields-read-object.twig' with { fields: fields } %}
}
@SuppressWarnings("unchecked")
private void readObject(@NonNull final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
{%- include 'blocks/class/fields-read-object.twig' with { fields: fields } %}
}
{%- endif %}
{%- include 'blocks/class/dao.twig' %}
}

View File

@ -1,10 +1,13 @@
{%- import 'utils.twig' as utils -%}
/**
/*
* This code is autogenerated by Touch Instinct tools
*/
package {{ packageName }}.api;
import android.support.annotation.NonNull;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
{%- if storable %}
import androidx.room.TypeConverter;
{%- endif %}
import com.bluelinelabs.logansquare.annotation.JsonEnum;
{%- if valuesTypes == "STRING" %}
@ -21,6 +24,9 @@ import ru.touchin.templates.logansquare.LoganSquareEnumConverter;
*/
@JsonEnum
public enum {{ name }} {
{% include 'blocks/enum/cases.twig' with { values: values } %}
{%- include 'blocks/enum/cases.twig' with { values: values } %}
{%- include 'blocks/enum/converters.twig' %}
}

View File

@ -1,9 +1,9 @@
/**
/*
* This code is autogenerated by Touch Instinct tools
*/
package {{ packageName }}.api;
import android.support.annotation.NonNull;
import androidx.annotation.NonNull;
import io.reactivex.Single;
import retrofit2.http.Body;

View File

@ -0,0 +1,38 @@
{%- import '../../utils.twig' as utils -%}
{%- if (storageAttributes is not null) %}
@androidx.room.Dao
public interface Dao {
@NonNull
@Query("SELECT * FROM {{ default(storageAttributes.tableName, type.baseTypeName) }}")
List<{{ type.baseTypeName }}> get();
@NonNull
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(@NonNull final Iterable<{{ type.baseTypeName }}> list);
@NonNull
@Delete
void delete(@NonNull final Iterable<{{ type.baseTypeName }}> list);
@Query("DELETE FROM {{ default(storageAttributes.tableName, type.baseTypeName) }}")
void clear();
}
@androidx.room.Dao
public interface ReactiveDao extends Dao {
@NonNull
@Query("SELECT * FROM {{ default(storageAttributes.tableName, type.baseTypeName) }}")
Flowable<List<{{ type.baseTypeName }}>> observe();
@NonNull
@Query("SELECT * FROM {{ default(storageAttributes.tableName, type.baseTypeName) }}")
Single<List<{{ type.baseTypeName }}>> getSingle();
}
{%- endif -%}

View File

@ -0,0 +1,134 @@
{%- import '../../utils.twig' as utils -%}
{%- if (storageAttributes is not null) -%}
{% set converters = [] %}
{%- for field in fields -%}
{%- if not (field.type.type.baseTypeName in converters) -%}
{%- if field.type.type.baseTypeName == "Array" %}
@TypeConverter
@Nullable
public static String serialize{{ field.type.type.itemsType.baseTypeName }}List(@Nullable final {{ utils.formatValueType(field.type.type, true, true) }} value) {
if (value == null) {
return null;
}
try {
return LoganSquare.serialize(value, {{ utils.formatValueType(field.type.type.itemsType, true, true) }}.class);
} catch (final IOException exception) {
return null;
}
}
@TypeConverter
@Nullable
public static {{ utils.formatValueType(field.type.type, true, true) }} deserialize{{ field.type.type.itemsType.baseTypeName }}List(@Nullable final String value) {
if (value == null) {
return null;
}
try {
return LoganSquare.parseList(value, {{ utils.formatValueType(field.type.type.itemsType, true, true) }}.class);
} catch (final IOException exception) {
return null;
}
}
{%- set converters = merge(converters, field.type.type.itemsType.baseTypeName) -%}
{%- elseif field.type.type.baseTypeName == "Map" %}
@TypeConverter
@Nullable
public static String serialize{{ field.type.type.valuesType.baseTypeName }}Map(@Nullable final {{ utils.formatValueType(field.type.type, true, true) }} value) {
if (value == null) {
return null;
}
try {
return LoganSquare.serialize(value), {{ utils.formatValueType(field.type.type.valuesType, true, true) }};
} catch (final IOException exception) {
return null;
}
}
@TypeConverter
@Nullable
public static {{ utils.formatValueType(field.type.type, true, true) }} deserialize{{ field.type.type.valuesType.baseTypeName }}Map(@Nullable final String value) {
if (value == null) {
return null;
}
try {
return LoganSquare.parseMap(value, {{ utils.formatValueType(field.type.type.valuesType, true, true) }}.class);
} catch (final IOException exception) {
return null;
}
}
{%- set converters = merge(converters, field.type.type.valuesType.baseTypeName) -%}
{%- elseif field.type.type.baseTypeName == "DateTime" %}
@TypeConverter
@Nullable
public static String serialize{{ field.type.type.baseTypeName }}(@Nullable final {{ utils.formatValueType(field.type.type, true, true) }} value) {
if (value == null) {
return null;
}
return value.toString();
}
@TypeConverter
@Nullable
public static {{ utils.formatValueType(field.type.type, true, true) }} deserialize{{ field.type.type.baseTypeName }}(@Nullable final String value) {
if (value == null) {
return null;
}
try {
return DateTime.parse(value);
} catch (final Exception exception) {
return null;
}
}
{%- set converters = merge(converters, field.type.type.baseTypeName) -%}
{%- elseif field.type.type.baseTypeName != "Bool"
and field.type.type.baseTypeName != "Int"
and field.type.type.baseTypeName != "Long"
and field.type.type.baseTypeName != "Double"
and field.type.type.baseTypeName != "String"
and field.type.storable != true %}
@TypeConverter
@Nullable
public static String serialize{{ field.type.type.baseTypeName }}(@Nullable final {{ utils.formatValueType(field.type.type, true, true) }} value) {
if (value == null) {
return null;
}
try {
return LoganSquare.serialize(value);
} catch (final IOException exception) {
return null;
}
}
@TypeConverter
@Nullable
public static {{ utils.formatValueType(field.type.type, true, true) }} deserialize{{ field.type.type.baseTypeName }}(@Nullable final String value) {
if (value == null) {
return null;
}
try {
return LoganSquare.parse(value, {{ utils.formatValueType(field.type.type, true, true) }}.class);
} catch (final IOException exception) {
return null;
}
}
{%- set converters = merge(converters, field.type.type.baseTypeName) -%}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- endif -%}

View File

@ -1,5 +1,4 @@
{%- import '../../utils.twig' as utils -%}
{%- for field in fields -%}
{{ utils.formatEquals(field.name, field.type.type.baseTypeName, field.optional) }} {%- if not (loop.last) %}
&& {% endif %}
ObjectsCompat.equals(this.{{ field.name }}, that.{{ field.name }}) {%- if not (loop.last) %}
&& {% endif %}
{%- endfor -%}

View File

@ -1,24 +1,32 @@
{%- import '../../utils.twig' as utils -%}
{%- if fields is not empty -%}
{%- for field in fields %}
{% if (field.description is not empty) %}
{% if (field.description is not empty) %}
/**
* {{ field.description }}
*/
{% endif -%}
* {{ field.description }}
*/
{%- endif %}
{{ utils.writeNullCheckAnnotation(field.type.type.baseTypeName, field.nullable, field.optional) }}
public {{ utils.formatValueType(field.type.type, field.nullable, field.optional) }} {% if (field.type.type.baseTypeName == "Bool") and (field.name matches "^is[A-Z,0-9].*") -%}{{ field.name }}{%- else -%}get{{ utils.capitalize(field.name) }}{%- endif -%}() {
{{ utils.formatValueGetter(field.name, field.type.type, field.nullable) }}
}
{% if (field.description is not empty) %}
public {{ utils.formatValueType(field.type.type, field.nullable, field.optional) }} {% if (field.type.type.baseTypeName == "Bool") and (field.name matches "^is[A-Z,0-9].*") -%}{{ field.name }}{%- else -%}get{{ capitalize(field.name) }}{%- endif -%}() {
{%- if field.nullable or field.optional %}
if (this.{{ field.name }} == null) {
return null;
}
{%- endif %}
{%- if field.type.type.baseTypeName == "Array" %}
return Collections.unmodifiableList(this.{{ field.name }});
{%- elseif field.type.type.baseTypeName == "Map" %}
return Collections.unmodifiableMap(this.{{ field.name }});
{%- else %}
return this.{{ field.name }};
{%- endif %}
}
{% if (field.description is not empty) %}
/**
* {{ field.description }}
*/
{% endif -%}
public void set{{ utils.capitalize(field.name) }}({{ utils.writeNullCheckAnnotation(field.type.type.baseTypeName, field.nullable, field.optional) }} final {{ utils.formatValueType(field.type.type, field.nullable, field.optional) }} {{ field.name }}) {
{{ utils.formatValueSetter("this", field.name, field.type.type.baseTypeName, field.nullable ) }}
}
{% endfor -%}
{%- endif -%}
* {{ field.description }}
*/
{%- endif %}
public void set{{ capitalize(field.name) }}({{ utils.writeNullCheckAnnotation(field.type.type.baseTypeName, field.nullable, field.optional) }} final {{ utils.formatValueType(field.type.type, field.nullable, field.optional) }} {{ field.name }}) {
this.{{ field.name }} = {{ field.name }};
}
{%- endfor -%}

View File

@ -1,4 +1,3 @@
{%- import '../../utils.twig' as utils -%}
{%- for field in fields %}
{{ utils.formatValueSetter(object, field.name, field.type.type.baseTypeName, field.nullable ) }}
{{ object }}.{{ field.name }} = {{ field.name }};
{%- endfor -%}

View File

@ -1,4 +1,18 @@
{%- import '../../utils.twig' as utils -%}
{% for field in fields %}
this.{{ field.name }} = {{ utils.formatReadObject(field.type.type, field.nullable, field.optional) }};
{%- endfor -%}
{%- if field.nullable or field.optional %}
this.{{ field.name }} = ({{ utils.formatValueType(field.type.type, field.nullable, field.optional) }}) inputStream.readObject();
{%- elseif field.type.type.baseTypeName == "Int" %}
this.{{ field.name }} = inputStream.readInt();
{%- elseif field.type.type.baseTypeName == "Long" %}
this.{{ field.name }} = inputStream.readLong();
{%- elseif field.type.type.baseTypeName == "Double" %}
this.{{ field.name }} = inputStream.readDouble();
{%- elseif field.type.type.baseTypeName == "String" %}
this.{{ field.name }} = inputStream.readUTF();
{%- elseif field.type.type.baseTypeName == "Bool" %}
this.{{ field.name }} = inputStream.readBoolean();
{%- else %}
this.{{ field.name }} = ({{ utils.formatValueType(field.type.type, field.nullable, field.optional) }}) inputStream.readObject();
{%- endif -%}
{%- endfor -%}

View File

@ -1,4 +1,44 @@
{%- import '../../utils.twig' as utils -%}
{% for field in fields -%}
{{ utils.formatValidateObject(concat("this.", field.name), field.type, field.type.type, field.nullable, field.optional) }}
{%- for field in fields %}
{%- if not (field.nullable or field.optional)
and field.type.type.baseTypeName != "Int"
and field.type.type.baseTypeName != "Long"
and field.type.type.baseTypeName != "Double"
and field.type.type.baseTypeName != "Bool" %}
validateNotNull(this.{{ field.name }});
{%- endif %}
{%- if field.type.type.baseTypeName == "Map" %}
{%- if field.nullable or field.optional %}
if (this.{{ field.name }} != null) {
validateCollection(this.{{ field.name }}.values(), CollectionValidationRule.EXCEPTION_IF_ANY_INVALID);
}
{%- else %}
validateCollection(this.{{ field.name }}.values(), CollectionValidationRule.EXCEPTION_IF_ANY_INVALID);
{%- endif %}
{%- elseif field.type.type.baseTypeName == "Array" %}
{%- if field.nullable or field.optional %}
if (this.{{ field.name }} != null) {
validateCollection(this.{{ field.name }}, CollectionValidationRule.EXCEPTION_IF_ANY_INVALID);
}
{%- else %}
validateCollection(this.{{ field.name }}, CollectionValidationRule.EXCEPTION_IF_ANY_INVALID);
{%- endif %}
{%- elseif field.type.type.baseTypeName != "Int"
and field.type.type.baseTypeName != "Long"
and field.type.type.baseTypeName != "Double"
and field.type.type.baseTypeName != "Bool"
and field.type.type.baseTypeName != "String"
and field.type.type.baseTypeName != "Decimal"
and field.type.type.baseTypeName != "DateTime"
and (field.type.values is empty) %}
if (this.{{ field.name }} instanceof ApiModel) {
{%- if field.nullable or field.optional %}
if (this.{{ field.name }} != null) {
((ApiModel) this.{{ field.name }}).validate();
}
{%- else %}
((ApiModel) this.{{ field.name }}).validate();
{%- endif %}
}
{%- endif -%}
{%- endfor -%}

View File

@ -1,4 +1,17 @@
{%- import '../../utils.twig' as utils -%}
{% for field in fields %}
outputStream.{{ utils.formatWriteObject(field.name, field.type.type, field.nullable, field.optional) }};
{%- endfor -%}
{%- if field.nullable or field.optional %}
outputStream.writeObject(this.{{ field.name }});
{%- elseif field.type.type.baseTypeName == "Int" %}
outputStream.writeInt(this.{{ field.name }});
{%- elseif field.type.type.baseTypeName == "Long" %}
outputStream.writeLong(this.{{ field.name }});
{%- elseif field.type.type.baseTypeName == "Double" %}
outputStream.writeDouble(this.{{ field.name }});
{%- elseif field.type.type.baseTypeName == "String" %}
outputStream.writeUTF(this.{{ field.name }});
{%- elseif field.type.type.baseTypeName == "Bool" %}
outputStream.writeBoolean(this.{{ field.name }});
{%- else %}
outputStream.writeObject(this.{{ field.name }});
{%- endif -%}
{%- endfor -%}

View File

@ -1,14 +1,23 @@
{%- import '../../utils.twig' as utils -%}
{%- if fields is not empty -%}
{% for field in fields %}
{% if (field.description is not empty) %}
/**
* {{ field.description }}
*/
{% endif -%}
{%- for field in fields %}
{%- if (field.description is not empty) %}
/**
* {{ field.description }}
*/
{%- endif %}
{{ utils.writeNullCheckAnnotation(field.type.type.baseTypeName, field.nullable, field.optional) }}
{%- if (storageAttributes is not null) %}
{%- if (field.type.storable) %}
@TypeConverters({{ field.type.type.baseTypeName }}.class)
{%- endif %}
{%- if (field.autoGenerate) %}
@PrimaryKey(autoGenerate = true)
{%- endif %}
{%- endif %}
{%- if (storageAttributes is null) or (field.autoGenerate != true) %}
@JsonField(name = "{{ field.jsonName }}")
{{ utils.writeNullCheckAnnotation(field.type.type.baseTypeName, field.nullable, field.optional) }}
private {{ utils.formatValueType(field.type.type, field.nullable, field.optional) }} {{ field.name }} {%- if field.optional %} = {{ utils.formatOptionalValueType(field.type.type, field.nullable) }}.empty(){% endif %};
{% endfor -%}
{% endif %}
{%- endif %}
private {{ utils.formatValueType(field.type.type, field.nullable, field.optional) }} {{ field.name }};
{%- endfor -%}

View File

@ -1,7 +1,7 @@
{%- import '../../utils.twig' as utils -%}
{%- if fields is not empty -%}
{%- for field in fields -%}
{{ utils.writeNullCheckAnnotation(field.type.type.baseTypeName, field.nullable, field.optional) }} final {{ utils.formatValueType(field.type.type, field.nullable, field.optional) }} {{ field.name }} {%- if not (loop.last) %}, {% endif %}
{%- for field in fields %}
{{ utils.writeNullCheckAnnotation(field.type.type.baseTypeName, field.nullable, field.optional) }} final {{ utils.formatValueType(field.type.type, field.nullable, field.optional) }} {{ field.name }} {%- if not (loop.last) %}, {% endif %}
{%- endfor -%}
{%- endif -%}
{%- endif -%}

View File

@ -2,7 +2,7 @@
{%- if typeParameters is not empty -%}
<
{%- for typeParameter in typeParameters %}
{{- utils.formatSimpleValueType(typeParameter) -}}{%- if not (loop.last) %}, {% endif %}
{{- utils.formatValueType(typeParameter, true, true) -}}{%- if not (loop.last) %}, {% endif %}
{%- endfor -%}
>
{%- endif -%}
{%- endif -%}

View File

@ -1,10 +1,11 @@
{%- import '../../utils.twig' as utils -%}
{%- for value in values %}
{% if (value.description is not empty) %}
{%- if (value.description is not empty) %}
/**
* {{ value.description }}
*/
{% endif -%}
* {{ value.description }}
*/
{%- endif %}
{%- if valuesTypes == "STRING" %}
@JsonStringValue("{{ value.value }}")
{%- elseif valuesTypes == "INT" %}

View File

@ -0,0 +1,22 @@
{%- if storable %}
@TypeConverter
@Nullable
public static String serialize(@Nullable final {{ name }} value) {
if (value == null) {
return null;
}
return value.name();
}
@TypeConverter
@Nullable
public static {{ name }} deserialize(@Nullable final String value) {
if (value == null) {
return null;
}
return {{ name }}.valueOf(value);
}
{%- endif -%}

View File

@ -4,4 +4,4 @@
*/
@NonNull
@POST("{{ method.url }}")
Single<BaseResponse<{{ method.responseType.type.typeName }}>> {{ utils.decapitalize(method.name) }}(@NonNull @Body {{ method.bodyType.type.typeName }} {{ utils.decapitalize(method.bodyType.type.typeName) }});
Single<BaseResponse<{{ method.responseType.type.typeName }}>> {{ lower(method.name) }}(@NonNull @Body {{ method.bodyType.type.typeName }} {{ lower(method.bodyType.type.typeName) }});

View File

@ -1,19 +1,3 @@
{% macro decapitalize(text) %}
{{- concat(slice(text, 0, 1) | lower, slice(text, 1, text | length)) -}}
{% endmacro %}
{% macro capitalize(text) %}
{{- concat(slice(text, 0, 1) | upper, slice(text, 1, text | length)) -}}
{% endmacro %}
{% macro enumType(valuesTypes) %}
{%- if valuesTypes == "STRING" -%}
String
{%- elseif valuesTypes == "INT" -%}
Int
{%- endif -%}
{% endmacro %}
{% macro parentClassType(parent) %}
{%- if parent is not null %}
{{- parent.type.baseTypeName -}}
@ -23,257 +7,30 @@ LoganSquareJsonModel
{% endmacro %}
{% macro writeNullCheckAnnotation(baseTypeName, nullable, optional) %}
{%- if optional -%}
@NonNull
{%- elseif nullable -%}
{%- if nullable or optional -%}
@Nullable
{%- elseif not (baseTypeName == "Int" or baseTypeName == "Long" or baseTypeName == "Double" or baseTypeName == "Bool") -%}
@NonNull
{%- endif -%}
{% endmacro %}
{% macro formatNonOptionalValueType(valueType, tryUsePrimitive) %}
{% macro formatValueType(valueType, nullable, optional) %}
{% import _self as self %}
{%- if valueType.baseTypeName == "Int" -%}
{%- if tryUsePrimitive -%}int{%- else -%}Integer{%- endif -%}
{%- if nullable or optional -%}Integer{%- else -%}int{%- endif -%}
{%- elseif valueType.baseTypeName == "Long" -%}
{%- if tryUsePrimitive -%}long{%- else -%}Long{%- endif -%}
{%- if nullable or optional -%}Long{%- else -%}long{%- endif -%}
{%- elseif valueType.baseTypeName == "Double" -%}
{%- if tryUsePrimitive -%}double{%- else -%}Double{%- endif -%}
{%- if nullable or optional -%}Double{%- else -%}double{%- endif -%}
{%- elseif valueType.baseTypeName == "Bool" -%}
{%- if nullable or optional -%}Boolean{%- else -%}boolean{%- endif -%}
{%- elseif valueType.baseTypeName == "Decimal" -%}
BigDecimal
{%- elseif valueType.baseTypeName == "Bool" -%}
{%- if tryUsePrimitive -%}boolean{%- else -%}Boolean{%- endif -%}
{%- elseif valueType.baseTypeName == "Map" -%}
Map<{{ self.formatNonOptionalValueType(valueType.keysType, false) }}, {{ self.formatNonOptionalValueType(valueType.valuesType, false) }}>
Map<{{ self.formatValueType(valueType.keysType, true, true) }}, {{ self.formatValueType(valueType.valuesType, true, true) }}>
{%- elseif valueType.baseTypeName == "Array" -%}
List<{{ self.formatNonOptionalValueType(valueType.itemsType, false) }}>
List<{{ self.formatValueType(valueType.itemsType, true, true) }}>
{%- else -%}
{{ valueType.baseTypeName }}
{%- endif -%}
{% endmacro %}
{% macro formatOptionalValueType(valueType, nullable) %}
{% import _self as self %}
{%- if nullable -%} JsonOptional {%- else -%} NonNullJsonOptional {%- endif -%}
{% endmacro %}
{% macro formatValueType(valueType, nullable, optional) %}
{% import _self as self %}
{%- if optional -%}
{{ self.formatOptionalValueType(valueType, nullable) }}<{{ self.formatNonOptionalValueType(valueType, false) }}>
{%- else -%}
{{ self.formatNonOptionalValueType(valueType, not nullable) }}
{%- endif -%}
{% endmacro %}
{% macro formatSimpleValueType(valueType) %}
{%- import _self as self -%}
{{- self.formatValueType(valueType, true, false) -}}
{% endmacro %}
{% macro formatNullableValueSetter(fieldName, valueType, nullable) %}
{%- if valueType == "List" -%}
{%- if nullable -%}
{{ fieldName }} != null ? new ArrayList<>({{ fieldName }}) : null
{%- else -%}
new ArrayList<>({{ fieldName }})
{%- endif -%}
{%- elseif valueType == "Map" -%}
{%- if nullable -%}
{{ fieldName }} != null ? new HashMap<>({{ fieldName }}) : null
{%- else -%}
new HashMap<>({{ fieldName }})
{%- endif -%}
{%- else -%}
{{ fieldName }}
{%- endif -%}
{% endmacro %}
{% macro formatValueSetter(object, fieldName, valueType, nullable) %}
{% import _self as self %}
{%- if nullable -%}
{{ object }}.{{ fieldName }} = {{ self.formatNullableValueSetter(fieldName, valueType, nullable)}};
{%- else -%}
{{ object }}.{{ fieldName }} = {{ fieldName }};
{%- endif -%}
{% endmacro %}
{% macro formatNullableValueGetter(fieldName, valueType, nullable) %}
{%- if valueType == "List" -%}
{%- if nullable -%}
{{ fieldName }} != null ? Collections.unmodifiableList({{ fieldName }}) : null
{%- else -%}
Collections.unmodifiableList({{ fieldName }})
{%- endif -%}
{%- elseif valueType == "Map" -%}
{%- if nullable -%}
{{ fieldName }} != null ? Collections.unmodifiableMap({{ fieldName }}) : null
{%- else -%}
Collections.unmodifiableMap({{ fieldName }})
{%- endif -%}
{%- else -%}
{{ fieldName }}
{%- endif -%}
{% endmacro %}
{% macro formatValueGetter(fieldName, valueType, nullable) %}
{% import _self as self %}
{%- if nullable -%}
return {{ self.formatNullableValueGetter(fieldName, valueType, nullable) }};
{%- else -%}
return this.{{ fieldName }};
{%- endif -%}
{% endmacro %}
{% macro formatEquals(fieldName, valueType, optional) %}
{%- if valueType == "List" -%}
ObjectUtils.isCollectionsEquals({{ fieldName }}{%- if optional -%} .get() {%- endif -%}, that.{{ fieldName }}{%- if optional -%} .get() {%- endif -%})
{%- elseif valueType == "Map" -%}
ObjectUtils.isMapsEquals({{ fieldName }}{%- if optional -%} .get() {%- endif -%}, that.{{ fieldName }}{%- if optional -%} .get() {%- endif -%})
{%- else -%}
ObjectUtils.equals({{ fieldName }}, that.{{ fieldName }})
{%- endif -%}
{% endmacro %}
{% macro escapeIfNeeded(expr) %}
{%- if expr == "default" -%}
`{{ expr }}`
{%- else -%}
{{ expr }}
{%- endif -%}
{% endmacro %}
{% macro mappingFromMapForField(field) %}
{%- if field.type.type.baseTypeName == "DateTime" -%}
map.value("{{ field.jsonName }}", using: {{ field.name -}}Transform)
{%- else -%}
map.value("{{ field.jsonName }}")
{%- endif -%}
{% endmacro %}
{% macro mappingToMapForField(field) %}
{%- if field.type.type.baseTypeName == "DateTime" -%}
(map["{{ field.jsonName }}"], {{ field.name -}}Transform)
{%- else -%}
map["{{ field.jsonName }}"]
{%- endif -%}
{% endmacro %}
{% macro formatWriteObject(fieldName, valueType, nullable, optional) %}
{%- if nullable or optional -%}
writeObject({{ fieldName }})
{%- else -%}
{%- if valueType.baseTypeName == "Int" -%}
writeInt({{ fieldName }})
{%- elseif valueType.baseTypeName == "Long" -%}
writeLong({{ fieldName }})
{%- elseif valueType.baseTypeName == "Double" -%}
writeDouble({{ fieldName }})
{%- elseif valueType.baseTypeName == "String" -%}
writeUTF({{ fieldName }})
{%- elseif valueType.baseTypeName == "Bool" -%}
writeBoolean({{ fieldName }})
{%- else -%}
writeObject({{ fieldName }})
{%- endif -%}
{%- endif -%}
{% endmacro %}
{% macro formatReadObject(valueType, nullable, optional) %}
{% import _self as self %}
{%- if nullable or optional -%}
({{ self.formatValueType(valueType, nullable, optional) }}) inputStream.readObject()
{%- else -%}
{%- if valueType.baseTypeName == "Int" -%}
inputStream.readInt()
{%- elseif valueType.baseTypeName == "Long" -%}
inputStream.readLong()
{%- elseif valueType.baseTypeName == "Double" -%}
inputStream.readDouble()
{%- elseif valueType.baseTypeName == "String" -%}
inputStream.readUTF()
{%- elseif valueType.baseTypeName == "Bool" -%}
inputStream.readBoolean()
{%- else -%}
({{ self.formatValueType(valueType, nullable, optional) }}) inputStream.readObject()
{%- endif -%}
{%- endif -%}
{% endmacro %}
{% macro formatValidateObject(object, valueTopType, valueType, nullable, optional) %}
{% import _self as self %}
{%- if not nullable
and valueType.baseTypeName != "Int"
and valueType.baseTypeName != "Long"
and valueType.baseTypeName != "Double"
and valueType.baseTypeName != "Bool" %}
{%- if optional %}
if (!{{ object }}.isEmpty()) {
validateNotNull({{ object }}.get());
}
{%- else %}
validateNotNull({{ object }});
{%- endif -%}
{%- endif -%}
{%- if valueType.baseTypeName == "Map" %}
{%- if optional %}
if ({{ object }}.get() != null) {
validateCollection({{ object }}.get().values(), CollectionValidationRule.EXCEPTION_IF_ANY_INVALID);
}
{%- else -%}
{%- if nullable %}
if ({{ object }} != null) {
validateCollection({{ object }}.values(), CollectionValidationRule.EXCEPTION_IF_ANY_INVALID);
}
{%- else %}
validateCollection({{ object }}.values(), CollectionValidationRule.EXCEPTION_IF_ANY_INVALID);
{%- endif -%}
{%- endif -%}
{%- elseif valueType.baseTypeName == "Array" %}
{%- if optional %}
if ({{ object }}.get() != null) {
validateCollection({{ object }}.get(), CollectionValidationRule.EXCEPTION_IF_ANY_INVALID);
}
{%- else %}
{%- if nullable %}
if ({{ object }} != null) {
validateCollection({{ object }}, CollectionValidationRule.EXCEPTION_IF_ANY_INVALID);
}
{%- else %}
validateCollection({{ object }}, CollectionValidationRule.EXCEPTION_IF_ANY_INVALID);
{%- endif -%}
{%- endif -%}
{%- elseif valueType.baseTypeName != "Int"
and valueType.baseTypeName != "Long"
and valueType.baseTypeName != "Double"
and valueType.baseTypeName != "Bool"
and valueType.baseTypeName != "String"
and valueType.baseTypeName != "Decimal"
and valueType.baseTypeName != "DateTime"
and (valueTopType.values is empty) %}
{%- if valueTopType.allFieldsOrdered is empty %}
if ({{ object }} instanceof ApiModel) {
((ApiModel) {{ object }}{%- if optional -%} .get() {%- endif -%}).validate();
} else if ({{ object }} instanceof List) {
validateCollection(((List) {{ object }}), CollectionValidationRule.EXCEPTION_IF_ANY_INVALID);
} else if ({{ object }} instanceof Map) {
validateCollection(((Map) {{ object }}).values(), CollectionValidationRule.EXCEPTION_IF_ANY_INVALID);
}
{%- elseif optional %}
if ({{ object }}.get() != null) {
{{ object }}.get().validate();
}
{%- elseif nullable %}
if ({{ object }} != null) {
{{ object }}.validate();
}
{%- else -%}
{{ object }}.validate();
{%- endif -%}
{%- endif -%}
{% endmacro %}

View File

@ -0,0 +1,44 @@
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonEncodingException
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import java.util.Arrays
abstract class AbstractCalendarJsonAdapter<T, FORMATTER>(
private val formats: Array<String>
) : JsonAdapter<T>() {
companion object {
private const val CANT_FIND_ANY_FORMATTERS = "Can't find any DateTimeFormatter"
}
private val formatters = formats.map(::createFormatter)
abstract fun createFormatter(pattern: String): FORMATTER
override fun fromJson(reader: JsonReader): T? {
val dateTimeString = reader.nextString()
formatters.forEachIndexed { index, dateTimeFormatter ->
try {
return fromJsonInner(dateTimeString, dateTimeFormatter)
} catch (e: IllegalArgumentException) {
if (index == formatters.lastIndex) {
throw JsonEncodingException("$dateTimeString doesn't fit any of the formats ${Arrays.toString(formats)}")
}
}
}
throw IllegalArgumentException(CANT_FIND_ANY_FORMATTERS)
}
override fun toJson(writer: JsonWriter, value: T?) {
if (formatters.isEmpty()) throw IllegalArgumentException(CANT_FIND_ANY_FORMATTERS)
value?.let {
writer.value(toJsonInner(value, formatters.first()))
} ?: throw JsonEncodingException("Value can't be null")
}
abstract fun fromJsonInner(value: String, dateTimeFormatter: FORMATTER): T
abstract fun toJsonInner(value: T?, dateTimeFormatter: FORMATTER): String?
}

View File

@ -0,0 +1,14 @@
import java.time.format.DateTimeFormatter
import java.time.temporal.TemporalAccessor
abstract class AbstractJavaTimeJsonAdapter<T : TemporalAccessor>(
formats: Array<String>
) : AbstractCalendarJsonAdapter<T, DateTimeFormatter>(formats) {
override fun createFormatter(pattern: String): DateTimeFormatter = DateTimeFormatter.ofPattern(pattern)
override fun toJsonInner(value: T?, dateTimeFormatter: DateTimeFormatter): String? {
value ?: return null
return dateTimeFormatter.format(value)
}
}

View File

@ -0,0 +1,8 @@
import org.joda.time.format.DateTimeFormat
import org.joda.time.format.DateTimeFormatter
abstract class AbstractJodaTimeJsonAdapter<T>(
formats: Array<String>
) : AbstractCalendarJsonAdapter<T, DateTimeFormatter>(formats) {
override fun createFormatter(pattern: String): DateTimeFormatter = DateTimeFormat.forPattern(pattern)
}

View File

@ -0,0 +1,14 @@
import android.graphics.Color
import com.squareup.moshi.FromJson
import com.squareup.moshi.ToJson
class ColorAdapter {
@ToJson
fun toJson(@HexColor color: Int): String = "#${Integer.toHexString(color)}"
@FromJson
@HexColor
fun fromJson(color: String): Int = Color.parseColor(color)
}

View File

@ -0,0 +1,22 @@
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import java.lang.reflect.Type
class DateFactory : JsonAdapter.Factory {
override fun create(type: Type, annotations: Set<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
val typeName: String = when(type) {
is Class<*> -> type.canonicalName ?: type.toString()
else -> type.toString()
}
return getCalendarAdapter(typeName, getPatterns(annotations))
}
private fun getPatterns(annotations: Set<out Annotation>) = annotations
.mapNotNull { it as? Format }
.firstOrNull()
?.patterns
?: throw IllegalArgumentException("You should use Format annotation for DateTime and LocalDate fields")
}

View File

@ -0,0 +1,16 @@
import org.joda.time.DateTime
import org.joda.time.format.DateTimeFormatter
class DateTimeJodaTimeJsonAdapter(
formats: Array<String>
) : AbstractJodaTimeJsonAdapter<DateTime>(formats) {
override fun fromJsonInner(value: String, dateTimeFormatter: DateTimeFormatter): DateTime {
return DateTime.parse(value, dateTimeFormatter)
}
override fun toJsonInner(value: DateTime?, dateTimeFormatter: DateTimeFormatter): String? {
return value?.toString(dateTimeFormatter)
}
}

View File

@ -0,0 +1,5 @@
import com.squareup.moshi.JsonQualifier
@JsonQualifier
@Target(AnnotationTarget.FIELD)
annotation class Format(val patterns: Array<String>)

View File

@ -0,0 +1,5 @@
import com.squareup.moshi.JsonQualifier
@JsonQualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class HexColor

View File

@ -0,0 +1,12 @@
import java.time.LocalDate
import java.time.format.DateTimeFormatter
class LocalDateJavaTimeJsonAdapter(
formats: Array<String>
) : AbstractJavaTimeJsonAdapter<LocalDate>(formats) {
override fun fromJsonInner(value: String, dateTimeFormatter: DateTimeFormatter): LocalDate {
return LocalDate.parse(value, dateTimeFormatter)
}
}

View File

@ -0,0 +1,16 @@
import org.joda.time.LocalDate
import org.joda.time.format.DateTimeFormatter
class LocalDateJodaTimeJsonAdapter(
formats: Array<String>
) : AbstractJodaTimeJsonAdapter<LocalDate>(formats) {
override fun fromJsonInner(value: String, dateTimeFormatter: DateTimeFormatter): LocalDate {
return LocalDate.parse(value, dateTimeFormatter)
}
override fun toJsonInner(value: LocalDate?, dateTimeFormatter: DateTimeFormatter): String? {
return value?.toString(dateTimeFormatter)
}
}

View File

@ -0,0 +1,13 @@
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
class ZonedDateTimeJavaTimeJsonAdapter(
formats: Array<String>
) : AbstractJavaTimeJsonAdapter<ZonedDateTime>(formats) {
override fun fromJsonInner(value: String, dateTimeFormatter: DateTimeFormatter): ZonedDateTime {
return ZonedDateTime.parse(value, dateTimeFormatter)
}
}

View File

@ -0,0 +1,22 @@
/*
* This code is autogenerated by Touch Instinct tools
*/
@file:Suppress("UnusedImports")
package {{ packageName }}.api
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.annotation.JsonFormat
import java.math.BigDecimal
import java.time.LocalDate
import java.time.ZonedDateTime
{% if (description is not empty) -%}
/**
* {{ description }}
*/
{% endif -%}
open class {% include 'blocks/class/classtype.twig' with { type: type } %} (
{%- include 'blocks/class/constructor-fields-info.twig' with { fields: allFieldsOrdered, superclassesFields: superclassesFields } %}
){% include 'blocks/class/supertype.twig' with { type: type, parent: parent } %} {%- include 'blocks/class/fields-super-initialization.twig' with { fields: superclassesFields } %}

18
KotlinServer/Enum.kt.twig Normal file
View File

@ -0,0 +1,18 @@
{%- import 'utils.twig' as utils -%}
/*
* This code is autogenerated by Touch Instinct tools
*/
package {{ packageName }}.api
import com.fasterxml.jackson.annotation.JsonValue
/**
* {{ description }}
*/
enum class {{ name }}(val code: {{ utils.formatEnumValueType(valuesTypes) }}, val description: String) {
{% include 'blocks/enum/cases.twig' with { valuesTypes: valuesTypes, values: values } %}
@JsonValue
fun toValue() = code
}

View File

@ -0,0 +1 @@
{{- type.baseTypeName -}}{%- include 'type-parameters.twig' with { typeParameters: type.typeParameters } -%}

View File

@ -0,0 +1,16 @@
{%- import '../../utils.twig' as utils -%}
{%- for field in fields %}
{%- if field.type.type.baseTypeName == "DateTime" %}
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "{{ utils.getDateFormat(field) }}", timezone = "utc")
{%- endif %}
{%- if field.type.type.baseTypeName == "Date" %}
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "{{ utils.getDateFormat(field) }}")
{%- endif %}
{%- if field.optional %}
@JsonInclude(JsonInclude.Include.NON_NULL)
{%- elseif field.nullable %}
@JsonInclude(JsonInclude.Include.ALWAYS)
{%- endif %}
{% if not (field in superclassesFields) %}val {% endif %}{{ field.name }}: {{ utils.formatValueType(field.type.type, field.nullable, field.optional) }}{{ utils.writeNullCheckMark(field.nullable, field.optional) }} {%- if not (loop.last) %},{% endif %}{{ utils.addDescription(field) }}
{%- endfor -%}

View File

@ -0,0 +1,7 @@
{%- if fields is not empty -%}
(
{%- for field in fields -%}
{{ field.name }} {%- if not (loop.last) %}, {% endif %}
{%- endfor -%}
)
{%- endif -%}

View File

@ -0,0 +1,3 @@
{%- import '../../utils.twig' as utils -%}
{{- utils.parentClassType(parent) -}}{%- include 'type-parameters.twig' with { typeParameters: type.parentTypeParameters } -%}

View File

@ -0,0 +1,8 @@
{%- import '../../utils.twig' as utils -%}
{%- if typeParameters is not empty -%}
<
{%- for typeParameter in typeParameters %}
{{- utils.formatValueType(typeParameter, true, true) -}}{%- if not (loop.last) %}, {% endif %}
{%- endfor -%}
>
{%- endif -%}

View File

@ -0,0 +1,4 @@
{%- import '../../utils.twig' as utils -%}
{%- for value in values %}
{{ value.nameUpperCaseWithUnderscope }}({{ utils.formatEnumValue(valuesTypes, value) }}, "{{ value.description }}"){%- if not (loop.last) %},{% else %};{% endif %}
{%- endfor -%}

44
KotlinServer/utils.twig Normal file
View File

@ -0,0 +1,44 @@
{% macro parentClassType(parent) %}
{%- if parent is not null %} : {{ parent.type.baseTypeName }}{%- endif -%}
{% endmacro %}
{% macro writeNullCheckMark(nullable, optional) %}
{%- if nullable or optional -%}
?
{%- endif -%}
{% endmacro %}
{% macro formatValueType(valueType, nullable, optional) %}
{% import _self as self %}
{%- if valueType.baseTypeName == "Bool" -%}
Boolean
{%- elseif valueType.baseTypeName == "DateTime" -%}
ZonedDateTime
{%- elseif valueType.baseTypeName == "Date" -%}
LocalDate
{%- elseif valueType.baseTypeName == "Decimal" -%}
BigDecimal
{%- elseif valueType.baseTypeName == "Map" -%}
Map<{{ self.formatValueType(valueType.keysType, true, true) }}, {{ self.formatValueType(valueType.valuesType, true, true) }}>
{%- elseif valueType.baseTypeName == "Array" -%}
List<{{ self.formatValueType(valueType.itemsType, true, true) }}>
{%- else -%}
{% include 'blocks/class/classtype.twig' with { type: valueType } %}
{%- endif -%}
{% endmacro %}
{% macro formatEnumValueType(valuesTypes) %}
{%- if valuesTypes == "STRING" -%}String{%- elseif valuesTypes == "INT" -%}Int{%- endif -%}
{% endmacro %}
{% macro formatEnumValue(valuesTypes, value) %}
{%- if valuesTypes == "STRING" -%}"{{ value.value }}"{%- elseif valuesTypes == "INT" -%}{{ value.value }}{%- endif -%}
{% endmacro %}
{% macro addDescription(field) %}
{%- if (field.description is not empty) %} // {{ field.description }}{%- endif -%}
{% endmacro %}
{%- macro getDateFormat(field) -%}
{{ field.type.dateFormat|replace({'Z':'X'}) }}
{%- endmacro -%}

View File

@ -6,28 +6,28 @@
import LeadKit
import SwiftDate
enum ApiDateFormat: String, DateFormat {
public enum ApiDateFormat: String, DateFormat {
{% for format in dateFormats -%}
case {{ format.name }} = "{{ format.format }}"
{% endfor %}
var dateToStringFormat: DateToStringStyles {
public var dateToStringFormat: DateToStringStyles {
return .custom(rawValue)
}
var stringToDateFormat: StringToDateStyles {
public var stringToDateFormat: StringToDateStyles {
return .custom(rawValue)
}
}
final class ApiDateFormattingService: DateFormattingService, Singleton {
public final class ApiDateFormattingService: DateFormattingService, Singleton {
typealias DateFormatType = ApiDateFormat
public typealias DateFormatType = ApiDateFormat
var currentRegion: Region = .local
public static let shared = ApiDateFormattingService()
static let shared = ApiDateFormattingService()
public var currentRegion: Region = .local
private init() {}

View File

@ -0,0 +1,45 @@
{%- import 'macroses/common.utils.twig' as utils -%}
import LeadKit
import Foundation
public enum ApiNumberFormat: NumberFormat {
case decimal
public var numberFormatter: NumberFormatter {
let numberFormatter = NumberFormatter()
numberFormatter.decimalSeparator = "."
numberFormatter.minimumIntegerDigits = 1
numberFormatter.maximumFractionDigits = 16
return numberFormatter
}
}
public final class ApiNumberFormattingService: NumberFormattingService, Singleton {
public typealias NumberFormatType = ApiNumberFormat
public static let shared = ApiNumberFormattingService()
public let formatters = computedFormatters
private init() {}
public func decimalNumber(from string: String, format: ApiNumberFormat) -> NSDecimalNumber? {
guard let number = number(from: string, format: format) else {
return nil
}
return NSDecimalNumber(decimal: number.decimalValue)
}
}
extension ApiNumberFormattingService {
public static func decimalNumber(from string: String, format: ApiNumberFormat) -> NSDecimalNumber? {
return shared.decimalNumber(from: string, format: format)
}
}
{{ "\n" }}

View File

@ -7,20 +7,19 @@
{%- set hasGenerics = utils.valueTypeHasGenerics(type) != null %}
{%- for field in allFieldsOrdered -%}
{%- set fieldsHasGenericsOrNonEqutableCollections = default(fieldsHasGenericsOrNonEqutableCollections, false) or (utils.hasGenericsOrNonEqutableCollections(field.type) != null) -%}
{%- set classAndFieldsHaveNotGenericsOrNonEqutableCollections = (not hasGenerics) and (not fieldsHasGenericsOrNonEqutableCollections) -%}
{%- endfor -%}
import SwiftDate
import LeadKit
/// {{ description }}
{% if (not hasChilds) -%}final {% endif %}class {{ classType }}: {{ parentClassType }} {
public {% if (not hasChilds) -%}final {% endif %}class {{ classType }}: {{ parentClassType }} {
{% include 'blocks/class/coding-keys.twig' with { fields: fields } %}
{% include 'blocks/class/fields.twig' with { fields: fields } %}
// MARK: - Initializers
{% if (hasParent and (fields is empty)) %} override {% endif %}init({%- include 'blocks/class/init-parameters-fields.twig' with { fields: allFieldsOrdered } -%}) {
public {% if (hasParent and (fields is empty)) %} override {% endif %}init({%- include 'blocks/class/init-parameters-fields.twig' with { fields: allFieldsOrdered } -%}) {
{%- include 'blocks/class/fields-initialization.twig' with { fields: fields } -%}
{% if hasParent %}
super.init({%- include 'blocks/class/fields-super-initialization.twig' with { fields: superclassesFields } -%})
@ -28,7 +27,7 @@ import LeadKit
}
{% if hasParent or fields is not empty %}
required init(from decoder: Decoder) throws {
public required init(from decoder: Decoder) throws {
{%- if fields is not empty %}
{% include 'blocks/class/fields-initialization-from-decoder.twig' with { fields: fields} %}
{%- endif -%}
@ -38,7 +37,7 @@ import LeadKit
}
{% endif %}
{% if hasParent -%}override {% endif %}func encode(to encoder: Encoder) throws {
public {% if hasParent -%}override {% endif %}func encode(to encoder: Encoder) throws {
{%- if fields is not empty %}
{% include 'blocks/class/fields-encode-to-encoder.twig' with { fields: fields} %}
{%- endif -%}
@ -47,8 +46,8 @@ import LeadKit
{%- endif %}
}
{% if (not hasGenerics) and (not fieldsHasGenericsOrNonEqutableCollections) -%}
func isEqual(to other: {{ classType }}?) -> Bool {
{% if classAndFieldsHaveNotGenericsOrNonEqutableCollections -%}
public func isEqual(to other: {{ classType }}?) -> Bool {
{% if (fields is empty) and (not hasParent) %}
return false
{% else %}
@ -56,33 +55,28 @@ import LeadKit
return false
}
return{%- if hasParent %} super.isEqual(to: other){%- endif %}{%- if (fields is not empty) and hasParent %} &&{% endif %} {% include 'blocks/class/fields-equal.twig' with { fields: fields } %}
{% endif %}
}{{ "\n" }}
return{%- if hasParent %} super.isEqual(to: other){%- endif %}{%- if (fields is not empty) and hasParent %} &&{% endif %} {% include 'blocks/class/fields-equal.twig' with { fields: fields } %} {% endif %}
}
{%- endif %}
}
{{ "\n" }}
{%- if (not hasChilds) and (not hasGenerics) and (not fieldsHasGenericsOrNonEqutableCollections) -%}
{%- if (not hasChilds) and classAndFieldsHaveNotGenericsOrNonEqutableCollections -%}
extension {{ type.baseTypeName }}: Equatable {
static func ==(lhs: {{ classType }}, rhs: {{ classType }}) -> Bool {
public static func ==(lhs: {{ classType }}, rhs: {{ classType }}) -> Bool {
return lhs.isEqual(to: rhs)
}
}
{{ "\n" }}
{%- endif -%}
{%- if not hasGenerics -%}
{%- if classAndFieldsHaveNotGenericsOrNonEqutableCollections -%}
extension {{ type.baseTypeName }} {
static let new{{ type.baseTypeName }} = {{ type.baseTypeName }}({%- include 'blocks/class/fields-initialization-default-values.twig' with { fields: allFieldsOrdered } -%})
func copy{%- if hasChilds -%}{{ type.baseTypeName }}{%- endif -%}With({%- include 'blocks/class/nullable-parameters-fields.twig' with { fields: allFieldsOrdered } -%}) -> {{ type.baseTypeName }} {
return {{ type.baseTypeName }}({%- include 'blocks/class/fields-optional-initialization.twig' with { fields: allFieldsOrdered } -%})
}
public static let new{{ type.baseTypeName }} = {{ type.baseTypeName }}({%- include 'blocks/class/fields-initialization-default-values.twig' with { fields: allFieldsOrdered } -%})
{% include 'blocks/class/copy-declaration.twig' with { hasChilds: hasChilds, type: type, fields: allFieldsOrdered } %}
}
{{ "\n" }}
{%- endif -%}

View File

@ -1,17 +1,12 @@
{%- import 'macroses/common.utils.twig' as utils -%}
{%- import 'macroses/enum.utils.twig' as enumutils -%}
import Foundation
/// {{ description }}
///
{% for value in values -%}
/// - {{ utils.decapitalize(value.name) }}: {{ value.description }}
{% endfor -%}
enum {{ name }}: {{ enumutils.enumType(valuesTypes) }}, Codable, RawRepresentable {
{% include 'blocks/enum/all-items.twig' %}
public enum {{ name }}: {{ enumutils.enumType(valuesTypes) }}, Codable, RawRepresentable, CaseIterable {
{% include 'blocks/enum/cases.twig' with { values: values } %}
}
{{ "\n" }}
{{ "\n" }}

View File

@ -8,7 +8,6 @@ extension {{ serviceName }} {
{% for method in methods %}
{%- include 'blocks/method/method-func.twig' with { method: method, isStatic: false } %}
{% endfor %}
}
@ -16,7 +15,5 @@ extension Singleton where Self: {{ serviceName }} {
{% for method in methods %}
{%- include 'blocks/method/method-func.twig' with { method: method, isStatic: true } %}
{% endfor %}
}
{{ "\n" }}

View File

@ -3,29 +3,48 @@ import RxSwift
import Alamofire
{% set serviceName = concat(networkServiceName, "NetworkService") -%}
class {{ serviceName }}: NetworkService {
{% set protocolName = concat(networkServiceName, "NetworkProtocol") -%}
static let apiBaseUrl = "{{ apiUrl }}"
public protocol {{ protocolName }} {
convenience init() {
func apiRequest<T: Decodable>(with parametersSingle: Single<ApiRequestParameters>, additionalValidStatusCodes: Set<Int>, decoder: JSONDecoder) -> Single<T>
func deferredApiRequestParameters(relativeUrl: String,
method: HTTPMethod,
parameters: Parameters?,
requestEncoding: ParameterEncoding?,
requestHeaders: HTTPHeaders?) -> Single<ApiRequestParameters>
{% for method in methods %}
{%- include 'blocks/method/method-declaration.twig' with { method: method, isStatic: false } -%}
{% endfor %}
}
open class {{ serviceName }}: NetworkService, {{ protocolName }} {
public static let apiBaseUrl = "{{ apiUrl }}"
public convenience init() {
self.init(configuration: NetworkServiceConfiguration(baseUrl: {{ serviceName }}.apiBaseUrl))
}
func apiRequest<T: Decodable>(with parameters: ApiRequestParameters, decoder: JSONDecoder = JSONDecoder()) -> Single<T> {
return rxRequest(with: parameters, decoder: decoder).map { $0.model }.asSingle()
open func apiRequest<T: Decodable>(with parametersSingle: Single<ApiRequestParameters>, additionalValidStatusCodes: Set<Int> = [], decoder: JSONDecoder = JSONDecoder()) -> Single<T> {
return parametersSingle.flatMap {
self.rxRequest(with: $0, additionalValidStatusCodes: additionalValidStatusCodes, decoder: decoder).map { $0.model }.asSingle()
}
}
func apiRequestParameters(relativeUrl: String,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
requestEncoding: ParameterEncoding? = nil,
requestHeaders: HTTPHeaders? = nil) -> ApiRequestParameters {
return configuration.apiRequestParameters(relativeUrl: relativeUrl,
method: method,
parameters: parameters,
requestEncoding: requestEncoding,
requestHeaders: requestHeaders)
open func deferredApiRequestParameters(relativeUrl: String,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
requestEncoding: ParameterEncoding? = nil,
requestHeaders: HTTPHeaders? = nil) -> Single<ApiRequestParameters> {
return .deferredJust {
self.configuration.apiRequestParameters(relativeUrl: relativeUrl,
method: method,
parameters: parameters,
requestEncoding: requestEncoding,
requestHeaders: requestHeaders)
}
}
}
{{ "\n" }}

View File

@ -0,0 +1,13 @@
{%- import '../../macroses/common.utils.twig' as utils -%}
{%- if fields is not empty -%}
{%- set nullableOptionalFields = [] -%}
{%- for field in fields -%}
{%- if field.nullable or field.optional -%}
{%- set nullableOptionalFields = nullableOptionalFields|merge([field]) -%}
{%- endif -%}
{%- endfor -%}
{%- for field in nullableOptionalFields -%}
{{ field.name }}: Bool = false{%- if not (loop.last) %}, {% endif %}
{%- endfor -%}
{%- endif -%}

View File

@ -0,0 +1,20 @@
{%- import '../../macroses/common.utils.twig' as utils -%}
public func copy{%- if hasChilds -%}{{ type.baseTypeName }}{%- endif -%}With({%- include '../class/nullable-parameters-fields.twig' with { fields: allFieldsOrdered } -%}) -> {{ type.baseTypeName }} {
return {{ type.baseTypeName }}({% include '../class/fields-optional-initialization.twig' with { fields: allFieldsOrdered } %})
}
{%- if allFieldsOrdered is not empty -%}
{%- for field in allFieldsOrdered -%}
{%- if field.nullable or field.optional -%}
{%- set containsOptionalFields = true -%}
{%- endif -%}
{%- endfor -%}
{%- endif -%}
{% if containsOptionalFields %}
public func copy{%- if hasChilds -%}{{ type.baseTypeName }}{%- endif -%}Without({%- include '../class/bool-parameters-fields.twig' with { fields: allFieldsOrdered } -%}) -> {{ type.baseTypeName }} {
return {{ type.baseTypeName }}({%- include '../class/fields-without-initialization.twig' with { fields: allFieldsOrdered } -%})
}
{% endif %}

View File

@ -0,0 +1,11 @@
{%- import '../../macroses/common.utils.twig' as utils -%}
{%- if fields is not empty -%}
{%- for field in fields -%}
{%- if field.nullable or field.optional -%}
{{ field.name }}: {{ field.name }} ? nil : self.{{ field.name }}{%- if not (loop.last) %}, {% endif %}
{%- else -%}
{{ field.name }}: self.{{ field.name }}{%- if not (loop.last) %}, {% endif %}
{%- endif -%}
{%- endfor -%}
{%- endif -%}

View File

@ -4,6 +4,6 @@
// MARK: - Fields
{% for field in fields %}
/// {{ field.description }}
let {{ field.name }}: {{ utils.formatNullableOrOptional(utils.formatValueType(field.type.type), field.nullable, field.optional) }}
public let {{ field.name }}: {{ utils.formatNullableOrOptional(utils.formatValueType(field.type.type), field.nullable, field.optional) }}
{% endfor -%}
{% endif %}

View File

@ -1,8 +0,0 @@
{% import '../../macroses/common.utils.twig' as utils -%}
static var allItems: [{{ name }}] {
{{ " " }}return [
{%- for value in values -%}
.{{ utils.decapitalize(value.name) }}{%- if not (loop.last) -%}, {% endif -%}
{%- endfor -%}
]
{{ " " }}}

View File

@ -0,0 +1,12 @@
{%- import '../../macroses/common.utils.twig' as utils -%}
{%- if (method.bodyType is not null) -%}
{%- set bodyParamName = utils.decapitalize(method.bodyType.type.typeName) -%}
{%- set bodyTypeName = method.bodyType.type.typeName -%}
{%- set hasBody = true -%}
{%- endif -%}
{%- set funcName = utils.decapitalize(method.name) -%}
{{ isStatic ? "static " : "" }}func {{ funcName }}({%- if hasBody -%}{{ bodyParamName }}: {{ bodyTypeName }},{{ " " }}{%- endif -%}requestEncoding: ParameterEncoding?, requestHeaders: HTTPHeaders?, additionalValidStatusCodes: Set<Int>) -> Single<{{ utils.formatValueType(method.apiResponseType) }}>

View File

@ -11,21 +11,24 @@
{%- set funcName = utils.decapitalize(method.name) -%}
/// {{ method.description }}
{{ isStatic ? "static " : "" }}func {{ funcName }}({%- if hasBody -%}{{ bodyParamName }}: {{ bodyTypeName }},{{ "\n " }}{%- endif -%}
public {{ isStatic ? "static " : "" }}func {{ funcName }}({%- if hasBody -%}{{ bodyParamName }}: {{ bodyTypeName }},{{ "\n " }}{%- endif -%}
requestEncoding: ParameterEncoding? = nil,
requestHeaders: HTTPHeaders? = nil) -> Single<{{ method.responseType.type.typeName }}> {
requestHeaders: HTTPHeaders? = nil,
additionalValidStatusCodes: Set<Int> = []) -> Single<{{ utils.formatValueType(method.apiResponseType) }}> {
{% if isStatic -%}
return shared.{{ funcName }}({%- if hasBody -%}{{ bodyParamName }}: {{ bodyParamName }},{{ "\n " }}{%- endif -%}
requestEncoding: requestEncoding,
requestHeaders: requestHeaders)
requestHeaders: requestHeaders,
additionalValidStatusCodes: additionalValidStatusCodes)
{%- else -%}
let parameters = apiRequestParameters(relativeUrl: "{{ method.url }}",
let parameters = deferredApiRequestParameters(relativeUrl: "{{ method.url }}",
method: .{{ methodType }},
parameters: {% if hasBody -%}{{ bodyParamName }}.toJSON(){%- else -%}nil{%- endif -%},
requestEncoding: requestEncoding,
requestHeaders: requestHeaders)
return apiRequest(with: parameters)
return apiRequest(with: parameters, additionalValidStatusCodes: additionalValidStatusCodes, decoder: JSONDecoder())
{%- endif %}
}

View File

@ -12,40 +12,79 @@
{% macro formatValueType(valueType) %}
{%- import _self as self -%}
{%- set baseTypeName = valueType.baseTypeName -%}
{%- if valueType.baseTypeName == "Array" -%}
{%- if baseTypeName == "Array" -%}
[{{ self.formatValueType(valueType.itemsType) }}]
{%- elseif valueType.baseTypeName == "Map" -%}
{%- elseif baseTypeName == "Map" -%}
[{{ self.formatValueType(valueType.keysType) }}: {{ self.formatValueType(valueType.valuesType) }}]
{%- elseif valueType.baseTypeName == "DateTime" -%}
{%- elseif baseTypeName == "Date" or baseTypeName == "DateTime" or baseTypeName == "DateTimeTimestamp" -%}
DateInRegion
{%- elseif valueType.baseTypeName == "Long" -%}
{%- elseif baseTypeName == "Long" -%}
Int64
{%- elseif valueType.baseTypeName == "Decimal" -%}
{%- elseif baseTypeName == "Decimal" or baseTypeName == "StringDecimal" -%}
NSDecimalNumber
{%- elseif baseTypeName == "Url" -%}
URL
{%- elseif baseTypeName == "Color" -%}
UIColor
{%- else -%}
{{ valueType.baseTypeName }}
{{ baseTypeName }}
{%- endif -%}
{% endmacro %}
{% macro formatEncodingValue(field) %}
{% macro formatEncodingValue(field, isStrongLinkCaptured) %}
{%- import _self as self -%}
{%- set baseTypeName = field.type.type.baseTypeName -%}
{%- if field.type.type.baseTypeName == "DateTime" -%}
ApiDateFormattingService.string(from: {{ self.formatNullableOrOptional(field.name, field.nullable, field.optional) -}}, format: .{{ dateFormatToName(field.type.dateFormat) }})
{%- elseif field.type.type.baseTypeName == "Decimal" -%}
{{ self.formatNullableOrOptional(field.name, field.nullable, field.optional) -}}
.decimalValue
{%- if baseTypeName == "Date" or baseTypeName == "DateTime" -%}
{{- self.formatEncodingDate(field) -}}
{%- elseif baseTypeName == "StringDecimal" -%}
{{- self.formatEncodingStringDecimal(field) -}}
{%- elseif baseTypeName == "Decimal" -%}
{{ self.formatFieldName(field, isStrongLinkCaptured) -}}.decimalValue
{%- elseif baseTypeName == "DateTimeTimestamp" -%}
Int({{ self.formatFieldName(field, isStrongLinkCaptured) -}}.timeIntervalSince1970)
{%- elseif baseTypeName == "Color" -%}
{{ self.formatFieldName(field, isStrongLinkCaptured) -}}.hexString
{%- elseif baseTypeName == "Url" -%}
{{ self.formatFieldName(field, isStrongLinkCaptured) -}}.absoluteString
{%- else -%}
{{ field.name }}
{%- endif -%}
{% endmacro %}
{% macro escapeIfNeeded(expr) %}
{%- if expr == "default" -%}
`{{ expr }}`
{% macro formatFieldName(field, isStrongLinkCaptured) %}
{%- import _self as self -%}
{%- if isStrongLinkCaptured -%}
{{ field.name }}
{%- else -%}
{{ expr }}
{{ self.formatNullableOrOptional(field.name, field.nullable, field.optional) -}}
{%- endif -%}
{% endmacro %}
{%- macro formatEncodingDate(field) -%}
{%- if field.type.dateFormats is not empty -%}
ApiDateFormattingService.string(from: {{ field.name -}}, format: .{{- dateFormatToName(field.type.dateFormats[0]) -}})
{%- else -%}
ApiDateFormattingService.string(from: {{ field.name -}}, format: .{{- dateFormatToName(field.type.dateFormat) -}})
{%- endif -%}
{%- endmacro -%}
{%- macro formatEncodingStringDecimal(field) -%}
ApiNumberFormattingService.string(from: {{ field.name -}}, format: .decimal)
{%- endmacro -%}
{% macro encodeIfPresent(field) %}
{%- import _self as self -%}
{%- set baseTypeName = field.type.type.baseTypeName -%}
{% if baseTypeName == "Date" or baseTypeName == "DateTime" or baseTypeName == "DateTimeTimestamp" or baseTypeName == "StringDecimal" %}
if let {{ field.name }} = {{ field.name }} {
try container.encode({{- self.formatEncodingValue(field, true) -}}, forKey: .{{- field.name -}})
}
{%- else -%}
try container.encodeIfPresent({{- self.formatEncodingValue(field, false) -}}, forKey: .{{- field.name -}})
{%- endif -%}
{% endmacro %}
@ -53,45 +92,33 @@
{%- import _self as self -%}
{%- if field.optional -%}
try container.encodeIfPresent({{ self.formatEncodingValue(field) }}, forKey: .{{ field.name }})
{{ self.encodeIfPresent(field) -}}
{%- elseif field.nullable -%}
if let value = {{ self.formatEncodingValue(field) }} {
try container.encode(value, forKey: .{{ field.name }})
if let {{ field.name }} = {{ field.name }} {
try container.encode({{- self.formatEncodingValue(field, true) -}}, forKey: .{{- field.name -}})
} else {
try container.encodeNil(forKey: .{{ field.name }})
try container.encodeNil(forKey: .{{- field.name -}})
}
{%- else -%}
try container.encode({{ self.formatEncodingValue(field) }}, forKey: .{{ field.name }})
try container.encode({{- self.formatEncodingValue(field, false) -}}, forKey: .{{- field.name -}})
{%- endif -%}
{% endmacro %}
{% macro decodeFromContainer(field) %}
{%- import _self as self -%}
{% if field.type.type.baseTypeName == "DateTime" %}
{{ self.decodeComplexField(field, "String") }}
{% elseif field.type.type.baseTypeName == "Decimal" %}
{{ self.decodeComplexField(field, "Decimal") }}
{%- import 'complexField.utils.twig' as complexFieldUtils -%}
{%- set baseTypeName = field.type.type.baseTypeName -%}
{%- if baseTypeName == "Color" or baseTypeName == "Date" or baseTypeName == "DateTime" or baseTypeName == "StringDecimal" or baseTypeName == "Url" -%}
{{ complexFieldUtils.decodeComplexField(field, "String") -}}
{%- elseif baseTypeName == "DateTimeTimestamp" -%}
{{ complexFieldUtils.decodeComplexField(field, "Int") -}}
{%- elseif baseTypeName == "Decimal" -%}
{{ complexFieldUtils.decodeComplexField(field, "Decimal") -}}
{%- else -%}
self.{{ field.name }} = try container.{{- self.formatOptionalDecode(field) -}}({{ self.formatValueType(field.type.type) }}.self, forKey: .{{ field.name }})
{%- endif -%}
{% endmacro %}
{% macro decodeComplexField(field, decodingType) %}
{%- import _self as self -%}
{%- if field.optional or field.nullable -%}
if let {{ field.name }} = try container.decodeIfPresent({{ decodingType }}.self, forKey: .{{ field.name }}) {
{{ self.initExpr(field) }}
} else {
self.{{ field.name }} = nil
}
{%- else -%}
let {{ field.name }} = try container.decode({{ decodingType }}.self, forKey: .{{ field.name }})
{{ self.initExpr(field) }}
{%- endif -%}
{% endmacro %}
{% macro formatOptionalDecode(field) %}
{%- if field.optional or field.nullable -%}
decodeIfPresent
@ -100,24 +127,20 @@
{%- endif -%}
{% endmacro %}
{% macro initExpr(field) %}
{%- if field.type.type.baseTypeName == "DateTime" -%}
if let date = ApiDateFormattingService.date(from: {{ field.name }}, format: .{{ dateFormatToName(field.type.dateFormat) }}, parsedIn: nil) {
self.{{ field.name }} = date
} else {
throw LeadKitError.failedToDecode(reason: "init?(string:format:fromRegion:) returned nil")
}
{%- elseif field.type.type.baseTypeName == "Decimal" -%}
self.{{ field.name }} = NSDecimalNumber(decimal: {{ field.name }})
{%- endif -%}
{% endmacro %}
{% macro enumValueName(value) %}
{%- import _self as self -%}
{{- self.decapitalize(value.name) -}}
{%- endmacro %}
{% macro escapeIfNeeded(expr) %}
{%- if expr == "default" or expr == "operator" -%}
`{{ expr }}`
{%- else -%}
{{ expr }}
{%- endif -%}
{% endmacro %}
{% macro defaultValueForField(field) %}
{%- set nullable = field.nullable -%}
{%- set optional = field.optional -%}
@ -131,7 +154,7 @@
[:]
{%- elseif baseTypeName == "String" -%}
""
{%- elseif baseTypeName == "DateTime" -%}
{%- elseif baseTypeName == "Date" or baseTypeName == "DateTime" or baseTypeName == "DateTimeTimestamp" -%}
Date().inDefaultRegion()
{%- elseif baseTypeName == "Double" -%}
0.0
@ -139,8 +162,12 @@
0
{%- elseif baseTypeName == "Bool" -%}
false
{%- elseif baseTypeName == "Decimal" -%}
{%- elseif baseTypeName == "Decimal" or baseTypeName == "StringDecimal" -%}
.zero
{%- elseif baseTypeName == "Color" -%}
.clear
{%- elseif baseTypeName == "Url" -%}
URL(string: "https://example.com")!
{%- elseif (field.type.values is not null) -%}
{%- import _self as self -%}

View File

@ -0,0 +1,58 @@
{% macro decodeComplexField(field, decodingType) %}
{%- import _self as self -%}
{%- if field.optional or field.nullable -%}
if let {{ field.name }} = try container.decodeIfPresent({{- decodingType -}}.self, forKey: .{{- field.name -}}) {
{{ self.initExpr(field) }}
} else {
self.{{ field.name }} = nil
}
{%- else -%}
let {{ field.name }} = try container.decode({{- decodingType -}}.self, forKey: .{{- field.name -}})
{{ self.initExpr(field) }}
{%- endif -%}
{% endmacro %}
{% macro initExpr(field) %}
{%- import _self as self -%}
{%- set baseTypeName = field.type.type.baseTypeName -%}
{%- if baseTypeName == "Date" or baseTypeName == "DateTime" -%}
{{ self.commonDateInit(field) -}}
{%- elseif baseTypeName == "Color" -%}
{%- set colorInit = "UIColor(hexString: %s)"|format(field.name) -%}
{{ self.decodeThrowableField(field, colorInit, 'Unable to decode color from hex string') -}}
{%- elseif baseTypeName == "Url" -%}
{%- set urlInit = "URL(string: %s)"|format(field.name) -%}
{{ self.decodeThrowableField(field, urlInit, 'Unable to decode URL from string') -}}
{%- elseif baseTypeName == "StringDecimal" -%}
{%- set stringDecimalInit = "ApiNumberFormattingService.decimalNumber(from: %s, format: .decimal)"|format(field.name) -%}
{{- self.decodeThrowableField(field, stringDecimalInit, 'Unable to decode decimal from string') -}}
{%- elseif baseTypeName == "DateTimeTimestamp" -%}
self.{{ field.name }} = DateInRegion(seconds: TimeInterval({{ field.name }}))
{%- elseif baseTypeName == "Decimal" -%}
self.{{ field.name }} = NSDecimalNumber(decimal: {{ field.name }})
{%- endif -%}
{% endmacro %}
{%- macro decodeThrowableField(field, init, errorMessage) -%}
if let value = {{ init }} {
self.{{ field.name }} = value
} else {
throw LeadKitError.failedToDecode(reason: "{{ errorMessage }}")
}
{%- endmacro -%}
{%- macro commonDateInit(field) -%}
{%- import _self as self -%}
{%- if field.type.dateFormats is not empty -%}
{%- set formattedDateFormats = [] -%}
{%- for dateFormat in field.type.dateFormats -%}
{%- set formattedDateFormats = formattedDateFormats|merge([".%s"|format(dateFormatToName(dateFormat))]) -%}
{%- endfor -%}
{%- set dateFormatsString = formattedDateFormats|join(', ') -%}
{%- set dateInit = "ApiDateFormattingService.date(from: %s, formats: [%s], parsedIn: nil)"|format(field.name, dateFormatsString) -%}
{{- self.decodeThrowableField(field, dateInit, "Unable to decode date from string") -}}
{%- else -%}
{%- set dateInit = "ApiDateFormattingService.date(from: %s, format: .%s, parsedIn: nil)"|format(field.name, dateFormatToName(field.type.dateFormat)) -%}
{{- self.decodeThrowableField(field, dateInit, "Unable to decode date from string") -}}
{%- endif -%}
{%- endmacro -%}

View File

@ -2,11 +2,13 @@
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<div class="aside__container">
<div class="header">
{%- include 'blocks/menu-header.html.twig' %}
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
</div>
</div>
</div>
@ -23,7 +25,12 @@
{% if author is not empty %}
<h2>{{ author }}</h2>
{% endif %}
<p>Версия {{ version }}</p>
<p>Версия: {{ version }}</p>
{% if buildVersion|length %}
<p>Сборка: {{ buildVersion }}</p>
{% endif %}
<p>{{ "now"|date("dd.MM.YYYY") }}</p>
</div>
<h2 class="main-title">
@ -103,7 +110,7 @@
<div class="page-data section-helper">
<h2 class="subtitle" id="{{ methodGroup.sectionTitle }}">{{ methodGroup.title }}</h2>
{% if methodGroup.description is not null %}
<p>{{ methodGroup.description }}</p>
<p>{{ methodGroup.description | escape }}</p>
{% endif %}
{% if methodGroup.baseUrl is not empty %}
<p>BaseUrl: {{ methodGroup.baseUrl }}</p>

View File

@ -1,7 +1,7 @@
<h2 class="subtitle" id="{{ structure.type.baseTypeName }}">{{ structure.type.baseTypeName }}</h2>
<h3>Описание</h3>
<p class="sub-header">{{ structure.description }}</p>
<p class="sub-header">{{ structure.description | escape }}</p>
<h3>Структура данных</h3>
<div class="table">

View File

@ -0,0 +1 @@
{{- type.baseTypeName -}}{%- include 'type-parameters.twig' with { typeParameters: type.typeParameters } -%}

View File

@ -1,7 +1,7 @@
<h2 class="subtitle" id="{{ structure.name }}">{{ structure.name }}</h2>
<h3>Описание</h3>
<p class="sub-header">{{ structure.description }}</p>
<p class="sub-header">{{ structure.description | escape }}</p>
<h3>Возможные значения</h3>
<div class="table table--small">
@ -13,7 +13,7 @@
{% for value in structure.values %}
<div class="row-body">
<div>{{ value.value }}</div>
<div>{{ value.description }}</div>
<div>{{ value.description | escape }}</div>
</div>
{% endfor %}
</div>

View File

@ -28,9 +28,9 @@
{%- if link is not null -%}
<a class="info" href="{{ link }}">{{- utils.formatNullable(valueType.typeName, nullable) -}}</a>
<a class="info" href="{{ link }}">{{- utils.formatNullableClassType(valueType, nullable) -}}</a>
{%- else -%}
{{- utils.formatNullable(valueType.typeName, nullable) -}}
{{- utils.formatNullableClassType(valueType, nullable) -}}
{%- endif -%}
{%- endif -%}
{%- endmacro -%}
@ -41,8 +41,11 @@
<div class="row-body">
<div>{{ field.jsonName }}</div>
<div>
{{ self.formatValueType(field.type.type, field.nullable, objectsLinks, useAnchors) }}
{{ self.formatValueType(field.type.type, field.nullable, objectsLinks, useAnchors) }}
{%- if field.type.type.typeName in ["DateTime", "Date"] -%}
&nbsp;({{ field.type.allDateFormats|join(', ') }})
{%- endif -%}
</div>
<div>{{ field.description }}</div>
<div>{{ field.description | escape }}</div>
<div>{{ utils.optionalDescription(field.optional) }}</div>
</div>

View File

@ -1,4 +1,4 @@
<menu class="main">
<ul class="navigation">
{%- if mainMenu.indexMenuItem is not null %}
<li {%- if mainMenu.indexMenuItem.active %} class="active" {%- endif -%}><a href="{{ mainMenu.indexMenuItem.path }}">Общие принципы построения API</a></li>
@ -29,7 +29,12 @@
{% endif %}
{%- if mainMenu.allContents is not null %}
<li {%- if mainMenu.allContents.active %} class="active" {%- endif -%}><a href="{{ mainMenu.allContents.path }}">Версия для печати</a></li>
<li {%- if mainMenu.allContents.active %} class="active" {%- endif -%}>
<a href="{{ mainMenu.allContents.path }}">Версия для печати</a>
{% if buildVersion|length %}
<a href="/{{ pageTitle|replace({ " ": "_" }) }}__v{{ version }}.b{{ buildVersion }}.pdf" target="_blank" class="btn">Скачать PDF</a>
{% endif %}
</li>
{% endif %}
</menu>
</ul>

View File

@ -0,0 +1,6 @@
<div class="title">
{{ pageTitle }}&ensp;
<span class="title__hint">{{ "now"|date("dd.MM.YYYY") }}</span><span
class="title__hint">Версия:&nbsp;{{ version }}</span>{% if buildVersion|length %}<span
class="title__hint">Сборка:&nbsp;{{ buildVersion }}</span>{% endif %}
</div>

View File

@ -1,4 +1,4 @@
<h2 class="subtitle" id="{{ method.anchorPath }}">{{ method.description }}</h2>
<h2 class="subtitle" id="{{ method.anchorPath }}">{{ method.description | escape }}</h2>
<h3>Метод</h3>
<p class="sub-header">{{ method.type }} {{ method.url }}</p>
@ -120,7 +120,7 @@
{% else %}
{% for value in method.errorsEnumeration.values -%}
{%- if value.value in method.errorsEnumeration.allowedValues %}
<p class="sub-header">#Код {{ value.value }}{{ value.description }}</p>
<p class="sub-header">#Код {{ value.value }}{{ value.description | escape }}</p>
{%- endif -%}
{%- endfor %}
{% endif %}
@ -130,7 +130,7 @@
<p class="sub-header">Результат отсутствует</p>
{% else %}
{% if method.booleanResponseDescription is not empty %}
<p>{{ method.booleanResponseDescription }}. Тип Boolean.</p>
<p>{{ method.booleanResponseDescription | escape }}. Тип Boolean.</p>
{% elseif method.responseFields is not empty %}
<p>Объект следующей структуры:</p>

View File

@ -1,4 +1,4 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://unpkg.com/split.js/split.min.js"></script>
<script src="{{ jsFolderPath }}/jquery.min.js"></script>
<script src="{{ jsFolderPath }}/split.min.js"></script>
<script type="text/javascript" src="{{ jsFolderPath }}/main.js?v=1.02"></script>
<script type="text/javascript" src="{{ jsFolderPath }}/searchItems.js?v=1.00"></script>

View File

@ -1,8 +1,8 @@
<li {%- if menu.active %} class="active" {%- endif -%}>
<a href="{{ first(menu.items).path }}">{{ menuTitle }}</a>
<menu class="child">
<ul class="child">
{% for item in menu.items %}
<li {%- if item.active %} class="active" {%- endif -%}><a href="{{ item.path }}">{{ item.title }}</a></li>
{% endfor %}
</menu>
</ul>
</li>

View File

@ -0,0 +1,8 @@
{%- import '../utils.twig' as utils -%}
{%- if typeParameters is not empty -%}
&lt;
{%- for typeParameter in typeParameters %}
{{- typeParameter.baseTypeName -}}{%- if not (loop.last) %}, {% endif %}
{%- endfor -%}
&gt;
{%- endif -%}

View File

@ -19,7 +19,7 @@
{
"result": <span class="text-digit">null</span>
"error_code": <span class="text-digit">{{ outOfDateError.value }}</span>,
"error_message": <span class="text-digit">"{{ outOfDateError.description }}"</span>
"error_message": <span class="text-digit">"{{ outOfDateError.description | escape }}"</span>
}
</div>
</div>

View File

@ -25,37 +25,48 @@ body {
display: flex;
}
.gutter {
cursor: col-resize;
background-image: url("../images/vertical-split.png");
background-color: transparent;
background-repeat: no-repeat;
background-position: 50% 200px;
.btn {
padding: 1rem 1.15rem;
border: 0;
background-color: #0ca9e6;
color: white;
font-size: 1.42rem;
line-height: 1;
font-weight: 500;
}
.gutter:hover {
background-color: #333c47;
.gutter {
z-index: 10;
cursor: col-resize;
}
.aside {
display: inline-block;
vertical-align: top;
font-size: 14px;
position: relative;
}
.aside__container {
position: fixed;
overflow-y: auto;
max-height: 100vh;
width: inherit;
min-width: inherit;
}
.header {
height: 7rem;
min-height: 7rem;
font-size: 14px;
}
.content {
min-height: calc(100vh - 7rem);
font-size: 14px;
line-height: 1rem;
}
.aside-left {
min-width: 300px;
min-width: 315px;
}
.aside-left .header {
@ -64,6 +75,10 @@ body {
border-bottom: 1px solid #2b333e;
}
.aside-right .content {
min-height: calc(100vh - 7rem);
}
.logo img {
height: 3.6em;
margin: .7em 0 0 2em;
@ -156,19 +171,30 @@ body {
background-color: #222933;
}
menu li {
.navigation a {
cursor: pointer;
color: inherit;
text-decoration: none;
width: 100%;
}
.aside-left menu.main {
.navigation .btn {
vertical-align: middle;
color: #fff;
width: auto;
}
.aside-left ul.navigation {
list-style: none;
margin: 0;
background: #2b333e;
padding: 0 0 2.2rem;
}
.aside-left menu.main li a {
display: block;
.aside-left ul.navigation li {
display: flex;
align-items: center;
justify-content: space-between;
line-height: 4rem;
vertical-align: middle;
padding-left: 3.57rem;
@ -182,27 +208,31 @@ menu li {
white-space: nowrap;
}
.aside-left menu.main > li a:hover,
.aside-left menu.main > li.active a {
.aside-left ul.navigation > li:hover,
.aside-left ul.navigation > li.active {
background-color: #222933;
padding-left: 3.14rem;
border-left: 0.43rem solid #0ca9e6;
color: white
color: white;
}
.aside-left menu.main > li:first-child + li.active {
.aside-left ul.navigation > li:first-child + li.active {
margin-top: 0;
}
.aside-left menu.secondary {
.aside-left ul.secondary {
list-style: none;
margin: 0;
padding: 3.57rem 0 3.57rem 6.28rem;
padding: 3.57rem 0 3.57rem 3.57rem;
}
.aside-left menu.secondary li a {
.aside-left ul.secondary a {
text-decoration: none;
color: inherit;
}
.aside-left ul.secondary li {
line-height: 2.64rem;
vertical-align: middle;
font-size: 1.42rem;
color: #0ca9e6;
text-decoration: none;
@ -211,37 +241,42 @@ menu li {
text-overflow: ellipsis;
white-space: nowrap;
padding-right: 1.42rem;
display: inline-block;
width: 100%;
}
.aside-left menu.secondary > li:not(.active) > a:hover {
.aside-left ul.secondary > li:not(.active):hover {
opacity: 0.8;
}
.aside-left menu.secondary > li.active > a {
.aside-left ul.secondary > li.active {
color: white
}
.aside-left menu.secondary > li.active menu.child {
.aside-left ul.secondary > li.active ul.child {
display: block;
}
.aside-left menu.child {
.aside-left ul.child {
display: none;
list-style: none;
margin: 6px 0;
padding: 0 3.75rem 0 1.57rem;
padding: 0 0 0 1.5rem;
border-left: 1px solid #fff;
min-width: 205px;
width: auto;
}
.aside-left menu.child > li > a {
color: #7a7f85;
.aside-left ul.child > a {
text-decoration: none;
color: inherit;
}
.aside-left menu.child > li.active > a {
.aside-left ul.child > li {
color: #7a7f85;
padding-right: 0
}
.aside-left ul.child > li.active {
color: #fff;
}
@ -260,12 +295,21 @@ menu li {
.title {
font-size: 2rem;
line-height: 2.4rem;
padding-top: 2.2rem;
padding: 2.2rem 1.42rem 1.42rem 3.57rem;
color: white;
padding-left: 4rem;
font-weight: 700;
}
.title__hint {
font-size: 1.42rem;
font-weight: 400;
color: #7a7f85;
}
.title__hint:not(:first-child) {
margin-left: 10px;
}
.aside-right .content {
padding: 1rem;
}
@ -362,6 +406,11 @@ menu li {
line-height: 2rem;
}
.table .btn {
width: 100%;
margin-top: 1.71rem;
}
.row-header {
display: table-row;
}
@ -575,17 +624,6 @@ menu li {
background-color: #f4f6f9;
}
.btn {
background-color: #0ca9e6;
border: 0;
color: white;
font-size: 1.42rem;
padding: 1.15rem;
width: 100%;
margin-top: 1.71rem;
font-weight: 500;
}
.part-example-response > .text-response {
display: inline-block;
width: calc(100% - 16rem);
@ -603,7 +641,7 @@ span.text-string {
}
a.show-example-response {
color: #0275eb;
color: #0ca9e6;
cursor: pointer;
}
@ -715,6 +753,7 @@ ol {
.main-page {
display: block;
min-width: 0;
background-color: #ffffff;
}

View File

@ -1,42 +1,44 @@
{%- include 'blocks/head.html.twig' with { title: pageTitle, cssFolderPath: cssFolderPath } %}
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
</div>
</div>
<div class="aside aside-right">
{%- include 'blocks/header.html.twig' with {
imagesFolderPath: imagesFolderPath,
methodsPath: methodsPath,
relativeToRootPath: relativeToRootPath
} %}
<div class="content">
<div class="page-data">
<div class="table">
<div class="part-table">
<div class="row-header">
<div>Код ошибки</div>
<div>Текстовое описание ошибки</div>
</div>
{% for errorValue in errorType.values %}
<div class="row-body">
<div>{{ errorValue.value }}</div>
<div>{{ errorValue.description }}</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
{%- include 'blocks/scripts.html.twig' with { jsFolderPath: jsFolderPath } %}
</body>
{%- include 'blocks/head.html.twig' with { title: pageTitle, cssFolderPath: cssFolderPath } %}
<body class="main-page">
<div class="aside aside-left">
<div class="aside__container">
<div class="header">
{%- include 'blocks/menu-header.html.twig' %}
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
</div>
</div>
</div>
<div class="aside aside-right">
{%- include 'blocks/header.html.twig' with {
imagesFolderPath: imagesFolderPath,
methodsPath: methodsPath,
relativeToRootPath: relativeToRootPath
} %}
<div class="content">
<div class="page-data">
<div class="table">
<div class="part-table">
<div class="row-header">
<div>Код ошибки</div>
<div>Текстовое описание ошибки</div>
</div>
{% for errorValue in errorType.values %}
<div class="row-body">
<div>{{ errorValue.value }}</div>
<div>{{ errorValue.description | escape }}</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
{%- include 'blocks/scripts.html.twig' with { jsFolderPath: jsFolderPath } %}
</body>
</html>

View File

@ -2,11 +2,13 @@
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<div class="aside__container">
<div class="header">
{%- include 'blocks/menu-header.html.twig' %}
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
</div>
</div>
</div>

4
Web-documentation/js/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
Web-documentation/js/split.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -2,22 +2,23 @@
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<menu class="secondary">
{% for menu in menus %}
{% include 'blocks/secondary-menu.html.twig' with {
menu: menu,
menuTitle: menu.title,
activeItemTypeName: name
} %}
{% endfor %}
</menu>
<div class="aside__container">
<div class="header">
{%- include 'blocks/menu-header.html.twig' %}
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<ul class="secondary">
{% for menu in menus %}
{% include 'blocks/secondary-menu.html.twig' with {
menu: menu,
menuTitle: menu.title,
activeItemTypeName: name
} %}
{% endfor %}
</ul>
</div>
</div>
</div>

View File

@ -2,18 +2,19 @@
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<menu class="secondary">
<li><a>Android</a></li>
<li class="active"><a>iOS</a></li>
<li><a>Windows Phone</a></li>
</menu>
<div class="aside__container">
<div class="header">
{%- include 'blocks/menu-header.html.twig' %}
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<ul class="secondary">
<li><a>Android</a></li>
<li class="active"><a>iOS</a></li>
<li><a>Windows Phone</a></li>
</ul>
</div>
</div>
</div>

View File

@ -2,24 +2,25 @@
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<menu class="secondary">
{% include 'blocks/secondary-menu.html.twig' with {
menu: enumsMenu,
menuTitle: "Перечисления",
activeItemTypeName: name
} %}
{% include 'blocks/secondary-menu.html.twig' with {
menu: classesMenu,
menuTitle: "Объекты"
} %}
</menu>
<div class="aside__container">
<div class="header">
{%- include 'blocks/menu-header.html.twig' %}
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<ul class="secondary">
{% include 'blocks/secondary-menu.html.twig' with {
menu: enumsMenu,
menuTitle: "Перечисления",
activeItemTypeName: name
} %}
{% include 'blocks/secondary-menu.html.twig' with {
menu: classesMenu,
menuTitle: "Объекты"
} %}
</ul>
</div>
</div>
</div>

View File

@ -2,24 +2,25 @@
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<menu class="secondary">
{% include 'blocks/secondary-menu.html.twig' with {
menu: enumsMenu,
menuTitle: "Перечисления",
activeItemTypeName: name
} %}
{% include 'blocks/secondary-menu.html.twig' with {
menu: classesMenu,
menuTitle: "Объекты"
} %}
</menu>
<div class="aside__container">
<div class="header">
{%- include 'blocks/menu-header.html.twig' %}
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<ul class="secondary">
{% include 'blocks/secondary-menu.html.twig' with {
menu: enumsMenu,
menuTitle: "Перечисления",
activeItemTypeName: name
} %}
{% include 'blocks/secondary-menu.html.twig' with {
menu: classesMenu,
menuTitle: "Объекты"
} %}
</ul>
</div>
</div>
</div>

View File

@ -2,11 +2,13 @@
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<div class="aside__container">
<div class="header">
{%- include 'blocks/menu-header.html.twig' %}
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
</div>
</div>
</div>

View File

@ -2,6 +2,10 @@
{{- expr -}}{%- if nullable -%}?{%- endif -%}
{% endmacro %}
{% macro formatNullableClassType(valueType, nullable) %}
{% include 'blocks/classtype.twig' with { type: valueType } %}{%- if nullable -%}?{%- endif -%}
{% endmacro %}
{% macro optionalDescription(optional) %}
{%- if optional -%}Нет{%- else -%}Да{%- endif -%}
{% endmacro %}

View File

@ -2,11 +2,13 @@
<body class="main-page">
<div class="aside aside-left">
<div class="header">
<div class="title">{{ pageTitle }}</div>
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
<div class="aside__container">
<div class="header">
{%- include 'blocks/menu-header.html.twig' %}
</div>
<div class="content">
{%- include 'blocks/main-menu.html.twig' with { mainMenu: mainMenu } %}
</div>
</div>
</div>