Skip to content

JavaScript

TODO(David)

Write this page. Stub created for structure only.

TODO

LWC JavaScript conventions

Standards for the JavaScript of Lightning Web Components and Aura components: the choice between the two, security, the API version, readability, and linting.

The standards of a Lightning component as a component, the choice of a Lightning Web Component over Aura and the standards that keep a component working under Lightning Web Security, are on Lightning Web Components and Aura. This page holds the standards of the language, wherever it runs.

Some standards on this page have an ESLint rule and a PMD rule; each says whether an organisation can switch off the PMD or the ESLint rule if duplicate violation reports are a problem.

Security

Standards that keep what a component knows from reaching anyone who should not have it, under the principle of least privilege (PLP).

Console and Debugger Statements

Console output is a security control, not a style preference, and it is more exposed than Apex debug logs: anyone who opens the browser's developer tools can read it, with no special permission in the org. The platform does not strip console statements from production, so lint-time enforcement is the only guard.

  • No console statements (console.log, console.warn, console.error, and the rest), in a component or in a Jest test. A console statement is treated like a debug statement in Apex, and blocks the pull request (severity 2); enforced by the ESLint rule no-console and the PMD JavaScript rule AvoidConsoleStatements. no-console also checks the first statement of a class method, so an organisation can switch off AvoidConsoleStatements if the duplicate violations are a problem.
  • No debugger; statements; enforced by the ESLint rule no-debugger. A leftover debugger; pauses execution for anyone with developer tools open.
  • Client-side diagnostics go through the org's logging framework, which logs from Lightning Web Components and Aura as well as Apex and Flow; see Observability.
  • Debug Mode stays off for production users: it serves unminified framework and component code, which slows every page and makes the client side easier to read and inspect. No rule checks this, because Debug Mode is a setting on each user in the org and not in the repository; an administrator checks the Debug Mode Users list in Setup.

Cookies

  • A cookie that JavaScript sets has the Secure attribute, as in document.cookie = 'theme=dark; Secure'. Without it, the browser can send the cookie over an unencrypted connection. A cookie with no Secure attribute blocks the pull request (severity 2); enforced by no-restricted-syntax, with a selector of the sample ESLint file, and RequireSecureCookie. The selector also finds a cookie set in the first statement of a method, so an organisation can switch off RequireSecureCookie if the duplicate violations are a problem.

Third-Party Libraries

A library that the org serves to its users is part of the org's attack surface, whether it is bundled in a component or loaded from a static resource (Supply Chain Security). A library bundled into a Lightning web component or a static resource also carries the vulnerability history of the version that was copied in, and it is easily forgotten: Renovate and Dependabot update the dependencies that a manifest such as package.json declares, and a copied library is declared nowhere (Version Control: Renovate and Dependabot). A scan on every pull request keeps it in view.

Strings Run as Code

Code written inside a string is not checked by the linter or the formatter, and it is where input from outside becomes running code.

  • setTimeout and setInterval take a function, never a string of code. A string blocks the pull request (severity 2); enforced by the ESLint rule no-implied-eval.
  • No javascript: URL is written in JavaScript. One blocks the pull request (severity 2); enforced by the ESLint rule no-script-url.

Salesforce's own ESLint configurations, for Aura components and for Lightning Web Components, make both rules an error, and these standards do not rank a rule that they name below the level that Salesforce gives it (Version Control: ESLint).

Sources:

API Version

A Lightning Web Component has an API version of its own, in its .js-meta.xml file, and the framework treats the component as it did in the release of that version (Component Versioning). Two examples, from the framework's own list:

  • From API 59.0, every HTML parsing error in a template stops the component compiling. Before that, some were only warnings.
  • From API 62.0, a template can bind an object or an array to class. An earlier version does not support the binding.

A component at an old API version blocks the pull request (severity 2). Enforced by BumpApiVersion and AvoidOldSalesforceApiVersions. The standard is in Metadata Standards: API Version.

Readability

Code Style

Code style standards change nothing about what the code does, and they make it easier to read. Prettier settles many of them in a file that it formats. A rule is the check for the rest, and for a file that Prettier did not format.

  • No redundant parentheses: an expression is not wrapped in a second pair, as in ((total)). Prettier removes them. One that remains is reported and does not block the pull request (severity 4); enforced by the PMD JavaScript rule UnnecessaryParentheses.
  • No block that does nothing: a pair of braces that belongs to no statement and declares nothing of its own is removed. A var inside such braces still belongs to the whole function, so the braces suggest a scope that they do not make. Braces that hold a let, const, or class declaration do make a scope, and stay: a case of a switch may have braces to hold a const of its own. Prettier does not remove a block. A block that does nothing is reported and does not block the pull request (severity 3); enforced by the ESLint rule no-lone-blocks.
  • No else after an if block that ends in return: the code after the if is the else. The extra level of nesting hides the main path of the function. An else after a return blocks the pull request (severity 2); enforced by the ESLint rule no-else-return and the PMD JavaScript rule NoElseReturn. Keep both rules: NoElseReturn also reports an else if after a return, which no-else-return allows.

