| | | 1 | | using System.Text.RegularExpressions; |
| | | 2 | | |
| | | 3 | | namespace AspxLint.Core.Rules; |
| | | 4 | | |
| | | 5 | | public sealed class Dir001PageDirective : IRule |
| | | 6 | | { |
| | 255 | 7 | | public string Id => "DIR-001"; |
| | 70 | 8 | | public string Name => "Directive de page absente ou mal placee"; |
| | 67 | 9 | | public Severity Severity => Severity.Error; |
| | | 10 | | public string Description => |
| | 25 | 11 | | "Un fichier ASPX doit commencer par <%@ Page ... %>, un ASCX par <%@ Control ... %>, un MASTER par <%@ Master .. |
| | 46 | 12 | | public bool HasFix => true; |
| | | 13 | | |
| | 152 | 14 | | private static string? Expected(string ext) => ext switch |
| | 152 | 15 | | { |
| | 132 | 16 | | "aspx" => "Page", |
| | 10 | 17 | | "ascx" => "Control", |
| | 6 | 18 | | "master" => "Master", |
| | 4 | 19 | | _ => null |
| | 152 | 20 | | }; |
| | | 21 | | |
| | | 22 | | public IEnumerable<Issue> Detect(string content, string[] lines, RuleContext ctx) |
| | | 23 | | { |
| | | 24 | | var expected = Expected(ctx.Ext); |
| | | 25 | | if (expected is null) yield break; |
| | | 26 | | |
| | | 27 | | int firstNonEmpty = -1; |
| | | 28 | | for (int i = 0; i < lines.Length; i++) |
| | | 29 | | { |
| | | 30 | | if (!string.IsNullOrWhiteSpace(lines[i])) { firstNonEmpty = i; break; } |
| | | 31 | | } |
| | | 32 | | if (firstNonEmpty < 0) yield break; |
| | | 33 | | |
| | | 34 | | var re = new Regex(@"<%@\s*" + expected + @"\b", RegexOptions.IgnoreCase); |
| | | 35 | | var hasDirective = lines.Any(l => re.IsMatch(l)); |
| | | 36 | | |
| | | 37 | | if (!hasDirective) |
| | | 38 | | { |
| | | 39 | | yield return new Issue(Id, Name, Severity, 1, 1, |
| | | 40 | | lines[firstNonEmpty], |
| | | 41 | | $"Directive @{expected} manquante. Ajoutez-la en premiere ligne."); |
| | | 42 | | } |
| | | 43 | | else if (firstNonEmpty > 0 && !re.IsMatch(lines[firstNonEmpty])) |
| | | 44 | | { |
| | | 45 | | int dirLine = -1; |
| | | 46 | | for (int i = 0; i < lines.Length; i++) |
| | | 47 | | if (re.IsMatch(lines[i])) { dirLine = i; break; } |
| | | 48 | | |
| | | 49 | | if (dirLine != firstNonEmpty && dirLine >= 0) |
| | | 50 | | yield return new Issue(Id, Name, Severity, dirLine + 1, 1, |
| | | 51 | | lines[dirLine], |
| | | 52 | | $"La directive @{expected} doit etre la premiere ligne non vide du fichier."); |
| | | 53 | | } |
| | | 54 | | } |
| | | 55 | | |
| | | 56 | | public string? Fix(string content, RuleContext ctx) |
| | | 57 | | { |
| | 33 | 58 | | var expected = Expected(ctx.Ext); |
| | 33 | 59 | | if (expected is null) return content; |
| | | 60 | | |
| | 33 | 61 | | var re = new Regex(@"<%@\s*" + expected + @"\b", RegexOptions.IgnoreCase); |
| | 33 | 62 | | var lines = content.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None).ToList(); |
| | 33 | 63 | | int dirIndex = -1; |
| | 188 | 64 | | for (int i = 0; i < lines.Count; i++) |
| | 97 | 65 | | if (re.IsMatch(lines[i])) { dirIndex = i; break; } |
| | | 66 | | |
| | 33 | 67 | | if (dirIndex < 0) |
| | | 68 | | { |
| | 21 | 69 | | var stub = $"<%@ {expected} Language=\"C#\" AutoEventWireup=\"true\" %>"; |
| | 21 | 70 | | return stub + "\n" + content; |
| | | 71 | | } |
| | 12 | 72 | | if (dirIndex > 0) |
| | | 73 | | { |
| | 2 | 74 | | var dirLine = lines[dirIndex]; |
| | 2 | 75 | | lines.RemoveAt(dirIndex); |
| | 2 | 76 | | while (lines.Count > 0 && string.IsNullOrWhiteSpace(lines[0])) lines.RemoveAt(0); |
| | 2 | 77 | | lines.Insert(0, dirLine); |
| | 2 | 78 | | return string.Join("\n", lines); |
| | | 79 | | } |
| | 10 | 80 | | return content; |
| | | 81 | | } |
| | | 82 | | } |