Skip to content

Commit 0901fba

Browse files
fix(config): create a config file on the first run (#15)
1 parent 5ee1113 commit 0901fba

4 files changed

Lines changed: 48 additions & 9 deletions

File tree

src/cli.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,16 @@ import { red } from 'colorette';
33
import { program } from 'commander';
44
import type { Issue } from 'cspell';
55
import { lint } from 'cspell';
6-
import { findConfig } from './config';
7-
import { reportErrors, reportSuccess, resetDisplay, showProgress, showStartupMessage, stopSpinner } from './display';
6+
import { findOrCreateConfig } from './config';
7+
import {
8+
reportErrors,
9+
reportSuccess,
10+
resetDisplay,
11+
showConfigurationFilePath,
12+
showProgress,
13+
showStartupMessage,
14+
stopSpinner
15+
} from './display';
816
import { handleIssues } from './handleIssue';
917

1018
interface CLIOptions {
@@ -52,7 +60,8 @@ const globs = program.processedArgs[0];
5260
showStartupMessage(globs);
5361

5462
const start = async () => {
55-
const configPath = await findConfig(options.config);
63+
const configPath = await findOrCreateConfig(options.config);
64+
showConfigurationFilePath(configPath);
5665

5766
const {
5867
issues: issueCount,

src/config.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,36 @@
11
import { extname } from 'node:path';
2+
import { existsSync } from 'node:fs';
23
import { readFile, writeFile } from 'node:fs/promises';
34
import type { CSpellSettings } from 'cspell';
45
import { searchForConfig } from 'cspell-lib';
6+
import findDefaultConfigPath from 'application-config-path';
57
// eslint-disable-next-line import/no-relative-packages
68
import { previousState } from './shared';
79

810
let configPath: string | undefined;
911

10-
export const findConfig = async (config?: string) => {
12+
export const writeToSettings = async (settings: CSpellSettings | { cspell: CSpellSettings }) => {
13+
await writeFile(configPath!, JSON.stringify(settings, null, 4));
14+
};
15+
16+
export const findOrCreateConfig = async (config?: string) => {
1117
// Try to locate a config file in the current working directory, or with the `config` option if it was provided.
1218
const configSource = config ?? (await searchForConfig(process.cwd()))?.__importRef?.filename;
1319

1420
// If no config file was found, use/create a config file in the user's configuration directory (platform dependent).
15-
const path = configSource ?? (await import('application-config-path')).default('cspell.json');
21+
const path = configSource ?? findDefaultConfigPath('cspell.json');
1622

1723
// Only JSON files are supported to prevent more dependencies for yml parsing. If the config file is not a JSON
1824
// file, it can still be used, but it won't be updated with new ignored words.
1925
if (extname(path) === '.json') {
2026
configPath = path;
2127
}
2228

29+
// If configSource is undefined, check if default config path exists. If it doesn't, create it.
30+
if (!configSource && !existsSync(path)) {
31+
await writeToSettings({});
32+
}
33+
2334
return path;
2435
};
2536

@@ -37,10 +48,6 @@ export const getSettings = async (): Promise<CSpellSettings | { cspell: CSpellSe
3748
}
3849
};
3950

40-
export const writeToSettings = async (settings: CSpellSettings | { cspell: CSpellSettings }) => {
41-
await writeFile(configPath!, JSON.stringify(settings, null, 4));
42-
};
43-
4451
export const addIgnoreWordToSettings = async (word: string) => {
4552
const settings = await getSettings();
4653
if (!settings) {

src/display.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ export const showStartupMessage = (globs: string[]) => {
132132
console.log(`\nFinding files matching ${cyan(globs.join(', '))}`);
133133
};
134134

135+
export const showConfigurationFilePath = (path: string) => {
136+
console.log(`Using configuration from ${cyan(path)}\n`);
137+
};
138+
135139
let spinner: Spinner | undefined;
136140
export const stopSpinner = () => {
137141
spinner?.stop();

test/index.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import fs from 'node:fs';
2+
import { join } from 'node:path';
13
import { writeFile } from 'node:fs/promises';
24
import { vi, afterEach, describe, test, expect } from 'vitest';
35
import { handleIssues } from '../src/handleIssue';
46
import { determineAction, formatContext } from '../src/display';
7+
import { findOrCreateConfig } from '../src/config';
58
import { Action } from '../src/shared';
69
import { allTypoSets } from './fixtures/data';
710
import { sampleReplacer } from './mocks/issue';
@@ -55,3 +58,19 @@ describe.each(allTypoSets)('%s', (name, data) => {
5558
expect(contextDisplays, name).toMatchObject(data.displays);
5659
});
5760
});
61+
62+
describe('findConfig', () => {
63+
test('should find a mock config file in working directory', async () => {
64+
const configPath = join(process.cwd(), 'cspell.json');
65+
66+
const readFileSpy = vi.spyOn(fs, 'readFile');
67+
68+
readFileSpy.mockImplementation(((path: string, _encoding: any, callback: (err: null, data: string) => void) => {
69+
callback(null, path === configPath ? '{}' : '');
70+
}) as typeof fs.readFile);
71+
72+
const config = await findOrCreateConfig();
73+
74+
expect(config).toBe(configPath);
75+
});
76+
});

0 commit comments

Comments
 (0)