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(config): create a config file on the first run #15

Merged
merged 7 commits into from
Feb 18, 2023
15 changes: 12 additions & 3 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@ import { red } from 'colorette';
import { program } from 'commander';
import type { Issue } from 'cspell';
import { lint } from 'cspell';
import { findConfig } from './config';
import { reportErrors, reportSuccess, resetDisplay, showProgress, showStartupMessage, stopSpinner } from './display';
import { findOrCreateConfig } from './config';
import {
reportErrors,
reportSuccess,
resetDisplay,
showConfigurationFilePath,
showProgress,
showStartupMessage,
stopSpinner
} from './display';
import { handleIssues } from './handleIssue';

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

const start = async () => {
const configPath = await findConfig(options.config);
const configPath = await findOrCreateConfig(options.config);
showConfigurationFilePath(configPath);

const {
issues: issueCount,
Expand Down
19 changes: 13 additions & 6 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
import { extname } from 'node:path';
import { existsSync } from 'node:fs';
import { readFile, writeFile } from 'node:fs/promises';
import type { CSpellSettings } from 'cspell';
import { searchForConfig } from 'cspell-lib';
import findDefaultConfigPath from 'application-config-path';
// eslint-disable-next-line import/no-relative-packages
import { previousState } from './shared';

let configPath: string | undefined;

export const findConfig = async (config?: string) => {
export const writeToSettings = async (settings: CSpellSettings | { cspell: CSpellSettings }) => {
await writeFile(configPath!, JSON.stringify(settings, null, 4));
};

export const findOrCreateConfig = async (config?: string) => {
// Try to locate a config file in the current working directory, or with the `config` option if it was provided.
const configSource = config ?? (await searchForConfig(process.cwd()))?.__importRef?.filename;

// If no config file was found, use/create a config file in the user's configuration directory (platform dependent).
const path = configSource ?? (await import('application-config-path')).default('cspell.json');
guilherssousa marked this conversation as resolved.
Show resolved Hide resolved
const path = configSource ?? findDefaultConfigPath('cspell.json');

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

// If configSource is undefined, check if default config path exists. If it doesn't, create it.
if (!configSource && !existsSync(path)) {
await writeToSettings({});
}

return path;
};

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

export const writeToSettings = async (settings: CSpellSettings | { cspell: CSpellSettings }) => {
await writeFile(configPath!, JSON.stringify(settings, null, 4));
};

export const addIgnoreWordToSettings = async (word: string) => {
const settings = await getSettings();
if (!settings) {
Expand Down
4 changes: 4 additions & 0 deletions src/display.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ export const showStartupMessage = (globs: string[]) => {
console.log(`\nFinding files matching ${cyan(globs.join(', '))}`);
};

export const showConfigurationFilePath = (path: string) => {
console.log(`Using configuration from ${cyan(path)}\n`);
guilherssousa marked this conversation as resolved.
Show resolved Hide resolved
};

let spinner: Spinner | undefined;
export const stopSpinner = () => {
spinner?.stop();
Expand Down
19 changes: 19 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import fs from 'node:fs';
import { join } from 'node:path';
import { writeFile } from 'node:fs/promises';
import { vi, afterEach, describe, test, expect } from 'vitest';
import { handleIssues } from '../src/handleIssue';
import { determineAction, formatContext } from '../src/display';
import { findOrCreateConfig } from '../src/config';
import { Action } from '../src/shared';
import { allTypoSets } from './fixtures/data';
import { sampleReplacer } from './mocks/issue';
Expand Down Expand Up @@ -55,3 +58,19 @@ describe.each(allTypoSets)('%s', (name, data) => {
expect(contextDisplays, name).toMatchObject(data.displays);
});
});

describe('findConfig', () => {
test('should find a mock config file in working directory', async () => {
const configPath = join(process.cwd(), 'cspell.json');

const readFileSpy = vi.spyOn(fs, 'readFile');

readFileSpy.mockImplementation(((path: string, _encoding: any, callback: (err: null, data: string) => void) => {
callback(null, path === configPath ? '{}' : '');
}) as typeof fs.readFile);

const config = await findOrCreateConfig();

expect(config).toBe(configPath);
});
});