@workos/oagen 0.22.6 → 0.22.7

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.
@@ -2694,6 +2694,7 @@ async function parseSpec(specPath, options) {
2694
2694
  const fieldInlineModels = extractInlineModelsFromSchemas(spec.components?.schemas);
2695
2695
  clearSchemaNameTransform();
2696
2696
  const finalModels = collapseJsonSuffixModels(mergeFieldInlineModels(responseNormalizedModels, fieldInlineModels), services);
2697
+ applyFieldHints(finalModels, options?.fieldHints);
2697
2698
  collectInlineEnumsFromModels(finalModels, enums);
2698
2699
  collectInlineEnumsFromOperations(services, enums);
2699
2700
  const auth = extractAuthSchemes(spec.components?.securitySchemes);
@@ -2716,6 +2717,22 @@ async function parseSpec(specPath, options) {
2716
2717
  validateModelRefs(result);
2717
2718
  return result;
2718
2719
  }
2720
+ /**
2721
+ * Apply `fieldHints` onto the built models, setting `Field.domainName` for each
2722
+ * matching (model name, wire field name) pair. Serialization still uses
2723
+ * `Field.name`; only the domain-facing identifier changes.
2724
+ */
2725
+ function applyFieldHints(models, fieldHints) {
2726
+ if (!fieldHints) return;
2727
+ for (const model of models) {
2728
+ const hints = fieldHints[model.name];
2729
+ if (!hints) continue;
2730
+ for (const field of model.fields) {
2731
+ const domainName = hints[field.name];
2732
+ if (domainName) field.domainName = domainName;
2733
+ }
2734
+ }
2735
+ }
2719
2736
  /** Extract authentication schemes from OpenAPI securitySchemes. */
2720
2737
  function extractAuthSchemes(securitySchemes) {
2721
2738
  if (!securitySchemes) return void 0;
@@ -5272,6 +5289,60 @@ function collectTsImports(lines) {
5272
5289
  return out;
5273
5290
  }
5274
5291
  /**
5292
+ * Remove the given symbols from generated `import type` bindings, in place.
5293
+ *
5294
+ * Called when an existing *value* import for the same symbol is being spliced
5295
+ * back into the file. A value import satisfies both runtime and type uses, so
5296
+ * leaving the generated `import type { X }` would re-declare `X` (TS2300
5297
+ * duplicate identifier). Callers guarantee every symbol here is absent from
5298
+ * generated *value* imports, so each occurrence is type-only and safe to drop.
5299
+ *
5300
+ * Handles whole-line `import type { … }` and inline `import { …, type X }`,
5301
+ * single- or multi-line. A statement whose bindings all get stripped is
5302
+ * removed entirely.
5303
+ */
5304
+ function dropGeneratedTypeOnlyBindings(resultLines, symbols) {
5305
+ if (symbols.size === 0) return;
5306
+ const out = [];
5307
+ for (let i = 0; i < resultLines.length; i++) {
5308
+ const line = resultLines[i];
5309
+ const trimmed = line.trim();
5310
+ if (!/^import\b/.test(trimmed) || !trimmed.includes("{")) {
5311
+ out.push(line);
5312
+ continue;
5313
+ }
5314
+ const span = [line];
5315
+ while (!span.join(" ").includes("}") && i + 1 < resultLines.length) {
5316
+ i++;
5317
+ span.push(resultLines[i]);
5318
+ }
5319
+ const m = span.join(" ").replace(/\s+/g, " ").trim().replace(/;\s*$/, "").match(/^import\s+(type\s+)?(?:(\w+)\s*,\s*)?\{\s*([^}]*)\s*\}\s+from\s+(['"][^'"]+['"])$/);
5320
+ if (!m) {
5321
+ for (const s of span) out.push(s);
5322
+ continue;
5323
+ }
5324
+ const isTypeOnly = !!m[1];
5325
+ const defaultName = m[2];
5326
+ const items = m[3].split(",").map((s) => s.trim()).filter(Boolean);
5327
+ const modQuoted = m[4];
5328
+ const kept = items.filter((raw) => {
5329
+ const isTypeBinding = isTypeOnly || raw.startsWith("type ");
5330
+ const bare = raw.replace(/^type\s+/, "");
5331
+ return !(isTypeBinding && symbols.has(bare));
5332
+ });
5333
+ if (kept.length === items.length) {
5334
+ for (const s of span) out.push(s);
5335
+ continue;
5336
+ }
5337
+ if (kept.length === 0 && !defaultName) continue;
5338
+ const lead = line.match(/^(\s*)/)?.[1] ?? "";
5339
+ const prefix = isTypeOnly ? "import type " : "import ";
5340
+ const defaultPart = defaultName ? `${defaultName}, ` : "";
5341
+ out.push(`${lead}${prefix}${defaultPart}{ ${kept.join(", ")} } from ${modQuoted};`);
5342
+ }
5343
+ resultLines.splice(0, resultLines.length, ...out);
5344
+ }
5345
+ /**
5275
5346
  * Add imports from the existing file that are absent from the generated
5276
5347
  * result. Handles:
5277
5348
  *
@@ -5393,28 +5464,49 @@ function spliceExtraImports(existingLines, resultLines) {
5393
5464
  const existingTs = collectTsImports(existingOutsideIgnore);
5394
5465
  const generatedTs = collectTsImports(resultLines);
5395
5466
  const extraTsLines = [];
5467
+ const allGeneratedTsIds = /* @__PURE__ */ new Set();
5468
+ const generatedValueIds = /* @__PURE__ */ new Set();
5469
+ for (const ids of generatedTs.named.values()) for (const id of ids) {
5470
+ allGeneratedTsIds.add(id);
5471
+ generatedValueIds.add(id);
5472
+ }
5473
+ for (const ids of generatedTs.typeOnly.values()) for (const id of ids) allGeneratedTsIds.add(id);
5474
+ for (const name of generatedTs.defaults.values()) {
5475
+ allGeneratedTsIds.add(name);
5476
+ generatedValueIds.add(name);
5477
+ }
5478
+ for (const name of generatedTs.namespaces.values()) {
5479
+ allGeneratedTsIds.add(name);
5480
+ generatedValueIds.add(name);
5481
+ }
5482
+ const reclaimedValueIds = /* @__PURE__ */ new Set();
5483
+ const generatedHasValue = (id) => generatedValueIds.has(id);
5484
+ const generatedHasTypeOnly = (id) => allGeneratedTsIds.has(id) && !generatedValueIds.has(id);
5396
5485
  for (const mod of existingTs.sideEffects) if (!generatedTs.sideEffects.has(mod)) extraTsLines.push(`import '${mod}';`);
5397
5486
  for (const [mod, name] of existingTs.defaults) {
5398
5487
  if (generatedTs.defaults.has(mod)) continue;
5399
5488
  if (!identifierUsed(ignoreRegionText, name)) continue;
5489
+ if (generatedHasValue(name)) continue;
5490
+ if (generatedHasTypeOnly(name)) reclaimedValueIds.add(name);
5400
5491
  extraTsLines.push(`import ${name} from '${mod}';`);
5401
5492
  }
5402
5493
  for (const [mod, name] of existingTs.namespaces) {
5403
5494
  if (!identifierUsed(ignoreRegionText, name)) continue;
5404
- if (!generatedTs.namespaces.has(mod)) extraTsLines.push(`import * as ${name} from '${mod}';`);
5495
+ if (generatedHasValue(name)) continue;
5496
+ if (generatedTs.namespaces.has(mod)) continue;
5497
+ if (generatedHasTypeOnly(name)) reclaimedValueIds.add(name);
5498
+ extraTsLines.push(`import * as ${name} from '${mod}';`);
5405
5499
  }
5406
5500
  for (const [mod, existIds] of existingTs.named) {
5407
- const genIds = generatedTs.named.get(mod) ?? /* @__PURE__ */ new Set();
5408
- const genTypeIds = generatedTs.typeOnly.get(mod) ?? /* @__PURE__ */ new Set();
5409
- const extra = [...existIds].filter((id) => !genIds.has(id) && !genTypeIds.has(id) && identifierUsed(ignoreRegionText, id));
5501
+ const extra = [...existIds].filter((id) => !generatedHasValue(id) && identifierUsed(ignoreRegionText, id));
5502
+ for (const id of extra) if (generatedHasTypeOnly(id)) reclaimedValueIds.add(id);
5410
5503
  if (extra.length > 0) extraTsLines.push(`import { ${extra.join(", ")} } from '${mod}';`);
5411
5504
  }
5412
5505
  for (const [mod, existIds] of existingTs.typeOnly) {
5413
- const genIds = generatedTs.typeOnly.get(mod) ?? /* @__PURE__ */ new Set();
5414
- const genNamedIds = generatedTs.named.get(mod) ?? /* @__PURE__ */ new Set();
5415
- const extra = [...existIds].filter((id) => !genIds.has(id) && !genNamedIds.has(id) && identifierUsed(ignoreRegionText, id));
5506
+ const extra = [...existIds].filter((id) => !allGeneratedTsIds.has(id) && identifierUsed(ignoreRegionText, id));
5416
5507
  if (extra.length > 0) extraTsLines.push(`import type { ${extra.join(", ")} } from '${mod}';`);
5417
5508
  }
5509
+ dropGeneratedTypeOnlyBindings(resultLines, reclaimedValueIds);
5418
5510
  const isPhpUseImport = (l) => /^use\s+[\w\\]+\\[\w\\]*(\s+as\s+\w+)?\s*;?$/.test(l);
5419
5511
  const existingPhpUse = new Set(existingOutsideIgnore.filter(isPhpUseImport).map((l) => l.trim()));
5420
5512
  const generatedPhpUse = new Set(resultLines.filter(isPhpUseImport).map((l) => l.trim()));
@@ -5458,7 +5550,31 @@ function spliceExtraImports(existingLines, resultLines) {
5458
5550
  if ((resultLines[i].match(/[)}]/g) ?? []).length > 0) break;
