{"id":15832,"library":"sovra","title":"Sovra Test Decider","description":"Sovra is a high-performance, Rust-based utility for monorepos designed to identify affected test files by analyzing code changes and their import graphs. It leverages Oxc for its underlying dependency resolution, ensuring fast execution. The library provides a Node.js API to determine which tests should be run in a given CI pipeline, significantly speeding up large repository workflows. It ships with comprehensive TypeScript support, including path aliases, and offers configurable resolver options that align with `oxc-resolver`. Currently at version 0.2.0, it is in active development, focusing on performance and accuracy for JavaScript and TypeScript projects. Its primary differentiator is its Rust-powered speed and its direct integration for test selection based on file changes.","status":"active","version":"0.2.0","language":"javascript","source_language":"en","source_url":"https://github.com/oblador/sovra","tags":["javascript","typescript"],"install":[{"cmd":"npm install sovra","lang":"bash","label":"npm"},{"cmd":"yarn add sovra","lang":"bash","label":"yarn"},{"cmd":"pnpm add sovra","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Used in common usage patterns for finding test files in a project.","package":"glob","optional":false}],"imports":[{"note":"Sovra primarily exports named functions for its API. Prefer ESM imports for type safety and modern JavaScript environments.","wrong":"import getAffected from 'sovra';\nconst getAffected = require('sovra');","symbol":"getAffected","correct":"import { getAffected } from 'sovra';"},{"note":"While `sovra` uses `oxc-resolver` internally, its types for `OxcResolverOptions` are re-exported or provided as part of `sovra`'s own type definitions, often accessible via a specific subpath or implicitly.","wrong":"import { OxcResolverOptions } from 'oxc-resolver';","symbol":"OxcResolverOptions","correct":"import { type OxcResolverOptions } from 'sovra/resolver';"},{"note":"For CommonJS environments, destructuring directly from `require('sovra')` is the correct approach as `getAffected` is a named export.","wrong":"const sovra = require('sovra');\nconst getAffected = sovra.getAffected;","symbol":"CommonJS require","correct":"const { getAffected } = require('sovra');"}],"quickstart":{"code":"import { getAffected } from \"sovra\";\nimport { execSync } from \"node:child_process\";\nimport { glob } from \"glob\";\n\nasync function runAffectedTests() {\n  const testFiles = await glob(\"src/**/*.spec.{ts,tsx}\");\n  const changedFiles = execSync(\"git diff --name-only main\", { encoding: \"utf8\" })\n    .trim()\n    .split(\"\\n\")\n    .filter(Boolean);\n\n  if (testFiles.length === 0 || changedFiles.length === 0) {\n    console.log(\"No test files or changed files found.\");\n    return;\n  }\n\n  const resolverOptions = {\n    tsconfig: {\n      configFile: \"tsconfig.json\"\n    }\n  };\n\n  const affected = await getAffected(testFiles, changedFiles, resolverOptions);\n\n  if (affected.errors && affected.errors.length > 0) {\n    console.error(\"Errors determining affected files:\", ...affected.errors);\n  } else if (affected.files && affected.files.length > 0) {\n    console.log(\"Affected test files:\", affected.files);\n    // Example: Run these tests with your test runner\n    // execSync(`pnpm jest ${affected.files.join(' ')}`, { stdio: 'inherit' });\n  } else {\n    console.log(\"No tests affected by the changes.\");\n  }\n}\n\nrunAffectedTests().catch(console.error);","lang":"typescript","description":"Demonstrates how to use `getAffected` to find test files impacted by recent Git changes, leveraging `glob` for file discovery and `tsconfig.json` for path resolution."},"warnings":[{"fix":"Refactor your codebase to use static import paths that can be resolved during static analysis. Avoid dynamic import or require patterns where possible for files that need to be tracked by Sovra.","message":"Sovra cannot analyze imports that use variables or expressions, as these can only be resolved at runtime. This includes patterns like `require(process.env.SOME_VAR)` or `import(`./file.${platform}.mjs`).","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Monitor the project's GitHub repository and release notes for upcoming breaking changes. Consider pinning to exact patch versions or reviewing changes when updating minor versions in production environments.","message":"As of version 0.2.0, Sovra is in early development. While stable for its current feature set, future minor versions might introduce breaking changes to the API surface as the project matures.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Modify the source code to use only static import paths that can be resolved at build time. Sovra's Rust-based analysis requires fixed import declarations.","cause":"Attempting to use `sovra` to analyze files containing import or require statements with dynamic paths (e.g., `require(variable)` or `import(`template-string/${var}`).","error":"Error: Dynamic import/require not supported for analysis."},{"fix":"Ensure you check `affected.files` and `affected.errors` for existence before attempting to access them, as shown in the quickstart example. Always wrap calls to `getAffected` in a `try...catch` block if not awaiting a Promise directly.","cause":"Incorrectly accessing properties from the result of `getAffected` without handling potential `undefined` or null results, or if the function threw an unexpected error.","error":"TypeError: Cannot read properties of undefined (reading 'files') or (reading 'errors')"},{"fix":"Install `glob` as a development dependency (`npm install -D glob` or `yarn add -D glob`). `node:child_process` is a built-in Node.js module and does not require installation; ensure your Node.js version is compatible and correctly referenced.","cause":"The `glob` package or `node:child_process` (when used with `execSync`) are used in common examples but are not direct dependencies of `sovra` itself.","error":"Error: Cannot find module 'glob' or 'node:child_process'"}],"ecosystem":"npm"}