@workos/oagen 0.11.0 → 0.13.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/README.md +5 -0
- package/dist/cli/index.mjs +131 -15
- package/dist/cli/index.mjs.map +1 -1
- package/dist/compat/index.d.mts +4 -2
- package/dist/compat/index.d.mts.map +1 -1
- package/dist/compat/index.mjs +6 -3
- package/dist/compat/index.mjs.map +1 -1
- package/dist/{diff-DZvzV9p3.mjs → diff-C38px0NK.mjs} +4 -3
- package/dist/diff-C38px0NK.mjs.map +1 -0
- package/dist/{differ-8emGtevH.d.mts → differ-fdF9qogA.d.mts} +9 -2
- package/dist/differ-fdF9qogA.d.mts.map +1 -0
- package/dist/index.d.mts +61 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/dist/{overlay-Dddz3Awz.mjs → overlay-xp7F8_dW.mjs} +85 -2
- package/dist/overlay-xp7F8_dW.mjs.map +1 -0
- package/dist/scripts/smoke/baseline.mjs +1 -1
- package/dist/scripts/smoke/baseline.mjs.map +1 -1
- package/dist/smoke.d.mts +24 -0
- package/dist/smoke.d.mts.map +1 -1
- package/dist/smoke.mjs +1 -1
- package/dist/smoke.mjs.map +1 -1
- package/dist/{tree-sitter-C53w_0WE.mjs → tree-sitter-DcUvm0KA.mjs} +23 -2
- package/dist/tree-sitter-DcUvm0KA.mjs.map +1 -0
- package/dist/{types-DpD1SBY_.d.mts → types-BL762XqW.d.mts} +7 -2
- package/dist/{types-DpD1SBY_.d.mts.map → types-BL762XqW.d.mts.map} +1 -1
- package/dist/verify/index.d.mts +2 -2
- package/dist/verify/index.mjs +3 -3
- package/docs/advanced/index.md +1 -0
- package/docs/advanced/transform-spec.md +124 -0
- package/docs/cli.md +13 -11
- package/docs/core/compatibility-policy.md +26 -0
- package/docs/core/compatibility.md +6 -0
- package/docs/index.md +1 -0
- package/package.json +1 -1
- package/dist/diff-DZvzV9p3.mjs.map +0 -1
- package/dist/differ-8emGtevH.d.mts.map +0 -1
- package/dist/overlay-Dddz3Awz.mjs.map +0 -1
- package/dist/tree-sitter-C53w_0WE.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -196,6 +196,11 @@ export default {
|
|
|
196
196
|
Connections: 'SSO', // All Connections ops mount on SSO
|
|
197
197
|
DirectoryGroups: 'DirectorySync',
|
|
198
198
|
},
|
|
199
|
+
modelHints: {
|
|
200
|
+
// Pin a model's placement when "first service to reference it wins"
|
|
201
|
+
// would otherwise drift as the spec evolves.
|
|
202
|
+
User: 'UserManagementUsers',
|
|
203
|
+
},
|
|
199
204
|
};
|
|
200
205
|
```
|
|
201
206
|
|
package/dist/cli/index.mjs
CHANGED
|
@@ -2278,7 +2278,7 @@ function validateModelRefs(spec) {
|
|
|
2278
2278
|
//#region src/parser/parse.ts
|
|
2279
2279
|
async function parseSpec(specPath, options) {
|
|
2280
2280
|
const { parsed } = await loadAndBundleSpec(specPath);
|
|
2281
|
-
const spec = parsed;
|
|
2281
|
+
const spec = options?.transformSpec ? options.transformSpec(parsed) : parsed;
|
|
2282
2282
|
const version = spec.openapi ?? "";
|
|
2283
2283
|
if (!version.startsWith("3.")) throw new SpecParseError(`Unsupported OpenAPI version: ${version}. oagen requires OpenAPI 3.x`, `Update the spec to OpenAPI 3.0 or 3.1. If you are using Swagger 2.x, convert it first with \`npx swagger2openapi ${specPath}\`.`);
|
|
2284
2284
|
const { models, enums } = extractSchemas(spec.components?.schemas, { schemaNameTransform: options?.schemaNameTransform });
|
|
@@ -2326,7 +2326,11 @@ function extractAuthSchemes(securitySchemes) {
|
|
|
2326
2326
|
//#endregion
|
|
2327
2327
|
//#region src/cli/parse.ts
|
|
2328
2328
|
async function parseCommand(opts) {
|
|
2329
|
-
const ir = await parseSpec(opts.spec
|
|
2329
|
+
const ir = await parseSpec(opts.spec, {
|
|
2330
|
+
operationIdTransform: opts.operationIdTransform,
|
|
2331
|
+
schemaNameTransform: opts.schemaNameTransform,
|
|
2332
|
+
transformSpec: opts.transformSpec
|
|
2333
|
+
});
|
|
2330
2334
|
console.log(JSON.stringify(ir, null, 2));
|
|
2331
2335
|
}
|
|
2332
2336
|
//#endregion
|
|
@@ -4289,7 +4293,7 @@ async function writeFiles(files, outputDir, options) {
|
|
|
4289
4293
|
continue;
|
|
4290
4294
|
}
|
|
4291
4295
|
if (file.skipIfExists) {
|
|
4292
|
-
if (header && !existingContent.startsWith(header)) await fs.writeFile(fullPath, header + "\n\n" + existingContent, "utf-8");
|
|
4296
|
+
if (header && !existingContent.startsWith(header) && !file.path.endsWith(".json")) await fs.writeFile(fullPath, header + "\n\n" + existingContent, "utf-8");
|
|
4293
4297
|
result.skipped.push(file.path);
|
|
4294
4298
|
continue;
|
|
4295
4299
|
}
|
|
@@ -4700,6 +4704,7 @@ function buildEmitterContext(spec, options) {
|
|
|
4700
4704
|
apiSurface: options.apiSurface,
|
|
4701
4705
|
overlayLookup: options.overlayLookup,
|
|
4702
4706
|
resolvedOperations: resolveOperations(spec, options.operationHints, options.mountRules),
|
|
4707
|
+
modelHints: options.modelHints,
|
|
4703
4708
|
targetDir: options.target,
|
|
4704
4709
|
priorTargetManifestPaths: options.priorTargetManifestPaths
|
|
4705
4710
|
};
|
|
@@ -5906,7 +5911,8 @@ function expandDocUrls(spec, docUrl) {
|
|
|
5906
5911
|
async function generateCommand(opts) {
|
|
5907
5912
|
let ir = await parseSpec(opts.spec, {
|
|
5908
5913
|
operationIdTransform: opts.operationIdTransform,
|
|
5909
|
-
schemaNameTransform: opts.schemaNameTransform
|
|
5914
|
+
schemaNameTransform: opts.schemaNameTransform,
|
|
5915
|
+
transformSpec: opts.transformSpec
|
|
5910
5916
|
});
|
|
5911
5917
|
if (opts.docUrl) ir = expandDocUrls(ir, opts.docUrl);
|
|
5912
5918
|
const emitter = getEmitter(opts.lang);
|
|
@@ -5932,6 +5938,7 @@ async function generateCommand(opts) {
|
|
|
5932
5938
|
overlayLookup,
|
|
5933
5939
|
operationHints: opts.operationHints,
|
|
5934
5940
|
mountRules: opts.mountRules,
|
|
5941
|
+
modelHints: opts.modelHints,
|
|
5935
5942
|
noPrune: opts.prune === false
|
|
5936
5943
|
});
|
|
5937
5944
|
if (opts.dryRun) for (const f of files) console.log(f.path);
|
|
@@ -6291,7 +6298,8 @@ function summarize(changes) {
|
|
|
6291
6298
|
async function diffCommand(opts) {
|
|
6292
6299
|
const parseOptions = {
|
|
6293
6300
|
operationIdTransform: opts.operationIdTransform,
|
|
6294
|
-
schemaNameTransform: opts.schemaNameTransform
|
|
6301
|
+
schemaNameTransform: opts.schemaNameTransform,
|
|
6302
|
+
transformSpec: opts.transformSpec
|
|
6295
6303
|
};
|
|
6296
6304
|
let [oldSpec, newSpec] = await Promise.all([parseSpec(opts.old, parseOptions), parseSpec(opts.new, parseOptions)]);
|
|
6297
6305
|
if (opts.docUrl) {
|
|
@@ -6666,7 +6674,10 @@ async function compatExtractCommand(opts) {
|
|
|
6666
6674
|
if (opts.spec) {
|
|
6667
6675
|
const specContent = readFileSync(opts.spec, "utf-8");
|
|
6668
6676
|
snapshot.source.specSha = createHash("sha256").update(specContent).digest("hex");
|
|
6669
|
-
enrichWithSpecContext(snapshot, await parseSpec(opts.spec, {
|
|
6677
|
+
enrichWithSpecContext(snapshot, await parseSpec(opts.spec, {
|
|
6678
|
+
schemaNameTransform: opts.schemaNameTransform,
|
|
6679
|
+
transformSpec: opts.transformSpec
|
|
6680
|
+
}));
|
|
6670
6681
|
}
|
|
6671
6682
|
const outputPath = resolve(opts.output, SNAPSHOT_FILENAME);
|
|
6672
6683
|
writeFileSync(outputPath, JSON.stringify(snapshot, null, 2));
|
|
@@ -7209,12 +7220,95 @@ function diffSnapshots(baseline, candidate, policy) {
|
|
|
7209
7220
|
if (isServiceWrapperConstructor(candSym, serviceAccessors)) continue;
|
|
7210
7221
|
changes.push(classifyAddedSymbol(candSym));
|
|
7211
7222
|
}
|
|
7223
|
+
detectForkedSchemas(changes, baseline, candidate);
|
|
7212
7224
|
return {
|
|
7213
7225
|
changes,
|
|
7214
7226
|
summary: summarizeChanges(changes)
|
|
7215
7227
|
};
|
|
7216
7228
|
}
|
|
7217
7229
|
/**
|
|
7230
|
+
* Detect "schema fork" antipattern and attach a remediation hint.
|
|
7231
|
+
*
|
|
7232
|
+
* Fires when:
|
|
7233
|
+
* 1. A return type or field type changed from `OldType` → `NewType`.
|
|
7234
|
+
* 2. `NewType` is newly added in the candidate snapshot.
|
|
7235
|
+
* 3. `NewType.fields ⊇ OldType.fields` (every field on the old type still
|
|
7236
|
+
* exists on the new one — the new schema is a strict superset, so the
|
|
7237
|
+
* same fields could have been added to the existing schema additively).
|
|
7238
|
+
*
|
|
7239
|
+
* Mutates `changes` in place: sets `remediation` on the matching change.
|
|
7240
|
+
* Leaves the original category and severity alone — this is just a hint.
|
|
7241
|
+
*
|
|
7242
|
+
* Identity match is by `displayName` of the type symbol, which corresponds
|
|
7243
|
+
* to the type name as it appears in `change.old.returnType` / `.type` and
|
|
7244
|
+
* `change.new.returnType` / `.type`.
|
|
7245
|
+
*/
|
|
7246
|
+
function detectForkedSchemas(changes, baseline, candidate) {
|
|
7247
|
+
const baselineTypeFields = collectTypeFieldSets(baseline);
|
|
7248
|
+
const candidateTypeFields = collectTypeFieldSets(candidate);
|
|
7249
|
+
const baselineTypeNames = new Set(baselineTypeFields.keys());
|
|
7250
|
+
for (const change of changes) {
|
|
7251
|
+
if (change.remediation) continue;
|
|
7252
|
+
let oldType;
|
|
7253
|
+
let newType;
|
|
7254
|
+
if (change.category === "return_type_changed") {
|
|
7255
|
+
oldType = change.old.returnType;
|
|
7256
|
+
newType = change.new.returnType;
|
|
7257
|
+
} else if (change.category === "field_type_changed") {
|
|
7258
|
+
oldType = change.old.type;
|
|
7259
|
+
newType = change.new.type;
|
|
7260
|
+
} else continue;
|
|
7261
|
+
if (!oldType || !newType || oldType === newType) continue;
|
|
7262
|
+
const oldTypeBare = bareTypeName(oldType);
|
|
7263
|
+
const newTypeBare = bareTypeName(newType);
|
|
7264
|
+
if (baselineTypeNames.has(newTypeBare)) continue;
|
|
7265
|
+
const oldFields = baselineTypeFields.get(oldTypeBare);
|
|
7266
|
+
const newFields = candidateTypeFields.get(newTypeBare);
|
|
7267
|
+
if (!oldFields || !newFields) continue;
|
|
7268
|
+
if (oldFields.size === 0) continue;
|
|
7269
|
+
let isSuperset = true;
|
|
7270
|
+
for (const f of oldFields) if (!newFields.has(f)) {
|
|
7271
|
+
isSuperset = false;
|
|
7272
|
+
break;
|
|
7273
|
+
}
|
|
7274
|
+
if (!isSuperset) continue;
|
|
7275
|
+
change.remediation = `Schema "${newTypeBare}" looks like "${oldTypeBare}" with additional fields. Consider adding the new fields to "${oldTypeBare}" instead of forking a new schema — forking forces a breaking type-name change in typed SDKs, while extending the existing schema is additive.`;
|
|
7276
|
+
}
|
|
7277
|
+
}
|
|
7278
|
+
/**
|
|
7279
|
+
* Build a map from type fqName → set of (lowercased) child field names.
|
|
7280
|
+
* Used by `detectForkedSchemas` for superset comparison.
|
|
7281
|
+
*/
|
|
7282
|
+
function collectTypeFieldSets(snapshot) {
|
|
7283
|
+
const result = /* @__PURE__ */ new Map();
|
|
7284
|
+
for (const sym of snapshot.symbols) {
|
|
7285
|
+
if (sym.kind !== "field" && sym.kind !== "property") continue;
|
|
7286
|
+
if (!sym.ownerFqName) continue;
|
|
7287
|
+
const localName = sym.fqName.includes(".") ? sym.fqName.slice(sym.fqName.lastIndexOf(".") + 1) : sym.fqName;
|
|
7288
|
+
let set = result.get(sym.ownerFqName);
|
|
7289
|
+
if (!set) {
|
|
7290
|
+
set = /* @__PURE__ */ new Set();
|
|
7291
|
+
result.set(sym.ownerFqName, set);
|
|
7292
|
+
}
|
|
7293
|
+
set.add(localName.toLowerCase());
|
|
7294
|
+
}
|
|
7295
|
+
return result;
|
|
7296
|
+
}
|
|
7297
|
+
/**
|
|
7298
|
+
* Strip array/nullable suffixes so we compare bare type names. Languages
|
|
7299
|
+
* encode these differently (`Foo[]`, `Foo | null`, `Foo?`, `List<Foo>`,
|
|
7300
|
+
* `Optional[Foo]`); this is a best-effort common-case stripper, not an
|
|
7301
|
+
* exhaustive parser.
|
|
7302
|
+
*/
|
|
7303
|
+
function bareTypeName(t) {
|
|
7304
|
+
let s = t.trim();
|
|
7305
|
+
s = s.replace(/\s*\|\s*null$/, "").replace(/\?$/, "");
|
|
7306
|
+
s = s.replace(/\[\]$/, "");
|
|
7307
|
+
const generic = s.match(/^[A-Za-z_][A-Za-z0-9_.]*<\s*([A-Za-z_][A-Za-z0-9_.]*)\s*>$/);
|
|
7308
|
+
if (generic) s = generic[1];
|
|
7309
|
+
return s;
|
|
7310
|
+
}
|
|
7311
|
+
/**
|
|
7218
7312
|
* Check if a symbol is a constructor belonging to a service wrapper class.
|
|
7219
7313
|
*
|
|
7220
7314
|
* Service wrapper constructors are internal plumbing (taking a client/config
|
|
@@ -7298,7 +7392,8 @@ function generateReport(diff, language) {
|
|
|
7298
7392
|
provenance: c.provenance,
|
|
7299
7393
|
old: c.old,
|
|
7300
7394
|
new: c.new,
|
|
7301
|
-
...c.message ? { message: c.message } : {}
|
|
7395
|
+
...c.message ? { message: c.message } : {},
|
|
7396
|
+
...c.remediation ? { remediation: c.remediation } : {}
|
|
7302
7397
|
}))
|
|
7303
7398
|
};
|
|
7304
7399
|
}
|
|
@@ -7319,6 +7414,7 @@ function formatHumanSummary(diff, opts) {
|
|
|
7319
7414
|
lines.push(" Breaking:");
|
|
7320
7415
|
for (const c of breaking) {
|
|
7321
7416
|
lines.push(` [${c.category}] ${c.symbol} — ${c.message}`);
|
|
7417
|
+
if (c.remediation) lines.push(` hint: ${c.remediation}`);
|
|
7322
7418
|
if (opts?.explain && c.provenance !== "unknown") lines.push(` provenance: ${c.provenance}`);
|
|
7323
7419
|
}
|
|
7324
7420
|
}
|
|
@@ -7327,6 +7423,7 @@ function formatHumanSummary(diff, opts) {
|
|
|
7327
7423
|
lines.push(" Soft-risk:");
|
|
7328
7424
|
for (const c of softRisk) {
|
|
7329
7425
|
lines.push(` [${c.category}] ${c.symbol} — ${c.message}`);
|
|
7426
|
+
if (c.remediation) lines.push(` hint: ${c.remediation}`);
|
|
7330
7427
|
if (opts?.explain && c.provenance !== "unknown") lines.push(` provenance: ${c.provenance}`);
|
|
7331
7428
|
}
|
|
7332
7429
|
}
|
|
@@ -7893,7 +7990,7 @@ function printCompatResult(result, baseline) {
|
|
|
7893
7990
|
console.log(`compat: ${result.preservationScore}% (${result.preservedSymbols}/${result.totalBaselineSymbols} symbols preserved)`);
|
|
7894
7991
|
}
|
|
7895
7992
|
async function verifyCommand(opts) {
|
|
7896
|
-
const { spec, oldSpec, lang, output, apiSurface, rawResults, smokeConfig, smokeRunner, scope, diagnostics, operationIdTransform, schemaNameTransform, compatConfig, compatReport, compatExplain } = opts;
|
|
7993
|
+
const { spec, oldSpec, lang, output, apiSurface, rawResults, smokeConfig, smokeRunner, scope, diagnostics, operationIdTransform, schemaNameTransform, transformSpec, compatConfig, compatReport, compatExplain } = opts;
|
|
7897
7994
|
const maxRetries = opts.maxRetries ?? 3;
|
|
7898
7995
|
const diagData = {};
|
|
7899
7996
|
const effectiveFailOn = opts.compatFailOn ?? compatConfig?.failOn ?? "breaking";
|
|
@@ -7909,7 +8006,8 @@ async function verifyCommand(opts) {
|
|
|
7909
8006
|
let parsedSpec;
|
|
7910
8007
|
if (effectiveScope === "spec-only" && spec) parsedSpec = await parseSpec(spec, {
|
|
7911
8008
|
operationIdTransform,
|
|
7912
|
-
schemaNameTransform
|
|
8009
|
+
schemaNameTransform,
|
|
8010
|
+
transformSpec
|
|
7913
8011
|
});
|
|
7914
8012
|
else if (effectiveScope === "spec-only") throw new CommandError("error: --scope spec-only requires --spec <path>", "", 1);
|
|
7915
8013
|
const compatFlow = parsedSpec && maxRetries > 0 ? await runOverlayRetryLoop({
|
|
@@ -7976,10 +8074,12 @@ async function verifyCommand(opts) {
|
|
|
7976
8074
|
console.log(separator);
|
|
7977
8075
|
const stalenessResult = runStalenessCheck(baseline, await parseSpec(oldSpec, {
|
|
7978
8076
|
operationIdTransform,
|
|
7979
|
-
schemaNameTransform
|
|
8077
|
+
schemaNameTransform,
|
|
8078
|
+
transformSpec
|
|
7980
8079
|
}), await parseSpec(spec, {
|
|
7981
8080
|
operationIdTransform,
|
|
7982
|
-
schemaNameTransform
|
|
8081
|
+
schemaNameTransform,
|
|
8082
|
+
transformSpec
|
|
7983
8083
|
}), lang);
|
|
7984
8084
|
if (stalenessResult.violations.length > 0) {
|
|
7985
8085
|
console.log(`Found ${stalenessResult.violations.length} stale symbol(s):`);
|
|
@@ -8279,7 +8379,8 @@ async function initCommand(opts) {
|
|
|
8279
8379
|
async function resolveCommand(opts) {
|
|
8280
8380
|
let ir = await parseSpec(opts.spec, {
|
|
8281
8381
|
operationIdTransform: opts.operationIdTransform,
|
|
8282
|
-
schemaNameTransform: opts.schemaNameTransform
|
|
8382
|
+
schemaNameTransform: opts.schemaNameTransform,
|
|
8383
|
+
transformSpec: opts.transformSpec
|
|
8283
8384
|
});
|
|
8284
8385
|
if (opts.docUrl) ir = expandDocUrls(ir, opts.docUrl);
|
|
8285
8386
|
const resolved = resolveOperations(ir, opts.operationHints, opts.mountRules);
|
|
@@ -8375,9 +8476,11 @@ const explicitConfigPath = configArgIdx !== -1 ? process.argv[configArgIdx + 1]
|
|
|
8375
8476
|
let configSmokeRunners;
|
|
8376
8477
|
let configOperationIdTransform;
|
|
8377
8478
|
let configSchemaNameTransform;
|
|
8479
|
+
let configTransformSpec;
|
|
8378
8480
|
let configDocUrl;
|
|
8379
8481
|
let configOperationHints;
|
|
8380
8482
|
let configMountRules;
|
|
8483
|
+
let configModelHints;
|
|
8381
8484
|
let configCompat;
|
|
8382
8485
|
try {
|
|
8383
8486
|
const config = await loadConfig(explicitConfigPath);
|
|
@@ -8386,9 +8489,11 @@ try {
|
|
|
8386
8489
|
configSmokeRunners = config.smokeRunners;
|
|
8387
8490
|
configOperationIdTransform = config.operationIdTransform;
|
|
8388
8491
|
configSchemaNameTransform = config.schemaNameTransform;
|
|
8492
|
+
configTransformSpec = config.transformSpec;
|
|
8389
8493
|
configDocUrl = config.docUrl;
|
|
8390
8494
|
configOperationHints = config.operationHints;
|
|
8391
8495
|
configMountRules = config.mountRules;
|
|
8496
|
+
configModelHints = config.modelHints;
|
|
8392
8497
|
configCompat = config.compat;
|
|
8393
8498
|
}
|
|
8394
8499
|
} catch (err) {
|
|
@@ -8401,7 +8506,12 @@ program.command("parse").description("Parse an OpenAPI spec and output IR as JSO
|
|
|
8401
8506
|
console.error("error: --spec <path> or OPENAPI_SPEC_PATH env var is required");
|
|
8402
8507
|
process.exit(1);
|
|
8403
8508
|
}
|
|
8404
|
-
return parseCommand(
|
|
8509
|
+
return parseCommand({
|
|
8510
|
+
...opts,
|
|
8511
|
+
operationIdTransform: configOperationIdTransform,
|
|
8512
|
+
schemaNameTransform: configSchemaNameTransform,
|
|
8513
|
+
transformSpec: configTransformSpec
|
|
8514
|
+
});
|
|
8405
8515
|
});
|
|
8406
8516
|
program.command("generate").description("Run a registered emitter against an OpenAPI spec").option("--spec <path>", "Path to OpenAPI spec file (or set OPENAPI_SPEC_PATH)").requiredOption("--lang <language>", "Target language").requiredOption("--output <dir>", "Output directory").option("--target <dir>", "Target directory for live SDK integration (merged output)").option("--namespace <name>", "SDK namespace/package name").option("--dry-run", "Preview files without writing").option("--api-surface <path>", "Path to baseline API surface JSON for compat overlay").option("--no-compat-check", "Skip compat overlay even if --api-surface is provided").option("--no-prune", "Skip deletion of stale files recorded in the previous .oagen-manifest.json").action((opts) => {
|
|
8407
8517
|
opts.spec ??= process.env.OPENAPI_SPEC_PATH;
|
|
@@ -8413,9 +8523,11 @@ program.command("generate").description("Run a registered emitter against an Ope
|
|
|
8413
8523
|
...opts,
|
|
8414
8524
|
operationIdTransform: configOperationIdTransform,
|
|
8415
8525
|
schemaNameTransform: configSchemaNameTransform,
|
|
8526
|
+
transformSpec: configTransformSpec,
|
|
8416
8527
|
docUrl: configDocUrl,
|
|
8417
8528
|
operationHints: configOperationHints,
|
|
8418
|
-
mountRules: configMountRules
|
|
8529
|
+
mountRules: configMountRules,
|
|
8530
|
+
modelHints: configModelHints
|
|
8419
8531
|
}).catch(handleError);
|
|
8420
8532
|
});
|
|
8421
8533
|
program.command("diff").description("Compare two OpenAPI specs and output a diff report").requiredOption("--old <path>", "Path to old spec").requiredOption("--new <path>", "Path to new spec").action((opts) => {
|
|
@@ -8423,6 +8535,7 @@ program.command("diff").description("Compare two OpenAPI specs and output a diff
|
|
|
8423
8535
|
...opts,
|
|
8424
8536
|
operationIdTransform: configOperationIdTransform,
|
|
8425
8537
|
schemaNameTransform: configSchemaNameTransform,
|
|
8538
|
+
transformSpec: configTransformSpec,
|
|
8426
8539
|
docUrl: configDocUrl
|
|
8427
8540
|
}).catch(handleError);
|
|
8428
8541
|
});
|
|
@@ -8434,7 +8547,8 @@ program.command("compat-extract").description("Extract a compat snapshot from a
|
|
|
8434
8547
|
opts.spec ??= process.env.OPENAPI_SPEC_PATH;
|
|
8435
8548
|
compatExtractCommand({
|
|
8436
8549
|
...opts,
|
|
8437
|
-
schemaNameTransform: configSchemaNameTransform
|
|
8550
|
+
schemaNameTransform: configSchemaNameTransform,
|
|
8551
|
+
transformSpec: configTransformSpec
|
|
8438
8552
|
}).catch(handleError);
|
|
8439
8553
|
});
|
|
8440
8554
|
program.command("compat-diff").description("Diff two compat snapshot files and produce a classified change report").requiredOption("--baseline <path>", "Path to the baseline compat snapshot JSON").requiredOption("--candidate <path>", "Path to the candidate compat snapshot JSON").option("--output <path>", "Write machine-readable report to this path").option("--fail-on <level>", "Fail threshold: none, breaking, or soft-risk", "breaking").option("--explain", "Include provenance explanations in output").action((opts) => {
|
|
@@ -8451,6 +8565,7 @@ program.command("verify").description("Run smoke tests (and optional compat chec
|
|
|
8451
8565
|
maxRetries: parseInt(opts.maxRetries, 10),
|
|
8452
8566
|
operationIdTransform: configOperationIdTransform,
|
|
8453
8567
|
schemaNameTransform: configSchemaNameTransform,
|
|
8568
|
+
transformSpec: configTransformSpec,
|
|
8454
8569
|
compatConfig: configCompat,
|
|
8455
8570
|
compatReport: opts.compatReport,
|
|
8456
8571
|
compatFailOn: opts.compatFailOn,
|
|
@@ -8468,6 +8583,7 @@ program.command("resolve").description("Resolve operation names from spec and ou
|
|
|
8468
8583
|
...opts,
|
|
8469
8584
|
operationIdTransform: configOperationIdTransform,
|
|
8470
8585
|
schemaNameTransform: configSchemaNameTransform,
|
|
8586
|
+
transformSpec: configTransformSpec,
|
|
8471
8587
|
docUrl: configDocUrl,
|
|
8472
8588
|
operationHints: configOperationHints,
|
|
8473
8589
|
mountRules: configMountRules
|