diff --git a/.fantomasignore b/.fantomasignore new file mode 100644 index 000000000..23053de09 --- /dev/null +++ b/.fantomasignore @@ -0,0 +1 @@ +packages/ diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 01520056b..714c2ae5d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -225,6 +225,8 @@ jobs: run: dotnet fsi scripts/inconsistentNugetVersionsInFSharpScripts.fsx - name: Check there are no non-verbose flags in scripts and CI YML files run: dotnet fsi scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx + - name: Check there is no unacceptable TypeScript keywords in .ts files + run: dotnet fsi scripts/unacceptableTypeScript.fsx - name: Sanity check nuget packages of .NET projects run: | dotnet restore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..294bb45c6 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +src/FileConventions.Test/DummyFiles/* diff --git a/scripts/eofConvention.fsx b/scripts/eofConvention.fsx index fee536187..81e0bd13e 100755 --- a/scripts/eofConvention.fsx +++ b/scripts/eofConvention.fsx @@ -3,9 +3,9 @@ open System.IO open System +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" - #load "../src/FileConventions/Helpers.fs" #load "../src/FileConventions/Library.fs" diff --git a/scripts/executableConvention.fsx b/scripts/executableConvention.fsx index fd413884d..e75649a10 100755 --- a/scripts/executableConvention.fsx +++ b/scripts/executableConvention.fsx @@ -3,6 +3,7 @@ open System open System.IO +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" #load "../src/FileConventions/Library.fs" diff --git a/scripts/inconsistentNugetVersionsInDotNetProjectsAndFSharpScripts.fsx b/scripts/inconsistentNugetVersionsInDotNetProjectsAndFSharpScripts.fsx index f44b24479..0d850a6c6 100755 --- a/scripts/inconsistentNugetVersionsInDotNetProjectsAndFSharpScripts.fsx +++ b/scripts/inconsistentNugetVersionsInDotNetProjectsAndFSharpScripts.fsx @@ -7,6 +7,7 @@ open System.IO #r "nuget: Fsdk, Version=0.9.99--date20260525-0605.git-a5cfc39" #r "nuget: Microsoft.Build, Version=17.8.43" +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" diff --git a/scripts/inconsistentNugetVersionsInFSharpScripts.fsx b/scripts/inconsistentNugetVersionsInFSharpScripts.fsx index 98a552b13..5cbcaf483 100755 --- a/scripts/inconsistentNugetVersionsInFSharpScripts.fsx +++ b/scripts/inconsistentNugetVersionsInFSharpScripts.fsx @@ -3,9 +3,9 @@ open System.IO open System.Linq +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" - #load "../src/FileConventions/Library.fs" #load "../src/FileConventions/Helpers.fs" diff --git a/scripts/inconsistentVersionsInGitHubCI.fsx b/scripts/inconsistentVersionsInGitHubCI.fsx index dd61a939e..eeb3d8114 100755 --- a/scripts/inconsistentVersionsInGitHubCI.fsx +++ b/scripts/inconsistentVersionsInGitHubCI.fsx @@ -2,9 +2,9 @@ open System.IO +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" - #load "../src/FileConventions/Library.fs" #load "../src/FileConventions/Helpers.fs" diff --git a/scripts/mixedLineEndings.fsx b/scripts/mixedLineEndings.fsx index 208b0dca3..114d64898 100755 --- a/scripts/mixedLineEndings.fsx +++ b/scripts/mixedLineEndings.fsx @@ -3,9 +3,9 @@ open System open System.IO +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" - #load "../src/FileConventions/Library.fs" #load "../src/FileConventions/Helpers.fs" diff --git a/scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx b/scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx index 6532ccf0f..6bc8641e3 100755 --- a/scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx +++ b/scripts/nonVerboseFlagsInGitHubCIAndScripts.fsx @@ -3,9 +3,9 @@ open System open System.IO +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" - #load "../src/FileConventions/Library.fs" #load "../src/FileConventions/Helpers.fs" diff --git a/scripts/shebangConvention.fsx b/scripts/shebangConvention.fsx index ceb39ddff..b68c28772 100755 --- a/scripts/shebangConvention.fsx +++ b/scripts/shebangConvention.fsx @@ -3,9 +3,9 @@ open System open System.IO +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" - #load "../src/FileConventions/Library.fs" #load "../src/FileConventions/Helpers.fs" diff --git a/scripts/unacceptableTypeScript.fsx b/scripts/unacceptableTypeScript.fsx new file mode 100755 index 000000000..86ec3d2ab --- /dev/null +++ b/scripts/unacceptableTypeScript.fsx @@ -0,0 +1,28 @@ +#!/usr/bin/env -S dotnet fsi + +open System +open System.IO + +#r "nuget: FSharpx.Collections, Version=3.1.0" +#r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" +#r "nuget: YamlDotNet, Version=16.1.3" +#load "../src/FileConventions/Library.fs" +#load "../src/FileConventions/Helpers.fs" + +let rootDir = Path.Combine(__SOURCE_DIRECTORY__, "..") |> DirectoryInfo + +let validExtensions = seq { ".ts" } + +let invalidFiles = + validExtensions + |> Seq.collect(fun ext -> + Helpers.GetInvalidFiles + rootDir + ("*" + ext) + FileConventions.ContainsUnacceptableTypeScript + ) + +let message = + "Please don't use unacceptable TypeScript keywords (e.g. 'any') in the following files:" + +Helpers.AssertNoInvalidFiles invalidFiles message diff --git a/scripts/unpinnedDotnetToolInstallVersions.fsx b/scripts/unpinnedDotnetToolInstallVersions.fsx index 304a66dbe..bc9eaf448 100755 --- a/scripts/unpinnedDotnetToolInstallVersions.fsx +++ b/scripts/unpinnedDotnetToolInstallVersions.fsx @@ -3,9 +3,9 @@ open System open System.IO +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" - #load "../src/FileConventions/Library.fs" #load "../src/FileConventions/Helpers.fs" diff --git a/scripts/unpinnedGitHubActionsImageVersions.fsx b/scripts/unpinnedGitHubActionsImageVersions.fsx index 833af568b..caffd8b88 100755 --- a/scripts/unpinnedGitHubActionsImageVersions.fsx +++ b/scripts/unpinnedGitHubActionsImageVersions.fsx @@ -3,9 +3,9 @@ open System open System.IO +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" - #load "../src/FileConventions/Library.fs" #load "../src/FileConventions/Helpers.fs" diff --git a/scripts/unpinnedNugetPackageReferenceVersionsInFSharpScripts.fsx b/scripts/unpinnedNugetPackageReferenceVersionsInFSharpScripts.fsx index d48fc1e29..de260dcc0 100755 --- a/scripts/unpinnedNugetPackageReferenceVersionsInFSharpScripts.fsx +++ b/scripts/unpinnedNugetPackageReferenceVersionsInFSharpScripts.fsx @@ -3,9 +3,9 @@ open System open System.IO +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" - #load "../src/FileConventions/Library.fs" #load "../src/FileConventions/Helpers.fs" diff --git a/scripts/unpinnedNugetPackageReferenceVersionsInProjects.fsx b/scripts/unpinnedNugetPackageReferenceVersionsInProjects.fsx index 9cbf74d25..bd50b162f 100755 --- a/scripts/unpinnedNugetPackageReferenceVersionsInProjects.fsx +++ b/scripts/unpinnedNugetPackageReferenceVersionsInProjects.fsx @@ -3,9 +3,9 @@ open System open System.IO +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" - #load "../src/FileConventions/Library.fs" #load "../src/FileConventions/Helpers.fs" diff --git a/scripts/wrapLatestCommitMsg.fsx b/scripts/wrapLatestCommitMsg.fsx index 9f16164fc..ff073484e 100755 --- a/scripts/wrapLatestCommitMsg.fsx +++ b/scripts/wrapLatestCommitMsg.fsx @@ -5,6 +5,7 @@ open System open System.Text.RegularExpressions open System.Linq +#r "nuget: FSharpx.Collections, Version=3.1.0" #r "nuget: Mono.Unix, Version=7.1.0-final.1.21458.1" #r "nuget: YamlDotNet, Version=16.1.3" diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptBadExample1.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptBadExample1.ts new file mode 100644 index 000000000..1da7cbe18 --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptBadExample1.ts @@ -0,0 +1,3 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +const message: any = "Hello, World!"; +console.log(message); diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptBadExample2.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptBadExample2.ts new file mode 100644 index 000000000..6653b1e8e --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptBadExample2.ts @@ -0,0 +1,3 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +const message: /* hehe */ any = "Hello, World!"; +console.log(message); diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptBadExample3.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptBadExample3.ts new file mode 100644 index 000000000..be5a94a8a --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptBadExample3.ts @@ -0,0 +1,2 @@ +const obj: { a?: number } = { a: 1 }; +delete obj.a; diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample1.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample1.ts new file mode 100644 index 000000000..824e1d992 --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample1.ts @@ -0,0 +1,2 @@ +const message: string = "Hello, World!"; +console.log(message); diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample10.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample10.ts new file mode 100644 index 000000000..f7b65be8d --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample10.ts @@ -0,0 +1,3 @@ +/* eslint @typescript-eslint/no-explicit-any: "off" */ +const message: any = "Hello, World!"; +console.log(message); diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample11.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample11.ts new file mode 100644 index 000000000..ac6aa13cb --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample11.ts @@ -0,0 +1,3 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const message: any = "Hello, World!"; +console.log(message); diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample2.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample2.ts new file mode 100644 index 000000000..9703e0d59 --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample2.ts @@ -0,0 +1,2 @@ +const anythingToSay: string = "Hello, World!"; +console.log(anythingToSay); diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample3.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample3.ts new file mode 100644 index 000000000..bdba2b838 --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample3.ts @@ -0,0 +1,2 @@ +const message: string = "Hello, any world!"; +console.log(message); diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample4.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample4.ts new file mode 100644 index 000000000..14645dcca --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample4.ts @@ -0,0 +1,2 @@ +const message: string = "Hello, world!" + "any time!"; +console.log(message); diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample5.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample5.ts new file mode 100644 index 000000000..e14818a86 --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample5.ts @@ -0,0 +1,4 @@ +const message: string = 'time any!'; +console.log(message); +const message2: string = `any time!`; +console.log(message2); diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample6.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample6.ts new file mode 100644 index 000000000..e6f38ee76 --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample6.ts @@ -0,0 +1,2 @@ +const message: string = 'hello world!'; // any time! +console.log(message); diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample7.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample7.ts new file mode 100644 index 000000000..6065bfb0c --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample7.ts @@ -0,0 +1,2 @@ +const message: string = 'hello world!'; /* any time! */ +console.log(message); diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample8.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample8.ts new file mode 100644 index 000000000..d6dd8eb9c --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample8.ts @@ -0,0 +1,3 @@ +const message: string = 'hello world!'; /* +any time */ +console.log(message); diff --git a/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample9.ts b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample9.ts new file mode 100644 index 000000000..89910a0cf --- /dev/null +++ b/src/FileConventions.Test/DummyFiles/DummyUnacceptableTypeScriptGoodExample9.ts @@ -0,0 +1,6 @@ +const message: string = `foo +any time`; +console.log(message); +const message2: string = 'bar\ +any time'; +console.log(message2); diff --git a/src/FileConventions.Test/FileConventions.Test.fs b/src/FileConventions.Test/FileConventions.Test.fs index ca24a71e7..067f37c99 100644 --- a/src/FileConventions.Test/FileConventions.Test.fs +++ b/src/FileConventions.Test/FileConventions.Test.fs @@ -674,3 +674,185 @@ let IsExecutableTest2() = )) Assert.That(IsExecutable fileInfo, Is.EqualTo false) + +[] +let ContainsUnacceptableTypeScriptTest1() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptBadExample1.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo true) + +[] +let ContainsUnacceptableTypeScriptTest2() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptGoodExample1.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo false) + +[] +let ContainsUnacceptableTypeScriptTest3() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptGoodExample2.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo false) + +[] +let ContainsUnacceptableTypeScriptTest4() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptGoodExample3.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo false) + +[] +let ContainsUnacceptableTypeScriptTest5() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptGoodExample4.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo false) + +[] +let ContainsUnacceptableTypeScriptTest6() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptGoodExample5.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo false) + +[] +let ContainsUnacceptableTypeScriptTest7() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptGoodExample6.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo false) + +[] +let ContainsUnacceptableTypeScriptTest8() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptGoodExample7.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo false) + +[] +let ContainsUnacceptableTypeScriptTest9() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptBadExample2.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo true) + +[] +let ContainsUnacceptableTypeScriptTest10() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptGoodExample8.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo false) + +[] +let ContainsUnacceptableTypeScriptTest11() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptGoodExample9.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo false) + +[] +let ContainsUnacceptableTypeScriptTest12() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptGoodExample10.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo false) + +[] +let ContainsUnacceptableTypeScriptTest13() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptBadExample3.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo true) + +[] +let ContainsUnacceptableTypeScriptTest14() = + let fileInfo = + (FileInfo( + Path.Combine( + __SOURCE_DIRECTORY__, + "DummyFiles", + "DummyUnacceptableTypeScriptGoodExample11.ts" + ) + )) + + Assert.That(ContainsUnacceptableTypeScript fileInfo, Is.EqualTo false) diff --git a/src/FileConventions/FileConventions.fsproj b/src/FileConventions/FileConventions.fsproj index 35063d840..d62bfac98 100644 --- a/src/FileConventions/FileConventions.fsproj +++ b/src/FileConventions/FileConventions.fsproj @@ -13,6 +13,7 @@ + diff --git a/src/FileConventions/Library.fs b/src/FileConventions/Library.fs index 6fac0339e..7118e6aac 100644 --- a/src/FileConventions/Library.fs +++ b/src/FileConventions/Library.fs @@ -3,8 +3,10 @@ open System open System.IO open System.Linq +open System.Text open System.Text.RegularExpressions +open FSharpx.Collections open Mono open Mono.Unix.Native open YamlDotNet.RepresentationModel @@ -540,6 +542,8 @@ let DetectInconsistentVersionsInFSharpScripts DetectInconsistentVersionsInNugetRefsInFSharpScripts fsxFiles let allowedNonVerboseFlags = + // TODO: add flags 'd' and 'x' for "git clean" but with tests that detect + // "foo -ab" as invalid cause I workarounded the prob for now with "-fdx" seq { "unzip" @@ -591,3 +595,165 @@ let NonVerboseFlags(fileInfo: FileInfo) = let IsExecutable(fileInfo: FileInfo) = let hasExecuteAccess = Syscall.access(fileInfo.FullName, AccessModes.X_OK) hasExecuteAccess = 0 + +let anyRegex = Regex(@"\bany\b", RegexOptions.Compiled) +let deleteRegex = Regex(@"\bdelete\b", RegexOptions.Compiled) +let stringCharMarkers = [ '"'; '\''; '`' ] |> Seq.map string +let singleLineCommentMarker = "//" +let multiLineCommentMarker = "/*" +let anyEslintRuleName = "@typescript-eslint/no-explicit-any" + +let anyEslintDisableNextLineComment = + $"// eslint-disable-next-line {anyEslintRuleName}" + +let anyEsLintDisableRuleForWholeFileComment = + $"/* eslint {anyEslintRuleName}: \"off\" */" + +let commentMarkers = + [ + singleLineCommentMarker + multiLineCommentMarker + ] + +let ContainsUnacceptableTypeScript(fileInfo: FileInfo) = + let rec substractAllSubstringsFromString + (leString: string) + : string * Option = + let substractFirstSubstringFromString + (leString: string) + : string * Option = + let findEarliestSubstring + (text: string) + (targetSubstrings: seq) + = + text + |> Seq.indexed + |> Seq.tryPick(fun (currentIndex, _) -> + targetSubstrings + |> Seq.tryFind(fun target -> + // Check if the text contains the target starting at this specific index + text.IndexOf(target, currentIndex) = currentIndex + ) + |> Option.map(fun foundMatch -> (currentIndex, foundMatch)) + ) + + let allMarkers = Seq.append stringCharMarkers commentMarkers + + let maybeBeginIndexOfStringOrComment = + findEarliestSubstring leString allMarkers + + match maybeBeginIndexOfStringOrComment with + | None -> (leString, None) + | Some(beginIndexOfString, marker) -> + let beforePart = leString.Substring(0, beginIndexOfString) + + if marker = singleLineCommentMarker then + (beforePart, None) + else + let restOfString = + leString.Substring(beginIndexOfString + 1) + + let endMarker = + if marker = multiLineCommentMarker then + "*/" + else + marker + + let endIndexOfString = restOfString.IndexOf endMarker + + if endIndexOfString < 0 then + (beforePart, Some marker) + else + let afterPart = + (restOfString.Substring(endIndexOfString + 1)) + + (beforePart + afterPart, None) + + let (substracted, maybeEndMarker) = + substractFirstSubstringFromString leString + + match maybeEndMarker with + | None -> + if substracted = leString then + (substracted, None) + else + substractAllSubstringsFromString substracted + | Some lookingForThisEndMarker -> + (substracted, Some lookingForThisEndMarker) + + let rec findContentToAnalyze + (nextLines: seq) + (contentSoFar: StringBuilder) + (maybeLookingForThisEndMarker: Option) + : unit = + match Seq.tryHeadTail nextLines with + | None -> () + | Some(line, tail) -> + match maybeLookingForThisEndMarker with + | None -> + let (cleanString, maybeEndMarker) = + substractAllSubstringsFromString line + + contentSoFar.AppendLine cleanString |> ignore + findContentToAnalyze tail contentSoFar maybeEndMarker + | Some lookingForThisEndMarker -> + let indexOfEndMarker = line.IndexOf lookingForThisEndMarker + + if indexOfEndMarker < 0 then + findContentToAnalyze + tail + contentSoFar + (Some lookingForThisEndMarker) + else + let afterPart = line.Substring indexOfEndMarker + + let cleanString, maybeEndMarker = + substractAllSubstringsFromString afterPart + + contentSoFar.AppendLine cleanString |> ignore + findContentToAnalyze tail contentSoFar maybeEndMarker + + let getTypeScriptContentToAnalyze(fileLines: seq) : string = + let wholeFileContentButTheStrings = StringBuilder() + findContentToAnalyze fileLines wholeFileContentButTheStrings None + wholeFileContentButTheStrings.ToString() + + let fileLines = File.ReadLines fileInfo.FullName |> Seq.toList + + let hasFileLevelEslintDisableComment = + match fileLines with + | firstLine :: _ -> + firstLine + .Trim() + .StartsWith anyEsLintDisableRuleForWholeFileComment + | [] -> false + + let contentToAnalyze = getTypeScriptContentToAnalyze fileLines + let hasDelete = deleteRegex.IsMatch(contentToAnalyze) + + let hasAny = + if hasFileLevelEslintDisableComment then + false + else + let filteredLines = + fileLines + |> Seq.mapi(fun lineIndex line -> lineIndex, line) + |> Seq.choose(fun (lineIndex, line) -> + let prevLineHasDisableNextLine = + if lineIndex > 0 then + fileLines.[lineIndex - 1] + .Trim() + .StartsWith anyEslintDisableNextLineComment + else + false + + if prevLineHasDisableNextLine then + None + else + Some line + ) + + let filteredContent = getTypeScriptContentToAnalyze filteredLines + anyRegex.IsMatch(filteredContent) + + hasAny || hasDelete