Skip to content

Commit cc2cd62

Browse files
committed
Add parse_value Twig function for DotNet models
Introduces a new parse_value Twig function in DotNet.php to centralize and simplify value parsing logic for model properties. Updates Model.cs.twig to use this function, reducing template complexity and improving maintainability.
1 parent d9f6d71 commit cc2cd62

File tree

2 files changed

+84
-60
lines changed

2 files changed

+84
-60
lines changed

src/SDK/Language/DotNet.php

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ public function getFilters(): array
467467
}
468468

469469
/**
470-
* get sub_scheme and property_name functions
470+
* get sub_scheme, property_name and parse_value functions
471471
* @return TwigFunction[]
472472
*/
473473
public function getFunctions(): array
@@ -494,7 +494,7 @@ public function getFunctions(): array
494494
}
495495

496496
return $result;
497-
}),
497+
}, ['is_safe' => ['html']]),
498498
new TwigFunction('property_name', function (array $definition, array $property) {
499499
$name = $property['name'];
500500
$name = \str_replace('$', '', $name);
@@ -504,6 +504,82 @@ public function getFunctions(): array
504504
}
505505
return $name;
506506
}),
507+
new TwigFunction('parse_value', function (array $property, string $mapAccess, string $v) {
508+
$required = $property['required'] ?? false;
509+
510+
// Handle sub_schema
511+
if (isset($property['sub_schema']) && !empty($property['sub_schema'])) {
512+
$subSchema = \ucfirst($property['sub_schema']);
513+
514+
if ($property['type'] === 'array') {
515+
$arraySource = $required
516+
? "((IEnumerable<object>){$mapAccess})"
517+
: "({$v} as IEnumerable<object>)";
518+
return "{$arraySource}?.Select(it => {$subSchema}.From(map: (Dictionary<string, object>)it)).ToList()!";
519+
} else {
520+
if ($required) {
521+
return "{$subSchema}.From(map: (Dictionary<string, object>){$mapAccess})";
522+
}
523+
return "({$v} as Dictionary<string, object>) is { } obj ? {$subSchema}.From(map: obj) : null";
524+
}
525+
}
526+
527+
// Handle enum
528+
if (isset($property['enum']) && !empty($property['enum'])) {
529+
$enumName = $property['enumName'] ?? $property['name'];
530+
$enumClass = \ucfirst($enumName);
531+
532+
if ($required) {
533+
return "new {$enumClass}({$mapAccess}.ToString())";
534+
}
535+
return "{$v} == null ? null : new {$enumClass}({$v}.ToString())";
536+
}
537+
538+
// Handle arrays
539+
if ($property['type'] === 'array') {
540+
$itemsType = $property['items']['type'] ?? 'object';
541+
$src = $required ? $mapAccess : $v;
542+
$arraySource = $required
543+
? "((IEnumerable<object>){$src})"
544+
: "({$src} as IEnumerable<object>)";
545+
546+
$selectExpression = match($itemsType) {
547+
'string' => 'x.ToString()',
548+
'integer' => 'Convert.ToInt64(x)',
549+
'number' => 'Convert.ToDouble(x)',
550+
'boolean' => '(bool)x',
551+
default => 'x'
552+
};
553+
554+
return "{$arraySource}?.Select(x => {$selectExpression}).ToList()!";
555+
}
556+
557+
// Handle integer/number
558+
if ($property['type'] === 'integer' || $property['type'] === 'number') {
559+
$convertMethod = $property['type'] === 'integer' ? 'Int64' : 'Double';
560+
561+
if ($required) {
562+
return "Convert.To{$convertMethod}({$mapAccess})";
563+
}
564+
return "{$v} == null ? null : Convert.To{$convertMethod}({$v})";
565+
}
566+
567+
// Handle boolean
568+
if ($property['type'] === 'boolean') {
569+
$typeName = $this->getTypeName($property);
570+
571+
if ($required) {
572+
return "({$typeName}){$mapAccess}";
573+
}
574+
return "({$typeName}?){$v}";
575+
}
576+
577+
// Handle string type
578+
if ($required) {
579+
return "{$mapAccess}.ToString()";
580+
}
581+
return "{$v}?.ToString()";
582+
}, ['is_safe' => ['html']]),
507583
];
508584
}
509585

templates/dotnet/Package/Models/Model.cs.twig

Lines changed: 6 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{% set DefinitionClass = definition.name | caseUcfirst | overrideIdentifier %}
12
using System;
23
using System.Linq;
34
using System.Collections.Generic;
@@ -11,7 +12,7 @@ namespace {{ spec.title | caseUcfirst }}.Models
1112
{
1213
{%~ for property in definition.properties %}
1314
[JsonPropertyName("{{ property.name }}")]
14-
public {{ sub_schema(property) | raw }} {{ property_name(definition, property) | overrideProperty(definition.name) }} { get; private set; }
15+
public {{ sub_schema(property) }} {{ property_name(definition, property) | overrideProperty(definition.name) }} { get; private set; }
1516

1617
{%~ endfor %}
1718
{%~ if definition.additionalProperties %}
@@ -20,7 +21,7 @@ namespace {{ spec.title | caseUcfirst }}.Models
2021
{%~ endif %}
2122
public {{ DefinitionClass }}(
2223
{%~ for property in definition.properties %}
23-
{{ sub_schema(property) | raw }} {{ property.name | caseCamel | escapeKeyword }}{% if not loop.last or (loop.last and definition.additionalProperties) %},{% endif %}
24+
{{ sub_schema(property) }} {{ property.name | caseCamel | escapeKeyword }}{% if not loop.last or (loop.last and definition.additionalProperties) %},{% endif %}
2425

2526
{%~ endfor %}
2627
{%~ if definition.additionalProperties %}
@@ -40,62 +41,9 @@ namespace {{ spec.title | caseUcfirst }}.Models
4041
{%~ set v = 'v' ~ loop.index0 %}
4142
{%~ set mapAccess = 'map["' ~ property.name ~ '"]' %}
4243
{{ property.name | caseCamel | escapeKeyword | removeDollarSign }}:{{' '}}
43-
{%- if not property.required -%}map.TryGetValue("{{ property.name }}", out var {{ v }}) ? {% endif %}
44-
{%- if property.sub_schema %}
45-
{%- if property.type == 'array' -%}
46-
{%- if property.required -%}
47-
{{ _self.parse_subschema_array(property.sub_schema, mapAccess, true) }}
48-
{%- else -%}
49-
{{ _self.parse_subschema_array(property.sub_schema, v, false) }}
50-
{%- endif %}
51-
{%- else -%}
52-
{%- if property.required -%}
53-
{{ property.sub_schema | caseUcfirst | overrideIdentifier }}.From(map: (Dictionary<string, object>){{ mapAccess | raw }})
54-
{%- else -%}
55-
({{ v }} as Dictionary<string, object>) is { } obj
56-
? {{ property.sub_schema | caseUcfirst | overrideIdentifier }}.From(map: obj)
57-
: null
58-
{%- endif %}
59-
{%- endif %}
60-
{%- elseif property.enum %}
61-
{%- set enumName = property['enumName'] ?? property.name -%}
62-
{%- if not property.required -%}
63-
map.TryGetValue("{{ property.name }}", out var enumRaw{{ loop.index }})
64-
? enumRaw{{ loop.index }} == null
65-
? null
66-
: new {{ enumName | caseUcfirst }}(enumRaw{{ loop.index }}.ToString()!)
67-
: null
68-
{%- else -%}
69-
new {{ enumName | caseUcfirst }}(map["{{ property.name }}"].ToString()!)
70-
{%- endif %}
71-
{%- else %}
72-
{%- if property.type == 'array' -%}
73-
{%- if property.required -%}
74-
{{ _self.parse_primitive_array(property.items.type, mapAccess, true) }}
75-
{%- else -%}
76-
{{ _self.parse_primitive_array(property.items.type, v, false) }}
77-
{%- endif -%}
78-
{%- else %}
79-
{%- if property.type == "integer" or property.type == "number" %}
80-
{%- if not property.required -%}Convert.To{% if property.type == "integer" %}Int64{% else %}Double{% endif %}({{ v }}){% else %}Convert.To{% if property.type == "integer" %}Int64{% else %}Double{% endif %}({{ mapAccess | raw }}){%- endif %}
81-
{%- else %}
82-
{%- if property.type == "boolean" -%}
83-
{%- if not property.required -%}
84-
({{ property | typeName }}?){{ v }}
85-
{%- else -%}
86-
({{ property | typeName }}){{ mapAccess | raw }}
87-
{%- endif %}
88-
{%- else -%}
89-
{%- if not property.required -%}
90-
{{ v }}?.ToString()
91-
{%- else -%}
92-
{{ mapAccess | raw }}.ToString()
93-
{%- endif %}
94-
{%- endif %}
95-
{%~ endif %}
96-
{%~ endif %}
97-
{%~ endif %}
98-
{%- if not property.required %} : null{% endif %}
44+
{%- if not property.required -%}map.TryGetValue("{{ property.name }}", out var {{ v }}) ? {% endif -%}
45+
{{ parse_value(property, mapAccess, v) }}
46+
{%- if not property.required %} : null{% endif -%}
9947
{%- if not loop.last or (loop.last and definition.additionalProperties) %},
10048
{%~ endif %}
10149
{%~ endfor %}

0 commit comments

Comments
 (0)