forked from StefanMaron/BusinessCentral.LinterCop
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request StefanMaron#674 from StefanMaron/BestPraticeOnAPIP…
…ages Add new rules for best pratices on API Pages
- Loading branch information
Showing
8 changed files
with
257 additions
and
1 deletion.
There are no files selected for viewing
37 changes: 37 additions & 0 deletions
37
BusinessCentral.LinterCop/Design/Rule0060RemovePropertyApplicationAreaOnApiPage.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using BusinessCentral.LinterCop.AnalysisContextExtension; | ||
using Microsoft.Dynamics.Nav.CodeAnalysis; | ||
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics; | ||
using System.Collections.Immutable; | ||
|
||
namespace BusinessCentral.LinterCop.Design | ||
{ | ||
[DiagnosticAnalyzer] | ||
public class Rule0060PropertyApplicationAreaOnApiPage : DiagnosticAnalyzer | ||
{ | ||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create<DiagnosticDescriptor>(DiagnosticDescriptors.Rule0060PropertyApplicationAreaOnApiPage); | ||
|
||
public override void Initialize(AnalysisContext context) | ||
=> context.RegisterSymbolAction(new Action<SymbolAnalysisContext>(this.AnalyzePropertyApplicationAreaOnApiPage), SymbolKind.Page); | ||
|
||
private void AnalyzePropertyApplicationAreaOnApiPage(SymbolAnalysisContext ctx) | ||
{ | ||
if (ctx.IsObsoletePendingOrRemoved()) return; | ||
|
||
if (ctx.Symbol is not IPageTypeSymbol pageTypeSymbol) | ||
return; | ||
|
||
if (pageTypeSymbol.PageType != PageTypeKind.API) | ||
return; | ||
|
||
if (pageTypeSymbol.GetProperty(PropertyKind.ApplicationArea) is IPropertySymbol propertyApplicationArea) | ||
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0060PropertyApplicationAreaOnApiPage, propertyApplicationArea.GetLocation())); | ||
|
||
IEnumerable<IControlSymbol> pageFields = pageTypeSymbol.FlattenedControls | ||
.Where(e => e.ControlKind == ControlKind.Field) | ||
.Where(e => e.GetProperty(PropertyKind.ApplicationArea) is not null); | ||
|
||
foreach (IControlSymbol pageField in pageFields) | ||
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0060PropertyApplicationAreaOnApiPage, pageField.GetProperty(PropertyKind.ApplicationArea).GetLocation())); | ||
} | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
BusinessCentral.LinterCop/Design/Rule0061SetODataKeyFieldsWithSystemIdField.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using BusinessCentral.LinterCop.AnalysisContextExtension; | ||
using Microsoft.Dynamics.Nav.CodeAnalysis; | ||
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics; | ||
using Microsoft.Dynamics.Nav.CodeAnalysis.Text; | ||
using System.Collections.Immutable; | ||
|
||
namespace BusinessCentral.LinterCop.Design | ||
{ | ||
[DiagnosticAnalyzer] | ||
public class Rule0061SetODataKeyFieldsWithSystemIdField : DiagnosticAnalyzer | ||
{ | ||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create<DiagnosticDescriptor>(DiagnosticDescriptors.Rule0061SetODataKeyFieldsWithSystemIdField); | ||
|
||
public override void Initialize(AnalysisContext context) | ||
=> context.RegisterSymbolAction(new Action<SymbolAnalysisContext>(this.AnalyzeODataKeyFieldsPropertyOnApiPage), SymbolKind.Page); | ||
|
||
private void AnalyzeODataKeyFieldsPropertyOnApiPage(SymbolAnalysisContext ctx) | ||
{ | ||
if (ctx.IsObsoletePendingOrRemoved()) return; | ||
|
||
if (ctx.Symbol is not IPageTypeSymbol pageTypeSymbol) | ||
return; | ||
|
||
if (pageTypeSymbol.PageType != PageTypeKind.API) | ||
return; | ||
|
||
if (pageTypeSymbol.GetBooleanPropertyValue(PropertyKind.SourceTableTemporary).GetValueOrDefault()) | ||
return; | ||
|
||
IPropertySymbol property = pageTypeSymbol.GetProperty(PropertyKind.ODataKeyFields); | ||
|
||
// Set the location of the diagnostic on the property itself (if exists) | ||
Location location = pageTypeSymbol.GetLocation(); | ||
if (property != null) | ||
location = property.GetLocation(); | ||
|
||
if (property == null || property.Value == null || property.ValueText != "2000000000") | ||
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0061SetODataKeyFieldsWithSystemIdField, location)); | ||
} | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
BusinessCentral.LinterCop/Design/Rule0062MandatoryFieldMissingOnApiPage.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using BusinessCentral.LinterCop.AnalysisContextExtension; | ||
using Microsoft.Dynamics.Nav.CodeAnalysis; | ||
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics; | ||
using System.Collections.Immutable; | ||
|
||
namespace BusinessCentral.LinterCop.Design | ||
{ | ||
[DiagnosticAnalyzer] | ||
public class Rule0062MandatoryFieldMissingOnApiPage : DiagnosticAnalyzer | ||
{ | ||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create<DiagnosticDescriptor>(DiagnosticDescriptors.Rule0062MandatoryFieldMissingOnApiPage); | ||
|
||
private static readonly Dictionary<string, string> _mandatoryFields = new Dictionary<string, string> | ||
{ | ||
{ "SystemId", "id" }, | ||
{ "SystemModifiedAt", "lastModifiedDateTime" } | ||
}; | ||
|
||
public override void Initialize(AnalysisContext context) | ||
=> context.RegisterSymbolAction(new Action<SymbolAnalysisContext>(this.AnalyzeRule0062MandatoryFieldOnApiPage), SymbolKind.Page); | ||
|
||
private void AnalyzeRule0062MandatoryFieldOnApiPage(SymbolAnalysisContext ctx) | ||
{ | ||
if (ctx.IsObsoletePendingOrRemoved()) return; | ||
|
||
if (ctx.Symbol is not IPageTypeSymbol pageTypeSymbol) | ||
return; | ||
|
||
if (pageTypeSymbol.PageType != PageTypeKind.API) | ||
return; | ||
|
||
if (pageTypeSymbol.GetBooleanPropertyValue(PropertyKind.SourceTableTemporary).GetValueOrDefault()) | ||
return; | ||
|
||
IEnumerable<IControlSymbol> pageFields = pageTypeSymbol.FlattenedControls | ||
.Where(e => e.ControlKind == ControlKind.Field) | ||
.Where(e => e.RelatedFieldSymbol != null); | ||
|
||
IEnumerable<KeyValuePair<string, string>> missingMandatoryFields = _mandatoryFields | ||
.Where(mf => !pageFields.Any(pf => mf.Key == pf.RelatedFieldSymbol?.Name && mf.Value == pf.Name)); | ||
|
||
foreach (KeyValuePair<string, string> field in missingMandatoryFields) | ||
{ | ||
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0062MandatoryFieldMissingOnApiPage, pageTypeSymbol.GetLocation(), new object[] { field.Key, field.Value })); | ||
} | ||
} | ||
} | ||
} |
66 changes: 66 additions & 0 deletions
66
BusinessCentral.LinterCop/Design/Rule0063GiveFieldMoreDescriptiveName.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
using BusinessCentral.LinterCop.AnalysisContextExtension; | ||
using Microsoft.Dynamics.Nav.CodeAnalysis; | ||
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics; | ||
using System.Collections.Immutable; | ||
|
||
namespace BusinessCentral.LinterCop.Design | ||
{ | ||
[DiagnosticAnalyzer] | ||
public class Rule0063GiveFieldMoreDescriptiveName : DiagnosticAnalyzer | ||
{ | ||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create<DiagnosticDescriptor>(DiagnosticDescriptors.Rule0063GiveFieldMoreDescriptiveName); | ||
private static readonly Dictionary<string, string> _descriptiveNames = new Dictionary<string, string> | ||
{ | ||
{ "SystemId", "id" }, | ||
{ "Name", "displayName" }, | ||
{ "SystemModifiedAt", "lastModifiedDateTime" } | ||
}; | ||
|
||
public override void Initialize(AnalysisContext context) | ||
=> context.RegisterSymbolAction(new Action<SymbolAnalysisContext>(this.AnalyzePropertyApplicationAreaOnFieldsOfApiPage), SymbolKind.Page); | ||
|
||
private void AnalyzePropertyApplicationAreaOnFieldsOfApiPage(SymbolAnalysisContext ctx) | ||
{ | ||
if (ctx.IsObsoletePendingOrRemoved()) return; | ||
|
||
if (ctx.Symbol is not IPageTypeSymbol pageTypeSymbol) | ||
return; | ||
|
||
if (pageTypeSymbol.PageType != PageTypeKind.API) | ||
return; | ||
|
||
IEnumerable<IControlSymbol> pageFields = pageTypeSymbol.FlattenedControls | ||
.Where(e => e.ControlKind == ControlKind.Field) | ||
.Where(e => e.RelatedFieldSymbol != null); | ||
|
||
foreach (IControlSymbol field in pageFields) | ||
{ | ||
ctx.CancellationToken.ThrowIfCancellationRequested(); | ||
string descriptiveName = GetDescriptiveName(field); | ||
if (!string.IsNullOrEmpty(descriptiveName) && field.Name != descriptiveName) | ||
{ | ||
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0063GiveFieldMoreDescriptiveName, field.GetLocation(), new object[] { descriptiveName })); | ||
} | ||
} | ||
} | ||
|
||
private static string GetDescriptiveName(IControlSymbol field) | ||
{ | ||
if (_descriptiveNames.ContainsKey(field.RelatedFieldSymbol.Name)) | ||
return _descriptiveNames[field.RelatedFieldSymbol.Name]; | ||
|
||
if (field.RelatedFieldSymbol.Name.Contains("No.") | ||
&& field.Name.Contains("no", StringComparison.OrdinalIgnoreCase) | ||
&& !field.Name.Contains("number", StringComparison.OrdinalIgnoreCase)) | ||
return ReplaceNoWithNumber(field.Name); | ||
|
||
return null; | ||
} | ||
public static string ReplaceNoWithNumber(string input) | ||
{ | ||
input = input.Replace("No", "Number"); | ||
input = input.Replace("no", "number"); | ||
return input; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters