Firebug Coding Style

From FirebugWiki

(Difference between revisions)
Jump to: navigation, search
(Added rule for comments)
(Improved description related to arrow functions and added example)
(29 intermediate revisions not shown)
Line 2: Line 2:
== Formatting Code ==
== Formatting Code ==
 +
=== File Encoding ===
 +
All source files should be encoded in UTF-8 without [http://en.wikipedia.org/wiki/Byte_order_mark BOM].
=== Whitespace ===
=== Whitespace ===
-
No tabs. No whitespace at the end of a line. But, every line should end with an end-of-line character, also the last line of a file.
+
No tabs. No whitespace at the end of a line. But, every line should end with Unix line break, i.e. a line feed character (<code>\n</code>, Unicode: <code>0x0A</code>), also the last line of a file.
-
Operators are surrounded by spaces as well as parameters in a function call, except the string concatinator.
+
Operators are surrounded by spaces as well as parameters in a function call.
<source lang="javascript">
<source lang="javascript">
-
var text = "Message: "+msgID+": "+msgText;
+
var text = "Message: " + msgID + ": " + msgText;
var result = result ? "positive" : "negative";
var result = result ? "positive" : "negative";
var target = event.target || document.getElementsByTagName("body")[0];
var target = event.target || document.getElementsByTagName("body")[0];
Line 48: Line 50:
=== Commands ===  
=== Commands ===  
-
Every command must end with a semicolon.
+
Every command must end with a semicolon and must be on its own line.
-
 
+
-
Variable definitions should be done separately, not comma-separated.
+
<source lang="javascript">
<source lang="javascript">
Line 57: Line 57:
foo = someFunction();
foo = someFunction();
 +
 +
bar += 3;
 +
return bar;
</source>
</source>
-
=== Licence ===
+
=== License ===
Files should include a license note at the first line of the file:
Files should include a license note at the first line of the file:
Line 82: Line 85:
=== Control Structures ===
=== Control Structures ===
-
Existing Firebug codebase uses braces on the next line like as follows:
+
==== Code Blocks ====
 +
The Firebug codebase uses brackets on the next line like as follows:
<source lang="javascript">
<source lang="javascript">
Line 89: Line 93:
     // ...
     // ...
}
}
 +
 +
foo("test", function bar()
 +
{
 +
    // ...
 +
});
</source>
</source>
-
Yes, there can be exceptions and [http://en.wikipedia.org/wiki/The_C_Programming_Language_%28book%29 K&R] style can be preferred in some cases. For example, definition of a config object.
+
There can be exceptions and [http://en.wikipedia.org/wiki/The_C_Programming_Language_%28book%29 K&R] style can be preferred in some cases. For example the definition of a config object or a one-line arrow function.
<source lang="javascript">
<source lang="javascript">
Line 100: Line 109:
     prop2: "value2",
     prop2: "value2",
};
};
-
</source>
 
-
 
-
Anyway, class and function definitions should always have the braces on the next line as follows:
 
-
 
-
<source lang="javascript">
 
-
Firebug.MyModule = extend(Firebug.Module,
 
-
{
 
-
    initializeUI: function()
 
-
    {
 
-
    },
 
-
});
 
-
</source>
 
-
 
-
<source lang="javascript">
 
-
function myFunction()
 
-
{
 
-
    // ....
 
-
}
 
</source>
</source>
Line 125: Line 116:
if (...)
if (...)
{
{
 +
    ...
}
}
else if (...)
else if (...)
{
{
 +
    ...
}
}
</source>
</source>
Line 154: Line 147:
}
}
</source>
</source>
-
 
-
To avoid misunderstandings ''for'' loops are always written in their long form, i.e. loop heads like <code>for (var i = count; i--; )</code> should be avoided in favor of <code>for (var i = count-1; i>=0; i--)</code>
 
<source lang="javascript">
<source lang="javascript">
-
for (var i=0; i<10; i++)
+
try
 +
{
 +
    ...
 +
}
 +
catch (err)
{
{
 +
    ...
}
}
</source>
</source>
 +
 +
==== Loops ====
 +
