{"id":49400124,"url":"https://github.com/kyungseopk1m/semver-checks","last_synced_at":"2026-06-13T17:00:41.748Z","repository":{"id":350600730,"uuid":"1206920433","full_name":"kyungseopk1m/semver-checks","owner":"kyungseopk1m","description":"Stop guessing semver bumps. Diffs your TypeScript API and tells you exactly what to bump.","archived":false,"fork":false,"pushed_at":"2026-06-12T14:59:28.000Z","size":365,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-12T16:29:22.937Z","etag":null,"topics":["breaking-changes","cli","developer-tools","devtools","npm","semantic-versioning","semver","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/semver-checks","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kyungseopk1m.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-10T11:43:39.000Z","updated_at":"2026-06-12T14:59:32.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kyungseopk1m/semver-checks","commit_stats":null,"previous_names":["kyungseopk1m/semver-checks"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/kyungseopk1m/semver-checks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyungseopk1m%2Fsemver-checks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyungseopk1m%2Fsemver-checks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyungseopk1m%2Fsemver-checks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyungseopk1m%2Fsemver-checks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kyungseopk1m","download_url":"https://codeload.github.com/kyungseopk1m/semver-checks/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyungseopk1m%2Fsemver-checks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34292326,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-13T02:00:06.617Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["breaking-changes","cli","developer-tools","devtools","npm","semantic-versioning","semver","typescript"],"created_at":"2026-04-28T17:21:57.006Z","updated_at":"2026-06-13T17:00:41.741Z","avatar_url":"https://github.com/kyungseopk1m.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![npm version](https://img.shields.io/npm/v/semver-checks.svg)](https://www.npmjs.com/package/semver-checks)\n[![CI](https://github.com/kyungseopk1m/semver-checks/actions/workflows/ci.yml/badge.svg)](https://github.com/kyungseopk1m/semver-checks/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Node.js Version](https://img.shields.io/badge/node-%3E%3D18.0.0-green.svg)](https://nodejs.org/)\n\n# semver-checks\n\nLint your TypeScript library's public API for semver violations.\n\n```bash\nnpx semver-checks compare v1.0.0 HEAD\n```\n\n- [Why semver-checks?](#why-semver-checks)\n- [Quick Start](#quick-start)\n- [Programmatic API](#programmatic-api)\n- [Change Rules](#change-rules)\n- [CLI Reference](#cli-reference)\n- [MCP Server](#mcp-server)\n- [CI Integration](#ci-integration)\n- [Comparison with Other Tools](#comparison-with-other-tools)\n- [How It Works](#how-it-works)\n- [FAQ](#faq)\n\n## Why semver-checks?\n\nTools like `semantic-release` and `changesets` rely on developers writing correct commit messages. In practice, commit messages don't always reflect actual API impact — a \"small refactor\" that removes a required export gets published as a patch, and downstream consumers' builds break.\n\nsemver-checks **analyzes your TypeScript public API directly** using [ts-morph](https://github.com/dsherret/ts-morph) and recommends the correct SemVer bump based on what actually changed in the type signatures — not what the commit message says.\n\n```typescript\n// v1.0.0\nexport interface Config { host: string; port: number; }\n\n// Developer writes: \"fix: add missing timeout config\"\n// Published as patch — but this is a MAJOR change:\nexport interface Config { host: string; port: number; timeout: number; }\n//                                                    ^^^^^^^^^^^^^^^^ required-property-added\n```\n\n```typescript\n// v1.0.0\nexport function findUser(id: string): User | null;\n\n// Developer writes: \"refactor: simplify findUser return\"\n// Published as minor — but consumers checking `result === null` silently break at runtime:\nexport function findUser(id: string): User;\n//                                    ^^^^ return-type-changed (MAJOR)\n```\n\nsemver-checks is complementary to your existing release workflow. Use it as a **verification step** before publishing — it tells you whether your intended bump is safe, or whether you're about to ship a breaking change by accident.\n\n## Quick Start\n\n```bash\nnpm install --save-dev semver-checks\n```\n\nCompare a git tag to the current working tree:\n\n```bash\nnpx semver-checks compare v1.0.0 HEAD\n```\n\nCompare the **published npm release** against your working tree — answers \"is my current change a breaking release?\" without needing git tags:\n\n```bash\nnpx semver-checks compare your-package@latest\n```\n\nA `\u003cpackage\u003e@\u003cversion\u003e` argument is fetched from the npm registry (via `npm pack`) and used as the old version. Concrete versions, ranges, and common dist-tags are auto-detected (`your-package@1.2.3`, `your-package@^1`, `your-package@next`). For an uncommon dist-tag, make the intent explicit with the `npm:` prefix or `--old-as npm` (`npm:your-package@my-custom-tag`) so it isn't mistaken for a git ref.\n\nCompare two local directories:\n\n```bash\nnpx semver-checks compare ./old ./new\n```\n\nExisting relative paths without a `./` prefix are also treated as local directories:\n\n```bash\nnpx semver-checks compare packages/core packages/core-next\n```\n\nIf a git ref collides with an existing path name, force ref interpretation explicitly:\n\n```bash\nnpx semver-checks compare main HEAD --old-as ref\n```\n\nOutput as JSON, Markdown (for PR comments), or GitHub Actions annotations:\n\n```bash\nnpx semver-checks compare v1.0.0 HEAD --format json\nnpx semver-checks compare v1.0.0 HEAD --format markdown\nnpx semver-checks compare v1.0.0 HEAD --format github\n```\n\nFail in CI if breaking changes are detected (`exit 1`):\n\n```bash\nnpx semver-checks compare v1.0.0 HEAD --strict\n```\n\nInspect the API surface of the current or a past version:\n\n```bash\nnpx semver-checks snapshot\nnpx semver-checks snapshot --ref v1.0.0\nnpx semver-checks snapshot --npm lodash@4.17.21\n```\n\n### Multiple entry points\n\nWhen `package.json` declares an `\"exports\"` map with several subpaths, every\nsubpath with a declared `.d.ts` entry is extracted and compared independently.\nAdding a subpath is a MINOR change and removing one is MAJOR; a change inside a\nsubpath is reported with a `#` separator (e.g. `./utils#helper`). No flags are\nneeded — the map is auto-detected.\n\nFor projects without an `\"exports\"` map, pass multiple entries explicitly by\nrepeating `--entry` or comma-separating them:\n\n```bash\nnpx semver-checks compare v1.0.0 HEAD --entry src/index.ts --entry src/utils.ts\nnpx semver-checks compare v1.0.0 HEAD --entry src/index.ts,src/utils.ts\n```\n\n### Example output\n\n```\nsemver-checks — Recommended bump: MAJOR\n  major: 2  minor: 1  patch: 0\n\n  Breaking Changes (MAJOR)\n  ✗ Required property 'timeout' was added to interface 'Config'\n      now: number\n  ✗ Type alias 'UserId' changed\n      before: string | number\n      after:  string\n\n  New Features (MINOR)\n  + Export 'createConfig' was added\n```\n\n## Programmatic API\n\n```typescript\nimport { compare, extract } from 'semver-checks';\n\nconst report = await compare({\n  oldSource: { type: 'git', ref: 'v1.0.0' },\n  newSource: { type: 'path', path: '.' },\n});\n\nconsole.log(report.recommended); // 'major' | 'minor' | 'patch'\nconsole.log(report.changes);     // ApiChange[]\nconsole.log(report.summary);     // { major: 2, minor: 1, patch: 0 }\n```\n\n```typescript\ninterface CompareOptions {\n  oldSource: SourceRef;\n  newSource: SourceRef;\n  entry?: string; // Optional: specify entry point (e.g., 'src/index.ts')\n  installDeps?: boolean; // Optional: install deps before analyzing local path sources\n}\n\ntype SourceRef =\n  | { type: 'path'; path: string }\n  | { type: 'git'; ref: string; cwd?: string }\n  | { type: 'npm'; spec: string }; // e.g. { type: 'npm', spec: 'lodash@4.17.21' }\n\ninterface SemverReport {\n  recommended: 'major' | 'minor' | 'patch';\n  changes: ApiChange[];\n  summary: { major: number; minor: number; patch: number };\n}\n\ninterface ApiChange {\n  kind: ChangeKind;\n  severity: 'major' | 'minor' | 'patch';\n  symbolPath: string;\n  message: string;\n  oldValue?: string;\n  newValue?: string;\n}\n```\n\nYou can also extract a snapshot independently:\n\n```typescript\nimport { extract } from 'semver-checks';\n\nconst snapshot = await extract({ projectPath: '.' });\n// Snapshots are keyed by export subpath ('.' is the root entry; additional\n// subpaths come from the package.json \"exports\" map).\nconsole.log(Object.keys(snapshot.entrypoints['.'])); // root entry's symbol names\n```\n\n## Change Rules\n\n### Breaking changes (MAJOR)\n\n| Rule | Description |\n|------|---|\n| `export-removed` | A public export was removed |\n| `required-param-added` | A required parameter was added to a function |\n| `param-removed` | A parameter was removed |\n| `param-type-changed` | A parameter's type changed |\n| `return-type-changed` | A function's return type changed |\n| `property-removed` | An interface property was removed |\n| `required-property-added` | A required property was added to an interface |\n| `property-type-changed` | An interface property's type changed |\n| `interface-property-became-required` | An optional interface property became required |\n| `interface-property-became-readonly` | An interface property changed from mutable to readonly |\n| `interface-method-removed` | An interface method was removed |\n| `required-interface-method-added` | A required interface method was added |\n| `interface-method-signature-changed` | An interface method's signature changed |\n| `enum-member-removed` | An enum member was removed |\n| `enum-member-value-changed` | An enum member's value changed |\n| `class-constructor-changed` | A class constructor's signature changed |\n| `class-method-removed` | A public class method was removed |\n| `class-method-signature-changed` | A public class method's signature changed |\n| `class-method-became-static` | A class method changed from instance to static |\n| `class-method-became-instance` | A class method changed from static to instance |\n| `class-property-removed` | A public class property was removed |\n| `class-property-type-changed` | A public class property's type changed |\n| `class-property-became-static` | A class property changed from instance to static |\n| `class-property-became-instance` | A class property changed from static to instance |\n| `class-property-became-required` | An optional class property became required |\n| `required-class-property-added` | A required class property was added |\n| `class-property-became-readonly` | A public class property changed from mutable to readonly |\n| `generic-param-required` | A required generic parameter was added |\n| `generic-param-removed` | A generic parameter was removed |\n| `generic-constraint-changed` | A generic parameter's constraint changed |\n| `overload-removed` | A function overload was removed |\n| `type-alias-changed` | A type alias definition changed |\n| `variable-type-changed` | An exported variable's type changed |\n\n### New features (MINOR)\n\n| Rule | Description |\n|------|---|\n| `export-added` | A new public export was added |\n| `optional-param-added` | An optional parameter was added |\n| `optional-property-added` | An optional property was added to an interface |\n| `interface-method-added` | An optional interface method was added |\n| `interface-property-became-optional` | A required interface property became optional |\n| `interface-property-became-mutable` | An interface property changed from readonly to mutable |\n| `enum-member-added` | An enum member was added |\n| `overload-added` | A function overload was added |\n| `generic-param-with-default` | A generic parameter with a default was added |\n| `class-method-added` | A public class method was added |\n| `class-property-added` | An optional public class property was added |\n| `class-property-became-optional` | A required class property became optional |\n| `class-property-became-mutable` | A public class property changed from readonly to mutable |\n| `param-type-widened` | A parameter's type was widened — existing callers still type-check (contravariant) |\n| `return-type-narrowed` | A function's return type was narrowed — existing consumers still type-check (covariant) |\n\n## CLI Reference\n\n### compare\n\n```\nsemver-checks compare \u003cold\u003e [new] [options]\n```\n\n| Option | Short | Description | Default |\n|--------|-------|---|---|\n| `--entry \u003cpath\u003e` | `-e` | Entry file path (e.g., `src/index.ts`); repeat or comma-separate for multiple entries | Auto-detect |\n| `--format \u003ctype\u003e` | `-f` | `text`, `json`, `markdown`, or `github` | `text` |\n| `--strict` | `-s` | Exit 1 if breaking changes are found | `false` |\n| `--install-deps` |  | Install dependencies before analyzing local path inputs | `false` |\n| `--old-as \u003ckind\u003e` |  | Force `\u003cold\u003e` to be interpreted as `path`, `ref` (or `git`), or `npm` | Auto-detect |\n| `--new-as \u003ckind\u003e` |  | Force `[new]` to be interpreted as `path`, `ref` (or `git`), or `npm` | Auto-detect |\n\n**Arguments:**\n- `\u003cold\u003e`: an npm spec (`pkg@version`), a git ref (tag, branch, commit SHA), or a local directory path for the old version\n- `[new]`: npm spec, git ref, or path for the new version; defaults to `.` (current directory)\n\n**Output formats:**\n- `text` — colored human-readable summary (default)\n- `json` — the structured `SemverReport`\n- `markdown` — a Markdown summary suitable for a PR comment or `$GITHUB_STEP_SUMMARY`\n- `github` — [GitHub Actions workflow commands](https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions) (`::error::` / `::warning::`) that surface inline on the PR\n\n\u003e If an argument matches an existing filesystem path, semver-checks treats it as a path source even without a `./` prefix.\n\u003e A `\u003cpackage\u003e@\u003cversion\u003e` shape that is not an existing path is resolved from the npm registry.\n\u003e A plain ref (`v1.2.3`, `main`) has no `@version` and is resolved as a git ref.\n\u003e A git ref that happens to share the `name@version` shape (e.g. a lerna/monorepo tag like `pkg@1.0.0`) would be auto-detected as an npm spec — force git resolution with `--old-as ref` in that case.\n\u003e Use `--old-as ref` / `--new-as ref` (or `--old-as npm`) when auto-detection guesses wrong.\n\n\u003e When using git refs, the command must run inside a git repository. The ref is resolved\n\u003e against the working directory's repo.\n\n### snapshot\n\n```\nsemver-checks snapshot [path] [options]\n```\n\n| Option | Short | Description |\n|--------|-------|---|\n| `--ref \u003cref\u003e` | `-r` | Use a git ref instead of a local path |\n| `--npm \u003cspec\u003e` |  | Snapshot a published npm package (e.g. `lodash@4.17.21`) |\n| `--entry \u003cpath\u003e` | `-e` | Entry file path; repeat or comma-separate for multiple entries |\n| `--install-deps` |  | Install dependencies before analyzing a local path |\n\n**Arguments:**\n- `[path]`: project path; defaults to `.` (current directory)\n\n### Global options\n\n| Option | Description |\n|--------|-------------|\n| `--mcp` | Start semver-checks as an MCP server over stdio |\n\n### Environment variables\n\n| Variable | Description |\n|----------|---|\n| `SEMVER_CHECKS_VERBOSE=1` | Print warnings for skipped symbols, type resolution failures, and dependency install issues |\n\n## MCP Server\n\nsemver-checks ships as a [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server, letting AI agents (Claude Code, Codex, Cursor, etc.) call it as a tool directly.\n\n### Setup\n\n```bash\n# Claude Code\nclaude mcp add semver-checks -- npx -y semver-checks --mcp\n```\n\nUse `npx -y` for global-on-demand installs so the MCP server does not block on an interactive \"install this package?\" prompt.\n\nOr add it to your `.claude/settings.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"semver-checks\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"semver-checks\", \"--mcp\"]\n    }\n  }\n}\n```\n\nFor a locally installed version:\n\n```json\n{\n  \"mcpServers\": {\n    \"semver-checks\": {\n      \"command\": \"/path/to/node_modules/.bin/semver-checks\",\n      \"args\": [\"--mcp\"]\n    }\n  }\n}\n```\n\nRelative paths and git refs are resolved from the MCP server process's current working directory. For reliable results, launch the server from the repository you want to inspect, or pass absolute filesystem paths for local sources.\n\n### Available Tools\n\n| Tool | Description |\n|------|-------------|\n| `semver_compare` | Compare two versions and get a SemVer recommendation + change list |\n| `semver_snapshot` | Extract the public API surface of a project as a JSON snapshot |\n| `semver_diff` | Diff two previously extracted snapshots |\n\n#### `semver_compare`\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `old` | string | Yes | Filesystem path or git ref (tag, branch, SHA) |\n| `new` | string | | Filesystem path or git ref. Defaults to `.` |\n| `entry` | string | | Entry file (e.g. `src/index.ts`). Auto-detected if omitted |\n| `oldAs` | `\"path\"` \\| `\"git\"` | | Force interpretation of `old` |\n| `newAs` | `\"path\"` \\| `\"git\"` | | Force interpretation of `new` |\n| `installDeps` | boolean | | Install dependencies before analysis |\n\n`oldAs` and `newAs` accept only `\"path\"` or `\"git\"` in MCP mode.\n\n#### `semver_snapshot`\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `path` | string | | Filesystem path or git ref. Defaults to `.` |\n| `entry` | string | | Entry file |\n| `asGitRef` | boolean | | Treat `path` as a git ref |\n| `installDeps` | boolean | | Install dependencies before analysis |\n\n#### `semver_diff`\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `oldSnapshot` | object | Yes | Snapshot JSON from `semver_snapshot` |\n| `newSnapshot` | object | Yes | Snapshot JSON from `semver_snapshot` |\n\n## CI Integration\n\n### GitHub Action\n\nsemver-checks ships a reusable composite action. The most ergonomic setup compares the **published `latest` release** against the PR's working tree, so it needs no git tags and posts inline annotations on the diff:\n\n```yaml\nname: SemVer Check\n\non:\n  pull_request:\n    branches: [main]\n\njobs:\n  semver-checks:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-node@v4\n        with:\n          node-version: '20'\n      - run: npm ci\n\n      - uses: kyungseopk1m/semver-checks@v0.5.0\n        with:\n          old: 'your-package@latest'   # the published version to compare against\n          format: 'github'             # inline ::error:: / ::warning:: annotations\n          strict: 'true'               # fail the PR on a breaking change\n```\n\n| Input | Description | Default |\n|-------|-------------|---------|\n| `old` | Old version — an npm spec (`pkg@latest`), git ref, or path | _(required)_ |\n| `new` | New version — git ref or path | `.` |\n| `entry` | Entry file (auto-detected from `package.json` when omitted) | _(auto)_ |\n| `format` | `text`, `json`, `markdown`, or `github` | `github` |\n| `strict` | Fail the step (exit 1) on a breaking change | `false` |\n| `version` | semver-checks version to run via `npx` | _(matches the action ref)_ |\n\nA full example that also posts a Markdown summary as a sticky PR comment lives in [`examples/github-actions.yml`](examples/github-actions.yml).\n\n### Without the action\n\nRun the CLI directly — for example, compare the published release to the working tree:\n\n```yaml\n      - name: Check for breaking changes\n        run: npx semver-checks compare your-package@latest --format github --strict\n```\n\nOr compare against a git tag:\n\n```yaml\n      - name: Check for breaking changes\n        run: npx semver-checks compare v$(node -p \"require('./package.json').version\") HEAD --strict\n```\n\n### With snapshot caching\n\nTo avoid re-extracting the baseline on every run, cache the snapshot file:\n\n```yaml\n- name: Restore baseline snapshot\n  id: cache\n  uses: actions/cache@v4\n  with:\n    path: .semver-baseline.json\n    key: semver-${{ github.event.pull_request.base.sha }}\n\n- name: Generate baseline snapshot\n  if: steps.cache.outputs.cache-hit != 'true'\n  run: npx semver-checks snapshot --ref ${{ github.event.pull_request.base.sha }} \u003e .semver-baseline.json\n```\n\n## Comparison with Other Tools\n\n| | semver-checks | semantic-release | changesets | npm-check-updates |\n|---|---|---|---|---|\n| Input | TypeScript AST | Commit messages | Manual YAML | package.json |\n| Detection | 48 typed rules | Keyword matching | Developer-declared | Version range only |\n| Recommendation | Automatic | Based on message format | Manual per change | Dependency updates only |\n\nsemver-checks is **not** a replacement for release tooling — it's a verification layer. Use it alongside `semantic-release` or `changesets` to ensure the declared bump actually matches the code changes.\n\n## How It Works\n\n1. **Extract**: Parse old and new TypeScript source files using ts-morph, building a typed API snapshot (functions, interfaces, enums, classes, type aliases, variables, namespaces)\n2. **Diff**: Compare the two snapshots symbol by symbol — detect additions, removals, and signature changes\n3. **Classify**: Apply the 48 classification rules to each diff, assigning `major`, `minor`, or `patch` severity\n4. **Report**: Return a structured `SemverReport` with the recommended bump and per-change details\n\nFor git ref comparisons, the ref is extracted to a temporary directory via `git archive`, dependencies are installed there if needed, and the directory is cleaned up after extraction. For npm specs, the published tarball is downloaded with `npm pack` and extracted to a temporary directory (no dependency install — the tarball already bundles its build output), then cleaned up. Local path comparisons do not install dependencies unless you opt in with `--install-deps` or `installDeps: true`.\n\n## FAQ\n\n### Will semver-checks catch every semver violation?\n\nNo. The tool catches API surface changes that are mechanically detectable from TypeScript's static type system: removed exports, signature changes, type changes, optionality changes, and so on. It does not detect behavioral changes, documentation changes, or changes hidden behind conditional compilation.\n\n### Does it have false positives?\n\nOccasionally, but less than before. Parameter and return type changes now go through a structural assignability check — a synthesized TypeScript program decides whether a change is a widening or a narrowing — so a widened parameter or a narrowed return type is classified as minor instead of a false major, and structurally equivalent rewrites like `readonly T[]` vs `ReadonlyArray\u003cT\u003e` are treated as no-ops. Other positions (type aliases, variables) are still compared as normalized serialized text: top-level union and intersection member reordering is normalized, so `string | number` and `number | string` no longer differ, but grouped expressions and deeper equivalent rewrites in those positions can still produce diffs. When a type can't be resolved in isolation (imported types, bare generics, or anything involving `any`), the tool falls back to the conservative major verdict.\n\n### Does it support default exports?\n\nNot currently. Only named exports are analyzed.\n\n### Can I compare against a published npm version?\n\nYes. Pass a `\u003cpackage\u003e@\u003cversion\u003e` spec and semver-checks downloads that release from the registry with `npm pack`, extracts the tarball, and analyzes its bundled `.d.ts` declarations:\n\n```bash\nnpx semver-checks compare your-package@latest          # published latest vs working tree\nnpx semver-checks compare your-package@1.0.0 your-package@2.0.0  # two published releases\n```\n\nBecause a published tarball ships compiled `.d.ts` files while your working tree ships `.ts` source, type *representation* can differ slightly between the two sides (TypeScript materializes some inferred types in declarations). Removals, additions, and signature changes are detected reliably; a handful of equivalent-but-reworded types may show up as a noisy diff. Comparing two published releases (`.d.ts` vs `.d.ts`) avoids that asymmetry.\n\n### Can I use it without a tsconfig.json?\n\nFor local path and git-ref inputs, yes — `tsconfig.json` must exist at the project root (or at the path inferred from the `exports` field in `package.json`). For npm specs, a permissive `tsconfig.json` is synthesized automatically when the published package does not ship one.\n\n### What happens if the analyzed project has TypeScript errors?\n\nsemver-checks will print a warning to stderr listing up to 5 errors and continue. Results may be incomplete if type errors affect the API surface. Set `SEMVER_CHECKS_VERBOSE=1` for full diagnostics.\n\n### How is the entry point determined?\n\nsemver-checks looks for the entry file in this order:\n1. The `--entry` flag if provided\n2. The `types` field under `exports['.']` in `package.json`\n3. The top-level `types` or `typings` field in `package.json`\n4. `src/index.ts`, then `index.ts` as fallbacks\n\n### Does it work with monorepos?\n\nYes. Point `--entry` at the package's specific entry file, or run the CLI from the package's subdirectory.\n\n## Requirements\n\n- Node.js ≥ 18.0.0\n- For local path / git-ref inputs: a `tsconfig.json` and TypeScript source files (`.ts`/`.tsx`) in the analyzed project\n- For npm specs: nothing extra — the tarball's bundled `.d.ts` declarations are analyzed, and a `tsconfig.json` is synthesized if absent\n\n### Dual module support\n\nsemver-checks ships both CommonJS and ES module builds:\n\n```javascript\n// ESM\nimport { compare } from 'semver-checks';\n\n// CJS\nconst { compare } = require('semver-checks');\n```\n\n## Contributing\n\nContributions are welcome. Please read [CONTRIBUTING.md](.github/CONTRIBUTING.md) before submitting a pull request.\n\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n\n## Author\n\nKyungseop Kim — [@kyungseopk1m](https://github.com/kyungseopk1m)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyungseopk1m%2Fsemver-checks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkyungseopk1m%2Fsemver-checks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyungseopk1m%2Fsemver-checks/lists"}