Skip to content

feat(create-eslint-config): implement setup wizard#51

Open
hanna-skryl wants to merge 3 commits intomainfrom
setup-wizard
Open

feat(create-eslint-config): implement setup wizard#51
hanna-skryl wants to merge 3 commits intomainfrom
setup-wizard

Conversation

@hanna-skryl
Copy link
Copy Markdown
Collaborator

Partially addresses #47

Summary

  • Interactive setup wizard for @code-pushup/eslint-config, triggered via npm init @code-pushup/eslint-config or imported programmatically
  • Detects project state (deps, files, tsconfig, node version, existing eslint config) and pre-selects recommended configs
  • Generates eslint.config.mjs (or .js for type: "module" projects) with preset inheritance
  • Installs all required peer dependencies via the detected package manager
  • Supports --yes, --configs, --tsconfig, --node-version-source, --node-version, and --dry-run CLI flags
  • Full README with usage, options table, programmatic API, and available configs

Note

Merging into existing eslint.config.* files is not yet implemented. The wizard prints a snippet for the user to paste manually. Handling defineConfig and tseslint.config wrappers will ship in a follow-up. Relevant code is marked with TODO comments.

@hanna-skryl hanna-skryl self-assigned this Apr 16, 2026
@hanna-skryl hanna-skryl marked this pull request as ready for review April 16, 2026 20:14
@hanna-skryl hanna-skryl requested a review from matejchalk April 16, 2026 20:14
Comment thread packages/create-eslint-config/src/lib/wizard.ts
Comment thread packages/create-eslint-config/src/lib/config-registry.ts
Comment thread packages/create-eslint-config/src/lib/codegen.ts
Comment on lines +41 to +54
describe('collectAllDeps', () => {
it('should merge dependencies, devDependencies, and peerDependencies', () => {
const deps = collectAllDeps({
dependencies: { a: '1' },
devDependencies: { b: '2' },
peerDependencies: { c: '3' },
});
expect([...deps].toSorted()).toEqual(['a', 'b', 'c']);
});

it('should return an empty set for null input', () => {
expect(collectAllDeps(null).size).toBe(0);
});
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a test case for duplicate packages. It's quite common to have the same package in devDependencies (for local development) and peerDependencies (for publishing).

Comment on lines +7 to +19
describe('readJsonFile', () => {
test('should parse a valid JSON file', async ({ tmp }) => {
const filePath = path.join(tmp, 'pkg.json');
await writeFile(filePath, JSON.stringify({ name: 'foo' }));
await expect(readJsonFile(filePath)).resolves.toEqual({ name: 'foo' });
});

test('should return null for a missing file', async ({ tmp }) => {
await expect(
readJsonFile(path.join(tmp, 'missing.json')),
).resolves.toBeNull();
});
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a test case for an existing file with invalid JSON.

Comment on lines +71 to +75
const manager = await detectPackageManager(targetDir);
logInfo(`Installing dependencies with ${manager}...`, '');
try {
await installDependencies(targetDir);
} catch (error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The detectPackageManager function is called twice - once here and once in installDependencies.

Comment on lines +6 to +16
/**
* Vitest test with a per-test `tmp` fixture: a fresh temporary directory
* that is automatically removed when the test settles.
*/
export const test = baseTest.extend<{ tmp: string }>({
tmp: async ({ task: _task }, use) => {
const dir = await mkdtemp(path.join(tmpdir(), 'create-eslint-config-'));
await use(dir);
await rm(dir, { recursive: true, force: true });
},
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't know Vitest had this feature, very cool. 👍

But why not use the recommended builder pattern? 🤔

},
"homepage": "https://github.com/code-pushup/eslint-config/tree/main/packages/create-eslint-config#readme",
"dependencies": {
"@inquirer/prompts": "^8.4.1",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although this doesn't happen in CI, I get lint errors locally, even after removing node_modules and re-installing.

  29:5  error  The version specifier does not contain the installed version of "@inquirer/prompts" package: 7.10.1  @nx/dependency-checks

I think it's because @inquirer/prompts isn't installed in the monorepo root.

Comment thread package.json
Comment thread packages/create-eslint-config/package.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants