style guide
shows the preferred conventions and, most importantly, it explains why the use of javascript programming language in Axional Studio
.1 Style guide vocabulary
Each guideline indicates its category. It can have the next values:
- Required: Its rules should always be followed.
- Recommended: Its rules generally should be followed.
- Avoid: Its rules indicate something you should rarely do.
In some cases, the guideline shows one example of good use and also, one example of bad use.
2 Functions
2.1 Catalogued functions
To use Javascript functions on Axional Studio
, they must be catalogued in a dictionary database system. (Table: wic_dbscripts_js_funcs)
-
Required: The
Catalogued JS function
name has to be the same as the last function defined in the content.This incorrect example defines
Catalogued JS function
addClient and the name of the js function is a different one:Copyfunction addClient(pStrCIF) { console.log("addClient function is different than Catalogued JS function"); } addClient("A99999999");
This incorrect example defines
Catalogued JS function
addClient with two main functions (addClient and __concatAddress):Copyfunction addClient(pStrCif) { console.log("addClient") } function __concatAddress(pStrAddress, pStrCipcode, pStrCity) { console.log("__concatAddress") } addClient("A99999999"); __concatAddress("carrer londres", "08001", "Barcelona");
Copyfunction addClient(pStrCif) { function __concatAddress(pStrAddress, pStrCipcode, pStrCity) { console.log("__concatAddress") } console.log("addClient") __concatAddress("carrer londres", "08001", "Barcelona"); } addClient("A99999999");
2.2 Local functions
To use local functions on Axional Studiom, they must be declared inside of a catalogued function.
-
Required: Use local functions to small services only used on the Catalogued JS functions.
Bad use: Create a local function used on diferents Catalogued JS functions
Copyfunction addClient(pStrID, pStrName, pStrCIF, pStrAddress, pStrPostCode, pStrCity) { function __checkIFExistsClient(pStrID) { if (pStrID == '999') { return false; } else { console.log("CLIENT NOT EXISTS") } return true; } function __concatAddress(pStrAddress, pStrPostCode, pStrCity) { let mStrConcat = pStrAddress + ' ' + pStrPostCode + ' ' + pStrCity; console.log("Concat address") return mStrConcat; } // Check if client exist __checkIFExistsClient(pStrID) //Concat address let mStrConcatAddress = __concatAddress(pStrAddress, pStrPostCode, pStrCity); //Add the client let mStrClient = pStrName + ' ' + mStrConcatAddress console.log("Add client"); return mStrClient } let mStrResult = addClient(1, 'SUMINISTRES INTERCITY', 'B99999999', 'Carrer Londres', '08001', 'Barcelona'); return mStrResult;
Create a local function only used in specific Catalogued JS functions
Copyfunction addClient(pStrID, pStrName, pStrCIF, pStrAddress, pStrPostCode, pStrCity) { // Local function wicht checks if client exist function __checkIFExistsClient(pStrID) { if (pStrID == '999') { return false; } else { console.log("CLIENT NOT EXISTS") } return true; } //Local function wicht concat address function __concatAddress(pStrAddress, pStrPostCode, pStrCity) { let mStrConcat = pStrAddress + ' ' + pStrPostCode + ' ' + pStrCity; console.log("Concat address") return mStrConcat; } let mBoolClientExist = __checkIFExistsClient(pStrID); //Concat address if(mBoolClientExist) { let mStrConcatAddress = __concatAddress(pStrAddress, pStrPostCode, pStrCity); //Add the client let mStrClient = pStrName + ' ' + mStrConcatAddress console.log("Add client"); return mStrClient } } let mStrResult = addClient(1, 'SUMINISTRES INTERCITY', 'B99999999', 'Carrer Londres', '08001', 'Barcelona'); return mStrResult;
-
Recommended: Limit it to no more than 75 lines.
2.3 Catalogued libraries
To use Javascript libraries on Axional Studio
, they must be catalogued inside a dictionary database system. (Table: wic_dbscript_js_libs)
2.4 Single responsability
Apply the single responsibility principle (SRP) to all functions. This helps make the app cleaner, easier to read and maintain, and makes testing simpler.
-
Required: Define one thing, service or component, by file. One service makes it easier to read and test.
The following incorrect example defines two services, check cif and add client, in the same
Catalogued JS function
called addClient:Copyfunction addClient(pStrID, pStrName, pStrCIF) { console.log("Add client"); //Check the cif if (pStrCIF.length > 20) { throw new Error("CIF can't be more greater than 20 characters"); } else { console.log("CIF is correct"); } //Add the client console.log("Add client"); let mStrClientInfo = 'ID: ' + pStrID + '. Name: ' + pStrName + ' (' + pStrCIF + ').'; return mStrClientInfo; } mStrClient = addClient(1, "SUMINISTRES CARLES", "B99999999"); return mStrClient;
We have to define two Catalogued JS functions to separate checkCIF and add client services:
- checkCIF:
Copy
function checkCIF(pStrCIF) { if (pStrCIF.length > 9) { return false; } else { console.log("Check cif"); } return true; }
- addClient:
Copy
function addClient(pStrID, pStrName, pStrCIF) { if (Ax.db.call("checkCIF", pSrtCIF)) { console.log("Add client") } else { return false; } return true; } addClient(1, "SUMINISTRES CARLES", "B99999999");
- checkCIF:
-
Recommended: File length shoud be less than 400 lines. A greater file is dificult to read and mantain.
3 Naming
3.1 Catalogued JS functions
Recommended: Catalogued JS function
names must be all with lower case character and include underscores.
Recommended: Name should follow this structure: f[wic_id]_[funct_name];
- wic_id: Wic identifier. Length has to be smaller than 6 digits.
-
funct_name: Name function. When the name has different words, separate it by underscores.
Functions should be named using a verb, and a noun. When functions perform some type of action on a resource,
thir name should reflect that. A role model format to follow is
action_resource
. For example,get_user
.
function testInvoices() { console.log("testInvoices"); }
3.2 Local functions
Required: Catalogued JS function
names must be camelCase.
Required: Prefix has to be two underscores.
Required: Functions should be named using a verb, and a noun. When functions perform some type of action on a resource, its name should reflect that. A good format to follow is actionResource
. For example, getUser
.
Bad use:
function __userData(pStrUserId) { console.log("__userData") }; function __userDataFunc(pStrUserId) { console.log("__userDataFunc") } function __totalOfItems(pIntItems) { console.log("__totalOfItems") }
Create a local function only used in specific Catalogued JS functions
function createInvoice() { function __getUser(pStrUserId) { console.log("__getUser"); } function __calculateTotal(pIntItems) { console.log("__calculateTotal"); } }
3.3 Parameters
A parameter or argument is a special kind of variable, used in a subroutine to refer to one of the pieces of data provided as an input to the subroutine.
3.3.1 General parameters
For those parameters of general purpose we provide the following recommendations:
Required: Parameter names must be camelcase.
Required: Prefix has to be the character 'p'.
function __concatAddress(pStrCityCode, pStrAddressName) { // ... }
3.3.2 Business logic parameters
Axional JS Scripts are commonly used in business logic, so most parameters and variables reference directly
the value of specific column names of database tables.
As the style guide
of the database model specifies to use lower case and hyphen separator for column names, on that case, we provide the following recommendations:
Required: Parameter names must be lowercase.
Required: Prefix has to be 'p_'-
function __concatAddress(p_city_code, p_address_name) { // ... }
3.4 Variables
Required: Parameter names must be camelCase.
Next rules have been established for different variable types:
3.4.1 Variable name convention
Type | Prefix | Example | Recomended |
---|---|---|---|
String | [mpg]str | mStrCityName | The string variable has to describe the content. In almost all cases has to be a name. |
Integer | [mpg]Int | mIntMinFact | For numbers, think about words that describe numbers. Words like maximum, minimum, total will. |
Number | [mpg]Num | mNumMinFact | For numbers, think about words that describe numbers. Words like maximum, minimum, total will. |
Big decimal Object | [mpg]Bc | mBcMinFact | For numbers, think about words that describe numbers. Words like maximum, minimum, total will. |
Date | [mpg]Date | mDateInvoiceDate | On date objects use a prefix or a suffix date. |
Boolean | [mpg]Bool | mBoolIsFieldEntry | Booleans can hold only 2 values, true or false. Given this, using prefixes like is, has, and can, will help the reader infer the type of the variable. |
Array | [mpg]Arr | mArrStatusCodes | Arrays are an iterable list of items, usually of the same type. Since they will hold multiple values, pluralizing the variable name makes sense. |
Resultset | [mpg]Rs | mRsSysTables | For resultsets use prefix rs. |
ResultsetRowMap | [mpg]Row | mRowSysTable | For ResultsetRowMap use prefix row |
Objects (JSON) | [mpg]Obj | mObjInvoices | For javascript objects (JSON) use prefix obj. |
3.4.2 Examples
Recommended: The string variable has to describe the content. In almost all cases has to be a name. Above any examples:
const mStrCityName = 'BARCELONA'; const mSqlCond = `city = '${mStrCityName}'`;
3.4.3 Number
Recommended: For numbers, think about words that describe numbers. Words like maximum
, minimum
, total
will.
const mIntMinFact = 1; const mIntMaxFact = 5; const mIntTotalFacts = 3;
3.4.4 Date
Recommended: On date objects use prefix or sufix date.
const mDateInvoiceDate = new Ax.sql.Date(); const mDateBirthDate = new Ax.sql.Date();
3.4.5 Boolean
Recommended: Booleans can hold only 2 values, true or false. Given this, using prefixes like is
, has
, and can
will help the reader infer the type of the variable.
const mBoolIsFieldEntry = true; const mBoolCanInsert = true;
3.4.6 Array
Recommended: Arrays are an iterable list of items, usually of the same type. Since they will hold multiple values, pluralizing
the variable name makes sense.
const mArrStatusCodes = ['OPEN', 'PROGRESS', 'CLOSED']; const mArrStatus = [{ name: 'OPEN', value: 1 }, { name: 'PROGRESS', value: 2 }, { name: 'CLOSED', value: 3 }];
3.4.7 Resultset
Recommended: For resultsets use prefix rs
.
let mRsSysTables = Ax.db.executeQuery(` <select> <columns>*</columns> <from table='systables'/> </select> `);
3.4.8 ResultsetRowMap
Recommended: For ResultsetRowMap use prefix row
.
let mRsSysTables = Ax.db.executeQuery(` <select> <columns>*</columns> <from table='systables'/> </select> `); for (let mRowSysTable of mRsSysTables) { console.log(mRowSysTable); }
3.4.9 Objects (JSON)
Recommended: For javascript objects (JSON) use prefix obj
.
let mObjInvoices = { num: 12, date: new Ax.sql.Date(), import: 123 }
4 Formating
4.1 Indentation
- Recommended: use tabs to indent code. Tabs must be set every 4 spaces.
- Avoid: Lines longer than 80 characters.
-
Recommended: When an expression will not fit on a single line, break it according to these general principles:
- If the below rules lead to confusing code or to code that's squished up against the right margin, just indent 8 spaces instead. Prefer higher-level breaks to lower-level breaks.
- Break after a comma.
Bad use
CopyAx.db.call("studioFunctionTest", parameter1, parameter2, parameter3, parameter4, parameter5, parameter6, parameter7, parameter8);
Good use
CopyAx.db.call("studioFunctionTest", parameter1, parameter2, parameter3, parameter4, parameter5, parameter6, parameter7, parameter8);
- Break after multiple variable definition.
Bad use
Copyconst mStrConstA = 'A', mStrConstB = 'B', mStrConstC = 'C';
Good use
Copyconst mStrConstA = 'A', mStrConstB = 'B', mStrConstC = 'C';
- Break before an operator.
Bad use
Copylet mBcOperation = mBcLongNum2 * (mBcLongNum3 + mBcLongNum4 - mBcLongNum5) + 4 * mBcLongNum6;
Bad use
Copylet mBcOperation = mBcLongNum2 * (mBcLongNum3 + mBcLongNum4 - mBcLongNum5) + 4 * mBcLongNum6;
Good use
Copylet mBcOperation = mBcLongNum2 * (mBcLongNum3 + mBcLongNum4 - mBcLongNum5) + 4 * mBcLongNum6;
- Align the new line with the beginning of the expression at the same level on the previous line.
Bad use
CopyAx.db.call("studioFunctionTest", parameter1, Ax.db.call("studioFunctionTest", parameter3), parameter4, parameter5, parameter6, parameter7, parameter8);
Good use
CopyAx.db.call("studioFunctionTest", parameter1, Ax.db.call("studioFunctionTest", parameter3), parameter4, parameter5, parameter6, parameter7, parameter8);
- Line wrapping for if statements should generally use the 8-space rule, since conventional (4 space) indentation makes seeing the body difficult.
Bad use
Copyif ((condition1 && condition2) || (condition3 && condition4) ||!(condition5 && condition6)) { console.log("...") }
Good use
Copyif ((condition1 && condition2) || (condition3 && condition4) || !(condition5 && condition6)) { console.log("...") }
-
Recommended: Not use block indentation on array literals, excepts, when array values are too long or contains an object
Bad use
Copyconst mArrValuesCodes = [ 3, 4, 5 ]
Good use
Copyconst mArrValuesCodes = [3, 4, 5]; const mArrValuesCodes2 = [ { a: "1", b: "2" }, { a: "1", b: "2" } ]
-
Required: Use block indentation on javascript objects.
Bad use
Copyconst mObjProperties = { a: "1", b:"2"};
Good use
Copyconst mObjProperties = { a : "1", b : "2" };
-
Required: Use block indentation when declaring an anonymous function in the list of arguments for a function call.
Bad use
CopymRsRecord.forEach((mRowTest) => { console.log("...") });
Good use
CopymRsRecord.forEach((mRowTest) => { console.log("...") });
-
Recommended: Not use braces if function only execute one statement.
Bad use
CopymRsRecord.forEach((mRowTest) => console.log("..."));
Good use
CopymRsRecord.forEach((mRowTest) => { console.log("...") });
-
Required: Use block indentation on swith case statement. After switch expression and after case expression. In addition, use a blank line between a break and the following case.
Bad use
Copyswitch(param1) { case 'A': console.log('A'); break; case 'B': console.log('B'); break; }
Good use
Copyswitch(param1) { case 'A': console.log('A'); break; case 'B': console.log('B'); break; default: console.log('default'); }
4.2 Statements
-
Required: Define one statement per line.
Bad use
Copyconst mStrA = "1"; console.log(mStrA); const mStrB = "2", mStrC = "3";
Good use
Copyconst mStrA = "1"; console.log(mStrA); const mStrB = "2", mStrC = "3";
-
Required: Every statement must be terminated with a semicolon.
Bad use
Copyconst mStrA = "1" console.log(mStrA)
Good use
Copyconst mStrA = "1"; console.log(mStrA);
4.3 Braces
-
Recommended: Follow the Kernighan and Ritchie style (Egyptian brackets) for nonempty blocks and block-like constructs:
- No line break before the opening brace.
- Line break after the opening brace.
- Line break before the closing brace, except when the next instruction is an else or else if.
- Line break after the closing brace if that brace terminates a statement or the body of a function or class statement, or a class method. Specifically, there is no line break after the brace if it is followed by else, catch, while, or a comma, semicolon, or right-parenthesis.
Bad use
Copyfunction fStudioExample(pStrStatus) { if (pStrStatus == "P") { console.log("...") } else { } }
Good use
Copyfunction fStudioExample(pStrStatus) { if (pStrStatus == "P") { console.log("...") } else { } }
-
Avoid: not use brackets, even if the body contains only a single statement.
Bad use
Copyfunction fStudioExample(pStrStatus) { if (pStrStatus == "P") console.log("P"); if (pStrStatus == "L") console.log("L"); }
Good use
Copyfunction fStudioExample(pStrStatus) { if (pStrStatus == "P") { console.log("P"); } if (pStrStatus == "L") { } }
4.4 Blank lines
-
Required: Use blank lines between consecutive functions.
Bad use
Copyfunction ficoServerFunction() { function __functionA() { console.log("...") } function __functionB() { console.log("...") } }
Good use
Copyfunction ficoServerFunction() { function __functionA() { console.log("...") } function __functionB() { console.log("...") } }
-
Recommended: Use blank lines within method bodies, sparingly to create logical groupings of statements.
Bad use
Copyfunction ficoServerFunction() { function __functionA() { const mStrConstA = "A", mArrValuesA = [1, 2, 3, 4]; mArrValuesA.forEach(item => { console.log(mStrConstA, item); }); const mStrConstB = "B", mArrValuesB = [5, 6, 7, 8]; mArrValuesB.forEach(item => { console.log(mStrConstB, item); }); } }
Good use
Copyfunction ficoServerFunction() { function __functionA() { const mStrConstA = "A", mArrValuesA = [1, 2, 3, 4]; mArrValuesA.forEach(item => { console.log(mStrConstA, item); }); const mStrConstB = "B", mArrValuesB = [5, 6, 7, 8]; mArrValuesB.forEach(item => { console.log(mStrConstB, item); }); } }
-
Avoid: Use blank lines at the start or end of a function body.
Bad use
Copyfunction ficoServerFunction() { function __functionA() { const mStrConstA = "A"; console.log(mStrConstA); } }
Good use
Copyfunction ficoServerFunction() { function __functionA() { const mStrConstA = "A"; console.log(mStrConstA); } }
4.5 White space
-
Required: Separating any reserved word:
-
if
,for
,while
,switch
,case
orcatch
from an open parenthesis (() that follows it on that line.Copyif (a == 5) {
-
else
orcatch
from a closing curly brace (}) that precedes it on that line.Copy} else {
- Before any open curly brace (
{
), with next exceptions: In a template expansion, as it is forbidden by the languageCopy`abc${1 + 2}def`
- After and before assignment operator (
=
,+=
,-=
,*=
).Copyconst a = "b";
- After a comma (
,
) or semicolon (;
). Note that spaces are never allowed before these characters.Copyconst mArrCodeValues = [1, 4, 8, 19]; __sumValues(a, b); for(let i = 0; i <= 5; i++) { console.log(i); }
- After the colon (
:
) in an object literal.Copylet objPerson = { age: 30, height: 180 };
- After and before comparison operators (
==
,===
,!=
,!==
,>
,>=
,<
,<=
).Copyconst a = (a == b);
Copyif (a == b) {
- After and before ternary operators (
?
,:
).Copyconst a = (1 == 1) ? 1 : 0;
- After and before arithmetic operators (
+
,-
,*
,/
,%
)Copyconst a = 1 + 2;
- On both sides of the double slash (
//
) that begins an end-of-line comment. Here, multiple spaces are allowed, but not required. -
JSON object properties
should be aligned on the semicolon.
Examples
-
if
andelse
:Bad use
Copyif(mIntA==4 && isValidated){ console.log("4"); }else if(mIntA==5 && isValidated){ console.log("5"); }else{ console.log("Diferent to 4 and 5"); }
Good use
Copyif (mIntA == 4 && isValidated) { console.log("4"); } else if (mIntA == 5 && isValidated) { console.log("5"); } else { console.log("Diferent to 4 and 5, or not validated"); }
-
for
andwhile
:Bad use
Copyfor(let i=5;i<=10;i++) { console.log(i); }
Good use
Copyfor (let i = 5; i <= 10; i++) { console.log(i); }
-
try
andcatch
:Bad use
Copytry{ throw new Ax.lang.Exception("E001", "Invoice XXX not found"); }catch(e){ console.log(e.getErrorCode(), e.getMessage()); }
Good use
Copytry { throw new Ax.lang.Exception("E001", "Invoice XXX not found"); } catch (e) { console.log(e.getErrorCode(), e.getMessage()); }
-
switch
andcase
:Bad use
Copyswitch(mIntA){ case 4: console.log("a") break; case 5: console.log("a") break; default: console.log("Diferent to 4 and 5"); }
Good use
Copyswitch (mIntA) { case 4: console.log("a") break; case 5: console.log("a") break; default: console.log("Diferent to 4 and 5"); }
-
Ternay operators
:Bad use
Copyconst mStrPersonName = mRsPerson == null?null:mRsPerson.name;
Good use
Copyconst mStrPersonName = mRsPerson == null ? null : mRsPerson.name;
-
JSON object properties
:Bad use
Copyconst mObjTest = { a:122, testProperty:1221 }
Good use
Copyconst mObjTest = { a : 122, testProperty : 1221 }
-
- avoid: Separating unari operators (!, ++, --):
Bad use
Copyfor (let i = 0; i < 10; i ++) { console.log(i); }
Good use
Copyfor (let i = 0; i < 10; i++) { console.log(i); }
4.6 Comments
- Required: Code has to be undertansdable, so the code has to have comments.
- Required: All the functions have to be commented.
-
Required: Format of multiline comments is next:
Copy
/** * __testFunction is used for show code, * and for test cases. */ function __testFunction() { … }
-
Required: Single-line format:
Copy
// Constant testA has a test value const mStrTestA = "value";
-
Required: Every function should be commented and has to to describe params and return value.
Copy
/** * __testFunction is a test of concatenate two strings. * @param {string} paramA. This is first param to contatenate. * @param {string} paramB. This is second param to contatenate. * @return {string} Return the result of concatenate paramA and paramB */ __testFunction(paramA, paramB) { return paramA + " " + paramB; };
-
Avoid: Add the comment at the final of a statement.
Bad use
Copyconst mStrTestA = "value"; /** Constant testA has a test value */
5 Language features
5.1 Variable and constants declarations
Javascript provides three keywords to declare variables. (var
, const
, let
)
-
var
: It declares a global variable. -
const
: It declares a variable that can be assigned once and then cannot be reassigned. The scope of theconst
statement is the block where it is declared. -
let
: It declares a local variable in a block scope.
-
Required: Declare all local variables with either
const
orlet
. Thevar
keyword only will be used when is not possible to useconst
orlet
.Bad use
Copyfunction fstudioExample(param1) { if (param1) { var mStrTestVar = "a"; } return mStrTestVar; }
Good use
Copyfunction fstudioExample(param1) { let mStrTestVar = null; if (param1) { mStrTestVar = "a"; } return mStrTestVar; }
-
Recommended: Not defined variables at the start of the function if it only is using in any particular block.
Bad use
Copyfunction fstudioExample(param1) { let mIntValueA = null, mIntValueB = null; if (param1) { mIntValueA = Ax.db.call("fstudio_get_default"); if (mIntValueA > 0) mIntValueB = mIntValueA * 2 / param1; } else { mIntValueB = 0; } return mIntValueB; }
Good use
Copyfunction fstudioExample(param1) { let mIntValueB = null; if (param1) { const mIntValueA = Ax.db.call("fstudio_get_default"); if (mIntValueA > 0) { mIntValueB = mIntValueA * 2 / param1; } } else { mIntValueB = 0; } return mIntValueB; }
-
Recommended: Use const instead of let when the variable is not going to updated.
Bad use
Copyfunction fstudioExample(param1) { let mArrValues = [1, 2, 3], mIntValue = 4, mDateNow = new Ax.sql.Date(); mArrValues.push(mIntValue); if (param1) { mDateNow = new Ax.sql.Date(2019,5,1); } return { param1: mArrValues, param2: mDateNow }; }
Good use
Copyfunction fstudioExample(param1) { const mArrValues = [1, 2, 3], mIntValue = 4; let mDateNow = new Ax.sql.Date(); mArrValues.push(mIntValue ); if (param1) { mDateNow = new Ax.sql.Date(2019,5,1); } return { param1: mArrValues, param2: mDateNow }; }
-
Avoid: Use of hardcoded values. Its make code dificult to read. Use ENUMERATIONS instead it.
Bad use
Copyfunction fstudioExample(pStrStatus) { switch(pStrStatus) { case 'P': console.log("...") break; case 'L': console.log("...") break; case 'C': console.log("...") break; } }
Good use
Copyfunction fstudioExample(pStrStatus) { const mObjInvoiceStatus = { PROCESS: 'P', LOADED: 'L', CLOSED: 'C' }; switch(pStrStatus) { case mObjInvoiceStatus.PROCESS: console.log("...") break; case mObjInvoiceStatus.LOADED: console.log("...") break; case mObjInvoiceStatus.CLOSED: console.log("...") break; } }
5.2 Array literals
-
Avoid: Use variadic Array constructor. The constructor is error-prone if arguments are added or removed. Use a literal instead.
Bad use
Copy/** Above case show in console [1,2,3] */ let mArrValues = new Array(1, 2, 3); console.log(mArrValues); /** Above case show in console [] */ let mIntValue = new Array(1); console.log(mIntValue);
Good use
Copy/** Above case show in console [1,2,3] */ let mArrValues = [1, 2, 3]; console.log(mArrValues); /** Above case show in console [1] */ let mIntValue = [1]; console.log(mIntValue);
5.3 Object literals
-
Avoid: Use the variadic Object constructor.
Bad use
Copyconst mObjPerson = new Object(); mObjPerson.firstName = "John"; mObjPerson.lastName = "Doe"; mObjPerson.age = 50; mObjPerson.eyeColor = "blue";
Good use
Copyconst mObjPerson = { firstName: "John", lastName: "Doe", age: 50, eyeColor: "blue" };
-
Recommended: Object literals may represent either structs (with unquoted keys and/or symbols) or dicts (with quoted and/or computed keys). Use structs in major cases.
Bad use
Copyconst mObjPerson = { "firstName": "John", "lastName": "Doe", "age": 50, "eyeColor": "blue" };
Good use
Copyconst mObjPerson = { firstName: "John", lastName: "Doe", age: 50, eyeColor: "blue" };
-
Required: Not combine unquoted (struts) and quoted (dicst) properties
Bad use
Copyconst mObjPerson = { "firstName": "John", "lastName": "Doe", age: 50, eyeColor: "blue" };
5.4 String literals
-
Required: use double quotes for single lines.
Copy
const strValue = "Test single line";
-
Required: use string literals for multiple lines.
Bad use
Copyfunction __sumvalues(a, b) { return "Here is a table of arithmetic operations: \n" + a + " " + b + " = " + (a + b); } console.log(__sumvalues(1,5));
Good use
Copyfunction __sumvalues(a, b) { return `Here is a table of arithmetic operations: ${a} + ${b} = ${a + b}`; } console.log(__sumvalues(1,5));
5.5 Enumerations
-
Required: Enumerations has to have next style:
- Define enumerations before function definition.
- Properties may not be added to an enum after it is defined.
- Enumeration must be constant, and all properties values must be deeply immutable.
- Enumeration name has to be in camelcase.
- Properties name has to be in uppercase.
Bad use
Copyfunction ficonListInvoices(pStrStatus) { const mObjInvoiceStatus = { pending: 'P', processed: 'o' }; mObjInvoiceStatus.processed = 'O'; mObjInvoiceStatus.canceled = 'C'; switch(pStrStatus) { case mObjInvoiceStatus.PENDING: console.log("...") break; case mObjInvoiceStatus.PROCESSED: console.log("...") break; case mObjInvoiceStatus.CANCELED: console.log("...") break; } }
Good use
Copyfunction ficonListInvoices(pStrStatus) { const mObjInvoiceStatus = { PENDING: 'P', PROCESSED: 'O', CANCELED: 'C' }; switch(pStrStatus) { case mObjInvoiceStatus.PENDING: console.log("...") break; case mObjInvoiceStatus.PROCESSED: console.log("...") break; case mObjInvoiceStatus.CANCELED: console.log("...") break; } }
5.6 Comparisons
-
Recommended: User strict equality operator (===). Regular equality check == has a problem. It cannot differentiate 0 from false because operands of different types are converted to numbers by the equality operator ==. An empty string, just like false, becomes a zero.
Bad use
Copyconsole.log(0 == false); //true console.log('' == false); //true
Good use
Copyconsole.log(0 === false); //false, because the types are different console.log('' === false); //false, because the types are different
-
Recommended: Use regular equality check == to check if a parameter is null, because it can have undefined value.
Copy
function __sumValues(param1, param2) { if (param1 == null) { console.log("Param1 has to be informed. Value: " + param1); return 0; } else if (param2 == null) { console.log("Param2 has to be informed. Value: " + param2); return 0; } return param1+param2; } __sumValues(); //Print message Param1 has to be informed. Value undefined __sumValues(1); //Print message Param2 has to be informed. Value undefined __sumValues(null,1); //Print message Param1 has to be informed. Value null __sumValues(null,null); //Print message Param1 has to be informed. Value null __sumValues(4,null); //Print message Param2 has to be informed. Value null __sumValues(4,5); //Return 9 console.log(null == undefined); //Print true console.log(null === undefined); //Print false
-
Recommended: Use regular equality check == to check if a parameter is not null and not undefined.
Bad use
Copylet mIntInvoice = 0; if (mIntInvoice) { //mIntInvoice evaluated to false because 0 is false. } let mObjProperties = null; if (mObjProperties) { //objProperties evaluated to true, null is converted to 0. } let mObjProperties2 = undefined; if (mObjProperties2) { //objProperties2 evaluated to true, undefined is converted to 0. }
Good use
Copylet mIntInvoice = 0; if (mIntInvoice != null) { //mIntInvoice != null evaluated to true because 0 is false. } let mObjProperties = null; if (mObjProperties != null) { //objProperties != null evaluated to false. } let mObjProperties2 = undefined; if (mObjProperties2 != null) { //objProperties2 != null evaluated to false. }
5.7 Arrow function
An arrow function expression is a syntactically compact alternative to a regular function expression, although without its own bindings to the this, arguments, super, or new.target keywords. Arrow function expressions are ill suited as methods, and they cannot be used as constructors.
-
Recommended: Use for shorter functions
Copy
const mArrElements = [ 'Hydrogen', 'Helium', 'Lithium', 'Beryllium' ]; // The regular function above can be written as the arrow function below mArrElements.map((element) => { return element.length; }); // [8, 6, 7, 9] // When the only statement in an arrow function is `return`, we can remove `return` and remove // the surrounding curly brackets mArrElements.map(element => element.length); // [8, 6, 7, 9]
-
Recommended: Use it for the behavior of the keyword.
Copy
var adder = { base: 1, add: function(a) { var f = v => v + this.base; return f(a); }, addThruCall: function(a) { var f = v => v + this.base; var b = { base: 2 }; return f.call(b, a); } }; console.log(adder.add(1)); // This would log 2 console.log(adder.addThruCall(1)); // This would log 2 still
5.8 Resultsets
-
Recommended: Close resultset when finished.
Copy
const mRsSysTables = Ax.db.executeQuery(` <select> <columns>tabname</columns> <from table='systables'/> </select> `); for (const mRowSysTable of mRsSysTables) { console.log(mRowSysTable.tabname) } mRsSysTables.close();
-
Avoid: Use * on columns. Select only the columns you will use.
Bad use
Copyconst mRsSysTables = Ax.db.executeQuery(` <select> <columns>*</columns> <from table='systables'/> </select> `); for (const mRowSysTable of mRsSysTables) { console.log(mRowSysTable.tabname) } mRsSysTables.close();
Good use
Copyconst mRsSysTables = Ax.db.executeQuery(` <select> <columns>tabname</columns> <from table='systables'/> </select> `); for (const mRowSysTable of mRsSysTables) { console.log(mRowSysTable.tabname) } mRsSysTables.close();
-
Avoid: Use * on columns. Select only the columns you will use.
Bad use
Copyconst mRsSysTables = Ax.db.executeQuery(` <select> <columns>*</columns> <from table='systables'/> </select> `); for (const mRowSysTable of mRsSysTables) { console.log(mRowSysTable.tabname) } mRsSysTables.close();
God use
Copyconst mRsSysTables = Ax.db.executeQuery(` <select> <columns>tabname</columns> <from table='systables'/> </select> `); for (const mRowSysTable of mRsSysTables) { console.log(mRowSysTable.tabname) } mRsSysTables.close();
5.9 Exceptions
-
Required: Use of Ax.lang.Exception instead of new Error or default javascript error to throw message error.
Bad use
Copytry { throw "Test error"; } catch (error) { console.log(error.getErrorMessage()); //On this case, error isn't an object, so it sentence throw a javascript error because getErrorMessage is not a function. }
Bad use
Copytry { throw new Error("Test error"); } catch (error) { console.log(error.getErrorMessage()); //On this case, error is an object but haven't defined method getErrorMessage, so it sentence throw a javascript error. }
Good use
Copytry { throw new Ax.lang.Exception("Test error"); } catch (error) { console.log(error.getErrorMessage()); }