lwc-convert 1.0.0 → 1.0.1
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 -21
- package/README.md +719 -719
- package/dist/cli/commands/aura.d.ts.map +1 -1
- package/dist/cli/commands/aura.js +10 -0
- package/dist/cli/commands/aura.js.map +1 -1
- package/dist/cli/commands/vf.d.ts.map +1 -1
- package/dist/cli/commands/vf.js +10 -0
- package/dist/cli/commands/vf.js.map +1 -1
- package/dist/cli/interactive.d.ts +1 -0
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +10 -0
- package/dist/cli/interactive.js.map +1 -1
- package/dist/cli/options.d.ts +2 -1
- package/dist/cli/options.d.ts.map +1 -1
- package/dist/cli/options.js +14 -13
- package/dist/cli/options.js.map +1 -1
- package/dist/generators/full-conversion.js +6 -6
- package/dist/generators/scaffolding.js +90 -90
- package/dist/generators/test-comparison.js +149 -149
- package/dist/generators/test-generator.js +231 -231
- package/dist/index.js +49 -35
- package/dist/index.js.map +1 -1
- package/dist/transformers/aura-to-lwc/events.js +130 -130
- package/dist/transformers/vf-to-lwc/components.js +79 -79
- package/dist/transformers/vf-to-lwc/data-binding.js +165 -165
- package/dist/utils/file-io.js +15 -15
- package/dist/utils/preview-generator.d.ts +20 -0
- package/dist/utils/preview-generator.d.ts.map +1 -0
- package/dist/utils/preview-generator.js +833 -0
- package/dist/utils/preview-generator.js.map +1 -0
- package/dist/utils/session-store.js +32 -32
- package/package.json +85 -81
|
@@ -123,25 +123,25 @@ function convertGlobalVariable(expression, lmsBinding) {
|
|
|
123
123
|
const nameMatch = expr.match(/\$CurrentPage\.Name/i);
|
|
124
124
|
if (paramMatch) {
|
|
125
125
|
const paramName = paramMatch[1];
|
|
126
|
-
code = `// Access URL parameter: ${paramName}
|
|
127
|
-
@wire(CurrentPageReference)
|
|
128
|
-
pageRef;
|
|
129
|
-
|
|
130
|
-
get ${paramName}() {
|
|
131
|
-
return this.pageRef?.state?.${paramName};
|
|
126
|
+
code = `// Access URL parameter: ${paramName}
|
|
127
|
+
@wire(CurrentPageReference)
|
|
128
|
+
pageRef;
|
|
129
|
+
|
|
130
|
+
get ${paramName}() {
|
|
131
|
+
return this.pageRef?.state?.${paramName};
|
|
132
132
|
}`;
|
|
133
133
|
}
|
|
134
134
|
else if (nameMatch) {
|
|
135
|
-
code = `// Access current page name
|
|
136
|
-
@wire(CurrentPageReference)
|
|
137
|
-
pageRef;
|
|
138
|
-
|
|
139
|
-
get pageName() {
|
|
140
|
-
return this.pageRef?.attributes?.name || this.pageRef?.state?.c__pageName || '';
|
|
135
|
+
code = `// Access current page name
|
|
136
|
+
@wire(CurrentPageReference)
|
|
137
|
+
pageRef;
|
|
138
|
+
|
|
139
|
+
get pageName() {
|
|
140
|
+
return this.pageRef?.attributes?.name || this.pageRef?.state?.c__pageName || '';
|
|
141
141
|
}`;
|
|
142
142
|
}
|
|
143
143
|
else {
|
|
144
|
-
code = `@wire(CurrentPageReference)
|
|
144
|
+
code = `@wire(CurrentPageReference)
|
|
145
145
|
pageRef;`;
|
|
146
146
|
}
|
|
147
147
|
}
|
|
@@ -156,65 +156,65 @@ pageRef;`;
|
|
|
156
156
|
// Generate handleMessage body based on LMS binding analysis
|
|
157
157
|
let handleMessageBody;
|
|
158
158
|
if (lmsBinding) {
|
|
159
|
-
handleMessageBody = `// Auto-detected from VF: calls ${lmsBinding.actionFunctionName} with message.${lmsBinding.messageProperty}
|
|
160
|
-
if (message.${lmsBinding.messageProperty}) {
|
|
161
|
-
this.${lmsBinding.actionFunctionName}(message.${lmsBinding.messageProperty})
|
|
162
|
-
.then(result => {
|
|
163
|
-
// Update component state with result
|
|
164
|
-
// Example: this.contactRecord = result;
|
|
165
|
-
})
|
|
166
|
-
.catch(error => {
|
|
167
|
-
this.handleError(error);
|
|
168
|
-
});
|
|
159
|
+
handleMessageBody = `// Auto-detected from VF: calls ${lmsBinding.actionFunctionName} with message.${lmsBinding.messageProperty}
|
|
160
|
+
if (message.${lmsBinding.messageProperty}) {
|
|
161
|
+
this.${lmsBinding.actionFunctionName}(message.${lmsBinding.messageProperty})
|
|
162
|
+
.then(result => {
|
|
163
|
+
// Update component state with result
|
|
164
|
+
// Example: this.contactRecord = result;
|
|
165
|
+
})
|
|
166
|
+
.catch(error => {
|
|
167
|
+
this.handleError(error);
|
|
168
|
+
});
|
|
169
169
|
}`;
|
|
170
170
|
warnings.push(`LMS handleMessage auto-wired to ${lmsBinding.actionFunctionName}(message.${lmsBinding.messageProperty})`);
|
|
171
171
|
}
|
|
172
172
|
else {
|
|
173
|
-
handleMessageBody = `// TODO: Handle message payload
|
|
173
|
+
handleMessageBody = `// TODO: Handle message payload
|
|
174
174
|
// Example: this.recordId = message.recordId;`;
|
|
175
175
|
}
|
|
176
|
-
code = `// Lightning Message Service: ${channelName}
|
|
177
|
-
@wire(MessageContext)
|
|
178
|
-
messageContext;
|
|
179
|
-
|
|
180
|
-
// Subscription reference for cleanup
|
|
181
|
-
_subscription = null;
|
|
182
|
-
|
|
183
|
-
// Lifecycle: Subscribe to message channel
|
|
184
|
-
connectedCallback() {
|
|
185
|
-
this.subscribeToMessageChannel();
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Lifecycle: Cleanup subscription
|
|
189
|
-
disconnectedCallback() {
|
|
190
|
-
this.unsubscribeFromMessageChannel();
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Subscribe to messages
|
|
194
|
-
subscribeToMessageChannel() {
|
|
195
|
-
if (!this._subscription) {
|
|
196
|
-
this._subscription = subscribe(
|
|
197
|
-
this.messageContext,
|
|
198
|
-
${channelVar},
|
|
199
|
-
(message) => this.handleMessage(message)
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Unsubscribe from messages
|
|
205
|
-
unsubscribeFromMessageChannel() {
|
|
206
|
-
unsubscribe(this._subscription);
|
|
207
|
-
this._subscription = null;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Handle incoming messages
|
|
211
|
-
handleMessage(message) {
|
|
212
|
-
${handleMessageBody}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Publish a message
|
|
216
|
-
publishMessage(payload) {
|
|
217
|
-
publish(this.messageContext, ${channelVar}, payload);
|
|
176
|
+
code = `// Lightning Message Service: ${channelName}
|
|
177
|
+
@wire(MessageContext)
|
|
178
|
+
messageContext;
|
|
179
|
+
|
|
180
|
+
// Subscription reference for cleanup
|
|
181
|
+
_subscription = null;
|
|
182
|
+
|
|
183
|
+
// Lifecycle: Subscribe to message channel
|
|
184
|
+
connectedCallback() {
|
|
185
|
+
this.subscribeToMessageChannel();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Lifecycle: Cleanup subscription
|
|
189
|
+
disconnectedCallback() {
|
|
190
|
+
this.unsubscribeFromMessageChannel();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Subscribe to messages
|
|
194
|
+
subscribeToMessageChannel() {
|
|
195
|
+
if (!this._subscription) {
|
|
196
|
+
this._subscription = subscribe(
|
|
197
|
+
this.messageContext,
|
|
198
|
+
${channelVar},
|
|
199
|
+
(message) => this.handleMessage(message)
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Unsubscribe from messages
|
|
205
|
+
unsubscribeFromMessageChannel() {
|
|
206
|
+
unsubscribe(this._subscription);
|
|
207
|
+
this._subscription = null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Handle incoming messages
|
|
211
|
+
handleMessage(message) {
|
|
212
|
+
${handleMessageBody}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Publish a message
|
|
216
|
+
publishMessage(payload) {
|
|
217
|
+
publish(this.messageContext, ${channelVar}, payload);
|
|
218
218
|
}`;
|
|
219
219
|
warnings.push(`Lightning Message Service detected: ${channelName} - connectedCallback/disconnectedCallback auto-generated`);
|
|
220
220
|
}
|
|
@@ -226,19 +226,19 @@ publishMessage(payload) {
|
|
|
226
226
|
const field = fieldMatch[1];
|
|
227
227
|
if (field === 'Id') {
|
|
228
228
|
imports.push("import userId from '@salesforce/user/Id';");
|
|
229
|
-
code = `// Current user ID
|
|
229
|
+
code = `// Current user ID
|
|
230
230
|
userId = userId;`;
|
|
231
231
|
}
|
|
232
232
|
else {
|
|
233
233
|
imports.push("import { getRecord } from 'lightning/uiRecordApi';");
|
|
234
234
|
imports.push("import userId from '@salesforce/user/Id';");
|
|
235
235
|
imports.push(`import USER_${field.toUpperCase()}_FIELD from '@salesforce/schema/User.${field}';`);
|
|
236
|
-
code = `// Current user ${field}
|
|
237
|
-
@wire(getRecord, { recordId: userId, fields: [USER_${field.toUpperCase()}_FIELD] })
|
|
238
|
-
user;
|
|
239
|
-
|
|
240
|
-
get user${field}() {
|
|
241
|
-
return this.user?.data?.fields?.${field}?.value;
|
|
236
|
+
code = `// Current user ${field}
|
|
237
|
+
@wire(getRecord, { recordId: userId, fields: [USER_${field.toUpperCase()}_FIELD] })
|
|
238
|
+
user;
|
|
239
|
+
|
|
240
|
+
get user${field}() {
|
|
241
|
+
return this.user?.data?.fields?.${field}?.value;
|
|
242
242
|
}`;
|
|
243
243
|
pattern = 'wire';
|
|
244
244
|
}
|
|
@@ -251,9 +251,9 @@ get user${field}() {
|
|
|
251
251
|
if (labelMatch) {
|
|
252
252
|
const [, namespace, labelName] = labelMatch;
|
|
253
253
|
imports.push(`import ${labelName} from '@salesforce/label/${namespace}.${labelName}';`);
|
|
254
|
-
code = `// Label: ${namespace}.${labelName}
|
|
255
|
-
label = {
|
|
256
|
-
${labelName}
|
|
254
|
+
code = `// Label: ${namespace}.${labelName}
|
|
255
|
+
label = {
|
|
256
|
+
${labelName}
|
|
257
257
|
};`;
|
|
258
258
|
}
|
|
259
259
|
}
|
|
@@ -264,7 +264,7 @@ label = {
|
|
|
264
264
|
if (resourceMatch) {
|
|
265
265
|
const resourceName = resourceMatch[1];
|
|
266
266
|
imports.push(`import ${resourceName} from '@salesforce/resourceUrl/${resourceName}';`);
|
|
267
|
-
code = `// Static resource: ${resourceName}
|
|
267
|
+
code = `// Static resource: ${resourceName}
|
|
268
268
|
${resourceName}Url = ${resourceName};`;
|
|
269
269
|
}
|
|
270
270
|
}
|
|
@@ -273,10 +273,10 @@ ${resourceName}Url = ${resourceName};`;
|
|
|
273
273
|
pattern = 'imperative';
|
|
274
274
|
warnings.push('$Action expressions need NavigationMixin for navigation');
|
|
275
275
|
imports.push("import { NavigationMixin } from 'lightning/navigation';");
|
|
276
|
-
code = `// Navigation action - use NavigationMixin
|
|
277
|
-
// Example: this[NavigationMixin.Navigate]({
|
|
278
|
-
// type: 'standard__recordPage',
|
|
279
|
-
// attributes: { recordId: id, actionName: 'view' }
|
|
276
|
+
code = `// Navigation action - use NavigationMixin
|
|
277
|
+
// Example: this[NavigationMixin.Navigate]({
|
|
278
|
+
// type: 'standard__recordPage',
|
|
279
|
+
// attributes: { recordId: id, actionName: 'view' }
|
|
280
280
|
// });`;
|
|
281
281
|
}
|
|
282
282
|
// $ObjectType
|
|
@@ -286,7 +286,7 @@ ${resourceName}Url = ${resourceName};`;
|
|
|
286
286
|
if (objectMatch) {
|
|
287
287
|
const [, objectName, fieldName] = objectMatch;
|
|
288
288
|
imports.push(`import ${fieldName.toUpperCase()}_FIELD from '@salesforce/schema/${objectName}.${fieldName}';`);
|
|
289
|
-
code = `// Field reference: ${objectName}.${fieldName}
|
|
289
|
+
code = `// Field reference: ${objectName}.${fieldName}
|
|
290
290
|
// Use in wire adapter or getFieldValue`;
|
|
291
291
|
}
|
|
292
292
|
}
|
|
@@ -311,28 +311,28 @@ function convertControllerProperty(property, controllerName) {
|
|
|
311
311
|
let code = '';
|
|
312
312
|
if (isWireCandidate) {
|
|
313
313
|
// Use wire adapter
|
|
314
|
-
code = `// Property: ${property.name} (from ${controllerName})
|
|
315
|
-
// Option 1: Wire to Apex getter
|
|
316
|
-
@wire(get${capitalize(property.name)})
|
|
317
|
-
${property.name};
|
|
318
|
-
|
|
319
|
-
// Option 2: Simple reactive property
|
|
320
|
-
${property.name};
|
|
321
|
-
|
|
322
|
-
// If using wire, add this to imports:
|
|
314
|
+
code = `// Property: ${property.name} (from ${controllerName})
|
|
315
|
+
// Option 1: Wire to Apex getter
|
|
316
|
+
@wire(get${capitalize(property.name)})
|
|
317
|
+
${property.name};
|
|
318
|
+
|
|
319
|
+
// Option 2: Simple reactive property
|
|
320
|
+
${property.name};
|
|
321
|
+
|
|
322
|
+
// If using wire, add this to imports:
|
|
323
323
|
// import get${capitalize(property.name)} from '@salesforce/apex/${controllerName}.get${capitalize(property.name)}';`;
|
|
324
324
|
}
|
|
325
325
|
else {
|
|
326
326
|
// Use imperative or reactive property
|
|
327
|
-
code = `// Property: ${property.name}
|
|
327
|
+
code = `// Property: ${property.name}
|
|
328
328
|
${property.name}${property.initialValue ? ` = ${property.initialValue}` : ''};`;
|
|
329
329
|
if (property.hasSetter) {
|
|
330
|
-
code += `
|
|
331
|
-
|
|
332
|
-
// This property had a setter in VF - update via method call
|
|
333
|
-
async update${capitalize(property.name)}(value) {
|
|
334
|
-
this.${property.name} = value;
|
|
335
|
-
// TODO: If this needs to persist, call Apex method
|
|
330
|
+
code += `
|
|
331
|
+
|
|
332
|
+
// This property had a setter in VF - update via method call
|
|
333
|
+
async update${capitalize(property.name)}(value) {
|
|
334
|
+
this.${property.name} = value;
|
|
335
|
+
// TODO: If this needs to persist, call Apex method
|
|
336
336
|
}`;
|
|
337
337
|
}
|
|
338
338
|
}
|
|
@@ -359,16 +359,16 @@ function convertControllerMethod(method, controllerName) {
|
|
|
359
359
|
if (isWireCandidate) {
|
|
360
360
|
// Generate wire-based code
|
|
361
361
|
if (method.parameters.length === 0) {
|
|
362
|
-
code = `// Wired Apex method: ${method.name}
|
|
363
|
-
@wire(${method.name})
|
|
364
|
-
${method.name}Result;
|
|
365
|
-
|
|
366
|
-
get ${method.name}Data() {
|
|
367
|
-
return this.${method.name}Result?.data;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
get ${method.name}Error() {
|
|
371
|
-
return this.${method.name}Result?.error;
|
|
362
|
+
code = `// Wired Apex method: ${method.name}
|
|
363
|
+
@wire(${method.name})
|
|
364
|
+
${method.name}Result;
|
|
365
|
+
|
|
366
|
+
get ${method.name}Data() {
|
|
367
|
+
return this.${method.name}Result?.data;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
get ${method.name}Error() {
|
|
371
|
+
return this.${method.name}Result?.error;
|
|
372
372
|
}`;
|
|
373
373
|
}
|
|
374
374
|
else {
|
|
@@ -376,15 +376,15 @@ get ${method.name}Error() {
|
|
|
376
376
|
const params = method.parameters
|
|
377
377
|
.map((p) => `${p.name}: this.${p.name}`)
|
|
378
378
|
.join(', ');
|
|
379
|
-
code = `// Wired Apex method: ${method.name}
|
|
380
|
-
@wire(${method.name}, { ${params} })
|
|
379
|
+
code = `// Wired Apex method: ${method.name}
|
|
380
|
+
@wire(${method.name}, { ${params} })
|
|
381
381
|
${method.name}Result;`;
|
|
382
382
|
}
|
|
383
383
|
if (method.isCacheable) {
|
|
384
|
-
code += `
|
|
385
|
-
|
|
386
|
-
// Note: This method is cacheable. Use refreshApex() to refresh:
|
|
387
|
-
// import { refreshApex } from '@salesforce/apex';
|
|
384
|
+
code += `
|
|
385
|
+
|
|
386
|
+
// Note: This method is cacheable. Use refreshApex() to refresh:
|
|
387
|
+
// import { refreshApex } from '@salesforce/apex';
|
|
388
388
|
// await refreshApex(this.${method.name}Result);`;
|
|
389
389
|
}
|
|
390
390
|
}
|
|
@@ -394,15 +394,15 @@ ${method.name}Result;`;
|
|
|
394
394
|
const paramObj = method.parameters.length > 0
|
|
395
395
|
? `{ ${method.parameters.map((p) => p.name).join(', ')} }`
|
|
396
396
|
: '';
|
|
397
|
-
code = `// Imperative Apex call: ${method.name}
|
|
398
|
-
async call${capitalize(method.name)}(${params}) {
|
|
399
|
-
try {
|
|
400
|
-
const result = await ${method.name}(${paramObj});
|
|
401
|
-
return result;
|
|
402
|
-
} catch (error) {
|
|
403
|
-
console.error('Error calling ${method.name}:', error);
|
|
404
|
-
throw error;
|
|
405
|
-
}
|
|
397
|
+
code = `// Imperative Apex call: ${method.name}
|
|
398
|
+
async call${capitalize(method.name)}(${params}) {
|
|
399
|
+
try {
|
|
400
|
+
const result = await ${method.name}(${paramObj});
|
|
401
|
+
return result;
|
|
402
|
+
} catch (error) {
|
|
403
|
+
console.error('Error calling ${method.name}:', error);
|
|
404
|
+
throw error;
|
|
405
|
+
}
|
|
406
406
|
}`;
|
|
407
407
|
}
|
|
408
408
|
return {
|
|
@@ -460,20 +460,20 @@ function generateDataAccessLayer(vfPage, apexController) {
|
|
|
460
460
|
for (const ro of remoteObjects) {
|
|
461
461
|
const objectNameLower = ro.objectName.toLowerCase();
|
|
462
462
|
// Generate wire adapter scaffolding
|
|
463
|
-
wireDeclarations.push(`// Wire adapter for ${ro.objectName} (converted from apex:remoteObjectModel)
|
|
464
|
-
// TODO: Create Apex controller method to replace Remote Objects
|
|
465
|
-
//
|
|
466
|
-
// Example Apex controller:
|
|
467
|
-
// @AuraEnabled(cacheable=true)
|
|
468
|
-
// public static List<${ro.objectName}> get${ro.objectName}s() {
|
|
469
|
-
// return [SELECT ${ro.fields} FROM ${ro.objectName} LIMIT 10];
|
|
470
|
-
// }
|
|
471
|
-
//
|
|
472
|
-
// @wire(get${ro.objectName}s)
|
|
473
|
-
// ${objectNameLower}s;
|
|
474
|
-
//
|
|
475
|
-
// Or use lightning/uiRecordApi for standard objects:
|
|
476
|
-
// import { getRecords } from 'lightning/uiRecordApi';
|
|
463
|
+
wireDeclarations.push(`// Wire adapter for ${ro.objectName} (converted from apex:remoteObjectModel)
|
|
464
|
+
// TODO: Create Apex controller method to replace Remote Objects
|
|
465
|
+
//
|
|
466
|
+
// Example Apex controller:
|
|
467
|
+
// @AuraEnabled(cacheable=true)
|
|
468
|
+
// public static List<${ro.objectName}> get${ro.objectName}s() {
|
|
469
|
+
// return [SELECT ${ro.fields} FROM ${ro.objectName} LIMIT 10];
|
|
470
|
+
// }
|
|
471
|
+
//
|
|
472
|
+
// @wire(get${ro.objectName}s)
|
|
473
|
+
// ${objectNameLower}s;
|
|
474
|
+
//
|
|
475
|
+
// Or use lightning/uiRecordApi for standard objects:
|
|
476
|
+
// import { getRecords } from 'lightning/uiRecordApi';
|
|
477
477
|
`);
|
|
478
478
|
imports.push(`// import get${ro.objectName}s from '@salesforce/apex/YourController.get${ro.objectName}s';`);
|
|
479
479
|
warnings.push(`Remote Object "${ro.objectName}" detected - create Apex controller method to replace`);
|
|
@@ -534,21 +534,21 @@ function generateDataAccessLayer(vfPage, apexController) {
|
|
|
534
534
|
: '';
|
|
535
535
|
// Extract the method name from the action (e.g., "{!doSomething}" -> "doSomething")
|
|
536
536
|
const methodName = extractMethodFromAction(af.action);
|
|
537
|
-
methods.push(`// Converted from apex:actionFunction "${af.name}" (imperative - has parameters)
|
|
538
|
-
// Parameters: ${paramNames.join(', ')}
|
|
539
|
-
async ${af.name}(${paramDeclaration}) {
|
|
540
|
-
this.isLoading = true;
|
|
541
|
-
try {
|
|
542
|
-
const result = await ${methodName || af.name}(${paramObject});
|
|
543
|
-
${af.rerender ? `// Originally rerendered: ${af.rerender} - update reactive properties to trigger re-render` : ''}
|
|
544
|
-
${af.oncomplete ? `// Original oncomplete callback: ${af.oncomplete}` : ''}
|
|
545
|
-
return result;
|
|
546
|
-
} catch (error) {
|
|
547
|
-
console.error('Error calling ${af.name}:', error);
|
|
548
|
-
throw error;
|
|
549
|
-
} finally {
|
|
550
|
-
this.isLoading = false;
|
|
551
|
-
}
|
|
537
|
+
methods.push(`// Converted from apex:actionFunction "${af.name}" (imperative - has parameters)
|
|
538
|
+
// Parameters: ${paramNames.join(', ')}
|
|
539
|
+
async ${af.name}(${paramDeclaration}) {
|
|
540
|
+
this.isLoading = true;
|
|
541
|
+
try {
|
|
542
|
+
const result = await ${methodName || af.name}(${paramObject});
|
|
543
|
+
${af.rerender ? `// Originally rerendered: ${af.rerender} - update reactive properties to trigger re-render` : ''}
|
|
544
|
+
${af.oncomplete ? `// Original oncomplete callback: ${af.oncomplete}` : ''}
|
|
545
|
+
return result;
|
|
546
|
+
} catch (error) {
|
|
547
|
+
console.error('Error calling ${af.name}:', error);
|
|
548
|
+
throw error;
|
|
549
|
+
} finally {
|
|
550
|
+
this.isLoading = false;
|
|
551
|
+
}
|
|
552
552
|
}`);
|
|
553
553
|
// Add import for the Apex method if we can determine the controller
|
|
554
554
|
if (methodName && apexController) {
|
|
@@ -561,19 +561,19 @@ async ${af.name}(${paramDeclaration}) {
|
|
|
561
561
|
}
|
|
562
562
|
else {
|
|
563
563
|
// Simple action function without params can potentially use wire (but still default to imperative for consistency)
|
|
564
|
-
methods.push(`// Converted from apex:actionFunction "${af.name}"
|
|
565
|
-
async ${af.name}() {
|
|
566
|
-
this.isLoading = true;
|
|
567
|
-
try {
|
|
568
|
-
// TODO: Implement - original action: ${af.action}
|
|
569
|
-
${af.rerender ? `// Originally rerendered: ${af.rerender}` : ''}
|
|
570
|
-
${af.oncomplete ? `// Had oncomplete: ${af.oncomplete}` : ''}
|
|
571
|
-
} catch (error) {
|
|
572
|
-
console.error('Error calling ${af.name}:', error);
|
|
573
|
-
throw error;
|
|
574
|
-
} finally {
|
|
575
|
-
this.isLoading = false;
|
|
576
|
-
}
|
|
564
|
+
methods.push(`// Converted from apex:actionFunction "${af.name}"
|
|
565
|
+
async ${af.name}() {
|
|
566
|
+
this.isLoading = true;
|
|
567
|
+
try {
|
|
568
|
+
// TODO: Implement - original action: ${af.action}
|
|
569
|
+
${af.rerender ? `// Originally rerendered: ${af.rerender}` : ''}
|
|
570
|
+
${af.oncomplete ? `// Had oncomplete: ${af.oncomplete}` : ''}
|
|
571
|
+
} catch (error) {
|
|
572
|
+
console.error('Error calling ${af.name}:', error);
|
|
573
|
+
throw error;
|
|
574
|
+
} finally {
|
|
575
|
+
this.isLoading = false;
|
|
576
|
+
}
|
|
577
577
|
}`);
|
|
578
578
|
}
|
|
579
579
|
}
|
package/dist/utils/file-io.js
CHANGED
|
@@ -182,21 +182,21 @@ async function writeLwcBundle(outputDir, bundle, dryRun = false) {
|
|
|
182
182
|
*/
|
|
183
183
|
async function writeConversionNotes(outputDir, componentName, notes, dryRun = false) {
|
|
184
184
|
const notesPath = path.join(outputDir, componentName, `${componentName}-conversion-notes.md`);
|
|
185
|
-
const content = `# Conversion Notes for ${componentName}
|
|
186
|
-
|
|
187
|
-
This file documents items that require manual attention after automated conversion.
|
|
188
|
-
|
|
189
|
-
## Action Items
|
|
190
|
-
|
|
191
|
-
${notes.map((note, i) => `${i + 1}. ${note}`).join('\n')}
|
|
192
|
-
|
|
193
|
-
## Verification Checklist
|
|
194
|
-
|
|
195
|
-
- [ ] Review all TODO comments in the generated code
|
|
196
|
-
- [ ] Verify Apex method imports and wire adapters
|
|
197
|
-
- [ ] Test event handling and data flow
|
|
198
|
-
- [ ] Validate styling matches original component
|
|
199
|
-
- [ ] Deploy to scratch org and test functionality
|
|
185
|
+
const content = `# Conversion Notes for ${componentName}
|
|
186
|
+
|
|
187
|
+
This file documents items that require manual attention after automated conversion.
|
|
188
|
+
|
|
189
|
+
## Action Items
|
|
190
|
+
|
|
191
|
+
${notes.map((note, i) => `${i + 1}. ${note}`).join('\n')}
|
|
192
|
+
|
|
193
|
+
## Verification Checklist
|
|
194
|
+
|
|
195
|
+
- [ ] Review all TODO comments in the generated code
|
|
196
|
+
- [ ] Verify Apex method imports and wire adapters
|
|
197
|
+
- [ ] Test event handling and data flow
|
|
198
|
+
- [ ] Validate styling matches original component
|
|
199
|
+
- [ ] Deploy to scratch org and test functionality
|
|
200
200
|
`;
|
|
201
201
|
if (dryRun) {
|
|
202
202
|
logger_1.logger.info(`[DRY RUN] Would write conversion notes: ${notesPath}`);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preview Generator - Creates standalone HTML previews of converted LWC components
|
|
3
|
+
*
|
|
4
|
+
* This allows users to evaluate the UI of their converted components in a browser
|
|
5
|
+
* without needing a full Salesforce deployment.
|
|
6
|
+
*/
|
|
7
|
+
import { LwcBundle } from './file-io';
|
|
8
|
+
/**
|
|
9
|
+
* Generate a complete preview HTML document
|
|
10
|
+
*/
|
|
11
|
+
export declare function generatePreviewHtml(bundle: LwcBundle, componentCss?: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Write the preview HTML file
|
|
14
|
+
*/
|
|
15
|
+
export declare function writePreviewFile(outputDir: string, bundle: LwcBundle, dryRun?: boolean): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Open the preview file in the default browser
|
|
18
|
+
*/
|
|
19
|
+
export declare function openPreview(previewPath: string): Promise<void>;
|
|
20
|
+
//# sourceMappingURL=preview-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-generator.d.ts","sourceRoot":"","sources":["../../src/utils/preview-generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAqdtC;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAkSpF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,SAAS,EACjB,MAAM,GAAE,OAAe,GACtB,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBpE"}
|