@kb-labs/devkit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursorrules +32 -0
- package/.github/CODEOWNERS +2 -0
- package/.github/actions/setup-node-pnpm/action.yml +47 -0
- package/.github/workflow-templates/ci.yml +13 -0
- package/.github/workflow-templates/drift-check.yml +10 -0
- package/.github/workflow-templates/profiles-validate.yml +16 -0
- package/.github/workflow-templates/release.yml +8 -0
- package/.github/workflows/ci-reusable.yml +131 -0
- package/.github/workflows/drift-check-reusable.yml +23 -0
- package/.github/workflows/fixtures.yml +74 -0
- package/.github/workflows/profiles-validate-reusable.yml +67 -0
- package/.github/workflows/release-reusable.yml +50 -0
- package/.vscode/settings.json +23 -0
- package/AGENTS.md +130 -0
- package/LICENSE +21 -0
- package/README.md +1542 -0
- package/agents/devkit-maintainer/context.globs +15 -0
- package/agents/devkit-maintainer/permissions.yml +17 -0
- package/agents/devkit-maintainer/prompt.md +28 -0
- package/agents/devkit-maintainer/runbook.md +31 -0
- package/agents/docs-crafter/prompt.md +24 -0
- package/agents/docs-crafter/runbook.md +18 -0
- package/agents/release-manager/context.globs +7 -0
- package/agents/release-manager/prompt.md +27 -0
- package/agents/release-manager/runbook.md +17 -0
- package/agents/test-generator/context.globs +7 -0
- package/agents/test-generator/prompt.md +27 -0
- package/agents/test-generator/runbook.md +18 -0
- package/bin/devkit-architecture.mjs +1225 -0
- package/bin/devkit-build-order.mjs +500 -0
- package/bin/devkit-check-build-readiness.mjs +222 -0
- package/bin/devkit-check-commands.mjs +394 -0
- package/bin/devkit-check-configs.mjs +461 -0
- package/bin/devkit-check-deprecated.mjs +532 -0
- package/bin/devkit-check-duplicates.mjs +431 -0
- package/bin/devkit-check-exports.mjs +561 -0
- package/bin/devkit-check-imports.mjs +712 -0
- package/bin/devkit-check-paths.mjs +670 -0
- package/bin/devkit-check-scripts.mjs +335 -0
- package/bin/devkit-check-structure.mjs +495 -0
- package/bin/devkit-check-types.mjs +450 -0
- package/bin/devkit-ci.mjs +261 -0
- package/bin/devkit-core-gate.mjs +225 -0
- package/bin/devkit-fix-deps.mjs +1169 -0
- package/bin/devkit-freshness.mjs +199 -0
- package/bin/devkit-health.mjs +489 -0
- package/bin/devkit-migrate-configs.mjs +370 -0
- package/bin/devkit-paths.mjs +192 -0
- package/bin/devkit-stats.mjs +453 -0
- package/bin/devkit-sync.mjs +12 -0
- package/bin/devkit-tsup-external.mjs +148 -0
- package/bin/devkit-types-audit.mjs +615 -0
- package/bin/devkit-types-order.mjs +637 -0
- package/bin/devkit-validate-naming.mjs +203 -0
- package/bin/devkit-visualize.mjs +452 -0
- package/bin/kb-devkit-qa-history.mjs +453 -0
- package/bin/kb-devkit-qa.mjs +915 -0
- package/eslint/node.js +134 -0
- package/eslint/react.js +260 -0
- package/package.json +186 -0
- package/prettier/index.json +10 -0
- package/sync/index.mjs +693 -0
- package/templates/configs/README.md +306 -0
- package/templates/configs/eslint.config.js +27 -0
- package/templates/configs/package.json.bin +25 -0
- package/templates/configs/package.json.lib +30 -0
- package/templates/configs/tsconfig.build.json +15 -0
- package/templates/configs/tsconfig.json +9 -0
- package/templates/configs/tsup.config.bin.ts +34 -0
- package/templates/configs/tsup.config.cli.ts +41 -0
- package/templates/configs/tsup.config.dual.ts +46 -0
- package/templates/configs/tsup.config.ts +36 -0
- package/templates/package-json/README.md +290 -0
- package/templates/package-json/package.json.bin.template +40 -0
- package/templates/package-json/package.json.template +45 -0
- package/tsconfig/base.json +21 -0
- package/tsconfig/cli.json +12 -0
- package/tsconfig/dist/__tests__/cache.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/cache.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/cache.spec.js +85 -0
- package/tsconfig/dist/__tests__/cache.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/fs-atomic.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/fs-atomic.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/fs-atomic.spec.js +153 -0
- package/tsconfig/dist/__tests__/fs-atomic.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/init-workspace.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/init-workspace.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/init-workspace.spec.js +99 -0
- package/tsconfig/dist/__tests__/init-workspace.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/kb-error.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/kb-error.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/kb-error.spec.js +190 -0
- package/tsconfig/dist/__tests__/kb-error.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/preset-lockfile.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/preset-lockfile.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/preset-lockfile.spec.js +142 -0
- package/tsconfig/dist/__tests__/preset-lockfile.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/product-config-profiles.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/product-config-profiles.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/product-config-profiles.spec.js +100 -0
- package/tsconfig/dist/__tests__/product-config-profiles.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/product-config.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/product-config.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/product-config.spec.js +298 -0
- package/tsconfig/dist/__tests__/product-config.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/runtime.spec.d.ts +2 -0
- package/tsconfig/dist/__tests__/runtime.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/runtime.spec.js +127 -0
- package/tsconfig/dist/__tests__/runtime.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/upsert-lockfile.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/upsert-lockfile.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/upsert-lockfile.spec.js +251 -0
- package/tsconfig/dist/__tests__/upsert-lockfile.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/validate-config.spec.d.ts +2 -0
- package/tsconfig/dist/__tests__/validate-config.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/validate-config.spec.js +14 -0
- package/tsconfig/dist/__tests__/validate-config.spec.js.map +1 -0
- package/tsconfig/dist/api/init-workspace.d.ts +10 -0
- package/tsconfig/dist/api/init-workspace.d.ts.map +1 -0
- package/tsconfig/dist/api/init-workspace.js +191 -0
- package/tsconfig/dist/api/init-workspace.js.map +1 -0
- package/tsconfig/dist/api/product-config.d.ts +21 -0
- package/tsconfig/dist/api/product-config.d.ts.map +1 -0
- package/tsconfig/dist/api/product-config.js +192 -0
- package/tsconfig/dist/api/product-config.js.map +1 -0
- package/tsconfig/dist/api/read-config.d.ts +22 -0
- package/tsconfig/dist/api/read-config.d.ts.map +1 -0
- package/tsconfig/dist/api/read-config.js +105 -0
- package/tsconfig/dist/api/read-config.js.map +1 -0
- package/tsconfig/dist/api/upsert-lockfile.d.ts +10 -0
- package/tsconfig/dist/api/upsert-lockfile.d.ts.map +1 -0
- package/tsconfig/dist/api/upsert-lockfile.js +63 -0
- package/tsconfig/dist/api/upsert-lockfile.js.map +1 -0
- package/tsconfig/dist/cache/fs-cache.d.ts +38 -0
- package/tsconfig/dist/cache/fs-cache.d.ts.map +1 -0
- package/tsconfig/dist/cache/fs-cache.js +142 -0
- package/tsconfig/dist/cache/fs-cache.js.map +1 -0
- package/tsconfig/dist/errors/kb-error.d.ts +32 -0
- package/tsconfig/dist/errors/kb-error.d.ts.map +1 -0
- package/tsconfig/dist/errors/kb-error.js +54 -0
- package/tsconfig/dist/errors/kb-error.js.map +1 -0
- package/tsconfig/dist/fs/__tests__/fs.spec.d.ts +2 -0
- package/tsconfig/dist/fs/__tests__/fs.spec.d.ts.map +1 -0
- package/tsconfig/dist/fs/__tests__/fs.spec.js +22 -0
- package/tsconfig/dist/fs/__tests__/fs.spec.js.map +1 -0
- package/tsconfig/dist/fs/fs.d.ts +6 -0
- package/tsconfig/dist/fs/fs.d.ts.map +1 -0
- package/tsconfig/dist/fs/fs.js +12 -0
- package/tsconfig/dist/fs/fs.js.map +1 -0
- package/tsconfig/dist/fs/index.d.ts +2 -0
- package/tsconfig/dist/fs/index.d.ts.map +1 -0
- package/tsconfig/dist/fs/index.js +2 -0
- package/tsconfig/dist/fs/index.js.map +1 -0
- package/tsconfig/dist/hash/config-hash.d.ts +17 -0
- package/tsconfig/dist/hash/config-hash.d.ts.map +1 -0
- package/tsconfig/dist/hash/config-hash.js +55 -0
- package/tsconfig/dist/hash/config-hash.js.map +1 -0
- package/tsconfig/dist/index.d.ts +5 -0
- package/tsconfig/dist/index.d.ts.map +1 -0
- package/tsconfig/dist/index.js +5 -0
- package/tsconfig/dist/index.js.map +1 -0
- package/tsconfig/dist/lockfile/lockfile.d.ts +54 -0
- package/tsconfig/dist/lockfile/lockfile.d.ts.map +1 -0
- package/tsconfig/dist/lockfile/lockfile.js +141 -0
- package/tsconfig/dist/lockfile/lockfile.js.map +1 -0
- package/tsconfig/dist/logging/__tests__/logger.spec.d.ts +2 -0
- package/tsconfig/dist/logging/__tests__/logger.spec.d.ts.map +1 -0
- package/tsconfig/dist/logging/__tests__/logger.spec.js +65 -0
- package/tsconfig/dist/logging/__tests__/logger.spec.js.map +1 -0
- package/tsconfig/dist/logging/__tests__/redaction.spec.d.ts +2 -0
- package/tsconfig/dist/logging/__tests__/redaction.spec.d.ts.map +1 -0
- package/tsconfig/dist/logging/__tests__/redaction.spec.js +34 -0
- package/tsconfig/dist/logging/__tests__/redaction.spec.js.map +1 -0
- package/tsconfig/dist/logging/__tests__/sinks-and-env.spec.d.ts +2 -0
- package/tsconfig/dist/logging/__tests__/sinks-and-env.spec.d.ts.map +1 -0
- package/tsconfig/dist/logging/__tests__/sinks-and-env.spec.js +90 -0
- package/tsconfig/dist/logging/__tests__/sinks-and-env.spec.js.map +1 -0
- package/tsconfig/dist/logging/index.d.ts +6 -0
- package/tsconfig/dist/logging/index.d.ts.map +1 -0
- package/tsconfig/dist/logging/index.js +6 -0
- package/tsconfig/dist/logging/index.js.map +1 -0
- package/tsconfig/dist/logging/logger.d.ts +9 -0
- package/tsconfig/dist/logging/logger.d.ts.map +1 -0
- package/tsconfig/dist/logging/logger.js +101 -0
- package/tsconfig/dist/logging/logger.js.map +1 -0
- package/tsconfig/dist/logging/redaction.d.ts +7 -0
- package/tsconfig/dist/logging/redaction.d.ts.map +1 -0
- package/tsconfig/dist/logging/redaction.js +23 -0
- package/tsconfig/dist/logging/redaction.js.map +1 -0
- package/tsconfig/dist/logging/sinks/json.d.ts +4 -0
- package/tsconfig/dist/logging/sinks/json.d.ts.map +1 -0
- package/tsconfig/dist/logging/sinks/json.js +23 -0
- package/tsconfig/dist/logging/sinks/json.js.map +1 -0
- package/tsconfig/dist/logging/sinks/stdout.d.ts +3 -0
- package/tsconfig/dist/logging/sinks/stdout.d.ts.map +1 -0
- package/tsconfig/dist/logging/sinks/stdout.js +24 -0
- package/tsconfig/dist/logging/sinks/stdout.js.map +1 -0
- package/tsconfig/dist/logging/types/index.d.ts +2 -0
- package/tsconfig/dist/logging/types/index.d.ts.map +1 -0
- package/tsconfig/dist/logging/types/index.js +2 -0
- package/tsconfig/dist/logging/types/index.js.map +1 -0
- package/tsconfig/dist/logging/types/types.d.ts +37 -0
- package/tsconfig/dist/logging/types/types.d.ts.map +1 -0
- package/tsconfig/dist/logging/types/types.js +2 -0
- package/tsconfig/dist/logging/types/types.js.map +1 -0
- package/tsconfig/dist/merge/layered-merge.d.ts +16 -0
- package/tsconfig/dist/merge/layered-merge.d.ts.map +1 -0
- package/tsconfig/dist/merge/layered-merge.js +97 -0
- package/tsconfig/dist/merge/layered-merge.js.map +1 -0
- package/tsconfig/dist/preset/resolve-preset.d.ts +29 -0
- package/tsconfig/dist/preset/resolve-preset.d.ts.map +1 -0
- package/tsconfig/dist/preset/resolve-preset.js +104 -0
- package/tsconfig/dist/preset/resolve-preset.js.map +1 -0
- package/tsconfig/dist/repo/__tests__/repo.spec.d.ts +2 -0
- package/tsconfig/dist/repo/__tests__/repo.spec.d.ts.map +1 -0
- package/tsconfig/dist/repo/__tests__/repo.spec.js +25 -0
- package/tsconfig/dist/repo/__tests__/repo.spec.js.map +1 -0
- package/tsconfig/dist/repo/index.d.ts +2 -0
- package/tsconfig/dist/repo/index.d.ts.map +1 -0
- package/tsconfig/dist/repo/index.js +2 -0
- package/tsconfig/dist/repo/index.js.map +1 -0
- package/tsconfig/dist/repo/repo.d.ts +6 -0
- package/tsconfig/dist/repo/repo.d.ts.map +1 -0
- package/tsconfig/dist/repo/repo.js +25 -0
- package/tsconfig/dist/repo/repo.js.map +1 -0
- package/tsconfig/dist/runtime/index.d.ts +2 -0
- package/tsconfig/dist/runtime/index.d.ts.map +1 -0
- package/tsconfig/dist/runtime/index.js +2 -0
- package/tsconfig/dist/runtime/index.js.map +1 -0
- package/tsconfig/dist/runtime/runtime.d.ts +46 -0
- package/tsconfig/dist/runtime/runtime.d.ts.map +1 -0
- package/tsconfig/dist/runtime/runtime.js +126 -0
- package/tsconfig/dist/runtime/runtime.js.map +1 -0
- package/tsconfig/dist/tsconfig.tools.tsbuildinfo +1 -0
- package/tsconfig/dist/tsconfig.tsbuildinfo +1 -0
- package/tsconfig/dist/types/index.d.ts +2 -0
- package/tsconfig/dist/types/index.d.ts.map +1 -0
- package/tsconfig/dist/types/index.js +2 -0
- package/tsconfig/dist/types/index.js.map +1 -0
- package/tsconfig/dist/types/init.d.ts +34 -0
- package/tsconfig/dist/types/init.d.ts.map +1 -0
- package/tsconfig/dist/types/init.js +6 -0
- package/tsconfig/dist/types/init.js.map +1 -0
- package/tsconfig/dist/types/preset.d.ts +27 -0
- package/tsconfig/dist/types/preset.d.ts.map +1 -0
- package/tsconfig/dist/types/preset.js +6 -0
- package/tsconfig/dist/types/preset.js.map +1 -0
- package/tsconfig/dist/types/types.d.ts +6 -0
- package/tsconfig/dist/types/types.d.ts.map +1 -0
- package/tsconfig/dist/types/types.js +2 -0
- package/tsconfig/dist/types/types.js.map +1 -0
- package/tsconfig/dist/utils/__tests__/env.spec.d.ts +2 -0
- package/tsconfig/dist/utils/__tests__/env.spec.d.ts.map +1 -0
- package/tsconfig/dist/utils/__tests__/env.spec.js +33 -0
- package/tsconfig/dist/utils/__tests__/env.spec.js.map +1 -0
- package/tsconfig/dist/utils/env.d.ts +7 -0
- package/tsconfig/dist/utils/env.d.ts.map +1 -0
- package/tsconfig/dist/utils/env.js +25 -0
- package/tsconfig/dist/utils/env.js.map +1 -0
- package/tsconfig/dist/utils/fs-atomic.d.ts +15 -0
- package/tsconfig/dist/utils/fs-atomic.d.ts.map +1 -0
- package/tsconfig/dist/utils/fs-atomic.js +45 -0
- package/tsconfig/dist/utils/fs-atomic.js.map +1 -0
- package/tsconfig/dist/utils/index.d.ts +3 -0
- package/tsconfig/dist/utils/index.d.ts.map +1 -0
- package/tsconfig/dist/utils/index.js +3 -0
- package/tsconfig/dist/utils/index.js.map +1 -0
- package/tsconfig/dist/utils/paths.d.ts +21 -0
- package/tsconfig/dist/utils/paths.d.ts.map +1 -0
- package/tsconfig/dist/utils/paths.js +32 -0
- package/tsconfig/dist/utils/paths.js.map +1 -0
- package/tsconfig/dist/utils/product-normalize.d.ts +27 -0
- package/tsconfig/dist/utils/product-normalize.d.ts.map +1 -0
- package/tsconfig/dist/utils/product-normalize.js +45 -0
- package/tsconfig/dist/utils/product-normalize.js.map +1 -0
- package/tsconfig/dist/validation/validate-config.d.ts +7 -0
- package/tsconfig/dist/validation/validate-config.d.ts.map +1 -0
- package/tsconfig/dist/validation/validate-config.js +22 -0
- package/tsconfig/dist/validation/validate-config.js.map +1 -0
- package/tsconfig/lib.json +13 -0
- package/tsconfig/node.json +12 -0
- package/tsconfig/react-app.json +8 -0
- package/tsconfig/react-lib.json +8 -0
- package/tsconfig/test.json +15 -0
- package/tsup/bin.js +172 -0
- package/tsup/dual.js +155 -0
- package/tsup/external-sync.mjs +41 -0
- package/tsup/external.mjs +109 -0
- package/tsup/node.js +65 -0
- package/tsup/react-lib.js +18 -0
- package/tsup/sdk.js +118 -0
- package/vite/react-app.js +50 -0
- package/vitest/node.js +37 -0
- package/vitest/react.js +39 -0
- package/vitest/vitest-setup.ts +9 -0
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @kb-labs/devkit - TypeScript Types Audit
|
|
5
|
+
*
|
|
6
|
+
* Deep type safety analysis for the entire monorepo using TypeScript Compiler API.
|
|
7
|
+
* Shows centralized audit report with type coverage, errors, and dependency chains.
|
|
8
|
+
*
|
|
9
|
+
* Unlike simple linting, this:
|
|
10
|
+
* - Uses TypeScript Compiler API for semantic analysis
|
|
11
|
+
* - Tracks type inheritance chains across packages
|
|
12
|
+
* - Shows impact: what breaks if type X is wrong
|
|
13
|
+
* - Provides single audit report for entire monorepo
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* kb-devkit-types-audit # Full audit report
|
|
17
|
+
* kb-devkit-types-audit --package=cli-core # Specific package
|
|
18
|
+
* kb-devkit-types-audit --errors-only # Only show errors
|
|
19
|
+
* kb-devkit-types-audit --coverage # Type coverage report
|
|
20
|
+
* kb-devkit-types-audit --json # JSON output
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import ts from 'typescript';
|
|
24
|
+
import fs from 'node:fs';
|
|
25
|
+
import path from 'node:path';
|
|
26
|
+
import { fileURLToPath } from 'node:url';
|
|
27
|
+
|
|
28
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
|
|
30
|
+
// ANSI colors
|
|
31
|
+
const colors = {
|
|
32
|
+
reset: '\x1b[0m',
|
|
33
|
+
red: '\x1b[31m',
|
|
34
|
+
green: '\x1b[32m',
|
|
35
|
+
yellow: '\x1b[33m',
|
|
36
|
+
blue: '\x1b[34m',
|
|
37
|
+
magenta: '\x1b[35m',
|
|
38
|
+
cyan: '\x1b[36m',
|
|
39
|
+
gray: '\x1b[90m',
|
|
40
|
+
bold: '\x1b[1m',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
function log(message, color = 'reset') {
|
|
44
|
+
if (!options.json) {
|
|
45
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Parse CLI arguments
|
|
50
|
+
const args = process.argv.slice(2);
|
|
51
|
+
const options = {
|
|
52
|
+
json: args.includes('--json'),
|
|
53
|
+
errorsOnly: args.includes('--errors-only'),
|
|
54
|
+
coverage: args.includes('--coverage'),
|
|
55
|
+
verbose: args.includes('--verbose') || args.includes('-v'),
|
|
56
|
+
package: args.find((arg) => arg.startsWith('--package='))?.split('=')[1],
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Find all packages
|
|
61
|
+
*/
|
|
62
|
+
function findPackages(rootDir) {
|
|
63
|
+
const packages = [];
|
|
64
|
+
const entries = fs.readdirSync(rootDir, { withFileTypes: true });
|
|
65
|
+
|
|
66
|
+
for (const entry of entries) {
|
|
67
|
+
if (!entry.isDirectory() || !entry.name.startsWith('kb-labs-')) {continue;}
|
|
68
|
+
|
|
69
|
+
const repoPath = path.join(rootDir, entry.name);
|
|
70
|
+
const packagesDir = path.join(repoPath, 'packages');
|
|
71
|
+
|
|
72
|
+
if (!fs.existsSync(packagesDir)) {continue;}
|
|
73
|
+
|
|
74
|
+
const packageDirs = fs.readdirSync(packagesDir, { withFileTypes: true });
|
|
75
|
+
|
|
76
|
+
for (const pkgDir of packageDirs) {
|
|
77
|
+
if (!pkgDir.isDirectory()) {continue;}
|
|
78
|
+
|
|
79
|
+
const packageJsonPath = path.join(packagesDir, pkgDir.name, 'package.json');
|
|
80
|
+
const tsconfigPath = path.join(packagesDir, pkgDir.name, 'tsconfig.json');
|
|
81
|
+
|
|
82
|
+
if (fs.existsSync(packageJsonPath) && fs.existsSync(tsconfigPath)) {
|
|
83
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
84
|
+
|
|
85
|
+
packages.push({
|
|
86
|
+
name: packageJson.name,
|
|
87
|
+
path: packageJsonPath,
|
|
88
|
+
dir: path.join(packagesDir, pkgDir.name),
|
|
89
|
+
tsconfigPath,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return packages;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Create TypeScript program for a package
|
|
100
|
+
*/
|
|
101
|
+
function createProgram(packageDir, tsconfigPath) {
|
|
102
|
+
const configFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
|
|
103
|
+
|
|
104
|
+
if (configFile.error) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const parsedConfig = ts.parseJsonConfigFileContent(
|
|
109
|
+
configFile.config,
|
|
110
|
+
ts.sys,
|
|
111
|
+
packageDir
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
if (parsedConfig.errors.length > 0) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return ts.createProgram({
|
|
119
|
+
rootNames: parsedConfig.fileNames,
|
|
120
|
+
options: parsedConfig.options,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Analyze type errors in a package
|
|
126
|
+
*/
|
|
127
|
+
function analyzeTypeErrors(program, packageName) {
|
|
128
|
+
const diagnostics = ts.getPreEmitDiagnostics(program);
|
|
129
|
+
|
|
130
|
+
const errors = [];
|
|
131
|
+
const warnings = [];
|
|
132
|
+
|
|
133
|
+
for (const diagnostic of diagnostics) {
|
|
134
|
+
if (!diagnostic.file) {continue;}
|
|
135
|
+
|
|
136
|
+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(
|
|
137
|
+
diagnostic.start
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
|
141
|
+
const severity = diagnostic.category === ts.DiagnosticCategory.Error ? 'error' : 'warning';
|
|
142
|
+
|
|
143
|
+
const issue = {
|
|
144
|
+
severity,
|
|
145
|
+
message,
|
|
146
|
+
file: diagnostic.file.fileName,
|
|
147
|
+
line: line + 1,
|
|
148
|
+
column: character + 1,
|
|
149
|
+
code: diagnostic.code,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
if (severity === 'error') {
|
|
153
|
+
errors.push(issue);
|
|
154
|
+
} else {
|
|
155
|
+
warnings.push(issue);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return { errors, warnings };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Calculate type coverage for a package
|
|
164
|
+
*/
|
|
165
|
+
function calculateTypeCoverage(program) {
|
|
166
|
+
const checker = program.getTypeChecker();
|
|
167
|
+
const sourceFiles = program.getSourceFiles().filter(
|
|
168
|
+
(sf) => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
let totalSymbols = 0;
|
|
172
|
+
let typedSymbols = 0;
|
|
173
|
+
let anyCount = 0;
|
|
174
|
+
let unknownCount = 0;
|
|
175
|
+
let tsIgnoreCount = 0;
|
|
176
|
+
|
|
177
|
+
for (const sourceFile of sourceFiles) {
|
|
178
|
+
// Count @ts-ignore comments
|
|
179
|
+
const text = sourceFile.getFullText();
|
|
180
|
+
const tsIgnoreMatches = text.match(/@ts-ignore/g);
|
|
181
|
+
tsIgnoreCount += tsIgnoreMatches ? tsIgnoreMatches.length : 0;
|
|
182
|
+
|
|
183
|
+
ts.forEachChild(sourceFile, function visit(node) {
|
|
184
|
+
// Check for 'any' type
|
|
185
|
+
if (ts.isTypeNode(node)) {
|
|
186
|
+
totalSymbols++;
|
|
187
|
+
|
|
188
|
+
const type = checker.getTypeAtLocation(node);
|
|
189
|
+
|
|
190
|
+
if (type.flags & ts.TypeFlags.Any) {
|
|
191
|
+
anyCount++;
|
|
192
|
+
} else if (type.flags & ts.TypeFlags.Unknown) {
|
|
193
|
+
unknownCount++;
|
|
194
|
+
} else {
|
|
195
|
+
typedSymbols++;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Check variables, parameters, properties
|
|
200
|
+
if (
|
|
201
|
+
ts.isVariableDeclaration(node) ||
|
|
202
|
+
ts.isParameter(node) ||
|
|
203
|
+
ts.isPropertyDeclaration(node)
|
|
204
|
+
) {
|
|
205
|
+
totalSymbols++;
|
|
206
|
+
|
|
207
|
+
if (node.type) {
|
|
208
|
+
const type = checker.getTypeAtLocation(node.type);
|
|
209
|
+
|
|
210
|
+
if (type.flags & ts.TypeFlags.Any) {
|
|
211
|
+
anyCount++;
|
|
212
|
+
} else if (type.flags & ts.TypeFlags.Unknown) {
|
|
213
|
+
unknownCount++;
|
|
214
|
+
} else {
|
|
215
|
+
typedSymbols++;
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
// No explicit type annotation - check inferred type
|
|
219
|
+
const symbol = checker.getSymbolAtLocation(node.name);
|
|
220
|
+
if (symbol) {
|
|
221
|
+
const type = checker.getTypeOfSymbolAtLocation(symbol, node);
|
|
222
|
+
|
|
223
|
+
if (type.flags & ts.TypeFlags.Any) {
|
|
224
|
+
anyCount++;
|
|
225
|
+
} else {
|
|
226
|
+
typedSymbols++;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
ts.forEachChild(node, visit);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const coverage = totalSymbols > 0 ? (typedSymbols / totalSymbols) * 100 : 100;
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
coverage: Math.round(coverage * 10) / 10,
|
|
240
|
+
totalSymbols,
|
|
241
|
+
typedSymbols,
|
|
242
|
+
anyCount,
|
|
243
|
+
unknownCount,
|
|
244
|
+
tsIgnoreCount,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Find type dependencies and inheritance chains
|
|
250
|
+
*/
|
|
251
|
+
function findTypeDependencies(program, packageName) {
|
|
252
|
+
const checker = program.getTypeChecker();
|
|
253
|
+
const sourceFiles = program.getSourceFiles().filter(
|
|
254
|
+
(sf) => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
const imports = new Set();
|
|
258
|
+
const extendsChains = [];
|
|
259
|
+
const implementsChains = [];
|
|
260
|
+
|
|
261
|
+
for (const sourceFile of sourceFiles) {
|
|
262
|
+
ts.forEachChild(sourceFile, function visit(node) {
|
|
263
|
+
// Track type imports
|
|
264
|
+
if (ts.isImportDeclaration(node)) {
|
|
265
|
+
const moduleSpecifier = node.moduleSpecifier;
|
|
266
|
+
if (ts.isStringLiteral(moduleSpecifier)) {
|
|
267
|
+
const moduleName = moduleSpecifier.text;
|
|
268
|
+
if (moduleName.startsWith('@kb-labs/')) {
|
|
269
|
+
imports.add(moduleName);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Track interface/class extensions
|
|
275
|
+
if (ts.isInterfaceDeclaration(node) || ts.isClassDeclaration(node)) {
|
|
276
|
+
if (node.heritageClauses) {
|
|
277
|
+
for (const clause of node.heritageClauses) {
|
|
278
|
+
for (const type of clause.types) {
|
|
279
|
+
const typeName = type.expression.getText();
|
|
280
|
+
|
|
281
|
+
if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
|
|
282
|
+
extendsChains.push({
|
|
283
|
+
child: node.name?.getText() || 'anonymous',
|
|
284
|
+
parent: typeName,
|
|
285
|
+
file: sourceFile.fileName,
|
|
286
|
+
});
|
|
287
|
+
} else if (clause.token === ts.SyntaxKind.ImplementsKeyword) {
|
|
288
|
+
implementsChains.push({
|
|
289
|
+
class: node.name?.getText() || 'anonymous',
|
|
290
|
+
interface: typeName,
|
|
291
|
+
file: sourceFile.fileName,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
ts.forEachChild(node, visit);
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
imports: Array.from(imports),
|
|
305
|
+
extends: extendsChains,
|
|
306
|
+
implements: implementsChains,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Audit a single package
|
|
312
|
+
*/
|
|
313
|
+
function auditPackage(packageInfo) {
|
|
314
|
+
const { name, dir, tsconfigPath } = packageInfo;
|
|
315
|
+
|
|
316
|
+
log(` Analyzing ${name}...`, 'gray');
|
|
317
|
+
|
|
318
|
+
const program = createProgram(dir, tsconfigPath);
|
|
319
|
+
|
|
320
|
+
if (!program) {
|
|
321
|
+
return {
|
|
322
|
+
name,
|
|
323
|
+
success: false,
|
|
324
|
+
reason: 'Failed to create TypeScript program',
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const { errors, warnings } = analyzeTypeErrors(program, name);
|
|
329
|
+
const coverage = calculateTypeCoverage(program);
|
|
330
|
+
const dependencies = findTypeDependencies(program, name);
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
name,
|
|
334
|
+
success: true,
|
|
335
|
+
errors,
|
|
336
|
+
warnings,
|
|
337
|
+
coverage,
|
|
338
|
+
dependencies,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Build impact graph (what breaks if this package has type errors)
|
|
344
|
+
*/
|
|
345
|
+
function buildImpactGraph(results) {
|
|
346
|
+
const graph = new Map();
|
|
347
|
+
|
|
348
|
+
// Build reverse dependency map
|
|
349
|
+
for (const result of results) {
|
|
350
|
+
if (!result.success) {continue;}
|
|
351
|
+
|
|
352
|
+
graph.set(result.name, new Set());
|
|
353
|
+
|
|
354
|
+
for (const dep of result.dependencies.imports) {
|
|
355
|
+
if (!graph.has(dep)) {
|
|
356
|
+
graph.set(dep, new Set());
|
|
357
|
+
}
|
|
358
|
+
graph.get(dep).add(result.name);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return graph;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Calculate impact score (how many packages depend on this)
|
|
367
|
+
*/
|
|
368
|
+
function calculateImpact(packageName, impactGraph) {
|
|
369
|
+
const visited = new Set();
|
|
370
|
+
const queue = [packageName];
|
|
371
|
+
|
|
372
|
+
while (queue.length > 0) {
|
|
373
|
+
const current = queue.shift();
|
|
374
|
+
if (visited.has(current)) {continue;}
|
|
375
|
+
visited.add(current);
|
|
376
|
+
|
|
377
|
+
const dependents = impactGraph.get(current);
|
|
378
|
+
if (dependents) {
|
|
379
|
+
for (const dep of dependents) {
|
|
380
|
+
if (!visited.has(dep)) {
|
|
381
|
+
queue.push(dep);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return visited.size - 1; // Exclude the package itself
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Print audit report
|
|
392
|
+
*/
|
|
393
|
+
function printAuditReport(results, impactGraph) {
|
|
394
|
+
log('\nš TypeScript Type Safety Audit Report\n', 'bold');
|
|
395
|
+
|
|
396
|
+
const successful = results.filter((r) => r.success);
|
|
397
|
+
const failed = results.filter((r) => !r.success);
|
|
398
|
+
|
|
399
|
+
log(`Analyzed ${successful.length} package(s)\n`, 'gray');
|
|
400
|
+
|
|
401
|
+
// Critical Issues
|
|
402
|
+
const withErrors = successful.filter((r) => r.errors.length > 0);
|
|
403
|
+
|
|
404
|
+
if (withErrors.length > 0) {
|
|
405
|
+
log(`ā Critical Issues (${withErrors.length} packages with type errors):\n`, 'red');
|
|
406
|
+
|
|
407
|
+
for (const result of withErrors.slice(0, 5)) {
|
|
408
|
+
const impact = calculateImpact(result.name, impactGraph);
|
|
409
|
+
|
|
410
|
+
log(` ${result.name}`, 'yellow');
|
|
411
|
+
log(` ${result.errors.length} error(s) - impacts ${impact} package(s)`, 'red');
|
|
412
|
+
|
|
413
|
+
if (options.verbose) {
|
|
414
|
+
for (const error of result.errors.slice(0, 3)) {
|
|
415
|
+
const relPath = error.file.replace(process.cwd(), '.');
|
|
416
|
+
log(` āā ${relPath}:${error.line}:${error.column}`, 'gray');
|
|
417
|
+
log(` ${error.message}`, 'gray');
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (withErrors.length > 5) {
|
|
423
|
+
log(` ... and ${withErrors.length - 5} more packages with errors`, 'gray');
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
log('', 'reset');
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Warnings
|
|
430
|
+
if (!options.errorsOnly) {
|
|
431
|
+
const totalWarnings = successful.reduce((sum, r) => sum + r.warnings.length, 0);
|
|
432
|
+
|
|
433
|
+
if (totalWarnings > 0) {
|
|
434
|
+
log(`ā ļø Warnings (${totalWarnings} total):\n`, 'yellow');
|
|
435
|
+
|
|
436
|
+
const topWarnings = successful
|
|
437
|
+
.filter((r) => r.warnings.length > 0)
|
|
438
|
+
.sort((a, b) => b.warnings.length - a.warnings.length)
|
|
439
|
+
.slice(0, 5);
|
|
440
|
+
|
|
441
|
+
for (const result of topWarnings) {
|
|
442
|
+
log(` ${result.name}: ${result.warnings.length} warning(s)`, 'gray');
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
log('', 'reset');
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Type Safety Issues
|
|
450
|
+
if (!options.errorsOnly) {
|
|
451
|
+
const anyUsage = successful.filter((r) => r.coverage.anyCount > 0);
|
|
452
|
+
const tsIgnoreUsage = successful.filter((r) => r.coverage.tsIgnoreCount > 0);
|
|
453
|
+
|
|
454
|
+
if (anyUsage.length > 0 || tsIgnoreUsage.length > 0) {
|
|
455
|
+
log(`š Type Safety Issues:\n`, 'yellow');
|
|
456
|
+
|
|
457
|
+
const totalAny = successful.reduce((sum, r) => sum + r.coverage.anyCount, 0);
|
|
458
|
+
const totalTsIgnore = successful.reduce((sum, r) => sum + r.coverage.tsIgnoreCount, 0);
|
|
459
|
+
|
|
460
|
+
log(` ${totalAny} usage(s) of 'any' type`, totalAny > 50 ? 'red' : 'yellow');
|
|
461
|
+
log(` ${totalTsIgnore} @ts-ignore comment(s)`, totalTsIgnore > 20 ? 'red' : 'yellow');
|
|
462
|
+
|
|
463
|
+
log('', 'reset');
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Type Coverage
|
|
468
|
+
if (options.coverage || !options.errorsOnly) {
|
|
469
|
+
log(`š Type Coverage:\n`, 'blue');
|
|
470
|
+
|
|
471
|
+
const sorted = [...successful].sort((a, b) => a.coverage.coverage - b.coverage.coverage);
|
|
472
|
+
|
|
473
|
+
const excellent = sorted.filter((r) => r.coverage.coverage >= 90);
|
|
474
|
+
const good = sorted.filter((r) => r.coverage.coverage >= 70 && r.coverage.coverage < 90);
|
|
475
|
+
const poor = sorted.filter((r) => r.coverage.coverage < 70);
|
|
476
|
+
|
|
477
|
+
log(` ā
Excellent (ā„90%): ${excellent.length} packages`, 'green');
|
|
478
|
+
log(` ā ļø Good (70-90%): ${good.length} packages`, 'yellow');
|
|
479
|
+
log(` ā Poor (<70%): ${poor.length} packages`, 'red');
|
|
480
|
+
|
|
481
|
+
if (options.verbose || options.coverage) {
|
|
482
|
+
log('\n Top packages by coverage:', 'cyan');
|
|
483
|
+
for (const result of sorted.slice(-5).reverse()) {
|
|
484
|
+
const coverage = result.coverage.coverage;
|
|
485
|
+
const color = coverage >= 90 ? 'green' : coverage >= 70 ? 'yellow' : 'red';
|
|
486
|
+
log(` ${result.name.padEnd(35)} ${coverage.toFixed(1)}%`, color);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
log('\n Bottom packages by coverage:', 'cyan');
|
|
490
|
+
for (const result of sorted.slice(0, 5)) {
|
|
491
|
+
const coverage = result.coverage.coverage;
|
|
492
|
+
const color = coverage >= 90 ? 'green' : coverage >= 70 ? 'yellow' : 'red';
|
|
493
|
+
log(` ${result.name.padEnd(35)} ${coverage.toFixed(1)}%`, color);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
log('', 'reset');
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Summary
|
|
501
|
+
log('ā'.repeat(60) + '\n', 'gray');
|
|
502
|
+
log('š Summary:\n', 'blue');
|
|
503
|
+
|
|
504
|
+
const totalErrors = successful.reduce((sum, r) => sum + r.errors.length, 0);
|
|
505
|
+
const totalWarnings = successful.reduce((sum, r) => sum + r.warnings.length, 0);
|
|
506
|
+
const avgCoverage =
|
|
507
|
+
successful.reduce((sum, r) => sum + r.coverage.coverage, 0) / successful.length;
|
|
508
|
+
|
|
509
|
+
log(` Total packages: ${successful.length}`, 'cyan');
|
|
510
|
+
log(` ā Type errors: ${totalErrors}`, totalErrors > 0 ? 'red' : 'green');
|
|
511
|
+
log(` ā ļø Warnings: ${totalWarnings}`, totalWarnings > 0 ? 'yellow' : 'green');
|
|
512
|
+
log(` š Avg coverage: ${avgCoverage.toFixed(1)}%`, avgCoverage >= 80 ? 'green' : 'yellow');
|
|
513
|
+
|
|
514
|
+
if (failed.length > 0) {
|
|
515
|
+
log(` ā ļø Failed to analyze: ${failed.length}`, 'yellow');
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
log('', 'reset');
|
|
519
|
+
|
|
520
|
+
// Tips
|
|
521
|
+
log('š” Tips:', 'blue');
|
|
522
|
+
log(' ⢠Use --errors-only to show only critical issues', 'gray');
|
|
523
|
+
log(' ⢠Use --coverage to see detailed coverage report', 'gray');
|
|
524
|
+
log(' ⢠Use --package=name to audit specific package', 'gray');
|
|
525
|
+
log(' ⢠Fix type errors to improve type safety', 'gray');
|
|
526
|
+
log('', 'reset');
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Main function
|
|
531
|
+
*/
|
|
532
|
+
async function main() {
|
|
533
|
+
const rootDir = process.cwd();
|
|
534
|
+
|
|
535
|
+
if (!options.json) {
|
|
536
|
+
log('\nš KB Labs TypeScript Type Safety Audit\n', 'bold');
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
let packages = findPackages(rootDir);
|
|
540
|
+
|
|
541
|
+
if (options.package) {
|
|
542
|
+
const fullPackageName = options.package.startsWith('@kb-labs/')
|
|
543
|
+
? options.package
|
|
544
|
+
: `@kb-labs/${options.package}`;
|
|
545
|
+
|
|
546
|
+
packages = packages.filter((p) => p.name === fullPackageName);
|
|
547
|
+
|
|
548
|
+
if (packages.length === 0) {
|
|
549
|
+
log(`ā ļø Package not found: ${fullPackageName}`, 'yellow');
|
|
550
|
+
process.exit(1);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (packages.length === 0) {
|
|
555
|
+
log('ā ļø No packages found with TypeScript configuration', 'yellow');
|
|
556
|
+
process.exit(0);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
log(`Found ${packages.length} package(s) to audit\n`, 'gray');
|
|
560
|
+
|
|
561
|
+
// Audit all packages
|
|
562
|
+
const results = [];
|
|
563
|
+
for (const pkg of packages) {
|
|
564
|
+
const result = auditPackage(pkg);
|
|
565
|
+
results.push(result);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
const impactGraph = buildImpactGraph(results);
|
|
569
|
+
|
|
570
|
+
if (options.json) {
|
|
571
|
+
const successful = results.filter((r) => r.success);
|
|
572
|
+
const totalErrors = successful.reduce((sum, r) => sum + r.errors.length, 0);
|
|
573
|
+
const totalWarnings = successful.reduce((sum, r) => sum + r.warnings.length, 0);
|
|
574
|
+
const avgCoverage =
|
|
575
|
+
successful.reduce((sum, r) => sum + r.coverage.coverage, 0) / successful.length;
|
|
576
|
+
|
|
577
|
+
const output = {
|
|
578
|
+
summary: {
|
|
579
|
+
total: results.length,
|
|
580
|
+
successful: successful.length,
|
|
581
|
+
failed: results.filter((r) => !r.success).length,
|
|
582
|
+
totalErrors,
|
|
583
|
+
totalWarnings,
|
|
584
|
+
avgCoverage: Math.round(avgCoverage * 10) / 10,
|
|
585
|
+
},
|
|
586
|
+
packages: results.map((r) => ({
|
|
587
|
+
name: r.name,
|
|
588
|
+
success: r.success,
|
|
589
|
+
errors: r.errors?.length || 0,
|
|
590
|
+
warnings: r.warnings?.length || 0,
|
|
591
|
+
coverage: r.coverage?.coverage,
|
|
592
|
+
anyCount: r.coverage?.anyCount,
|
|
593
|
+
tsIgnoreCount: r.coverage?.tsIgnoreCount,
|
|
594
|
+
impact: calculateImpact(r.name, impactGraph),
|
|
595
|
+
})),
|
|
596
|
+
issues: results
|
|
597
|
+
.filter((r) => r.success && r.errors.length > 0)
|
|
598
|
+
.map((r) => ({
|
|
599
|
+
package: r.name,
|
|
600
|
+
errors: r.errors,
|
|
601
|
+
impact: calculateImpact(r.name, impactGraph),
|
|
602
|
+
})),
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
console.log(JSON.stringify(output, null, 2));
|
|
606
|
+
} else {
|
|
607
|
+
printAuditReport(results, impactGraph);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// Exit with error if there are type errors
|
|
611
|
+
const hasErrors = results.some((r) => r.success && r.errors.length > 0);
|
|
612
|
+
process.exit(hasErrors ? 1 : 0);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
main();
|