Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add use import statements for PHP Snippets #2000

Merged
merged 41 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
c5ce95b
Draft php imports in snippets
shemogumbe Mar 19, 2024
1ce78f9
fix import paths for models and request builders php
shemogumbe Mar 19, 2024
b6dd764
add imports after opening php tag
shemogumbe Mar 19, 2024
4d85aa7
fix request builder namespace paths
shemogumbe Mar 19, 2024
c50eabf
fix request builder namespace and path
shemogumbe Mar 19, 2024
67965a8
do not transform imports parts to lowercase or snake case
shemogumbe Mar 19, 2024
ba80fb0
replace . with \\ in requestbuilder namespace path
shemogumbe Mar 19, 2024
aa52e79
replace . with \\ in requestbuilder namespace path
shemogumbe Mar 19, 2024
61c1edd
remove double slashes on request builder path
shemogumbe Mar 19, 2024
5f351b4
fix replace dots with slashes on import paths
shemogumbe Mar 19, 2024
dc939fd
fix replace dots with slashes on import paths -change case
shemogumbe Mar 19, 2024
2c3f0c7
fix dot to slash replacement
shemogumbe Mar 19, 2024
3cbb7a0
fix dot to slash replacement
shemogumbe Mar 19, 2024
52c0ec4
Update request builder path
shemogumbe Mar 19, 2024
96e365c
Update request builder path - change casing
shemogumbe Mar 19, 2024
c25fbbc
remove double slashes on request builder paths
shemogumbe Mar 19, 2024
b084377
remove equest builder name- use namespace only for imports
shemogumbe Mar 19, 2024
aa10935
remove model name - use model namespace without fqcn
shemogumbe Mar 19, 2024
6eff992
remove model name - use model namespace without fqcn
shemogumbe Mar 19, 2024
e1979fc
unit tests for php use statements
shemogumbe Mar 20, 2024
28e5bc1
add unit tests for use statements in php snippets
shemogumbe Mar 20, 2024
ecbe529
move tests to php generator test
shemogumbe Mar 20, 2024
39737b6
fix code coverage
shemogumbe Mar 20, 2024
2c91c7a
Merge branch 'shem/php_snipet_imports' of github.com:microsoftgraph/m…
shemogumbe Mar 20, 2024
74150dc
remove request builder imports - namespaces are enough
shemogumbe Mar 20, 2024
5e28ebf
add request builder filename to import
shemogumbe Mar 22, 2024
56d2526
add model and request builder class name import
shemogumbe Mar 22, 2024
e1073f0
fix tests include class names on imports
shemogumbe Mar 22, 2024
57a1345
fix import class names
shemogumbe Mar 22, 2024
2c50c33
improve code readability
shemogumbe Mar 22, 2024
9666b45
fix indentation
shemogumbe Mar 22, 2024
105f874
update classname in imports
shemogumbe Mar 22, 2024
8ae1bf0
fix casing for request builder name
shemogumbe Mar 22, 2024
a450747
fix casing for request builder name
shemogumbe Mar 22, 2024
6e2220b
Update tests to reflect request builde class names
shemogumbe Mar 22, 2024
0fb9297
remove duplicate unit tests
shemogumbe Mar 25, 2024
3e9d947
fix failing tests
shemogumbe Mar 25, 2024
5c85dfc
fix failing tests
shemogumbe Mar 25, 2024
68b437c
Convert importsgenerator to static class
shemogumbe Mar 25, 2024
92a6469
Fix snippet import tests
shemogumbe Mar 25, 2024
fde5539
remove duplcate unit tests
shemogumbe Mar 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CodeSnippetsReflection.OpenAPI.Test/PhpGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public async Task GeneratesTheCorrectFluentApiPathForIndexedCollections()
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("->me()->messages()->byMessageId('message-id')", result);

}

[Fact]
Expand Down
78 changes: 78 additions & 0 deletions CodeSnippetsReflection.OpenAPI.Test/PhpImportGeneratorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using CodeSnippetsReflection.OpenAPI.LanguageGenerators;
using Xunit;

namespace CodeSnippetsReflection.OpenAPI.Test;

