THT is in early 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 style for formatting code, either with style guide documents (e.g. Python’s PEP 8) or utilities (aka “linters”).

THT goes a step further. It has a Format Checker that identifies code formatting issues at compile time.

These rules were collected from best practices used by professional programmers using comparable languages (e.g. Java & JavaScript).

Benefits

Formatting Rules 

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

— Steve McConnell, Code Complete

General

Whitespace

Indentation

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

// ✖ No
let nums = [
'Do',
'Re',
'Mi'
];

// ✔ Yes
let nums = [
    'Do',
    'Re',
    'Mi'
];
Infix operators + = == &&

Space before & after: YES

let a = b + 1;  // ✔ Yes
let a = b+1;    // ✖ No
let a=b+1;      // ✖ No

if (isGood && isOk) { ... }  // ✔ Yes
if (isGood&&isOk) { ... }    // ✖ No
Prefix operators ! -

Spaces after: NO

let isNormal = !isAdmin;   // ✔ Yes
let isNormal = ! isAdmin;  // ✖ No

if (!isAdmin) { ... }    // ✔ Yes
if (! isAdmin) { ... }   // ✖ No

let a = -23;   // ✔ Yes
let a = - 23;  // ✖ No
Semicolons ;

Space before: NO
Space after: YES (must be newline)

let foo = 1;   // ✔ Yes
let foo = 1 ;  // ✖ No
Commas ,

Space before: NO
Space after: YES

doSomething(123, 45, 6789);  // ✔ Yes
doSomething(123,45,6789);    // ✖ No
Parentheses ( )

Inside padding: NO

if (isOk) { ... }    // ✔ Yes
if ( isOk ) { ... }  // ✖ No

check(myVar);    // ✔ Yes
check( myVar );  // ✖ No

let a = b / (c / d);    // ✔ Yes
let a = b / ( c / d );  // ✖ No
Square braces [ ]

Inside padding: NO

let a = [1, 2, 3];    // ✔ Yes
let a = [ 1, 2, 3 ];  // ✖ No

user['userId'];    // ✔ Yes
user[ 'userId' ];  // ✖ No
Curly braces { }

Inside padding: YES

let a = { foo: 1 };  // ✔ Yes
let a = {foo: 1};    // ✖ No

if (isOk) { return a; }  // ✔ Yes
if (isOk) {return a;}    // ✖ No
Empty Maps & Lists [] {}

Inside padding: NO

let a = [];   // ✔ Yes
let a = [ ];  // ✖ No

let b = {};   // ✔ Yes
let b = { };  // ✖ No
Colons :

Space before: NO
Space after: YES

let a = { foo: 1 };   // ✔ Yes

let a = { foo : 1 };  // ✖ No
let a = { foo:1 };    // ✖ No
Function argument list ( )

Space before: NO
Space after: YES

function foo(myVar) { ... }   // ✔ Yes

function foo(myVar){ ... }    // ✖ No
function foo (myVar) { ... }  // ✖ No

Statement keywords

Space after: YES

if(isOk)  // ✖ No
if (isOk) // ✔ Yes

for (i in items) // ✔ Yes
for(i in items)  // ✖ No
Open braces {

Space before: YES
Same line: YES
Next line: NO (but not prohibited)

// ✔ Yes
function main() {
    // ...
}

// ✖ No - no space before {
function main(){
    // ...
}

// ✖ No - dangling {
function main()
{
    // ...
}
Closing braces } ]

Next Line: YES

// ✔ Yes
let nums = [
    111,
    222,
];

// ✖ No
let nums = [
    111,
    222 ];

Parser Rules 

Nested ternary expressions: NO

// ✖ No
var a = check1 ? action1() : check2 ? action2() : defaultAction();

Optional function arguments always appear after required arguments.

// ✔ Yes
function sayHello(userName, isAdmin = false) { ... }

// ✖ No
function sayHello(isAdmin = false, userName) { ... }

Assignment inside conditional: NO

// ✖ No
if (line = readLine()) { ... }

// ✔ Yes
line = readLine();
if (line) { ... }

Statements after continue or break: NO

for {
    if (getNextUser()) {
        continue;
        users += 1;  // ✖ No - unreachable
    }
}
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
httpResponse