apiwatcher-cli 0.1.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/changesets/stripe/2025-09-30.clover__2026-08-26.dahlia.json +4576 -0
- package/changesets/stripe/index.json +16 -0
- package/data/stripe/events.json +271 -0
- package/data/stripe/method-map.json +5718 -0
- package/dist/changeset/index-file.d.ts +30 -0
- package/dist/changeset/index-file.d.ts.map +1 -0
- package/dist/changeset/index-file.js +34 -0
- package/dist/changeset/index-file.js.map +1 -0
- package/dist/changeset/load.d.ts +21 -0
- package/dist/changeset/load.d.ts.map +1 -0
- package/dist/changeset/load.js +113 -0
- package/dist/changeset/load.js.map +1 -0
- package/dist/changeset/types.d.ts +97 -0
- package/dist/changeset/types.d.ts.map +1 -0
- package/dist/changeset/types.js +18 -0
- package/dist/changeset/types.js.map +1 -0
- package/dist/changeset/version.d.ts +17 -0
- package/dist/changeset/version.d.ts.map +1 -0
- package/dist/changeset/version.js +33 -0
- package/dist/changeset/version.js.map +1 -0
- package/dist/cli/args.d.ts +15 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +82 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +333 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +92 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/report/impact.d.ts +40 -0
- package/dist/report/impact.d.ts.map +1 -0
- package/dist/report/impact.js +331 -0
- package/dist/report/impact.js.map +1 -0
- package/dist/report/impact.test.d.ts +2 -0
- package/dist/report/impact.test.d.ts.map +1 -0
- package/dist/report/impact.test.js +247 -0
- package/dist/report/impact.test.js.map +1 -0
- package/dist/report/render.d.ts +9 -0
- package/dist/report/render.d.ts.map +1 -0
- package/dist/report/render.js +211 -0
- package/dist/report/render.js.map +1 -0
- package/dist/scanner/ast.d.ts +74 -0
- package/dist/scanner/ast.d.ts.map +1 -0
- package/dist/scanner/ast.js +930 -0
- package/dist/scanner/ast.js.map +1 -0
- package/dist/scanner/paths.d.ts +42 -0
- package/dist/scanner/paths.d.ts.map +1 -0
- package/dist/scanner/paths.js +179 -0
- package/dist/scanner/paths.js.map +1 -0
- package/dist/scanner/scan.d.ts +11 -0
- package/dist/scanner/scan.d.ts.map +1 -0
- package/dist/scanner/scan.js +268 -0
- package/dist/scanner/scan.js.map +1 -0
- package/dist/scanner/scan.test.d.ts +2 -0
- package/dist/scanner/scan.test.d.ts.map +1 -0
- package/dist/scanner/scan.test.js +134 -0
- package/dist/scanner/scan.test.js.map +1 -0
- package/dist/scanner/types.d.ts +74 -0
- package/dist/scanner/types.d.ts.map +1 -0
- package/dist/scanner/types.js +7 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/scanner/version.d.ts +23 -0
- package/dist/scanner/version.d.ts.map +1 -0
- package/dist/scanner/version.js +155 -0
- package/dist/scanner/version.js.map +1 -0
- package/dist/scanner/walk.d.ts +26 -0
- package/dist/scanner/walk.d.ts.map +1 -0
- package/dist/scanner/walk.js +117 -0
- package/dist/scanner/walk.js.map +1 -0
- package/dist/scanner/wrapper.test.d.ts +2 -0
- package/dist/scanner/wrapper.test.d.ts.map +1 -0
- package/dist/scanner/wrapper.test.js +92 -0
- package/dist/scanner/wrapper.test.js.map +1 -0
- package/dist/specdiff/build-method-map.d.ts +6 -0
- package/dist/specdiff/build-method-map.d.ts.map +1 -0
- package/dist/specdiff/build-method-map.js +231 -0
- package/dist/specdiff/build-method-map.js.map +1 -0
- package/dist/specdiff/compat.d.ts +20 -0
- package/dist/specdiff/compat.d.ts.map +1 -0
- package/dist/specdiff/compat.js +58 -0
- package/dist/specdiff/compat.js.map +1 -0
- package/dist/specdiff/diff.d.ts +28 -0
- package/dist/specdiff/diff.d.ts.map +1 -0
- package/dist/specdiff/diff.js +529 -0
- package/dist/specdiff/diff.js.map +1 -0
- package/dist/specdiff/diff.test.d.ts +2 -0
- package/dist/specdiff/diff.test.d.ts.map +1 -0
- package/dist/specdiff/diff.test.js +260 -0
- package/dist/specdiff/diff.test.js.map +1 -0
- package/dist/specdiff/fetch.d.ts +28 -0
- package/dist/specdiff/fetch.d.ts.map +1 -0
- package/dist/specdiff/fetch.js +68 -0
- package/dist/specdiff/fetch.js.map +1 -0
- package/dist/specdiff/methodmap.d.ts +45 -0
- package/dist/specdiff/methodmap.d.ts.map +1 -0
- package/dist/specdiff/methodmap.js +109 -0
- package/dist/specdiff/methodmap.js.map +1 -0
- package/dist/specdiff/openapi.d.ts +166 -0
- package/dist/specdiff/openapi.d.ts.map +1 -0
- package/dist/specdiff/openapi.js +282 -0
- package/dist/specdiff/openapi.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { test, before } from 'node:test';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { scanRepo } from './scan.js';
|
|
6
|
+
import { loadPathAliases, loadWorkspacePackages, expandAlias } from './paths.js';
|
|
7
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const FIXTURE = resolve(HERE, '../../test/fixtures/wrapper-app');
|
|
9
|
+
const MAP = {
|
|
10
|
+
sdkVersion: 'test',
|
|
11
|
+
generatedAt: new Date(0).toISOString(),
|
|
12
|
+
byEndpoint: {},
|
|
13
|
+
byCall: {
|
|
14
|
+
'products.list': { method: 'get', path: '/v1/products' },
|
|
15
|
+
'refunds.create': { method: 'post', path: '/v1/refunds' },
|
|
16
|
+
'subscriptions.cancel': { method: 'delete', path: '/v1/subscriptions/{id}' },
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Every call in this fixture is reached through indirection a naive scanner
|
|
21
|
+
* would miss. They are all full confidence or the detection has regressed —
|
|
22
|
+
* these are the shapes real repositories actually use.
|
|
23
|
+
*/
|
|
24
|
+
let scan;
|
|
25
|
+
before(async () => {
|
|
26
|
+
scan = await scanRepo(FIXTURE, { methodMap: MAP });
|
|
27
|
+
});
|
|
28
|
+
function call(namespace, method) {
|
|
29
|
+
return scan.usages.find((u) => u.kind === 'sdkCall' && u.namespace === namespace && u.method === method);
|
|
30
|
+
}
|
|
31
|
+
test('a client built inside a conditional is still resolved', () => {
|
|
32
|
+
// `export const stripeClient = env.KEY ? new Stripe(...) : null`
|
|
33
|
+
const usage = call('products', 'list');
|
|
34
|
+
assert.ok(usage, 'expected products.list to be found');
|
|
35
|
+
assert.equal(usage?.confidence, 1, 'env-guarded construction should not cost confidence');
|
|
36
|
+
});
|
|
37
|
+
test('a client imported by workspace package name is resolved', () => {
|
|
38
|
+
// billing.ts imports from `@wrapper/core/src/client`.
|
|
39
|
+
assert.ok(scan.clients.some((c) => c.file === 'src/services/billing.ts' && c.name === 'stripeClient'), `expected a resolved client in billing.ts, got ${JSON.stringify(scan.clients)}`);
|
|
40
|
+
});
|
|
41
|
+
test('a locally aliased client keeps full confidence', () => {
|
|
42
|
+
// `const client = stripeClient` — the call site says nothing about Stripe.
|
|
43
|
+
const usage = call('products', 'list');
|
|
44
|
+
assert.equal(usage?.via, 'client');
|
|
45
|
+
assert.equal(usage?.confidence, 1);
|
|
46
|
+
});
|
|
47
|
+
test('a client arriving as a typed parameter is recognised', () => {
|
|
48
|
+
// `async function refundCharge(stripe: Stripe, ...)` — the annotation is the
|
|
49
|
+
// only evidence available, and it is definitive.
|
|
50
|
+
const usage = call('refunds', 'create');
|
|
51
|
+
assert.ok(usage, 'expected refunds.create to be found');
|
|
52
|
+
assert.equal(usage?.confidence, 1);
|
|
53
|
+
});
|
|
54
|
+
test('a client returned by a factory function is recognised', () => {
|
|
55
|
+
// `const sdk = getStripeClient()`
|
|
56
|
+
const usage = call('subscriptions', 'cancel');
|
|
57
|
+
assert.ok(usage, 'expected subscriptions.cancel to be found');
|
|
58
|
+
assert.equal(usage?.via, 'sdk');
|
|
59
|
+
assert.equal(usage?.confidence, 1);
|
|
60
|
+
});
|
|
61
|
+
test('the pinned version is read from a constant behind a path alias', () => {
|
|
62
|
+
// `apiVersion: STRIPE_API_VERSION`, imported via `@/config/constants`.
|
|
63
|
+
assert.equal(scan.version.apiVersion, '2025-09-30.clover');
|
|
64
|
+
});
|
|
65
|
+
test('the stripe dependency is found in a workspace package', () => {
|
|
66
|
+
// Declared in packages/core, not at the repo root.
|
|
67
|
+
assert.equal(scan.version.sdkRange, '^22.0.0');
|
|
68
|
+
});
|
|
69
|
+
test('fields read through a list iteration carry the right path', () => {
|
|
70
|
+
const fields = scan.usages
|
|
71
|
+
.filter((u) => u.kind === 'responseField' && u.namespace === 'products')
|
|
72
|
+
.map((u) => u.field);
|
|
73
|
+
assert.ok(fields.includes('data[].default_price'), `expected data[].default_price, got ${JSON.stringify(fields)}`);
|
|
74
|
+
});
|
|
75
|
+
// --- resolution units ------------------------------------------------------
|
|
76
|
+
test('tsconfig paths are read, comments and all', async () => {
|
|
77
|
+
const aliases = await loadPathAliases(FIXTURE);
|
|
78
|
+
assert.ok(aliases, 'expected aliases from a tsconfig containing comments');
|
|
79
|
+
assert.deepEqual(expandAlias(aliases, FIXTURE, '@/config/constants'), ['src/config/constants']);
|
|
80
|
+
assert.deepEqual(expandAlias(aliases, FIXTURE, 'stripe'), [], 'package imports are not aliases');
|
|
81
|
+
});
|
|
82
|
+
test('workspace packages map names to directories', async () => {
|
|
83
|
+
const workspaces = await loadWorkspacePackages(FIXTURE);
|
|
84
|
+
assert.equal(workspaces.get('@wrapper/core'), 'packages/core');
|
|
85
|
+
});
|
|
86
|
+
test('a test mock does not override the real version constant', async () => {
|
|
87
|
+
// formbricks pins 2026-02-25 in constants.ts and a different value in its
|
|
88
|
+
// vitest setup; the declaration must win over the mock.
|
|
89
|
+
const result = await scanRepo(FIXTURE, { methodMap: MAP });
|
|
90
|
+
assert.equal(result.version.apiVersion, '2025-09-30.clover');
|
|
91
|
+
});
|
|
92
|
+
//# sourceMappingURL=wrapper.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapper.test.js","sourceRoot":"","sources":["../../src/scanner/wrapper.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type MethodMap } from './methodmap.js';
|
|
2
|
+
/** Find the installed stripe package's CJS entry point. */
|
|
3
|
+
export declare function findStripeCore(searchFrom?: string): string;
|
|
4
|
+
export declare function buildMethodMap(coreFile?: string): Promise<MethodMap>;
|
|
5
|
+
export declare function writeMethodMap(map: MethodMap, outFile: string): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=build-method-map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-method-map.d.ts","sourceRoot":"","sources":["../../src/specdiff/build-method-map.ts"],"names":[],"mappings":"AAMA,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AA4NtE,2DAA2D;AAC3D,wBAAgB,cAAc,CAAC,UAAU,GAAE,MAAsB,GAAG,MAAM,CAYzE;AAaD,wBAAsB,cAAc,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CA+B1E;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGnF"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
import ts from 'typescript';
|
|
5
|
+
import { callKey, endpointKey } from './methodmap.js';
|
|
6
|
+
const factsCache = new Map();
|
|
7
|
+
function parse(file, text) {
|
|
8
|
+
return ts.createSourceFile(file, text, ts.ScriptTarget.ES2022, true, ts.ScriptKind.JS);
|
|
9
|
+
}
|
|
10
|
+
function resolveRequire(fromFile, spec) {
|
|
11
|
+
if (!spec.startsWith('.'))
|
|
12
|
+
return null;
|
|
13
|
+
const base = resolve(dirname(fromFile), spec);
|
|
14
|
+
for (const candidate of [base, `${base}.js`, join(base, 'index.js')]) {
|
|
15
|
+
if (existsSync(candidate) && !candidate.endsWith('/'))
|
|
16
|
+
return candidate;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
async function factsFor(file) {
|
|
21
|
+
const cached = factsCache.get(file);
|
|
22
|
+
if (cached)
|
|
23
|
+
return cached;
|
|
24
|
+
const sf = parse(file, await readFile(file, 'utf8'));
|
|
25
|
+
const aliases = new Map();
|
|
26
|
+
const classes = new Map();
|
|
27
|
+
const visit = (node) => {
|
|
28
|
+
// const Alias_js_1 = require("./Foo.js")
|
|
29
|
+
if (ts.isVariableStatement(node)) {
|
|
30
|
+
for (const decl of node.declarationList.declarations) {
|
|
31
|
+
if (!ts.isIdentifier(decl.name) || !decl.initializer)
|
|
32
|
+
continue;
|
|
33
|
+
const init = decl.initializer;
|
|
34
|
+
if (ts.isCallExpression(init) &&
|
|
35
|
+
ts.isIdentifier(init.expression) &&
|
|
36
|
+
init.expression.text === 'require' &&
|
|
37
|
+
init.arguments.length === 1) {
|
|
38
|
+
const arg = init.arguments[0];
|
|
39
|
+
if (arg && ts.isStringLiteral(arg)) {
|
|
40
|
+
const target = resolveRequire(file, arg.text);
|
|
41
|
+
if (target)
|
|
42
|
+
aliases.set(decl.name.text, target);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (ts.isClassDeclaration(node) && node.name)
|
|
48
|
+
classes.set(node.name.text, node);
|
|
49
|
+
ts.forEachChild(node, visit);
|
|
50
|
+
};
|
|
51
|
+
visit(sf);
|
|
52
|
+
const facts = { aliases, classes };
|
|
53
|
+
factsCache.set(file, facts);
|
|
54
|
+
return facts;
|
|
55
|
+
}
|
|
56
|
+
/** `'/v1/payment_intents/' + encodeURIComponent(id) + '/confirm'` -> `/v1/payment_intents/{id}/confirm` */
|
|
57
|
+
function pathFromExpression(expr) {
|
|
58
|
+
if (ts.isStringLiteral(expr) || ts.isNoSubstitutionTemplateLiteral(expr))
|
|
59
|
+
return expr.text;
|
|
60
|
+
if (ts.isTemplateExpression(expr)) {
|
|
61
|
+
let out = expr.head.text;
|
|
62
|
+
for (const span of expr.templateSpans) {
|
|
63
|
+
out += `{${placeholderName(span.expression)}}`;
|
|
64
|
+
out += span.literal.text;
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
// String concatenation, used by some older generated output.
|
|
69
|
+
if (ts.isBinaryExpression(expr) && expr.operatorToken.kind === ts.SyntaxKind.PlusToken) {
|
|
70
|
+
const left = pathFromExpression(expr.left);
|
|
71
|
+
const right = pathFromExpression(expr.right);
|
|
72
|
+
if (left === null && right === null)
|
|
73
|
+
return null;
|
|
74
|
+
return `${left ?? `{${placeholderName(expr.left)}}`}${right ?? `{${placeholderName(expr.right)}}`}`;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
/** Recover the parameter name from `encodeURIComponent(id)` so paths read well. */
|
|
79
|
+
function placeholderName(expr) {
|
|
80
|
+
let inner = expr;
|
|
81
|
+
while (ts.isCallExpression(inner) && inner.arguments.length >= 1) {
|
|
82
|
+
const first = inner.arguments[0];
|
|
83
|
+
if (!first)
|
|
84
|
+
break;
|
|
85
|
+
inner = first;
|
|
86
|
+
}
|
|
87
|
+
if (ts.isIdentifier(inner))
|
|
88
|
+
return inner.text;
|
|
89
|
+
if (ts.isPropertyAccessExpression(inner))
|
|
90
|
+
return inner.name.text;
|
|
91
|
+
return 'id';
|
|
92
|
+
}
|
|
93
|
+
/** Pull every `this._makeRequest('GET', '/v1/...')` out of a resource class. */
|
|
94
|
+
function leafMethods(cls, namespace) {
|
|
95
|
+
const out = [];
|
|
96
|
+
for (const member of cls.members) {
|
|
97
|
+
if (!ts.isMethodDeclaration(member) || !member.name)
|
|
98
|
+
continue;
|
|
99
|
+
const name = ts.isIdentifier(member.name) || ts.isStringLiteral(member.name) ? member.name.text : null;
|
|
100
|
+
if (!name || name.startsWith('_'))
|
|
101
|
+
continue;
|
|
102
|
+
let found = null;
|
|
103
|
+
const visit = (node) => {
|
|
104
|
+
if (found)
|
|
105
|
+
return;
|
|
106
|
+
if (ts.isCallExpression(node) &&
|
|
107
|
+
ts.isPropertyAccessExpression(node.expression) &&
|
|
108
|
+
node.expression.name.text === '_makeRequest' &&
|
|
109
|
+
node.arguments.length >= 2) {
|
|
110
|
+
const [verb, pathArg] = node.arguments;
|
|
111
|
+
if (verb && pathArg && ts.isStringLiteral(verb)) {
|
|
112
|
+
const path = pathFromExpression(pathArg);
|
|
113
|
+
if (path)
|
|
114
|
+
found = { namespace, method: name, httpMethod: verb.text.toLowerCase(), path };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
ts.forEachChild(node, visit);
|
|
118
|
+
};
|
|
119
|
+
if (member.body)
|
|
120
|
+
visit(member.body);
|
|
121
|
+
if (found)
|
|
122
|
+
out.push(found);
|
|
123
|
+
}
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
function containerChildren(cls) {
|
|
127
|
+
const out = [];
|
|
128
|
+
const visit = (node) => {
|
|
129
|
+
if (ts.isExpressionStatement(node) &&
|
|
130
|
+
ts.isBinaryExpression(node.expression) &&
|
|
131
|
+
node.expression.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
|
|
132
|
+
const { left, right } = node.expression;
|
|
133
|
+
if (ts.isPropertyAccessExpression(left) &&
|
|
134
|
+
left.expression.kind === ts.SyntaxKind.ThisKeyword &&
|
|
135
|
+
ts.isNewExpression(right) &&
|
|
136
|
+
ts.isPropertyAccessExpression(right.expression) &&
|
|
137
|
+
ts.isIdentifier(right.expression.expression)) {
|
|
138
|
+
out.push({
|
|
139
|
+
accessor: left.name.text,
|
|
140
|
+
alias: right.expression.expression.text,
|
|
141
|
+
className: right.expression.name.text,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
ts.forEachChild(node, visit);
|
|
146
|
+
};
|
|
147
|
+
for (const member of cls.members) {
|
|
148
|
+
if (ts.isConstructorDeclaration(member) && member.body)
|
|
149
|
+
visit(member.body);
|
|
150
|
+
}
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
async function walk(file, className, prefix, out, seen, depth) {
|
|
154
|
+
if (depth > 5)
|
|
155
|
+
return;
|
|
156
|
+
const guard = `${file}#${className}#${prefix}`;
|
|
157
|
+
if (seen.has(guard))
|
|
158
|
+
return;
|
|
159
|
+
seen.add(guard);
|
|
160
|
+
const facts = await factsFor(file);
|
|
161
|
+
const cls = facts.classes.get(className);
|
|
162
|
+
if (!cls)
|
|
163
|
+
return;
|
|
164
|
+
const methods = leafMethods(cls, prefix);
|
|
165
|
+
if (methods.length > 0) {
|
|
166
|
+
out.push(...methods);
|
|
167
|
+
// A resource can still expose nested sub-resources, so keep walking.
|
|
168
|
+
}
|
|
169
|
+
for (const child of containerChildren(cls)) {
|
|
170
|
+
const target = facts.aliases.get(child.alias);
|
|
171
|
+
if (!target)
|
|
172
|
+
continue;
|
|
173
|
+
const nextPrefix = prefix === '' ? child.accessor : `${prefix}.${child.accessor}`;
|
|
174
|
+
await walk(target, child.className, nextPrefix, out, seen, depth + 1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/** Find the installed stripe package's CJS entry point. */
|
|
178
|
+
export function findStripeCore(searchFrom = process.cwd()) {
|
|
179
|
+
let dir = resolve(searchFrom);
|
|
180
|
+
for (let i = 0; i < 10; i++) {
|
|
181
|
+
const candidate = join(dir, 'node_modules', 'stripe', 'cjs', 'stripe.core.js');
|
|
182
|
+
if (existsSync(candidate))
|
|
183
|
+
return candidate;
|
|
184
|
+
const parent = dirname(dir);
|
|
185
|
+
if (parent === dir)
|
|
186
|
+
break;
|
|
187
|
+
dir = parent;
|
|
188
|
+
}
|
|
189
|
+
throw new Error('Could not find node_modules/stripe/cjs/stripe.core.js. Install the stripe package first (npm i stripe).');
|
|
190
|
+
}
|
|
191
|
+
async function stripeVersion(coreFile) {
|
|
192
|
+
// package.json sits two levels up from cjs/stripe.core.js and is not exported,
|
|
193
|
+
// so read it off disk rather than through require().
|
|
194
|
+
const pkg = join(dirname(dirname(coreFile)), 'package.json');
|
|
195
|
+
try {
|
|
196
|
+
return JSON.parse(await readFile(pkg, 'utf8')).version ?? 'unknown';
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return 'unknown';
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
export async function buildMethodMap(coreFile) {
|
|
203
|
+
const core = coreFile ?? findStripeCore();
|
|
204
|
+
factsCache.clear();
|
|
205
|
+
const leaves = [];
|
|
206
|
+
await walk(core, 'Stripe', '', leaves, new Set(), 0);
|
|
207
|
+
if (leaves.length === 0) {
|
|
208
|
+
throw new Error(`No SDK methods found in ${core}. The stripe package layout may have changed.`);
|
|
209
|
+
}
|
|
210
|
+
const byEndpoint = {};
|
|
211
|
+
const byCall = {};
|
|
212
|
+
for (const leaf of leaves.sort((a, b) => `${a.namespace}.${a.method}`.localeCompare(`${b.namespace}.${b.method}`))) {
|
|
213
|
+
const key = endpointKey(leaf.httpMethod, leaf.path);
|
|
214
|
+
const refs = (byEndpoint[key] ??= []);
|
|
215
|
+
if (!refs.some((r) => r.namespace === leaf.namespace && r.method === leaf.method)) {
|
|
216
|
+
refs.push({ namespace: leaf.namespace, method: leaf.method });
|
|
217
|
+
}
|
|
218
|
+
byCall[callKey(leaf.namespace, leaf.method)] = { method: leaf.httpMethod, path: leaf.path };
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
sdkVersion: await stripeVersion(core),
|
|
222
|
+
generatedAt: new Date().toISOString(),
|
|
223
|
+
byEndpoint,
|
|
224
|
+
byCall,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
export async function writeMethodMap(map, outFile) {
|
|
228
|
+
await mkdir(dirname(outFile), { recursive: true });
|
|
229
|
+
await writeFile(outFile, `${JSON.stringify(map, null, 2)}\n`, 'utf8');
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=build-method-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-method-map.js","sourceRoot":"","sources":["../../src/specdiff/build-method-map.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Severity } from '../changeset/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Whether a type change actually breaks anything depends on which way the data
|
|
4
|
+
* flows.
|
|
5
|
+
*
|
|
6
|
+
* Adding a value to a request enum is additive — you could not have been sending
|
|
7
|
+
* it before. Removing one is breaking, because a value you do send stops being
|
|
8
|
+
* accepted. For responses it is the mirror image: a new variant is something
|
|
9
|
+
* your `switch` may not handle, but it does not make correct code incorrect, so
|
|
10
|
+
* it stays additive rather than crying wolf.
|
|
11
|
+
*/
|
|
12
|
+
export type Direction = 'request' | 'response';
|
|
13
|
+
export interface TypeVerdict {
|
|
14
|
+
changed: boolean;
|
|
15
|
+
severity: Severity;
|
|
16
|
+
/** Short human phrase describing the change, e.g. "no longer accepts a, b". */
|
|
17
|
+
detail: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function classifyTypeChange(fromSig: string, toSig: string, direction: Direction): TypeVerdict;
|
|
20
|
+
//# sourceMappingURL=compat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compat.d.ts","sourceRoot":"","sources":["../../src/specdiff/compat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;;;;;;;;GASG;AACH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;AAE/C,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;CAChB;AAiBD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,SAAS,GACnB,WAAW,CAkDb"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const SET_SIG = /^(enum|union)\(([^)]*)\)$/;
|
|
2
|
+
function setMembers(sig) {
|
|
3
|
+
const m = SET_SIG.exec(sig);
|
|
4
|
+
if (!m)
|
|
5
|
+
return null;
|
|
6
|
+
const kind = m[1];
|
|
7
|
+
const body = m[2] ?? '';
|
|
8
|
+
return { kind, members: new Set(body === '' ? [] : body.split('|')) };
|
|
9
|
+
}
|
|
10
|
+
function list(values, max = 6) {
|
|
11
|
+
if (values.length <= max)
|
|
12
|
+
return values.join(', ');
|
|
13
|
+
return `${values.slice(0, max).join(', ')} and ${values.length - max} more`;
|
|
14
|
+
}
|
|
15
|
+
export function classifyTypeChange(fromSig, toSig, direction) {
|
|
16
|
+
if (fromSig === toSig)
|
|
17
|
+
return { changed: false, severity: 'additive', detail: '' };
|
|
18
|
+
const before = setMembers(fromSig);
|
|
19
|
+
const after = setMembers(toSig);
|
|
20
|
+
if (before && after && before.kind === after.kind) {
|
|
21
|
+
const removed = [...before.members].filter((v) => !after.members.has(v)).sort();
|
|
22
|
+
const added = [...after.members].filter((v) => !before.members.has(v)).sort();
|
|
23
|
+
if (removed.length === 0 && added.length === 0) {
|
|
24
|
+
return { changed: false, severity: 'additive', detail: '' };
|
|
25
|
+
}
|
|
26
|
+
if (removed.length === 0) {
|
|
27
|
+
// Pure widening.
|
|
28
|
+
return direction === 'request'
|
|
29
|
+
? { changed: true, severity: 'additive', detail: `now also accepts ${list(added)}` }
|
|
30
|
+
: { changed: true, severity: 'additive', detail: `can now also return ${list(added)}` };
|
|
31
|
+
}
|
|
32
|
+
if (direction === 'request') {
|
|
33
|
+
return {
|
|
34
|
+
changed: true,
|
|
35
|
+
severity: 'breaking',
|
|
36
|
+
detail: added.length > 0
|
|
37
|
+
? `no longer accepts ${list(removed)} (and now accepts ${list(added)})`
|
|
38
|
+
: `no longer accepts ${list(removed)}`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// A response value that disappears only leaves a dead branch behind.
|
|
42
|
+
return {
|
|
43
|
+
changed: true,
|
|
44
|
+
severity: 'additive',
|
|
45
|
+
detail: added.length > 0
|
|
46
|
+
? `no longer returns ${list(removed)}; can now return ${list(added)}`
|
|
47
|
+
: `no longer returns ${list(removed)}`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// Anything else — scalar swap, object becoming an array, a ref changing
|
|
51
|
+
// identity — is a genuine incompatibility in both directions.
|
|
52
|
+
return {
|
|
53
|
+
changed: true,
|
|
54
|
+
severity: 'breaking',
|
|
55
|
+
detail: `changed from ${fromSig} to ${toSig}`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compat.js","sourceRoot":"","sources":["../../src/specdiff/compat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Changeset } from '../changeset/types.js';
|
|
2
|
+
import { type OpenApiSpec } from './openapi.js';
|
|
3
|
+
import { type MethodMap } from './methodmap.js';
|
|
4
|
+
export interface DiffOptions {
|
|
5
|
+
methodMap?: MethodMap;
|
|
6
|
+
/** Nesting depth to compare within a schema. Refs are always boundaries. */
|
|
7
|
+
maxDepth?: number;
|
|
8
|
+
/** Include `additive` entries. Off by default: they never break anything. */
|
|
9
|
+
includeAdditive?: boolean;
|
|
10
|
+
/** Cap on endpoints/paths cited per resource change, to keep changesets small. */
|
|
11
|
+
maxAttribution?: number;
|
|
12
|
+
source?: Changeset['source'];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Diffs two Stripe OpenAPI specs into a changeset.
|
|
16
|
+
*
|
|
17
|
+
* Requests are diffed per operation, because Stripe inlines request shapes.
|
|
18
|
+
* Responses are diffed per component schema with `$ref` as a boundary, then
|
|
19
|
+
* attributed to the endpoints that return them — expanding refs per endpoint
|
|
20
|
+
* produces unstable field sets and duplicates one real change across hundreds of
|
|
21
|
+
* paths.
|
|
22
|
+
*
|
|
23
|
+
* The only inference is rename detection, kept deliberately conservative: a
|
|
24
|
+
* wrong `replacement` sends someone to the wrong field, which is worse than
|
|
25
|
+
* reporting a removal and an addition separately.
|
|
26
|
+
*/
|
|
27
|
+
export declare function diffSpecs(oldSpec: OpenApiSpec, newSpec: OpenApiSpec, options?: DiffOptions): Changeset;
|
|
28
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/specdiff/diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAmD,MAAM,uBAAuB,CAAC;AAExG,OAAO,EAWL,KAAK,WAAW,EAIjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAElE,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kFAAkF;IAClF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;CAC9B;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,GAAE,WAAgB,GAAG,SAAS,CA6K1G"}
|