lwc-convert 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.
- package/LICENSE +21 -0
- package/README.md +719 -0
- package/dist/cli/commands/aura.d.ts +6 -0
- package/dist/cli/commands/aura.d.ts.map +1 -0
- package/dist/cli/commands/aura.js +225 -0
- package/dist/cli/commands/aura.js.map +1 -0
- package/dist/cli/commands/vf.d.ts +6 -0
- package/dist/cli/commands/vf.d.ts.map +1 -0
- package/dist/cli/commands/vf.js +218 -0
- package/dist/cli/commands/vf.js.map +1 -0
- package/dist/cli/interactive.d.ts +20 -0
- package/dist/cli/interactive.d.ts.map +1 -0
- package/dist/cli/interactive.js +577 -0
- package/dist/cli/interactive.js.map +1 -0
- package/dist/cli/options.d.ts +21 -0
- package/dist/cli/options.d.ts.map +1 -0
- package/dist/cli/options.js +24 -0
- package/dist/cli/options.js.map +1 -0
- package/dist/generators/full-conversion.d.ts +41 -0
- package/dist/generators/full-conversion.d.ts.map +1 -0
- package/dist/generators/full-conversion.js +538 -0
- package/dist/generators/full-conversion.js.map +1 -0
- package/dist/generators/scaffolding.d.ts +40 -0
- package/dist/generators/scaffolding.d.ts.map +1 -0
- package/dist/generators/scaffolding.js +716 -0
- package/dist/generators/scaffolding.js.map +1 -0
- package/dist/generators/test-comparison.d.ts +47 -0
- package/dist/generators/test-comparison.d.ts.map +1 -0
- package/dist/generators/test-comparison.js +855 -0
- package/dist/generators/test-comparison.js.map +1 -0
- package/dist/generators/test-generator.d.ts +27 -0
- package/dist/generators/test-generator.d.ts.map +1 -0
- package/dist/generators/test-generator.js +385 -0
- package/dist/generators/test-generator.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +226 -0
- package/dist/index.js.map +1 -0
- package/dist/mappings/aura-to-lwc.json +321 -0
- package/dist/mappings/vf-to-lwc.json +354 -0
- package/dist/parsers/aura/controller-parser.d.ts +36 -0
- package/dist/parsers/aura/controller-parser.d.ts.map +1 -0
- package/dist/parsers/aura/controller-parser.js +269 -0
- package/dist/parsers/aura/controller-parser.js.map +1 -0
- package/dist/parsers/aura/helper-parser.d.ts +21 -0
- package/dist/parsers/aura/helper-parser.d.ts.map +1 -0
- package/dist/parsers/aura/helper-parser.js +173 -0
- package/dist/parsers/aura/helper-parser.js.map +1 -0
- package/dist/parsers/aura/markup-parser.d.ts +59 -0
- package/dist/parsers/aura/markup-parser.d.ts.map +1 -0
- package/dist/parsers/aura/markup-parser.js +279 -0
- package/dist/parsers/aura/markup-parser.js.map +1 -0
- package/dist/parsers/aura/style-parser.d.ts +37 -0
- package/dist/parsers/aura/style-parser.d.ts.map +1 -0
- package/dist/parsers/aura/style-parser.js +151 -0
- package/dist/parsers/aura/style-parser.js.map +1 -0
- package/dist/parsers/vf/apex-parser.d.ts +51 -0
- package/dist/parsers/vf/apex-parser.d.ts.map +1 -0
- package/dist/parsers/vf/apex-parser.js +251 -0
- package/dist/parsers/vf/apex-parser.js.map +1 -0
- package/dist/parsers/vf/page-parser.d.ts +61 -0
- package/dist/parsers/vf/page-parser.d.ts.map +1 -0
- package/dist/parsers/vf/page-parser.js +403 -0
- package/dist/parsers/vf/page-parser.js.map +1 -0
- package/dist/transformers/aura-to-lwc/controller.d.ts +36 -0
- package/dist/transformers/aura-to-lwc/controller.d.ts.map +1 -0
- package/dist/transformers/aura-to-lwc/controller.js +372 -0
- package/dist/transformers/aura-to-lwc/controller.js.map +1 -0
- package/dist/transformers/aura-to-lwc/events.d.ts +47 -0
- package/dist/transformers/aura-to-lwc/events.d.ts.map +1 -0
- package/dist/transformers/aura-to-lwc/events.js +262 -0
- package/dist/transformers/aura-to-lwc/events.js.map +1 -0
- package/dist/transformers/aura-to-lwc/markup.d.ts +51 -0
- package/dist/transformers/aura-to-lwc/markup.d.ts.map +1 -0
- package/dist/transformers/aura-to-lwc/markup.js +465 -0
- package/dist/transformers/aura-to-lwc/markup.js.map +1 -0
- package/dist/transformers/vf-to-lwc/components.d.ts +40 -0
- package/dist/transformers/vf-to-lwc/components.d.ts.map +1 -0
- package/dist/transformers/vf-to-lwc/components.js +374 -0
- package/dist/transformers/vf-to-lwc/components.js.map +1 -0
- package/dist/transformers/vf-to-lwc/data-binding.d.ts +53 -0
- package/dist/transformers/vf-to-lwc/data-binding.d.ts.map +1 -0
- package/dist/transformers/vf-to-lwc/data-binding.js +660 -0
- package/dist/transformers/vf-to-lwc/data-binding.js.map +1 -0
- package/dist/transformers/vf-to-lwc/markup.d.ts +44 -0
- package/dist/transformers/vf-to-lwc/markup.d.ts.map +1 -0
- package/dist/transformers/vf-to-lwc/markup.js +816 -0
- package/dist/transformers/vf-to-lwc/markup.js.map +1 -0
- package/dist/utils/confidence-scorer.d.ts +100 -0
- package/dist/utils/confidence-scorer.d.ts.map +1 -0
- package/dist/utils/confidence-scorer.js +358 -0
- package/dist/utils/confidence-scorer.js.map +1 -0
- package/dist/utils/file-io.d.ts +62 -0
- package/dist/utils/file-io.d.ts.map +1 -0
- package/dist/utils/file-io.js +248 -0
- package/dist/utils/file-io.js.map +1 -0
- package/dist/utils/logger.d.ts +34 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +130 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/open-folder.d.ts +9 -0
- package/dist/utils/open-folder.d.ts.map +1 -0
- package/dist/utils/open-folder.js +76 -0
- package/dist/utils/open-folder.js.map +1 -0
- package/dist/utils/path-resolver.d.ts +29 -0
- package/dist/utils/path-resolver.d.ts.map +1 -0
- package/dist/utils/path-resolver.js +240 -0
- package/dist/utils/path-resolver.js.map +1 -0
- package/dist/utils/session-store.d.ts +158 -0
- package/dist/utils/session-store.d.ts.map +1 -0
- package/dist/utils/session-store.js +518 -0
- package/dist/utils/session-store.js.map +1 -0
- package/dist/utils/vf-controller-resolver.d.ts +36 -0
- package/dist/utils/vf-controller-resolver.d.ts.map +1 -0
- package/dist/utils/vf-controller-resolver.js +162 -0
- package/dist/utils/vf-controller-resolver.js.map +1 -0
- package/package.json +81 -0
package/README.md
ADDED
|
@@ -0,0 +1,719 @@
|
|
|
1
|
+
# 🔄 lwc-convert
|
|
2
|
+
|
|
3
|
+
> **A precision TypeScript CLI tool for converting Salesforce Aura components and Visualforce pages to Lightning Web Components (LWC)**
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="#-quick-start">Quick Start</a> •
|
|
7
|
+
<a href="#-features">Features</a> •
|
|
8
|
+
<a href="#-conversion-mappings">Mappings</a> •
|
|
9
|
+
<a href="#-cli-reference">CLI Reference</a> •
|
|
10
|
+
<a href="#-contributing">Contributing</a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
[](https://nodejs.org/)
|
|
16
|
+
[](https://www.typescriptlang.org/)
|
|
17
|
+
[](LICENSE)
|
|
18
|
+
[](https://github.com/Lastonedown86/lwc-convert/pulls)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 🎯 Overview
|
|
23
|
+
|
|
24
|
+
`lwc-convert` automates the migration of legacy Salesforce UI technologies to modern Lightning Web Components:
|
|
25
|
+
|
|
26
|
+
| Source Technology | Target | Confidence |
|
|
27
|
+
|-------------------|--------|------------|
|
|
28
|
+
| **Aura Components** | LWC | High |
|
|
29
|
+
| **Visualforce Pages** | LWC | Medium-High |
|
|
30
|
+
|
|
31
|
+
### What You Get
|
|
32
|
+
|
|
33
|
+
For each conversion, the tool generates a **complete LWC bundle**:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
myComponent/
|
|
37
|
+
├── myComponent.html # Converted template
|
|
38
|
+
├── myComponent.js # ES6 class with decorators
|
|
39
|
+
├── myComponent.css # Scoped styles
|
|
40
|
+
├── myComponent.js-meta.xml # Component configuration
|
|
41
|
+
└── CONVERSION_NOTES.md # Action items & guidance
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## ✨ Features
|
|
47
|
+
|
|
48
|
+
### 🎯 Single-Component Focus
|
|
49
|
+
Unlike batch tools that sacrifice accuracy, `lwc-convert` processes **one component at a time** for maximum precision and detailed error reporting.
|
|
50
|
+
|
|
51
|
+
### 📝 Two Output Modes
|
|
52
|
+
|
|
53
|
+
| Mode | Description | Best For |
|
|
54
|
+
|------|-------------|----------|
|
|
55
|
+
| **Scaffolding** (default) | Generates skeleton with `// TODO:` comments | Complex components requiring manual attention |
|
|
56
|
+
| **Full Conversion** (`--full`) | Complete transformation with `// REVIEW:` markers | Simple, standard components |
|
|
57
|
+
|
|
58
|
+
### 🔍 Smart Analysis
|
|
59
|
+
- Parses Aura markup, controllers, helpers, and styles
|
|
60
|
+
- Analyzes Apex controllers for VF pages
|
|
61
|
+
- Detects patterns and suggests modern equivalents
|
|
62
|
+
- Identifies potential issues upfront
|
|
63
|
+
|
|
64
|
+
### 📋 Conversion Notes
|
|
65
|
+
Every conversion includes a detailed markdown file with:
|
|
66
|
+
- ✅ Completed transformations
|
|
67
|
+
- ⚠️ Items needing manual attention
|
|
68
|
+
- 📖 Migration guidance and best practices
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 🚀 Quick Start
|
|
73
|
+
|
|
74
|
+
### Interactive Mode
|
|
75
|
+
|
|
76
|
+
Just run `lwc-convert` without arguments to launch the interactive TUI:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npx lwc-convert
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
You'll be guided through:
|
|
83
|
+
1. **Select conversion type** (Aura or Visualforce)
|
|
84
|
+
2. **Choose component** from auto-discovered list or enter path
|
|
85
|
+
3. **Configure options** (scaffolding/full, output dir, open folder)
|
|
86
|
+
4. **Confirm and convert!**
|
|
87
|
+
|
|
88
|
+
### Prerequisites
|
|
89
|
+
|
|
90
|
+
- **Node.js** 18.0 or higher
|
|
91
|
+
- **npm** 8.0 or higher
|
|
92
|
+
|
|
93
|
+
### Installation
|
|
94
|
+
|
|
95
|
+
**Via npm (recommended):**
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Run directly with npx (no install needed)
|
|
99
|
+
npx lwc-convert aura AccountCard
|
|
100
|
+
|
|
101
|
+
# Or install globally
|
|
102
|
+
npm install -g lwc-convert
|
|
103
|
+
lwc-convert aura AccountCard
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**From source (for development):**
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git clone https://github.com/Lastonedown86/lwc-convert.git
|
|
110
|
+
cd lwc-convert
|
|
111
|
+
npm install
|
|
112
|
+
npm run build
|
|
113
|
+
npm link
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Your First Conversion
|
|
117
|
+
|
|
118
|
+
**Convert an Aura Component:**
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# Just use the component name — the CLI searches automatically!
|
|
122
|
+
lwc-convert aura AccountCard
|
|
123
|
+
|
|
124
|
+
# Or use a full path
|
|
125
|
+
lwc-convert aura ./force-app/main/default/aura/AccountCard
|
|
126
|
+
|
|
127
|
+
# Full conversion mode
|
|
128
|
+
lwc-convert aura AccountCard --full
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Convert a Visualforce Page:**
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Just use the page name (with or without .page extension)
|
|
135
|
+
lwc-convert vf ContactList
|
|
136
|
+
|
|
137
|
+
# With Apex controller (also supports just the class name)
|
|
138
|
+
lwc-convert vf ContactList --controller ContactListController
|
|
139
|
+
|
|
140
|
+
# Or use full paths
|
|
141
|
+
lwc-convert vf ./pages/ContactList.page --controller ./classes/ContactListController.cls
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Preview Without Writing Files:**
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
lwc-convert aura MyComponent --dry-run --verbose
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
> **💡 Smart Path Resolution:** The CLI automatically searches common Salesforce project locations:
|
|
151
|
+
> - `force-app/main/default/aura/`, `src/aura/`, `aura/`
|
|
152
|
+
> - `force-app/main/default/pages/`, `src/pages/`, `pages/`
|
|
153
|
+
> - `force-app/main/default/classes/`, `src/classes/`, `classes/`
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 📖 CLI Reference
|
|
158
|
+
|
|
159
|
+
### Commands
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
lwc-convert aura <name-or-path> # Convert Aura component bundle
|
|
163
|
+
lwc-convert vf <name-or-path> # Convert Visualforce page
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Global Options
|
|
167
|
+
|
|
168
|
+
| Option | Description |
|
|
169
|
+
|--------|-------------|
|
|
170
|
+
| `-V, --version` | Display version |
|
|
171
|
+
| `-h, --help` | Show help |
|
|
172
|
+
|
|
173
|
+
### Aura Command Options
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
lwc-convert aura <bundle-path> [options]
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
| Option | Description | Default |
|
|
180
|
+
|--------|-------------|---------|
|
|
181
|
+
| `--full` | Full conversion instead of scaffolding | `false` |
|
|
182
|
+
| `-o, --output <dir>` | Output directory | `./lwc-output` |
|
|
183
|
+
| `--open` | Open output folder in file explorer | `false` |
|
|
184
|
+
| `--dry-run` | Preview without writing files | `false` |
|
|
185
|
+
| `--verbose` | Show detailed logs | `false` |
|
|
186
|
+
|
|
187
|
+
### VF Command Options
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
lwc-convert vf <page-path> [options]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
| Option | Description | Default |
|
|
194
|
+
|--------|-------------|---------|
|
|
195
|
+
| `--full` | Full conversion instead of scaffolding | `false` |
|
|
196
|
+
| `-o, --output <dir>` | Output directory | `./lwc-output` |
|
|
197
|
+
| `--controller <path>` | Apex controller for enhanced analysis | — |
|
|
198
|
+
| `--open` | Open output folder in file explorer | `false` |
|
|
199
|
+
| `--dry-run` | Preview without writing files | `false` |
|
|
200
|
+
| `--verbose` | Show detailed logs | `false` |
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 🔄 Output Modes
|
|
205
|
+
|
|
206
|
+
### Scaffolding Mode (Default)
|
|
207
|
+
|
|
208
|
+
Generates an LWC skeleton optimized for manual completion:
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
import { LightningElement, api } from 'lwc';
|
|
212
|
+
|
|
213
|
+
// TODO: Import Apex method - verify class and method name
|
|
214
|
+
// import getRecords from '@salesforce/apex/MyController.getRecords';
|
|
215
|
+
|
|
216
|
+
export default class MyComponent extends LightningElement {
|
|
217
|
+
// TODO: Verify if this should be @api (public) or private
|
|
218
|
+
@api recordId;
|
|
219
|
+
|
|
220
|
+
// Converted from aura:attribute "items"
|
|
221
|
+
items = [];
|
|
222
|
+
|
|
223
|
+
// TODO: Migrate logic from Aura init handler
|
|
224
|
+
connectedCallback() {
|
|
225
|
+
// Original init logic goes here
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// TODO: Implement - converted from controller.handleSave
|
|
229
|
+
handleSave(event) {
|
|
230
|
+
// Original: component.get("v.record"), then server call
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Full Conversion Mode (`--full`)
|
|
236
|
+
|
|
237
|
+
Attempts complete code transformation:
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
import { LightningElement, api, wire } from 'lwc';
|
|
241
|
+
import getRecords from '@salesforce/apex/MyController.getRecords';
|
|
242
|
+
|
|
243
|
+
export default class MyComponent extends LightningElement {
|
|
244
|
+
@api recordId;
|
|
245
|
+
items = [];
|
|
246
|
+
isLoading = false;
|
|
247
|
+
|
|
248
|
+
connectedCallback() {
|
|
249
|
+
this.loadRecords();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async loadRecords() {
|
|
253
|
+
this.isLoading = true;
|
|
254
|
+
try {
|
|
255
|
+
// REVIEW: Verify Apex method parameters
|
|
256
|
+
this.items = await getRecords({ recordId: this.recordId });
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.error('Error loading records:', error);
|
|
259
|
+
} finally {
|
|
260
|
+
this.isLoading = false;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
handleSave(event) {
|
|
265
|
+
// REVIEW: Complex logic converted - verify behavior
|
|
266
|
+
const record = { ...this.currentRecord };
|
|
267
|
+
// ... conversion continues
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## 📋 Conversion Mappings
|
|
275
|
+
|
|
276
|
+
### Aura to LWC
|
|
277
|
+
|
|
278
|
+
<details>
|
|
279
|
+
<summary><strong>🏷️ Component Tags</strong></summary>
|
|
280
|
+
|
|
281
|
+
| Aura | LWC |
|
|
282
|
+
|------|-----|
|
|
283
|
+
| `<aura:component>` | `<template>` |
|
|
284
|
+
| `<aura:if isTrue="{!v.show}">` | `<template if:true={show}>` |
|
|
285
|
+
| `<aura:if isFalse="{!v.hide}">` | `<template if:false={hide}>` |
|
|
286
|
+
| `<aura:iteration items="{!v.list}" var="item">` | `<template for:each={list} for:item="item">` |
|
|
287
|
+
| `<aura:set attribute="x">` | Named slots or JavaScript |
|
|
288
|
+
| `<aura:html tag="div">` | Direct HTML element |
|
|
289
|
+
|
|
290
|
+
</details>
|
|
291
|
+
|
|
292
|
+
<details>
|
|
293
|
+
<summary><strong>📝 Expressions</strong></summary>
|
|
294
|
+
|
|
295
|
+
| Aura | LWC |
|
|
296
|
+
|------|-----|
|
|
297
|
+
| `{!v.propertyName}` | `{propertyName}` |
|
|
298
|
+
| `{!v.object.field}` | `{object.field}` |
|
|
299
|
+
| `{!c.handleClick}` | `{handleClick}` |
|
|
300
|
+
| `{!globalId}` | `data-id` attribute |
|
|
301
|
+
| `{!$Label.ns.name}` | Import from `@salesforce/label` |
|
|
302
|
+
|
|
303
|
+
</details>
|
|
304
|
+
|
|
305
|
+
<details>
|
|
306
|
+
<summary><strong>🎛️ Attributes</strong></summary>
|
|
307
|
+
|
|
308
|
+
| Aura | LWC |
|
|
309
|
+
|------|-----|
|
|
310
|
+
| `<aura:attribute name="x" type="String"/>` | `@api x;` |
|
|
311
|
+
| `<aura:attribute access="private"/>` | Property without `@api` |
|
|
312
|
+
| `<aura:attribute default="value"/>` | `x = 'value';` |
|
|
313
|
+
| `aura:id="elementId"` | `data-id="elementId"` |
|
|
314
|
+
|
|
315
|
+
</details>
|
|
316
|
+
|
|
317
|
+
<details>
|
|
318
|
+
<summary><strong>⚡ JavaScript Patterns</strong></summary>
|
|
319
|
+
|
|
320
|
+
| Aura | LWC |
|
|
321
|
+
|------|-----|
|
|
322
|
+
| `component.get("v.name")` | `this.name` |
|
|
323
|
+
| `component.set("v.name", val)` | `this.name = val` |
|
|
324
|
+
| `component.find("auraId")` | `this.template.querySelector('[data-id="auraId"]')` |
|
|
325
|
+
| `helper.doSomething(cmp)` | `this.doSomething()` |
|
|
326
|
+
| `$A.enqueueAction(action)` | Imperative Apex call |
|
|
327
|
+
| `$A.getCallback(fn)` | Direct function call |
|
|
328
|
+
|
|
329
|
+
</details>
|
|
330
|
+
|
|
331
|
+
<details>
|
|
332
|
+
<summary><strong>🔄 Lifecycle Hooks</strong></summary>
|
|
333
|
+
|
|
334
|
+
| Aura Handler | LWC Lifecycle |
|
|
335
|
+
|--------------|---------------|
|
|
336
|
+
| `init` | `connectedCallback()` |
|
|
337
|
+
| `render` | `renderedCallback()` |
|
|
338
|
+
| `afterRender` | `renderedCallback()` |
|
|
339
|
+
| `unrender` | `disconnectedCallback()` |
|
|
340
|
+
| `destroy` | `disconnectedCallback()` |
|
|
341
|
+
|
|
342
|
+
</details>
|
|
343
|
+
|
|
344
|
+
<details>
|
|
345
|
+
<summary><strong>📡 Events</strong></summary>
|
|
346
|
+
|
|
347
|
+
| Aura | LWC |
|
|
348
|
+
|------|-----|
|
|
349
|
+
| `$A.get("e.c:myEvent")` | `new CustomEvent('myevent', {...})` |
|
|
350
|
+
| `event.fire()` | `this.dispatchEvent(event)` |
|
|
351
|
+
| `event.setParams({...})` | `{ detail: {...} }` in CustomEvent |
|
|
352
|
+
| `event.getParam("x")` | `event.detail.x` |
|
|
353
|
+
| `<aura:handler event="c:MyEvt" action="{!c.handle}"/>` | `onmyevent={handle}` |
|
|
354
|
+
| `<aura:registerEvent name="x"/>` | Document in JSDoc |
|
|
355
|
+
|
|
356
|
+
</details>
|
|
357
|
+
|
|
358
|
+
<details>
|
|
359
|
+
<summary><strong>⚡ Lightning Components</strong></summary>
|
|
360
|
+
|
|
361
|
+
| Aura | LWC |
|
|
362
|
+
|------|-----|
|
|
363
|
+
| `<lightning:button>` | `<lightning-button>` |
|
|
364
|
+
| `<lightning:input>` | `<lightning-input>` |
|
|
365
|
+
| `<lightning:card>` | `<lightning-card>` |
|
|
366
|
+
| `<lightning:datatable>` | `<lightning-datatable>` |
|
|
367
|
+
| `<lightning:recordEditForm>` | `<lightning-record-edit-form>` |
|
|
368
|
+
| `iconName="standard:account"` | `icon-name="standard:account"` |
|
|
369
|
+
|
|
370
|
+
</details>
|
|
371
|
+
|
|
372
|
+
<details>
|
|
373
|
+
<summary><strong>🛠️ Utility Functions</strong></summary>
|
|
374
|
+
|
|
375
|
+
| Aura | LWC |
|
|
376
|
+
|------|-----|
|
|
377
|
+
| `$A.util.isEmpty(x)` | `!x \|\| x.length === 0` |
|
|
378
|
+
| `$A.util.isUndefinedOrNull(x)` | `x === undefined \|\| x === null` |
|
|
379
|
+
| `$A.util.addClass(el, 'cls')` | `el.classList.add('cls')` |
|
|
380
|
+
| `$A.util.removeClass(el, 'cls')` | `el.classList.remove('cls')` |
|
|
381
|
+
| `$A.util.toggleClass(el, 'cls')` | `el.classList.toggle('cls')` |
|
|
382
|
+
|
|
383
|
+
</details>
|
|
384
|
+
|
|
385
|
+
### Visualforce to LWC
|
|
386
|
+
|
|
387
|
+
<details>
|
|
388
|
+
<summary><strong>📄 Page Structure</strong></summary>
|
|
389
|
+
|
|
390
|
+
| Visualforce | LWC |
|
|
391
|
+
|-------------|-----|
|
|
392
|
+
| `<apex:page>` | `<template>` |
|
|
393
|
+
| `<apex:form>` | `<lightning-record-edit-form>` or `<form>` |
|
|
394
|
+
| `<apex:pageBlock>` | `<lightning-card>` |
|
|
395
|
+
| `<apex:pageBlockSection>` | `<lightning-layout>` |
|
|
396
|
+
| `<apex:pageBlockButtons>` | SLDS button group |
|
|
397
|
+
|
|
398
|
+
</details>
|
|
399
|
+
|
|
400
|
+
<details>
|
|
401
|
+
<summary><strong>📝 Input Components</strong></summary>
|
|
402
|
+
|
|
403
|
+
| Visualforce | LWC |
|
|
404
|
+
|-------------|-----|
|
|
405
|
+
| `<apex:inputText>` | `<lightning-input type="text">` |
|
|
406
|
+
| `<apex:inputTextarea>` | `<lightning-textarea>` |
|
|
407
|
+
| `<apex:inputCheckbox>` | `<lightning-input type="checkbox">` |
|
|
408
|
+
| `<apex:inputField>` | `<lightning-input-field>` |
|
|
409
|
+
| `<apex:selectList>` | `<lightning-combobox>` |
|
|
410
|
+
| `<apex:selectRadio>` | `<lightning-radio-group>` |
|
|
411
|
+
|
|
412
|
+
</details>
|
|
413
|
+
|
|
414
|
+
<details>
|
|
415
|
+
<summary><strong>📊 Output Components</strong></summary>
|
|
416
|
+
|
|
417
|
+
| Visualforce | LWC |
|
|
418
|
+
|-------------|-----|
|
|
419
|
+
| `<apex:outputText>` | `{value}` or `<lightning-formatted-text>` |
|
|
420
|
+
| `<apex:outputField>` | `<lightning-output-field>` |
|
|
421
|
+
| `<apex:outputLabel>` | `<label>` |
|
|
422
|
+
| `<apex:outputLink>` | `<a>` or NavigationMixin |
|
|
423
|
+
|
|
424
|
+
</details>
|
|
425
|
+
|
|
426
|
+
<details>
|
|
427
|
+
<summary><strong>📋 Data Components</strong></summary>
|
|
428
|
+
|
|
429
|
+
| Visualforce | LWC |
|
|
430
|
+
|-------------|-----|
|
|
431
|
+
| `<apex:pageBlockTable>` | `<lightning-datatable>` |
|
|
432
|
+
| `<apex:dataTable>` | `<lightning-datatable>` |
|
|
433
|
+
| `<apex:repeat>` | `<template for:each>` |
|
|
434
|
+
| `<apex:dataList>` | `<template for:each>` with `<ul>` |
|
|
435
|
+
| `<apex:detail>` | `<lightning-record-form>` |
|
|
436
|
+
| `<apex:relatedList>` | `<lightning-related-list-view>` |
|
|
437
|
+
|
|
438
|
+
</details>
|
|
439
|
+
|
|
440
|
+
<details>
|
|
441
|
+
<summary><strong>🎬 Action Components</strong></summary>
|
|
442
|
+
|
|
443
|
+
| Visualforce | LWC |
|
|
444
|
+
|-------------|-----|
|
|
445
|
+
| `<apex:commandButton>` | `<lightning-button onclick={handler}>` |
|
|
446
|
+
| `<apex:commandLink>` | `<lightning-button variant="base">` |
|
|
447
|
+
| `<apex:actionFunction>` | Imperative Apex call |
|
|
448
|
+
| `<apex:actionSupport>` | Event handler (onclick, onchange) |
|
|
449
|
+
| `<apex:actionPoller>` | `setInterval` in `connectedCallback` |
|
|
450
|
+
| `<apex:actionStatus>` | `<lightning-spinner>` with loading state |
|
|
451
|
+
|
|
452
|
+
</details>
|
|
453
|
+
|
|
454
|
+
<details>
|
|
455
|
+
<summary><strong>💬 Messages</strong></summary>
|
|
456
|
+
|
|
457
|
+
| Visualforce | LWC |
|
|
458
|
+
|-------------|-----|
|
|
459
|
+
| `<apex:pageMessages>` | `ShowToastEvent` |
|
|
460
|
+
| `<apex:messages>` | `ShowToastEvent` |
|
|
461
|
+
| `<apex:message>` | `<lightning-helptext>` or validation |
|
|
462
|
+
|
|
463
|
+
</details>
|
|
464
|
+
|
|
465
|
+
<details>
|
|
466
|
+
<summary><strong>🌐 Global Variables</strong></summary>
|
|
467
|
+
|
|
468
|
+
| Visualforce | LWC |
|
|
469
|
+
|-------------|-----|
|
|
470
|
+
| `{!$CurrentPage.parameters.id}` | `@wire(CurrentPageReference)` |
|
|
471
|
+
| `{!$User.Id}` | `import userId from '@salesforce/user/Id'` |
|
|
472
|
+
| `{!$Label.ns.name}` | `import label from '@salesforce/label/ns.name'` |
|
|
473
|
+
| `{!$Resource.name}` | `import res from '@salesforce/resourceUrl/name'` |
|
|
474
|
+
|
|
475
|
+
</details>
|
|
476
|
+
|
|
477
|
+
<details>
|
|
478
|
+
<summary><strong>🔌 Data Access Patterns</strong></summary>
|
|
479
|
+
|
|
480
|
+
| Visualforce | LWC |
|
|
481
|
+
|-------------|-----|
|
|
482
|
+
| Controller getter property | `@wire` decorator |
|
|
483
|
+
| Controller action method | Imperative Apex with `@AuraEnabled` |
|
|
484
|
+
| `@RemoteAction` | Imperative Apex with `@AuraEnabled` |
|
|
485
|
+
| `rerender="sectionId"` | Reactive property update |
|
|
486
|
+
| `oncomplete="js()"` | Promise `.then()` or `async/await` |
|
|
487
|
+
|
|
488
|
+
</details>
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
## 🏗️ Architecture
|
|
493
|
+
|
|
494
|
+
```
|
|
495
|
+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
496
|
+
│ Parsers │────▶│ Transformers │────▶│ Generators │
|
|
497
|
+
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
498
|
+
│ │ │
|
|
499
|
+
▼ ▼ ▼
|
|
500
|
+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
501
|
+
│ • Aura Markup │ │ • Markup Trans. │ │ • Scaffolding │
|
|
502
|
+
│ • Aura JS │ │ • JS Transform │ │ • Full Convert │
|
|
503
|
+
│ • Aura CSS │ │ • Event Trans. │ │ • Meta XML │
|
|
504
|
+
│ • VF Page │ │ • Data Binding │ │ • Conv. Notes │
|
|
505
|
+
│ • Apex Class │ │ │ │ │
|
|
506
|
+
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### Processing Pipeline
|
|
510
|
+
|
|
511
|
+
1. **Parse** — Read and analyze source files (`.cmp`, `Controller.js`, `Helper.js`, `.css`, `.page`, `.cls`)
|
|
512
|
+
2. **Extract** — Build intermediate representation (attributes, handlers, events, dependencies)
|
|
513
|
+
3. **Transform** — Apply conversion rules (tag mappings, expressions, JavaScript patterns)
|
|
514
|
+
4. **Generate** — Create complete LWC bundle (HTML, JS, CSS, meta XML)
|
|
515
|
+
5. **Document** — Generate conversion notes with action items
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
## 📁 Project Structure
|
|
520
|
+
|
|
521
|
+
```
|
|
522
|
+
lwc-convert/
|
|
523
|
+
├── src/
|
|
524
|
+
│ ├── index.ts # CLI entry point
|
|
525
|
+
│ ├── cli/
|
|
526
|
+
│ │ ├── commands/
|
|
527
|
+
│ │ │ ├── aura.ts # Aura conversion command
|
|
528
|
+
│ │ │ └── vf.ts # VF conversion command
|
|
529
|
+
│ │ └── options.ts # CLI option definitions
|
|
530
|
+
│ ├── parsers/
|
|
531
|
+
│ │ ├── aura/ # Aura file parsers
|
|
532
|
+
│ │ └── vf/ # VF/Apex parsers
|
|
533
|
+
│ ├── transformers/
|
|
534
|
+
│ │ ├── aura-to-lwc/ # Aura transformation rules
|
|
535
|
+
│ │ └── vf-to-lwc/ # VF transformation rules
|
|
536
|
+
│ ├── generators/
|
|
537
|
+
│ │ ├── scaffolding.ts # Skeleton generator
|
|
538
|
+
│ │ └── full-conversion.ts # Complete converter
|
|
539
|
+
│ ├── mappings/ # Conversion mapping configs
|
|
540
|
+
│ └── utils/ # Shared utilities
|
|
541
|
+
├── tests/
|
|
542
|
+
│ ├── fixtures/ # Sample components for testing
|
|
543
|
+
│ └── __tests__/ # Test suites
|
|
544
|
+
├── package.json
|
|
545
|
+
├── tsconfig.json
|
|
546
|
+
└── README.md
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## 🧪 Development
|
|
552
|
+
|
|
553
|
+
### Setup
|
|
554
|
+
|
|
555
|
+
```bash
|
|
556
|
+
npm install # Install dependencies
|
|
557
|
+
npm run build # Compile TypeScript
|
|
558
|
+
npm run dev -- aura ./path/to/component # Run with ts-node
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Scripts
|
|
562
|
+
|
|
563
|
+
| Script | Description |
|
|
564
|
+
|--------|-------------|
|
|
565
|
+
| `npm run build` | Compile TypeScript → JavaScript |
|
|
566
|
+
| `npm run dev` | Run CLI with ts-node |
|
|
567
|
+
| `npm test` | Run Jest test suite |
|
|
568
|
+
| `npm run lint` | Run ESLint |
|
|
569
|
+
| `npm run format` | Format with Prettier |
|
|
570
|
+
|
|
571
|
+
### Testing
|
|
572
|
+
|
|
573
|
+
```bash
|
|
574
|
+
npm test # Run all tests
|
|
575
|
+
npm test -- --testPathPattern=parsers # Run parser tests only
|
|
576
|
+
npm test -- --coverage # Generate coverage report
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
### Tech Stack
|
|
580
|
+
|
|
581
|
+
| Category | Technology |
|
|
582
|
+
|----------|------------|
|
|
583
|
+
| Language | TypeScript 5.x |
|
|
584
|
+
| Runtime | Node.js 18+ |
|
|
585
|
+
| CLI | Commander.js |
|
|
586
|
+
| HTML/XML | htmlparser2 + domhandler |
|
|
587
|
+
| JavaScript AST | Babel (parser, traverse, generator) |
|
|
588
|
+
| CSS | PostCSS |
|
|
589
|
+
| Testing | Jest + ts-jest |
|
|
590
|
+
| Linting | ESLint |
|
|
591
|
+
| Formatting | Prettier |
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
595
|
+
## ⚠️ Limitations
|
|
596
|
+
|
|
597
|
+
### General
|
|
598
|
+
- **Single component only** — No batch processing by design
|
|
599
|
+
- **Static analysis** — Cannot detect runtime behavior
|
|
600
|
+
- **Manual testing required** — Generated code should be tested
|
|
601
|
+
|
|
602
|
+
### Aura-Specific
|
|
603
|
+
- Complex/nested expressions may need manual adjustment
|
|
604
|
+
- `$A.createComponent` patterns require manual migration
|
|
605
|
+
- Application events need manual pub/sub or LMS setup
|
|
606
|
+
- Custom renderers need manual conversion
|
|
607
|
+
|
|
608
|
+
### Visualforce-Specific
|
|
609
|
+
- `apex:actionRegion` needs architectural redesign
|
|
610
|
+
- Page includes need component composition
|
|
611
|
+
- `renderAs="pdf"` has no LWC equivalent
|
|
612
|
+
- Inline JavaScript needs manual migration
|
|
613
|
+
|
|
614
|
+
---
|
|
615
|
+
|
|
616
|
+
## 🔧 Troubleshooting
|
|
617
|
+
|
|
618
|
+
<details>
|
|
619
|
+
<summary><strong>"No .cmp file found in Aura bundle"</strong></summary>
|
|
620
|
+
|
|
621
|
+
Ensure you're pointing to the component folder containing the `.cmp` file, not a parent directory.
|
|
622
|
+
|
|
623
|
+
```bash
|
|
624
|
+
# ✅ Correct
|
|
625
|
+
lwc-convert aura ./aura/MyComponent
|
|
626
|
+
|
|
627
|
+
# ❌ Incorrect
|
|
628
|
+
lwc-convert aura ./aura
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
</details>
|
|
632
|
+
|
|
633
|
+
<details>
|
|
634
|
+
<summary><strong>"Expected a .page file"</strong></summary>
|
|
635
|
+
|
|
636
|
+
The VF command requires a `.page` file path, not a directory.
|
|
637
|
+
|
|
638
|
+
```bash
|
|
639
|
+
# ✅ Correct
|
|
640
|
+
lwc-convert vf ./pages/MyPage.page
|
|
641
|
+
|
|
642
|
+
# ❌ Incorrect
|
|
643
|
+
lwc-convert vf ./pages/
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
</details>
|
|
647
|
+
|
|
648
|
+
<details>
|
|
649
|
+
<summary><strong>Build Errors</strong></summary>
|
|
650
|
+
|
|
651
|
+
1. Ensure Node.js 18+ is installed
|
|
652
|
+
2. Delete `node_modules` and run `npm install`
|
|
653
|
+
3. Check for TypeScript errors: `npm run build`
|
|
654
|
+
|
|
655
|
+
</details>
|
|
656
|
+
|
|
657
|
+
### Getting Help
|
|
658
|
+
|
|
659
|
+
1. Run with `--verbose` for detailed output
|
|
660
|
+
2. Use `--dry-run` to preview without writing files
|
|
661
|
+
3. Check the generated `CONVERSION_NOTES.md` file
|
|
662
|
+
4. Review `// TODO:` and `// REVIEW:` comments in generated code
|
|
663
|
+
|
|
664
|
+
---
|
|
665
|
+
|
|
666
|
+
## 🤝 Contributing
|
|
667
|
+
|
|
668
|
+
Contributions are welcome! Here's how to help:
|
|
669
|
+
|
|
670
|
+
### Reporting Issues
|
|
671
|
+
|
|
672
|
+
1. Check existing issues first
|
|
673
|
+
2. Include reproduction steps
|
|
674
|
+
3. Attach sample component (sanitized) if possible
|
|
675
|
+
4. Include CLI output with `--verbose`
|
|
676
|
+
|
|
677
|
+
### Submitting Changes
|
|
678
|
+
|
|
679
|
+
1. Fork the repository
|
|
680
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
681
|
+
3. Write tests for new functionality
|
|
682
|
+
4. Ensure all tests pass (`npm test`)
|
|
683
|
+
5. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
684
|
+
6. Push to the branch (`git push origin feature/amazing-feature`)
|
|
685
|
+
7. Open a Pull Request
|
|
686
|
+
|
|
687
|
+
### Development Guidelines
|
|
688
|
+
|
|
689
|
+
- Follow existing code style
|
|
690
|
+
- Add tests for new features
|
|
691
|
+
- Update documentation for new mappings
|
|
692
|
+
- Keep commits focused and atomic
|
|
693
|
+
|
|
694
|
+
---
|
|
695
|
+
|
|
696
|
+
## 📄 License
|
|
697
|
+
|
|
698
|
+
MIT License — Copyright © 2025
|
|
699
|
+
|
|
700
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
701
|
+
|
|
702
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
703
|
+
|
|
704
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
## 🙏 Acknowledgments
|
|
709
|
+
|
|
710
|
+
- [Salesforce Lightning Web Components](https://developer.salesforce.com/docs/component-library/documentation/en/lwc) documentation
|
|
711
|
+
- [Aura Components Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/)
|
|
712
|
+
- [Visualforce Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/)
|
|
713
|
+
- The open source community for excellent parsing libraries
|
|
714
|
+
|
|
715
|
+
---
|
|
716
|
+
|
|
717
|
+
<p align="center">
|
|
718
|
+
<strong>Made with ❤️ for Salesforce developers migrating to Lightning Web Components</strong>
|
|
719
|
+
</p>
|