Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ jobs:
- run: pnpm install --frozen-lockfile

- run: pnpm quality:check

- run: pnpm coverage:check
2 changes: 1 addition & 1 deletion .github/workflows/framework-doctor-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- uses: actions/checkout@v4

- name: Run Framework Doctor
uses: pitis/framework-doctor@main
uses: pitis/framework-doctor@v1
with:
directory: ${{ inputs.directory }}
fail-on-low-score: ${{ inputs.fail-on-low-score }}
Expand Down
8 changes: 6 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ inputs:
description: 'Output format: text or json'
required: false
default: 'text'
cli-version:
description: 'Version of @framework-doctor/cli to run'
required: false
default: '1.1.0'
fail-on-low-score:
description: 'Fail the step if score is below threshold'
required: false
Expand All @@ -36,9 +40,9 @@ runs:
run: |
USE_JSON=${{ inputs.post-to-pr == 'true' || inputs.fail-on-low-score == 'true' }}
if [ "$USE_JSON" = "true" ]; then
npx -y @framework-doctor/cli "${{ inputs.directory }}" --format json -y 2>&1 | tee "$OUTPUT_FILE"
npx -y @framework-doctor/cli@${{ inputs.cli-version }} "${{ inputs.directory }}" --format json -y 2>&1 | tee "$OUTPUT_FILE"
else
npx -y @framework-doctor/cli "${{ inputs.directory }}" --format ${{ inputs.format }} -y
npx -y @framework-doctor/cli@${{ inputs.cli-version }} "${{ inputs.directory }}" --format ${{ inputs.format }} -y
fi
shell: bash

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"release": "pnpm build && changeset publish",
"prepare": "husky",
"demo:angular": "pnpm build && pnpm exec framework-doctor examples/angular/demo-app",
"demo:react": "pnpm build && pnpm exec framework-doctor examples/react/demo-app"
"demo:react": "pnpm build && pnpm exec framework-doctor examples/react/demo-app",
"coverage:check": "turbo run coverage --filter=./packages/*"
},
"devDependencies": {
"@framework-doctor/cli": "workspace:*",
Expand Down
6 changes: 4 additions & 2 deletions packages/angular-doctor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@
"lint:fix": "oxlint --fix src tests",
"typecheck": "tsc --noEmit",
"test": "pnpm build && vitest run",
"prepublishOnly": "pnpm run build"
"prepublishOnly": "pnpm run build",
"coverage": "pnpm build && vitest run --coverage"
},
"dependencies": {
"@framework-doctor/core": "workspace:*",
Expand All @@ -83,7 +84,8 @@
"rimraf": "catalog:",
"tsdown": "catalog:",
"typescript": "catalog:",
"vitest": "catalog:"
"vitest": "catalog:",
"@vitest/coverage-v8": "catalog:"
},
"packageManager": "pnpm@10.30.0"
}
4 changes: 0 additions & 4 deletions packages/angular-doctor/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ export interface WorkspacePackage {
directory: string;
}

export interface HandleErrorOptions {
shouldExit: boolean;
}

