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,29 @@ async function isDuplicate(componentPath: string, newName: string): Promise<bool
return (allLwcComponents.includes(newName) || allAuraComponents.includes(newName));
}

// enforce unique new file name under current component directory to avoid file loss
floralan marked this conversation as resolved.
Show resolved Hide resolved
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);
}
// get all file names and filter out folder names
const allFileNames = allFiles.map(file => {
floralan marked this conversation as resolved.
Show resolved Hide resolved
const split = file ? file.split('.') : '';
if (split.length <= 1) {
return '';
} else {
return split[0];
}
});
if (allFileNames.includes(newName)) {
const errorMessage = nls.localize(RENAME_INPUT_DUP_FILE_NAME_ERROR);
notificationService.showErrorMessage(errorMessage);
throw new Error(format(errorMessage));
}
}

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: 'Component name is already in use for a file in current component directory',
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 @@ -89,7 +89,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 @@ -213,6 +214,48 @@ describe('Force Rename Lightning Component', () => {
expect(exceptionThrown).to.equal(true);
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 = false;
try {
const executor = new RenameLwcComponentExecutor(sourceUri.fsPath);
await executor.run({
type: 'CONTINUE',
data: {name: 'templateOne'}
});
} catch (e) {
exceptionThrown = true;
}
expect(exceptionThrown).to.equal(true);
floralan marked this conversation as resolved.
Show resolved Hide resolved
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 = false;
try {
const executor = new RenameLwcComponentExecutor(sourceUri.fsPath);
await executor.run({
type: 'CONTINUE',
data: {name: 'example'}
});
} catch (e) {
exceptionThrown = true;
}
expect(exceptionThrown).to.equal(true);
expect(renameStub.callCount).to.equal(0);
});
});

describe ('#isNameMatch', () => {
Expand Down