> ## Documentation Index
> Fetch the complete documentation index at: https://docs.moxycode.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Code Analysis Rules

> The complete list of rules MoxyCode checks for in Apex and LWC files.

MoxyCode analyses your Apex and LWC code against a set of built-in rules covering governor limits, security, LWC best practices, and code quality. New rules are added regularly — this page reflects the current rule set.

## Severity levels

|                 |                                                                      |
| --------------- | -------------------------------------------------------------------- |
| 🔴 **Critical** | Governor limit violations and security issues — fix before deploying |
| 🟡 **Warning**  | Best practice violations — should be addressed                       |
| 🔵 **Info**     | Code quality suggestions — low urgency, no production risk           |

***

## Apex rules

### Critical

<AccordionGroup>
  <Accordion title="SOQL query inside a loop">
    **Rule ID:** `soql-in-loop`

    A SOQL query is being executed inside a `for` loop. Each iteration of the loop counts as a separate query against Salesforce's governor limit of 100 SOQL queries per transaction.

    **Why it matters:** In production, this will throw a `System.LimitException: Too many SOQL queries: 101` error when the loop runs more than 100 times.

    **Fix:** Move the SOQL query outside the loop. Collect the IDs you need first, then query with a `WHERE Id IN :idSet` pattern.

    ```apex theme={null}
        // ❌ Before
        for (Account acc : accounts) {
            List<Contact> contacts = [SELECT Id FROM Contact WHERE AccountId = :acc.Id];
        }

        // ✅ After
        Set<Id> accountIds = new Map<Id, Account>(accounts).keySet();
        List<Contact> contacts = [SELECT Id, AccountId FROM Contact WHERE AccountId IN :accountIds];
    ```
  </Accordion>

  <Accordion title="DML statement inside a loop">
    **Rule ID:** `dml-in-loop`

    A DML statement (`insert`, `update`, `delete`, `upsert`, or `undelete`) is being executed inside a `for` loop. Each iteration counts against Salesforce's governor limit of 150 DML statements per transaction.

    **Why it matters:** In production, this will throw a `System.LimitException: Too many DML statements: 151` error when the loop runs more than 150 times.

    **Fix:** Collect records in a list inside the loop, then perform a single bulk DML operation after the loop.

    ```apex theme={null}
        // ❌ Before
        for (Account acc : accounts) {
            acc.Name = 'Updated';
            update acc;
        }

        // ✅ After
        for (Account acc : accounts) {
            acc.Name = 'Updated';
        }
        update accounts;
    ```
  </Accordion>

  <Accordion title="@future call inside a loop">
    **Rule ID:** `future-in-loop`

    A `@future` method is being called inside a `for` loop. Each call counts against Salesforce's governor limit of 50 future calls per transaction.

    **Why it matters:** In production, this will throw a `System.LimitException: Too many future calls: 51` error when the loop runs more than 50 times.

    **Fix:** Refactor the `@future` method to accept a collection of IDs and call it once outside the loop.

    ```apex theme={null}
        // ❌ Before
        for (Account acc : accounts) {
            processAsync(acc.Id);
        }

        // ✅ After
        Set<Id> accountIds = new Map<Id, Account>(accounts).keySet();
        processAsync(accountIds);
    ```
  </Accordion>

  <Accordion title="Hardcoded Salesforce record ID">
    **Rule ID:** `hardcoded-id`

    A Salesforce record ID is hardcoded directly in the code. Record IDs are org-specific and will be different in every sandbox, scratch org, and production environment.

    **Why it matters:** Code with hardcoded IDs will fail silently or throw errors when deployed to a different org. This is a common source of bugs when promoting code from sandbox to production.

    **Fix:** Use a Custom Label, Custom Setting, or Custom Metadata Type to store org-specific IDs and reference them in your code instead.
  </Accordion>
</AccordionGroup>

### Warning

