sigdiff 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -1,14 +1,18 @@
1
1
  # sigdiff
2
2
 
3
- Diffs the public API surface of a TypeScript project between two git refs and outputs a structured changelog.
3
+ Detects breaking changes in TypeScript projects by diffing the actual API surface between git refs. No config, no setup, no commit conventions.
4
4
 
5
5
  ```bash
6
6
  npx sigdiff v1.0.0..v2.0.0
7
7
  ```
8
8
 
9
- ## Why
9
+ ## Why this exists
10
10
 
11
- Commit messages are a human interpretation of a change — imprecise, incomplete, or missing entirely. `sigdiff` adds a second perspective: what the code actually exported. It catches things commit messages miss, like a signature change buried in a large PR.
11
+ Tools like `changesets` require developers to manually describe what changed. `semantic-release` relies on commit message conventions. `api-extractor` extracts the API surface but leaves semver classification to humans.
12
+
13
+ `sigdiff` skips all of that. Point it at two git refs and it tells you what changed in your exports, classified by semver level. Think [`cargo-semver-checks`](https://github.com/obi1kenobi/cargo-semver-checks) for TypeScript.
14
+
15
+ The goal here is to keep it simple and minimize overhead. No config files. No plugins. No workflow changes.
12
16
 
13
17
  ## Usage
14
18
 
@@ -16,21 +20,23 @@ Commit messages are a human interpretation of a change — imprecise, incomplete
16
20
  # Compare last tag to HEAD
17
21
  npx sigdiff
18
22
 
19
- # Compare two refs
23
+ # Compare two tags
20
24
  npx sigdiff v1.0.0..v2.0.0
21
25
 
26
+ # Any git ref works: branches, commits, relative refs
27
+ npx sigdiff main..feature-branch
28
+ npx sigdiff abc1234..def5678
29
+ npx sigdiff HEAD~5..HEAD
30
+
22
31
  # Scope to a specific entrypoint
23
32
  npx sigdiff --entrypoint src/index.ts
24
33
 
25
34
  # JSON output
26
35
  npx sigdiff --json
27
- ```
28
-
29
- ## What it detects
30
36
 
31
- Functions, arrow functions, interfaces, type aliases, enums, classes, and constants parameters, return types, property shapes, and member names.
32
-
33
- Changes are classified as `major`, `minor`, or `patch` per semver rules.
37
+ # Exit with code 1 if breaking changes are detected (useful for CI)
38
+ npx sigdiff --check
39
+ ```
34
40
 
35
41
  ## Example output
36
42
 
@@ -38,7 +44,7 @@ Changes are classified as `major`, `minor`, or `patch` per semver rules.
38
44
  ### Breaking Changes
39
45
 
40
46
  - Removed function `fetchLegacyData`
41
- - `createUser` signature changed: `(name: string, email: string)` `(opts: CreateUserOpts)`
47
+ - `createUser` signature changed: `(name: string, email: string)` -> `(opts: CreateUserOpts)`
42
48
 
43
49
  ### New
44
50
 
@@ -48,6 +54,34 @@ Changes are classified as `major`, `minor`, or `patch` per semver rules.
48
54
  Suggested version bump: major
49
55
  ```
50
56
 
57
+ ## What it detects
58
+
59
+ Functions, arrow functions, interfaces, type aliases, enums, classes, and constants. Parameters, return types, property shapes, and member names.
60
+
61
+ Changes are classified as `major`, `minor`, or `patch` per semver rules.
62
+
63
+ ## How it compares
64
+
65
+ | | sigdiff | changesets | semantic-release | api-extractor |
66
+ | --------------------- | --------------- | ----------------------- | -------------------- | --------------- |
67
+ | Detects API changes | Automatic (AST) | Manual (you write them) | No (commit messages) | Automatic (AST) |
68
+ | Semver classification | Automatic | Manual | Commit-based | Manual |
69
+ | Changelog output | Yes | Yes | Yes | No |
70
+ | Config required | None | Yes | Yes | Yes |
71
+ | Git ref comparison | Any ref | N/A | N/A | Baseline file |
72
+
73
+ ## CI integration
74
+
75
+ Use `--check` to fail your pipeline when breaking changes are introduced:
76
+
77
+ ```yaml
78
+ # .github/workflows/ci.yml
79
+ - name: API surface check
80
+ run: npx sigdiff origin/main..HEAD --entrypoint src/index.ts --check
81
+ ```
82
+
83
+ Without `--check`, sigdiff always exits 0 and just prints the diff. With `--check`, it exits 1 if any breaking changes are detected, making it easy to gate PRs.
84
+
51
85
  ## Programmatic API
52
86
 
53
87
  ```typescript
@@ -61,10 +95,10 @@ console.log(format(buildResult(classify(diff(before, after)))));
61
95
 
62
96
  ## Notes
63
97
 
64
- - TypeScript only no JS support (no type info to diff)
65
- - Single-package projects only — no monorepo support yet
66
- - Read-only never touches your working tree
67
- - 1 runtime dependency ([`cac`](https://github.com/cacjs/cac))
98
+ - TypeScript only. No JS support (no type info to diff).
99
+ - Single-package projects. No monorepo support yet.
100
+ - Read-only. Never touches your working tree.
101
+ - 1 runtime dependency ([`cac`](https://github.com/cacjs/cac)). ~8 KB published.
68
102
 
69
103
  ## License
70
104
 
package/dist/cli.js CHANGED
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const cac_1 = __importDefault(require("cac"));
8
+ const package_json_1 = require("../package.json");
8
9
  const errors_1 = require("./errors");
9
10
  const git_1 = require("./git");
10
11
  const diff_1 = require("./diff");
@@ -15,6 +16,7 @@ cli
15
16
  .command('[range]', 'Diff the public API surface between two git refs')
16
17
  .option('--entrypoint <path>', 'Scope to a specific file')
17
18
  .option('--json', 'Output as JSON instead of markdown')
19
+ .option('--check', 'Exit with code 1 if breaking changes are detected')
18
20
  .action((range, options) => {
19
21
  try {
20
22
  (0, git_1.assertGitRepo)();
@@ -26,9 +28,12 @@ cli
26
28
  const result = (0, format_1.buildResult)(classified);
27
29
  const output = (0, format_1.format)(result, { json: options.json });
28
30
  process.stdout.write(output);
31
+ if (options.check && result.breaking.length > 0) {
32
+ process.exit(1);
33
+ }
29
34
  }
30
35
  catch (err) {
31
- if (err instanceof errors_1.AstlogException) {
36
+ if (err instanceof errors_1.SigdiffException) {
32
37
  process.stderr.write(`Error: ${err.error.message}\n`);
33
38
  process.exit(1);
34
39
  }
@@ -36,5 +41,5 @@ cli
36
41
  }
37
42
  });
38
43
  cli.help();
39
- cli.version('0.1.0');
44
+ cli.version(package_json_1.version);
40
45
  cli.parse();
package/dist/errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type AstlogError = {
1
+ export type SigdiffError = {
2
2
  code: 'INVALID_REF';
3
3
  message: string;
4
4
  } | {
@@ -14,7 +14,7 @@ export type AstlogError = {
14
14
  code: 'NOT_GIT_REPO';
15
15
  message: string;
16
16
  };
17
- export declare class AstlogException extends Error {
18
- readonly error: AstlogError;
19
- constructor(error: AstlogError);
17
+ export declare class SigdiffException extends Error {
18
+ readonly error: SigdiffError;
19
+ constructor(error: SigdiffError);
20
20
  }
package/dist/errors.js CHANGED
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AstlogException = void 0;
4
- class AstlogException extends Error {
3
+ exports.SigdiffException = void 0;
4
+ class SigdiffException extends Error {
5
5
  constructor(error) {
6
6
  super(error.message);
7
7
  this.error = error;
8
- this.name = 'AstlogException';
8
+ this.name = 'SigdiffException';
9
9
  }
10
10
  }
11
- exports.AstlogException = AstlogException;
11
+ exports.SigdiffException = SigdiffException;
package/dist/git.js CHANGED
@@ -47,7 +47,7 @@ function assertGitRepo() {
47
47
  (0, child_process_1.execSync)('git rev-parse --git-dir', { stdio: 'ignore' });
48
48
  }
49
49
  catch {
50
- throw new errors_1.AstlogException({
50
+ throw new errors_1.SigdiffException({
51
51
  code: 'NOT_GIT_REPO',
52
52
  message: 'Not a git repository. Run sigdiff from inside a git repo.'
53
53
  });
@@ -57,7 +57,7 @@ function resolveRefs(rangeArg) {
57
57
  if (rangeArg) {
58
58
  const parts = rangeArg.split('..');
59
59
  if (parts.length !== 2 || !parts[0] || !parts[1]) {
60
- throw new errors_1.AstlogException({
60
+ throw new errors_1.SigdiffException({
61
61
  code: 'INVALID_REF',
62
62
  message: `Invalid range format: "${rangeArg}". Expected format: <ref>..<ref>`
63
63
  });
@@ -73,7 +73,7 @@ function resolveRefs(rangeArg) {
73
73
  }).trim();
74
74
  }
75
75
  catch {
76
- throw new errors_1.AstlogException({
76
+ throw new errors_1.SigdiffException({
77
77
  code: 'NO_TAGS',
78
78
  message: 'No git tags found. Provide an explicit range: sigdiff <ref>..<ref>'
79
79
  });
@@ -83,7 +83,7 @@ function resolveRefs(rangeArg) {
83
83
  function extractAtRef(ref, entrypoint) {
84
84
  const files = discoverFiles(ref, entrypoint);
85
85
  if (files.length === 0) {
86
- throw new errors_1.AstlogException({
86
+ throw new errors_1.SigdiffException({
87
87
  code: 'NO_TYPESCRIPT',
88
88
  message: `No TypeScript files found at ref "${ref}".`
89
89
  });
@@ -114,7 +114,7 @@ function validateRef(ref) {
114
114
  (0, child_process_1.execSync)(`git rev-parse --verify ${ref}`, { stdio: 'ignore' });
115
115
  }
116
116
  catch {
117
- throw new errors_1.AstlogException({
117
+ throw new errors_1.SigdiffException({
118
118
  code: 'INVALID_REF',
119
119
  message: `Git ref "${ref}" does not exist.`
120
120
  });
package/dist/index.d.ts CHANGED
@@ -2,6 +2,6 @@ export { extract } from './extract';
2
2
  export { diff } from './diff';
3
3
  export { classify } from './classify';
4
4
  export { buildResult, format } from './format';
5
- export { AstlogException } from './errors';
5
+ export { SigdiffException } from './errors';
6
6
  export type { ApiSurface, ExportedSymbol, Change, ClassifiedChange, ChangelogResult, SemverLevel, SymbolKind } from './types';
7
- export type { AstlogError } from './errors';
7
+ export type { SigdiffError } from './errors';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AstlogException = exports.format = exports.buildResult = exports.classify = exports.diff = exports.extract = void 0;
3
+ exports.SigdiffException = exports.format = exports.buildResult = exports.classify = exports.diff = exports.extract = void 0;
4
4
  var extract_1 = require("./extract");
5
5
  Object.defineProperty(exports, "extract", { enumerable: true, get: function () { return extract_1.extract; } });
6
6
  var diff_1 = require("./diff");
@@ -11,4 +11,4 @@ var format_1 = require("./format");
11
11
  Object.defineProperty(exports, "buildResult", { enumerable: true, get: function () { return format_1.buildResult; } });
12
12
  Object.defineProperty(exports, "format", { enumerable: true, get: function () { return format_1.format; } });
13
13
  var errors_1 = require("./errors");
14
- Object.defineProperty(exports, "AstlogException", { enumerable: true, get: function () { return errors_1.AstlogException; } });
14
+ Object.defineProperty(exports, "SigdiffException", { enumerable: true, get: function () { return errors_1.SigdiffException; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigdiff",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Changelog from code, not commits. AST-based API surface diffing for TypeScript.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",