Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: SFDX: Rename Component now shows an error message if one uses an existing file name as the new component name to avoid data loss. #4039

Merged
merged 9 commits into from
Apr 21, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const RENAME_LIGHTNING_COMPONENT_EXECUTOR = 'force_rename_lightning_component';
const RENAME_INPUT_PLACEHOLDER = 'rename_component_input_placeholder';
const RENAME_INPUT_PROMPT = 'rename_component_input_prompt';
const RENAME_INPUT_DUP_ERROR = 'rename_component_input_dup_error';
const RENAME_INPUT_DUP_FILE_NAME_ERROR = 'rename_component_input_dup_file_name_error';
const RENAME_WARNING = 'rename_component_warning';
const LWC = 'lwc';
const AURA = 'aura';
Expand Down Expand Up @@ -88,6 +89,7 @@ async function renameComponent(sourceFsPath: string, newName: string) {
const componentName = getComponentName(componentPath);
await checkForDuplicateName(componentPath, newName);
const items = await fs.promises.readdir(componentPath);
await checkForDuplicateInComponent(componentPath, newName, items);
for (const item of items) {
// only rename the file that has same name with component
if (isNameMatch(item, componentName, componentPath)) {
Expand Down Expand Up @@ -154,6 +156,34 @@ async function isDuplicate(componentPath: string, newName: string): Promise<bool
return (allLwcComponents.includes(newName) || allAuraComponents.includes(newName));
}

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good use of the "why" in a comment 👍

* check duplicate name under current component directory and __tests__ directory to avoid file loss
*/
async function checkForDuplicateInComponent(componentPath: string, newName: string, items: string[]) {
let allFiles = items;
if (items.includes(TEST_FOLDER)) {
const testFiles = await fs.promises.readdir(path.join(componentPath, TEST_FOLDER));
allFiles = items.concat(testFiles);
}
const allFileNames = getOnlyFileNames(allFiles);
if (allFileNames.includes(newName)) {
const errorMessage = nls.localize(RENAME_INPUT_DUP_FILE_NAME_ERROR);
notificationService.showErrorMessage(errorMessage);
throw new Error(format(errorMessage));
}
}

function getOnlyFileNames(allFiles: string[]) {
return allFiles.map(file => {
const split = file ? file.split('.') : '';
if (split.length <= 1) {
return '';
} else {
return split[0];
}
});
}

export function isNameMatch(item: string, componentName: string, componentPath: string): boolean {
const isLwc = isLwcComponent(componentPath);
let regularExp: RegExp;
Expand Down
1 change: 1 addition & 0 deletions packages/salesforcedx-vscode-core/src/messages/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ export const messages = {
sobject_refresh_standard: 'Standard SObjects',
force_rename_lightning_component: 'SFDX: Rename Component',
rename_component_input_dup_error: 'Component name is already in use in LWC or Aura',
rename_component_input_dup_file_name_error: 'This file name is already in use in the current component directory. Choose a different name and try again.',
rename_component_input_placeholder: 'Enter a unique component name',
rename_component_input_prompt: 'Press Enter to confirm your input or Escape to cancel',
rename_component_warning: 'Warning: References to the old name will not be updated. Update manually and redeploy once all changes have been made.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import * as path from 'path';
import * as sinon from 'sinon';
import * as vscode from 'vscode';
import {isNameMatch, RenameLwcComponentExecutor} from '../../../src/commands/forceRenameLightningComponent';
import { nls } from '../../../src/messages';

const RENAME_INPUT_DUP_ERROR = 'rename_component_input_dup_error';
const RENAME_INPUT_DUP_FILE_NAME_ERROR = 'rename_component_input_dup_file_name_error';
const lwcPath = vscode.Uri.parse('/force-app/main/default/lwc');
const auraPath = vscode.Uri.parse('/force-app/main/default/aura/');
const lwcComponent = 'hero';
Expand Down Expand Up @@ -89,7 +92,8 @@ describe('Force Rename Lightning Component', () => {
.onCall(0).resolves([])
.onCall(1).resolves([])
.onCall(2).resolves([testFolder])
.onCall(3).resolves(testFiles);
.onCall(3).resolves([])
.onCall(4).resolves(testFiles);
const executor = new RenameLwcComponentExecutor(sourceUri.fsPath);
await executor.run({
type: 'CONTINUE',
Expand Down Expand Up @@ -200,17 +204,62 @@ describe('Force Rename Lightning Component', () => {
readdirStub
.onFirstCall().resolves([lwcComponent])
.onSecondCall().resolves([]);
let exceptionThrown = false;
let exceptionThrown: any;
const errorMessage = nls.localize(RENAME_INPUT_DUP_ERROR);
try {
const executor = new RenameLwcComponentExecutor(sourceUri.fsPath);
await executor.run({
type: 'CONTINUE',
data: {name: 'hero'}
});
} catch (e) {
exceptionThrown = true;
exceptionThrown = e;
}
expect(exceptionThrown.message).to.equal(errorMessage);
expect(renameStub.callCount).to.equal(0);
});

it('should prevent new component name from duplicating any existing file name under current component directory', async () => {
const sourceUri = vscode.Uri.joinPath(lwcPath, lwcComponent);
readdirStub
.onCall(0).resolves([])
.onCall(1).resolves([])
.onCall(2).resolves(itemsInHero.concat([testFolder]))
.onCall(3).resolves(testFiles);
let exceptionThrown: any;
const errorMessage = nls.localize(RENAME_INPUT_DUP_FILE_NAME_ERROR);
try {
const executor = new RenameLwcComponentExecutor(sourceUri.fsPath);
await executor.run({
type: 'CONTINUE',
data: {name: 'templateOne'}
});
} catch (e) {
exceptionThrown = e;
}
expect(exceptionThrown.message).to.equal(errorMessage);
expect(renameStub.callCount).to.equal(0);
});

it('should prevent new component name from duplicating any exiting test file name', async () => {
const sourceUri = vscode.Uri.joinPath(lwcPath, lwcComponent);
readdirStub
.onCall(0).resolves([])
.onCall(1).resolves([])
.onCall(2).resolves(itemsInHero.concat([testFolder]))
.onCall(3).resolves(testFiles);
let exceptionThrown: any;
const errorMessage = nls.localize(RENAME_INPUT_DUP_FILE_NAME_ERROR);
try {
const executor = new RenameLwcComponentExecutor(sourceUri.fsPath);
await executor.run({
type: 'CONTINUE',
data: {name: 'example'}
});
} catch (e) {
exceptionThrown = e;
}
expect(exceptionThrown).to.equal(true);
expect(exceptionThrown.message).to.equal(errorMessage);
expect(renameStub.callCount).to.equal(0);
});
});
Expand Down