@workos/oagen 0.6.0 → 0.8.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/dist/cli/index.mjs +1339 -451
- package/dist/cli/index.mjs.map +1 -1
- package/dist/compat/index.d.mts +144 -57
- package/dist/compat/index.d.mts.map +1 -1
- package/dist/compat/index.mjs +365 -35
- package/dist/compat/index.mjs.map +1 -1
- package/dist/{diff-CltJMcwG.mjs → diff-BaH9qa8k.mjs} +100 -23
- package/dist/diff-BaH9qa8k.mjs.map +1 -0
- package/dist/differ-CTl98yoS.d.mts +116 -0
- package/dist/differ-CTl98yoS.d.mts.map +1 -0
- package/dist/index.d.mts +4 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +177 -4
- package/dist/index.mjs.map +1 -1
- package/dist/{differ-CG5ZErKl.mjs → overlay-TYxHOCow.mjs} +1112 -553
- package/dist/overlay-TYxHOCow.mjs.map +1 -0
- package/dist/scripts/smoke/baseline.mjs +176 -3
- package/dist/scripts/smoke/baseline.mjs.map +1 -1
- package/dist/smoke.d.mts +43 -0
- package/dist/smoke.d.mts.map +1 -1
- package/dist/smoke.mjs +176 -3
- package/dist/smoke.mjs.map +1 -1
- package/dist/tree-sitter-C53w_0WE.mjs.map +1 -1
- package/dist/{types-C7g5sLuX.d.mts → types-mTtkgy_h.d.mts} +213 -2
- package/dist/types-mTtkgy_h.d.mts.map +1 -0
- package/dist/verify/index.d.mts +4 -3
- package/dist/verify/index.d.mts.map +1 -1
- package/dist/verify/index.mjs +12 -10
- package/dist/verify/index.mjs.map +1 -1
- package/docs/architecture/emitter-contract.md +2 -2
- package/docs/architecture/extractor-contract.md +6 -5
- package/docs/architecture/pipeline.md +4 -3
- package/docs/architecture/workflows.md +5 -3
- package/docs/cli.md +148 -6
- package/docs/contributor/public-api.md +1 -1
- package/docs/core/compatibility-ir.md +200 -0
- package/docs/core/compatibility-policy.md +170 -0
- package/docs/core/compatibility.md +83 -0
- package/docs/core/index.md +5 -0
- package/docs/core/manifest-schema.md +76 -0
- package/docs/core/quickstart.md +9 -2
- package/docs/core/verify-compat.md +235 -0
- package/package.json +1 -1
- package/skills/generate-emitter/SKILL.md +12 -7
- package/skills/generate-emitter/references/project-scaffold.md +27 -6
- package/skills/generate-extractor/SKILL.md +14 -8
- package/skills/generate-sdk/SKILL.md +2 -2
- package/skills/generate-smoke-test/SKILL.md +9 -5
- package/skills/review-operations/SKILL.md +2 -2
- package/skills/verify-compat/SKILL.md +1 -1
- package/dist/diff-CltJMcwG.mjs.map +0 -1
- package/dist/differ-CG5ZErKl.mjs.map +0 -1
- package/dist/types-C7g5sLuX.d.mts.map +0 -1
package/dist/compat/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as safeParse$1, v as ExtractorError } from "../tree-sitter-C53w_0WE.mjs";
|
|
2
|
-
import { _ as
|
|
2
|
+
import { A as getDefaultPolicy, C as defaultSeverityForCategory, D as isCompatibleSchemaVersion, E as COMPAT_SCHEMA_VERSION, O as validateSnapshot, S as summarizeChanges, T as apiSurfaceToSnapshot, _ as nodeHints, a as registerExtractor, b as classifyAddedSymbol, c as filterSurface, d as specDerivedHttpKeys, f as specDerivedMethodPaths, g as namedTypeWordsOverlap, h as defaultIsNullableOnlyDifference, i as getExtractor, j as mergePolicy, k as ALL_LANGUAGE_IDS, l as specDerivedEnumValues, m as NAMED_TYPE_RE, n as isPatchableChange, o as diffSnapshots, p as specDerivedNames, r as patchOverlay, s as diffSurfaces, t as buildOverlayLookup, u as specDerivedFieldPaths, v as resolveHints, w as severityMeetsThreshold, x as classifySymbolChanges, y as typeExistsInSurface } from "../overlay-TYxHOCow.mjs";
|
|
3
3
|
import path, { basename, dirname, join, relative, resolve } from "node:path";
|
|
4
4
|
import Parser from "tree-sitter";
|
|
5
5
|
import ts from "typescript";
|
|
@@ -9,6 +9,225 @@ import Python from "tree-sitter-python";
|
|
|
9
9
|
import Ruby from "tree-sitter-ruby";
|
|
10
10
|
import Go from "tree-sitter-go";
|
|
11
11
|
import RustLang from "tree-sitter-rust";
|
|
12
|
+
//#region src/compat/concepts.ts
|
|
13
|
+
/**
|
|
14
|
+
* Group classified changes from multiple languages into conceptual changes.
|
|
15
|
+
*
|
|
16
|
+
* Changes are grouped by their `conceptualChangeId` — a deterministic ID
|
|
17
|
+
* derived from the symbol, category, and match details. Changes with the
|
|
18
|
+
* same ID across different languages represent the same conceptual change.
|
|
19
|
+
*/
|
|
20
|
+
function buildConceptualRollup(perLanguageResults) {
|
|
21
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
22
|
+
for (const { diff: result, language } of perLanguageResults) for (const change of result.changes) {
|
|
23
|
+
const existing = grouped.get(change.conceptualChangeId);
|
|
24
|
+
if (existing) existing.impact[language] = change.severity;
|
|
25
|
+
else grouped.set(change.conceptualChangeId, {
|
|
26
|
+
id: change.conceptualChangeId,
|
|
27
|
+
symbol: change.symbol,
|
|
28
|
+
category: change.category,
|
|
29
|
+
impact: { [language]: change.severity },
|
|
30
|
+
message: change.message,
|
|
31
|
+
old: change.old,
|
|
32
|
+
new: change.new
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return { conceptualChanges: [...grouped.values()] };
|
|
36
|
+
}
|
|
37
|
+
/** Get the highest severity across all languages for a conceptual change. */
|
|
38
|
+
function highestSeverity(change) {
|
|
39
|
+
const severities = Object.values(change.impact);
|
|
40
|
+
if (severities.includes("breaking")) return "breaking";
|
|
41
|
+
if (severities.includes("soft-risk")) return "soft-risk";
|
|
42
|
+
return "additive";
|
|
43
|
+
}
|
|
44
|
+
/** Count conceptual changes by highest severity. */
|
|
45
|
+
function summarizeConceptualChanges(rollup) {
|
|
46
|
+
let breaking = 0;
|
|
47
|
+
let softRisk = 0;
|
|
48
|
+
let additive = 0;
|
|
49
|
+
for (const change of rollup.conceptualChanges) {
|
|
50
|
+
const sev = highestSeverity(change);
|
|
51
|
+
if (sev === "breaking") breaking++;
|
|
52
|
+
else if (sev === "soft-risk") softRisk++;
|
|
53
|
+
else additive++;
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
breaking,
|
|
57
|
+
softRisk,
|
|
58
|
+
additive
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/compat/report.ts
|
|
63
|
+
/** Generate a machine-readable compat report from a diff result. */
|
|
64
|
+
function generateReport(diff, language) {
|
|
65
|
+
return {
|
|
66
|
+
schemaVersion: "1",
|
|
67
|
+
language: language ?? "unknown",
|
|
68
|
+
summary: diff.summary,
|
|
69
|
+
changes: diff.changes.map((c) => ({
|
|
70
|
+
severity: c.severity,
|
|
71
|
+
category: c.category,
|
|
72
|
+
symbol: c.symbol,
|
|
73
|
+
conceptualChangeId: c.conceptualChangeId,
|
|
74
|
+
provenance: c.provenance,
|
|
75
|
+
old: c.old,
|
|
76
|
+
new: c.new,
|
|
77
|
+
...c.message ? { message: c.message } : {}
|
|
78
|
+
}))
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** Generate a human-readable summary string for terminal output. */
|
|
82
|
+
function formatHumanSummary(diff, opts) {
|
|
83
|
+
const lines = [];
|
|
84
|
+
lines.push(`Compat report${opts?.language ? ` for ${opts.language}` : ""}:`);
|
|
85
|
+
lines.push(` ${diff.summary.breaking} breaking, ${diff.summary.softRisk} soft-risk, ${diff.summary.additive} additive`);
|
|
86
|
+
if (diff.changes.length === 0) {
|
|
87
|
+
lines.push(" No compatibility changes detected.");
|
|
88
|
+
return lines.join("\n");
|
|
89
|
+
}
|
|
90
|
+
const breaking = diff.changes.filter((c) => c.severity === "breaking");
|
|
91
|
+
const softRisk = diff.changes.filter((c) => c.severity === "soft-risk");
|
|
92
|
+
const additive = diff.changes.filter((c) => c.severity === "additive");
|
|
93
|
+
if (breaking.length > 0) {
|
|
94
|
+
lines.push("");
|
|
95
|
+
lines.push(" Breaking:");
|
|
96
|
+
for (const c of breaking) {
|
|
97
|
+
lines.push(` [${c.category}] ${c.symbol} — ${c.message}`);
|
|
98
|
+
if (opts?.explain && c.provenance !== "unknown") lines.push(` provenance: ${c.provenance}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (softRisk.length > 0) {
|
|
102
|
+
lines.push("");
|
|
103
|
+
lines.push(" Soft-risk:");
|
|
104
|
+
for (const c of softRisk) {
|
|
105
|
+
lines.push(` [${c.category}] ${c.symbol} — ${c.message}`);
|
|
106
|
+
if (opts?.explain && c.provenance !== "unknown") lines.push(` provenance: ${c.provenance}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (additive.length > 0) {
|
|
110
|
+
lines.push("");
|
|
111
|
+
lines.push(` Additive: ${additive.length} new symbol(s)`);
|
|
112
|
+
}
|
|
113
|
+
return lines.join("\n");
|
|
114
|
+
}
|
|
115
|
+
/** Generate a conceptual cross-language report from multiple per-language results. */
|
|
116
|
+
function generateConceptualReport(perLanguageResults) {
|
|
117
|
+
return { conceptualChanges: buildConceptualRollup(perLanguageResults).conceptualChanges.map((c) => ({
|
|
118
|
+
id: c.id,
|
|
119
|
+
symbol: c.symbol,
|
|
120
|
+
category: c.category,
|
|
121
|
+
impact: c.impact
|
|
122
|
+
})) };
|
|
123
|
+
}
|
|
124
|
+
/** Format a conceptual cross-language summary for terminal output. */
|
|
125
|
+
function formatConceptualSummary(perLanguageResults) {
|
|
126
|
+
const rollup = buildConceptualRollup(perLanguageResults);
|
|
127
|
+
const summary = summarizeConceptualChanges(rollup);
|
|
128
|
+
const lines = [];
|
|
129
|
+
lines.push("Cross-language conceptual summary:");
|
|
130
|
+
lines.push(` ${summary.breaking} breaking, ${summary.softRisk} soft-risk, ${summary.additive} additive`);
|
|
131
|
+
if (rollup.conceptualChanges.length === 0) {
|
|
132
|
+
lines.push(" No cross-language changes.");
|
|
133
|
+
return lines.join("\n");
|
|
134
|
+
}
|
|
135
|
+
for (const change of rollup.conceptualChanges) {
|
|
136
|
+
const sev = highestSeverity(change);
|
|
137
|
+
const impactStr = Object.entries(change.impact).map(([lang, s]) => `${lang}: ${s}`).join(", ");
|
|
138
|
+
lines.push(` [${sev}] ${change.category}: ${change.symbol}`);
|
|
139
|
+
lines.push(` impact: ${impactStr}`);
|
|
140
|
+
}
|
|
141
|
+
return lines.join("\n");
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
//#region src/compat/approvals.ts
|
|
145
|
+
/** Validate that an approval is narrow enough to be accepted. */
|
|
146
|
+
function validateApproval(approval) {
|
|
147
|
+
const errors = [];
|
|
148
|
+
if (!approval.symbol || approval.symbol.trim() === "") errors.push("Approval must target a specific symbol");
|
|
149
|
+
if (!approval.category) errors.push("Approval must specify a change category");
|
|
150
|
+
if (!approval.reason || approval.reason.trim() === "") errors.push("Approval must include a reason");
|
|
151
|
+
if (approval.symbol === "*" || approval.symbol.endsWith(".*") || approval.symbol.endsWith("::*")) errors.push(`Approval symbol "${approval.symbol}" is too broad — must target a specific symbol`);
|
|
152
|
+
return {
|
|
153
|
+
valid: errors.length === 0,
|
|
154
|
+
errors
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/** Validate all approvals in a config. Returns errors keyed by index. */
|
|
158
|
+
function validateApprovals(approvals) {
|
|
159
|
+
const result = /* @__PURE__ */ new Map();
|
|
160
|
+
for (let i = 0; i < approvals.length; i++) {
|
|
161
|
+
const validation = validateApproval(approvals[i]);
|
|
162
|
+
if (!validation.valid) result.set(i, validation.errors);
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Match a classified change against a list of approvals.
|
|
168
|
+
* Returns the first matching approval, or null if none match.
|
|
169
|
+
*/
|
|
170
|
+
function matchApproval(change, approvals, language) {
|
|
171
|
+
for (const approval of approvals) if (approvalMatchesChange(approval, change, language)) return approval;
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Apply approvals to a list of changes.
|
|
176
|
+
* Returns matches for every change (approved or not).
|
|
177
|
+
*/
|
|
178
|
+
function applyApprovals(changes, approvals, language) {
|
|
179
|
+
return changes.map((change) => {
|
|
180
|
+
const approval = matchApproval(change, approvals, language);
|
|
181
|
+
return {
|
|
182
|
+
change,
|
|
183
|
+
approval,
|
|
184
|
+
approved: approval !== null
|
|
185
|
+
};
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Filter changes to only those NOT covered by approvals.
|
|
190
|
+
* These are the remaining unapproved changes that may cause failure.
|
|
191
|
+
*/
|
|
192
|
+
function unapprovedChanges(changes, approvals, language) {
|
|
193
|
+
return changes.filter((change) => !matchApproval(change, approvals, language));
|
|
194
|
+
}
|
|
195
|
+
function approvalMatchesChange(approval, change, language) {
|
|
196
|
+
if (approval.approved === false) return false;
|
|
197
|
+
if (approval.category !== change.category) return false;
|
|
198
|
+
if (!symbolMatches(approval.symbol, change.symbol)) return false;
|
|
199
|
+
if (!languageMatches(approval.appliesTo, language)) return false;
|
|
200
|
+
if (approval.match && !narrowingMatches(approval.match, change)) return false;
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
function symbolMatches(approvalSymbol, changeSymbol) {
|
|
204
|
+
if (approvalSymbol === changeSymbol) return true;
|
|
205
|
+
return approvalSymbol.replace(/::/g, ".").replace(/\\/g, ".") === changeSymbol.replace(/::/g, ".").replace(/\\/g, ".");
|
|
206
|
+
}
|
|
207
|
+
function languageMatches(appliesTo, language) {
|
|
208
|
+
if (!appliesTo || appliesTo === "all-impacted-languages") return true;
|
|
209
|
+
return appliesTo.includes(language);
|
|
210
|
+
}
|
|
211
|
+
function narrowingMatches(match, change) {
|
|
212
|
+
if (match.parameter) {
|
|
213
|
+
const paramInOld = change.old.parameter === match.parameter;
|
|
214
|
+
const paramInNew = change.new.parameter === match.parameter;
|
|
215
|
+
if (!paramInOld && !paramInNew) return false;
|
|
216
|
+
}
|
|
217
|
+
if (match.member) {
|
|
218
|
+
const memberInOld = change.old.member === match.member;
|
|
219
|
+
const memberInNew = change.new.member === match.member;
|
|
220
|
+
if (!memberInOld && !memberInNew) return false;
|
|
221
|
+
}
|
|
222
|
+
if (match.oldName) {
|
|
223
|
+
if (!Object.values(change.old).some((v) => v === match.oldName)) return false;
|
|
224
|
+
}
|
|
225
|
+
if (match.newName) {
|
|
226
|
+
if (!Object.values(change.new).some((v) => v === match.newName)) return false;
|
|
227
|
+
}
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
//#endregion
|
|
12
231
|
//#region src/compat/extractors/shared.ts
|
|
13
232
|
/** Sort an object's keys alphabetically. Shared across all extractors for deterministic output. */
|
|
14
233
|
function sortRecord(record) {
|
|
@@ -38,6 +257,9 @@ var ExportCollector = class {
|
|
|
38
257
|
const nodeExtractor = {
|
|
39
258
|
language: "node",
|
|
40
259
|
hints: nodeHints,
|
|
260
|
+
async extractSnapshot(sdkPath) {
|
|
261
|
+
return apiSurfaceToSnapshot(await this.extract(sdkPath));
|
|
262
|
+
},
|
|
41
263
|
async extract(sdkPath) {
|
|
42
264
|
sdkPath = resolve(sdkPath);
|
|
43
265
|
const configPath = ts.findConfigFile(sdkPath, ts.sys.fileExists, "tsconfig.json");
|
|
@@ -176,12 +398,13 @@ function extractClass(sym, checker) {
|
|
|
176
398
|
else deprecationMessage = "";
|
|
177
399
|
}
|
|
178
400
|
for (const member of decl.members) if (ts.isConstructorDeclaration(member)) for (const param of member.parameters) {
|
|
179
|
-
const paramName = param.name.getText();
|
|
401
|
+
const { name: paramName, isDestructured } = extractParameterInfo(param, param.name.getText());
|
|
180
402
|
const paramType = param.type ? checker.typeToString(checker.getTypeFromTypeNode(param.type)) : "any";
|
|
181
403
|
constructorParams.push({
|
|
182
404
|
name: paramName,
|
|
183
405
|
type: paramType,
|
|
184
|
-
optional: !!param.questionToken || !!param.initializer
|
|
406
|
+
optional: !!param.questionToken || !!param.initializer,
|
|
407
|
+
passingStyle: isDestructured ? "options_object" : "positional"
|
|
185
408
|
});
|
|
186
409
|
}
|
|
187
410
|
}
|
|
@@ -226,10 +449,56 @@ function extractParam(sym, checker) {
|
|
|
226
449
|
const decl = sym.getDeclarations()?.[0];
|
|
227
450
|
const isOptional = decl && ts.isParameter(decl) ? !!decl.questionToken || !!decl.initializer : false;
|
|
228
451
|
const type = checker.getTypeOfSymbolAtLocation(sym, decl);
|
|
452
|
+
const { name, isDestructured } = extractParameterInfo(decl, sym.name);
|
|
453
|
+
const typeStr = checker.typeToString(type);
|
|
454
|
+
let passingStyle;
|
|
455
|
+
if (isDestructured) passingStyle = "options_object";
|
|
456
|
+
else {
|
|
457
|
+
const resolvedType = checker.getTypeOfSymbolAtLocation(sym, decl);
|
|
458
|
+
const isObjectLike = resolvedType.isClassOrInterface() || (resolvedType.getFlags() & ts.TypeFlags.Object) !== 0;
|
|
459
|
+
const isPrimitive = [
|
|
460
|
+
"string",
|
|
461
|
+
"number",
|
|
462
|
+
"boolean",
|
|
463
|
+
"undefined",
|
|
464
|
+
"null",
|
|
465
|
+
"void",
|
|
466
|
+
"never",
|
|
467
|
+
"any",
|
|
468
|
+
"unknown"
|
|
469
|
+
].includes(typeStr);
|
|
470
|
+
if (isObjectLike && !isPrimitive && !typeStr.startsWith("Promise<")) passingStyle = "options_object";
|
|
471
|
+
else passingStyle = "positional";
|
|
472
|
+
}
|
|
229
473
|
return {
|
|
230
|
-
name
|
|
231
|
-
type:
|
|
232
|
-
optional: isOptional
|
|
474
|
+
name,
|
|
475
|
+
type: typeStr,
|
|
476
|
+
optional: isOptional,
|
|
477
|
+
passingStyle
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
function extractParameterInfo(decl, fallback) {
|
|
481
|
+
if (!decl || !ts.isParameter(decl)) return {
|
|
482
|
+
name: fallback,
|
|
483
|
+
isDestructured: false
|
|
484
|
+
};
|
|
485
|
+
if (ts.isIdentifier(decl.name)) return {
|
|
486
|
+
name: decl.name.text,
|
|
487
|
+
isDestructured: false
|
|
488
|
+
};
|
|
489
|
+
const index = decl.parent.parameters?.indexOf(decl) ?? -1;
|
|
490
|
+
const suffix = index > 0 ? String(index) : "";
|
|
491
|
+
if (ts.isObjectBindingPattern(decl.name)) return {
|
|
492
|
+
name: `options${suffix}`,
|
|
493
|
+
isDestructured: true
|
|
494
|
+
};
|
|
495
|
+
if (ts.isArrayBindingPattern(decl.name)) return {
|
|
496
|
+
name: `args${suffix}`,
|
|
497
|
+
isDestructured: false
|
|
498
|
+
};
|
|
499
|
+
return {
|
|
500
|
+
name: fallback,
|
|
501
|
+
isDestructured: false
|
|
233
502
|
};
|
|
234
503
|
}
|
|
235
504
|
function extractInterface(sym, checker) {
|
|
@@ -717,7 +986,8 @@ function buildSurface$6(allClasses, hints) {
|
|
|
717
986
|
const params = method.params.map((p) => ({
|
|
718
987
|
name: p.name,
|
|
719
988
|
type: p.type,
|
|
720
|
-
optional: p.optional
|
|
989
|
+
optional: p.optional,
|
|
990
|
+
passingStyle: "named"
|
|
721
991
|
}));
|
|
722
992
|
if (!apiMethods[method.name]) apiMethods[method.name] = [];
|
|
723
993
|
apiMethods[method.name].push({
|
|
@@ -859,6 +1129,9 @@ function createPhpExtractor(hintOverrides) {
|
|
|
859
1129
|
return {
|
|
860
1130
|
language: "php",
|
|
861
1131
|
hints: mergedHints,
|
|
1132
|
+
async extractSnapshot(sdkPath) {
|
|
1133
|
+
return apiSurfaceToSnapshot(await this.extract(sdkPath));
|
|
1134
|
+
},
|
|
862
1135
|
async extract(sdkPath) {
|
|
863
1136
|
let sourceDir;
|
|
864
1137
|
const libPath = resolve(sdkPath, "lib");
|
|
@@ -1050,6 +1323,7 @@ function extractFunctionParams(paramsNode, skipFirst) {
|
|
|
1050
1323
|
if (!paramsNode) return [];
|
|
1051
1324
|
const params = [];
|
|
1052
1325
|
let skippedFirst = false;
|
|
1326
|
+
let seenStarMarker = false;
|
|
1053
1327
|
for (const child of paramsNode.namedChildren) {
|
|
1054
1328
|
if (!skippedFirst && !skipFirst && child.type === "identifier" && (child.text === "self" || child.text === "cls")) {
|
|
1055
1329
|
skippedFirst = true;
|
|
@@ -1059,13 +1333,18 @@ function extractFunctionParams(paramsNode, skipFirst) {
|
|
|
1059
1333
|
skippedFirst = true;
|
|
1060
1334
|
continue;
|
|
1061
1335
|
}
|
|
1062
|
-
if (child.text === "*")
|
|
1336
|
+
if (child.text === "*") {
|
|
1337
|
+
seenStarMarker = true;
|
|
1338
|
+
continue;
|
|
1339
|
+
}
|
|
1063
1340
|
if (child.type === "list_splat_pattern") {
|
|
1341
|
+
seenStarMarker = true;
|
|
1064
1342
|
const nameNode = child.namedChildren.find((c) => c.type === "identifier");
|
|
1065
1343
|
params.push({
|
|
1066
1344
|
name: nameNode ? `*${nameNode.text}` : "*args",
|
|
1067
1345
|
type: "",
|
|
1068
|
-
optional: true
|
|
1346
|
+
optional: true,
|
|
1347
|
+
passingStyle: "positional"
|
|
1069
1348
|
});
|
|
1070
1349
|
continue;
|
|
1071
1350
|
}
|
|
@@ -1074,17 +1353,20 @@ function extractFunctionParams(paramsNode, skipFirst) {
|
|
|
1074
1353
|
params.push({
|
|
1075
1354
|
name: nameNode ? `**${nameNode.text}` : "**kwargs",
|
|
1076
1355
|
type: "",
|
|
1077
|
-
optional: true
|
|
1356
|
+
optional: true,
|
|
1357
|
+
passingStyle: "keyword"
|
|
1078
1358
|
});
|
|
1079
1359
|
continue;
|
|
1080
1360
|
}
|
|
1361
|
+
const passingStyle = seenStarMarker ? "keyword" : "keyword_or_positional";
|
|
1081
1362
|
if (child.type === "typed_parameter") {
|
|
1082
1363
|
const nameNode = child.namedChildren.find((c) => c.type === "identifier");
|
|
1083
1364
|
const typeNode = child.childForFieldName("type");
|
|
1084
1365
|
if (nameNode) params.push({
|
|
1085
1366
|
name: nameNode.text,
|
|
1086
1367
|
type: typeNode ? typeNode.text : "",
|
|
1087
|
-
optional: false
|
|
1368
|
+
optional: false,
|
|
1369
|
+
passingStyle
|
|
1088
1370
|
});
|
|
1089
1371
|
} else if (child.type === "typed_default_parameter") {
|
|
1090
1372
|
const nameNode = child.childForFieldName("name");
|
|
@@ -1092,19 +1374,22 @@ function extractFunctionParams(paramsNode, skipFirst) {
|
|
|
1092
1374
|
if (nameNode) params.push({
|
|
1093
1375
|
name: nameNode.text,
|
|
1094
1376
|
type: typeNode ? typeNode.text : "",
|
|
1095
|
-
optional: true
|
|
1377
|
+
optional: true,
|
|
1378
|
+
passingStyle
|
|
1096
1379
|
});
|
|
1097
1380
|
} else if (child.type === "default_parameter") {
|
|
1098
1381
|
const nameNode = child.childForFieldName("name");
|
|
1099
1382
|
if (nameNode) params.push({
|
|
1100
1383
|
name: nameNode.text,
|
|
1101
1384
|
type: "",
|
|
1102
|
-
optional: true
|
|
1385
|
+
optional: true,
|
|
1386
|
+
passingStyle
|
|
1103
1387
|
});
|
|
1104
1388
|
} else if (child.type === "identifier") params.push({
|
|
1105
1389
|
name: child.text,
|
|
1106
1390
|
type: "",
|
|
1107
|
-
optional: false
|
|
1391
|
+
optional: false,
|
|
1392
|
+
passingStyle
|
|
1108
1393
|
});
|
|
1109
1394
|
}
|
|
1110
1395
|
return params;
|
|
@@ -1324,7 +1609,8 @@ function buildSurface$5(parsedFiles, hints) {
|
|
|
1324
1609
|
const params = method.params.map((p) => ({
|
|
1325
1610
|
name: p.name,
|
|
1326
1611
|
type: p.type,
|
|
1327
|
-
optional: p.optional
|
|
1612
|
+
optional: p.optional,
|
|
1613
|
+
...p.passingStyle ? { passingStyle: p.passingStyle } : {}
|
|
1328
1614
|
}));
|
|
1329
1615
|
const returnType = unwrapReturnType(method.returnType);
|
|
1330
1616
|
if (!apiMethods[method.name]) apiMethods[method.name] = [];
|
|
@@ -1385,7 +1671,8 @@ function buildSurface$5(parsedFiles, hints) {
|
|
|
1385
1671
|
const params = method.params.map((p) => ({
|
|
1386
1672
|
name: p.name,
|
|
1387
1673
|
type: p.type,
|
|
1388
|
-
optional: p.optional
|
|
1674
|
+
optional: p.optional,
|
|
1675
|
+
...p.passingStyle ? { passingStyle: p.passingStyle } : {}
|
|
1389
1676
|
}));
|
|
1390
1677
|
if (!apiMethods[method.name]) apiMethods[method.name] = [];
|
|
1391
1678
|
apiMethods[method.name].push({
|
|
@@ -1419,14 +1706,16 @@ function buildSurface$5(parsedFiles, hints) {
|
|
|
1419
1706
|
constructorParams.push(...method.params.map((p) => ({
|
|
1420
1707
|
name: p.name,
|
|
1421
1708
|
type: p.type,
|
|
1422
|
-
optional: p.optional
|
|
1709
|
+
optional: p.optional,
|
|
1710
|
+
...p.passingStyle ? { passingStyle: p.passingStyle } : {}
|
|
1423
1711
|
})));
|
|
1424
1712
|
continue;
|
|
1425
1713
|
}
|
|
1426
1714
|
const params = method.params.map((p) => ({
|
|
1427
1715
|
name: p.name,
|
|
1428
1716
|
type: p.type,
|
|
1429
|
-
optional: p.optional
|
|
1717
|
+
optional: p.optional,
|
|
1718
|
+
...p.passingStyle ? { passingStyle: p.passingStyle } : {}
|
|
1430
1719
|
}));
|
|
1431
1720
|
if (!apiMethods[method.name]) apiMethods[method.name] = [];
|
|
1432
1721
|
apiMethods[method.name].push({
|
|
@@ -1703,6 +1992,9 @@ function createPythonExtractor(hintOverrides) {
|
|
|
1703
1992
|
return {
|
|
1704
1993
|
language: "python",
|
|
1705
1994
|
hints: mergedHints,
|
|
1995
|
+
async extractSnapshot(sdkPath) {
|
|
1996
|
+
return apiSurfaceToSnapshot(await this.extract(sdkPath));
|
|
1997
|
+
},
|
|
1706
1998
|
async extract(sdkPath) {
|
|
1707
1999
|
const sourceRoot = findPythonSourceRoot(sdkPath);
|
|
1708
2000
|
if (!sourceRoot) throw new ExtractorError(`No Python package found in ${sdkPath}`, `Ensure the --sdk-path argument points to a Python project root containing a package directory with __init__.py.`);
|
|
@@ -1899,7 +2191,8 @@ function extractMethodParams(methodNode) {
|
|
|
1899
2191
|
params.push({
|
|
1900
2192
|
name: paramNode.text,
|
|
1901
2193
|
type: "Object",
|
|
1902
|
-
optional: false
|
|
2194
|
+
optional: false,
|
|
2195
|
+
passingStyle: "positional"
|
|
1903
2196
|
});
|
|
1904
2197
|
break;
|
|
1905
2198
|
case "optional_parameter": {
|
|
@@ -1907,7 +2200,8 @@ function extractMethodParams(methodNode) {
|
|
|
1907
2200
|
if (nameNode) params.push({
|
|
1908
2201
|
name: nameNode.text,
|
|
1909
2202
|
type: "Object",
|
|
1910
|
-
optional: true
|
|
2203
|
+
optional: true,
|
|
2204
|
+
passingStyle: "positional"
|
|
1911
2205
|
});
|
|
1912
2206
|
break;
|
|
1913
2207
|
}
|
|
@@ -1918,7 +2212,8 @@ function extractMethodParams(methodNode) {
|
|
|
1918
2212
|
params.push({
|
|
1919
2213
|
name: nameNode.text,
|
|
1920
2214
|
type: "Object",
|
|
1921
|
-
optional: valueNode !== null
|
|
2215
|
+
optional: valueNode !== null,
|
|
2216
|
+
passingStyle: "keyword"
|
|
1922
2217
|
});
|
|
1923
2218
|
}
|
|
1924
2219
|
break;
|
|
@@ -1928,7 +2223,8 @@ function extractMethodParams(methodNode) {
|
|
|
1928
2223
|
params.push({
|
|
1929
2224
|
name: nameNode ? `*${nameNode.text}` : "*args",
|
|
1930
2225
|
type: "Object",
|
|
1931
|
-
optional: true
|
|
2226
|
+
optional: true,
|
|
2227
|
+
passingStyle: "positional"
|
|
1932
2228
|
});
|
|
1933
2229
|
break;
|
|
1934
2230
|
}
|
|
@@ -1937,7 +2233,8 @@ function extractMethodParams(methodNode) {
|
|
|
1937
2233
|
params.push({
|
|
1938
2234
|
name: nameNode ? `**${nameNode.text}` : "**kwargs",
|
|
1939
2235
|
type: "Object",
|
|
1940
|
-
optional: true
|
|
2236
|
+
optional: true,
|
|
2237
|
+
passingStyle: "keyword"
|
|
1941
2238
|
});
|
|
1942
2239
|
break;
|
|
1943
2240
|
}
|
|
@@ -1946,7 +2243,8 @@ function extractMethodParams(methodNode) {
|
|
|
1946
2243
|
params.push({
|
|
1947
2244
|
name: nameNode ? `&${nameNode.text}` : "&block",
|
|
1948
2245
|
type: "Object",
|
|
1949
|
-
optional: true
|
|
2246
|
+
optional: true,
|
|
2247
|
+
passingStyle: "positional"
|
|
1950
2248
|
});
|
|
1951
2249
|
break;
|
|
1952
2250
|
}
|
|
@@ -2086,6 +2384,9 @@ function collectRbFiles(dir) {
|
|
|
2086
2384
|
const rubyExtractor = {
|
|
2087
2385
|
language: "ruby",
|
|
2088
2386
|
hints: rubyHints,
|
|
2387
|
+
async extractSnapshot(sdkPath) {
|
|
2388
|
+
return apiSurfaceToSnapshot(await this.extract(sdkPath));
|
|
2389
|
+
},
|
|
2089
2390
|
async extract(sdkPath) {
|
|
2090
2391
|
const libPath = resolve(sdkPath, "lib");
|
|
2091
2392
|
try {
|
|
@@ -2517,7 +2818,8 @@ function buildSurface$4(allStructs, allTypes, allFuncs, allConsts) {
|
|
|
2517
2818
|
const params = fn.params.filter((p) => p.type !== "context.Context").map((p) => ({
|
|
2518
2819
|
name: p.name,
|
|
2519
2820
|
type: goTypeToString(p.type),
|
|
2520
|
-
optional: false
|
|
2821
|
+
optional: false,
|
|
2822
|
+
passingStyle: "positional"
|
|
2521
2823
|
}));
|
|
2522
2824
|
if (!apiMethods[fn.name]) apiMethods[fn.name] = [];
|
|
2523
2825
|
apiMethods[fn.name].push({
|
|
@@ -2674,6 +2976,9 @@ const goExtractor = {
|
|
|
2674
2976
|
return false;
|
|
2675
2977
|
}
|
|
2676
2978
|
},
|
|
2979
|
+
async extractSnapshot(sdkPath) {
|
|
2980
|
+
return apiSurfaceToSnapshot(await this.extract(sdkPath));
|
|
2981
|
+
},
|
|
2677
2982
|
async extract(sdkPath) {
|
|
2678
2983
|
const goFiles = walkGoFiles(sdkPath);
|
|
2679
2984
|
if (goFiles.length === 0) throw new ExtractorError(`No .go files found in ${sdkPath}`, `Ensure the --sdk-path argument points to a Go project root containing .go source files.`);
|
|
@@ -3005,7 +3310,8 @@ function buildSurface$3(allStructs, allEnums, allFuncs, allTraits, allTypeAliase
|
|
|
3005
3310
|
const params = fn.params.map((p) => ({
|
|
3006
3311
|
name: p.name,
|
|
3007
3312
|
type: rustTypeToString(p.type),
|
|
3008
|
-
optional: p.type.startsWith("Option<")
|
|
3313
|
+
optional: p.type.startsWith("Option<"),
|
|
3314
|
+
passingStyle: "positional"
|
|
3009
3315
|
}));
|
|
3010
3316
|
const returnType = unwrapResultType(fn.returnType);
|
|
3011
3317
|
if (!apiMethods[fn.name]) apiMethods[fn.name] = [];
|
|
@@ -3162,6 +3468,9 @@ const rustExtractor = {
|
|
|
3162
3468
|
return [`${modelName}Response`];
|
|
3163
3469
|
}
|
|
3164
3470
|
},
|
|
3471
|
+
async extractSnapshot(sdkPath) {
|
|
3472
|
+
return apiSurfaceToSnapshot(await this.extract(sdkPath));
|
|
3473
|
+
},
|
|
3165
3474
|
async extract(sdkPath) {
|
|
3166
3475
|
const rsFiles = walkRustFiles(sdkPath);
|
|
3167
3476
|
if (rsFiles.length === 0) throw new ExtractorError(`No .rs files found in ${sdkPath}`, `Ensure the --sdk-path argument points to a Rust project root containing .rs source files.`);
|
|
@@ -3487,7 +3796,8 @@ function buildSurface$2(allDataClasses, allClasses, allEnums, allTypeAliases) {
|
|
|
3487
3796
|
const params = method.params.map((p) => ({
|
|
3488
3797
|
name: p.name,
|
|
3489
3798
|
type: p.type,
|
|
3490
|
-
optional: p.optional
|
|
3799
|
+
optional: p.optional,
|
|
3800
|
+
passingStyle: "named"
|
|
3491
3801
|
}));
|
|
3492
3802
|
if (!methods[method.name]) methods[method.name] = [];
|
|
3493
3803
|
methods[method.name].push({
|
|
@@ -3500,7 +3810,8 @@ function buildSurface$2(allDataClasses, allClasses, allEnums, allTypeAliases) {
|
|
|
3500
3810
|
const constructorParams = cls.constructorParams.map((p) => ({
|
|
3501
3811
|
name: p.name,
|
|
3502
3812
|
type: p.type,
|
|
3503
|
-
optional: false
|
|
3813
|
+
optional: false,
|
|
3814
|
+
passingStyle: "named"
|
|
3504
3815
|
}));
|
|
3505
3816
|
classes[cls.name] = {
|
|
3506
3817
|
name: cls.name,
|
|
@@ -3595,6 +3906,9 @@ const kotlinExtractor = {
|
|
|
3595
3906
|
return [`${modelName}Response`];
|
|
3596
3907
|
}
|
|
3597
3908
|
},
|
|
3909
|
+
async extractSnapshot(sdkPath) {
|
|
3910
|
+
return apiSurfaceToSnapshot(await this.extract(sdkPath));
|
|
3911
|
+
},
|
|
3598
3912
|
async extract(sdkPath) {
|
|
3599
3913
|
const ktFiles = walkKotlinFiles(sdkPath);
|
|
3600
3914
|
if (ktFiles.length === 0) throw new ExtractorError(`No .kt files found in ${sdkPath}`, `Ensure the --sdk-path argument points to a Kotlin project root containing .kt source files.`);
|
|
@@ -3850,7 +4164,8 @@ function buildSurface$1(allClasses, allEnums, _hints) {
|
|
|
3850
4164
|
const params = method.params.map((p) => ({
|
|
3851
4165
|
name: p.name,
|
|
3852
4166
|
type: p.type,
|
|
3853
|
-
optional: p.optional
|
|
4167
|
+
optional: p.optional,
|
|
4168
|
+
passingStyle: "named"
|
|
3854
4169
|
}));
|
|
3855
4170
|
if (!methods[method.name]) methods[method.name] = [];
|
|
3856
4171
|
methods[method.name].push({
|
|
@@ -3871,7 +4186,8 @@ function buildSurface$1(allClasses, allEnums, _hints) {
|
|
|
3871
4186
|
const constructorParams = cls.constructorParams.map((p) => ({
|
|
3872
4187
|
name: p.name,
|
|
3873
4188
|
type: p.type,
|
|
3874
|
-
optional: false
|
|
4189
|
+
optional: false,
|
|
4190
|
+
passingStyle: "named"
|
|
3875
4191
|
}));
|
|
3876
4192
|
classes[cls.name] = {
|
|
3877
4193
|
name: cls.name,
|
|
@@ -4086,6 +4402,9 @@ function createDotnetExtractor(hintOverrides) {
|
|
|
4086
4402
|
return {
|
|
4087
4403
|
language: "dotnet",
|
|
4088
4404
|
hints: mergedHints,
|
|
4405
|
+
async extractSnapshot(sdkPath) {
|
|
4406
|
+
return apiSurfaceToSnapshot(await this.extract(sdkPath));
|
|
4407
|
+
},
|
|
4089
4408
|
async extract(sdkPath) {
|
|
4090
4409
|
let sourceDir;
|
|
4091
4410
|
const srcPath = resolve(sdkPath, "src");
|
|
@@ -4264,11 +4583,17 @@ function extractFunctions(modules, sourceFile) {
|
|
|
4264
4583
|
const paramsStr = funcMatch[3] || "";
|
|
4265
4584
|
if (name === "defstruct" || name === "defmodule") continue;
|
|
4266
4585
|
const params = [];
|
|
4586
|
+
const paramStyles = [];
|
|
4267
4587
|
if (paramsStr.trim()) {
|
|
4268
4588
|
const paramParts = paramsStr.split(",");
|
|
4269
4589
|
for (const part of paramParts) {
|
|
4270
|
-
const
|
|
4271
|
-
|
|
4590
|
+
const trimmed = part.trim();
|
|
4591
|
+
const paramNameMatch = trimmed.match(/^(\w+)/);
|
|
4592
|
+
if (paramNameMatch) {
|
|
4593
|
+
params.push(paramNameMatch[1]);
|
|
4594
|
+
const isKeywordList = /\\\\\s*\[/.test(trimmed);
|
|
4595
|
+
paramStyles.push(isKeywordList ? "keyword" : "positional");
|
|
4596
|
+
}
|
|
4272
4597
|
}
|
|
4273
4598
|
}
|
|
4274
4599
|
functions.push({
|
|
@@ -4276,6 +4601,7 @@ function extractFunctions(modules, sourceFile) {
|
|
|
4276
4601
|
name,
|
|
4277
4602
|
arity: params.length,
|
|
4278
4603
|
params,
|
|
4604
|
+
paramStyles,
|
|
4279
4605
|
isPrivate,
|
|
4280
4606
|
sourceFile
|
|
4281
4607
|
});
|
|
@@ -4436,10 +4762,11 @@ function buildSurface(allStructs, allFunctions, allEnumModules, allTypeSpecs) {
|
|
|
4436
4762
|
for (const func of funcs) {
|
|
4437
4763
|
if (seenFuncs.has(func.name)) continue;
|
|
4438
4764
|
seenFuncs.add(func.name);
|
|
4439
|
-
const params = func.params.map((p) => ({
|
|
4765
|
+
const params = func.params.map((p, i) => ({
|
|
4440
4766
|
name: p,
|
|
4441
4767
|
type: "any",
|
|
4442
|
-
optional: false
|
|
4768
|
+
optional: false,
|
|
4769
|
+
passingStyle: func.paramStyles[i] ?? "positional"
|
|
4443
4770
|
}));
|
|
4444
4771
|
if (!methods[func.name]) methods[func.name] = [];
|
|
4445
4772
|
methods[func.name].push({
|
|
@@ -4535,6 +4862,9 @@ const elixirExtractor = {
|
|
|
4535
4862
|
return [`${modelName}Response`];
|
|
4536
4863
|
}
|
|
4537
4864
|
},
|
|
4865
|
+
async extractSnapshot(sdkPath) {
|
|
4866
|
+
return apiSurfaceToSnapshot(await this.extract(sdkPath));
|
|
4867
|
+
},
|
|
4538
4868
|
async extract(sdkPath) {
|
|
4539
4869
|
let sourceDir;
|
|
4540
4870
|
const libPath = resolve(sdkPath, "lib");
|
|
@@ -4571,6 +4901,6 @@ const elixirExtractor = {
|
|
|
4571
4901
|
}
|
|
4572
4902
|
};
|
|
4573
4903
|
//#endregion
|
|
4574
|
-
export { buildOverlayLookup, diffSurfaces, dotnetExtractor, elixirExtractor, filterSurface, getExtractor, goExtractor, kotlinExtractor, nodeExtractor, nodeHints, patchOverlay, phpExtractor, pythonExtractor, registerExtractor, resolveHints, rubyExtractor, rustExtractor, specDerivedEnumValues, specDerivedFieldPaths, specDerivedHttpKeys, specDerivedMethodPaths, specDerivedNames };
|
|
4904
|
+
export { ALL_LANGUAGE_IDS, COMPAT_SCHEMA_VERSION, apiSurfaceToSnapshot, applyApprovals, buildConceptualRollup, buildOverlayLookup, classifyAddedSymbol, classifySymbolChanges, defaultSeverityForCategory, diffSnapshots, diffSurfaces, dotnetExtractor, elixirExtractor, filterSurface, formatConceptualSummary, formatHumanSummary, generateConceptualReport, generateReport, getDefaultPolicy, getExtractor, goExtractor, highestSeverity, isCompatibleSchemaVersion, isPatchableChange, kotlinExtractor, matchApproval, mergePolicy, nodeExtractor, nodeHints, patchOverlay, phpExtractor, pythonExtractor, registerExtractor, resolveHints, rubyExtractor, rustExtractor, severityMeetsThreshold, specDerivedEnumValues, specDerivedFieldPaths, specDerivedHttpKeys, specDerivedMethodPaths, specDerivedNames, summarizeChanges, summarizeConceptualChanges, unapprovedChanges, validateApproval, validateApprovals, validateSnapshot };
|
|
4575
4905
|
|
|
4576
4906
|
//# sourceMappingURL=index.mjs.map
|