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

Moar fantomas #614

Merged
merged 4 commits into from
Sep 5, 2024
Merged
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
2 changes: 1 addition & 1 deletion .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"fantomas": {
"version": "6.3.1",
"version": "6.3.11",
"commands": [
"fantomas"
]
Expand Down
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*.{fs,fsi,fsx}]
end_of_line = lf
fsharp_multiline_bracket_style = aligned
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Easier for source controle diff.

fsharp_multi_line_lambda_closing_newline = true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bit of a personal preference.


[{tests,samples}/**/*.fs]
fsharp_experimental_elmish = true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formats expressions like foo [ bar1 ; bar2 ] nicer.

7 changes: 6 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
* text=auto
*.sh text eol=lf
*.sh text eol=lf

# Always use lf for F# files
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Life is easier when all files are lf.
Your editor most likely uses LF internally anyway (Rider and code do).

*.fs text eol=lf
*.fsx text eol=lf
*.fsi text eol=lf
12 changes: 7 additions & 5 deletions .github/workflows/fantomas-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@ on:
pull_request:
paths:
- 'samples/**'
- 'src/**'
- 'tests/**'

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
fantomas-check:
name: Fantomas check the
name: Code format check
runs-on: ubuntu-22.04
strategy:
matrix:
CHECK_FOLDER: [ 'samples/' ]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Restore packages
run: dotnet tool restore
- name: Run Fantomas
run: dotnet fantomas --check "${{ matrix.CHECK_FOLDER }}"
run: dotnet fantomas --check src samples tests
- name: log failure
if: failure()
run: echo "Some files need formatting, please run 'dotnet fantomas src samples tests'"
21 changes: 3 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,25 +235,10 @@ Please be aware that Giraffe strictly aims to remain as light as possible while

### Code conventions