public class PhpImportTests : OpenApiSnippetGeneratorTestBase
{
private readonly PhpGenerator _generator = new();

[Fact]
public async Task GeneratesRequestBuilderImports()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/me/calendar/events?$filter=startsWith(subject,'All')");
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("use Microsoft\\Graph\\GraphServiceClient;", result);
Assert.Contains("use Microsoft\\Graph\\Generated\\Users\\Item\\Calendar\\Events\\EventsRequestBuilderGetRequestConfiguration;", result);
}

[Fact]
public async Task GenerateModelImports(){
var bodyContent = @"{
""displayName"": ""New display name""
}";
using var requestPayload = new HttpRequestMessage(HttpMethod.Patch, $"{ServiceRootUrl}/applications/{{id}}")
{
Content = new StringContent(bodyContent, Encoding.UTF8, "application/json")
};
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("use Microsoft\\Graph\\GraphServiceClient;", result);
Assert.Contains("use Microsoft\\Graph\\Generated\\Models\\Application;", result);

}
[Fact]
public async Task GenerateComplexModelImports(){
var bodyContent = @"{
""subject"": ""Annual review"",
""body"": {
""contentType"": ""HTML"",
""content"": ""You should be proud!""
},
""toRecipients"": [
{
""emailAddress"": {
""address"": ""[email protected]""
}
}
],
""extensions"": [
{
""@odata.type"": ""microsoft.graph.openTypeExtension"",
""extensionName"": ""Com.Contoso.Referral"",
""companyName"": ""Wingtip Toys"",
""expirationDate"": ""2015-12-30T11:00:00.000Z"",
""dealValue"": 10000
}
]
}";
using var requestPayload = new HttpRequestMessage(HttpMethod.Post, $"{ServiceRootUrl}/me/messages/")
{
Content = new StringContent(bodyContent, Encoding.UTF8, "application/json")
};
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var result = _generator.GenerateCodeSnippet(snippetModel);
Assert.Contains("use Microsoft\\Graph\\GraphServiceClient;", result);
Assert.Contains("use Microsoft\\Graph\\Generated\\Models\\Message;", result);
Assert.Contains("use Microsoft\\Graph\\Generated\\Models\\ItemBody;", result);
Assert.Contains("use Microsoft\\Graph\\Generated\\Models\\Recipient;", result);
Assert.Contains("use Microsoft\\Graph\\Generated\\Models\\EmailAddress;", result);
Assert.Contains("use Microsoft\\Graph\\Generated\\Models\\Extension;", result);
Assert.Contains("use Microsoft\\Graph\\Generated\\Models\\OpenTypeExtension;", result);
}
}
6 changes: 2 additions & 4 deletions CodeSnippetsReflection.OpenAPI.Test/SnippetImportTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ public async Task TestGenerateImportTemplatesForModelImports()
Content = new StringContent(userJsonObject, Encoding.UTF8, "application/json")
};
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var importsGenerator = new ImportsGenerator();
var result = importsGenerator.GenerateImportTemplates(snippetModel);
var result = ImportsGenerator.GenerateImportTemplates(snippetModel);
Assert.NotNull(result);
Assert.IsType<List<ImportTemplate>>(result);
Assert.Equal(2, result.Count);
Expand All @@ -36,8 +35,7 @@ public async Task TestGenerateImportTemplatesForRequestBuilderImports()
{
using var requestPayload = new HttpRequestMessage(HttpMethod.Get, $"{ServiceRootUrl}/me/calendar/events?$filter=startsWith(subject,'All')");
var snippetModel = new SnippetModel(requestPayload, ServiceRootUrl, await GetV1SnippetMetadata());
var importsGenerator = new ImportsGenerator();
var result = importsGenerator.GenerateImportTemplates(snippetModel);
var result = ImportsGenerator.GenerateImportTemplates(snippetModel);
Assert.NotNull(result);
Assert.IsType<List<ImportTemplate>>(result);
Assert.NotNull(result[0].Path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,54 @@
WriteObjectProperty(RequestBodyVarName, payloadSb, codeGraph.Body, indentManager);
}
WriteRequestExecutionPath(codeGraph, payloadSb, indentManager);
var importStatements = GetImportStatements(snippetModel);
var phpTagIndex = payloadSb.ToString().IndexOf("<?php");
if (phpTagIndex >= 0)
{
var insertPosition = phpTagIndex + "<?php".Length + Environment.NewLine.Length;
payloadSb.Insert(insertPosition, string.Join(Environment.NewLine, importStatements) + Environment.NewLine);
}
else
{
payloadSb.Insert(0, string.Join(Environment.NewLine, importStatements) + Environment.NewLine);
}
return payloadSb.ToString().Trim();
}
private static HashSet<string> GetImportStatements(SnippetModel snippetModel)
{
const string modelImportPrefix = "use Microsoft\\Graph\\Generated\\Models";
const string requestBuilderImportPrefix = "use Microsoft\\Graph\\Generated";

var snippetImports = new HashSet<string>();

snippetImports.Add("use Microsoft\\Graph\\GraphServiceClient;");

var imports = ImportsGenerator.GenerateImportTemplates(snippetModel);
foreach (var import in imports)
{
switch (import.Kind)
{
case ImportKind.Model:
var typeDefinition = import.ModelProperty.TypeDefinition;
if (typeDefinition != null){
snippetImports.Add($"{modelImportPrefix}\\{typeDefinition};");
// check if model has a nested namespace and append it to the import statement
}
break;

case ImportKind.Path:
if (!string.IsNullOrEmpty(import.Path) && !string.IsNullOrEmpty(import.RequestBuilderName))
{
//construct path to request builder
var importPath = import.Path.Split('.')
.Select(static s => s.ToFirstCharacterUpperCase()).ToArray();
snippetImports.Add($"{requestBuilderImportPrefix}{string.Join("\\", importPath).Replace("\\Me\\", "\\Users\\Item\\")}\\{import.RequestBuilderName}{import.HttpMethod.ToLowerInvariant().ToFirstCharacterUpperCase()}RequestConfiguration;");
}
break;
}
}
return snippetImports;
}
private static void WriteRequestExecutionPath(SnippetCodeGraph codeGraph, StringBuilder payloadSb, IndentManager indentManager)
{
var method = codeGraph.HttpMethod.Method.ToLower();
Expand Down Expand Up @@ -212,7 +257,7 @@
WriteCodeProperty(childPropertyName ?? propertyAssignment, payloadSb, codeProperty, child, indentManager, ++childPosition, newChildName);
}
}
private static void WriteCodeProperty(string propertyAssignment, StringBuilder payloadSb, CodeProperty parent, CodeProperty child, IndentManager indentManager, int childPosition = 0, string childPropertyName = default, bool fromMap = false)

