Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 .github/instructions/lc0092-naming-pattern.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ Invalid user-supplied patterns fail gracefully: `CompilePattern` catches `Argume
**HasDiagnostic (9 cases):** ProcedureLowerCaseStart, VariableLowerCaseStart, VariableWithSpecialChars, ParameterLowerCaseStart, ReturnValueLowerCaseStart, ObjectLowerCaseStart, FieldWithSpecialChars, ActionLowerCaseStart, ControlLowerCaseStart.
**NoDiagnostic (18 cases):** ProcedurePascalCase, VariablePascalCase, FieldWithLettersAndDigits, ObsoleteProcedure, TriggerMethod, InterfaceImplementingMethod, EventSubscriberPascalCase, EventSubscriberPlatformParams, EventSubscriberUserParams, ApiPageControlCamelCase, ActionAcceleratorKey, EnumValueBlankSpace, EnumValueLowerCaseStart, SingleLetterVariable, SingleLetterParameter, UnderscorePrefix, XRecVariable, XRecParameter, ParameterPascalCase.
**HasDiagnosticWithCustomSettings (1 case):** EnumValueLowerCaseStartCustomSettings.
**SchemaParity (1 case):** NamingTargetEnumMatchesSchemaPropertyNames.

## Phase 2 roadmap (not yet implemented)

Expand Down
10 changes: 9 additions & 1 deletion .github/instructions/settings-schema.instructions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
applyTo: 'src/ALCops.Common/Settings/ALCopsSettings.cs'
applyTo: 'src/**/{ALCopsSettings,alcops.schema,NamingPattern}*'
---

# Settings Schema Synchronization
Expand Down Expand Up @@ -31,6 +31,14 @@ When you:
| Add a new `NamingTarget` enum value | Add to the `propertyNames.enum` array in `NamingPatterns` |
| Add/modify fields in `NamingPattern.cs` | Update the `NamingPattern` definition in `$defs` |

## Required parity guard test

For NamingPattern schema parity, the PR must include or update a test that validates `NamingPattern.NamingTarget` enum values against `NamingPatterns.propertyNames.enum` in `alcops.schema.json`.

Minimum expectation:
- Run `NamingTargetEnumMatchesSchemaPropertyNames` in `src/ALCops.LinterCop.Test/Rules/NamingPattern/NamingPatternSettings.cs`.
- The test must fail when either side adds/removes a target without updating the other.

## Description format

Each property description should follow this pattern:
Expand Down
10 changes: 7 additions & 3 deletions src/ALCops.Common/Settings/alcops.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@
"EventSubscriber",
"EventDeclaration",
"Variable",
"LocalVariable",
"GlobalVariable",
"Parameter",
"VarParameter",
"ReturnValue",
"Object",
"Field",
Expand All @@ -65,9 +68,10 @@
}
},
"UseSequentialGuidScope": {
"type": "string",
"enum": ["AllGuidFields"],
"description": "Controls the scope of the sequential GUID check. When set to 'AllGuidFields', all CreateGuid() calls are flagged, not just those in primary key fields. Used by PC0029."
"type": ["string", "null"],
"enum": ["AllGuidFields", null],
"default": null,
"description": "Controls the scope of the sequential GUID check. When set to 'AllGuidFields', all CreateGuid() calls are flagged, not just those in primary key fields. Used by PC0029. Default: null"
},
"ToolTipAllowedPunctuations": {
"type": "array",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using RoslynTestKit;
using System.Text.Json;
using NamingPatternTarget = ALCops.LinterCop.Analyzers.NamingPattern.NamingTarget;
using NamingPatternConfig = ALCops.LinterCop.Analyzers.NamingPattern.NamingPatternConfig;
using NamingPatternSetting = ALCops.Common.Settings.NamingPattern;
Expand Down Expand Up @@ -67,6 +68,68 @@ public async Task InheritanceFallsBackToVariableWhenOnlyVariableHasOverride(
Assert.That(actual, Is.EqualTo(expected));
}

[Test]
public void NamingTargetEnumMatchesSchemaPropertyNames()
{
string repoRoot = FindRepositoryRoot();
string schemaPath = Path.Combine(repoRoot, "src", "ALCops.Common", "Settings", "alcops.schema.json");

Assert.That(File.Exists(schemaPath), Is.True, $"Schema file not found: {schemaPath}");

using JsonDocument document = JsonDocument.Parse(File.ReadAllText(schemaPath));

JsonElement enumValues = document.RootElement
.GetProperty("properties")
.GetProperty("NamingPatterns")
.GetProperty("propertyNames")
.GetProperty("enum");

var schemaTargets = enumValues
.EnumerateArray()
.Where(item => item.ValueKind == JsonValueKind.String)
.Select(item => item.GetString())
.OfType<string>()
.ToHashSet(StringComparer.Ordinal);

var namingTargets = Enum.GetNames(typeof(NamingPatternTarget))
.ToHashSet(StringComparer.Ordinal);

var missingInSchema = namingTargets.Except(schemaTargets).OrderBy(name => name).ToArray();
var extraInSchema = schemaTargets.Except(namingTargets).OrderBy(name => name).ToArray();

Assert.Multiple(() =>
{
Assert.That(
missingInSchema,
Is.Empty,
$"NamingTarget enum values missing in schema: {string.Join(", ", missingInSchema)}");

Assert.That(
extraInSchema,
Is.Empty,
$"Schema contains unknown NamingPatterns targets: {string.Join(", ", extraInSchema)}");
});
}

private static string FindRepositoryRoot()
{
var current = new DirectoryInfo(Environment.CurrentDirectory);

while (current is not null)
{
if (File.Exists(Path.Combine(current.FullName, "ALCops.sln")))
{
return current.FullName;
}

current = current.Parent;
}

Assert.Fail("Could not locate repository root (ALCops.sln).");

return string.Empty;
}

private static string AllowPatternFor(string targetName) => $"{targetName}_Allow";
private static string DisallowPatternFor(string targetName) => $"{targetName}_Disallow";

Expand Down
Loading