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 +49 -15
- package/dist/cli.js +7 -2
- package/dist/errors.d.ts +4 -4
- package/dist/errors.js +4 -4
- package/dist/git.js +5 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
# sigdiff
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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)`
|
|
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
|
|
65
|
-
- Single-package projects
|
|
66
|
-
- Read-only
|
|
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.
|
|
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(
|
|
44
|
+
cli.version(package_json_1.version);
|
|
40
45
|
cli.parse();
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type
|
|
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
|
|
18
|
-
readonly error:
|
|
19
|
-
constructor(error:
|
|
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.
|
|
4
|
-
class
|
|
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 = '
|
|
8
|
+
this.name = 'SigdiffException';
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
|
-
exports.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 {
|
|
5
|
+
export { SigdiffException } from './errors';
|
|
6
6
|
export type { ApiSurface, ExportedSymbol, Change, ClassifiedChange, ChangelogResult, SemverLevel, SymbolKind } from './types';
|
|
7
|
-
export type {
|
|
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.
|
|
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, "
|
|
14
|
+
Object.defineProperty(exports, "SigdiffException", { enumerable: true, get: function () { return errors_1.SigdiffException; } });
|