<AccordionGroup>
  <Accordion title="Missing sharing keyword">
    **Rule ID:** `missing-sharing-keyword`

    An Apex class is declared without an explicit `with sharing`, `without sharing`, or `inherited sharing` keyword.

    **Why it matters:** Without an explicit sharing declaration, the class inherits the sharing context of its caller — which may be `without sharing`. This can expose records the running user should not have access to.

    **Fix:** Add an explicit sharing keyword to every Apex class.

    ```apex theme={null}
        // ❌ Before
        public class AccountService {

        // ✅ After
        public with sharing class AccountService {
    ```
  </Accordion>

  <Accordion title="SOQL mode unspecified">
    **Rule ID:** `soql-mode-unspecified`

    A SOQL query does not explicitly specify `USER_MODE` or `SYSTEM_MODE`.

    **Why it matters:** Without an explicit mode, SOQL runs in system mode by default — ignoring the running user's field-level security and object permissions. This can expose data the user should not have access to.

    **Fix:** Add `WITH USER_MODE` to enforce the running user's permissions, or `WITH SYSTEM_MODE` to make the intent explicit.

    ```apex theme={null}
        // ❌ Before
        List<Account> accounts = [SELECT Id, Name FROM Account];

        // ✅ After
        List<Account> accounts = [SELECT Id, Name FROM Account WITH USER_MODE];
    ```
  </Accordion>

  <Accordion title="Unsafe single-record SOQL">
    **Rule ID:** `unsafe-single-soql`

    A SOQL query expected to return a single record is assigned directly to a variable without null protection or a try-catch block.

    **Why it matters:** If the query returns no records, Salesforce throws a `System.QueryException: List has no rows for assignment to SObject` error — which will crash the transaction.

    **Fix:** Wrap the query in a try-catch block or query into a list and check for results first.

    ```apex theme={null}
        // ❌ Before
        Account acc = [SELECT Id FROM Account WHERE Name = 'Acme' LIMIT 1];

        // ✅ After
        List<Account> accounts = [SELECT Id FROM Account WHERE Name = 'Acme' LIMIT 1];
        Account acc = accounts.isEmpty() ? null : accounts[0];
    ```
  </Accordion>

  <Accordion title="Direct trigger logic">
    **Rule ID:** `direct-trigger-logic`

    Business logic is written directly in the trigger body instead of delegating to a handler class.

    **Why it matters:** Triggers with inline logic are difficult to test, maintain, and extend. The Salesforce best practice is to keep trigger bodies thin and delegate all logic to a dedicated handler class.

    **Fix:** Create a trigger handler class and call it from the trigger body.

    ```apex theme={null}
        // ❌ Before
        trigger AccountTrigger on Account (before insert) {
            for (Account acc : Trigger.new) {
                acc.Name = acc.Name.toUpperCase();
            }
        }

        // ✅ After
        trigger AccountTrigger on Account (before insert) {
            AccountTriggerHandler.handleBeforeInsert(Trigger.new);
        }
    ```

    <Note>
      This rule has a Low Confidence rating — refactoring trigger logic into a handler class is a structural change that requires careful testing. MoxyCode will explain the pattern but review the suggested fix thoroughly before applying.
    </Note>
  </Accordion>
</AccordionGroup>

### Info

<AccordionGroup>
  <Accordion title="System.debug statement left in code">
    **Rule ID:** `apex-system-debug`

    A `System.debug()` statement is present in the code.

    **Why it matters:** Debug statements left in production code clutter debug logs, add minor performance overhead, and can expose sensitive data in logs.

    **Fix:** Remove all `System.debug()` statements before deploying to production.
  </Accordion>
</AccordionGroup>

***

## LWC JavaScript rules

### Critical

<AccordionGroup>
  <Accordion title="Direct innerHTML assignment">
    **Rule ID:** `lwc-inner-html`

    A component is using direct `innerHTML` assignment to render content.

    **Why it matters:** Direct `innerHTML` assignment is an XSS vulnerability — if the content includes user-supplied data, it can be used to inject malicious scripts. Lightning Locker Service also blocks this pattern.

    **Fix:** Use LWC template directives (`lwc:if`, `for:each`) to render dynamic content safely.
  </Accordion>

  <Accordion title="@api property mutated directly">
    **Rule ID:** `lwc-api-mutated`

    A component is directly mutating an `@api` property inside the component.

    **Why it matters:** `@api` properties are owned by the parent component. Mutating them directly breaks the unidirectional data flow pattern in LWC and can cause unpredictable rendering behaviour.

    **Fix:** Copy the `@api` value to a tracked internal property and mutate the internal copy instead.
  </Accordion>
</AccordionGroup>

### Warning

<AccordionGroup>
  <Accordion title="Direct window access">
    **Rule ID:** `lwc-window-access`

    The component is accessing the global `window` object directly.

    **Why it matters:** Direct `window` access is blocked by Lightning Locker Service in production Salesforce orgs. Code that works in local development will fail when deployed.

    **Fix:** Use LWC-supported alternatives. For timers, use `setTimeout` and `setInterval` without the `window.` prefix.
  </Accordion>

  <Accordion title="Direct document access">
    **Rule ID:** `lwc-document-access`

    The component is using `document.querySelector()` or similar DOM APIs directly.

    **Why it matters:** Direct `document` access is blocked by Lightning Locker Service. Each component only has access to its own DOM — not the full page document.

    **Fix:** Use `this.template.querySelector()` to access elements within the component's own shadow DOM.

    ```javascript theme={null}
        // ❌ Before
        const input = document.querySelector('.my-input');

        // ✅ After
        const input = this.template.querySelector('.my-input');
    ```
  </Accordion>

  <Accordion title="Wire adapter error unchecked">
    **Rule ID:** `lwc-wire-error-unchecked`

    A wire adapter result is being used without checking the `.error` property first.

    **Why it matters:** Wire adapters return both `data` and `error`. If the wire call fails and `.error` is not handled, the component will silently fail or throw a runtime error when trying to access `.data`.

    **Fix:** Always check both `.data` and `.error` when using wire adapters.

    ```javascript theme={null}
        // ❌ Before
        @wire(getContacts, { accountId: '$accountId' })
        contacts;

        // ✅ After
        @wire(getContacts, { accountId: '$accountId' })
        wiredContacts({ error, data }) {
            if (data) {
                this.contacts = data;
            } else if (error) {
                this.error = error;
            }
        }
    ```
  </Accordion>
