agent-docs 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/.cursor/plans/OPTIMISE.md +379 -0
  2. package/.cursor/plans/VERSIONING.md +207 -0
  3. package/.cursor/rules/IMPORTANT.mdc +97 -0
  4. package/.github/ISSUE_TEMPLATE/bug_report.md +13 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  6. package/.github/dependabot.yml +38 -0
  7. package/.github/pull_request_template.md +10 -0
  8. package/.github/workflows/format.yml +35 -0
  9. package/CODE_OF_CONDUCT.md +64 -0
  10. package/CONTRIBUTING.md +52 -0
  11. package/LICENSE.md +20 -0
  12. package/PLAN.md +707 -0
  13. package/README.md +133 -0
  14. package/SECURITY.md +21 -0
  15. package/docs/APEXANNOTATIONS.md +472 -0
  16. package/docs/APEXDOC.md +198 -0
  17. package/docs/CML.md +877 -0
  18. package/docs/CODEANALYZER.md +435 -0
  19. package/docs/CONTEXTDEFINITIONS.md +617 -0
  20. package/docs/ESLINT.md +827 -0
  21. package/docs/ESLINTJSDOC.md +520 -0
  22. package/docs/FIELDSERVICE.md +4452 -0
  23. package/docs/GRAPHBINARY.md +208 -0
  24. package/docs/GRAPHENGINE.md +616 -0
  25. package/docs/GRAPHML.md +337 -0
  26. package/docs/GRAPHSON.md +302 -0
  27. package/docs/GREMLIN.md +490 -0
  28. package/docs/GRYO.md +232 -0
  29. package/docs/HUSKY.md +106 -0
  30. package/docs/JEST.md +387 -0
  31. package/docs/JORJE.md +537 -0
  32. package/docs/JSDOC.md +621 -0
  33. package/docs/PMD.md +910 -0
  34. package/docs/PNPM.md +409 -0
  35. package/docs/PRETTIER.md +716 -0
  36. package/docs/PRETTIERAPEX.md +874 -0
  37. package/docs/REVENUETRANSACTIONMANAGEMENT.md +887 -0
  38. package/docs/TINKERPOP.md +252 -0
  39. package/docs/VITEST.md +706 -0
  40. package/docs/VSCODE.md +231 -0
  41. package/docs/XPATH31.md +213 -0
  42. package/package.json +32 -0
  43. package/postinstall.mjs +51 -0
  44. package/prettier.config.js +18 -0
