This 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:

    Copy
    function 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):

    Copy
    function addClient(pStrCif) {
        console.log("addClient")
    }
        
    function __concatAddress(pStrAddress, pStrCipcode, pStrCity) {
        console.log("__concatAddress")
    }
        
    addClient("A99999999");
    __concatAddress("carrer londres", "08001", "Barcelona");
    Copy
    function 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

    Copy
    function 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

    Copy
    function 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:

    Copy
    function 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");
  • 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.

Copy
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:

Copy
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

Copy
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'.

Copy
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_'-

Copy
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:

Copy
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.

Copy
const mIntMinFact = 1;
const mIntMaxFact = 5;
const mIntTotalFacts = 3;

3.4.4 Date

Recommended: On date objects use prefix or sufix date.

Copy
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.

Copy
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.

Copy
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.

Copy
let mRsSysTables = Ax.db.executeQuery(`
    <select>
        <columns>*</columns>
        <from table='systables'/>
    </select>
`);

3.4.8 ResultsetRowMap

Recommended: For ResultsetRowMap use prefix row.

Copy
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.

Copy
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

      Copy
      Ax.db.call("studioFunctionTest", parameter1, parameter2, parameter3, parameter4, parameter5, parameter6, parameter7, parameter8);

      Good use

      Copy
      Ax.db.call("studioFunctionTest", parameter1, parameter2, parameter3, 
              parameter4, parameter5, parameter6, parameter7, parameter8);
    • Break after multiple variable definition.

      Bad use

      Copy
      const mStrConstA = 'A', mStrConstB = 'B', mStrConstC = 'C';

      Good use

      Copy
      const mStrConstA = 'A', 
            mStrConstB = 'B', 
            mStrConstC = 'C';
    • Break before an operator.

      Bad use

      Copy
      let mBcOperation = mBcLongNum2 * (mBcLongNum3 + mBcLongNum4 - mBcLongNum5) + 4 * mBcLongNum6;

      Bad use

      Copy
      let mBcOperation = mBcLongNum2 * (mBcLongNum3 + mBcLongNum4 
                                      - mBcLongNum5) + 4 * mBcLongNum6;

      Good use

      Copy
      let 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

      Copy
      Ax.db.call("studioFunctionTest", parameter1, Ax.db.call("studioFunctionTest", 
              parameter3), parameter4, parameter5, parameter6, parameter7, parameter8);

      Good use

      Copy
      Ax.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

      Copy
      if ((condition1 && condition2)
      || (condition3 && condition4)
      ||!(condition5 && condition6)) { 
          console.log("...")
      }

      Good use

      Copy
      if ((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

    Copy
    const mArrValuesCodes = [
        3,
        4,
        5
    ]

    Good use

    Copy
    const mArrValuesCodes = [3, 4, 5];
    const mArrValuesCodes2 = [
        {
            a: "1",
            b: "2"
        },
        {
            a: "1",
            b: "2"
        }
    ]
  • Required: Use block indentation on javascript objects.

    Bad use

    Copy
    const mObjProperties = { a: "1", b:"2"};

    Good use

    Copy
    const 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

    Copy
    mRsRecord.forEach((mRowTest) => { console.log("...")  });

    Good use

    Copy
    mRsRecord.forEach((mRowTest) => { 
        console.log("...")  
    });
  • Recommended: Not use braces if function only execute one statement.

    Bad use

    Copy
    mRsRecord.forEach((mRowTest) => console.log("..."));

    Good use

    Copy
    mRsRecord.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

    Copy
    switch(param1) {
        case 'A':
        console.log('A');
        break;
        case 'B':
        console.log('B');
        break;
    }

    Good use

    Copy
    switch(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

    Copy
    const mStrA = "1"; console.log(mStrA);
    const mStrB = "2", mStrC = "3";

    Good use

    Copy
    const mStrA = "1"; 
    console.log(mStrA);
    
    const mStrB = "2", 
          mStrC = "3";
  • Required: Every statement must be terminated with a semicolon.

    Bad use

    Copy
    const mStrA = "1"
    console.log(mStrA)

    Good use

    Copy
    const 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

    Copy
    function fStudioExample(pStrStatus) {
        if (pStrStatus == "P")
        {
            console.log("...")
        }
        else 
        {
        
        }
        
    }

    Good use

    Copy
    function fStudioExample(pStrStatus) {
        if (pStrStatus == "P") {
            console.log("...")
        } else {
        
        }
    }
  • Avoid: not use brackets, even if the body contains only a single statement.

    Bad use

    Copy
    function fStudioExample(pStrStatus) {
        if (pStrStatus == "P")
            console.log("P");
    
        if (pStrStatus == "L") console.log("L");
    }

    Good use

    Copy
    function fStudioExample(pStrStatus) {
        if (pStrStatus == "P") {
            console.log("P");
        } 
        
        if (pStrStatus == "L") {
            
        }
    }

4.4 Blank lines

  • Required: Use blank lines between consecutive functions.

    Bad use

    Copy
    function ficoServerFunction() {
        function __functionA() {
            console.log("...")
        }
        function __functionB() {
            console.log("...")
        }
    }

    Good use

    Copy
    function 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

    Copy
    function 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

    Copy
    function 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

    Copy
    function ficoServerFunction() {                        
        function __functionA() {
            
            const mStrConstA = "A";
            
            console.log(mStrConstA);
        
        }
    }

    Good use

    Copy
    function ficoServerFunction() {
        function __functionA() {
            const mStrConstA = "A";
            
            console.log(mStrConstA);
        }
    }

4.5 White space

  • Required: Separating any reserved word:
    • if, for, while, switch, case or catch from an open parenthesis (() that follows it on that line.
      Copy
      if (a == 5) {
    • else or catch 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 language
      Copy
      `abc${1 + 2}def`
    • After and before assignment operator ( =, +=, -=, *=).
      Copy
      const a = "b";
    • After a comma ( ,) or semicolon ( ;). Note that spaces are never allowed before these characters.
      Copy
      const 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.
      Copy
      let objPerson = {
          age: 30,
          height: 180
      };
    • After and before comparison operators ( ==, ===, !=, !==, >, >=, <, <=).
      Copy
      const a = (a == b);
      Copy
      if (a == b) {
    • After and before ternary operators ( ?, :).
      Copy
      const a = (1 == 1) ? 1 : 0;
    • After and before arithmetic operators ( +, -, *, /, %)
      Copy
      const 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 and else:

      Bad use

      Copy
      if(mIntA==4 && isValidated){
          console.log("4");
      }else if(mIntA==5 && isValidated){
          console.log("5");
      }else{
          console.log("Diferent to 4 and 5");
      }

      Good use

      Copy
      if (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 and while:

      Bad use

      Copy
      for(let i=5;i<=10;i++) {
       console.log(i);
      }

      Good use

      Copy
      for (let i = 5; i <= 10; i++) {
          console.log(i);
      }
    • try and catch:

      Bad use

      Copy
      try{
       throw new Ax.lang.Exception("E001", "Invoice XXX not found");
      }catch(e){
       console.log(e.getErrorCode(), e.getMessage());
      }

      Good use

      Copy
      try {
          throw new Ax.lang.Exception("E001", "Invoice XXX not found");
      } catch (e) {
          console.log(e.getErrorCode(), e.getMessage());
      }
    • switch and case:

      Bad use

      Copy
      switch(mIntA){
          case 4:
              console.log("a")
              break;
          case 5:
              console.log("a")
              break;
          default:
              console.log("Diferent to 4 and 5");
      }

      Good use

      Copy
      switch (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

      Copy
      const mStrPersonName = mRsPerson == null?null:mRsPerson.name;

      Good use

      Copy
      const mStrPersonName = mRsPerson == null ? null : mRsPerson.name;
    • JSON object properties:

      Bad use

      Copy
      const mObjTest = {
        a:122,
        testProperty:1221
      }

      Good use

      Copy
      const mObjTest = {
           a            : 122,
           testProperty : 1221
      }
  • avoid: Separating unari operators (!, ++, --):

    Bad use

    Copy
    for (let i = 0; i < 10; i ++) {
        console.log(i);
    }

    Good use

    Copy
    for (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

    Copy
    const 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 the const 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 or let. The var keyword only will be used when is not possible to use const or let.

    Bad use

    Copy
    function fstudioExample(param1) {
        if (param1) {
            var mStrTestVar = "a";
        }
        
        return mStrTestVar;
    }

    Good use

    Copy
    function 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

    Copy
    function 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

    Copy
    function 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

    Copy
    function 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

    Copy
    function 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

    Copy
    function fstudioExample(pStrStatus) {
        switch(pStrStatus) {
            case 'P':
                console.log("...")
                break;
                
            case 'L':
                console.log("...")
                break;
                
            case 'C':
                console.log("...")
                break;
        }
    }

    Good use

    Copy
    function 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

    Copy
    const mObjPerson = new Object();
        mObjPerson.firstName = "John";
        mObjPerson.lastName = "Doe";
        mObjPerson.age = 50;
        mObjPerson.eyeColor = "blue";

    Good use

    Copy
    const 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

    Copy
    const mObjPerson = {
            "firstName": "John",
            "lastName": "Doe",
            "age": 50,
            "eyeColor": "blue"
        };

    Good use

    Copy
    const mObjPerson = {
            firstName: "John",
            lastName: "Doe",
            age: 50,
            eyeColor: "blue"
        };
  • Required: Not combine unquoted (struts) and quoted (dicst) properties

    Bad use

    Copy
    const 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

    Copy
    function __sumvalues(a, b) {
          return "Here is a table of arithmetic operations: \n" + 
                    a + "  " + b + " = " + (a + b);
        }
        
        console.log(__sumvalues(1,5));

    Good use

    Copy
    function __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

    Copy
    function 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

    Copy
    function 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

    Copy
    console.log(0 == false);  //true
        console.log('' == false); //true

    Good use

    Copy
    console.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

    Copy
    let 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

    Copy
    let 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

    Copy
    const mRsSysTables = Ax.db.executeQuery(`
            <select>
                <columns>*</columns>
                <from table='systables'/>
            </select>
        `);
        
        for (const mRowSysTable of mRsSysTables) {
            console.log(mRowSysTable.tabname)
        }
        
        mRsSysTables.close();

    Good use

    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

    Copy
    const mRsSysTables = Ax.db.executeQuery(`
            <select>
                <columns>*</columns>
                <from table='systables'/>
            </select>
        `);
        
        for (const mRowSysTable of mRsSysTables) {
            console.log(mRowSysTable.tabname)
        }
        
        mRsSysTables.close();

    God use

    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();

5.9 Exceptions

  • Required: Use of Ax.lang.Exception instead of new Error or default javascript error to throw message error.

    Bad use

    Copy
    try {
            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

    Copy
    try {
            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

    Copy
    try {
            throw new Ax.lang.Exception("Test error");
        } catch (error) {
            console.log(error.getErrorMessage());  
        }