@workos/oagen 0.8.0 → 0.9.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 +68 -77
- package/dist/cli/index.mjs.map +1 -1
- package/dist/compat/index.mjs +1 -1
- package/dist/{diff-BaH9qa8k.mjs → diff-DZvzV9p3.mjs} +21 -21
- package/dist/{diff-BaH9qa8k.mjs.map → diff-DZvzV9p3.mjs.map} +1 -1
- package/dist/index.d.mts +10 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{overlay-TYxHOCow.mjs → overlay-Bt6oz0dg.mjs} +2 -2
- package/dist/{overlay-TYxHOCow.mjs.map → overlay-Bt6oz0dg.mjs.map} +1 -1
- package/dist/verify/index.d.mts.map +1 -1
- package/dist/verify/index.mjs +46 -31
- package/dist/verify/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -4771,8 +4771,7 @@ function generateAllFiles(spec, emitter, ctx) {
|
|
|
4771
4771
|
...emitter.generateClient(spec, ctx),
|
|
4772
4772
|
...emitter.generateErrors(ctx),
|
|
4773
4773
|
...emitter.generateTypeSignatures?.(reachableSpec, ctx) ?? [],
|
|
4774
|
-
...emitter.generateTests(reachableSpec, ctx)
|
|
4775
|
-
...emitter.generateManifest?.(spec, ctx) ?? []
|
|
4774
|
+
...emitter.generateTests(reachableSpec, ctx)
|
|
4776
4775
|
];
|
|
4777
4776
|
}
|
|
4778
4777
|
/** Apply file header to generated files, respecting headerPlacement and JSON files. */
|
|
@@ -4786,11 +4785,13 @@ function applyFileHeaders(files, header) {
|
|
|
4786
4785
|
function generateFiles(spec, emitter, options) {
|
|
4787
4786
|
const ctx = buildEmitterContext(spec, options);
|
|
4788
4787
|
const files = generateAllFiles(spec, emitter, ctx);
|
|
4788
|
+
const operations = emitter.buildOperationsMap?.(spec, ctx);
|
|
4789
4789
|
const header = emitter.fileHeader();
|
|
4790
4790
|
return {
|
|
4791
4791
|
files: applyFileHeaders(files, header),
|
|
4792
4792
|
ctx,
|
|
4793
|
-
header
|
|
4793
|
+
header,
|
|
4794
|
+
operations
|
|
4794
4795
|
};
|
|
4795
4796
|
}
|
|
4796
4797
|
//#endregion
|
|
@@ -5056,7 +5057,8 @@ async function writeManifest(dir, opts) {
|
|
|
5056
5057
|
...opts.emitterVersion !== void 0 ? { emitterVersion: opts.emitterVersion } : {},
|
|
5057
5058
|
...opts.configSha !== void 0 ? { configSha: opts.configSha } : {},
|
|
5058
5059
|
...opts.compatSchemaVersion !== void 0 ? { compatSchemaVersion: opts.compatSchemaVersion } : {},
|
|
5059
|
-
files: [...new Set(opts.files)].sort()
|
|
5060
|
+
files: [...new Set(opts.files)].sort(),
|
|
5061
|
+
...opts.operations !== void 0 ? { operations: opts.operations } : {}
|
|
5060
5062
|
};
|
|
5061
5063
|
const manifestPath = path$1.join(dir, MANIFEST_FILENAME);
|
|
5062
5064
|
await fs.mkdir(dir, { recursive: true });
|
|
@@ -5138,7 +5140,7 @@ async function removeEmptyParents(startDir, stopDir) {
|
|
|
5138
5140
|
async function generate(spec, emitter, options) {
|
|
5139
5141
|
const targetManifestForCtx = options.target && !options.noPrune ? await readManifest(options.target) : null;
|
|
5140
5142
|
const priorTargetManifestPaths = targetManifestForCtx ? new Set(targetManifestForCtx.files) : void 0;
|
|
5141
|
-
const { files: withHeaders, header } = generateFiles(spec, emitter, {
|
|
5143
|
+
const { files: withHeaders, header, operations } = generateFiles(spec, emitter, {
|
|
5142
5144
|
...options,
|
|
5143
5145
|
priorTargetManifestPaths
|
|
5144
5146
|
});
|
|
@@ -5164,7 +5166,8 @@ async function generate(spec, emitter, options) {
|
|
|
5164
5166
|
currentPaths: outputEmittedPaths,
|
|
5165
5167
|
language: emitter.language,
|
|
5166
5168
|
header,
|
|
5167
|
-
noPrune: options.noPrune
|
|
5169
|
+
noPrune: options.noPrune,
|
|
5170
|
+
operations
|
|
5168
5171
|
});
|
|
5169
5172
|
const allOutputFiles = [...writeResult.written, ...writeResult.merged];
|
|
5170
5173
|
if (allOutputFiles.length > 0) await formatTargetFiles(emitter, options.outputDir, allOutputFiles);
|
|
@@ -5186,7 +5189,8 @@ async function generate(spec, emitter, options) {
|
|
|
5186
5189
|
currentPaths: targetResult.emittedPaths,
|
|
5187
5190
|
language: emitter.language,
|
|
5188
5191
|
header,
|
|
5189
|
-
noPrune: options.noPrune
|
|
5192
|
+
noPrune: options.noPrune,
|
|
5193
|
+
operations
|
|
5190
5194
|
});
|
|
5191
5195
|
const allTargetFiles = [
|
|
5192
5196
|
...targetResult.written,
|
|
@@ -5202,19 +5206,18 @@ async function generate(spec, emitter, options) {
|
|
|
5202
5206
|
* then write the fresh manifest. Safe on first adoption (no previous manifest).
|
|
5203
5207
|
*/
|
|
5204
5208
|
async function applyManifestPrune(opts) {
|
|
5209
|
+
const manifestOpts = {
|
|
5210
|
+
language: opts.language,
|
|
5211
|
+
files: opts.currentPaths,
|
|
5212
|
+
operations: opts.operations
|
|
5213
|
+
};
|
|
5205
5214
|
if (opts.noPrune) {
|
|
5206
|
-
await writeManifest(opts.dir,
|
|
5207
|
-
language: opts.language,
|
|
5208
|
-
files: opts.currentPaths
|
|
5209
|
-
});
|
|
5215
|
+
await writeManifest(opts.dir, manifestOpts);
|
|
5210
5216
|
return;
|
|
5211
5217
|
}
|
|
5212
5218
|
if (!opts.prevManifest) {
|
|
5213
5219
|
console.log(`${opts.label}: no ${MANIFEST_FILENAME} found — skipping prune (this baseline manifest will be written now).`);
|
|
5214
|
-
await writeManifest(opts.dir,
|
|
5215
|
-
language: opts.language,
|
|
5216
|
-
files: opts.currentPaths
|
|
5217
|
-
});
|
|
5220
|
+
await writeManifest(opts.dir, manifestOpts);
|
|
5218
5221
|
return;
|
|
5219
5222
|
}
|
|
5220
5223
|
const stale = computeStalePaths(opts.prevManifest, opts.currentPaths);
|
|
@@ -5226,10 +5229,7 @@ async function applyManifestPrune(opts) {
|
|
|
5226
5229
|
for (const p of preserved) console.log(` ${p}`);
|
|
5227
5230
|
}
|
|
5228
5231
|
}
|
|
5229
|
-
await writeManifest(opts.dir,
|
|
5230
|
-
language: opts.language,
|
|
5231
|
-
files: opts.currentPaths
|
|
5232
|
-
});
|
|
5232
|
+
await writeManifest(opts.dir, manifestOpts);
|
|
5233
5233
|
}
|
|
5234
5234
|
//#endregion
|
|
5235
5235
|
//#region src/engine/registry.ts
|
|
@@ -5740,7 +5740,7 @@ function patchOverlay(overlay, changes, baseline) {
|
|
|
5740
5740
|
if (baseClass && baseClass.methods[methodName]?.length > 0) {
|
|
5741
5741
|
const httpKey = overlay.httpKeyByMethod.get(`${className}.${methodName}`);
|
|
5742
5742
|
if (!httpKey && overlay.httpKeyByMethod.size === 0 && !warnedManifest) {
|
|
5743
|
-
console.warn("Warning: No
|
|
5743
|
+
console.warn("Warning: No operations map in .oagen-manifest.json. Method-level violations cannot be auto-patched. Implement buildOperationsMap in your emitter for the self-correcting loop to resolve these.");
|
|
5744
5744
|
warnedManifest = true;
|
|
5745
5745
|
}
|
|
5746
5746
|
if (httpKey) {
|
|
@@ -5774,6 +5774,49 @@ function getExtractor(language) {
|
|
|
5774
5774
|
return extractor;
|
|
5775
5775
|
}
|
|
5776
5776
|
//#endregion
|
|
5777
|
+
//#region src/engine/manifest-reader.ts
|
|
5778
|
+
/**
|
|
5779
|
+
* Read the operations map from `.oagen-manifest.json` in the given directory
|
|
5780
|
+
* and convert it to `ManifestEntry[]` for the overlay builder.
|
|
5781
|
+
*
|
|
5782
|
+
* Returns undefined if the manifest is absent or has no operations field.
|
|
5783
|
+
*/
|
|
5784
|
+
function readManifestSync(dir) {
|
|
5785
|
+
const manifestPath = path$1.join(dir, MANIFEST_FILENAME);
|
|
5786
|
+
if (!existsSync(manifestPath)) return void 0;
|
|
5787
|
+
try {
|
|
5788
|
+
const operations = JSON.parse(readFileSync(manifestPath, "utf-8"))?.operations;
|
|
5789
|
+
if (!operations || typeof operations !== "object") return void 0;
|
|
5790
|
+
return convertOperationsToManifestEntries(operations);
|
|
5791
|
+
} catch {
|
|
5792
|
+
return;
|
|
5793
|
+
}
|
|
5794
|
+
}
|
|
5795
|
+
/** Convert the operations map from .oagen-manifest.json into ManifestEntry[]. */
|
|
5796
|
+
function convertOperationsToManifestEntries(operations) {
|
|
5797
|
+
const entries = [];
|
|
5798
|
+
for (const [httpKey, value] of Object.entries(operations)) {
|
|
5799
|
+
const spaceIdx = httpKey.indexOf(" ");
|
|
5800
|
+
const httpMethod = httpKey.slice(0, spaceIdx);
|
|
5801
|
+
const httpPath = httpKey.slice(spaceIdx + 1);
|
|
5802
|
+
const values = Array.isArray(value) ? value : [value];
|
|
5803
|
+
for (const v of values) {
|
|
5804
|
+
const entry = v;
|
|
5805
|
+
entries.push({
|
|
5806
|
+
operationId: "",
|
|
5807
|
+
sdkResourceProperty: entry.service ?? "",
|
|
5808
|
+
sdkMethodName: entry.sdkMethod ?? "",
|
|
5809
|
+
httpMethod,
|
|
5810
|
+
path: httpPath,
|
|
5811
|
+
pathParams: [],
|
|
5812
|
+
bodyFields: [],
|
|
5813
|
+
queryFields: []
|
|
5814
|
+
});
|
|
5815
|
+
}
|
|
5816
|
+
}
|
|
5817
|
+
return entries;
|
|
5818
|
+
}
|
|
5819
|
+
//#endregion
|
|
5777
5820
|
//#region src/cli/overlay-loader.ts
|
|
5778
5821
|
/**
|
|
5779
5822
|
* Load an API surface from disk, discover/load the manifest, resolve
|
|
@@ -5792,30 +5835,7 @@ function loadOverlayContext(opts) {
|
|
|
5792
5835
|
} catch (err) {
|
|
5793
5836
|
throw new ConfigError(`Failed to parse API surface JSON: ${err instanceof Error ? err.message : String(err)}`, `Ensure "${opts.apiSurfacePath}" contains valid JSON. Re-run \`oagen extract\` to regenerate it.`);
|
|
5794
5837
|
}
|
|
5795
|
-
|
|
5796
|
-
const resolvedManifestPath = opts.manifestPath ?? path$1.join(opts.outputDir, "smoke-manifest.json");
|
|
5797
|
-
if (opts.manifestPath || existsSync(resolvedManifestPath)) try {
|
|
5798
|
-
const parsed = JSON.parse(readFileSync(resolvedManifestPath, "utf-8"));
|
|
5799
|
-
if (Array.isArray(parsed)) manifest = parsed;
|
|
5800
|
-
else if (typeof parsed === "object" && parsed !== null) manifest = Object.entries(parsed).map(([httpKey, value]) => {
|
|
5801
|
-
const spaceIdx = httpKey.indexOf(" ");
|
|
5802
|
-
const httpMethod = httpKey.slice(0, spaceIdx);
|
|
5803
|
-
const httpPath = httpKey.slice(spaceIdx + 1);
|
|
5804
|
-
const v = value;
|
|
5805
|
-
return {
|
|
5806
|
-
operationId: "",
|
|
5807
|
-
sdkResourceProperty: v.service ?? "",
|
|
5808
|
-
sdkMethodName: v.sdkMethod ?? "",
|
|
5809
|
-
httpMethod,
|
|
5810
|
-
path: httpPath,
|
|
5811
|
-
pathParams: [],
|
|
5812
|
-
bodyFields: [],
|
|
5813
|
-
queryFields: []
|
|
5814
|
-
};
|
|
5815
|
-
});
|
|
5816
|
-
} catch {
|
|
5817
|
-
if (opts.manifestPath) throw new ConfigError(`Failed to read manifest: ${resolvedManifestPath}`, `Verify the manifest file exists and contains valid JSON. If using --manifest, check the path is correct.`);
|
|
5818
|
-
}
|
|
5838
|
+
const manifest = readManifestSync(opts.outputDir);
|
|
5819
5839
|
let hints = nodeHints;
|
|
5820
5840
|
try {
|
|
5821
5841
|
hints = getExtractor(opts.lang).hints;
|
|
@@ -5896,7 +5916,6 @@ async function generateCommand(opts) {
|
|
|
5896
5916
|
if (opts.apiSurface && opts.compatCheck !== false) {
|
|
5897
5917
|
const ctx = loadOverlayContext({
|
|
5898
5918
|
apiSurfacePath: opts.apiSurface,
|
|
5899
|
-
manifestPath: opts.manifest,
|
|
5900
5919
|
outputDir: opts.output,
|
|
5901
5920
|
lang: opts.lang,
|
|
5902
5921
|
spec: ir
|
|
@@ -7454,37 +7473,9 @@ function cleanGeneratedFiles(dir) {
|
|
|
7454
7473
|
} catch {}
|
|
7455
7474
|
}
|
|
7456
7475
|
}
|
|
7457
|
-
/**
|
|
7458
|
-
* Load a smoke-manifest.json from the generated SDK directory and convert
|
|
7459
|
-
* it to ManifestEntry[] for the overlay builder.
|
|
7460
|
-
*/
|
|
7461
|
-
function loadManifestFromDir(outputDir) {
|
|
7462
|
-
const manifestPath = path$1.join(outputDir, "smoke-manifest.json");
|
|
7463
|
-
if (!existsSync(manifestPath)) return void 0;
|
|
7464
|
-
try {
|
|
7465
|
-
const parsed = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
7466
|
-
if (Array.isArray(parsed)) return parsed;
|
|
7467
|
-
if (typeof parsed === "object" && parsed !== null) return Object.entries(parsed).map(([httpKey, value]) => {
|
|
7468
|
-
const spaceIdx = httpKey.indexOf(" ");
|
|
7469
|
-
const httpMethod = httpKey.slice(0, spaceIdx);
|
|
7470
|
-
const httpPath = httpKey.slice(spaceIdx + 1);
|
|
7471
|
-
const v = value;
|
|
7472
|
-
return {
|
|
7473
|
-
operationId: "",
|
|
7474
|
-
sdkResourceProperty: v.service ?? "",
|
|
7475
|
-
sdkMethodName: v.sdkMethod ?? "",
|
|
7476
|
-
httpMethod,
|
|
7477
|
-
path: httpPath,
|
|
7478
|
-
pathParams: [],
|
|
7479
|
-
bodyFields: [],
|
|
7480
|
-
queryFields: []
|
|
7481
|
-
};
|
|
7482
|
-
});
|
|
7483
|
-
} catch {}
|
|
7484
|
-
}
|
|
7485
7476
|
async function runOverlayRetryLoop(opts) {
|
|
7486
7477
|
const { baseline, parsedSpec, outputDir, lang, maxRetries, namespace, onRetry } = opts;
|
|
7487
|
-
let overlay = buildOverlayLookup(baseline,
|
|
7478
|
+
let overlay = buildOverlayLookup(baseline, readManifestSync(outputDir), parsedSpec, getExtractor(lang).hints);
|
|
7488
7479
|
let prevPreserved = -1;
|
|
7489
7480
|
const patchedPerIteration = [];
|
|
7490
7481
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
@@ -8039,8 +8030,8 @@ export const ${`${toCamelCase(lang)}Emitter`}: Emitter = {
|
|
|
8039
8030
|
return [];
|
|
8040
8031
|
},
|
|
8041
8032
|
|
|
8042
|
-
|
|
8043
|
-
return
|
|
8033
|
+
buildOperationsMap(_spec: ApiSpec, _ctx: EmitterContext) {
|
|
8034
|
+
return {};
|
|
8044
8035
|
},
|
|
8045
8036
|
|
|
8046
8037
|
fileHeader(): string {
|
|
@@ -8254,7 +8245,7 @@ program.command("parse").description("Parse an OpenAPI spec and output IR as JSO
|
|
|
8254
8245
|
}
|
|
8255
8246
|
return parseCommand(opts);
|
|
8256
8247
|
});
|
|
8257
|
-
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("--
|
|
8248
|
+
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) => {
|
|
8258
8249
|
opts.spec ??= process.env.OPENAPI_SPEC_PATH;
|
|
8259
8250
|
if (!opts.spec) {
|
|
8260
8251
|
console.error("error: --spec <path> or OPENAPI_SPEC_PATH env var is required");
|