Skip to content

Commit d1dd087

Browse files
Merge pull request #466 from sf-aastha-paruthi/u/aparuthi/lwcfoldername
@W-20609628 Folder Name Validation
2 parents 9116f58 + 1d74fe6 commit d1dd087

File tree

4 files changed

+194
-0
lines changed

4 files changed

+194
-0
lines changed

messages/assess.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
"operationCancelled": "Operation cancelled.",
118118
"invalidYesNoResponse": "Invalid response. Please answer y or n.",
119119
"notSfdxProjectFolderPath": "Provided folder is not a valid Salesforce DX project. Please select a folder containing sfdx-project.json",
120+
"restrictedFolderName": "Restricted folder name: %s. Do not use 'labels', 'messageChannels', or 'lwc'. Try again with a different name.",
120121
"errorRunningAssess": "Assessment process failed reason : %s",
121122
"enableVerboseOutput": "Enable verbose output",
122123
"apexFileChangesIdentifiedNotApplied": "Changes were identified but not applied for the %s Apex class when the assessment mode was running.",

messages/migrate.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"notEmptyProjectFolderPath": "Provided project folder is not empty. Please provide a valid empty project folder name and path",
4747
"invalidYesNoResponse": "Invalid response. Please answer y or n.",
4848
"notSfdxProjectFolderPath": "Provided folder is not a valid Salesforce DX project. Please select a folder containing sfdx-project.json",
49+
"restrictedFolderName": "Restricted folder name: %s. Do not use 'labels', 'messageChannels', or 'lwc'. Try again with a different name.",
4950
"operationCancelled": "Operation cancelled.",
5051
"errorRunningMigrate": "Migration process failed reason : %s",
5152
"exceptionSettingDesignersToStandardDataModel": "We've encountered an exception while configuring the Omnistudio standard designers to use the standard data model. Try again later.",

src/utils/projectPathUtil.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,14 @@ export class ProjectPathUtil {
158158
return false;
159159
}
160160