</AccordionGroup>

### Info

<AccordionGroup>
  <Accordion title="@track decorator on primitive value">
    **Rule ID:** `lwc-track-unnecessary`

    A `@track` decorator is being used on a primitive value (string, number, boolean).

    **Why it matters:** Since API version 46, all component properties are reactive by default. Using `@track` on primitives is unnecessary and adds noise to the code.

    **Fix:** Remove the `@track` decorator from primitive properties.

    ```javascript theme={null}
        // ❌ Before
        @track title = 'Hello';

        // ✅ After
        title = 'Hello';
    ```
  </Accordion>

  <Accordion title="event.target.value used">
    **Rule ID:** `lwc-event-target-value`

    The component is using `event.target.value` to read input values.

    **Why it matters:** For Lightning base components (`lightning-input`, `lightning-combobox`, etc.), the correct property is `event.detail.value`. Using `event.target.value` returns `undefined` for these components.

    **Fix:** Use `event.detail.value` for Lightning base components.

    ```javascript theme={null}
        // ❌ Before
        handleChange(event) {
            this.value = event.target.value;
        }

        // ✅ After
        handleChange(event) {
            this.value = event.detail.value;
        }
    ```
  </Accordion>

  <Accordion title="console.log left in code">
    **Rule ID:** `console-log-production`

    A `console.log()` or `console.error()` statement is present in the component JavaScript.

    **Why it matters:** Console statements left in production code clutter browser developer tools and can expose sensitive data.

    **Fix:** Remove all `console.log()` and `console.error()` statements before deploying to production.
  </Accordion>

  <Accordion title="Imperative Apex call missing .catch()">
    **Rule ID:** `lwc-missing-catch`

    An imperative Apex method call uses `.then()` without a `.catch()` block.

    **Why it matters:** Without a `.catch()` handler, any error thrown by the Apex method will be silently swallowed — the component will stop working with no visible error.

    **Fix:** Always add a `.catch()` block to handle errors from imperative Apex calls.

    ```javascript theme={null}
        // ❌ Before
        getAccountData({ accountId: this.recordId })
            .then(result => {
                this.account = result;
            });

        // ✅ After
        getAccountData({ accountId: this.recordId })
            .then(result => {
                this.account = result;
            })
            .catch(error => {
                this.error = error;
            });
    ```
  </Accordion>
</AccordionGroup>

***

## LWC HTML rules

### Warning

<AccordionGroup>
  <Accordion title="String onclick handler">
    **Rule ID:** `lwc-string-onclick`

    An `onclick` attribute is using string function call syntax.

    **Why it matters:** String-based event handlers like `onclick="handleClick()"` are not supported in LWC templates. This is a common mistake for developers coming from Aura components or standard HTML.

    **Fix:** Use curly brace expression syntax to reference the handler method.

    ```html theme={null}
        <!-- ❌ Before -->
        <button onclick="handleClick()">Click me</button>

        <!-- ✅ After -->
        <button onclick={handleClick}>Click me</button>
    ```
  </Accordion>

  <Accordion title="for:each missing key attribute">
    **Rule ID:** `lwc-for-each-no-key`

    A `for:each` directive is missing a `key` attribute on the repeated element.

    **Why it matters:** LWC requires a unique `key` attribute on elements rendered with `for:each` to efficiently track and re-render list items. Without it, LWC will throw a template rendering error.

    **Fix:** Add a `key` attribute with a unique value — typically the record ID.

    ```html theme={null}
        <!-- ❌ Before -->
        <template for:each={contacts} for:item="contact">
            <p>{contact.Name}</p>
        </template>

        <!-- ✅ After -->
        <template for:each={contacts} for:item="contact">
            <p key={contact.Id}>{contact.Name}</p>
        </template>
    ```
  </Accordion>
</AccordionGroup>

***

## Shared rules (Apex + LWC)

### Warning

<AccordionGroup>
  <Accordion title="Empty catch block">
    **Rule ID:** `empty-catch`

    A `catch` block is present but empty — exceptions are being silently swallowed.

    **Why it matters:** Empty catch blocks hide errors completely. When something goes wrong, there is no log, no user feedback, and no way to diagnose the problem.

    **Fix:** Always handle caught exceptions — at minimum, log them or surface an error message.

    ```apex theme={null}
        // ❌ Before
        try {
            update account;
        } catch (Exception e) {
        }

        // ✅ After
        try {
            update account;
        } catch (Exception e) {
            System.debug('Error updating account: ' + e.getMessage());
            throw e;
        }
    ```
  </Accordion>
</AccordionGroup>

***

<Card title="Code Analysis" icon="magnifying-glass" href="/workflows/code-analysis">
  Learn how MoxyCode surfaces these rules in your editor
</Card>
