Skip to content

Commit 967850a

Browse files
committed
Even more linting
1 parent 02994f9 commit 967850a

7 files changed

Lines changed: 59 additions & 38 deletions

File tree

eslint.config.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,16 @@ export default defineConfig([
77
files: ['src/**/*.ts', 'test/**/*.ts'],
88
extends: [
99
eslint.configs.recommended,
10-
tseslint.configs.recommended,
11-
tseslint.configs.strict,
12-
tseslint.configs.stylistic,
10+
tseslint.configs.strictTypeChecked,
11+
tseslint.configs.stylisticTypeChecked,
12+
tseslint.configs.recommendedTypeChecked,
1313
],
1414
},
15+
{
16+
languageOptions: {
17+
parserOptions: {
18+
projectService: true,
19+
},
20+
},
21+
},
1522
]);

src/commands/dotenv.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default class DotEnv extends SfCommand<void> {
2424

2525
public async run(): Promise<void> {
2626
const { flags } = await this.parse(DotEnv);
27-
const envFilePath = flags.env ?? DEFAULT_ENV_PATH;
27+
const envFilePath = flags.env;
2828
const envConfig = await getEnv(this.argv, true, envFilePath);
2929

3030
if (!this.jsonEnabled()) {

src/shared/configMeta.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default [
99
'Whether or not to print out the loaded env variables prior to running any other SF CLI command',
1010
input: {
1111
validator: (value: ConfigValue): boolean =>
12+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
1213
value != null && ['true', 'false'].includes(value.toString()),
1314
failedMessage: 'must provide either "true" or "false"',
1415
},

src/shared/loadingMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export function displayLoadedEnvVars(
3131
const sorted = [...loadedVars].sort();
3232
const environmentVariableLabel = `environment variable${loadedCount === 1 ? '' : 's'}`;
3333
const header = `\n ────────── Loading Environment Variables ─────────\n`;
34+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
3435
const loadingLine = `Loading ${loadedCount} ${environmentVariableLabel} from file ${envConfig.envFilePath}:`;
3536
let printedMessage = sorted.join(DELIMITER);
3637

test/prerun.test.ts

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,22 @@ jest.mock('path', () => ({
4141
const dotenvPopulateImpl = (
4242
env: Record<string, string>,
4343
values: Record<string, string>,
44-
options: { override?: boolean } = {}
44+
options: { override?: boolean } = { override: false }
4545
) => {
46-
const override = Boolean(options?.override);
46+
const override = Boolean(options.override);
4747
for (const key of Object.keys(values)) {
4848
if (Object.prototype.hasOwnProperty.call(env, key)) {
4949
if (override) env[key] = values[key];
5050
} else {
5151
env[key] = values[key];
5252
}
5353
}
54+
return null;
5455
};
5556

5657
jest.mock('dotenv', () => ({
5758
default: {
58-
parse: (val: string) => {
59+
parse: (val?: string) => {
5960
return (val?.split('\n') ?? [])
6061
.filter((val) => val)
6162
.map((splitValue: string) => {
@@ -152,8 +153,8 @@ describe('prerun hook', () => {
152153
it('should default to false when SF_DOTENV_DISABLED is not set', async () => {
153154
expect(process.env.SF_DOTENV_DISABLED).toBeUndefined();
154155
const argv = ['some-command'];
155-
mockedPathExists.mockImplementation(async () => true);
156-
mockedReadFile.mockImplementation(async () => 'TEST_VAR=test_value');
156+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
157+
mockedReadFile.mockImplementation(() => Promise.resolve('TEST_VAR=test_value'));
157158

158159
await testHook({ Command: mockCommand, config: mockConfig, argv });
159160

@@ -164,8 +165,8 @@ describe('prerun hook', () => {
164165
it('should proceed when SF_DOTENV_DISABLED is not true', async () => {
165166
process.env.SF_DOTENV_DISABLED = 'false';
166167
const argv = ['some-command'];
167-
mockedPathExists.mockImplementation(async () => true);
168-
mockedReadFile.mockImplementation(async () => 'TEST_VAR=test_value');
168+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
169+
mockedReadFile.mockImplementation(() => Promise.resolve('TEST_VAR=test_value'));
169170

170171
await testHook({ Command: mockCommand, config: mockConfig, argv });
171172

@@ -187,8 +188,8 @@ describe('prerun hook', () => {
187188
describe('environment file path resolution', () => {
188189
it('should use --env parameter when provided', async () => {
189190
const argv = ['some-command', '--env', 'custom.env'];
190-
mockedPathExists.mockImplementation(async () => true);
191-
mockedReadFile.mockImplementation(async () => 'TEST_VAR=test_value');
191+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
192+
mockedReadFile.mockImplementation(() => Promise.resolve('TEST_VAR=test_value'));
192193

193194
await testHook({ Command: mockCommand, config: mockConfig, argv });
194195

@@ -198,8 +199,8 @@ describe('prerun hook', () => {
198199

199200
it('should use -e parameter when provided', async () => {
200201
const argv = ['some-command', '-e', 'custom.env'];
201-
mockedPathExists.mockImplementation(async () => true);
202-
mockedReadFile.mockImplementation(async () => 'TEST_VAR=test_value');
202+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
203+
mockedReadFile.mockImplementation(() => Promise.resolve('TEST_VAR=test_value'));
203204
mockedResolve.mockReturnValue('custom.env');
204205

205206
await testHook({ Command: mockCommand, config: mockConfig, argv });
@@ -211,8 +212,8 @@ describe('prerun hook', () => {
211212
it('should use SF_DOTENV_FILE environment variable when set', async () => {
212213
process.env.SF_DOTENV_FILE = 'env-file.env';
213214
const argv = ['some-command'];
214-
mockedPathExists.mockImplementation(async () => true);
215-
mockedReadFile.mockImplementation(async () => 'TEST_VAR=test_value');
215+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
216+
mockedReadFile.mockImplementation(() => Promise.resolve('TEST_VAR=test_value'));
216217

217218
await testHook({ Command: mockCommand, config: mockConfig, argv });
218219

@@ -222,8 +223,8 @@ describe('prerun hook', () => {
222223

223224
it('should use default .env file when no custom path is provided', async () => {
224225
const argv = ['some-command'];
225-
mockedPathExists.mockImplementation(async () => true);
226-
mockedReadFile.mockImplementation(async () => 'TEST_VAR=test_value');
226+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
227+
mockedReadFile.mockImplementation(() => Promise.resolve('TEST_VAR=test_value'));
227228

228229
await testHook({ Command: mockCommand, config: mockConfig, argv });
229230

@@ -233,8 +234,8 @@ describe('prerun hook', () => {
233234

234235
it('should remove --env parameter and its value from argv', async () => {
235236
const argv = ['some-command', '--env', 'custom.env', 'other-arg'];
236-
mockedPathExists.mockImplementation(async () => true);
237-
mockedReadFile.mockImplementation(async () => 'TEST_VAR=test_value');
237+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
238+
mockedReadFile.mockImplementation(() => Promise.resolve('TEST_VAR=test_value'));
238239

239240
await testHook({ Command: mockCommand, config: mockConfig, argv });
240241

@@ -245,7 +246,7 @@ describe('prerun hook', () => {
245246
describe('file existence handling', () => {
246247
it('should return early when .env file does not exist', async () => {
247248
const argv = ['some-command'];
248-
mockedPathExists.mockImplementation(async () => false);
249+
mockedPathExists.mockImplementation(() => Promise.resolve(false));
249250

250251
await testHook({ Command: mockCommand, config: mockConfig, argv });
251252

@@ -254,7 +255,7 @@ describe('prerun hook', () => {
254255

255256
it('should warn when custom env file does not exist', async () => {
256257
const argv = ['some-command', '--env', 'missing.env'];
257-
mockedPathExists.mockImplementation(async () => false);
258+
mockedPathExists.mockImplementation(() => Promise.resolve(false));
258259

259260
await testHook({ Command: mockCommand, config: mockConfig, argv });
260261

@@ -265,7 +266,7 @@ describe('prerun hook', () => {
265266
it('should not warn when custom env file does not exist and logging disabled', async () => {
266267
shouldLogMock.mockReturnValue(undefined);
267268
const argv = ['some-command', '--env', 'missing.env'];
268-
mockedPathExists.mockImplementation(async () => false);
269+
mockedPathExists.mockImplementation(() => Promise.resolve(false));
269270

270271
await testHook({ Command: mockCommand, config: mockConfig, argv });
271272

@@ -274,7 +275,7 @@ describe('prerun hook', () => {
274275

275276
it('should not warn when default .env file does not exist', async () => {
276277
const argv = ['some-command'];
277-
mockedPathExists.mockImplementation(async () => false);
278+
mockedPathExists.mockImplementation(() => Promise.resolve(false));
278279

279280
await testHook({ Command: mockCommand, config: mockConfig, argv });
280281

@@ -286,7 +287,7 @@ describe('prerun hook', () => {
286287
it('should load environment variables from .env file', async () => {
287288
const argv = ['some-command'];
288289
const envContent = 'TEST_VAR=test_value\nANOTHER_VAR=another_value';
289-
mockedPathExists.mockImplementation(async () => true);
290+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
290291
mockedReadFile.mockResolvedValue(envContent);
291292

292293
await testHook({ Command: mockCommand, config: mockConfig, argv });
@@ -298,7 +299,7 @@ describe('prerun hook', () => {
298299
it('should display loading message with correct count and file path', async () => {
299300
const argv = ['some-command'];
300301
const envContent = 'TEST_VAR=test_value\nANOTHER_VAR=another_value';
301-
mockedPathExists.mockImplementation(async () => true);
302+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
302303
mockedReadFile.mockResolvedValue(envContent);
303304
mockedRelative.mockReturnValue(DEFAULT_ENV_PATH);
304305

@@ -312,7 +313,7 @@ describe('prerun hook', () => {
312313
it('should not display loading message when --json flag is present', async () => {
313314
const argv = ['some-command', '--json'];
314315
const envContent = 'TEST_VAR=test_value';
315-
mockedPathExists.mockImplementation(async () => true);
316+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
316317
mockedReadFile.mockResolvedValue(envContent);
317318

318319
await testHook({ Command: mockCommand, config: mockConfig, argv });
@@ -322,7 +323,7 @@ describe('prerun hook', () => {
322323

323324
it('should handle empty .env file', async () => {
324325
const argv = ['some-command'];
325-
mockedPathExists.mockImplementation(async () => true);
326+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
326327
mockedReadFile.mockResolvedValue('');
327328

328329
await testHook({ Command: mockCommand, config: mockConfig, argv });
@@ -335,7 +336,7 @@ describe('prerun hook', () => {
335336
it('should handle file read errors gracefully', async () => {
336337
const argv = ['some-command'];
337338
const error = new Error('Permission denied');
338-
mockedPathExists.mockImplementation(async () => true);
339+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
339340
mockedReadFile.mockRejectedValue(error);
340341

341342
await testHook({ Command: mockCommand, config: mockConfig, argv });
@@ -345,7 +346,7 @@ describe('prerun hook', () => {
345346

346347
it('should handle non-Error exceptions', async () => {
347348
const argv = ['some-command'];
348-
mockedPathExists.mockImplementation(async () => true);
349+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
349350
mockedReadFile.mockRejectedValue('String error');
350351

351352
await testHook({ Command: mockCommand, config: mockConfig, argv });
@@ -357,7 +358,7 @@ describe('prerun hook', () => {
357358
describe('environment variable precedence', () => {
358359
it('should call dotenv.populate with override==true so .env file values take precedence', async () => {
359360
const argv = ['some-command'];
360-
mockedPathExists.mockImplementation(async () => true);
361+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
361362
mockedReadFile.mockResolvedValue('FOO=bar');
362363

363364
await testHook({ Command: mockCommand, config: mockConfig, argv });
@@ -373,7 +374,7 @@ describe('prerun hook', () => {
373374
process.env.EXISTING_VAR = 'existing_value';
374375
const argv = ['some-command'];
375376
const envContent = 'EXISTING_VAR=new_value\nNEW_VAR=new_value';
376-
mockedPathExists.mockImplementation(async () => true);
377+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
377378
mockedReadFile.mockResolvedValue(envContent);
378379

379380
await testHook({ Command: mockCommand, config: mockConfig, argv });
@@ -386,7 +387,7 @@ describe('prerun hook', () => {
386387
process.env.NOT_IN_ENV_FILE = 'unchanged_value';
387388
const argv = ['some-command'];
388389
const envContent = 'ONLY_IN_FILE=from_file';
389-
mockedPathExists.mockImplementation(async () => true);
390+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
390391
mockedReadFile.mockResolvedValue(envContent);
391392

392393
await testHook({ Command: mockCommand, config: mockConfig, argv });
@@ -400,7 +401,7 @@ describe('prerun hook', () => {
400401
process.env.LEAVE_ME_ALONE = 'original';
401402
const argv = ['some-command'];
402403
const envContent = 'OVERWRITE_ME=new\nANOTHER_NEW=value';
403-
mockedPathExists.mockImplementation(async () => true);
404+
mockedPathExists.mockImplementation(() => Promise.resolve(true));
404405
mockedReadFile.mockResolvedValue(envContent);
405406

406407
await testHook({ Command: mockCommand, config: mockConfig, argv });

test/shared/environment.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jest.mock('path', () => ({
2626

2727
jest.mock('dotenv', () => ({
2828
default: {
29-
parse: (content: string) => {
29+
parse: (content?: string) => {
3030
const result: Record<string, string> = {};
3131
for (const line of (content ?? '').split('\n').filter(Boolean)) {
3232
const eq = line.indexOf('=');
@@ -40,9 +40,9 @@ jest.mock('dotenv', () => ({
4040
populate: (
4141
env: Record<string, string>,
4242
values: Record<string, string>,
43-
options: { override?: boolean } = {}
43+
options: { override?: boolean } = { override: false }
4444
) => {
45-
const shouldOverrideExistingValue = Boolean(options?.override);
45+
const shouldOverrideExistingValue = Boolean(options.override);
4646
for (const key of Object.keys(values)) {
4747
if (Object.prototype.hasOwnProperty.call(env, key) || !shouldOverrideExistingValue) {
4848
env[key] = values[key];

test/tsconfig.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"extends": "@salesforce/dev-config/tsconfig-strict-esm",
3+
"compilerOptions": {
4+
"baseUrl": ".",
5+
"noEmit": true,
6+
"skipLibCheck": true,
7+
"strictNullChecks": true,
8+
"sourceMap": true
9+
},
10+
"include": ["./**/*.ts"]
11+
}

0 commit comments

Comments
 (0)