Formatting

The opening curly bracket sits on the same line as the declaration or statement that it opens, which is how Prettier formats JavaScript. In JavaScript this is more than style: a return followed by a line break ends the statement, so an object whose bracket starts on the next line is never returned.

Comments

The General: Comments standards apply to JavaScript. These are particular to it.

  • The Salesforce Documenter (SFDoc) extension writes its default author, ChangeMeIn@UserSettingsUnder.SFDoc, into the JavaScript file of a Lightning Web Component or an Aura component when its setting for Lightning JavaScript is on. That string in a JavaScript file blocks the pull request (severity 2). Enforced by NoSfdocDefaultAuthor.
  • An eslint-disable comment, or an inline configuration comment that turns a rule off, blocks the pull request (severity 2) until the violation is fixed or the owning team approves the suppression. Enforced by NoUnapprovedEslintSuppression and @lwc/lwc-platform/no-inline-disable.
  • TODO, TO-DO, FIXME, FIX-ME, or HACK as the first word of a comment line, or with a colon after it, is reported in every JavaScript file, static resources included, so a third-party library that still holds such a comment is reported too, which shows what the library leaves unfinished. One that remains is reported at severity 5. Enforced by NoUnresolvedTodosJavaScript.

Complexity

A function is simple enough to read in one pass. These rules count what makes a function hard to follow, and a count is a signal for a reviewer, not proof of a problem (Maintainability), so none of them blocks a pull request. Each limit is set in the sample ESLint configuration, where an organisation may change it.

  • Blocks nest no more than 3 deep in a function. An if, for, while, do, switch, or try inside three others is reported at severity 3, the same depth and severity as nested if statements in Apex (Complexity and Unused Code). Enforced by max-depth.
  • A function has a cyclomatic complexity of 10 or less, the limit that Apex uses. A function with more paths through it is reported at severity 4. Enforced by complexity.
  • A function has no more than 50 lines of code. Blank lines and comments do not count, so the rule never discourages a comment. A longer function is reported at severity 4. Enforced by max-lines-per-function.

Naming

The naming standards for JavaScript are on the General: Naming page, with the naming standards of the other languages.

Required Formatting

Duplicated Code

  • No block of code is copied from one component to another. A duplicated block is a function in a shared module that both import, so that a fix is made once. A block of JavaScript or TypeScript that appears more than once across the repository is reported at severity 5, for the developer's information (Refactoring Duplicates). Enforced by DetectCopyPasteForJavascript and DetectCopyPasteForTypescript.

Error Prevention

Braces

The body of every if, else, for, and while is wrapped in braces, even when it is one line. A missing pair of braces blocks the pull request (severity 2); enforced by the ESLint rule curly and the PMD JavaScript rules IfStmtsMustUseBraces, IfElseStmtsMustUseBraces, ForLoopsMustUseBraces, and WhileLoopsMustUseBraces. curly also checks do loops, so an organisation can switch off the {N} PMD brace rules if the duplicate violations are a problem.

The reason is the one given for Apex (Braces): JavaScript reads braces, not indentation, so a line added later under an unbraced if runs every time, however it is indented. That is the mistake behind Apple's "goto fail" bug (CVE-2014-1266). Google's JavaScript style requires braces on every control structure for the same reason, and ESLint's curly rule exists to enforce it. The standard is about control statements: an arrow function with an expression body, such as item => item.id, has no block to brace.

Assignments in Conditions

No condition holds an assignment. The condition of an if, while, do, or for statement has no =, ++, or -- in it, and neither has any part of a ternary expression (a ? b : c). An = where a comparison was meant, as in if (total = 0), is a common bug: the value is assigned, and the condition then tests the value assigned. Where an assignment is meant, it is a statement of its own. The update part of a for loop, as in i++, is not a condition, and is allowed. To read every match of a global regular expression, use for (const match of text.matchAll(pattern)), not a while loop that assigns in its condition. An assignment in a condition blocks the pull request (severity 2); enforced by the ESLint rule no-cond-assign and the PMD JavaScript rule AssignmentInOperand.

Unreachable Code

No statement follows a return, throw, break, or continue in the same block. Such a statement never runs. It is dead code, which is removed, or a sign that the jump is in the wrong place. A statement that can never run blocks the pull request (severity 2); enforced by the ESLint rule no-unreachable and the PMD JavaScript rule UnreachableCode.

