Skip to content

Commit 5470c1c

Browse files
authored
Merge pull request #2023 from appwrite/fix/ts-nullable-model-properties
fix: type nullable TypeScript model properties as T | null
2 parents e6e0811 + 7605737 commit 5470c1c

60 files changed

Lines changed: 113 additions & 11 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎mock-server/app/http.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -866,7 +866,7 @@
866866
->label('scope', 'public')
867867
->inject('response')
868868
->action(function (UtopiaSwooleResponse $response) {
869-
$response->json(['enabled' => false]);
869+
$response->json(['enabled' => false, 'verified' => null]);
870870
});
871871

872872
App::get('/v1/mock/tests/general/presets')

‎src/SDK/Language/Web.php‎

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -907,8 +907,12 @@ protected function expandTypeOption(string $option, int $indent): string
907907
* Render a model property, breaking a parenthesised union array type across
908908
* lines when the declaration overflows the print width.
909909
*/
910-
protected function formatModelProperty(string $label, string $type, int $indent): string
910+
protected function formatModelProperty(string $label, string $type, int $indent, bool $nullable = false): string
911911
{
912+
if ($nullable) {
913+
return $this->formatNullableModelProperty($label, $type, $indent);
914+
}
915+
912916
$pad = str_repeat(' ', $indent);
913917
if (mb_strlen($pad . $label . ': ' . $type . ';') <= self::PRINT_WIDTH) {
914918
return $label . ': ' . $type . ';';
@@ -936,6 +940,34 @@ protected function formatModelProperty(string $label, string $type, int $indent)
936940
. implode("\n" . $inner . '| ', $options) . "\n" . $pad . ')[];';
937941
}
938942

943+
protected function formatNullableModelProperty(string $label, string $type, int $indent): string
944+
{
945+
$pad = str_repeat(' ', $indent);
946+
$union = $type . ' | null';
947+
if (mb_strlen($pad . $label . ': ' . $union . ';') <= self::PRINT_WIDTH) {
948+
return $label . ': ' . $union . ';';
949+
}
950+
951+
$inner = $pad . str_repeat(' ', 4);
952+
if (!str_contains($type, '<') && mb_strlen($inner . $union . ';') <= self::PRINT_WIDTH) {
953+
return $label . ":\n" . $inner . $union . ';';
954+
}
955+
956+
if (preg_match('/^\((.+)\)\[\]$/', $type, $match) === 1) {
957+
if (mb_strlen($inner . '| ' . $type) <= self::PRINT_WIDTH) {
958+
return $label . ":\n" . $inner . '| ' . $type . "\n" . $inner . '| null;';
959+
}
960+
961+
$options = $this->splitTopLevel($match[1], '|', trackGenerics: true);
962+
$member = $inner . str_repeat(' ', 6) . '| ';
963+
964+
return $label . ":\n" . $inner . "| (\n" . $member . implode("\n" . $member, $options)
965+
. "\n" . $inner . ' )[]' . "\n" . $inner . '| null;';
966+
}
967+
968+
return $label . ': ' . $union . ';';
969+
}
970+
939971
/**
940972
* Break a union return type across lines when the closing `): Type` line
941973
* overflows, matching Prettier's leading-pipe layout inside the generic.
@@ -1096,7 +1128,7 @@ public function getFilters(): array
10961128

10971129
return $lhs . ' ' . $this->wrapConditionalType($type, $indent);
10981130
}, ['is_safe' => ['html']]),
1099-
new TwigFilter('tsModelProperty', fn(string $label, string $type, int $indent = 8): string => $this->formatModelProperty($label, $type, $indent), ['is_safe' => ['html']]),
1131+
new TwigFilter('tsModelProperty', fn(string $label, string $type, int $indent = 8, bool $nullable = false): string => $this->formatModelProperty($label, $type, $indent, $nullable), ['is_safe' => ['html']]),
11001132
new TwigFilter('tsArgument', fn(Operation $method, ?Parameter $parameter = null): string => $this->formatArgument($method, $parameter), ['is_safe' => ['html']]),
11011133
new TwigFilter('tsRestTuple', fn(Operation $method, Specification $spec): string => $this->formatRestTuple($method, $spec), ['is_safe' => ['html']]),
11021134
new TwigFilter('tsTypeAlias', fn(string $name, string $generics, string $tail, int $indent = 4): string => $this->formatTypeAlias($name, $generics, $tail, $indent), ['is_safe' => ['html']]),

‎templates/deno/src/models.d.ts.twig‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export namespace Models {
5858
/**
5959
* {{ property.description }}
6060
*/
61-
{{ (property | schemaName) | escapeKeyword }}{% if not (property | schemaRequired) %}?{% endif %}: {{_self.sub_schema(property, definition, definitions)}};
61+
{{ (property | schemaName) | escapeKeyword }}{% if not (property | schemaRequired) %}?{% endif %}: {{_self.sub_schema(property, definition, definitions)}}{% if (property | schemaNullable) %} | null{% endif %};
6262
{% endfor %}
6363
}
6464
{% endfor %}