When making changes please use existing code as a guideline for coding style and documentation. For example add spaces when creating tuples (`(a,b)` --> `(a, b)`), annotating variable types (`str:string` --> `str : string`) or other language constructs.
We use [Fantomas](https://fsprojects.github.io/fantomas/docs/index.html) to ensure consistent code formatting across the project. Before committing, format your code by running the following command:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not do any attempt to keep the rules. They were implemented inconsistent anyway and I feel like the default from the style guide suffice here.


Examples:

```fsharp
let someHttpHandler:HttpHandler =
fun (ctx:HttpContext) next -> task {
// Some work
}
```

should be:

```fsharp
let someHttpHandler : HttpHandler =
fun (ctx : HttpContext) (next : HttpFunc) ->
task {
// Some work
}
```bash
dotnet fantomas src samples tests
```

### Keep documentation and unit tests up to date
Expand Down
22 changes: 13 additions & 9 deletions samples/EndpointRoutingApp/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,22 @@ let handler3 (a: string, b: string, c: string, d: int) : HttpHandler =
fun (_: HttpFunc) (ctx: HttpContext) -> sprintf "Hello %s %s %s %i" a b c d |> ctx.WriteTextAsync

let endpoints =
[ subRoute "/foo" [ GET [ route "/bar" (text "Aloha!") ] ]
GET
[ route "/" (text "Hello World")
[
subRoute "/foo" [ GET [ route "/bar" (text "Aloha!") ] ]
GET [
route "/" (text "Hello World")
routef "/%s/%i" handler2
routef "/%s/%s/%s/%i" handler3 ]
GET_HEAD
[ route "/foo" (text "Bar")
routef "/%s/%s/%s/%i" handler3
]
GET_HEAD [
route "/foo" (text "Bar")
route "/x" (text "y")
route "/abc" (text "def")
route "/123" (text "456") ]
// Not specifying a http verb means it will listen to all verbs
subRoute "/sub" [ route "/test" handler1 ] ]
route "/123" (text "456")
]
// Not specifying a http verb means it will listen to all verbs
subRoute "/sub" [ route "/test" handler1 ]
]

let notFoundHandler = "Not Found" |> text |> RequestErrors.notFound

Expand Down
3 changes: 2 additions & 1 deletion samples/NewtonsoftJson/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ let configureServices (services: IServiceCollection) =
JsonSerializerSettings(),
serviceProvider.GetService<Microsoft.IO.RecyclableMemoryStreamManager>()
)
:> Json.ISerializer)
:> Json.ISerializer
)
.AddRouting()
.AddResponseCaching()
.AddGiraffe()
Expand Down
19 changes: 11 additions & 8 deletions samples/ResponseCachingApp/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,17 @@ let responseCachingMiddleware: HttpHandler =
(Some [| "query1"; "query2" |])

let endpoints: Endpoint list =
[ subRoute
"/cached"
[ GET
[ route "/public" (publicResponseCaching 30 None >=> dateTimeHandler)
route "/private" (privateResponseCaching 30 None >=> dateTimeHandler)
route "/not" (noResponseCaching >=> dateTimeHandler)
route "/vary/not" (publicResponseCaching 30 None >=> dateTimeHandler)
route "/vary/yes" (responseCachingMiddleware >=> dateTimeHandler) ] ] ]
[
subRoute "/cached" [
GET [
route "/public" (publicResponseCaching 30 None >=> dateTimeHandler)
route "/private" (privateResponseCaching 30 None >=> dateTimeHandler)
route "/not" (noResponseCaching >=> dateTimeHandler)
route "/vary/not" (publicResponseCaching 30 None >=> dateTimeHandler)
route "/vary/yes" (responseCachingMiddleware >=> dateTimeHandler)
]
]
]

let notFoundHandler = "Not Found" |> text |> RequestErrors.notFound

Expand Down
18 changes: 11 additions & 7 deletions samples/ResponseCachingApp/test-run.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ type Url = Url of string
type Title = Title of string

let urls =
{| notCached = Url "http://localhost:5000/cached/not"
publicCached = Url "http://localhost:5000/cached/public"
privateCached = Url "http://localhost:5000/cached/private"
publicCachedNoVaryByQueryKeys = Url "http://localhost:5000/cached/vary/not"
cachedVaryByQueryKeys = Url "http://localhost:5000/cached/vary/yes" |}
{|
notCached = Url "http://localhost:5000/cached/not"
publicCached = Url "http://localhost:5000/cached/public"
privateCached = Url "http://localhost:5000/cached/private"
publicCachedNoVaryByQueryKeys = Url "http://localhost:5000/cached/vary/not"
cachedVaryByQueryKeys = Url "http://localhost:5000/cached/vary/yes"
|}

let queryParams1: QueryParams = [ ("query1", "a"); ("query2", "b") ]
let queryParams2: QueryParams = [ ("query1", "c"); ("query2", "d") ]
Expand Down Expand Up @@ -59,8 +61,10 @@ let run (qps: QueryParams list) (title: Title) (url: Url) =

let runFiveRequests =
run
[ for _ in 1..5 do
[] ]
[
for _ in 1..5 do
[]
]

let testPublicCachedNoVaryByQueryKeys () =
let allQueryParams = [ queryParams1; queryParams1; queryParams2; queryParams2 ]
Expand Down
70 changes: 40 additions & 30 deletions src/Giraffe/Auth.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ module Auth =
open Microsoft.AspNetCore.Http
open Microsoft.AspNetCore.Authentication
open Microsoft.AspNetCore.Authorization

/// <summary>
/// Challenges a client to authenticate via a specific authScheme.
/// </summary>
/// <param name="authScheme">The name of an authentication scheme from your application.</param>
/// <param name="next"></param>
/// <param name="ctx"></param>
/// <returns>A Giraffe <see cref="HttpHandler"/> function which can be composed into a bigger web application.</returns>
let challenge (authScheme : string) : HttpHandler =
fun (next : HttpFunc) (ctx : HttpContext) ->
let challenge (authScheme: string) : HttpHandler =
fun (next: HttpFunc) (ctx: HttpContext) ->
task {
do! ctx.ChallengeAsync authScheme
return! next ctx
Expand All @@ -29,8 +29,8 @@ module Auth =
/// <param name="next"></param>
/// <param name="ctx"></param>
/// <returns>A Giraffe <see cref="HttpHandler"/> function which can be composed into a bigger web application.</returns>
let signOut (authScheme : string) : HttpHandler =
fun (next : HttpFunc) (ctx : HttpContext) ->
let signOut (authScheme: string) : HttpHandler =
fun (next: HttpFunc) (ctx: HttpContext) ->
task {
do! ctx.SignOutAsync authScheme
return! next ctx
Expand All @@ -44,9 +44,13 @@ module Auth =
/// <param name="next"></param>
/// <param name="ctx"></param>
/// <returns>A Giraffe <see cref="HttpHandler"/> function which can be composed into a bigger web application.</returns>
let authorizeRequest (predicate : HttpContext -> bool) (authFailedHandler : HttpHandler) : HttpHandler =
fun (next : HttpFunc) (ctx : HttpContext) ->
(if predicate ctx then next else authFailedHandler earlyReturn) ctx
let authorizeRequest (predicate: HttpContext -> bool) (authFailedHandler: HttpHandler) : HttpHandler =
fun (next: HttpFunc) (ctx: HttpContext) ->
(if predicate ctx then
next
else
authFailedHandler earlyReturn)
ctx

[<Obsolete("Please use `authorizeUser` as a replacement for `evaluateUserPolicy`. In the next major version this function will be removed.")>]
/// <summary>
Expand All @@ -55,10 +59,8 @@ module Auth =
/// <param name="policy">One or many conditions which a <see cref="System.Security.Claims.ClaimsPrincipal"/> must meet. The policy function should return true on success and false on failure.</param>
/// <param name="authFailedHandler">A <see cref="HttpHandler"/> function which will be executed when the policy returns false.</param>
/// <returns>A Giraffe <see cref="HttpHandler"/> function which can be composed into a bigger web application.</returns>
let evaluateUserPolicy (policy : ClaimsPrincipal -> bool) (authFailedHandler : HttpHandler) : HttpHandler =
authorizeRequest
(fun ctx -> policy ctx.User)
authFailedHandler
let evaluateUserPolicy (policy: ClaimsPrincipal -> bool) (authFailedHandler: HttpHandler) : HttpHandler =
authorizeRequest (fun ctx -> policy ctx.User) authFailedHandler

/// <summary>
/// Validates if a <see cref="System.Security.Claims.ClaimsPrincipal"/> satisfies a certain condition. If the policy returns true then it will continue with the next function otherwise it will short circuit and execute the authFailedHandler.
Expand All @@ -71,7 +73,7 @@ module Auth =
/// </summary>
/// <param name="authFailedHandler">A <see cref="HttpHandler"/> function which will be executed when authentication failed.</param>
/// <returns>A Giraffe <see cref="HttpHandler"/> function which can be composed into a bigger web application.</returns>
let requiresAuthentication (authFailedHandler : HttpHandler) : HttpHandler =
let requiresAuthentication (authFailedHandler: HttpHandler) : HttpHandler =
authorizeUser
(fun user -> isNotNull user && isNotNull user.Identity && user.Identity.IsAuthenticated)
authFailedHandler
Expand All @@ -82,21 +84,17 @@ module Auth =
/// <param name="role">The required role of which a user must be a member of in order to pass the validation.</param>
/// <param name="authFailedHandler">A <see cref="HttpHandler"/> function which will be executed when validation fails.</param>
/// <returns>A Giraffe <see cref="HttpHandler"/> function which can be composed into a bigger web application.</returns>
let requiresRole (role : string) (authFailedHandler : HttpHandler) : HttpHandler =
authorizeUser
(fun user -> user.IsInRole role)
authFailedHandler
let requiresRole (role: string) (authFailedHandler: HttpHandler) : HttpHandler =
authorizeUser (fun user -> user.IsInRole role) authFailedHandler

/// <summary>
/// Validates if a user is a member of at least one of a given list of roles.
/// </summary>
/// <param name="roles">A list of roles of which a user must be a member of (minimum one) in order to pass the validation.</param>
/// <param name="authFailedHandler">A <see cref="HttpHandler"/> function which will be executed when validation fails.</param>
/// <returns>A Giraffe <see cref="HttpHandler"/> function which can be composed into a bigger web application.</returns>
let requiresRoleOf (roles : string list) (authFailedHandler : HttpHandler) : HttpHandler =
authorizeUser
(fun user -> List.exists user.IsInRole roles)
authFailedHandler
let requiresRoleOf (roles: string list) (authFailedHandler: HttpHandler) : HttpHandler =
authorizeUser (fun user -> List.exists user.IsInRole roles) authFailedHandler

/// <summary>
/// Validates if a user meets a given authorization policy.
Expand All @@ -106,12 +104,18 @@ module Auth =
/// <param name="next"></param>
/// <param name="ctx"></param>
/// <returns>A Giraffe <see cref="HttpHandler"/> function which can be composed into a bigger web application.</returns>
let authorizeByPolicyName (policyName : string) (authFailedHandler : HttpHandler) : HttpHandler =
fun (next : HttpFunc) (ctx : HttpContext) ->
let authorizeByPolicyName (policyName: string) (authFailedHandler: HttpHandler) : HttpHandler =
fun (next: HttpFunc) (ctx: HttpContext) ->
task {
let authService = ctx.GetService<IAuthorizationService>()
let! result = authService.AuthorizeAsync (ctx.User, policyName)
return! (if result.Succeeded then next else authFailedHandler earlyReturn) ctx
let! result = authService.AuthorizeAsync(ctx.User, policyName)

return!
(if result.Succeeded then
next
else
authFailedHandler earlyReturn)
ctx
}

/// <summary>
Expand All @@ -122,10 +126,16 @@ module Auth =
/// <param name="next"></param>
/// <param name="ctx"></param>
/// <returns>A Giraffe <see cref="HttpHandler"/> function which can be composed into a bigger web application.</returns>
let authorizeByPolicy (policy : AuthorizationPolicy) (authFailedHandler : HttpHandler) : HttpHandler =
fun (next : HttpFunc) (ctx : HttpContext) ->
let authorizeByPolicy (policy: AuthorizationPolicy) (authFailedHandler: HttpHandler) : HttpHandler =
fun (next: HttpFunc) (ctx: HttpContext) ->
task {
let authService = ctx.GetService<IAuthorizationService>()
let! result = authService.AuthorizeAsync (ctx.User, policy)
return! (if result.Succeeded then next else authFailedHandler earlyReturn) ctx
}
let! result = authService.AuthorizeAsync(ctx.User, policy)

return!
(if result.Succeeded then
next
else
authFailedHandler earlyReturn)
ctx
}
10 changes: 5 additions & 5 deletions src/Giraffe/ComputationExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ module Giraffe.ComputationExpressions
/// Enables control flow and binding of `Option{T}` objects
/// </summary>
type OptionBuilder() =
member __.Bind(v, f) = Option.bind f v
member __.Return v = Some v
member __.Bind(v, f) = Option.bind f v
member __.Return v = Some v
member __.ReturnFrom v = v
member __.Zero() = None
member __.Zero() = None

let opt = OptionBuilder()

Expand All @@ -22,6 +22,6 @@ let opt = OptionBuilder()
/// </summary>
type ResultBuilder() =
member __.Bind(v, f) = Result.bind f v
member __.Return v = Ok v
member __.Return v = Ok v

let res = ResultBuilder()
let res = ResultBuilder()
Loading
Loading