Version: v0.8.0 - Beta.  We welcome contributors & feedback.

Format Checker

Programs are meant to be read by humans and only incidentally for computers to execute.

— H. Abelson and G. Sussman
Structure and Interpretation of Computer Programs

Background 

Most programming languages promote a uniform coding style, either with a style guide (e.g. Python’s PEP 8) or with formatting utilities (aka “linters”).

THT goes a step further by having a Format Checker that identifies issues at compile time.

The rules are taken from two main sources:

Benefits of Built-In Code Formatting

Q: Why is whitespace so important?

Consistent use of whitespace creates a visual rhythm, and follows our natural ability to visually process information in chunks that are related to each other (see “Gestalt laws of grouping”).

Using conventions frees your brain from the mundane aspects of programming, which offer little payback.

— Steve McConnell, Code Complete

Formatting Rules 

General

Indent With Spaces

TAB characters are not allowed.

Configure your editor to insert 4 spaces for your Tab key (aka “soft tabs”), if it doesn’t already do so by default.

Whitespace

Indentation

Lines inside multiline braces of {}, [], or () should be indented 4 spaces.

// ✓ Yes
if true {
    print('...')
}

// ✕ No
if true {
 print('...')
}

// ✓ Yes
$list = [
    111
    222
    333
]

// ✕ No
$list = [
111
222
333
]

Infix operators + = == &&

Space before & after: YES

$a = $b + 1  // ✓ Yes
$a = $b+1    // ✕ No
$a=$b+1      // ✕ No

if $isGood && $isOk {...}  // ✓ Yes
if $isGood&&$isOk {...}    // ✕ No

Prefix operators ! -

Space after: NO

if !$isAdmin {...}    // ✓ Yes
if ! $isAdmin {...}   // ✕ No

$a = -23   // ✓ Yes
$a = - 23  // ✕ No

Commas ,

Space before: NO
Space after: YES

doSomething($a, $b, $c)  // ✓ Yes
doSomething($a,$b,$c)    // ✕ No

Parentheses ( )

Inside padding: NO
Outer wrapping: NO

doSomething($myVar)    // ✓ Yes
doSomething( $myVar )  // ✕ No

$a = $b / ($c / $d)    // ✓ Yes
$a = $b / ( $c / $d )  // ✕ No

Square Braces [ ]

Inside padding: NO

$a = [1, 2, 3]    // ✓ Yes
$a = [ 1, 2, 3 ]  // ✕ No

$user['userId']    // ✓ Yes
$user[ 'userId' ]  // ✕ No

Curly Braces { }

Inside padding: YES

$a = { foo: 1 }  // ✓ Yes
$a = {foo: 1}    // ✕ No

if $isOk { return $a }  // ✓ Yes
if $isOk {return $a}    // ✕ No

Colons :

Space before: NO
Space after: YES

$a = { foo: 1 }   // ✓ Yes

$a = { foo : 1 }  // ✕ No
          ^
$a = { foo:1 }    // ✕ No
          ^^

Function Argument List ( )

Space before: NO
Space after: YES

fun foo($myVar) {   // ✓ Yes

fun foo($myVar){    // ✕ No
              ^^
fun foo ($myVar) {  // ✕ No
       ^

Open Braces {

Space before: YES
Same line: YES

// ✓ Yes
fun main {

// ✕ No
fun main{

// ✕ No
fun main
{

Closing Braces } ]

Next Line: YES

// ✓ Yes
$nums = [
    111
    222
]

// ✕ No
$nums = [
    111
    222 ]

Trailing Commas ,

After single line: NO
After multiple lines: NO

// ✕ No
$list = [1, 2, 3, ]
                ^
// ✕ No
$map = { aa: 1, bb: 2, cc: 3, }
                            ^
// ✕ No
$map = {
    aa: 1,
    bb: 2,
    cc: 3,
}

// ✓ Yes
$map = {
    aa: 1
    bb: 2
    cc: 3
}

// ✓ Yes
$list = [
    111
    222
    333
]

Blank Lines

Use blank lines to group related lines together. Think of consecutive line of code as a “paragraph”.

// ✕ No

$userName = getUserName()
if $userName == 'admin': return true
$userAgeDays = getUserAgeDays($userName)
if $userAgeDays > 1000: return true


// ✓ Yes

$userName = getUserName()
if $userName == 'admin': return true

$userAgeDays = getUserAgeDays($userName)
if $userAgeDays > 1000: return true

Parser Rules 

Names

Module and class names are strict UpperCamelCase. This includes acronyms.

User
XmlReader
XmlHttpRequest

All other names (variables, functions, bare map keys) are strict camelCase. This includes acronyms.

user
firstName
userId
userHasIphone
httpOutput

Other Rules

Assignment inside conditional: NO

// ✕ No
if $line = readLine() {...}
         ^
// ✓ Yes  (If-Assign operator)
if $line := readLine() {...}
         ^^

Nested ternary expressions: NO

// ✕ No
check1 ? action1() : check2 ? action2() : action3()

// ✓ Yes - if/else
if check1 {
    action1()
}
else if check2 {
    action2()
}
else {
    action3()
}

Max function arguments: 4

Use Option Maps for keyword arguments.

// ✕ No - More than 4 arguments
fun doSomething($a1, $a2, $a3, $a4, $a5) {
    ...
}

// ✓ Yes - Combine args into a Map
doSomething('foo', { flag: true, num: 123 })

fun doSomething($mainArg, $args) {
    $args.check({
        flag: false
        num: 0
    })
}

HTML Templates 

These are additional rules for markup within HTML Template Functions.

Tag Names

Uppercase: NO

// ✕ No
<SPAN>

// ✓ Yes
<span>

Parameters

Quoted: YES

// ✕ No
<div class=my-class>

// ✓ Yes
<div class="my-class">

Space around equals: NO

// ✕ No
<div class = "my-class">

// ✓ Yes
<div class="my-class">