To avoid misunderstandings ''for'' loops are always written in their long form, i.e. loop heads like <code>for (var i = count; i--; )</code> should be avoided in favor of <code>for (var i = count - 1; i >= 0; i--)</code>.<br/>
 +
Also there are spaces between the statements and the operands and you should write <code>i++</code> instead of <code>++i</code>.
<source lang="javascript">
<source lang="javascript">
-
try
+
for (var i = 0; i < 10; i++)
-
{
+
-
}
+
-
catch (err)
+
{
{
 +
    ...
}
}
</source>
</source>
 +
==== Ternary expressions ====
 +
Ternary expressions must be wrapped in brackets for clarity.
 +
 +
<source lang="javascript">
 +
var variable = (condition ? true : false);
 +
</source>
 +
 +
==== Braces and brackets ====
Firebug prefers no braces, if they are not necessary.
Firebug prefers no braces, if they are not necessary.
Line 190: Line 196:
else
else
{
{
-
     dump(2);
+
     dump("2");
}
}
</source>
</source>
Line 205: Line 211:
     dump(2);
     dump(2);
}
}
 +
</source>
 +
 +
Firebug prefers no brackets for operators like <code>typeof</code>.
 +
 +
<source lang="javascript">
 +
if (typeof variable == "object")
 +
    return false;
 +
</source>
 +
 +
=== Functions ===
 +
Class and function definitions should always have the braces on the next line as follows:
 +
 +
<source lang="javascript">
 +
Firebug.MyModule = extend(Firebug.Module,
 +
{
 +
    initializeUI: function()
 +
    {
 +
    },
 +
});
 +
</source>
 +
 +
<source lang="javascript">
 +
function myFunction()
 +
{
 +
    // ....
 +
}
 +
</source>
 +
 +
There's one exception related to [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/arrow_functions arrow functions]. If an arrow function is a simple one-liner, braces around the function body and the <code>return</code> statement are not necessary. If braces are set, they can be placed on the same line.
 +
 +
<source lang="javascript">
 +
Object.defineProperty(dbg, "onExceptionUnwind", {
 +
    set: (hook) => { threadHook = hook; },
 +
    get: () => threadHook
 +
});
</source>
</source>
Line 210: Line 251:
Multi-line as well as single line comments should always be put into their own line.
Multi-line as well as single line comments should always be put into their own line.
So you should write:
So you should write:
 +
<source lang="javascript">
<source lang="javascript">
// This is a comment
// This is a comment
var abc = xyz;
var abc = xyz;
 +
</source>
 +
 +
Comments for blocks of code will be placed above them.
 +
 +
<source lang="javascript">
 +
if (foo == "bar")
 +
{
 +
    ...
 +
}
 +
// foo is not set to "bar"
 +
else
 +
{
 +
    ...
 +
}
 +
</source>
 +
 +