Check warning on line 260 in CodeSnippetsReflection.OpenAPI/LanguageGenerators/PhpGenerator.cs

View workflow job for this annotation

GitHub Actions / Build

Remove this unused method parameter 'childPosition'. (https://rules.sonarsource.com/csharp/RSPEC-1172)

Check warning on line 260 in CodeSnippetsReflection.OpenAPI/LanguageGenerators/PhpGenerator.cs

View workflow job for this annotation

GitHub Actions / Build

Method has 8 parameters, which is greater than the 7 authorized. (https://rules.sonarsource.com/csharp/RSPEC-107)
{
var isArray = parent.PropertyType == PropertyType.Array;
var isMap = parent.PropertyType == PropertyType.Map;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
snippetBuilder.Insert(0, string.Join(Environment.NewLine, importStatements));
return snippetBuilder.ToString();
}
private static HashSet<string> GetImportStatements(SnippetModel snippetModel)

Check warning on line 76 in CodeSnippetsReflection.OpenAPI/LanguageGenerators/PythonGenerator.cs

View workflow job for this annotation

GitHub Actions / Build

Refactor this method to reduce its Cognitive Complexity from 18 to the 15 allowed. (https://rules.sonarsource.com/csharp/RSPEC-3776)
{
const string modelImportPrefix = "from msgraph.generated.models";
const string requestBuilderImportPrefix = "from msgraph.generated";
Expand All @@ -82,8 +82,7 @@

snippetImports.Add("from msgraph import GraphServiceClient");

var importsGenerator = new ImportsGenerator();
var imports = importsGenerator.GenerateImportTemplates(snippetModel);
var imports = ImportsGenerator.GenerateImportTemplates(snippetModel);
foreach (var import in imports)
{
switch (import.Kind)
Expand Down Expand Up @@ -304,9 +303,9 @@
var enumValues = codeProperty.Value.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x =>
{
var enumHint = x.Split('.').Last().Trim();

Check warning on line 306 in CodeSnippetsReflection.OpenAPI/LanguageGenerators/PythonGenerator.cs

View workflow job for this annotation

GitHub Actions / Build

Indexing at Count-1 should be used instead of the "Enumerable" extension method "Last" (https://rules.sonarsource.com/csharp/RSPEC-6608)
// the enum member may be invalid so default to generating the first value in case a look up fails.
var enumMember = codeProperty.Children.FirstOrDefault(member => member.Value.Equals(enumHint, StringComparison.OrdinalIgnoreCase)).Value ?? codeProperty.Children.FirstOrDefault().Value ?? enumHint;

Check warning on line 308 in CodeSnippetsReflection.OpenAPI/LanguageGenerators/PythonGenerator.cs

View workflow job for this annotation

GitHub Actions / Build

"Find" method should be used instead of the "FirstOrDefault" extension method. (https://rules.sonarsource.com/csharp/RSPEC-6602)
return $"{enumTypeString.TrimEnd('?')}.{enumMember.ToFirstCharacterUpperCase()}";
})
.Aggregate(static (x, y) => $"{x} | {y}");
Expand Down Expand Up @@ -351,7 +350,7 @@
case PropertyType.Map:
return "{";
case PropertyType.Enum:
return $"{ReplaceIfReservedTypeName(typeString.Split('.').First())}?";

Check warning on line 353 in CodeSnippetsReflection.OpenAPI/LanguageGenerators/PythonGenerator.cs

View workflow job for this annotation

GitHub Actions / Build

Indexing at 0 should be used instead of the "Enumerable" extension method "First" (https://rules.sonarsource.com/csharp/RSPEC-6608)
default:
return string.Empty;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using CodeSnippetsReflection.StringExtensions;
using Microsoft.OpenApi.Services;


namespace CodeSnippetsReflection.OpenAPI.LanguageGenerators
{
public enum ImportKind
Expand Down Expand Up @@ -33,16 +34,20 @@
{
get; set;
}
public string HttpMethod
{
get; set;
}
}

public class ImportsGenerator
public static class ImportsGenerator
{
public List<ImportTemplate> imports = new();
public static List<ImportTemplate> imports = new();

Check warning on line 45 in CodeSnippetsReflection.OpenAPI/LanguageGenerators/SnippetImports.cs

View workflow job for this annotation

GitHub Actions / Build

Make this field 'private' and encapsulate it in a 'public' property. (https://rules.sonarsource.com/csharp/RSPEC-1104)

Check warning on line 45 in CodeSnippetsReflection.OpenAPI/LanguageGenerators/SnippetImports.cs

View workflow job for this annotation

GitHub Actions / Build

Use an immutable collection or reduce the accessibility of the public static field 'imports'. (https://rules.sonarsource.com/csharp/RSPEC-2386)

Check warning on line 45 in CodeSnippetsReflection.OpenAPI/LanguageGenerators/SnippetImports.cs

View workflow job for this annotation

GitHub Actions / Build

Change the visibility of 'imports' or make it 'const' or 'readonly'. (https://rules.sonarsource.com/csharp/RSPEC-2223)

public List<ImportTemplate> GenerateImportTemplates(SnippetModel snippetModel)
public static List<ImportTemplate> GenerateImportTemplates(SnippetModel snippetModel)
{
var codeGraph = new SnippetCodeGraph(snippetModel);
var imports = new List<ImportTemplate>();

Check warning on line 50 in CodeSnippetsReflection.OpenAPI/LanguageGenerators/SnippetImports.cs

View workflow job for this annotation

GitHub Actions / Build

Rename 'imports' which hides the field with the same name. (https://rules.sonarsource.com/csharp/RSPEC-1117)
if (codeGraph.HasHeaders() || codeGraph.HasParameters() || codeGraph.HasOptions())
{
var className = codeGraph.Nodes.Last().GetClassName().ToFirstCharacterUpperCase();
Expand All @@ -55,7 +60,8 @@
{
Kind = ImportKind.Path,
Path = Regex.Replace(path.Replace("\\", ".").Replace("()", ""), @"\{[^}]*-id\}", "item", RegexOptions.Compiled, TimeSpan.FromSeconds(60)),
RequestBuilderName = requestBuilderName
RequestBuilderName = requestBuilderName,
HttpMethod = codeGraph.HttpMethod.ToString()
});
}
}
Expand Down