feat(wave3): add @mosaic/quality-rails — TypeScript code quality scaffolder
- Project detection: detectProjectKind (node/python/rust/unknown) - Scaffolder: writes ESLint/Biome/pre-commit configs based on profile - Embedded templates for strict/standard/minimal profiles - CLI: quality-rails init | check | doctor - Depends on @mosaic/types workspace:*
This commit is contained in:
40
packages/quality-rails/tests/detect.test.ts
Normal file
40
packages/quality-rails/tests/detect.test.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { detectProjectKind } from '../src/detect.js';
|
||||
|
||||
async function withTempDir(run: (directory: string) => Promise<void>): Promise<void> {
|
||||
const directory = await mkdtemp(join(tmpdir(), 'quality-rails-detect-'));
|
||||
try {
|
||||
await run(directory);
|
||||
} finally {
|
||||
await rm(directory, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
describe('detectProjectKind', () => {
|
||||
it('returns node when package.json exists', async () => {
|
||||
await withTempDir(async (directory) => {
|
||||
await writeFile(join(directory, 'package.json'), '{"name":"fixture"}\n', 'utf8');
|
||||
|
||||
await expect(detectProjectKind(directory)).resolves.toBe('node');
|
||||
});
|
||||
});
|
||||
|
||||
it('returns python when pyproject.toml exists and package.json does not', async () => {
|
||||
await withTempDir(async (directory) => {
|
||||
await writeFile(join(directory, 'pyproject.toml'), '[project]\nname = "fixture"\n', 'utf8');
|
||||
|
||||
await expect(detectProjectKind(directory)).resolves.toBe('python');
|
||||
});
|
||||
});
|
||||
|
||||
it('returns unknown when no known project files exist', async () => {
|
||||
await withTempDir(async (directory) => {
|
||||
await expect(detectProjectKind(directory)).resolves.toBe('unknown');
|
||||
});
|
||||
});
|
||||
});
|
||||
57
packages/quality-rails/tests/scaffolder.test.ts
Normal file
57
packages/quality-rails/tests/scaffolder.test.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { scaffoldQualityRails } from '../src/scaffolder.js';
|
||||
import type { RailsConfig } from '../src/types.js';
|
||||
|
||||
async function withTempDir(run: (directory: string) => Promise<void>): Promise<void> {
|
||||
const directory = await mkdtemp(join(tmpdir(), 'quality-rails-scaffold-'));
|
||||
try {
|
||||
await run(directory);
|
||||
} finally {
|
||||
await rm(directory, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
describe('scaffoldQualityRails', () => {
|
||||
it('writes expected node quality rails files', async () => {
|
||||
await withTempDir(async (directory) => {
|
||||
await writeFile(join(directory, 'package.json'), '{"name":"fixture"}\n', 'utf8');
|
||||
|
||||
const previous = process.env.MOSAIC_QUALITY_RAILS_SKIP_INSTALL;
|
||||
process.env.MOSAIC_QUALITY_RAILS_SKIP_INSTALL = '1';
|
||||
|
||||
const config: RailsConfig = {
|
||||
projectPath: directory,
|
||||
kind: 'node',
|
||||
profile: 'strict',
|
||||
linters: ['eslint', 'biome'],
|
||||
formatters: ['prettier'],
|
||||
hooks: true,
|
||||
};
|
||||
|
||||
const result = await scaffoldQualityRails(config);
|
||||
|
||||
process.env.MOSAIC_QUALITY_RAILS_SKIP_INSTALL = previous;
|
||||
|
||||
await expect(readFile(join(directory, '.eslintrc'), 'utf8')).resolves.toContain('parser');
|
||||
await expect(readFile(join(directory, 'biome.json'), 'utf8')).resolves.toContain('"formatter"');
|
||||
await expect(readFile(join(directory, '.githooks', 'pre-commit'), 'utf8')).resolves.toContain('pnpm lint');
|
||||
await expect(readFile(join(directory, 'PR-CHECKLIST.md'), 'utf8')).resolves.toContain('Code Review Checklist');
|
||||
|
||||
expect(result.filesWritten).toEqual(
|
||||
expect.arrayContaining([
|
||||
'.eslintrc',
|
||||
'biome.json',
|
||||
'.githooks/pre-commit',
|
||||
'PR-CHECKLIST.md',
|
||||
]),
|
||||
);
|
||||
expect(result.commandsToRun).toContain('git config core.hooksPath .githooks');
|
||||
expect(result.warnings).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user