To describe what specific functions do, especially published APIs, [http://en.wikipedia.org/wiki/JSDoc JSDoc] comments are used.
 +
 +
<source lang="javascript">
 +
/**
 +
* Returns the domain of a given URL
 +
*
 +
* @param {string} url URL, for which to get the domain
 +
*
 +
* @return {string} Domain
 +
*/
 +
Url.getDomain = function(url)
 +
{
 +
    var m = /[^:]+:\/{1,3}([^\/]+)/.exec(url);
 +
    return m ? m[1] : "";
 +
};
</source>
</source>
Line 228: Line 301:
     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
</source>
</source>
 +
 +
=== Module Dependencies ===
 +
Required modules at the top of a module should be listed in a specific order. That is:
 +
 +
# <code>firebug/firebug</code>
 +
# <code>lib/trace</code>
 +
# Other <code>lib/</code> modules
 +
# Other modules
 +
 +
<source lang="javascript">
 +
define([
 +
    "firebug/firebug",
 +
    "firebug/lib/trace",
 +
    "firebug/lib/css",
 +
    "firebug/lib/dom",
 +
    ...
 +
    "firebug/chrome/eventSource",
 +
    "firebug/chrome/infoTip",
 +
    ...
 +
],
 +
</source>
 +
 +
The preferred sorting order for the other modules is alphabetically ascending.
== Naming ==
== Naming ==
 +
 +
American English is used for all labels and comments. That means, that you should write e.g. <code>synchronize</code> instead of <code>synchronise</code> or <code>color</code> instead of <code>colour</code>.
=== Functions and Methods ===
=== Functions and Methods ===
Functions should use camelCase but should not capitalize the first letter.
Functions should use camelCase but should not capitalize the first letter.
 +
 +
Functions names must start with a verb. There are two exceptions to this rule, though:
 +
 +
* Functions passed as parameters to another function, i.e. callbacks. They can be named just <code>callback</code> or describe the event when they are called.
 +
* Event handlers should be prefixed by "on" to describe when the handler is called.
<source lang="javascript">
<source lang="javascript">
-
function foo()
+
function initialize()
{
{
 +
    ...
}
}
</source>
</source>
<source lang="javascript">
<source lang="javascript">
-
function myFoo()
+
function getLocationList()
{
{
 +
    ...
 +
}
 +
</source>
 +
 +
<source lang="javascript">
 +
function eachPanel(callback)
 +
{
 +
    ...
 +
}
 +
</source>
 +
 +
<source lang="javascript">
 +
function setBreakpoints(afterBreakpointsAdded)
 +
{
 +
    ...
 +
}
 +
</source>
 +
 +
<source lang="javascript">
 +
onBreakpointAdded: function(context, bp)
 +
{
 +
    ...
}
}
</source>
</source>
Line 252: Line 378:
function ObjectConstructor()
function ObjectConstructor()
{
{
 +
    ...
}
}
</source>
</source>
Line 266: Line 393:
     myMethod: function()
     myMethod: function()
     {
     {
 +
        ...
     }
     }
};
};
Line 280: Line 408:
=== Variables ===
=== Variables ===
-
Variables should use camelCase and not capitalize the first letter.
+
Variables should use camelCase and not capitalize the first letter. Variable definitions should be done separately, not comma-separated. They don't have to be initialized immediately but before they are used.
 +
If abbreviations are used, they should be written lower case at the beginning of a variable but in capitals when they are in the middle of the name. Also they should not be a single character.
<source lang="javascript">
<source lang="javascript">
-
var thisIsMyVariable = true;
+
var myFirstVariable = true;
 +
var mySecondVariable = false;
 +
var url = "http://getfirebug.com/wiki";
 +
var baseURL = "http://getfirebug.com/";
</source>
</source>
=== Prefixes ===
=== Prefixes ===
Firebug codebase doesn't use any prefixes for member fields.
Firebug codebase doesn't use any prefixes for member fields.
 +
 +
=== Preferences ===
 +
Firebug preference names are written in camelCase and are made up by `extensions.firebug.` + preference name. If the preference is related to a specific module, prepend it by its name.
 +
 +
<source lang="properties">
 +
extensions.firebug.showFirstRunPage
 +
extensions.firebug.netShowBFCacheResponses
 +
</source>
== Good Practices ==
== Good Practices ==
Line 299: Line 439:
     initialize: function()
     initialize: function()
     {
     {
 +
        ...
     },
     },
     shutdown: function()
     shutdown: function()
     {
     {
 +
        ...
     }
     }
});
});
Line 334: Line 476:
</source>
</source>
-
== Example File ==
+
=== Strict Mode ===
-
Example of a typical Firebug file implementing a module object. Firebug namespaces (FBL.ns) are no longer the preferred way for Firebug files. See AMD below.
+
 
 +
Source files should include a "use strict"; directive below the AMD imports separated by an empty line before and after it:
<source lang="javascript">
<source lang="javascript">
/* See license.txt for terms of usage */
/* See license.txt for terms of usage */
 +
 +
