Skip to content

Javascript coding guidelines

Quentin Smetz edited this page Mar 16, 2020 · 23 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
    },
    "parser": "babel-eslint",
    "parserOptions": {
        "ecmaVersion": 6,
        "sourceType": "module",
        "ecmaFeatures": {
            "jsx": false,
            "modules": true,
            "experimentalObjectRestSpread": true
        }
    },
    "extends": "eslint:recommended",
    "rules": {
        "array-bracket-spacing": ["warn", "never"],
        "brace-style": "warn",
        "camelcase": ["warn", {"properties": "never"}],
        "comma-dangle": ["off"],
        "comma-spacing": ["warn", {"before": false, "after": true}],
        "curly": ["warn"],
        "eol-last": ["error"],
        "eqeqeq": ["warn", "smart"],
        "indent": ["off", 4, {"SwitchCase": 1}],
        "key-spacing": ["warn"],
        "keyword-spacing": ["warn"],
        "linebreak-style": ["error", "unix"],
        "no-console": ["warn", {"allow": ["warn", "error"]}],
        "no-empty": ["warn"],
        "no-multi-spaces": ["warn"],
        "no-redeclare": ["warn"],
        "no-unused-expressions": ["warn"],
        "no-unused-vars": ["warn", {"args": "none"}],
        "no-use-before-define": ["warn", "nofunc"],
        "object-curly-spacing": ["warn", "never"],
        "quotes": ["off", "double"],
        "semi": ["error", "always"],
        "semi-spacing": ["warn", {"before": false, "after": true}],
        "space-before-blocks": ["warn"],
        "space-before-function-paren": ["warn", {"anonymous": "always", "named": "never"}],
        "space-infix-ops": ["warn"],
        "space-in-parens": ["warn", "never"]
    },
    "globals": {
        "openerp": true, "odoo": true, "CKEDITOR": true, "we3": true,

        "$": false, "jQuery": false, "_": false, "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, "PDFJS": false, "ClipboardJS": false, "PDFSlidesViewer": false,
        "MutationObserver": false, "Element": false, "URL": 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(...)

Clone this wiki locally