With Statements

No with statement. Inside one, a name can be a property of the object or a variable outside it, and the reader cannot tell which. A with statement blocks the pull request (severity 2); enforced by the PMD JavaScript rule AvoidWithStatement (severity 2) and the ESLint rule no-with (severity 3). Keep both rules. In a Lightning web component, a with statement stops ESLint with a parse error, and AvoidWithStatement misses a with statement that is the first statement of a method.

Equality

Values are compared with === and !==, not == and !=. The loose operators convert the types first, so '0' == false is true. The one exception is value == null, which tests for null and undefined together. A loose comparison blocks the pull request (severity 2); enforced by the ESLint rule eqeqeq and the PMD JavaScript rule EqualComparison. eqeqeq reports every comparison that EqualComparison reports, and more, so an organisation can switch off EqualComparison if the duplicate violations are a problem.

Return Values

A function returns a value on every path, or on none. A function that returns a value on one path and nothing on another gives its caller undefined with no warning. A mixed return blocks the pull request (severity 2); enforced by the ESLint rule consistent-return and the PMD JavaScript rule ConsistentReturn. consistent-return also checks the methods of a class, so an organisation can switch off ConsistentReturn if the duplicate violations are a problem.

Number Parsing

parseInt is always given a radix, as in parseInt(value, 10). Without one, a string that starts with 0x is read as hexadecimal. A call with no radix blocks the pull request (severity 2); enforced by the PMD JavaScript rule UseBaseWithParseInt and the ESLint rule radix. radix also checks Number.parseInt, so an organisation can switch off UseBaseWithParseInt if the duplicate violations are a problem.

Symbol Descriptions

A Symbol is created with a description, as in Symbol('rowId'), and not as Symbol(). A symbol that is logged shows its description, which makes it easier to debug (symbol-description); a symbol with none cannot be told from another in a log or an error message. A Symbol() with no description is reported at severity 3 and does not block the pull request; enforced by the ESLint rule symbol-description.

Formatting/Linting

The JavaScript of Aura components and Lightning Web Components is checked by ESLint, from the one ESLint configuration file of the repository. The file, the packages that it loads, and how it runs are in Version Control: ESLint.

SonarJS

These standards recommend adding eslint-plugin-sonarjs, SonarSource's JavaScript rules for ESLint, to each organisation's project. Its rules handle five standards for component JavaScript:

  • No hard-coded passwords or other credentials (sonarjs/no-hardcoded-passwords).
  • No weak hashing algorithms, such as MD5 and SHA-1 (sonarjs/hashing).
  • No clear-text protocols, such as http and ftp, in URLs (sonarjs/no-clear-text-protocols).
  • No hard-coded IP addresses (sonarjs/no-hardcoded-ip).
  • No conditional whose branches are all the same (sonarjs/no-all-duplicated-branches).

Testing

TODO

Consider moving this section to the Testing page (testing.md, Content item 144).

TODO

Jest unit tests for LWC, mocking patterns, coverage expectations

  • The Jest tests run on a pull request only when its delta package holds a Lightning web component, and a failing test blocks the pull request. Enforced by the LWC Jest Tests workflow.
  • A Lightning web component that has a test has at least 80% line coverage, counted over all its JavaScript files, and a tested component below 80% blocks the pull request. The threshold is in jest.config.js from the first day of a project, because a coverage requirement added later to a component library with little coverage is much harder to meet (Version Control: Jest). Enforced by jest.config.js and the LWC Jest Tests workflow.
  • A component with no test file is named in the report of the run, and it does not fail the gate. Enforced by the LWC Jest Tests workflow.
  • The failing tests, each with its message, are in a table on the pull request and in the job summary, not in a log. Enforced by the LWC Jest Tests workflow, which reads the JSON output of Jest.

Rules

The rules that this page mentions. The Standard column gives each rule's standard in one line, and the Section column links to the section that mentions the rule; "Not yet written" marks a rule of this page that no section mentions yet. Appendix F.6 holds the full cross-reference.