‎templates/node/src/models/requestModel.ts.twig‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export interface {{ requestModelName | caseUcfirst }} {
2424
/**
2525
* {{ property.description }}
2626
*/
27-
{{ (((property | schemaName) | escapeKeyword) ~ ((property | schemaRequired) ? '' : '?')) | tsModelProperty(((property | getPropertyType(spec)) | replace({'Models.': ''})), 4) | raw }}
27+
{{ (((property | schemaName) | escapeKeyword) ~ ((property | schemaRequired) ? '' : '?')) | tsModelProperty(((property | getPropertyType(spec)) | replace({'Models.': ''})), 4, (property | schemaNullable)) | raw }}
2828
{%~ endfor %}
2929
}
3030

‎templates/react-native/src/models.ts.twig‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export namespace Models {
3939
*{% if (property.description | trimLines) is not empty %} {{ property.description | trimLines | raw }}{% endif %}
4040

4141
*/
42-
{{ ((property | schemaName) | removeDash ~ ((property | schemaRequired) ? '' : '?')) | tsModelProperty((property | getSubSchema(spec, definitionName)), 8) | raw }}
42+
{{ ((property | schemaName) | removeDash ~ ((property | schemaRequired) ? '' : '?')) | tsModelProperty((property | getSubSchema(spec, definitionName)), 8, (property | schemaNullable)) | raw }}
4343
{% endfor %}
4444
};
4545
{% endif %}
@@ -64,7 +64,7 @@ export namespace Models {
6464
*{% if (property.description | trimLines) is not empty %} {{ property.description | trimLines | raw }}{% endif %}
6565

6666
*/
67-
{{ ((property | schemaName) | removeDash ~ ((property | schemaRequired) ? '' : '?')) | tsModelProperty((property | getSubSchema(spec, requestModelName)), 8) | raw }}
67+
{{ ((property | schemaName) | removeDash ~ ((property | schemaRequired) ? '' : '?')) | tsModelProperty((property | getSubSchema(spec, requestModelName)), 8, (property | schemaNullable)) | raw }}
6868
{% endfor %}
6969
};
7070
{% if requestModel.additionalProperties %}

‎templates/rust/tests/tests.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ async fn test_general_service(client: &Client, string_in_array: &[String]) -> Re
152152
println!("preset: name={}, count={}, enabled={}", item.name, item.count, item.enabled);
153153
}
154154
println!("empty presets: {}", general.list_empty_presets().await?.presets.len());
155+
println!("preset verified: {}", preset.verified.map_or("null".to_string(), |verified| verified.to_string()));
155156

156157
// Exception Responses
157158
match general.error400().await {

‎templates/web/src/models.ts.twig‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export namespace Models {
4242
*{% if (property.description | trimLines) is not empty %} {{ property.description | trimLines | raw }}{% endif %}
4343

4444
*/
45-
{{ ((property | schemaName) | removeDash ~ ((property | schemaRequired) ? '' : '?')) | tsModelProperty((property | getSubSchema(spec, definitionName)), 8) | raw }}
45+
{{ ((property | schemaName) | removeDash ~ ((property | schemaRequired) ? '' : '?')) | tsModelProperty((property | getSubSchema(spec, definitionName)), 8, (property | schemaNullable)) | raw }}
4646
{% endfor %}
4747
};
4848
{% endif %}
@@ -67,7 +67,7 @@ export namespace Models {
6767
*{% if (property.description | trimLines) is not empty %} {{ property.description | trimLines | raw }}{% endif %}
6868

6969
*/
70-
{{ ((property | schemaName) | removeDash ~ ((property | schemaRequired) ? '' : '?')) | tsModelProperty((property | getSubSchema(spec, requestModelName)), 8) | raw }}
70+
{{ ((property | schemaName) | removeDash ~ ((property | schemaRequired) ? '' : '?')) | tsModelProperty((property | getSubSchema(spec, requestModelName)), 8, (property | schemaNullable)) | raw }}
7171
{% endfor %}
7272
};
7373
{% if requestModel.additionalProperties %}

‎tests/e2e/Android16Java17Test.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ final class Android16Java17Test extends Base
5454
...Base::ENUM_RESPONSES,
5555
...Base::MODEL_RESPONSES,
5656
...Base::MODEL_DEFAULT_RESPONSES,
57+
...Base::NULLABLE_MODEL_RESPONSES,
5758
...Base::EXCEPTION_RESPONSES,
5859
...Base::REALTIME_RESPONSES,
5960
// ...Base::COOKIE_RESPONSES,

‎tests/e2e/Android5Java17Test.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ final class Android5Java17Test extends Base
5151
...Base::ENUM_RESPONSES,
5252
...Base::MODEL_RESPONSES,
5353
...Base::MODEL_DEFAULT_RESPONSES,
54+
...Base::NULLABLE_MODEL_RESPONSES,
5455
...Base::EXCEPTION_RESPONSES,
5556
...Base::REALTIME_RESPONSES,
5657
// ...Base::COOKIE_RESPONSES,

‎tests/e2e/AppleSwift61Test.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ final class AppleSwift61Test extends Base
5252
...Base::MODEL_RESPONSES,
5353
...Base::OBJECT_ARRAY_RESPONSES,
5454
...Base::MODEL_DEFAULT_RESPONSES,
55+
...Base::NULLABLE_MODEL_RESPONSES,
5556
...Base::EXCEPTION_RESPONSES,
5657
...Base::REALTIME_RESPONSES,
5758
...Base::COOKIE_RESPONSES,

0 commit comments

Comments
 (0)