161+
// Check if folder path ends with restricted names (case insensitive)
162+
const restrictedFolderNames = ['labels', 'messagechannels', 'lwc'];
163+
const folderName = path.basename(folderPath);
164+
if (restrictedFolderNames.includes(folderName.toLowerCase())) {
165+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
166+
return false;
167+
}
168+
161169
if (mode === EMPTY_MODE && fs.readdirSync(folderPath).length > 0) {
162170
Logger.error(messages.getMessage('notEmptyProjectFolderPath'));
163171
return false;

test/utils/projectPathUtil.test.ts

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import * as fs from 'fs';
2+
import * as path from 'path';
3+
import { expect } from 'chai';
4+
import * as sinon from 'sinon';
5+
import { Messages } from '@salesforce/core';
6+
import { Logger } from '../../src/utils/logger';
7+
8+
Messages.importMessagesDirectory(__dirname);
9+
const messages = Messages.loadMessages('@salesforce/plugin-omnistudio-migration-tool', 'assess');
10+
11+
describe('ProjectPathUtil - Restricted Folder Name Validation', () => {
12+
let loggerErrorStub: sinon.SinonStub;
13+
let fsExistsSyncStub: sinon.SinonStub;
14+
let fsLstatSyncStub: sinon.SinonStub;
15+
16+
beforeEach(() => {
17+
loggerErrorStub = sinon.stub(Logger, 'error');
18+
fsExistsSyncStub = sinon.stub(fs, 'existsSync');
19+
fsLstatSyncStub = sinon.stub(fs, 'lstatSync');
20+
});
21+
22+
afterEach(() => {
23+
loggerErrorStub.restore();
24+
fsExistsSyncStub.restore();
25+
fsLstatSyncStub.restore();
26+
});
27+
28+
/**
29+
* Helper function that simulates the isValidFolderPath restricted name check
30+
*/
31+
function isRestrictedFolderName(folderPath: string): boolean {
32+
const restrictedFolderNames = ['labels', 'messagechannels', 'lwc'];
33+
const folderName = path.basename(folderPath);
34+
return restrictedFolderNames.includes(folderName.toLowerCase());
35+
}
36+
37+
describe('Restricted folder names', () => {
38+
it('should reject folder path ending with "lwc"', () => {
39+
const folderPath = '/some/path/lwc';
40+
41+
if (isRestrictedFolderName(folderPath)) {
42+
const folderName = path.basename(folderPath);
43+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
44+
}
45+
46+
expect(loggerErrorStub.calledOnce).to.be.true;
47+
expect(loggerErrorStub.firstCall.args[0]).to.include('Restricted folder name: lwc');
48+
expect(loggerErrorStub.firstCall.args[0]).to.include('Try again with a different name');
49+
});
50+
51+
it('should reject folder path ending with "labels"', () => {
52+
const folderPath = '/some/path/labels';
53+
54+
if (isRestrictedFolderName(folderPath)) {
55+
const folderName = path.basename(folderPath);
56+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
57+
}
58+
59+
expect(loggerErrorStub.calledOnce).to.be.true;
60+
expect(loggerErrorStub.firstCall.args[0]).to.include('Restricted folder name: labels');
61+
expect(loggerErrorStub.firstCall.args[0]).to.include('Try again with a different name');
62+
});
63+
64+
it('should reject folder path ending with "messageChannels"', () => {
65+
const folderPath = '/some/path/messageChannels';
66+
67+
if (isRestrictedFolderName(folderPath)) {
68+
const folderName = path.basename(folderPath);
69+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
70+
}
71+
72+
expect(loggerErrorStub.calledOnce).to.be.true;
73+
expect(loggerErrorStub.firstCall.args[0]).to.include('Restricted folder name: messageChannels');
74+
expect(loggerErrorStub.firstCall.args[0]).to.include('Try again with a different name');
75+
});
76+
77+
it('should reject folder path with uppercase "LWC" (case insensitive)', () => {
78+
const folderPath = '/some/path/LWC';
79+
80+
if (isRestrictedFolderName(folderPath)) {
81+
const folderName = path.basename(folderPath);
82+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
83+
}
84+
85+
expect(loggerErrorStub.calledOnce).to.be.true;
86+
expect(loggerErrorStub.firstCall.args[0]).to.include('Restricted folder name: LWC');
87+
expect(loggerErrorStub.firstCall.args[0]).to.include('Try again with a different name');
88+
});
89+
90+
it('should reject folder path with mixed case "Labels" (case insensitive)', () => {
91+
const folderPath = '/some/path/Labels';
92+
93+
if (isRestrictedFolderName(folderPath)) {
94+
const folderName = path.basename(folderPath);
95+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
96+
}
97+
98+
expect(loggerErrorStub.calledOnce).to.be.true;
99+
expect(loggerErrorStub.firstCall.args[0]).to.include('Restricted folder name: Labels');
100+
expect(loggerErrorStub.firstCall.args[0]).to.include('Try again with a different name');
101+
});
102+
103+
it('should reject folder path with uppercase "MESSAGECHANNELS" (case insensitive)', () => {
104+
const folderPath = '/some/path/MESSAGECHANNELS';
105+
106+
if (isRestrictedFolderName(folderPath)) {
107+
const folderName = path.basename(folderPath);
108+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
109+
}
110+
111+
expect(loggerErrorStub.calledOnce).to.be.true;
112+
expect(loggerErrorStub.firstCall.args[0]).to.include('Restricted folder name: MESSAGECHANNELS');
113+
expect(loggerErrorStub.firstCall.args[0]).to.include('Try again with a different name');
114+
});
115+
});
116+
117+
describe('Valid folder names', () => {
118+
it('should allow folder path ending with "myproject"', () => {
119+
const folderPath = '/some/path/myproject';
120+
121+
if (isRestrictedFolderName(folderPath)) {
122+
const folderName = path.basename(folderPath);
123+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
124+
}
125+
126+
expect(loggerErrorStub.called).to.be.false;
127+
});
128+
129+
it('should allow folder path ending with "src"', () => {
130+
const folderPath = '/some/path/src';
131+
132+
if (isRestrictedFolderName(folderPath)) {
133+
const folderName = path.basename(folderPath);
134+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
135+
}
136+
137+
expect(loggerErrorStub.called).to.be.false;
138+
});
139+
140+
it('should allow folder path containing "lwc" but not ending with it', () => {
141+
const folderPath = '/some/lwc/myproject';
142+
143+
if (isRestrictedFolderName(folderPath)) {
144+
const folderName = path.basename(folderPath);
145+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
146+
}
147+
148+
expect(loggerErrorStub.called).to.be.false;
149+
});
150+
151+
it('should allow folder path containing "labels" but not ending with it', () => {
152+
const folderPath = '/some/labels/customfolder';
153+
154+
if (isRestrictedFolderName(folderPath)) {
155+
const folderName = path.basename(folderPath);
156+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
157+
}
158+
159+
expect(loggerErrorStub.called).to.be.false;
160+
});
161+
162+
it('should allow folder name that contains restricted name as substring', () => {
163+
const folderPath = '/some/path/mylwcproject';
164+
165+
if (isRestrictedFolderName(folderPath)) {
166+
const folderName = path.basename(folderPath);
167+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
168+
}
169+
170+
expect(loggerErrorStub.called).to.be.false;
171+
});
172+
173+
it('should allow folder name "labelsbackup"', () => {
174+
const folderPath = '/some/path/labelsbackup';
175+
176+
if (isRestrictedFolderName(folderPath)) {
177+
const folderName = path.basename(folderPath);
178+
Logger.error(messages.getMessage('restrictedFolderName', [folderName]));
179+
}
180+
181+
expect(loggerErrorStub.called).to.be.false;
182+
});
183+
});
184+
});

0 commit comments

Comments
 (0)