Javascript coding guidelines

Sébastien Theys edited this page Jun 1, 2018 · 15 revisions

From v11, we introduce a new coding standard for Odoo Javascript code. Here it is:

Use a Linter

  • A sample configuration for ESLint:
{
    "env": {
        "commonjs": true,
        "es6": true
    },
    "extends": "eslint:recommended",
    "parserOptions": {
        "sourceType": "module"
    },
    "rules": {
        "indent": [
            "off",
            4,
            {
                "SwitchCase": 1
            }
        ],
        "linebreak-style": [
            "error",
            "unix"
        ],
        "quotes": [
            "off",
            "double"
        ],
        "semi": [
            "error",
            "always"
        ],
        "comma-dangle": [
            "off"
        ],
        "no-console": [
            "warn",
            {
                "allow": ["warn", "error"]
            }
        ],
        "no-unused-vars": [
            "warn",
            {
                "args": "none"
            }
        ],
        "no-empty": [
            "warn"
        ],
        "eqeqeq": [
            "error",
            "smart"
        ],
        "space-before-function-paren": [
            "warn",
            {"anonymous": "always", "named": "never"}
        ],
        "keyword-spacing": [
            "warn"
        ],
        "no-use-before-define": [
            "warn",
            "nofunc"
        ]
    },
    "globals": {
        "$": false,
        "jQuery": false,
        "_": false,
        "openerp": true,
        "odoo": true,
        "CKEDITOR": true,
        "google": false,
        "window": false,
        "setTimeout": false,
        "clearTimeout": false,
        "document": false,
        "console": false,
        "QUnit": false,
        "moment": false,
        "FileReader": false,
        "nv": false,
        "d3": false,
        "ace": false,
        "Option": false,
        "py": false,
        "XMLHttpRequest": false,
        "setInterval": false,
        "clearInterval": false,
        "Image": false,
        "jstz": false,
        "ZeroClipboard": false,
        "sessionStorage": false,
        "Node": false,
        "history": false,
        "gapi": false,
        "Event": false,
        "Gravitec": false,
        "navigator": false,
        "OneSignal": false
    }
}

Generic guidelines

  • Add "use strict"; on top of every odoo JS module
  • Variables and functions should be camelcased (myVariable) instead of snakecased (my_variable)
  • Do not name a variable event, use ev. This is to avoid bugs on non-Chrome browsers as Chrome is magically assigning a global event variable (so if you use the event variable without declaring it, it will be fine on chrome but crash on every other browser).
  • Name all entities exported by a JS module.

So, instead of

    return Widget.extend({
        // ...
    });

you should use:

    var MyWidget = Widget.extend({
        // ...
    });
    return MyWidget;
  • There should be one space after every JS keyword, including function (but not after function names):
    function (a, b) { /*...*/ }
    function myFunction(a, b) { /*...*/ }
    if (a) { /*...*/ }
  • The if-else structure should be this one:
    if (a) {
        // ...
    } else if (b) {
        // ...
    } else {
        // ...
    }
  • Use strict comparisons (=== instead of ==)

  • JS files should have a (soft) width limit of 80 chars width, and a hard limit of 100

  • Avoid introspection: don't build dynamically a method name and call it. It is more fragile and more difficult to refactor

  • Methods should be private if possible and those methods' names should begin with an underscore. They should never be called from another object.

  • Never read an attribute of an attribute on something that you have a reference. So, this is not good:

    this.myObject.propA.propB
  • Write unit tests

  • Object definition on more than one line: each element should have a trailing comma

  • strings: double quotes for all textual strings (such as "Hello"), and single quotes for all other strings, such as a css selector '.o_form_view'

  • Always use this._super.apply(this, arguments);

  • Keys in an object: ordered by alphabetic order

  • no assignation hidden in a statement:

Replace

return (this.current = $.extend(true, {}, this.params));`

with

this.current = $.extend(true, {}, this.params));
return this.current;

Documentation

  • Document every functions and every files, with the JSDoc style (see http://usejsdoc.org/)

  • For function overriding other functions, consider adding the tag @override in the JS Doc. Also, you can mention which method is overridden:

    /**
     * When a save operation has been confirmed from the model, this method is
     * called.
     *
     * @private
     * @override method from field manager mixin
     * @param {string} id
     */
    _confirmSave: function (id) {
  • There should be an empty line between the main function comments and the tags, or parameter descriptions

Widgets

  • Never use a reference to the parent widget

  • Avoid using the 'include' functionality: extending a class is fine and does not cause issue, including a class is much more fragile, and may not work.

  • For the widgets, here is how the various attributes/functions should be ordered:

    1. All static attributes, such as template, events, custom_events, ...

    2. All methods from the lifecycle of a widget, in this order: init, willStart, start, destroy

    3. If there are public methods, a section titled "Public", with an empty line before and after

    4. All public methods, camelcased, in alphabetic order

    5. If there are private methods, a section titled "Private", with an empty line before and after

    6. All private methods, camelcased and prefixed with _, in alphabetic order

    7. If there are event handlers, a section titled "Handlers", with an empty line before and after

    8. All handlers, camelcased and prefixed with _on, in alphabetic order

    9. If there are static methods, they should be in a section titled "Static". All static methods are considered public, camelcased with no _.

  • For the event handlers defined by the key event or custom_events, do not inline the function. Always add a string name, and add the definition in the handler section

  • Use this.$(...) instead of this.$el.find(...)

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.