agent-docs 1.1.0 → 1.3.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/PLAN.md +10 -10
- package/README.md +4 -0
- package/docs/A4DWORKFLOWS.md +121 -0
- package/docs/LIGHTNINGBASECOMPONENTS.md +328 -0
- package/docs/LWCHTMLTEMPLATES.md +314 -0
- package/docs/PMD.md +265 -761
- package/docs/PRETTIER.md +1 -39
- package/docs/XPATH31.md +0 -5
- package/package.json +31 -32
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# LWC HTML Templates
|
|
2
|
+
|
|
3
|
+
> **Version**: 1.0.0
|
|
4
|
+
|
|
5
|
+
## File Structure
|
|
6
|
+
|
|
7
|
+
- Location: `lwc/<ComponentName>/<ComponentName>.html`
|
|
8
|
+
- Additional HTML files allowed for multiple template rendering (advanced)
|
|
9
|
+
- Leverage virtual DOM; avoid manual DOM manipulation in JavaScript
|
|
10
|
+
|
|
11
|
+
## Template Structure
|
|
12
|
+
|
|
13
|
+
- **Root element:** `<template>` (renders as `<namespace-component-name>`)
|
|
14
|
+
- **Nested `<template>` tags:** required for directives; only allowed attributes:
|
|
15
|
+
- `for:each`, `iterator:iteratorname`, `lwc:if`, `lwc:else`, `lwc:elseif`, `if:true|false`
|
|
16
|
+
- No other directives or HTML attributes (e.g., no `class` on nested `<template>`)
|
|
17
|
+
- **No inline `<style>` or `<script>` tags** — use separate CSS/JS files
|
|
18
|
+
- Follow Lightning Design System patterns and accessibility guidelines
|
|
19
|
+
|
|
20
|
+
## Data Binding & Expressions
|
|
21
|
+
|
|
22
|
+
| Syntax | Usage |
|
|
23
|
+
|--------|-------|
|
|
24
|
+
| `{property}` | Bind data (no spaces around property) |
|
|
25
|
+
| `{data.name}` | Dot notation supported |
|
|
26
|
+
| `{!property}` | Two-way binding (form inputs) |
|
|
27
|
+
| `{handlerMethod}` | Event handler binding |
|
|
28
|
+
|
|
29
|
+
### Allowed Expression Syntax
|
|
30
|
+
|
|
31
|
+
The `{expression}` binding syntax **only** supports:
|
|
32
|
+
|
|
33
|
+
- **Simple property references:** `{myProperty}`
|
|
34
|
+
- **Dot notation paths:** `{contact.name}`, `{account.owner.email}`
|
|
35
|
+
- **Method references for events:** `onclick={handleClick}`
|
|
36
|
+
|
|
37
|
+
**That's it.** No operators, no function calls, no array indexing, no ternaries.
|
|
38
|
+
|
|
39
|
+
### ❌ What's NOT Allowed (Common AI Agent Mistakes)
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<!-- ❌ Logical operators -->
|
|
43
|
+
{isReadOnly || isLoading}
|
|
44
|
+
{isActive && isVisible}
|
|
45
|
+
|
|
46
|
+
<!-- ❌ Negation operator -->
|
|
47
|
+
{!isDisabled}
|
|
48
|
+
|
|
49
|
+
<!-- ❌ Ternary expressions -->
|
|
50
|
+
{isActive ? 'active' : 'inactive'}
|
|
51
|
+
|
|
52
|
+
<!-- ❌ Arithmetic -->
|
|
53
|
+
{count + 1}
|
|
54
|
+
{price * quantity}
|
|
55
|
+
|
|
56
|
+
<!-- ❌ Array indexing -->
|
|
57
|
+
{items[0].name}
|
|
58
|
+
{person[2].name['John']}
|
|
59
|
+
|
|
60
|
+
<!-- ❌ Function calls in templates -->
|
|
61
|
+
{formatDate(startDate)}
|
|
62
|
+
{calculateTotal()}
|
|
63
|
+
|
|
64
|
+
<!-- ❌ String concatenation -->
|
|
65
|
+
{'Hello ' + name}
|
|
66
|
+
{`Item: ${itemName}`}
|
|
67
|
+
|
|
68
|
+
<!-- ❌ Comparisons -->
|
|
69
|
+
{count > 0}
|
|
70
|
+
{status === 'active'}
|
|
71
|
+
|
|
72
|
+
<!-- ❌ Nullish coalescing / optional chaining in binding -->
|
|
73
|
+
{user?.name}
|
|
74
|
+
{value ?? 'default'}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### ✅ The Solution: Use JavaScript Getters
|
|
78
|
+
|
|
79
|
+
All computed logic **must** be moved to getters in the JavaScript class:
|
|
80
|
+
|
|
81
|
+
**JavaScript (myComponent.js):**
|
|
82
|
+
```javascript
|
|
83
|
+
import { LightningElement, api, track } from 'lwc';
|
|
84
|
+
|
|
85
|
+
export default class MyComponent extends LightningElement {
|
|
86
|
+
@api isReadOnly = false;
|
|
87
|
+
@api isLoading = false;
|
|
88
|
+
@track items = [];
|
|
89
|
+
|
|
90
|
+
// ✅ Logical operators → getter
|
|
91
|
+
get isDisabled() {
|
|
92
|
+
return this.isReadOnly || this.isLoading;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ✅ Negation → getter
|
|
96
|
+
get isEnabled() {
|
|
97
|
+
return !this.isDisabled;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ✅ Ternary → getter
|
|
101
|
+
get buttonLabel() {
|
|
102
|
+
return this.isLoading ? 'Loading...' : 'Submit';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ✅ Arithmetic → getter
|
|
106
|
+
get itemCountPlusOne() {
|
|
107
|
+
return this.count + 1;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ✅ Array indexing → getter
|
|
111
|
+
get firstItemName() {
|
|
112
|
+
return this.items[0]?.name || '';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ✅ String formatting → getter
|
|
116
|
+
get formattedCount() {
|
|
117
|
+
return `${this.count} items`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ✅ Comparisons for conditional rendering → getter
|
|
121
|
+
get hasItems() {
|
|
122
|
+
return this.items.length > 0;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ✅ Complex class computation → getter
|
|
126
|
+
get containerClass() {
|
|
127
|
+
return {
|
|
128
|
+
'slds-box': true,
|
|
129
|
+
'slds-theme_shade': this.isActive,
|
|
130
|
+
'slds-hide': !this.isVisible
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**HTML (myComponent.html):**
|
|
137
|
+
```html
|
|
138
|
+
<template>
|
|
139
|
+
<template lwc:if={hasItems}>
|
|
140
|
+
<div class={containerClass}>
|
|
141
|
+
<p>{formattedCount}</p>
|
|
142
|
+
<p>First item: {firstItemName}</p>
|
|
143
|
+
</div>
|
|
144
|
+
</template>
|
|
145
|
+
|
|
146
|
+
<lightning-button
|
|
147
|
+
label={buttonLabel}
|
|
148
|
+
disabled={isDisabled}
|
|
149
|
+
onclick={handleClick}>
|
|
150
|
+
</lightning-button>
|
|
151
|
+
</template>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Why This Design?
|
|
155
|
+
|
|
156
|
+
Salesforce made this intentional choice for:
|
|
157
|
+
|
|
158
|
+
| Reason | Explanation |
|
|
159
|
+
|--------|-------------|
|
|
160
|
+
| **Performance** | Simple property lookups are fast; no runtime expression parsing/evaluation |
|
|
161
|
+
| **Security** | No risk of template injection or expression-based exploits |
|
|
162
|
+
| **Predictability** | Reactivity is straightforward—change a property, component re-renders |
|
|
163
|
+
| **Testability** | All logic lives in unit-testable JavaScript, not scattered in templates |
|
|
164
|
+
| **Debugging** | Stack traces point to JS files, not opaque template expressions |
|
|
165
|
+
|
|
166
|
+
### AI Agent Rule Summary
|
|
167
|
+
|
|
168
|
+
> **LWC Template Expression Rule:** The `{...}` binding syntax accepts ONLY property names and dot-notation paths. Any logic requiring operators (`||`, `&&`, `?:`, `+`, `>`, `===`, etc.), function calls, array indexing, or string interpolation MUST be implemented as a getter in the JavaScript class.
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
Template binding: {propertyName} or {object.nested.property}
|
|
172
|
+
Computed logic: get computedProperty() { return /* any JS expression */; }
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Conditional Rendering
|
|
176
|
+
|
|
177
|
+
Use `lwc:if`, `lwc:elseif`, `lwc:else` directives (prefer over multiple templates for simple conditions):
|
|
178
|
+
|
|
179
|
+
```html
|
|
180
|
+
<template lwc:if={condition}>...</template>
|
|
181
|
+
<template lwc:elseif={otherCondition}>...</template>
|
|
182
|
+
<template lwc:else>...</template>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Note:** The condition must be a simple property reference or getter—not an expression:
|
|
186
|
+
|
|
187
|
+
```html
|
|
188
|
+
<!-- ❌ Invalid -->
|
|
189
|
+
<template lwc:if={items.length > 0}>
|
|
190
|
+
|
|
191
|
+
<!-- ✅ Valid — use a getter -->
|
|
192
|
+
<template lwc:if={hasItems}>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## List Rendering
|
|
196
|
+
|
|
197
|
+
### for:each
|
|
198
|
+
```html
|
|
199
|
+
<template for:each={array} for:item="item">
|
|
200
|
+
<div key={item.uniqueId}>{item.property}</div>
|
|
201
|
+
</template>
|
|
202
|
+
```
|
|
203
|
+
- `key` required: string/number, **not** index or object
|
|
204
|
+
- Access current item via `for:item="itemName"` → `{itemName.property}`
|
|
205
|
+
|
|
206
|
+
### iterator
|
|
207
|
+
```html
|
|
208
|
+
<template iterator:it={array}>
|
|
209
|
+
<div key={it.value.uniqueId}>{it.value.property}</div>
|
|
210
|
+
</template>
|
|
211
|
+
```
|
|
212
|
+
- Iterator name must be lowercase
|
|
213
|
+
- Properties: `{it.value.property}`, `{it.index}`, `{it.first}`, `{it.last}`
|
|
214
|
+
- Combine with `lwc:if` for first/last styling: `lwc:if={it.first}`
|
|
215
|
+
|
|
216
|
+
## Multiple Template Rendering (Advanced)
|
|
217
|
+
|
|
218
|
+
- Import templates: `import templateOne from "./templateOne.html"`
|
|
219
|
+
- Override `render()` to return template based on state
|
|
220
|
+
- CSS must match template filename: `templateTwo.html` → `templateTwo.css`
|
|
221
|
+
- Default: `componentName.html` when no `render()` override
|
|
222
|
+
- **Prefer `lwc:if` for simple variations; use multiple templates for significantly different layouts**
|
|
223
|
+
|
|
224
|
+
## Class Object Binding (LWC API v62.0+)
|
|
225
|
+
|
|
226
|
+
Bind dynamic classes using arrays or objects instead of string concatenation:
|
|
227
|
+
|
|
228
|
+
| Input | Output |
|
|
229
|
+
|-------|--------|
|
|
230
|
+
| `["highlight", "yellow"]` | `class="highlight yellow"` |
|
|
231
|
+
| `{highlight: true, hidden: false}` | `class="highlight"` |
|
|
232
|
+
|
|
233
|
+
- Booleans, numbers, functions render as empty string (use `String(value)` if needed)
|
|
234
|
+
- Use getters to compute complex class combinations
|
|
235
|
+
|
|
236
|
+
**Example with getter:**
|
|
237
|
+
```javascript
|
|
238
|
+
get cardClasses() {
|
|
239
|
+
return {
|
|
240
|
+
'slds-card': true,
|
|
241
|
+
'slds-card_boundary': this.hasBorder,
|
|
242
|
+
'custom-highlight': this.isHighlighted
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
```html
|
|
248
|
+
<div class={cardClasses}>...</div>
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Inline Style Binding
|
|
252
|
+
|
|
253
|
+
- Syntax: `style={computedStyles}`
|
|
254
|
+
- Getter returns semi-colon separated properties: `width: 50%; font-size: 20px`
|
|
255
|
+
- Use kebab-case CSS properties (`font-size`, not `fontSize`)
|
|
256
|
+
- **Prefer CSS classes over inline styles**; use inline for dynamic/computed values only
|
|
257
|
+
|
|
258
|
+
**Example:**
|
|
259
|
+
```javascript
|
|
260
|
+
get progressBarStyle() {
|
|
261
|
+
return `width: ${this.progressPercent}%; background-color: ${this.barColor}`;
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
```html
|
|
266
|
+
<div class="progress-bar" style={progressBarStyle}></div>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Event Handling
|
|
270
|
+
|
|
271
|
+
- Bind handlers via method reference: `onclick={handleClick}`
|
|
272
|
+
- No inline functions in templates
|
|
273
|
+
- Access values via `event.target.value`
|
|
274
|
+
- Custom events: extend `LightningElement`, use proper event naming
|
|
275
|
+
|
|
276
|
+
```html
|
|
277
|
+
<!-- ❌ Invalid — no inline functions -->
|
|
278
|
+
<button onclick={() => this.handleClick()}>
|
|
279
|
+
|
|
280
|
+
<!-- ✅ Valid — method reference -->
|
|
281
|
+
<button onclick={handleClick}>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Accessibility
|
|
285
|
+
|
|
286
|
+
- Include proper ARIA attributes
|
|
287
|
+
- Use semantic HTML elements
|
|
288
|
+
- Ensure keyboard navigation for interactive elements
|
|
289
|
+
|
|
290
|
+
## Performance
|
|
291
|
+
|
|
292
|
+
- Minimize DOM manipulation
|
|
293
|
+
- Use lazy loading / pagination for large lists
|
|
294
|
+
- Avoid unnecessary rerenders by optimizing data binding
|
|
295
|
+
- Getters are re-evaluated on every render—keep them lightweight or cache expensive computations
|
|
296
|
+
|
|
297
|
+
## Validation Checklist
|
|
298
|
+
|
|
299
|
+
- [ ] File path: `lwc/<ComponentName>/<ComponentName>.html`
|
|
300
|
+
- [ ] Root element is `<template>`
|
|
301
|
+
- [ ] Nested `<template>` tags include only allowed directives
|
|
302
|
+
- [ ] Nested `<template>` tags have no other attributes (e.g., no `class`)
|
|
303
|
+
- [ ] No inline `<style>` or `<script>` tags
|
|
304
|
+
- [ ] No manual DOM manipulation in JS
|
|
305
|
+
- [ ] Data binding: `{property}` syntax, no spaces
|
|
306
|
+
- [ ] **No computed expressions in templates** (no operators, function calls, array indexing)
|
|
307
|
+
- [ ] **All computed logic implemented as getters in JS class**
|
|
308
|
+
- [ ] `for:each`: has `for:item` and unique `key` (string/number)
|
|
309
|
+
- [ ] `iterator`: lowercase name, unique `key={it.value.uniqueId}`
|
|
310
|
+
- [ ] Multiple templates: proper imports, `render()` override, matching CSS filenames
|
|
311
|
+
- [ ] Class binding follows v62.0+ semantics (arrays/objects via getters)
|
|
312
|
+
- [ ] Inline styles: `style={getter}`, kebab-case properties
|
|
313
|
+
- [ ] Valid HTML syntax (use Salesforce Extensions Pack for validation)
|
|
314
|
+
- [ ] Follows accessibility and performance best practices
|