package/docs/PMD.md ADDED
@@ -0,0 +1,910 @@
1
+ ````markdown
2
+ # PMD Quick Reference
3
+
4
+ > **Version**: 1.0.0
5
+
6
+ Condensed PMD guide for Salesforce Code Analyzer integration.
7
+
8
+ **Reference:**
9
+ [PMD Engine](https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/guide/engine-pmd.html)
10
+
11
+ **Schema:**
12
+ [PMD Ruleset XML Schema](https://pmd.sourceforge.io/ruleset_2_0_0.xsd)
13
+
14
+ ## Related Docs
15
+
16
+ - [Code Analyzer Config](CODEANALYZER.md) - `code-analyzer.yml` reference
17
+ - [XPath 3.1](XPATH31.md) - XPath syntax for rules
18
+ - [Apex AST](#apex-ast-reference) - AST node types/patterns
19
+
20
+ ## Installation
21
+
22
+ Download from [GitHub releases](https://github.com/pmd/pmd/releases), extract,
23
+ add `bin/` to PATH. Salesforce Code Analyzer bundles PMD—direct install only for
24
+ standalone CLI.
25
+
26
+ ## Rulesets
27
+
28
+ XML files defining rules to execute. Reference in `code-analyzer.yml`:
29
+
30
+ ```yaml
31
+ engines:
32
+ pmd:
33
+ rulesets:
34
+ - rulesets/design/InnerClassesCannotBeStatic.xml
35
+ ```
36
+ ````
37
+
38
+ ### Design
39
+
40
+ ```xml
41
+ <?xml version="1.0" ?>
42
+ <ruleset
43
+ name="Custom Rules"
44
+ xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
45
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
46
+ xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"
47
+ >
48
+ <description>My custom rules</description>
49
+ <exclude-pattern>.*/test/.*</exclude-pattern>
50
+ <include-pattern>.*/src/.*</include-pattern>
51
+ <!-- Rules here -->
52
+ </ruleset>
53
+ ```
54
+
55
+ **Elements:** `<description>` (required), `<exclude-pattern>` (optional,
56
+ multiple), `<include-pattern>` (optional, multiple), `<rule>` (required,
57
+ multiple)
58
+
59
+ ### Referencing Rules
60
+
61
+ ```xml
62
+ <!-- Single rule -->
63
+ <rule ref="category/apex/codestyle.xml/NoMethodCallsInConditionals" />
64
+
65
+ <!-- Category with exclusions -->
66
+ <rule ref="category/apex/codestyle.xml">
67
+ <exclude name="WhileLoopsMustUseBraces"/>
68
+ </rule>
69
+ ```
70
+
71
+ ## Rule Configuration
72
+
73
+ ### Priority
74
+
75
+ 1=High, 5=Low. Filter via `--minimum-priority`:
76
+
77
+ ```xml
78
+ <rule ref="category/apex/errorprone.xml/EmptyCatchBlock">
79
+ <priority>5</priority>
80
+ </rule>
81
+ ```
82
+
83
+ ### Properties
84
+
85
+ **Property attributes:** `name` (required), `value` (optional—attr or child),
86
+ `description`, `type`, `delimiter`, `min`, `max`
87
+
88
+ **Important:** Code Analyzer only supports `severity`/`tags` overrides in
89
+ `code-analyzer.yml`. Property overrides require ruleset XML.
90
+
91
+ ```xml
92
+ <!-- Value as child element (recommended) -->
93
+ <property name="reportLevel"><value>150</value></property>
94
+
95
+ <!-- Value as attribute -->
96
+ <property name="reportLevel" value="150" />
97
+
98
+ <!-- Multivalued (comma-separated) -->
99
+ <property name="legalCollectionTypes" value="java.util.ArrayList,java.util.Vector"/>
100
+ ```
101
+
102
+ **Override custom rules:**
103
+
104
+ ```xml
105
+ <rule ref="rulesets/design/EnumMinimumValues.xml/EnumMinimumValues">
106
+ <properties>
107
+ <property name="minValues">
108
+ <value>4</value>
109
+ </property>
110
+ </properties>
111
+ </rule>
112
+ ```
113
+
114
+ **code-analyzer.yml (severity/tags only):**
115
+
116
+ ```yaml
117
+ rules:
118
+ pmd:
119
+ NPathComplexity:
120
+ severity: 'High'
121
+ tags: ['Recommended']
122
+ ```
123
+
124
+ **Complete Override Example:**
125
+
126
+ 1. Create `rulesets/custom-overrides.xml`:
127
+
128
+ ```xml
129
+ <?xml version="1.0" ?>
130
+ <ruleset
131
+ name="Custom Property Overrides"
132
+ xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
133
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
134
+ xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"
135
+ >
136
+ <description>Custom property overrides</description>
137
+ <rule ref="rulesets/design/EnumMinimumValues.xml/EnumMinimumValues">
138
+ <properties>
139
+ <property name="minValues">
140
+ <value>4</value>
141
+ </property>
142
+ </properties>
143
+ </rule>
144
+ <rule
145
+ ref="rulesets/design/PreferSwitchOverIfElseChains.xml/PreferSwitchOverIfElseChains"
146
+ >
147
+ <properties>
148
+ <property name="minElseIfStatements">
149
+ <value>4</value>
150
+ </property>
151
+ </properties>
152
+ </rule>
153
+ </ruleset>
154
+ ```
155
+
156
+ 2. Reference in `code-analyzer.yml`:
157
+
158
+ ```yaml
159
+ engines:
160
+ pmd:
161
+ custom_rulesets:
162
+ - rulesets/design/EnumMinimumValues.xml # Original first
163
+ - rulesets/design/PreferSwitchOverIfElseChains.xml
164
+ - rulesets/custom-overrides.xml # Override after
165
+ ```
166
+
167
+ **Ref format:** `{ruleset-path}/{rule-name}`
168
+
169
+ **XPathRule Custom Properties:** PMD 7.x doesn't validate custom XPathRule
170
+ properties. Use substitution pattern:
171
+
172
+ ```xpath
173
+ if ('${propertyName}' = '${propertyName}') then 'defaultValue' else '${propertyName}'
174
+ ```
175
+
176
+ When undefined, `${propertyName}` stays literal → check true → default used.
177
+
178
+ ### Examples
179
+
180
+ ```xml
181
+ <rule name="MyRule" language="apex" ...>
182
+ <description>Rule description</description>
183
+ <priority>3</priority>
184
+ <properties><!-- XPath --></properties>
185
+ <example><![CDATA[
186
+ // Violation
187
+ public void badExample() { }
188
+ // Valid
189
+ public void goodExample() { }
190
+ ]]></example>
191
+ </rule>
192
+ ```
193
+
194
+ ### Custom Messages
195
+
196
+ ```xml
197
+ <rule
198
+ ref="category/apex/errorprone.xml/EmptyCatchBlock"
199
+ message="Empty catch blocks should be avoided"
200
+ />
201
+ ```
202
+
203
+ ### Rule Element Structure
204
+
205
+ **Child elements (order required):** `description` → `priority` → `properties` →
206
+ `exclude` → `example`
207
+
208
+ Verify: `pnpm check-xml-order` | Fix: `pnpm fix-xml-order`
209
+
210
+ **Attributes:** `name`, `language`, `minimumLanguageVersion`,
211
+ `maximumLanguageVersion`, `ref`, `message`, `class`, `since`, `externalInfoUrl`,
212
+ `deprecated` (default: false), `dfa`, `typeResolution` (default: false)
213
+
214
+ ## Suppressing Warnings
215
+
216
+ Quick reference for suppressing PMD rule violations in Apex code. Use
217
+ suppressions sparingly—prefer fixing issues or improving rules when possible.
218
+
219
+ ### Suppression Methods (Priority Order)
220
+
221
+ 1. **Fix the issue or improve the rule** (preferred)
222
+ 2. **Annotations** - Class/method level
223
+ 3. **NOPMD comment** - Line level
224
+ 4. **Rule properties** - Global suppression via `violationSuppressRegex` or
225
+ `violationSuppressXPath`
226
+
227
+ ### Annotations
228
+
229
+ #### Suppress All PMD Warnings
230
+
231
+ ```apex
232
+ @SuppressWarnings('PMD')
233
+ public class MyClass {
234
+ // All PMD warnings suppressed in this class
235
+ }
236
+ ```
237
+
238
+ #### Suppress Specific Rule
239
+
240
+ ```apex
241
+ @SuppressWarnings('PMD.UnusedLocalVariable')
242
+ public class MyClass {
243
+ void method() {
244
+ int unused = 42; // No violation
245
+ }
246
+ }
247
+ ```
248
+
249
+ #### Suppress Multiple Rules
250
+
251
+ ```apex
252
+ @SuppressWarnings('PMD.UnusedLocalVariable, PMD.UnusedPrivateMethod')
253
+ public class MyClass {
254
+ private int unused;
255
+ private void unusedMethod() {}
256
+ }
257
+ ```
258
+
259
+ **Note:** Apex uses single quotes and comma-separated values (not JSON array
260
+ syntax like Java).
261
+
262
+ ### NOPMD Comment
263
+
264
+ Suppress a single line violation:
265
+
266
+ ```apex
267
+ public class MyClass {
268
+ private int bar; // NOPMD - accessed by native method
269
+ }
270
+ ```
271
+
272
+ **Important:** The `// NOPMD` marker must be on the same line as the violation.
273
+ Optional message after marker appears in reports:
274
+
275
+ ```apex
276
+ if (condition) { // NOPMD - temporary workaround
277
+ }
278
+ ```
279
+
280
+ #### Custom Suppression Marker
281
+
282
+ Change the marker via CLI `--suppress-marker` option (default: `NOPMD`):
283
+
284
+ ```bash
285
+ sf code-analyzer run --suppress-marker "TURN_OFF_WARNINGS"
286
+ ```
287
+
288
+ ### Rule Properties (Global Suppression)
289
+
290
+ **Important:** Salesforce Code Analyzer does not support property overrides via
291
+ `code-analyzer.yml`. Configure suppression properties via custom ruleset XML
292
+ files using `ref=` syntax.
293
+
294
+ Create a custom ruleset XML file to suppress violations matching patterns.
295
+
296
+ #### violationSuppressRegex
297
+
298
+ Suppress violations where the message matches a regex:
299
+
300
+ **Custom ruleset XML:**
301
+
302
+ ```xml
303
+ <rule ref="category/apex/bestpractices.xml/UnusedFormalParameter">
304
+ <properties>
305
+ <property name="violationSuppressRegex">
306
+ <value>.*'mySpecialParameter'.*</value>
307
+ </property>
308
+ </properties>
309
+ </rule>
310
+ ```
311
+
312
+ **For custom rules:**
313
+
314
+ ```xml
315
+ <rule ref="rulesets/design/SomeRule.xml/SomeRule">
316
+ <properties>
317
+ <property name="violationSuppressRegex">
318
+ <value>.*'mySpecialParameter'.*</value>
319
+ </property>
320
+ </properties>
321
+ </rule>
322
+ ```
323
+
324
+ #### violationSuppressXPath
325
+
326
+ Suppress violations where XPath query matches (XPath 3.1, context node is the
327
+ violation node):
328
+
329
+ **Custom ruleset XML:**
330
+
331
+ ```xml
332
+ <?xml version="1.0" ?>
333
+ <ruleset
334
+ name="Suppression Rules"
335
+ xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
336
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
337
+ xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"
338
+ >
339
+ <description>Suppression rules for specific patterns</description>
340
+
341
+ <!-- Suppress String parameters -->
342
+ <rule ref="category/apex/bestpractices.xml/UnusedFormalParameter">
343
+ <properties>
344
+ <property name="violationSuppressXPath">
345
+ <value>.[pmd-apex:typeIs('String')]</value>
346
+ </property>
347
+ </properties>
348
+ </rule>
349
+
350
+ <!-- Suppress in classes containing "Bean" -->
351
+ <rule ref="rulesets/design/SomeRule.xml/SomeRule">
352
+ <properties>
353
+ <property name="violationSuppressXPath">
354
+ <value>
355
+ ./ancestor-or-self::ClassDeclaration[contains(@SimpleName, 'Bean')]
356
+ </value>
357
+ </property>
358
+ </properties>
359
+ </rule>
360
+
361
+ <!-- Suppress in equals/hashCode methods -->
362
+ <rule ref="rulesets/design/AnotherRule.xml/AnotherRule">
363
+ <properties>
364
+ <property name="violationSuppressXPath">
365
+ <value>
366
+ ./ancestor-or-self::MethodDeclaration[@Name = ('equals', 'hashCode')]
367
+ </value>
368
+ </property>
369
+ </properties>
370
+ </rule>
371
+
372
+ <!-- Suppress in classes ending with "Bean" (regex match) -->
373
+ <rule ref="rulesets/design/YetAnotherRule.xml/YetAnotherRule">
374
+ <properties>
375
+ <property name="violationSuppressXPath">
376
+ <value>
377
+ ./ancestor-or-self::ClassDeclaration[matches(@SimpleName, '^.*Bean$')]
378
+ </value>
379
+ </property>
380
+ </properties>
381
+ </rule>
382
+ </ruleset>
383
+ ```
384
+
385
+ Then reference in `code-analyzer.yml`:
386
+
387
+ ```yaml
388
+ engines:
389
+ pmd:
390
+ custom_rulesets:
391
+ - rulesets/design/SomeRule.xml
392
+ - rulesets/design/AnotherRule.xml
393
+ - rulesets/design/YetAnotherRule.xml
394
+ - rulesets/suppression-rules.xml # Custom suppression ruleset
395
+ ```
396
+
397
+ **XPath Notes:**
398
+
399
+ - Use `.` to reference the context node (the violation node)
400
+ - Prefer `./ancestor-or-self::` over `//` to avoid over-suppressing
401
+ - Context node varies by rule (check rule implementation)
402
+ - XPath 3.1 syntax supported (since PMD 7)
403
+
404
+ ### Best Practices
405
+
406
+ 1. **Fix or improve rules first** - Suppressions hide issues; better to fix root
407
+ cause
408
+ 2. **Be specific** - Suppress only what's necessary (specific rules, not all PMD
409
+ warnings)
410
+ 3. **Document why** - Add comments explaining suppression reason
411
+ 4. **Review periodically** - Suppressions may become unnecessary after code/rule
412
+ changes
413
+
414
+ ## CLI Usage
415
+
416
+ ```bash
417
+ pmd check -d <source> -R <ruleset> -f <format>
418
+ ```
419
+
420
+ **Options:** | Option | Description | |--------|-------------| | `-d`, `--dir` |
421
+ Source directory | | `-R`, `--rulesets` | Ruleset file | | `-f`, `--format` |
422
+ Report format | | `--minimum-priority` | Filter priority (1-5 or
423
+ High/Medium/Low) | | `-l`, `--language` | Language (apex, java, etc.) | |
424
+ `--use-version` | Language version (PMD 7+) | | `--fail-on-violation` | Exit
425
+ with error on violations | | `--no-cache` | Disable cache | | `--cache` | Enable
426
+ cache with file |
427
+
428
+ **PMD 6→7 changes:** `-no-cache`→`--no-cache`,
429
+ `-failOnViolation`→`--fail-on-violation`, `-reportfile`→`--report-file`,
430
+ `-language`→`--use-version`
431
+
432
+ ```bash
433
+ pmd check -d src/main/apex -R rulesets/all.xml -f html -l apex --use-version 60
434
+ ```
435
+
436
+ ## Report Formats
437
+
438
+ `text`, `xml`, `html`, `csv`, `json`, `sarif`, `codeclimate`, `junit`
439
+
440
+ ## CPD (Copy-Paste Detector)
441
+
442
+ Finds duplicated code for refactoring.
443
+
444
+ ```bash
445
+ pmd cpd --minimum-tokens 100 --language apex --files src/
446
+ ```
447
+
448
+ **Options:** `--minimum-tokens` (required), `--language`, `--format`
449
+ (text/xml/csv/csv_with_linecount_per_file/vs/json), `--ignore-identifiers`,
450
+ `--ignore-literals`, `--ignore-annotations`, `--skip-duplicate-files`
451
+
452
+ **Suppression:**
453
+
454
+ ```java
455
+ // CPD-OFF
456
+ public void duplicateCode() { }
457
+ // CPD-ON
458
+ ```
459
+
460
+ **GUI:** `pmd cpd-gui`
461
+
462
+ ## Incremental Analysis
463
+
464
+ ```bash
465
+ pmd --cache <cache_file> -d <source> -R <ruleset>
466
+ ```
467
+
468
+ Code Analyzer handles automatically.
469
+
470
+ ## Rule Categories
471
+
472
+ 1. Best Practices 2. Code Style 3. Design 4. Documentation 5. Error Prone 6.
473
+ Multithreading 7. Performance 8. Security
474
+
475
+ ## GitHub Actions
476
+
477
+ ```yaml
478
+ steps:
479
+ - uses: actions/checkout@v4
480
+ - uses: actions/setup-java@v4
481
+ with:
482
+ distribution: 'temurin'
483
+ java-version: '11'
484
+ - uses: pmd/pmd-github-action@v2
485
+ with:
486
+ rulesets: 'rulesets/design/InnerClassesCannotBeStatic.xml'
487
+ ```
488
+
489
+ **Inputs:** `rulesets` (required), `version` (default: "latest"), `sourcePath`
490
+ (default: "."), `analyzeModifiedFilesOnly` (default: "true"),
491
+ `createGitHubAnnotations` (default: "true"), `uploadSarifReport` (default:
492
+ "true")
493
+
494
+ **Output:** `violations` (count)
495
+
496
+ ```yaml
497
+ - uses: pmd/pmd-github-action@v2
498
+ id: pmd
499
+ with:
500
+ rulesets: 'rulesets/all.xml'
501
+ - name: Fail on violations
502
+ if: steps.pmd.outputs.violations != 0
503
+ run: exit 1
504
+ ```
505
+
506
+ **Limits:** No `auxclasspath`, XPath rules only, no custom env vars, max 300
507
+ files with `analyzeModifiedFilesOnly`
508
+
509
+ ## Language Versions
510
+
511
+ Use `--use-version` to specify. Rules can set
512
+ `minimumLanguageVersion`/`maximumLanguageVersion`. Check `pmd check --help` for
513
+ available versions.
514
+
515
+ ## Code Metrics
516
+
517
+ **ApexMetrics:** `CYCLO`, `COGNITIVE_COMPLEXITY`, `NCSS`, `WEIGHED_METHOD_COUNT`
518
+
519
+ ```java
520
+ import net.sourceforge.pmd.lang.apex.metrics.ApexMetrics;
521
+ import net.sourceforge.pmd.lang.metrics.MetricsUtil;
522
+
523
+ int cyclo = MetricsUtil.computeMetric(ApexMetrics.CYCLO, node);
524
+ int cognitive = MetricsUtil.computeMetric(ApexMetrics.COGNITIVE_COMPLEXITY, node);
525
+ ```
526
+
527
+ **Refs:**
528
+ [ApexMetrics API](https://docs.pmd-code.org/apidocs/pmd-apex/7.20.0-SNAPSHOT/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.html),
529
+ [MetricsUtil API](https://docs.pmd-code.org/apidocs/pmd-core/7.20.0-SNAPSHOT/net/sourceforge/pmd/lang/metrics/MetricsUtil.html)
530
+
531
+ ## Apex Support
532
+
533
+ Built-in rules, Summit AST parser (PMD 7+), metrics, language-specific config.
534
+
535
+ **Refs:**
536
+ [Apex Language Docs](https://pmd.github.io/pmd/pmd_languages_apex.html)
537
+
538
+ ## Apex AST Reference
539
+
540
+ **Note:** This reference is for PMD 7.0.0+, which uses Summit AST parser
541
+ (replaced Jorje parser in PMD 6).
542
+
543
+ ### PMD 7 Apex AST Changes
544
+
545
+ PMD 7.0.0 switched from Jorje to Summit AST parser. Key changes:
546
+
547
+ #### Removed Attributes
548
+
549
+ - **`Method/@Synthetic`** - Removed. Summit AST doesn't generate synthetic
550
+ methods, so this attribute would always be false.
551
+ - **`Method/@Namespace`** - Removed. This attribute was never fully implemented
552
+ and always returned an empty string.
553
+ - **`ReferenceExpression/@Context`** - Removed. This attribute was not used and
554
+ always returned null.
555
+
556
+ #### Removed Nodes
557
+
558
+ - **`BridgeMethodCreator`** - Removed. This was an artificially generated node
559
+ by Jorje. Summit AST doesn't generate synthetic methods.
560
+ - **Methods named `<clinit>` and `<init>`** - No longer generated by Summit AST.
561
+
562
+ #### Impact on XPath Rules
563
+
564
+ When migrating XPath rules from PMD 6 to PMD 7:
565
+
566
+ 1. **Remove references to removed attributes:**
567
+ - Remove `@Synthetic` checks on `Method` nodes
568
+ - Remove `@Namespace` checks on any nodes
569
+ - Remove `@Context` checks on `ReferenceExpression` nodes
570
+
571
+ 2. **Remove references to removed nodes:**
572
+ - Remove XPath expressions matching `BridgeMethodCreator` nodes
573
+ - Remove checks for method names `<clinit>` or `<init>`
574
+
575
+ 3. **Test thoroughly:** The AST structure is mostly compatible, but some edge
576
+ cases may differ.
577
+
578
+ **References:**
579
+
580
+ - [PMD 7 Migration Guide - Apex AST](https://pmd.github.io/pmd/pmd_userdocs_migrating_to_pmd7.html#apex-ast)
581
+ - [Apex Language Documentation](https://pmd.github.io/pmd/pmd_languages_apex.html)
582
+
583
+ ### Core Structure Nodes
584
+
585
+ **UserClass** - Class declaration
586
+
587
+ - `@Name`, `@SimpleName` - Class name
588
+ - `@Abstract`, `@Interface` - Type flags
589
+ - `@Nested` - Inner class flag
590
+
591
+ **ApexFile** - File/compilation unit (root)
592
+
593
+ **Method** - Method declaration
594
+
595
+ - `@Image`, `@MethodName`, `@FullMethodName` - Method name
596
+ - `@ReturnType` - Return type
597
+ - `@Constructor` - Constructor flag
598
+ - `@InputParametersSize` - Parameter count
599
+ - Children: `ModifierNode`, `Parameter`, `BlockStatement`
600
+
601
+ **Field** / **FieldDeclaration** / **FieldDeclarationStatements** - Field
602
+ declarations
603
+
604
+ - `@Name` - Field name
605
+ - Children: `ModifierNode`, `VariableExpression`
606
+
607
+ **Property** - Property declaration (getter/setter)
608
+
609
+ **Parameter** - Method/constructor parameter
610
+
611
+ - `@Image` - Parameter name
612
+ - `@Type` - Parameter type
613
+
614
+ **ModifierNode** - Access/type modifiers
615
+
616
+ - `@Static`, `@Final`, `@Abstract`, `@Public`, `@Private`, `@Protected`
617
+ - `@Override`, `@Global`, `@WebService`
618
+
619
+ **Annotation** - Annotation
620
+
621
+ - `@Name` - Annotation name (e.g., `'SuppressWarnings'`, `'IsTest'`)
622
+ - Note: Path is `Field/ModifierNode/Annotation[@Name]` (not
623
+ `Field/Annotation[@Name]`)
624
+
625
+ ### Control Flow Nodes
626
+
627
+ **IfBlockStatement** - if statement
628
+
629
+ - Children: `StandardCondition`, `BlockStatement`
630
+
631
+ **IfElseBlockStatement** - if-else chain
632
+
633
+ - Children: multiple `IfBlockStatement`
634
+
635
+ **SwitchStatement** - switch statement
636
+
637
+ - Children: `StandardCondition`, case blocks
638
+
639
+ **WhileLoopStatement** - while loop
640
+
641
+ - Children: `StandardCondition`, `BlockStatement`
642
+
643
+ **ForLoopStatement** - for loop
644
+
645
+ - Children: `StandardCondition`, `BlockStatement`
646
+
647
+ **ForEachStatement** - for-each loop
648
+
649
+ - Children: `StandardCondition`, `BlockStatement`
650
+
651
+ **DoLoopStatement** - do-while loop
652
+
653
+ **CatchBlockStatement** - catch block
654
+
655
+ **StandardCondition** - Condition expression (if, while, etc.)
656
+
657
+ - Children: `BooleanExpression`, `PrimaryExpression`
658
+
659
+ ### Expression Nodes
660
+
661
+ **PrimaryExpression** - Primary expression (method calls, field access, etc.)
662
+
663
+ - Children: `MethodCallExpression`, `ReferenceExpression`, `VariableExpression`,
664
+ etc.
665
+
666
+ **MethodCallExpression** - Method invocation
667
+
668
+ - `@Image` - Method name
669
+ - Children: arguments
670
+
671
+ **ReferenceExpression** - Field/method reference
672
+
673
+ - `@Image` - Reference name
674
+
675
+ **VariableExpression** - Variable reference
676
+
677
+ - `@Image` - Variable name
678
+
679
+ **ThisVariableExpression** - `this` reference
680
+
681
+ **AssignmentExpression** - Assignment
682
+
683
+ - `@Op` - Operator (`=`, `+=`, `-=`, `*=`, `/=`, `%=`)
684
+
685
+ **BinaryExpression** - Binary operation
686
+
687
+ - `@Op` - Operator (`+`, `-`, `*`, `/`, `==`, `!=`, `<`, `<=`, `>`, `>=`, `and`,
688
+ `or`, etc.)
689
+
690
+ **UnaryExpression** - Unary operation
691
+
692
+ - `@Op` - Operator (`++`, `--`, `+`, `-`, `!`, `not`)
693
+
694
+ **TernaryExpression** - Ternary operator (`? :`)
695
+
696
+ - Children: `StandardCondition`, then/else expressions
697
+
698
+ **BooleanExpression** - Boolean expression
699
+
700
+ - `@Op` - Operator (`==`, `!=`, `<`, `>`, `and`, `or`, etc.)
701
+ - Children: `VariableExpression`, `LiteralExpression`, etc.
702
+
703
+ **LiteralExpression** - Literal value
704
+
705
+ - `@Image` - Literal text
706
+ - `@Null` - Null literal flag
707
+ - `@String` - String literal flag
708
+ - `@LiteralType` - Type (e.g., `'Integer'`, `'String'`, `'Boolean'`)
709
+
710
+ **InstanceOfExpression** - `instanceof` check
711
+
712
+ **NewListLiteralExpression** - List literal `new List<Type>{...}`
713
+
714
+ - Children: elements
715
+
716
+ **NewMapLiteralExpression** - Map literal `new Map<K,V>{...}`
717
+
718
+ - Children: `MapEntryNode`
719
+
720
+ **MapEntryNode** - Map entry (key-value pair)
721
+
722
+ - `@BeginLine`, `@EndLine` - Line numbers
723
+
724
+ ### Statement Nodes
725
+
726
+ **BlockStatement** - Code block `{...}`
727
+
728
+ - `@BeginLine`, `@EndLine` - Line numbers
729
+
730
+ **ReturnStatement** - return statement
731
+
732
+ - Children: expression
733
+
734
+ **ThrowStatement** - throw statement
735
+
736
+ - Children: exception expression
737
+
738
+ **BreakStatement** - break statement
739
+
740
+ **ContinueStatement** - continue statement
741
+
742
+ ### Other Nodes
743
+
744
+ **FormalComment** - Javadoc/comment
745
+
746
+ **Important:** PMD's Apex parser only includes block comments (`/* */`) and
747
+ ApexDoc comments (`/** */`) in the AST as `FormalComment` nodes. Single-line
748
+ comments (`//`) are **not** included in the AST and cannot be detected using
749
+ XPath expressions. For rules that need to detect single-line comments (e.g.,
750
+ `// prettier-ignore`, `// NOPMD`), use regex-based rules instead of PMD XPath
751
+ rules. See [Regex Engine](CODEANALYZER.md#regex-engine) for creating regex-based
752
+ rules.
753
+
754
+ **UserEnum** - Enum declaration
755
+
756
+ - Children: `Field` (enum values)
757
+
758
+ **VariableDeclaration** - Variable declaration
759
+
760
+ - `@Image` - Variable name
761
+ - Children: `VariableExpression`, `VariableInitializer`
762
+
763
+ **VariableDeclarationStatements** - Variable declaration statement
764
+
765
+ - Children: `VariableDeclaration`, `ModifierNode`
766
+
767
+ **VariableInitializer** - Variable initialization
768
+
769
+ - Children: `Expression`
770
+
771
+ **Expression** - Generic expression wrapper
772
+
773
+ ### Common Attributes
774
+
775
+ **Identity/Name:**
776
+
777
+ - `@Image` - Text/image (name, value, operator symbol)
778
+ - `@Name`, `@SimpleName` - Node name
779
+ - `@MethodName`, `@FullMethodName` - Method names
780
+ - `@VariableName` - Variable name
781
+
782
+ **Location:**
783
+
784
+ - `@BeginLine`, `@EndLine` - Line numbers
785
+ - `@BeginColumn`, `@EndColumn` - Column numbers
786
+ - `@CurlyBrace` - Has curly braces
787
+
788
+ **Type/Flags:**
789
+
790
+ - `@Type`, `@ReturnType`, `@LiteralType` - Types
791
+ - `@Static`, `@Final`, `@Abstract`, `@Public`, `@Private`, `@Protected` -
792
+ Modifiers
793
+ - `@Constructor`, `@Interface`, `@Nested` - Structure flags
794
+ - `@Override`, `@Null`, `@String` - Special flags
795
+
796
+ **Operators:**
797
+
798
+ - `@Op` - Operator symbol (`+`, `-`, `==`, `!=`, `++`, `--`, `+=`, etc.)
799
+
800
+ **Counts:**
801
+
802
+ - `@InputParametersSize` - Parameter count
803
+
804
+ ### Common Patterns
805
+
806
+ #### Find methods
807
+
808
+ ```xpath
809
+ //Method[@Image = 'methodName']
810
+ //Method[@Static = true()]
811
+ //Method[@Constructor = true()]
812
+ ```
813
+
814
+ #### Find classes
815
+
816
+ ```xpath
817
+ //UserClass[@Nested = true()]
818
+ //UserClass[@Abstract = true()]
819
+ ```
820
+
821
+ #### Find variables
822
+
823
+ ```xpath
824
+ //VariableDeclaration[ancestor::Method] # Local vars only
825
+ //VariableExpression[@Image = 'varName']
826
+ ```
827
+
828
+ #### Find method calls
829
+
830
+ ```xpath
831
+ //MethodCallExpression[@Image = 'methodName']
832
+ //PrimaryExpression/MethodCallExpression
833
+ ```
834
+
835
+ #### Check modifiers
836
+
837
+ ```xpath
838
+ //Method[ModifierNode[@Static = true()]]
839
+ //Field[ModifierNode[@Final = true()]]
840
+ ```
841
+
842
+ #### Check annotations
843
+
844
+ ```xpath
845
+ //Annotation[@Name = 'SuppressWarnings']
846
+ //Method/ModifierNode/Annotation[@Name = 'IsTest']
847
+ ```
848
+
849
+ #### Find control flow
850
+
851
+ ```xpath
852
+ //IfBlockStatement[StandardCondition//MethodCallExpression]
853
+ //WhileLoopStatement[StandardCondition//VariableExpression]
854
+ ```
855
+
856
+ #### Check operators
857
+
858
+ ```xpath
859
+ //BinaryExpression[@Op = '==']
860
+ //UnaryExpression[@Op = '++']
861
+ //AssignmentExpression[@Op = '+=']
862
+ ```
863
+
864
+ #### Check expressions
865
+
866
+ ```xpath
867
+ //LiteralExpression[@Null = true()]
868
+ //BooleanExpression[@Op = 'and']
869
+ //TernaryExpression
870
+ ```
871
+
872
+ #### Line number checks
873
+
874
+ ```xpath
875
+ //Method[@BeginLine = @EndLine] # Single line
876
+ //BlockStatement[@BeginLine != @EndLine] # Multi-line
877
+ ```
878
+
879
+ #### Count checks
880
+
881
+ ```xpath
882
+ //Method[count(Parameter) > 2]
883
+ //IfElseBlockStatement[count(IfBlockStatement) >= 3]
884
+ ```
885
+
886
+ ### Important Notes
887
+
888
+ - **Annotations:** Use `Field/ModifierNode/Annotation[@Name]` path (ModifierNode
889
+ is required)
890
+ - **Local vars:** Use `VariableDeclaration[ancestor::Method]` to exclude class
891
+ fields
892
+ - **Nested expressions:** Use `//` or `.//` to find nested nodes
893
+ - **Context:** Use `ancestor::`, `descendant::`, `parent::`, `child::` axes for
894
+ navigation
895
+ - **Predicates:** Use `[condition]` to filter nodes
896
+
897
+ ## Code Analyzer Integration
898
+
899
+ Configure via `code-analyzer.yml`:
900
+
901
+ - **Rulesets:** `engines.pmd.rulesets` (array)
902
+ - **Properties:** `rules.pmd.{RuleName}.properties`
903
+ - **Severity/Tags:** `rules.pmd.{RuleName}.severity`,
904
+ `rules.pmd.{RuleName}.tags`
905
+
906
+ See [CODEANALYZER.md](CODEANALYZER.md).
907
+
908
+ ```
909
+
910
+ ```