mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-09-11 10:46:25 +03:00
server, CI: use ormolu as a formatter for Haskell sources
### Description - sets up a Makefile target for running ormolu to format and check source code - updates CI to run ormolu instead of stylish-haskell (and to check instead of format actively) Compare #1679. Here's the plan for merging this: 1. merge this PR; at this point, all PRs will fail CI unless they have the `ignore-server-format-checks` label set 2. merge follow-up PR #2404 that does nothing but actually reformats the codebase 3. tag the merge commit as `post-ormolu` (also on `graphql-engine`, for the benefits of community contributors) 4. provide the following script to any devs in order to update their branches: ``` $ git checkout my-feature-branch $ git merge post-ormolu^ $ make format $ git commit -a -m "reformat with ormolu" $ git merge -s ours post-ormolu ``` (I'll put this in the commit message) https://github.com/hasura/graphql-engine-mono/pull/2020 Co-authored-by: Philip Lykke Carlsen <358550+plcplc@users.noreply.github.com> Co-authored-by: Swann Moreau <62569634+evertedsphere@users.noreply.github.com> GitOrigin-RevId: 130f480a6d79967c8d045b7f3a6dec30b10472a7
This commit is contained in:
parent
f1daabab04
commit
a206d04062
34
.github/workflows/server-format.yml
vendored
34
.github/workflows/server-format.yml
vendored
@ -1,34 +0,0 @@
|
||||
name: server format
|
||||
on:
|
||||
label:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'server/**'
|
||||
|
||||
jobs:
|
||||
stylish-haskell:
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.pull_request.labels.*.name, 'ignore-server-format-checks') && github.event.label.name != 'ignore-server-format-checks'"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run stylish-haskell
|
||||
shell: bash
|
||||
run: |
|
||||
if git show -q --pretty=format:"%s" | grep -q "\[no-format\]"; then
|
||||
echo "Found [no-format], skipping."
|
||||
else
|
||||
CHANGED_HS_FILES=$(git diff --name-only origin/${{github.base_ref}}...${{github.sha}} -- "./server/*.hs" | xargs -i -d '\n' sh -c 'ls -d {} 2>/dev/null || true' | sed 's%^server/%%')
|
||||
echo "Changed Haskell files are:"
|
||||
echo "$CHANGED_HS_FILES"
|
||||
cd server
|
||||
curl -sL https://raw.github.com/jaspervdj/stylish-haskell/master/scripts/latest.sh | sh -s $(echo $CHANGED_HS_FILES) -i
|
||||
if [ -n "$(git status --porcelain)" ] ; then
|
||||
echo "Files that needed formatting:"
|
||||
git diff --name-only --diff-filter=M
|
||||
for hfile in $(git status --porcelain | sed -n 's/^ M //p'); do
|
||||
echo "::warning file=server/$hfile::This file needs to be formatted using stylish-haskell.\nRun `cd server && stylish-haskell $hfile` to do so."
|
||||
done
|
||||
fi
|
||||
fi
|
52
Makefile
Normal file
52
Makefile
Normal file
@ -0,0 +1,52 @@
|
||||
# skip contrib with its generated .hs file because it doesn't
|
||||
# come with a cabal file, which can trigger a bug in ormolu
|
||||
FORMAT_HS_FILES = $(shell git ls-files '*.hs' '*.hs-boot' | grep -v '^contrib/')
|
||||
FORMAT_CHANGED_HS_FILES = $(shell git diff --diff-filter=d --name-only `git merge-base HEAD origin/main` \
|
||||
| grep '.*\(hs\|hs-boot\)$$' | grep -v '^contrib/')
|
||||
|
||||
ORMOLU_CHECK_VERSION = 0.3.0.0
|
||||
ORMOLU_ARGS = --cabal-default-extensions
|
||||
ORMOLU = ormolu
|
||||
ORMOLU_VERSION = $(shell $(ORMOLU) --version | awk 'NR==1 { print $$2 }')
|
||||
|
||||
# default target
|
||||
.PHONY: help
|
||||
## help: prints help message
|
||||
help:
|
||||
@echo "Usage:"
|
||||
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
|
||||
|
||||
.PHONY: check-ormolu-version
|
||||
check-ormolu-version:
|
||||
@if ! [ "$(ORMOLU_VERSION)" = "$(ORMOLU_CHECK_VERSION)" ]; then \
|
||||
echo "WARNING: ormolu version mismatch, expected $(ORMOLU_CHECK_VERSION)"; \
|
||||
fi
|
||||
|
||||
.PHONY: format-hs
|
||||
## format-hs: auto-format Haskell source code using ormolu
|
||||
format-hs: check-ormolu-version
|
||||
@echo running ormolu --mode inplace
|
||||
@$(ORMOLU) $(ORMOLU_ARGS) --mode inplace $(FORMAT_HS_FILES)
|
||||
|
||||
.PHONY: format-hs-changed
|
||||
## format-hs-changed: auto-format Haskell source code using ormolu (changed files only)
|
||||
format-hs-changed: check-ormolu-version
|
||||
@echo running ormolu --mode inplace
|
||||
@if [ -n "$(FORMAT_CHANGED_HS_FILES)" ]; then \
|
||||
$(ORMOLU) $(ORMOLU_ARGS) --mode inplace $(FORMAT_CHANGED_HS_FILES); \
|
||||
fi
|
||||
|
||||
.PHONY: check-format-hs
|
||||
## check-format-hs: check Haskell source code formatting using ormolu
|
||||
check-format-hs: check-ormolu-version
|
||||
@echo running ormolu --mode check
|
||||
@$(ORMOLU) $(ORMOLU_ARGS) --mode check $(FORMAT_HS_FILES)
|
||||
|
||||
.PHONY: format
|
||||
format: format-hs
|
||||
|
||||
.PHONY: format-changed
|
||||
format-changed: format-hs-changed
|
||||
|
||||
.PHONY: check-format
|
||||
check-format: check-format-hs
|
@ -1,395 +0,0 @@
|
||||
# stylish-haskell configuration file
|
||||
# ==================================
|
||||
|
||||
# The stylish-haskell tool is mainly configured by specifying steps. These steps
|
||||
# are a list, so they have an order, and one specific step may appear more than
|
||||
# once (if needed). Each file is processed by these steps in the given order.
|
||||
steps:
|
||||
# Convert some ASCII sequences to their Unicode equivalents. This is disabled
|
||||
# by default.
|
||||
# - unicode_syntax:
|
||||
# # In order to make this work, we also need to insert the UnicodeSyntax
|
||||
# # language pragma. If this flag is set to true, we insert it when it's
|
||||
# # not already present. You may want to disable it if you configure
|
||||
# # language extensions using some other method than pragmas. Default:
|
||||
# # true.
|
||||
# add_language_pragma: true
|
||||
|
||||
# Format module header
|
||||
#
|
||||
# Currently, this option is not configurable and will format all exports and
|
||||
# module declarations to minimize diffs
|
||||
#
|
||||
# - module_header:
|
||||
# # How many spaces use for indentation in the module header.
|
||||
# indent: 4
|
||||
#
|
||||
# # Should export lists be sorted? Sorting is only performed within the
|
||||
# # export section, as delineated by Haddock comments.
|
||||
# sort: true
|
||||
#
|
||||
# # See `separate_lists` for the `imports` step.
|
||||
# separate_lists: true
|
||||
|
||||
# Format record definitions. This is disabled by default.
|
||||
#
|
||||
# You can control the layout of record fields. The only rules that can't be configured
|
||||
# are these:
|
||||
#
|
||||
# - "|" is always aligned with "="
|
||||
# - "," in fields is always aligned with "{"
|
||||
# - "}" is likewise always aligned with "{"
|
||||
#
|
||||
# - records:
|
||||
# # How to format equals sign between type constructor and data constructor.
|
||||
# # Possible values:
|
||||
# # - "same_line" -- leave "=" AND data constructor on the same line as the type constructor.
|
||||
# # - "indent N" -- insert a new line and N spaces from the beginning of the next line.
|
||||
# equals: "indent 2"
|
||||
#
|
||||
# # How to format first field of each record constructor.
|
||||
# # Possible values:
|
||||
# # - "same_line" -- "{" and first field goes on the same line as the data constructor.
|
||||
# # - "indent N" -- insert a new line and N spaces from the beginning of the data constructor
|
||||
# first_field: "indent 2"
|
||||
#
|
||||
# # How many spaces to insert between the column with "," and the beginning of the comment in the next line.
|
||||
# field_comment: 0
|
||||
#
|
||||
# # How many spaces to insert before "deriving" clause. Deriving clauses are always on separate lines.
|
||||
# deriving: 2
|
||||
#
|
||||
# # How many spaces to insert before "via" clause counted from indentation of deriving clause
|
||||
# # Possible values:
|
||||
# # - "same_line" -- "via" part goes on the same line as "deriving" keyword.
|
||||
# # - "indent N" -- insert a new line and N spaces from the beginning of "deriving" keyword.
|
||||
# via: "indent 2"
|
||||
#
|
||||
# # Sort typeclass names in the "deriving" list alphabetically.
|
||||
# sort_deriving: false
|
||||
#
|
||||
# # Wheter or not to break enums onto several lines
|
||||
# #
|
||||
# # Default: false
|
||||
# break_enums: true
|
||||
#
|
||||
# # Whether or not to break single constructor data types before `=` sign
|
||||
# #
|
||||
# # Default: true
|
||||
# break_single_constructors: false
|
||||
#
|
||||
# # Whether or not to curry constraints on function.
|
||||
# #
|
||||
# # E.g: @allValues :: Enum a => Bounded a => Proxy a -> [a]@
|
||||
# #
|
||||
# # Instead of @allValues :: (Enum a, Bounded a) => Proxy a -> [a]@
|
||||
# #
|
||||
# # Default: false
|
||||
# curried_context: false
|
||||
|
||||
# Align the right hand side of some elements. This is quite conservative
|
||||
# and only applies to statements where each element occupies a single
|
||||
# line.
|
||||
# Possible values:
|
||||
# - always - Always align statements.
|
||||
# - adjacent - Align statements that are on adjacent lines in groups.
|
||||
# - never - Never align statements.
|
||||
# All default to always.
|
||||
- simple_align:
|
||||
cases: always
|
||||
top_level_patterns: always
|
||||
records: always
|
||||
multi_way_if: always
|
||||
|
||||
# Import cleanup
|
||||
- imports:
|
||||
# There are different ways we can align names and lists.
|
||||
#
|
||||
# - global: Align the import names and import list throughout the entire
|
||||
# file.
|
||||
#
|
||||
# - file: Like global, but don't add padding when there are no qualified
|
||||
# imports in the file.
|
||||
#
|
||||
# - group: Only align the imports per group (a group is formed by adjacent
|
||||
# import lines).
|
||||
#
|
||||
# - none: Do not perform any alignment.
|
||||
#
|
||||
# Default: global.
|
||||
align: global
|
||||
|
||||
# The following options affect only import list alignment.
|
||||
#
|
||||
# List align has following options:
|
||||
#
|
||||
# - after_alias: Import list is aligned with end of import including
|
||||
# 'as' and 'hiding' keywords.
|
||||
#
|
||||
# > import qualified Data.List as List (concat, foldl, foldr, head,
|
||||
# > init, last, length)
|
||||
#
|
||||
# - with_alias: Import list is aligned with start of alias or hiding.
|
||||
#
|
||||
# > import qualified Data.List as List (concat, foldl, foldr, head,
|
||||
# > init, last, length)
|
||||
#
|
||||
# - with_module_name: Import list is aligned `list_padding` spaces after
|
||||
# the module name.
|
||||
#
|
||||
# > import qualified Data.List as List (concat, foldl, foldr, head,
|
||||
# init, last, length)
|
||||
#
|
||||
# This is mainly intended for use with `pad_module_names: false`.
|
||||
#
|
||||
# > import qualified Data.List as List (concat, foldl, foldr, head,
|
||||
# init, last, length, scanl, scanr, take, drop,
|
||||
# sort, nub)
|
||||
#
|
||||
# - new_line: Import list starts always on new line.
|
||||
#
|
||||
# > import qualified Data.List as List
|
||||
# > (concat, foldl, foldr, head, init, last, length)
|
||||
#
|
||||
# - repeat: Repeat the module name to align the import list.
|
||||
#
|
||||
# > import qualified Data.List as List (concat, foldl, foldr, head)
|
||||
# > import qualified Data.List as List (init, last, length)
|
||||
#
|
||||
# Default: after_alias
|
||||
list_align: after_alias
|
||||
|
||||
# Right-pad the module names to align imports in a group:
|
||||
#
|
||||
# - true: a little more readable
|
||||
#
|
||||
# > import qualified Data.List as List (concat, foldl, foldr,
|
||||
# > init, last, length)
|
||||
# > import qualified Data.List.Extra as List (concat, foldl, foldr,
|
||||
# > init, last, length)
|
||||
#
|
||||
# - false: diff-safe
|
||||
#
|
||||
# > import qualified Data.List as List (concat, foldl, foldr, init,
|
||||
# > last, length)
|
||||
# > import qualified Data.List.Extra as List (concat, foldl, foldr,
|
||||
# > init, last, length)
|
||||
#
|
||||
# Default: true
|
||||
pad_module_names: true
|
||||
|
||||
# Long list align style takes effect when import is too long. This is
|
||||
# determined by 'columns' setting.
|
||||
#
|
||||
# - inline: This option will put as much specs on same line as possible.
|
||||
#
|
||||
# - new_line: Import list will start on new line.
|
||||
#
|
||||
# - new_line_multiline: Import list will start on new line when it's
|
||||
# short enough to fit to single line. Otherwise it'll be multiline.
|
||||
#
|
||||
# - multiline: One line per import list entry.
|
||||
# Type with constructor list acts like single import.
|
||||
#
|
||||
# > import qualified Data.Map as M
|
||||
# > ( empty
|
||||
# > , singleton
|
||||
# > , ...
|
||||
# > , delete
|
||||
# > )
|
||||
#
|
||||
# Default: inline
|
||||
long_list_align: inline
|
||||
|
||||
# Align empty list (importing instances)
|
||||
#
|
||||
# Empty list align has following options
|
||||
#
|
||||
# - inherit: inherit list_align setting
|
||||
#
|
||||
# - right_after: () is right after the module name:
|
||||
#
|
||||
# > import Vector.Instances ()
|
||||
#
|
||||
# Default: inherit
|
||||
empty_list_align: inherit
|
||||
|
||||
# List padding determines indentation of import list on lines after import.
|
||||
# This option affects 'long_list_align'.
|
||||
#
|
||||
# - <integer>: constant value
|
||||
#
|
||||
# - module_name: align under start of module name.
|
||||
# Useful for 'file' and 'group' align settings.
|
||||
#
|
||||
# Default: 4
|
||||
list_padding: 4
|
||||
|
||||
# Separate lists option affects formatting of import list for type
|
||||
# or class. The only difference is single space between type and list
|
||||
# of constructors, selectors and class functions.
|
||||
#
|
||||
# - true: There is single space between Foldable type and list of it's
|
||||
# functions.
|
||||
#
|
||||
# > import Data.Foldable (Foldable (fold, foldl, foldMap))
|
||||
#
|
||||
# - false: There is no space between Foldable type and list of it's
|
||||
# functions.
|
||||
#
|
||||
# > import Data.Foldable (Foldable(fold, foldl, foldMap))
|
||||
#
|
||||
# Default: true
|
||||
separate_lists: true
|
||||
|
||||
# Space surround option affects formatting of import lists on a single
|
||||
# line. The only difference is single space after the initial
|
||||
# parenthesis and a single space before the terminal parenthesis.
|
||||
#
|
||||
# - true: There is single space associated with the enclosing
|
||||
# parenthesis.
|
||||
#
|
||||
# > import Data.Foo ( foo )
|
||||
#
|
||||
# - false: There is no space associated with the enclosing parenthesis
|
||||
#
|
||||
# > import Data.Foo (foo)
|
||||
#
|
||||
# Default: false
|
||||
space_surround: false
|
||||
|
||||
# Enabling this argument will use the new GHC lib parse to format imports.
|
||||
#
|
||||
# This currently assumes a few things, it will assume that you want post
|
||||
# qualified imports. It is also not as feature complete as the old
|
||||
# imports formatting.
|
||||
#
|
||||
# It does not remove redundant lines or merge lines. As such, the full
|
||||
# feature scope is still pending.
|
||||
#
|
||||
# It _is_ however, a fine alternative if you are using features that are
|
||||
# not parseable by haskell src extensions and you're comfortable with the
|
||||
# presets.
|
||||
#
|
||||
# Default: false
|
||||
ghc_lib_parser: false
|
||||
|
||||
# Language pragmas
|
||||
- language_pragmas:
|
||||
# We can generate different styles of language pragma lists.
|
||||
#
|
||||
# - vertical: Vertical-spaced language pragmas, one per line.
|
||||
#
|
||||
# - compact: A more compact style.
|
||||
#
|
||||
# - compact_line: Similar to compact, but wrap each line with
|
||||
# `{-#LANGUAGE #-}'.
|
||||
#
|
||||
# Default: vertical.
|
||||
style: vertical
|
||||
|
||||
# Align affects alignment of closing pragma brackets.
|
||||
#
|
||||
# - true: Brackets are aligned in same column.
|
||||
#
|
||||
# - false: Brackets are not aligned together. There is only one space
|
||||
# between actual import and closing bracket.
|
||||
#
|
||||
# Default: true
|
||||
align: true
|
||||
|
||||
# stylish-haskell can detect redundancy of some language pragmas. If this
|
||||
# is set to true, it will remove those redundant pragmas. Default: true.
|
||||
remove_redundant: true
|
||||
|
||||
# Language prefix to be used for pragma declaration, this allows you to
|
||||
# use other options non case-sensitive like "language" or "Language".
|
||||
# If a non correct String is provided, it will default to: LANGUAGE.
|
||||
language_prefix: LANGUAGE
|
||||
|
||||
# Replace tabs by spaces. This is disabled by default.
|
||||
# - tabs:
|
||||
# # Number of spaces to use for each tab. Default: 8, as specified by the
|
||||
# # Haskell report.
|
||||
# spaces: 8
|
||||
|
||||
# Remove trailing whitespace
|
||||
- trailing_whitespace: {}
|
||||
|
||||
# Squash multiple spaces between the left and right hand sides of some
|
||||
# elements into single spaces. Basically, this undoes the effect of
|
||||
# simple_align but is a bit less conservative.
|
||||
# - squash: {}
|
||||
|
||||
# A common setting is the number of columns (parts of) code will be wrapped
|
||||
# to. Different steps take this into account.
|
||||
#
|
||||
# Set this to null to disable all line wrapping.
|
||||
#
|
||||
# Default: 80.
|
||||
columns: 100
|
||||
|
||||
# By default, line endings are converted according to the OS. You can override
|
||||
# preferred format here.
|
||||
#
|
||||
# - native: Native newline format. CRLF on Windows, LF on other OSes.
|
||||
#
|
||||
# - lf: Convert to LF ("\n").
|
||||
#
|
||||
# - crlf: Convert to CRLF ("\r\n").
|
||||
#
|
||||
# Default: native.
|
||||
newline: native
|
||||
|
||||
# Sometimes, language extensions are specified in a cabal file or from the
|
||||
# command line instead of using language pragmas in the file. stylish-haskell
|
||||
# needs to be aware of these, so it can parse the file correctly.
|
||||
#
|
||||
# No language extensions are enabled by default.
|
||||
language_extensions:
|
||||
- ApplicativeDo
|
||||
- BangPatterns
|
||||
- BlockArguments
|
||||
- ConstraintKinds
|
||||
- DataKinds
|
||||
- DefaultSignatures
|
||||
- DeriveDataTypeable
|
||||
- DeriveFoldable
|
||||
- DeriveFunctor
|
||||
- DeriveGeneric
|
||||
- DeriveLift
|
||||
- DeriveTraversable
|
||||
- DerivingVia
|
||||
- EmptyCase
|
||||
- ExistentialQuantification
|
||||
- FlexibleContexts
|
||||
- FlexibleInstances
|
||||
- FunctionalDependencies
|
||||
- GADTs
|
||||
- GeneralizedNewtypeDeriving
|
||||
- InstanceSigs
|
||||
- LambdaCase
|
||||
- MultiParamTypeClasses
|
||||
- MultiWayIf
|
||||
- NamedFieldPuns
|
||||
- NoImplicitPrelude
|
||||
- OverloadedStrings
|
||||
- QuantifiedConstraints
|
||||
- QuasiQuotes
|
||||
- RankNTypes
|
||||
- RecordWildCards
|
||||
- RoleAnnotations
|
||||
- ScopedTypeVariables
|
||||
- StandaloneDeriving
|
||||
- TemplateHaskell
|
||||
- TupleSections
|
||||
- TypeApplications
|
||||
- TypeFamilies
|
||||
- TypeFamilyDependencies
|
||||
- TypeOperators
|
||||
|
||||
# Attempt to find the cabal file in ancestors of the current directory, and
|
||||
# parse options (currently only language extensions) from that.
|
||||
#
|
||||
# Default: true
|
||||
cabal: true
|
@ -301,9 +301,17 @@ The backend-specific and common test suites are disjoint; for example, run `pyte
|
||||
|
||||
## Code conventions
|
||||
|
||||
This helps enforce a uniform style for all committers.
|
||||
The following conventions help us maintain a uniform style for all committers:
|
||||
make sure your contributions are in line with them.
|
||||
|
||||
- Compiler warnings are turned on, make sure your code has no warnings.
|
||||
- Use [hlint](https://github.com/ndmitchell/hlint) to make sure your code has no warnings.
|
||||
You can use our custom hlint config with `$ hlint --hint=server/.hlint.yaml .`
|
||||
- Use [stylish-haskell](https://github.com/jaspervdj/stylish-haskell) to format your code.
|
||||
We enforce these by means of CI hooks which will fail the build if any of these
|
||||
are not met.
|
||||
|
||||
- No compiler warnings: Make sure your code builds with no warnings (adding
|
||||
`-Werror` to `ghc-options` in your `cabal.project` is a good way of checking
|
||||
this.)
|
||||
- No lint failures: Use [hlint](https://github.com/ndmitchell/hlint) with our
|
||||
custom config to validate your code, using `hlint --hint=server/.hlint.yaml`.
|
||||
- Consistent formatting: Use [ormolu](https://github.com/tweag/ormolu) to
|
||||
format your code. `ormolu -ei '*.hs'` will format all files with a `.hs`
|
||||
extension in the current directory.
|
||||
|
143
server/STYLE.md
143
server/STYLE.md
@ -1,117 +1,29 @@
|
||||
# Code conventions and style guide
|
||||
|
||||
This is a short document describing the preferred coding style for this project. We've tried to cover the major areas of formatting and naming. When something isn't covered by this guide, err on the side of consistency with existing code.
|
||||
This is a short document describing the preferred coding style for this
|
||||
project. We've tried to cover the major areas of formatting and naming. When
|
||||
something isn't covered by this guide, err on the side of consistency with
|
||||
existing code.
|
||||
|
||||
### Formatting
|
||||
|
||||
Use [stylish-haskell](https://github.com/jaspervdj/stylish-haskell) to format your code.
|
||||
We use [ormolu](https://github.com/tweag/ormolu) to format our code. The
|
||||
top-level `Makefile` has targets `format` and `check-format` that can be
|
||||
used for this.
|
||||
|
||||
#### Line Length
|
||||
|
||||
We do not enforce a hard limit on line length, but we try to keep lines under 80 characters where possible to make it easier to tile files horizontally. It’s okay if long lines spill into the 80–100 character range if wrapping them would harm readability. In particular, we don’t want to discourage descriptive variable names, nor do we want to discourage introducing local variables, so consider 80 characters a target length rather than a limit.
|
||||
We do not enforce a hard limit on line length, but we try to keep lines under
|
||||
80 characters where possible to make it easier to tile files horizontally.
|
||||
It’s okay if long lines spill into the 80–100 character range if wrapping
|
||||
them would harm readability. In particular, we don’t want to discourage
|
||||
descriptive variable names, nor do we want to discourage introducing local
|
||||
variables, so consider 80 characters a target length rather than a limit.
|
||||
|
||||
One exception to the above is multiline comments, which should almost always be wrapped to 80 characters. Most editors support automatically reflowing blocks of text with a configurable line length; consider learning the relevant hotkey in your editor of choice.
|
||||
|
||||
#### Whitespace
|
||||
|
||||
Do not use tabs. Use spaces for indenting. Indent your code blocks with **2
|
||||
spaces**. Indent the `where` keyword two spaces to set it apart from the rest of
|
||||
the code and indent the definitions in a `where` clause 2 spaces. Some examples:
|
||||
|
||||
```haskell
|
||||
sayHello :: IO ()
|
||||
sayHello = do
|
||||
name <- getLine
|
||||
putStrLn $ greeting name
|
||||
where
|
||||
greeting name = "Hello, " ++ name ++ "!"
|
||||
|
||||
filter :: (a -> Bool) -> [a] -> [a]
|
||||
filter _ [] = []
|
||||
filter p (x:xs)
|
||||
| p x = x : filter p xs
|
||||
| otherwise = filter p xs
|
||||
```
|
||||
|
||||
Include newlines at the ends of files. Do not include other trailing whitespace on the end of lines.
|
||||
|
||||
#### Data Declarations
|
||||
|
||||
Align the constructors in a data type definition. Example:
|
||||
|
||||
```haskell
|
||||
data Tree a
|
||||
= Branch !a !(Tree a) !(Tree a)
|
||||
| Leaf
|
||||
```
|
||||
|
||||
```haskell
|
||||
data HttpException
|
||||
= InvalidStatusCode Int
|
||||
| MissingContentHeader
|
||||
```
|
||||
|
||||
Format records as follows:
|
||||
|
||||
```haskell
|
||||
data Person = Person
|
||||
{ firstName :: !String -- ^ First name
|
||||
, lastName :: !String -- ^ Last name
|
||||
, age :: !Int -- ^ Age
|
||||
} deriving (Eq, Show)
|
||||
```
|
||||
|
||||
#### List Declarations
|
||||
|
||||
Align the elements in the list. Example:
|
||||
|
||||
```haskell
|
||||
exceptions =
|
||||
[ InvalidStatusCode
|
||||
, MissingContentHeader
|
||||
, InternalServerError
|
||||
]
|
||||
```
|
||||
|
||||
Optionally, you can skip the first newline. Use your judgement.
|
||||
|
||||
```haskell
|
||||
directions = [ North
|
||||
, East
|
||||
, South
|
||||
, West
|
||||
]
|
||||
```
|
||||
|
||||
#### Export Lists
|
||||
|
||||
Format export lists as follows:
|
||||
|
||||
```haskell
|
||||
module Data.Set
|
||||
( -- * The @Set@ type
|
||||
Set
|
||||
, empty
|
||||
, singleton
|
||||
|
||||
-- * Querying
|
||||
, member
|
||||
) where
|
||||
```
|
||||
|
||||
### Imports
|
||||
|
||||
Imports should be grouped in the following order:
|
||||
|
||||
1. `Hasura.Prelude`
|
||||
2. `qualified` imports of standard library / third party imports
|
||||
3. unqualified standard library imports / related third party imports
|
||||
4. `qualified` imports of local application/library specific imports
|
||||
5. unqualified local application/library specific imports
|
||||
|
||||
Put a blank line between each group of imports. The imports in each group should
|
||||
be sorted alphabetically, by module name (this is done by `stylish-haskell`
|
||||
automatically).
|
||||
One exception to the above is multiline comments, which should almost always
|
||||
be wrapped to 80 characters. Most editors support automatically reflowing
|
||||
blocks of text with a configurable line length; consider learning the
|
||||
relevant hotkey in your editor of choice.
|
||||
|
||||
### Naming
|
||||
|
||||
@ -306,7 +218,8 @@ Use line comments (comments that start with `--`) for short comments (1–3
|
||||
lines). For longer comments, use multiline comments (comments that begin with
|
||||
`{-` and end with `-}`).
|
||||
|
||||
Use [Haddock syntax](https://haskell-haddock.readthedocs.io/en/latest/markup.html) for documentation comments. Running Haddock should always complete successfully.
|
||||
Use [Haddock syntax](https://haskell-haddock.readthedocs.io/en/latest/markup.html)
|
||||
for documentation comments. Running Haddock should always complete successfully.
|
||||
|
||||
#### Module headers
|
||||
|
||||
@ -463,7 +376,11 @@ runSelectQuery tables constraints cache shouldPrepare =
|
||||
|
||||
#### Out-of-line `Note`s
|
||||
|
||||
For especially tricky details that deserve thorough explanation and may need to be referenced from multiple places, we emulate [GHC’s Notes](https://www.stackbuilders.com/news/the-notes-of-ghc). A `Note` is an out-of-line comment written at the top-level of a module, written with a short title header:
|
||||
For especially tricky details that deserve thorough explanation and may need
|
||||
to be referenced from multiple places, we emulate [GHC’s
|
||||
Notes](https://www.stackbuilders.com/news/the-notes-of-ghc). A `Note` is an
|
||||
out-of-line comment written at the top-level of a module, written with a
|
||||
short title header:
|
||||
|
||||
```haskell
|
||||
{- Note [Checking metadata consistency in run_sql]
|
||||
@ -476,7 +393,8 @@ metadata to track the table under its new name instead of its old one.
|
||||
... -}
|
||||
```
|
||||
|
||||
At any point where the comment is relevant, we add a short comment referring to the note:
|
||||
At any point where the comment is relevant, we add a short comment referring
|
||||
to the note:
|
||||
|
||||
```haskell
|
||||
-- see Note [Checking metadata consistency in run_sql]
|
||||
@ -484,9 +402,14 @@ containsDDLKeyword :: Text -> Bool
|
||||
containsDDLKeyword = TDFA.match $$(quoteRegex ...)
|
||||
```
|
||||
|
||||
A key advantage of notes is that they can be referenced from multiple places, so information does not necessarily need to be connected to any particular binding the way it must be for Haddock comments.
|
||||
A key advantage of notes is that they can be referenced from multiple places,
|
||||
so information does not necessarily need to be connected to any particular
|
||||
binding the way it must be for Haddock comments.
|
||||
|
||||
When updating a piece of code that includes a reference to a `Note`, take care to ensure the `Note` is updated as well if necessary! Inevitably, some will get stale and go out of sync with the code, but that’s okay—just fix them up when you find some information is outdated.
|
||||
When updating a piece of code that includes a reference to a `Note`, take
|
||||
care to ensure the `Note` is updated as well if necessary! Inevitably, some
|
||||
will get stale and go out of sync with the code, but that’s okay—just fix
|
||||
them up when you find some information is outdated.
|
||||
|
||||
### Misc
|
||||
|
||||
|
@ -57,6 +57,7 @@ common common-all
|
||||
FunctionalDependencies
|
||||
GADTs
|
||||
GeneralizedNewtypeDeriving
|
||||
ImportQualifiedPost
|
||||
InstanceSigs
|
||||
LambdaCase
|
||||
MultiParamTypeClasses
|
||||
|
@ -6,8 +6,6 @@ module Data.Tuple.Extended
|
||||
, uncurry4
|
||||
) where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Data.Tuple
|
||||
|
||||
curry3 :: ((a, b, c) -> d) -> a -> b -> c -> d
|
||||
|
Loading…
Reference in New Issue
Block a user