export interface PackageJson {
name?: string;
dependencies?: Record<string, string>;
Expand Down
2 changes: 1 addition & 1 deletion packages/angular-doctor/src/utils/check-reduced-motion.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { readPackageJson } from '@framework-doctor/core';
import { spawnSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { ANGULAR_MOTION_LIBRARIES } from '../constants.js';
import type { Diagnostic } from '../types.js';
import { readPackageJson } from './read-package-json.js';

const REDUCED_MOTION_GREP_PATTERN = 'prefers-reduced-motion|useReducedMotion';
const REDUCED_MOTION_FILE_GLOBS = [
Expand Down
2 changes: 1 addition & 1 deletion packages/angular-doctor/src/utils/discover-project.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { readPackageJson } from '@framework-doctor/core';
import { spawnSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { SOURCE_FILE_PATTERN } from '../constants.js';
import type { PackageJson, ProjectInfo, WorkspacePackage } from '../types.js';
import { readPackageJson } from './read-package-json.js';

const collectDependencies = (packageJson: PackageJson): Record<string, string> => ({
...packageJson.peerDependencies,
Expand Down
25 changes: 1 addition & 24 deletions packages/angular-doctor/src/utils/handle-error.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1 @@
import { logger } from '@framework-doctor/core';
import type { HandleErrorOptions } from '../types.js';

const DEFAULT_HANDLE_ERROR_OPTIONS: HandleErrorOptions = {
shouldExit: true,
};

export const handleError = (
error: unknown,
options: HandleErrorOptions = DEFAULT_HANDLE_ERROR_OPTIONS,
): void => {
logger.break();
logger.error('Something went wrong. Please check the error below for more details.');
logger.error('If the problem persists, please open an issue on GitHub.');
logger.error('');
if (error instanceof Error) {
logger.error(error.message);
}
logger.break();
if (options.shouldExit) {
process.exit(1);
}
process.exitCode = 1;
};
export { handleError } from '@framework-doctor/core';
5 changes: 0 additions & 5 deletions packages/angular-doctor/src/utils/read-package-json.ts

This file was deleted.

96 changes: 3 additions & 93 deletions packages/angular-doctor/src/utils/run-knip.ts
Original file line number Diff line number Diff line change
@@ -1,95 +1,5 @@
import { spawnSync } from 'node:child_process';
import { createRequire } from 'node:module';
import path from 'node:path';
import { runKnipJson } from '@framework-doctor/core';
import type { Diagnostic } from '../types.js';

interface KnipExport {
name: string;
line?: number;
col?: number;
}

interface KnipIssue {
file: string;
exports?: KnipExport[];
types?: KnipExport[];
devDependencies?: Array<{ name: string }>;
}

interface KnipJsonOutput {
files?: string[];
issues?: KnipIssue[];
}

const asDiagnostics = (
items: Array<{ file: string; message: string; rule: string; line?: number; column?: number }>,
rootDirectory: string,
): Diagnostic[] =>
items.map((item) => ({
filePath: path.resolve(rootDirectory, item.file),
plugin: 'knip',
rule: item.rule,
severity: 'warning',
message: item.message,
help: 'Remove dead code or keep it in an explicit public API boundary.',
line: item.line ?? 0,
column: item.column ?? 0,
category: 'maintainability',
}));

export const runKnip = async (rootDirectory: string): Promise<Diagnostic[]> => {
const require = createRequire(import.meta.url);
const knipMainPath = require.resolve('knip');
const knipBin = path.join(path.dirname(knipMainPath), '../bin/knip.js');

const run = spawnSync(process.execPath, [knipBin, '--reporter', 'json'], {
cwd: rootDirectory,
encoding: 'utf-8',
});

const stdout = run.stdout.toString().trim();
if (!stdout) return [];

let payload: KnipJsonOutput | null = null;
try {
payload = JSON.parse(stdout) as KnipJsonOutput;
} catch {
return [];
}

const items: Array<{
file: string;
message: string;
rule: string;
line?: number;
column?: number;
}> = [];

for (const file of payload.files ?? []) {
items.push({ file, message: `Unused file: ${file}`, rule: 'files' });
}

for (const issue of payload.issues ?? []) {
const { file } = issue;
for (const exp of issue.exports ?? []) {
items.push({
file,
message: `Unused export: ${exp.name}`,
rule: 'exports',
line: exp.line,
column: exp.col,
});
}
for (const typeItem of issue.types ?? []) {
items.push({
file,
message: `Unused type: ${typeItem.name}`,
rule: 'types',
line: typeItem.line,
column: typeItem.col,
});
}
}

return asDiagnostics(items, rootDirectory);
};
export const runKnip = async (rootDirectory: string): Promise<Diagnostic[]> =>
runKnipJson(rootDirectory);
40 changes: 40 additions & 0 deletions packages/angular-doctor/tests/diagnose.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { describe, expect, it, vi } from 'vitest';

const mockedProjectInfo = {
rootDirectory: '/mock/project',
projectName: 'mock-angular-project',
angularVersion: '^19.0.0',
hasTypeScript: true,
sourceFileCount: 36,
};

const mockedScanResult = {
diagnostics: [],
scoreResult: { score: 98, label: 'Great' },
skippedChecks: [],
projectInfo: mockedProjectInfo,
};

vi.mock('../src/scan.js', () => ({
scan: vi.fn(async () => mockedScanResult),
}));

vi.mock('../src/utils/discover-project.js', () => ({
discoverProject: vi.fn(() => mockedProjectInfo),
}));

import { diagnose } from '../src/index.js';

describe('diagnose', () => {
it('returns mapped diagnose response', async () => {
const result = await diagnose('/mock/project', {
lint: false,
deadCode: false,
});

expect(result.project).toEqual(mockedProjectInfo);
expect(result.score).toEqual(mockedScanResult.scoreResult);
expect(result.diagnostics).toEqual([]);
expect(result.elapsedMilliseconds).toBeGreaterThanOrEqual(0);
});
});
8 changes: 0 additions & 8 deletions packages/angular-doctor/tests/placeholder.test.ts

This file was deleted.

9 changes: 9 additions & 0 deletions packages/angular-doctor/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,14 @@ import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
testTimeout: 30_000,
coverage: {
provider: 'v8',
thresholds: {
lines: 50,
functions: 50,
branches: 40,
statements: 50,
},
},
},
});
8 changes: 7 additions & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@
],
"scripts": {
"build": "rimraf dist && cross-env NODE_ENV=production tsdown",
"lint": "oxlint src tests",
"lint:fix": "oxlint --fix src tests",
"typecheck": "tsc --noEmit",
"test": "pnpm build && vitest run",
"coverage": "pnpm build && vitest run --coverage",
"prepublishOnly": "pnpm run build"
},
"dependencies": {
Expand All @@ -52,11 +56,13 @@
"chokidar": "^4.0.0"
},
"devDependencies": {
"@vitest/coverage-v8": "catalog:",
"@types/node": "catalog:",
"cross-env": "catalog:",
"rimraf": "catalog:",
"tsdown": "catalog:",
"typescript": "catalog:"
"typescript": "catalog:",
"vitest": "catalog:"
},
"packageManager": "pnpm@10.30.0"
}
Loading