Skip to content
This repository has been archived by the owner on Jul 17, 2020. It is now read-only.

Code standards: JS

ArtOfCode edited this page Jan 21, 2020 · 19 revisions

The status of this document is currently Adopted.

The following is our style guide for writing JavaScript. All JS contributions MUST adhere to this document unless there's a good reason not to; such reasons MUST have a linter ignore applied to them, and SHOULD be documented using a comment above the relevant code.

This guide uses RFC 2119 terminology.

1. Encoding

Use UTF8 encoding, without BOM. Ensure your editor is set to use UTF8 w/o BOM.

2. Language Version

Use features of ES6 or above where they are available. Prefer modern constructs over equivalents from previous language versions. Code will be transpiled to ES5 for builds, so we can use modern features without worrying about browser compatibility. Particularly:

  • Use const, not var. Use let if your variable will be re-assigned.
  • Use arrow functions, () => {}, where possible. Only use function if a this context is necessary.
  • Use async/await, not callbacks or Promise. Only use a callback when calling an API that does not offer async.

3. Modules

Write code in ES6 modules. Group related functionality (such as code relating to posts routes) into a single file; split it into multiple files if the file becomes excessively long. Use import/export to reference code from other files.

4. Naming

Name all variables and methods using lowerCamelCase. SHOUTY_CASE may be used for constants (true constants only, not just all const variables).

Name files in lisp-case, using a .js extension: mod-dashboard.js.

5. Spacing

  • Indent code by four spaces. Do not use tab stops.
  • Always use a space on both sides of an operator, including in assignments and declarations: 1 + 1, const foo = 'bar';, () => {}.
  • Use a space between parameters in function declarations and calls: (foo, bar) => { }, sendFormData(form, 'POST').
  • Use a space between key and value when declaring object literals, and between each pair: const data = {a: 1, b: 2};
  • Use a space between control flow keywords and the opening parenthesis; as well as between the closing parenthesis and the opening brace: if (x === 1) {.
  • Do not use a space between function definitions or function calls and the opening parenthesis: function getUsersByGroup(groupId); let users = getUsersByGroup(1).
  • Do not use spaces inside parentheses: (x === 1), not ( x === 1 )
  • Do not write more than one statement per line.

6. Required optional elements

  • Semicolons must not be omitted at the end of statements.
  • Braces must not be omitted for single-line statements following a control flow expression (e.g. if/else, for, while).
  • Equality checks must use strict equality checking (===). The only exception is when checking for null/undefined values, which may be written as if (value == null).

7. Quotes

Prefer double quotes. If a quoted string contains a literal double quote character, use single quotes instead:

const mergeTargetModal = document.querySelector("#js-merge-target-select");
const groupLinks = document.querySelectorAll('[data-type="type_group"] > a');

Use of template literals is allowed where it makes sense.

8. Line length

Do not write lines longer than 120 characters. Lines that would be longer than 120 characters must be hard-wrapped onto the next line, and every continuation line must be indented at least one more level than the first line. Wrapped lines may be indented further to align certain elements with one another.

codidact.createDangerConfirmationAudit(document.querySelectorAll('.modal.is-danger > .modal--body'),
                                       'POST', 'https://codidact.org/audits/danger-confirmation');

9. Bracing

Follow the K&R style of bracing:

  • No line break before opening brace
  • Line break after opening brace
  • Line break before closing brace
  • Line break after closing brace

A blank line must also be added after a closing brace where the brace closes a function, method, or class body.

class ModalDialog {
    constructor(data) {
        if (Object.keys(data).length > 0) {
            this.dataset = data;
        }
        else {
            this.dataset = {};
        }
    }

    get name() {
        return this.dataset['name'] || '(none)';
    }
}

10. Conditional assignment

When assigning one of two possible values to a variable according to a condition, prefer the ternary operator (?:):

this.dataset = (Object.keys(data).length > 0) ? data : {};

Note the use of parentheses around the conditional expression - it makes it more obvious at first glance that this is a conditional statement. This is a requirement.

For very long or deeply indented expressions that exceed the 120-char line length limit (item 8), use the following line-break and indenting style:

this.dataset = (Object.keys(data).length > 0 && data.includes("email")
                && data["createdAt"] >= someLongDateTimeString)
               ? data
               : {};

When assigning to multiple variables according to the same condition, do not use a ternary expression. The if / else block should be used instead (remember: don't repeat yourself).