import type { QualityProfile, RailsConfig } from './types.js'; const PROFILE_TO_MAX_WARNINGS: Record = { strict: 0, standard: 10, minimal: 50, }; const PROFILE_TO_LINE_LENGTH: Record = { strict: 100, standard: 110, minimal: 120, }; export function eslintTemplate(profile: QualityProfile): string { return `${JSON.stringify( { root: true, parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint'], extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], env: { node: true, es2022: true, }, parserOptions: { ecmaVersion: 'latest', sourceType: 'module', }, rules: { 'no-console': profile === 'strict' ? 'error' : 'warn', '@typescript-eslint/no-explicit-any': profile === 'minimal' ? 'off' : profile === 'strict' ? 'error' : 'warn', '@typescript-eslint/explicit-function-return-type': profile === 'strict' ? 'warn' : 'off', 'max-lines-per-function': [ profile === 'minimal' ? 'off' : 'warn', { max: profile === 'strict' ? 60 : 100, skipBlankLines: true, skipComments: true, }, ], }, }, null, 2, )}\n`; } export function biomeTemplate(profile: QualityProfile): string { return `${JSON.stringify( { $schema: 'https://biomejs.dev/schemas/1.8.3/schema.json', formatter: { enabled: true, indentStyle: 'space', indentWidth: 2, lineWidth: PROFILE_TO_LINE_LENGTH[profile], }, linter: { enabled: true, rules: { recommended: true, suspicious: { noConsole: profile === 'strict' ? 'error' : 'warn', }, complexity: { noExcessiveCognitiveComplexity: profile === 'strict' ? 'warn' : profile === 'standard' ? 'info' : 'off', }, }, }, javascript: { formatter: { quoteStyle: 'single', trailingCommas: 'all', }, }, }, null, 2, )}\n`; } export function pyprojectSection(profile: QualityProfile): string { const lineLength = PROFILE_TO_LINE_LENGTH[profile]; return [ '# >>> mosaic-quality-rails >>>', '[tool.ruff]', `line-length = ${lineLength}`, 'target-version = "py311"', '', '[tool.ruff.lint]', 'select = ["E", "F", "I", "UP", "B"]', `ignore = ${profile === 'minimal' ? '[]' : '["E501"]'}`, '', '[tool.black]', `line-length = ${lineLength}`, '', '# <<< mosaic-quality-rails <<<', '', ].join('\n'); } export function rustfmtTemplate(profile: QualityProfile): string { const maxWidth = PROFILE_TO_LINE_LENGTH[profile]; const useSmallHeuristics = profile === 'strict' ? 'Max' : 'Default'; return [ `max_width = ${maxWidth}`, `use_small_heuristics = "${useSmallHeuristics}"`, `imports_granularity = "${profile === 'minimal' ? 'Crate' : 'Module'}"`, `group_imports = "${profile === 'strict' ? 'StdExternalCrate' : 'Preserve'}"`, '', ].join('\n'); } function resolveHookCommands(config: RailsConfig): string[] { const commands: string[] = []; if (config.kind === 'node') { if (config.linters.some((linter) => linter.toLowerCase() === 'eslint')) { commands.push('pnpm lint'); } if (config.linters.some((linter) => linter.toLowerCase() === 'biome')) { commands.push('pnpm biome check .'); } if (config.formatters.some((formatter) => formatter.toLowerCase() === 'prettier')) { commands.push('pnpm prettier --check .'); } commands.push('pnpm test --if-present'); } if (config.kind === 'python') { commands.push('ruff check .'); commands.push('black --check .'); } if (config.kind === 'rust') { commands.push('cargo fmt --check'); commands.push('cargo clippy --all-targets --all-features -- -D warnings'); } if (commands.length === 0) { commands.push('echo "No quality commands configured for this project kind"'); } return commands; } export function preCommitHookTemplate(config: RailsConfig): string { const commands = resolveHookCommands(config) .map((command) => `${command} || exit 1`) .join('\n'); return [ '#!/usr/bin/env sh', 'set -eu', '', 'echo "[quality-rails] Running pre-commit checks..."', commands, 'echo "[quality-rails] Checks passed."', '', ].join('\n'); } export function prChecklistTemplate(profile: QualityProfile): string { return [ '# Code Review Checklist', '', `Profile: **${profile}**`, '', '- [ ] Requirements mapped to tests', '- [ ] Error handling covers unhappy paths', '- [ ] Lint and typecheck are clean', '- [ ] Test suite passes', '- [ ] Security-sensitive paths reviewed', `- [ ] Warnings count <= ${PROFILE_TO_MAX_WARNINGS[profile]}`, '', ].join('\n'); }