Skip to content

Commit 960a167

Browse files
committed
Add directives to fix AutoREST's serialization of AdditionalProperties.
1 parent 10f8d30 commit 960a167

File tree

3 files changed

+66
-6
lines changed

3 files changed

+66
-6
lines changed

src/readme.graph.md

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,20 +361,26 @@ directive:
361361
subject: (Application|ServicePrincipal)SynchronizationJobCredentials
362362
variant: Validate1|ValidateExpanded1|ValidateViaIdentity1|ValidateViaIdentityExpanded1
363363
remove: true
364-
# Add AfterToJson
364+
# Modify generated .json.cs model classes.
365365
- from: source-file-csharp
366366
where: $
367367
transform: >
368368
if (!$documentPath.match(/generated%5Capi%5CModels%5CMicrosoftGraph\w*\d*.json.cs/gm))
369369
{
370370
return $;
371371
} else {
372+
// Add AfterToJson
372373
let afterJsonDeclarationRegex = /(^\s*)(partial\s*void\s*AfterFromJson\s*\(Microsoft.Graph.PowerShell.Runtime.Json.JsonObject\s*json\s*\);$)/gm
373374
$ = $.replace(afterJsonDeclarationRegex, '$1$2\n$1partial void AfterToJson(ref Microsoft.Graph.PowerShell.Runtime.Json.JsonObject container, Microsoft.Graph.PowerShell.Runtime.SerializationMode serializationMode);\n');
374375
let afterJsonRegex = /(^\s*)(AfterToJson\(ref\s*container\s*\);$)/gm
375376
$ = $.replace(afterJsonRegex, '$1$2\n$1AfterToJson(ref container, serializationMode);\n');
377+
378+
// Pass exclusion properties to base classes during serialization.
379+
let baseClassInitializerRegex = /(new\s*Microsoft.Graph.PowerShell.Models.MicrosoftGraph\w*\(\s*json\s*,\s*new\s*global::System.Collections.Generic.HashSet<string>\()(\){\W.*}\);)/gm
380+
$ = $.replace(baseClassInitializerRegex, '$1(exclusions ?? new System.Collections.Generic.HashSet<string>())$2');
376381
return $;
377382
}
383+
# Modify generated .cs model classes.
378384
- from: source-file-csharp
379385
where: $
380386
transform: >
@@ -388,6 +394,24 @@ directive:
388394
$ = $.replace(valuesPropertiesRegex, '$1$2 new $3');
389395
}
390396
397+
// Add new modifier to 'additionalProperties' properties of classes that derive from an IAssociativeArray. See example https://regex101.com/r/hnX7xO/2.
398+
let additionalPropertiesRegex = /(SerializedName\s*=\s*@"additionalProperties".*\s*.*)(\s*)(.*AdditionalProperties\s*{\s*get;\s*set;\s*})/gmi
399+
if($.match(additionalPropertiesRegex)) {
400+
$ = $.replace(additionalPropertiesRegex, '$1$2 new $3');
401+
}
402+
403+
// Add new modifier to 'keys' properties of classes that derive from an IAssociativeArray. See example https://regex101.com/r/hnX7xO/2.
404+
let keysRegex = /(SerializedName\s*=\s*@"keys".*\s*.*)(\s*)(.*Keys\s*{\s*get;\s*set;\s*})/gmi
405+
if($.match(keysRegex)) {
406+
$ = $.replace(keysRegex, '$1$2 new $3');
407+
}
408+
409+
// Add new modifier to 'count' properties of classes that derive from an IAssociativeArray. See example https://regex101.com/r/hnX7xO/2.
410+
let countRegex = /(SerializedName\s*=\s*@"count".*\s*.*)(\s*)(.*Count\s*{\s*get;\s*set;\s*})/gmi
411+
if($.match(countRegex)) {
412+
$ = $.replace(countRegex, '$1$2 new $3');
413+
}
414+
391415
let regexPattern = /^\s*public\s*partial\s*class\s*MicrosoftGraph(?<EntityName>.*):$/gm;
392416
let regexArray;
393417
while ((regexArray = regexPattern.exec($)) !== null) {
@@ -404,29 +428,36 @@ directive:
404428
}
405429
return $;
406430
}
407-
# Override OnDefault to handle all success, 2xx responses, as success and not error.
431+
# Modify generated .cs cmdlets.
408432
- from: source-file-csharp
409433
where: $
410434
transform: >
411435
if (!$documentPath.match(/generated%2Fcmdlets%2F\w*\d*.cs/gm))
412436
{
413437
return $;
414438
} else {
439+
// Initialize AdditionalProperties prop to a new Hashtable by default.
440+
let additionalPropertiesPropRegex = /System.Collections.Hashtable\s*AdditionalProperties\s*{\s*get;\s*set;\s*}$/gmi
441+
let newAdditionalPropertiesProp = "System.Collections.Hashtable AdditionalProperties { get; set; } = new System.Collections.Hashtable();"
442+
$ = $.replace(additionalPropertiesPropRegex, newAdditionalPropertiesProp);
443+
444+
// Override OnDefault to handle all success, 2xx responses, as success and not error.
415445
let overrideOnDefaultRegex = /(\s*)(partial\s*void\s*overrideOnDefault)/gmi
416446
let overrideOnDefaultImplementation = "$1partial void overrideOnDefault(global::System.Net.Http.HttpResponseMessage responseMessage, global::System.Threading.Tasks.Task<Microsoft.Graph.PowerShell.Models.IOdataError> response, ref global::System.Threading.Tasks.Task<bool> returnNow) => this.OverrideOnDefault(responseMessage,ref returnNow);$1$2"
417447
$ = $.replace(overrideOnDefaultRegex, overrideOnDefaultImplementation);
418448
419449
return $;
420450
}
421451
422-
# Add custom -PageSize parameter to *_List cmdlets that support Odata next link.
452+
# Modify generated .cs list cmdlets.
423453
- from: source-file-csharp
424454
where: $
425455
transform: >
426456
if (!$documentPath.match(/generated%2Fcmdlets%2FGet\w*_List\d*.cs/gm))
427457
{
428458
return $;
429459
} else {
460+
// Add custom -PageSize parameter to *_List cmdlets that support Odata next link.
430461
let odataNextLinkRegex = /(^\s*)(if\s*\(\s*result.OdataNextLink\s*!=\s*null\s*\))/gmi
431462
if($.match(odataNextLinkRegex)) {
432463
$ = $.replace(odataNextLinkRegex, '$1if (result.OdataNextLink != null && this.ShouldIteratePages(this.InvocationInformation.BoundParameters, result.Value.Length))\n$1');
@@ -442,4 +473,21 @@ directive:
442473
}
443474
return $;
444475
}
476+
477+
# Modify generated runtime TypeConverterExtensions class.
478+
- from: source-file-csharp
479+
where: $
480+
transform: >
481+
if (!$documentPath.match(/generated%5Cruntime%5CTypeConverterExtensions.cs/gm))
482+
{
483+
return $;
484+
} else {
485+
// Use a case-insensitive contains search.
486+
let keyValueContainsRegex = /(exclusions|inclusions)(\?.Contains\(key\?.ToString\(\))(\)\))/gm
487+
$ = $.replace(keyValueContainsRegex, '$1$2, System.StringComparer.OrdinalIgnoreCase$3');
488+
489+
let propertyContainsRegex = /(exclusions|inclusions)(\?.Contains\(property.Name)(\)\))/gm
490+
$ = $.replace(propertyContainsRegex, '$1$2, System.StringComparer.OrdinalIgnoreCase$3');
491+
return $;
492+
}
445493
```

tools/Custom/ListCmdlet.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,12 @@ public void InitializePaging(ref global::System.Management.Automation.Invocation
9898
{
9999
currentPageSize = limit;
100100
}
101-
// Explicitly set `-Top` parameter to currentPageSize in order for the generated cmdlets to construct a URL with a `$top` query parameter.
102-
invocationInfo.BoundParameters["Top"] = currentPageSize;
103-
top = currentPageSize;
101+
102+
if (invocationInfo.BoundParameters.ContainsKey("PageSize") || invocationInfo.BoundParameters.ContainsKey("Top") || invocationInfo.BoundParameters.ContainsKey("All")){
103+
// Explicitly set `-Top` parameter to currentPageSize in order for the generated cmdlets to construct a URL with a `$top` query parameter.
104+
invocationInfo.BoundParameters["Top"] = currentPageSize;
105+
top = currentPageSize;
106+
}
104107

105108
if (limit != default)
106109
{

tools/GenerateModules.ps1

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,15 @@ $ModuleMapping.Keys | ForEach-Object -Begin { $RequestCount = 0 } -End { Write-H
136136
}
137137
} | Set-Content $ModulePsm1
138138

139+
# Address AutoREST bug where it looks for exports in the wrong directory.
140+
$InternalModulePsm1 = Join-Path $ModuleProjectDir "/internal/$ModulePrefix.$ModuleName.internal.psm1"
141+
(Get-Content -Path $InternalModulePsm1) | ForEach-Object{
142+
$_
143+
if ($_ -match '\$exportsPath = \$PSScriptRoot') {
144+
' $exportsPath = Join-Path $PSScriptRoot "../exports"'
145+
}
146+
} | Set-Content $InternalModulePsm1
147+
139148
if ($LASTEXITCODE) {
140149
Write-Error "Failed to build '$ModuleName' module."
141150
}

0 commit comments

Comments
 (0)