5459
5551
  }
5460
5552
  }
5461
- if (lastImportIdx >= 0) resultLines.splice(lastImportIdx + 1, 0, ...allExtra);
5553
+ if (lastImportIdx >= 0) {
5554
+ resultLines.splice(lastImportIdx + 1, 0, ...allExtra);
5555
+ return;
5556
+ }
5557
+ let insertAt = 0;
5558
+ let inBlockComment = false;
5559
+ for (let i = 0; i < resultLines.length; i++) {
5560
+ const t = resultLines[i].trim();
5561
+ if (inBlockComment) {
5562
+ insertAt = i + 1;
5563
+ if (t.includes("*/")) inBlockComment = false;
5564
+ continue;
5565
+ }
5566
+ if (t.startsWith("//")) {
5567
+ insertAt = i + 1;
5568
+ continue;
5569
+ }
5570
+ if (t.startsWith("/*")) {
5571
+ insertAt = i + 1;
5572
+ inBlockComment = !t.includes("*/");
5573
+ continue;
5574
+ }
5575
+ break;
5576
+ }
5577
+ resultLines.splice(insertAt, 0, ...allExtra);
5462
5578
  }
5463
5579
  //#endregion
5464
5580
  //#region src/ir/operation-hints.ts
@@ -6832,7 +6948,8 @@ async function generateCommand(opts) {
6832
6948
  let ir = await parseSpec(opts.spec, {
6833
6949
  operationIdTransform: opts.operationIdTransform,
6834
6950
  schemaNameTransform: opts.schemaNameTransform,
6835
- transformSpec: opts.transformSpec
6951
+ transformSpec: opts.transformSpec,
6952
+ fieldHints: opts.fieldHints
6836
6953
  });
6837
6954
  if (opts.docUrl) ir = expandDocUrls(ir, opts.docUrl);
6838
6955
  const emitter = getEmitter(opts.lang);
@@ -9802,6 +9919,7 @@ let configDocUrl;
9802
9919
  let configOperationHints;
9803
9920
  let configMountRules;
9804
9921
  let configModelHints;
9922
+ let configFieldHints;
9805
9923
  let configEmitterOptions;
9806
9924
  let configCompat;
9807
9925
  try {
@@ -9816,6 +9934,7 @@ try {
9816
9934
  configOperationHints = config.operationHints;
9817
9935
  configMountRules = config.mountRules;
9818
9936
  configModelHints = config.modelHints;
9937
+ configFieldHints = config.fieldHints;
9819
9938
  configEmitterOptions = config.emitterOptions;
9820
9939
  configCompat = config.compat;
9821
9940
  }
@@ -9851,6 +9970,7 @@ program.command("generate").description("Run a registered emitter against an Ope
9851
9970
  operationHints: configOperationHints,
9852
9971
  mountRules: configMountRules,
9853
9972
  modelHints: configModelHints,
9973
+ fieldHints: configFieldHints,
9854
9974
  emitterOptions: configEmitterOptions?.[opts.lang]
9855
9975
  }).catch(handleError);
9856
9976
  });