Rule Kind Severity Standard Section
LibraryWithKnownCriticalSeverityVulnerability Stock Code Analyzer RetireJS 1 No JavaScript library with a known vulnerability of critical severity Third-Party Libraries
@lwc/lwc-platform/no-inline-disable Stock Code Analyzer ESLint 2 No comment that switches off an ESLint rule for a line Comments
AssignmentInOperand Stock PMD 2 No assignment in a condition: no =, ++, or -- in an if, while, do, for, or ternary test Assignments in Conditions
AvoidConsoleStatements Stock PMD 2 No console statements, in a component or in a Jest test Console and Debugger Statements
AvoidOldSalesforceApiVersions Stock Code Analyzer Regex 2 Every metadata file states a recent API version API Version
AvoidWithStatement Stock PMD 2 No with statement With Statements
BumpApiVersion Custom PMD XPath 2 Every metadata file is at or above the API version floor Notes on this rule. API Version
consistent-return Stock Code Analyzer ESLint 2 A function returns a value on every path, or on none Return Values
ConsistentReturn Stock PMD 2 A function returns a value on every path, or on none Return Values
curly Stock Code Analyzer ESLint 2 Wrap the body of every if, else, for, and while in braces, even one line Braces
eqeqeq Stock Code Analyzer ESLint 2 Compare values with === and !==, not == and !=; value == null is the one exception Equality
EqualComparison Stock PMD 2 Compare values with === and !==, not == and !=; value == null is the one exception Equality
ForLoopsMustUseBraces Stock PMD 2 Wrap the body of every for loop in braces, even one line Braces
IfElseStmtsMustUseBraces Stock PMD 2 Wrap the body of every else in braces, even one line Braces
IfStmtsMustUseBraces Stock PMD 2 Wrap the body of every if in braces, even one line Braces
LibraryWithKnownHighSeverityVulnerability Stock Code Analyzer RetireJS 2 No JavaScript library with a known vulnerability of high severity Third-Party Libraries
no-cond-assign Stock Code Analyzer ESLint 2 No assignment in a condition Assignments in Conditions
no-console Stock Code Analyzer ESLint 2 No console statements Console and Debugger Statements
no-debugger Stock Code Analyzer ESLint 2 No debugger statements Console and Debugger Statements
no-else-return Stock Code Analyzer ESLint 2 No else after an if block that ends in return Code Style
no-implied-eval Stock Code Analyzer ESLint 2 setTimeout and setInterval take a function, never a string of code Strings Run as Code
no-restricted-syntax Stock Code Analyzer ESLint 2 No variable, parameter, function, class, or import named top or location Cookies
no-script-url Stock Code Analyzer ESLint 2 No javascript: URL is written in JavaScript Strings Run as Code
no-unreachable Stock Code Analyzer ESLint 2 No statement follows a return, throw, break, or continue in the same block Unreachable Code
NoElseReturn Stock PMD 2 No else after an if block that ends in return Code Style
NoSfdocDefaultAuthor Custom Code Analyzer Regex 2 The author is a person or a team, never a tool default such as ChangeMeIn@UserSettingsUnder.SFDoc Comments
NoUnapprovedEslintSuppression Custom Code Analyzer Regex 2 No ESLint suppression without an approving review from the owning team Comments
radix Stock Code Analyzer ESLint 2 parseInt is always given a radix, as in parseInt(value, 10) Number Parsing
RequireSecureCookie Custom PMD XPath 2 A cookie that JavaScript sets has the Secure attribute Cookies
UnreachableCode Stock PMD 2 No statement follows a return, throw, break, or continue in the same block Unreachable Code
UseBaseWithParseInt Stock PMD 2 parseInt is always given a radix, as in parseInt(value, 10) Number Parsing
WhileLoopsMustUseBraces Stock PMD 2 Wrap the body of every while loop in braces, even one line Braces
LibraryWithKnownMediumSeverityVulnerability Stock Code Analyzer RetireJS 3 No JavaScript library with a known vulnerability of medium severity Third-Party Libraries
max-depth Stock Code Analyzer ESLint 3 Blocks nest no more than 3 deep in a function Complexity
no-lone-blocks Stock Code Analyzer ESLint 3 No block that belongs to no statement and declares nothing Code Style
no-with Stock Code Analyzer ESLint 3 No with statement With Statements
symbol-description Stock Code Analyzer ESLint 3 A Symbol is created with a description, as in Symbol('rowId') Symbol Descriptions
complexity Stock Code Analyzer ESLint 4 A function has a cyclomatic complexity of 10 or less Complexity
LibraryWithKnownLowSeverityVulnerability Stock Code Analyzer RetireJS 4 No JavaScript library with a known vulnerability of low severity Third-Party Libraries
max-lines-per-function Stock Code Analyzer ESLint 4 A function has no more than 50 lines of code, not counting blank lines and comments Complexity
UnnecessaryParentheses Stock PMD 4 No redundant parentheses around an expression Code Style
DetectCopyPasteForJavascript Stock Code Analyzer CPD 5 No copied blocks of JavaScript; share a function in a module Duplicated Code
DetectCopyPasteForTypescript Stock Code Analyzer CPD 5 No copied blocks of TypeScript; share a function in a module Duplicated Code
NoUnresolvedTodosJavaScript Custom Code Analyzer Regex 5 No TODO, TO-DO, FIXME, FIX-ME, or HACK comment stays in JavaScript Comments