@salesforce/afv-skills 1.28.0 → 1.30.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.
- package/README.md +2 -0
- package/package.json +1 -1
- package/skills/agentforce-architecture-analyze/README.md +2 -8
- package/skills/agentforce-architecture-analyze/SKILL.md +2 -2
- package/skills/agentforce-architecture-analyze/references/contract.json +4 -4
- package/skills/agentforce-architecture-analyze/references/soql_fields.md +1 -1
- package/skills/data360-activate/README.md +0 -1
- package/skills/data360-activate/SKILL.md +0 -2
- package/skills/data360-connect/README.md +0 -2
- package/skills/data360-connect/SKILL.md +0 -2
- package/skills/data360-harmonize/SKILL.md +0 -1
- package/skills/data360-orchestrate/README.md +0 -7
- package/skills/data360-orchestrate/SKILL.md +0 -2
- package/skills/data360-prepare/README.md +0 -1
- package/skills/data360-prepare/SKILL.md +0 -1
- package/skills/data360-query/README.md +0 -1
- package/skills/data360-query/SKILL.md +0 -1
- package/skills/data360-segment/README.md +0 -1
- package/skills/data360-segment/SKILL.md +0 -2
- package/skills/dx-code-analyzer-configure/SKILL.md +31 -13
- package/skills/dx-code-analyzer-custom-rule-create/SKILL.md +484 -0
- package/skills/dx-code-analyzer-custom-rule-create/assets/pmd-ruleset-template.xml +31 -0
- package/skills/dx-code-analyzer-custom-rule-create/examples/metadata-xml-example-fields-api.md +87 -0
- package/skills/dx-code-analyzer-custom-rule-create/examples/metadata-xml-example-flows.md +105 -0
- package/skills/dx-code-analyzer-custom-rule-create/examples/metadata-xml-example-permissions.md +95 -0
- package/skills/dx-code-analyzer-custom-rule-create/examples/metadata-xml-examples.md +84 -0
- package/skills/dx-code-analyzer-custom-rule-create/examples/regex-examples.md +127 -0
- package/skills/dx-code-analyzer-custom-rule-create/examples/xpath-examples.md +227 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/advanced-pmd-patterns.md +288 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/apex-ast-reference.md +127 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/eslint-custom-plugins.md +247 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/eslint-rules-discovery.md +188 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/eslint-tier2-configurable.md +114 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/eslint-tier3-custom-plugins.md +113 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/metadata-xml-rules.md +285 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/regex-rule-schema.md +174 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/troubleshooting.md +141 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns-governor-limits.md +83 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns-method-calls.md +108 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns-security.md +45 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns-structure.md +127 -0
- package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns.md +131 -0
- package/skills/dx-code-analyzer-custom-rule-create/scripts/create-pmd-rule.js +209 -0
- package/skills/dx-code-analyzer-custom-rule-create/scripts/create-regex-rule.js +220 -0
- package/skills/dx-code-analyzer-run/SKILL.md +41 -8
- package/skills/experience-cms-brand-apply/SKILL.md +47 -16
- package/skills/experience-lwc-generate/README.md +3 -2
- package/skills/experience-lwc-generate/references/async-notification-patterns.md +1 -1
- package/skills/experience-lwc-generate/references/component-patterns.md +3 -3
- package/skills/experience-lwc-generate/references/flow-integration-guide.md +1 -1
- package/skills/experience-lwc-generate/references/lwc-best-practices.md +4 -4
- package/skills/experience-lwc-generate/references/scoring-and-testing.md +1 -1
- package/skills/experience-lwc-generate/references/state-management.md +2 -2
- package/skills/experience-lwc-generate/references/triangle-pattern.md +3 -3
- package/skills/experience-lwc-generate/scripts/post-tool-validate.py +2 -2
- package/skills/experience-lwc-generate/scripts/template_validator.py +1 -1
- package/skills/external-diagram-mermaid-generate/README.md +2 -2
- package/skills/external-diagram-mermaid-generate/SKILL.md +1 -3
- package/skills/external-diagram-mermaid-generate/assets/agentforce/agent-flow.md +4 -4
- package/skills/external-diagram-mermaid-generate/assets/architecture/system-landscape.md +1 -1
- package/skills/external-diagram-mermaid-generate/assets/datamodel/b2b-commerce-erd.md +3 -3
- package/skills/external-diagram-mermaid-generate/assets/datamodel/campaigns-erd.md +1 -1
- package/skills/external-diagram-mermaid-generate/assets/datamodel/consent-erd.md +2 -2
- package/skills/external-diagram-mermaid-generate/assets/datamodel/files-erd.md +2 -2
- package/skills/external-diagram-mermaid-generate/assets/datamodel/forecasting-erd.md +2 -2
- package/skills/external-diagram-mermaid-generate/assets/datamodel/fsl-erd.md +2 -2
- package/skills/external-diagram-mermaid-generate/assets/datamodel/party-model-erd.md +1 -1
- package/skills/external-diagram-mermaid-generate/assets/datamodel/quote-order-erd.md +3 -3
- package/skills/external-diagram-mermaid-generate/assets/datamodel/revenue-cloud-erd.md +2 -2
- package/skills/external-diagram-mermaid-generate/assets/datamodel/sales-cloud-erd.md +1 -1
- package/skills/external-diagram-mermaid-generate/assets/datamodel/salesforce-erd.md +1 -1
- package/skills/external-diagram-mermaid-generate/assets/datamodel/scheduler-erd.md +2 -2
- package/skills/external-diagram-mermaid-generate/assets/datamodel/service-cloud-erd.md +3 -3
- package/skills/external-diagram-mermaid-generate/assets/datamodel/territory-management-erd.md +1 -1
- package/skills/external-diagram-mermaid-generate/assets/integration/api-sequence.md +1 -1
- package/skills/external-diagram-mermaid-generate/assets/oauth/authorization-code-pkce.md +1 -1
- package/skills/external-diagram-mermaid-generate/assets/oauth/authorization-code.md +1 -1
- package/skills/external-diagram-mermaid-generate/assets/oauth/client-credentials.md +1 -1
- package/skills/external-diagram-mermaid-generate/assets/oauth/device-authorization.md +2 -2
- package/skills/external-diagram-mermaid-generate/assets/oauth/jwt-bearer.md +2 -2
- package/skills/external-diagram-mermaid-generate/assets/oauth/refresh-token.md +1 -1
- package/skills/external-diagram-mermaid-generate/assets/oauth/user-agent-social-sign-on.md +2 -2
- package/skills/external-diagram-mermaid-generate/assets/role-hierarchy/user-hierarchy.md +1 -1
- package/skills/external-diagram-mermaid-generate/references/color-palette.md +13 -13
- package/skills/external-diagram-mermaid-generate/references/diagram-conventions.md +5 -5
- package/skills/external-diagram-mermaid-generate/references/erd-conventions.md +1 -1
- package/skills/external-diagram-mermaid-generate/references/mermaid-styling.md +2 -2
- package/skills/external-diagram-mermaid-generate/references/preview-guide.md +1 -1
- package/skills/external-diagram-mermaid-generate/references/usage-examples.md +9 -9
- package/skills/external-diagram-mermaid-generate/scripts/README.md +1 -1
- package/skills/integration-connectivity-connected-app-configure/README.md +4 -5
- package/skills/integration-connectivity-connected-app-configure/SKILL.md +2 -2
- package/skills/integration-connectivity-connected-app-configure/references/example-usage.md +7 -7
- package/skills/integration-connectivity-connected-app-configure/references/migration-guide.md +1 -1
- package/skills/integration-connectivity-connected-app-configure/references/oauth-flows-reference.md +1 -1
- package/skills/integration-connectivity-connected-app-configure/references/testing-validation-guide.md +3 -3
- package/skills/integration-connectivity-generate/README.md +1 -1
- package/skills/integration-connectivity-generate/SKILL.md +6 -0
- package/skills/integration-connectivity-generate/assets/callouts/rest-queueable-callout.cls +1 -1
- package/skills/integration-connectivity-generate/assets/external-services/external-service-operations.md +1 -1
- package/skills/integration-connectivity-generate/assets/soap/wsdl2apex-guide.md +1 -1
- package/skills/integration-connectivity-generate/references/callout-patterns.md +4 -0
- package/skills/integration-connectivity-generate/references/cdc-guide.md +2 -2
- package/skills/integration-connectivity-generate/references/event-driven-architecture-guide.md +5 -5
- package/skills/integration-connectivity-generate/references/event-patterns.md +3 -2
- package/skills/integration-connectivity-generate/references/external-services-guide.md +4 -1
- package/skills/integration-connectivity-generate/references/messaging-api-v2.md +2 -2
- package/skills/integration-connectivity-generate/references/named-credentials-automation.md +1 -1
- package/skills/integration-connectivity-generate/references/named-credentials-guide.md +12 -2
- package/skills/integration-connectivity-generate/references/platform-events-guide.md +3 -3
- package/skills/integration-connectivity-generate/references/rest-callout-patterns.md +1 -1
- package/skills/integration-connectivity-generate/references/scoring-rubric.md +1 -1
- package/skills/integration-connectivity-generate/references/security-best-practices.md +5 -2
- package/skills/integration-connectivity-generate/scripts/configure-named-credential.sh +16 -5
- package/skills/integration-connectivity-generate/scripts/set-api-credential.sh +11 -2
- package/skills/integration-connectivity-generate/scripts/suggest_credential_setup.py +4 -3
- package/skills/integration-connectivity-generate/scripts/validate_integration.py +1 -1
- package/skills/mobile-platform-native-capabilities-integrate/SKILL.md +3 -3
- package/skills/omnistudio-callable-apex-generate/README.md +1 -5
- package/skills/omnistudio-callable-apex-generate/SKILL.md +14 -4
- package/skills/omnistudio-callable-apex-generate/assets/pattern_callable_vanilla.cls +8 -1
- package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterface2Conversion/TRANSCRIPT.md +1 -1
- package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterfaceConversion/TRANSCRIPT.md +1 -1
- package/skills/omnistudio-datamapper-generate/SKILL.md +1 -1
- package/skills/omnistudio-datamapper-generate/assets/completion-summary-template.md +2 -2
- package/skills/omnistudio-datamapper-generate/references/best-practices.md +9 -9
- package/skills/omnistudio-datamapper-generate/references/naming-conventions.md +6 -6
- package/skills/omnistudio-datapacks-deploy/README.md +1 -1
- package/skills/omnistudio-datapacks-deploy/examples/business-internet-plus-bundle/deploy-business-internet-plus-bundle.yaml +1 -1
- package/skills/omnistudio-dependencies-analyze/SKILL.md +12 -5
- package/skills/omnistudio-dependencies-analyze/references/dependency-patterns.md +9 -9
- package/skills/omnistudio-dependencies-analyze/references/namespace-guide.md +1 -1
- package/skills/omnistudio-epc-catalog-generate/README.md +1 -1
- package/skills/omnistudio-flexcard-generate/SKILL.md +11 -4
- package/skills/omnistudio-flexcard-generate/references/best-practices.md +6 -6
- package/skills/omnistudio-flexcard-generate/references/data-binding-guide.md +9 -9
- package/skills/omnistudio-integration-procedure-generate/SKILL.md +9 -1
- package/skills/omnistudio-integration-procedure-generate/references/element-types.md +3 -3
- package/skills/omnistudio-omniscript-generate/SKILL.md +2 -2
- package/skills/omnistudio-omniscript-generate/references/best-practices.md +1 -1
- package/skills/omnistudio-omniscript-generate/scripts/check-duplicate-omniscript.sh +8 -0
- package/skills/omnistudio-omniscript-generate/scripts/deploy-omniscript.sh +8 -0
- package/skills/platform-apex-logs-debug/README.md +2 -2
- package/skills/platform-apex-logs-debug/references/cli-commands.md +2 -2
- package/skills/platform-apex-logs-debug/references/debug-log-reference.md +16 -16
- package/skills/platform-apex-logs-debug/references/log-analysis-tools.md +2 -2
- package/skills/platform-apex-test-run/README.md +1 -1
- package/skills/platform-apex-test-run/references/test-fix-loop.md +2 -2
- package/skills/platform-apex-test-run/references/testing-best-practices.md +3 -3
- package/skills/platform-custom-field-generate/SKILL.md +86 -126
- package/skills/platform-custom-field-generate/references/advanced-picklists.md +590 -0
- package/skills/platform-data-manage/README.md +4 -4
- package/skills/platform-data-manage/references/bulk-testing-example.md +1 -1
- package/skills/platform-data-manage/references/crud-workflow-example.md +2 -2
- package/skills/platform-data-manage/references/orchestration.md +6 -6
- package/skills/platform-flexipage-generate/SKILL.md +281 -346
- package/skills/platform-flexipage-generate/references/cli_commands.md +39 -0
- package/skills/platform-flexipage-generate/references/flexipage_fieldSection.md +162 -0
- package/skills/platform-flexipage-generate/references/flexipage_richText.md +84 -0
- package/skills/platform-flexipage-generate/references/identifiers_and_regions.md +167 -0
- package/skills/platform-flexipage-generate/references/mcp_action_examples.md +104 -0
- package/skills/platform-flexipage-generate/references/record_flexipage_dynamicHighlights.md +119 -0
- package/skills/platform-flexipage-generate/references/xml_rules.md +335 -0
- package/skills/platform-flexipage-generate/scripts/resolve-component-instructions.sh +42 -0
- package/skills/platform-flexipage-generate/scripts/scan-lwc-components.sh +113 -0
- package/skills/platform-metadata-deploy/README.md +2 -2
- package/skills/platform-metadata-deploy/references/agent-deployment-guide.md +2 -2
- package/skills/platform-metadata-deploy/references/deployment-workflows.md +16 -16
- package/skills/platform-metadata-deploy/references/orchestration.md +3 -3
- package/skills/platform-metadata-deploy/references/trigger-deployment-safety.md +2 -2
- package/skills/platform-models-api-configure/SKILL.md +140 -0
- package/skills/platform-models-api-configure/scripts/get-orgjwt.sh +48 -0
- package/skills/platform-policy-rule-generate/SKILL.md +260 -0
- package/skills/platform-policy-rule-generate/references/deploy-errors.md +54 -0
- package/skills/platform-policy-rule-generate/references/fixtures-index.md +29 -0
- package/skills/platform-policy-rule-generate/references/policy-schema-full.md +250 -0
- package/skills/platform-policy-rule-generate/references/templates-access.md +132 -0
- package/skills/platform-policy-rule-generate/references/templates-advanced.md +58 -0
- package/skills/platform-policy-rule-generate/references/templates-record.md +75 -0
- package/skills/platform-policy-rule-generate/references/templates-transform.md +70 -0
- package/skills/platform-policy-rule-generate/references/templates.md +10 -0
- package/skills/platform-policy-rule-generate/references/ui-compatibility.md +142 -0
- package/skills/platform-soql-query/README.md +1 -1
- package/skills/platform-soql-query/SKILL.md +1 -1
- package/skills/platform-soql-query/references/anti-patterns.md +1 -1
- package/skills/platform-soql-query/references/field-coverage-rules.md +1 -1
- package/skills/platform-soql-query/references/query-optimization.md +1 -1
- package/skills/platform-soql-query/scripts/post-tool-validate.py +3 -3
- package/skills/platform-value-set-generate/SKILL.md +305 -0
- package/skills/data360-activate/CREDITS.md +0 -5
- package/skills/data360-connect/CREDITS.md +0 -5
- package/skills/data360-harmonize/CREDITS.md +0 -3
- package/skills/data360-orchestrate/CREDITS.md +0 -15
- package/skills/data360-orchestrate/UPSTREAM.md +0 -45
- package/skills/data360-prepare/CREDITS.md +0 -7
- package/skills/data360-query/CREDITS.md +0 -7
- package/skills/data360-segment/CREDITS.md +0 -3
- package/skills/experience-lwc-generate/CREDITS.md +0 -5
- package/skills/external-diagram-mermaid-generate/CREDITS.md +0 -46
- package/skills/external-diagram-visual-generate/CREDITS.md +0 -80
- package/skills/external-diagram-visual-generate/README.md +0 -83
- package/skills/external-diagram-visual-generate/SKILL.md +0 -207
- package/skills/external-diagram-visual-generate/assets/architecture/integration-flow.md +0 -55
- package/skills/external-diagram-visual-generate/assets/erd/core-objects.md +0 -131
- package/skills/external-diagram-visual-generate/assets/erd/custom-objects.md +0 -60
- package/skills/external-diagram-visual-generate/assets/lwc/dashboard-card.md +0 -45
- package/skills/external-diagram-visual-generate/assets/lwc/data-table.md +0 -57
- package/skills/external-diagram-visual-generate/assets/lwc/record-form.md +0 -60
- package/skills/external-diagram-visual-generate/assets/review/apex-review.md +0 -57
- package/skills/external-diagram-visual-generate/assets/review/lwc-review.md +0 -48
- package/skills/external-diagram-visual-generate/references/architect-aesthetic-guide.md +0 -257
- package/skills/external-diagram-visual-generate/references/examples-index.md +0 -35
- package/skills/external-diagram-visual-generate/references/gemini-cli-setup.md +0 -65
- package/skills/external-diagram-visual-generate/references/interview-questions.md +0 -529
- package/skills/external-diagram-visual-generate/references/iteration-workflow.md +0 -173
- package/skills/external-diagram-visual-generate/scripts/check-prerequisites.sh +0 -101
- package/skills/external-diagram-visual-generate/scripts/generate_image.py +0 -243
- package/skills/integration-connectivity-connected-app-configure/CREDITS.md +0 -3
- package/skills/integration-connectivity-generate/CREDITS.md +0 -5
- package/skills/omnistudio-callable-apex-generate/CREDITS.md +0 -9
- package/skills/omnistudio-datamapper-generate/CREDITS.md +0 -5
- package/skills/omnistudio-datapacks-deploy/CREDITS.md +0 -5
- package/skills/omnistudio-dependencies-analyze/CREDITS.md +0 -5
- package/skills/omnistudio-epc-catalog-generate/CREDITS.md +0 -14
- package/skills/omnistudio-flexcard-generate/CREDITS.md +0 -5
- package/skills/omnistudio-integration-procedure-generate/CREDITS.md +0 -5
- package/skills/omnistudio-omniscript-generate/CREDITS.md +0 -5
- package/skills/platform-apex-generate/CREDITS.md +0 -5
- package/skills/platform-apex-logs-debug/CREDITS.md +0 -22
- package/skills/platform-apex-test-generate/CREDITS.md +0 -5
- package/skills/platform-apex-test-run/CREDITS.md +0 -22
- package/skills/platform-data-manage/CREDITS.md +0 -5
- package/skills/platform-metadata-deploy/CREDITS.md +0 -25
- package/skills/platform-soql-query/CREDITS.md +0 -21
- /package/skills/omnistudio-callable-apex-generate/examples/Test_VlocityOpenInterfaceConversion/{MyCustomVlocityOpenInterface2.cls → MyCustomClass.cls} +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Metadata XML Examples: Flows
|
|
2
|
+
|
|
3
|
+
[← Back to Metadata XML Examples Index](metadata-xml-examples.md)
|
|
4
|
+
|
|
5
|
+
## Example 5: Require Flow Auto-Layout
|
|
6
|
+
|
|
7
|
+
**Problem:** Flows should use Auto-Layout canvas for consistency and maintainability.
|
|
8
|
+
|
|
9
|
+
**Target file:** `*.flow-meta.xml`
|
|
10
|
+
|
|
11
|
+
**Sample violating metadata:**
|
|
12
|
+
```xml
|
|
13
|
+
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
14
|
+
<apiVersion>58.0</apiVersion>
|
|
15
|
+
<label>My Flow</label>
|
|
16
|
+
<processMetadataValues>
|
|
17
|
+
<name>CanvasMode</name>
|
|
18
|
+
<value><stringValue>FREE_FORM_CANVAS</stringValue></value>
|
|
19
|
+
</processMetadataValues>
|
|
20
|
+
</Flow>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**XPath (PMD 7 — flags FREE_FORM_CANVAS):**
|
|
24
|
+
```xpath
|
|
25
|
+
//*[@Text='FREE_FORM_CANVAS']/../..
|
|
26
|
+
[local-name()='value']
|
|
27
|
+
[ancestor::*[local-name()='processMetadataValues'][.//*[@Text='CanvasMode']]]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**How it works:** Finds text nodes with "FREE_FORM_CANVAS", navigates up to the `<value>` element, then confirms it's inside a `processMetadataValues` block that also contains "CanvasMode".
|
|
31
|
+
|
|
32
|
+
**PMD ruleset:**
|
|
33
|
+
```xml
|
|
34
|
+
<rule name="FlowMustUseAutoLayout"
|
|
35
|
+
language="xml"
|
|
36
|
+
message="Flows must use AUTO_LAYOUT_CANVAS mode"
|
|
37
|
+
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule">
|
|
38
|
+
<description>Enforces auto-layout canvas mode on all flows for consistency</description>
|
|
39
|
+
<priority>3</priority>
|
|
40
|
+
<properties>
|
|
41
|
+
<property name="xpath">
|
|
42
|
+
<value><![CDATA[
|
|
43
|
+
//*[@Text='FREE_FORM_CANVAS']/../..
|
|
44
|
+
[local-name()='value']
|
|
45
|
+
[ancestor::*[local-name()='processMetadataValues'][.//*[@Text='CanvasMode']]]
|
|
46
|
+
]]></value>
|
|
47
|
+
</property>
|
|
48
|
+
</properties>
|
|
49
|
+
</rule>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Example 6: Flow Missing Fault Handler
|
|
55
|
+
|
|
56
|
+
**Problem:** Flow actions without fault connectors can fail silently.
|
|
57
|
+
|
|
58
|
+
**Target file:** `*.flow-meta.xml`
|
|
59
|
+
|
|
60
|
+
**Sample violating metadata:**
|
|
61
|
+
```xml
|
|
62
|
+
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
63
|
+
<recordCreates>
|
|
64
|
+
<name>Create_Account</name>
|
|
65
|
+
<object>Account</object>
|
|
66
|
+
<connector>
|
|
67
|
+
<targetReference>Next_Step</targetReference>
|
|
68
|
+
</connector>
|
|
69
|
+
<!-- No <faultConnector> element! -->
|
|
70
|
+
</recordCreates>
|
|
71
|
+
</Flow>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**XPath:**
|
|
75
|
+
```xpath
|
|
76
|
+
//*[local-name()='Flow']/*[
|
|
77
|
+
local-name()='recordCreates' or local-name()='recordUpdates'
|
|
78
|
+
or local-name()='recordDeletes' or local-name()='recordLookups'
|
|
79
|
+
][
|
|
80
|
+
not(*[local-name()='faultConnector'])
|
|
81
|
+
]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**PMD ruleset:**
|
|
85
|
+
```xml
|
|
86
|
+
<rule name="FlowActionRequiresFaultHandler"
|
|
87
|
+
language="xml"
|
|
88
|
+
message="Flow DML/query actions must have a fault connector for error handling"
|
|
89
|
+
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule">
|
|
90
|
+
<description>Ensures all data operations in flows have fault paths</description>
|
|
91
|
+
<priority>2</priority>
|
|
92
|
+
<properties>
|
|
93
|
+
<property name="xpath">
|
|
94
|
+
<value><![CDATA[
|
|
95
|
+
//*[local-name()='Flow']/*[
|
|
96
|
+
local-name()='recordCreates' or local-name()='recordUpdates'
|
|
97
|
+
or local-name()='recordDeletes' or local-name()='recordLookups'
|
|
98
|
+
][
|
|
99
|
+
not(*[local-name()='faultConnector'])
|
|
100
|
+
]
|
|
101
|
+
]]></value>
|
|
102
|
+
</property>
|
|
103
|
+
</properties>
|
|
104
|
+
</rule>
|
|
105
|
+
```
|
package/skills/dx-code-analyzer-custom-rule-create/examples/metadata-xml-example-permissions.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Metadata XML Examples: Permissions
|
|
2
|
+
|
|
3
|
+
[← Back to Metadata XML Examples Index](metadata-xml-examples.md)
|
|
4
|
+
|
|
5
|
+
## Example 1: Flag ModifyAllData / ViewAllData Permissions
|
|
6
|
+
|
|
7
|
+
**Problem:** Permission sets granting ModifyAllData or ViewAllData are a security risk.
|
|
8
|
+
|
|
9
|
+
**Target file:** `*.permissionset-meta.xml`
|
|
10
|
+
|
|
11
|
+
**Sample violating metadata:**
|
|
12
|
+
```xml
|
|
13
|
+
<PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
14
|
+
<label>Power User</label>
|
|
15
|
+
<userPermissions>
|
|
16
|
+
<enabled>true</enabled>
|
|
17
|
+
<name>ModifyAllData</name>
|
|
18
|
+
</userPermissions>
|
|
19
|
+
</PermissionSet>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**XPath (PMD 7):**
|
|
23
|
+
```xpath
|
|
24
|
+
//*[@Text='ModifyAllData' or @Text='ViewAllData']/../..
|
|
25
|
+
[local-name()='userPermissions']
|
|
26
|
+
[.//*[@Text='true']]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**How it works:**
|
|
30
|
+
1. `//*[@Text='ModifyAllData' or @Text='ViewAllData']` — find text node with dangerous permission name
|
|
31
|
+
2. `/../..` — navigate up: text node → `<name>` element → `<userPermissions>` parent
|
|
32
|
+
3. `[local-name()='userPermissions']` — confirm we're at the right element
|
|
33
|
+
4. `[.//*[@Text='true']]` — check that a descendant text node contains "true" (the `<enabled>` value)
|
|
34
|
+
|
|
35
|
+
**PMD ruleset:**
|
|
36
|
+
```xml
|
|
37
|
+
<rule name="NoDangerousPermissions"
|
|
38
|
+
language="xml"
|
|
39
|
+
message="Permission set grants ModifyAllData or ViewAllData — use specific object permissions instead"
|
|
40
|
+
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule">
|
|
41
|
+
<description>Flags permission sets that grant ModifyAllData or ViewAllData</description>
|
|
42
|
+
<priority>1</priority>
|
|
43
|
+
<properties>
|
|
44
|
+
<property name="xpath">
|
|
45
|
+
<value><![CDATA[
|
|
46
|
+
//*[@Text='ModifyAllData' or @Text='ViewAllData']/../..
|
|
47
|
+
[local-name()='userPermissions']
|
|
48
|
+
[.//*[@Text='true']]
|
|
49
|
+
]]></value>
|
|
50
|
+
</property>
|
|
51
|
+
</properties>
|
|
52
|
+
</rule>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Example 4: No Field Permissions in Profiles
|
|
58
|
+
|
|
59
|
+
**Problem:** Field permissions should be managed via Permission Sets, not Profiles.
|
|
60
|
+
|
|
61
|
+
**Target file:** `*.profile-meta.xml`
|
|
62
|
+
|
|
63
|
+
**Sample violating metadata:**
|
|
64
|
+
```xml
|
|
65
|
+
<Profile xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
66
|
+
<fieldPermissions>
|
|
67
|
+
<editable>true</editable>
|
|
68
|
+
<field>Account.Revenue__c</field>
|
|
69
|
+
<readable>true</readable>
|
|
70
|
+
</fieldPermissions>
|
|
71
|
+
</Profile>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**XPath:**
|
|
75
|
+
```xpath
|
|
76
|
+
//*[local-name()='Profile']/*[local-name()='fieldPermissions']
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**PMD ruleset:**
|
|
80
|
+
```xml
|
|
81
|
+
<rule name="NoFieldPermissionsInProfile"
|
|
82
|
+
language="xml"
|
|
83
|
+
message="Field permissions should be in Permission Sets, not Profiles"
|
|
84
|
+
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule">
|
|
85
|
+
<description>Profiles should not contain field-level security — use Permission Sets</description>
|
|
86
|
+
<priority>2</priority>
|
|
87
|
+
<properties>
|
|
88
|
+
<property name="xpath">
|
|
89
|
+
<value><![CDATA[
|
|
90
|
+
//*[local-name()='Profile']/*[local-name()='fieldPermissions']
|
|
91
|
+
]]></value>
|
|
92
|
+
</property>
|
|
93
|
+
</properties>
|
|
94
|
+
</rule>
|
|
95
|
+
```
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Metadata XML Rule Examples
|
|
2
|
+
|
|
3
|
+
Real-world custom PMD rules targeting Salesforce metadata XML files for org governance.
|
|
4
|
+
|
|
5
|
+
⚠️ **PMD 7 Note:** All examples use `@Text` for text content matching. The `text()` function does NOT work in PMD 7's XML language. See `references/metadata-xml-rules.md` for full details.
|
|
6
|
+
|
|
7
|
+
## Example Index
|
|
8
|
+
|
|
9
|
+
| # | Example | File |
|
|
10
|
+
|---|---------|------|
|
|
11
|
+
| 1 | Flag ModifyAllData / ViewAllData Permissions | [metadata-xml-example-permissions.md](metadata-xml-example-permissions.md) |
|
|
12
|
+
| 2 | Require Description on Custom Fields | [metadata-xml-example-fields-api.md](metadata-xml-example-fields-api.md) |
|
|
13
|
+
| 3 | Enforce Minimum API Version | [metadata-xml-example-fields-api.md](metadata-xml-example-fields-api.md) |
|
|
14
|
+
| 4 | No Field Permissions in Profiles | [metadata-xml-example-permissions.md](metadata-xml-example-permissions.md) |
|
|
15
|
+
| 5 | Require Flow Auto-Layout | [metadata-xml-example-flows.md](metadata-xml-example-flows.md) |
|
|
16
|
+
| 6 | Flow Missing Fault Handler | [metadata-xml-example-flows.md](metadata-xml-example-flows.md) |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## How to Create These
|
|
21
|
+
|
|
22
|
+
1. Run `sf code-analyzer ast-dump --file your-file.xml --language xml` to see the DOM structure. If ast-dump fails, read the raw XML file directly — the file content IS the AST.
|
|
23
|
+
2. Write XPath using `local-name()` for element matching and `@Text` for text content (NOT `text()`)
|
|
24
|
+
3. Navigate from text nodes to parent elements using `../..`
|
|
25
|
+
4. Scope to the correct metadata type by checking the root element or using `ancestor::`
|
|
26
|
+
5. Configure `file_extensions: { xml: [".xml"] }` in `code-analyzer.yml` (just `.xml` covers all compound metadata extensions)
|
|
27
|
+
6. Add the rule to a ruleset XML file with `language="xml"`
|
|
28
|
+
7. Reference the ruleset in `code-analyzer.yml` under `engines.pmd.custom_rulesets`
|
|
29
|
+
8. Validate: `sf code-analyzer rules --rule-selector pmd:RuleName`
|
|
30
|
+
9. Test positive + negative: run against both a violating and clean metadata file
|
|
31
|
+
|
|
32
|
+
## Complete Multi-Rule Ruleset Example
|
|
33
|
+
|
|
34
|
+
```xml
|
|
35
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
36
|
+
<ruleset name="MetadataGovernance"
|
|
37
|
+
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
|
38
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
39
|
+
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
|
40
|
+
|
|
41
|
+
<description>Org governance rules for Salesforce metadata</description>
|
|
42
|
+
|
|
43
|
+
<rule name="NoDangerousPermissions" language="xml"
|
|
44
|
+
message="Permission set grants ModifyAllData or ViewAllData"
|
|
45
|
+
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule">
|
|
46
|
+
<priority>1</priority>
|
|
47
|
+
<properties>
|
|
48
|
+
<property name="xpath">
|
|
49
|
+
<value><![CDATA[
|
|
50
|
+
//*[@Text='ModifyAllData' or @Text='ViewAllData']/../..
|
|
51
|
+
[local-name()='userPermissions']
|
|
52
|
+
[.//*[@Text='true']]
|
|
53
|
+
]]></value>
|
|
54
|
+
</property>
|
|
55
|
+
</properties>
|
|
56
|
+
</rule>
|
|
57
|
+
|
|
58
|
+
<rule name="FieldRequiresDescription" language="xml"
|
|
59
|
+
message="Custom field must have a non-empty description"
|
|
60
|
+
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule">
|
|
61
|
+
<priority>3</priority>
|
|
62
|
+
<properties>
|
|
63
|
+
<property name="xpath">
|
|
64
|
+
<value><![CDATA[
|
|
65
|
+
//*[local-name()='CustomField'][not(*[local-name()='description']) or *[local-name()='description'][not(@Text)]]
|
|
66
|
+
]]></value>
|
|
67
|
+
</property>
|
|
68
|
+
</properties>
|
|
69
|
+
</rule>
|
|
70
|
+
|
|
71
|
+
<rule name="MinimumApiVersion" language="xml"
|
|
72
|
+
message="API version must be 60.0 or higher"
|
|
73
|
+
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule">
|
|
74
|
+
<priority>3</priority>
|
|
75
|
+
<properties>
|
|
76
|
+
<property name="xpath">
|
|
77
|
+
<value><![CDATA[
|
|
78
|
+
//*[local-name()='apiVersion']/*[number(@Text) < 60]
|
|
79
|
+
]]></value>
|
|
80
|
+
</property>
|
|
81
|
+
</properties>
|
|
82
|
+
</rule>
|
|
83
|
+
</ruleset>
|
|
84
|
+
```
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Regex Rule Examples
|
|
2
|
+
|
|
3
|
+
Real-world custom regex rules solving problems from the Code Analyzer community.
|
|
4
|
+
|
|
5
|
+
## Example 1: Ban Hardcoded Salesforce IDs
|
|
6
|
+
|
|
7
|
+
**Problem:** Developers hardcode record IDs that differ between orgs.
|
|
8
|
+
(GitHub issue #738 — community request for detecting bad patterns)
|
|
9
|
+
|
|
10
|
+
```yaml
|
|
11
|
+
engines:
|
|
12
|
+
regex:
|
|
13
|
+
custom_rules:
|
|
14
|
+
NoHardcodedSalesforceIds:
|
|
15
|
+
regex: "/['\"](?<target>0[a-zA-Z0-9]{14}(?:[a-zA-Z0-9]{3})?)['\"]/g"
|
|
16
|
+
description: "Detects hardcoded 15 or 18 character Salesforce record IDs"
|
|
17
|
+
violation_message: "Replace hardcoded ID with Custom Label, Custom Metadata, or Custom Setting"
|
|
18
|
+
severity: 2
|
|
19
|
+
tags: ["Custom", "Security"]
|
|
20
|
+
file_extensions: [".cls", ".trigger"]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Why this pattern:**
|
|
24
|
+
- Salesforce IDs are exactly **15 or 18 characters** (never 16 or 17)
|
|
25
|
+
- They always **start with `0`** (the key prefix)
|
|
26
|
+
- `0[a-zA-Z0-9]{14}` matches 15-char IDs (0 + 14 more)
|
|
27
|
+
- `(?:[a-zA-Z0-9]{3})?` optionally matches the 3-char case-safe suffix (making 18-char)
|
|
28
|
+
- `(?<target>...)` narrows the violation highlight to just the ID, not the surrounding quotes
|
|
29
|
+
- ⚠️ Do NOT use `{15,18}` — this also matches 16/17 char strings and false-positives on normal words like `'BusinessAccount'` or `'RecordTypeInfos'`
|
|
30
|
+
|
|
31
|
+
**Note on `regex_ignore`:** This field works **per-line**, not per-file. Adding `/@isTest/` only skips lines that literally contain `@isTest` — it does NOT exclude entire test classes. To exclude test files entirely, use `ignores.files` in `code-analyzer.yml` with a glob like `**/*Test.cls`.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Example 2: Flag TODO/FIXME Before Merge
|
|
36
|
+
|
|
37
|
+
**Problem:** Developers leave TODOs that never get resolved.
|
|
38
|
+
|
|
39
|
+
```yaml
|
|
40
|
+
engines:
|
|
41
|
+
regex:
|
|
42
|
+
custom_rules:
|
|
43
|
+
NoUnresolvedTodos:
|
|
44
|
+
regex: "/(?:TODO|FIXME|HACK|XXX)\\b/gi"
|
|
45
|
+
description: "Flags unresolved TODO/FIXME comments"
|
|
46
|
+
violation_message: "Resolve this TODO/FIXME before merging to main"
|
|
47
|
+
severity: 4
|
|
48
|
+
tags: ["Custom", "BestPractices"]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Example 3: Enforce WITH USER_MODE on SOQL
|
|
54
|
+
|
|
55
|
+
**Problem:** SOQL queries without FLS enforcement are a security risk.
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
engines:
|
|
59
|
+
regex:
|
|
60
|
+
custom_rules:
|
|
61
|
+
RequireUserModeOnSoql:
|
|
62
|
+
regex: "/\\[\\s*SELECT(?![^\\]]*WITH\\s+(?:USER_MODE|SECURITY_ENFORCED))[^\\]]*\\]/gi"
|
|
63
|
+
description: "SOQL queries must use WITH USER_MODE or WITH SECURITY_ENFORCED"
|
|
64
|
+
violation_message: "Add WITH USER_MODE to this SOQL query for FLS enforcement"
|
|
65
|
+
severity: 2
|
|
66
|
+
tags: ["Custom", "Security"]
|
|
67
|
+
file_extensions: [".cls", ".trigger"]
|
|
68
|
+
regex_ignore: "/@isTest|@IsTest|@testSetup|@TestSetup/"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Example 4: Ban @SuppressWarnings and NOPMD
|
|
74
|
+
|
|
75
|
+
**Problem:** Teams want to prevent suppression of violations.
|
|
76
|
+
(GitHub issue #1972 — real user request)
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
engines:
|
|
80
|
+
regex:
|
|
81
|
+
custom_rules:
|
|
82
|
+
ProhibitSuppressWarnings:
|
|
83
|
+
regex: "/@SuppressWarnings\\([^)]*\\)|\\/\\/\\s*NOPMD/gi"
|
|
84
|
+
description: "Prohibits suppression of code analysis warnings"
|
|
85
|
+
violation_message: "Fix the underlying issue instead of suppressing warnings"
|
|
86
|
+
severity: 2
|
|
87
|
+
tags: ["Custom", "BestPractices"]
|
|
88
|
+
file_extensions: [".cls", ".trigger"]
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Example 5: Detect Old API Versions in Metadata
|
|
94
|
+
|
|
95
|
+
**Problem:** Metadata files using API versions more than 2 years old.
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
engines:
|
|
99
|
+
regex:
|
|
100
|
+
custom_rules:
|
|
101
|
+
NoOldApiVersions:
|
|
102
|
+
regex: "/<apiVersion>(4[0-9]|5[0-5])\\.0<\\/apiVersion>/g"
|
|
103
|
+
description: "Detects metadata files using API version 55.0 or below"
|
|
104
|
+
violation_message: "Update API version to 60.0 or higher"
|
|
105
|
+
severity: 3
|
|
106
|
+
tags: ["Custom", "BestPractices"]
|
|
107
|
+
file_extensions: [".xml"]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Example 6: Enforce Test Class Naming Convention
|
|
113
|
+
|
|
114
|
+
**Problem:** Test classes should end with `_TEST` or `Test`.
|
|
115
|
+
|
|
116
|
+
```yaml
|
|
117
|
+
engines:
|
|
118
|
+
regex:
|
|
119
|
+
custom_rules:
|
|
120
|
+
TestClassNaming:
|
|
121
|
+
regex: "/@(?:isTest|IsTest)(?:\\([^)]*\\))?\\s*(?:public|private)\\s+class\\s+(?!.*(?:_TEST|Test)\\b)\\w+/g"
|
|
122
|
+
description: "Test classes must end with _TEST or Test suffix"
|
|
123
|
+
violation_message: "Rename this test class to end with _TEST or Test (e.g., MyServiceTest)"
|
|
124
|
+
severity: 3
|
|
125
|
+
tags: ["Custom", "CodeStyle"]
|
|
126
|
+
file_extensions: [".cls"]
|
|
127
|
+
```
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# XPath Rule Examples
|
|
2
|
+
|
|
3
|
+
Real-world custom PMD/XPath rules for Apex, derived from community requests and common enforcement needs.
|
|
4
|
+
|
|
5
|
+
## Example 1: Ban System.debug in Production Code
|
|
6
|
+
|
|
7
|
+
**Problem:** Debug statements clutter logs and expose sensitive data.
|
|
8
|
+
|
|
9
|
+
**Sample violating code:**
|
|
10
|
+
```apex
|
|
11
|
+
public class MyService {
|
|
12
|
+
public void doWork() {
|
|
13
|
+
System.debug('Sensitive: ' + record.SSN__c);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**AST nodes (from ast-dump):**
|
|
19
|
+
```xml
|
|
20
|
+
<MethodCallExpression FullMethodName='System.debug' InputParametersSize='1' ...>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**XPath:**
|
|
24
|
+
```xpath
|
|
25
|
+
//MethodCallExpression[@FullMethodName='System.debug']
|
|
26
|
+
[not(ancestor::UserClass[ModifierNode[@Test = true()]])]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**PMD ruleset:**
|
|
30
|
+
```xml
|
|
31
|
+
<rule name="NoSystemDebugInProduction" language="apex"
|
|
32
|
+
message="System.debug statements are not allowed in production code"
|
|
33
|
+
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule">
|
|
34
|
+
<priority>3</priority>
|
|
35
|
+
<properties>
|
|
36
|
+
<property name="xpath">
|
|
37
|
+
<value>//MethodCallExpression[@FullMethodName='System.debug'][not(ancestor::UserClass[ModifierNode[@Test = true()]])]</value>
|
|
38
|
+
</property>
|
|
39
|
+
</properties>
|
|
40
|
+
</rule>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Example 2: SOQL Query Inside a Loop
|
|
46
|
+
|
|
47
|
+
**Problem:** Governor limit risk — N+1 queries.
|
|
48
|
+
|
|
49
|
+
**Sample violating code:**
|
|
50
|
+
```apex
|
|
51
|
+
public class AccountProcessor {
|
|
52
|
+
public void process(List<Account> accounts) {
|
|
53
|
+
for (Account acc : accounts) {
|
|
54
|
+
List<Contact> contacts = [SELECT Id FROM Contact WHERE AccountId = :acc.Id];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**AST nodes:**
|
|
61
|
+
```xml
|
|
62
|
+
<ForEachStatement>
|
|
63
|
+
...
|
|
64
|
+
<BlockStatement>
|
|
65
|
+
<VariableDeclarationStatements>
|
|
66
|
+
<VariableDeclaration>
|
|
67
|
+
<SoqlExpression Query='SELECT Id FROM Contact...' />
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**XPath:**
|
|
71
|
+
```xpath
|
|
72
|
+
//ForEachStatement/BlockStatement//SoqlExpression
|
|
73
|
+
|
|
|
74
|
+
//ForLoopStatement/BlockStatement//SoqlExpression
|
|
75
|
+
|
|
|
76
|
+
//WhileLoopStatement/BlockStatement//SoqlExpression
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
> ⚠️ **Why `/BlockStatement//`?** ForEachStatement has the iterable SOQL as a direct child alongside BlockStatement. Without scoping to `/BlockStatement//`, the XPath also matches `for (Contact c : [SELECT...])` — a valid Apex idiom that is NOT a governor limit risk.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Example 3: Enforce @IsTest(testFor) Annotation
|
|
84
|
+
|
|
85
|
+
**Problem:** Test classes should specify which class they test for traceability.
|
|
86
|
+
(GitHub issue #2008 — real community request)
|
|
87
|
+
|
|
88
|
+
**Sample violating code:**
|
|
89
|
+
```apex
|
|
90
|
+
@IsTest
|
|
91
|
+
public class MyServiceTest {
|
|
92
|
+
// Missing testFor parameter
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**AST nodes:**
|
|
97
|
+
```xml
|
|
98
|
+
<UserClass Image='MyServiceTest'>
|
|
99
|
+
<ModifierNode Test='true'>
|
|
100
|
+
<Annotation Image='IsTest'>
|
|
101
|
+
<!-- No AnnotationParameter with Name='testFor' -->
|
|
102
|
+
</Annotation>
|
|
103
|
+
</ModifierNode>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**XPath:**
|
|
107
|
+
```xpath
|
|
108
|
+
/ApexFile/UserClass/ModifierNode/Annotation[
|
|
109
|
+
@Image='IsTest'
|
|
110
|
+
and count(AnnotationParameter[@Name='testFor']) = 0
|
|
111
|
+
]
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Example 4: DML Operations Without Try-Catch
|
|
117
|
+
|
|
118
|
+
**Problem:** Unhandled DML exceptions cause runtime failures.
|
|
119
|
+
(GitHub issue #738 — user requested "detect missing try-catch")
|
|
120
|
+
|
|
121
|
+
**Sample violating code:**
|
|
122
|
+
```apex
|
|
123
|
+
public class AccountService {
|
|
124
|
+
public void createAccount(String name) {
|
|
125
|
+
Account acc = new Account(Name = name);
|
|
126
|
+
insert acc; // No try-catch!
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**AST nodes:**
|
|
132
|
+
```xml
|
|
133
|
+
<DmlInsertStatement>
|
|
134
|
+
<VariableExpression Image='acc' />
|
|
135
|
+
</DmlInsertStatement>
|
|
136
|
+
<!-- No TryCatchFinallyBlockStatement ancestor -->
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**XPath:**
|
|
140
|
+
```xpath
|
|
141
|
+
//DmlInsertStatement[not(ancestor::TryCatchFinallyBlockStatement)]
|
|
142
|
+
|
|
|
143
|
+
//DmlUpdateStatement[not(ancestor::TryCatchFinallyBlockStatement)]
|
|
144
|
+
|
|
|
145
|
+
//DmlDeleteStatement[not(ancestor::TryCatchFinallyBlockStatement)]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Example 5: Nested If Statements (Max Depth 3)
|
|
151
|
+
|
|
152
|
+
**Problem:** Deep nesting reduces readability and maintainability.
|
|
153
|
+
|
|
154
|
+
**Sample violating code:**
|
|
155
|
+
```apex
|
|
156
|
+
public class ComplexLogic {
|
|
157
|
+
public void process(Integer a, Integer b, Integer c, Integer d) {
|
|
158
|
+
if (a > 0) {
|
|
159
|
+
if (b > 0) {
|
|
160
|
+
if (c > 0) {
|
|
161
|
+
if (d > 0) { // 4th level — violation!
|
|
162
|
+
doWork();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**XPath (flags depth 4+):**
|
|
172
|
+
```xpath
|
|
173
|
+
//IfBlockStatement[
|
|
174
|
+
ancestor::IfBlockStatement[
|
|
175
|
+
ancestor::IfBlockStatement[
|
|
176
|
+
ancestor::IfBlockStatement
|
|
177
|
+
]
|
|
178
|
+
]
|
|
179
|
+
]
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Example 6: Class Without Explicit Sharing Declaration
|
|
185
|
+
|
|
186
|
+
**Problem:** Classes without sharing default to "without sharing" — security risk.
|
|
187
|
+
|
|
188
|
+
**Sample violating code:**
|
|
189
|
+
```apex
|
|
190
|
+
public class UnsafeService { // No "with sharing" or "without sharing"
|
|
191
|
+
public List<Account> getAccounts() {
|
|
192
|
+
return [SELECT Id FROM Account];
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**AST nodes:**
|
|
198
|
+
```xml
|
|
199
|
+
<UserClass Image='UnsafeService'>
|
|
200
|
+
<ModifierNode WithSharing='false' WithoutSharing='false' InheritedSharing='false' ...>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**XPath:**
|
|
204
|
+
```xpath
|
|
205
|
+
//UserClass[
|
|
206
|
+
ModifierNode[
|
|
207
|
+
@WithSharing = false()
|
|
208
|
+
and @WithoutSharing = false()
|
|
209
|
+
and @InheritedSharing = false()
|
|
210
|
+
]
|
|
211
|
+
and not(ModifierNode[@Test = true()])
|
|
212
|
+
]
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## How to Create These
|
|
218
|
+
|
|
219
|
+
For each example above, the creation process was:
|
|
220
|
+
|
|
221
|
+
1. Write the sample violating code (5-10 lines)
|
|
222
|
+
2. Run: `sf code-analyzer ast-dump --file sample.cls`
|
|
223
|
+
3. Find the relevant node in the XML output
|
|
224
|
+
4. Write XPath using the exact node names and attributes
|
|
225
|
+
5. Create the ruleset XML using the template
|
|
226
|
+
6. Validate: `sf code-analyzer rules --rule-selector pmd:RuleName`
|
|
227
|
+
7. Test: `sf code-analyzer run --rule-selector pmd:RuleName --target sample.cls`
|