define([
 +
    "firebug/firebug",
 +
    "firebug/domplate"
 +
],
 +
function(Firebug, Domplate) {
-
FBL.ns(function() {
+
"use strict";
-
// ********************************************************************************************* //
+
// ...
-
// Constants
+
-
var MY_CONSTANT = true;
 
-
 
-
// ********************************************************************************************* //
 
-
// Module Implementation
 
-
 
-
Firebug.MyModule = extend(Firebug.Module,
 
-
{
 
-
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-
    // Initialization
 
-
 
-
    initializeUI: function()
 
-
    {
 
-
    },
 
-
 
-
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-
    // Toolbar Actions
 
-
 
-
    myButtonHandler: function()
 
-
    {
 
-
    }
 
-
});
 
-
 
-
// ********************************************************************************************* //
 
-
// Registration
 
-
 
-
Firebug.registerModule(Firebug.StartButton);
 
-
 
-
// ********************************************************************************************* //
 
});
});
</source>
</source>
-
 
-
The code should also have [[Firebug Source Code Comments|comments]].
 
== Example Module File ==
== Example Module File ==
Line 385: Line 503:
define([
define([
-
    "firebug/lib",
 
     "firebug/firebug",
     "firebug/firebug",
-
     "firebug/domplate"
+
     "firebug/lib/trace",
 +
    "firebug/lib/domplate",
 +
    "firebug/lib/object"
],
],
-
function(FBL, Firebug, Domplate) {
+
function(Firebug, Obj, Domplate) {
 +
 
 +
"use strict";
// ********************************************************************************************* //
// ********************************************************************************************* //
Line 399: Line 520:
// Module Implementation
// Module Implementation
-
Firebug.MyModule = extend(Firebug.Module,
+
Firebug.MyModule = Obj.extend(Firebug.Module,
{
{
     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Line 428: Line 549:
The code should also have [[Firebug Source Code Comments|comments]].
The code should also have [[Firebug Source Code Comments|comments]].
 +
 +
== Resources ==
 +
* [https://github.com/fflorent/firebug_vimrc/ vimrc file] supporting Firebug coding style.
== See also ==
== See also ==
* [[Firebug Modules]]
* [[Firebug Modules]]
* [[Firebug Source Code Comments]]
* [[Firebug Source Code Comments]]
 +
* [[Firebug Localization]]
* [https://developer.mozilla.org/en/JavaScript_Tips Mozilla JavaScript Tips]
* [https://developer.mozilla.org/en/JavaScript_Tips Mozilla JavaScript Tips]
* [https://developer.mozilla.org/en/Developer_Guide/Coding_Style Mozilla Coding Style]
* [https://developer.mozilla.org/en/Developer_Guide/Coding_Style Mozilla Coding Style]

Revision as of 00:38, 11 March 2014

This document attempts to explain the basic styles and patterns, that are used in the Firebug codebase. New code should try to conform to these standards, so that it is as easy to maintain as existing code. Of course every rule has an exception, but it's important to know the rules nonetheless!

Contents

Formatting Code

File Encoding

All source files should be encoded in UTF-8 without BOM.

Whitespace

No tabs. No whitespace at the end of a line. But, every line should end with Unix line break, i.e. a line feed character (\n, Unicode: 0x0A), also the last line of a file.

Operators are surrounded by spaces as well as parameters in a function call.

var text = "Message: " + msgID + ": " + msgText;
var result = result ? "positive" : "negative";
var target = event.target || document.getElementsByTagName("body")[0];
var expression = getExpressionAt(rangeParent.data, rangeOffset);

The incrementation and decrementation operators are not separated by spaces. So e.g. you should write while(i-- > 0) instead of while(i --> 0) to avoid misinterpretations.

Source File Size

A source file should avoid huge amount of code lines. Couple thousands of lines in a file is already a lot. Firebug is using AMD syntax and more smaller files (modules) is preferred.

Line Length

100 characters or less. There is no exception in *.js files! In some cases this rule can be broken in *.html or *.xul files. But keep in mind long lines are hard to read (also search results are hard to read).

When wrapping lines, operators stay at the end of a line.

if ((... &&
    ...) ||
    ...)
{
}
var string = ... +
    ...;

Also member operators stay at the end of the line.

var service = Cc[...].
    getService(...);

Indentation

Four spaces per logic level.

Commands

Every command must end with a semicolon and must be on its own line.

var foo = 1;
var bar = 2;
 
foo = someFunction();
 
bar += 3;
return bar;

License

Files should include a license note at the first line of the file:

/* See license.txt for terms of usage */
...

In case of *.xml files (e.g. in overlays), this must be after XML declaration, for example:

<?xml version="1.0"?>
<!-- See license.txt for terms of usage -->
...
</xml>

In case of *.properties or *.manifest files, this must be commented using # character.

# See license.txt for terms of usage
...

Control Structures

Code Blocks

The Firebug codebase uses brackets on the next line like as follows:

function foo()
{
    // ...
}
 
foo("test", function bar()
{
    // ...
});

There can be exceptions and K&R style can be preferred in some cases. For example the definition of a config object or a one-line arrow function.

var foo = { prop1: "value1" };
 
var bar = {
    prop1: "value1",
    prop2: "value2",
};

Control structures should look like as follows (also notice the spacing between a keyword and the left bracket):

if (...)
{
    ...
}
else if (...)
{
    ...
}

Another example showing how to deal with spaces:

if ((a > 0) && (b > 0))
{
}
switch (...)
{
    case 1:
        ...
        break;
 
    case 2:
        ...
        break;
 
    default:
        ...
}
try
{
    ...
}
catch (err)
{
    ...
}

Loops

To avoid misunderstandings for loops are always written in their long form, i.e. loop heads like for (var i = count; i--; ) should be avoided in favor of for (var i = count - 1; i >= 0; i--).
Also there are spaces between the statements and the operands and you should write i++ instead of ++i.

for (var i = 0; i < 10; i++)
{
    ...
}

Ternary expressions

Ternary expressions must be wrapped in brackets for clarity.

var variable = (condition ? true : false);

Braces and brackets

Firebug prefers no braces, if they are not necessary.

if (...)
    dump(true);
else
    dump(false);

But if one of the branches needs braces use them for all. Also note

if (...)
{
    dump("0");
    dump("1");
}
else
{
    dump("2");
}

If the head of a control structure is wrapped into several lines because it is longer than the maximum line length, also use braces, even when the block just contains one line.

if (...
    ...)
{
    dump("0");
}
else
{
    dump(2);
}

Firebug prefers no brackets for operators like typeof.

if (typeof variable == "object")
    return false;

Functions

Class and function definitions should always have the braces on the next line as follows:

Firebug.MyModule = extend(Firebug.Module,
{
    initializeUI: function()
    {
    },
});
function myFunction()
{
    // ....
}

There's one exception related to arrow functions. If an arrow function is a simple one-liner, braces around the function body and the return statement are not necessary. If braces are set, they can be placed on the same line.

Object.defineProperty(dbg, "onExceptionUnwind", {
    set: (hook) => { threadHook = hook; },
    get: () => threadHook
});

Comments

Multi-line as well as single line comments should always be put into their own line. So you should write:

// This is a comment
var abc = xyz;

Comments for blocks of code will be placed above them.

if (foo == "bar")
{
    ...
}
// foo is not set to "bar"
else
{
    ...
}

To describe what specific functions do, especially published APIs, JSDoc comments are used.

/**
 * Returns the domain of a given URL
 * 
 * @param {string} url URL, for which to get the domain
 * 
 * @return {string} Domain
 */
Url.getDomain = function(url)
{
    var m = /[^:]+:\/{1,3}([^\/]+)/.exec(url);
    return m ? m[1] : "";
};

Horizontal Lines

Sometimes it is helpful to divide portions of a file by a horizontal line. For this you should use following comment (100 characters long):

// ********************************************************************************************* //

Firebug codebase also uses the following horizontal separator for dividing members of one object (this separator uses indentation (4 spaces) since it's used within an object scope that is indented (100 characters long).

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

Module Dependencies

Required modules at the top of a module should be listed in a specific order. That is:

  1. firebug/firebug
  2. lib/trace
  3. Other lib/ modules
  4. Other modules
define([
    "firebug/firebug",
    "firebug/lib/trace",
    "firebug/lib/css",
    "firebug/lib/dom",
    ...
    "firebug/chrome/eventSource",
    "firebug/chrome/infoTip",
    ...
],

The preferred sorting order for the other modules is alphabetically ascending.

Naming

American English is used for all labels and comments. That means, that you should write e.g. synchronize instead of synchronise or color instead of colour.

Functions and Methods

Functions should use camelCase but should not capitalize the first letter.

Functions names must start with a verb. There are two exceptions to this rule, though:

  • Functions passed as parameters to another function, i.e. callbacks. They can be named just callback or describe the event when they are called.
  • Event handlers should be prefixed by "on" to describe when the handler is called.
function initialize()
{
    ...
}
function getLocationList()
{
    ...
}
function eachPanel(callback)
{
    ...
}
function setBreakpoints(afterBreakpointsAdded)
{
    ...
}
onBreakpointAdded: function(context, bp)
{
    ...
}

Objects

Constructors for objects should be capitalized and use CamelCase.

function ObjectConstructor()
{
    ...
}
Firebug.MyModule = extend(Firebug.Module,
{
});
MyObject.prototype = ()
{
    myMethod: function()
    {
        ...
    }
};

Constants

Constants should be capitalized as follows:

var MY_CONSTANT = true;

Use var instead of const, since the code can also be used in the browser environment where const is not supported.

Variables

Variables should use camelCase and not capitalize the first letter. Variable definitions should be done separately, not comma-separated. They don't have to be initialized immediately but before they are used. If abbreviations are used, they should be written lower case at the beginning of a variable but in capitals when they are in the middle of the name. Also they should not be a single character.

var myFirstVariable = true;
var mySecondVariable = false;
var url = "http://getfirebug.com/wiki";
var baseURL = "http://getfirebug.com/";

Prefixes

Firebug codebase doesn't use any prefixes for member fields.

Preferences

Firebug preference names are written in camelCase and are made up by `extensions.firebug.` + preference name. If the preference is related to a specific module, prepend it by its name.

extensions.firebug.showFirstRunPage
extensions.firebug.netShowBFCacheResponses

Good Practices

Vertical Indentation

Method defintions should be separated by a new line. Note the new line between initialize and shutdown methods.

Firebug.MyModule = extend(Firebug.Module,
{
    initialize: function()
    {
        ...
    },
 
    shutdown: function()
    {
        ...
    }
});

Also portions of code logically belonging together should be separated by a new line from other code. Note the new line between super.initialize and this.onMutateText.

initialize: function()
{
    super.initialize.apply(this, arguments);
 
    this.onMutateText = bind(this.onMutateText, this);
    this.onMutateAttr = bind(this.onMutateAttr, this);
    this.onMutateNode = bind(this.onMutateNode, this);
}

Horizontal lines should be surrounded by new lines too

function myFunc1()
{
}
 
// ********************************************************************************************* //
 
function myFunc2()
{
}

Strict Mode

Source files should include a "use strict"; directive below the AMD imports separated by an empty line before and after it:

/* See license.txt for terms of usage */
 
define([
    "firebug/firebug",
    "firebug/domplate"
],
function(Firebug, Domplate) {
 
"use strict";
 
// ...
 
});

Example Module File

Example of a typical asynchronous module definition (AMD). Every file in Firebug source base should use the AMD pattern starting from Firebug 1.8.

/* See license.txt for terms of usage */
 
define([
    "firebug/firebug",
    "firebug/lib/trace",
    "firebug/lib/domplate",
    "firebug/lib/object"
],
function(Firebug, Obj, Domplate) {
 
"use strict";
 
// ********************************************************************************************* //
// Constants
 
var MY_CONSTANT = true;
 
// ********************************************************************************************* //
// Module Implementation
 
Firebug.MyModule = Obj.extend(Firebug.Module,
{
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Initialization
 
    initializeUI: function()
    {
    },
 
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Toolbar Actions
 
    myButtonHandler: function()
    {
    }
});
 
// ********************************************************************************************* //
// Registration
 
Firebug.registerModule(Firebug.MyModule);
 
return Firebug.MyModule;
 
// ********************************************************************************************* //
});

The code should also have comments.

Resources

See also

Personal tools