@workos/oagen-emitters 0.13.0 → 0.14.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/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +7 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{plugin-B9F2jmwy.mjs → plugin-BxVeu2v9.mjs} +610 -22
- package/dist/plugin-BxVeu2v9.mjs.map +1 -0
- package/dist/plugin.mjs +1 -1
- package/package.json +2 -2
- package/src/node/discriminated-models.ts +735 -0
- package/src/node/index.ts +56 -5
- package/src/node/models.ts +15 -1
- package/src/node/node-overrides.ts +49 -6
- package/src/php/index.ts +25 -2
- package/src/ruby/index.ts +27 -2
- package/src/rust/index.ts +26 -2
- package/src/shared/model-utils.ts +15 -5
- package/dist/plugin-B9F2jmwy.mjs.map +0 -1
|
@@ -2692,6 +2692,7 @@ function enrichModelsFromSpec(models) {
|
|
|
2692
2692
|
_lastSyntheticEnums = collector.enums.map((e) => ({
|
|
2693
2693
|
name: e.name,
|
|
2694
2694
|
values: e.values.map((v) => ({
|
|
2695
|
+
name: toUpperSnakeCase(String(v.value)),
|
|
2695
2696
|
value: v.value,
|
|
2696
2697
|
description: v.description
|
|
2697
2698
|
}))
|
|
@@ -2985,7 +2986,7 @@ function mapTypeRef$7(ref, opts) {
|
|
|
2985
2986
|
const genericDefaults = opts?.genericDefaults;
|
|
2986
2987
|
return mapTypeRef(ref, {
|
|
2987
2988
|
primitive: mapPrimitive$6,
|
|
2988
|
-
array: (_r, items) => `${parenthesizeUnion(items)}[]`,
|
|
2989
|
+
array: (_r, items) => `${parenthesizeUnion$1(items)}[]`,
|
|
2989
2990
|
model: (r) => resolveDomainName(r.name) + (genericDefaults?.get(r.name) ?? ""),
|
|
2990
2991
|
enum: (r) => inlineEnumUnions.get(r.name) ?? r.name,
|
|
2991
2992
|
union: (r, variants) => joinUnionVariants$5(r, variants),
|
|
@@ -3002,7 +3003,7 @@ function mapWireTypeRef(ref, opts) {
|
|
|
3002
3003
|
const genericDefaults = opts?.genericDefaults;
|
|
3003
3004
|
return mapTypeRef(ref, {
|
|
3004
3005
|
primitive: mapWirePrimitive,
|
|
3005
|
-
array: (_r, items) => `${parenthesizeUnion(items)}[]`,
|
|
3006
|
+
array: (_r, items) => `${parenthesizeUnion$1(items)}[]`,
|
|
3006
3007
|
model: (r) => wireInterfaceName(resolveDomainName(r.name)) + (genericDefaults?.get(r.name) ?? ""),
|
|
3007
3008
|
enum: (r) => inlineEnumUnions.get(r.name) ?? r.name,
|
|
3008
3009
|
union: (r, variants) => joinUnionVariants$5(r, variants),
|
|
@@ -3039,7 +3040,7 @@ function joinUnionVariants$5(ref, variants) {
|
|
|
3039
3040
|
if (unique.length === 1) return unique[0];
|
|
3040
3041
|
return unique.join(" | ");
|
|
3041
3042
|
}
|
|
3042
|
-
function parenthesizeUnion(type) {
|
|
3043
|
+
function parenthesizeUnion$1(type) {
|
|
3043
3044
|
return type.includes(" | ") || type.includes(" & ") ? `(${type})` : type;
|
|
3044
3045
|
}
|
|
3045
3046
|
//#endregion
|
|
@@ -4627,7 +4628,7 @@ function splitCamelWords(name) {
|
|
|
4627
4628
|
return parts;
|
|
4628
4629
|
}
|
|
4629
4630
|
/** Naive singularize: strip trailing 's' unless it ends in 'ss'. */
|
|
4630
|
-
function singularize$
|
|
4631
|
+
function singularize$4(word) {
|
|
4631
4632
|
return word.endsWith("s") && !word.endsWith("ss") ? word.slice(0, -1) : word;
|
|
4632
4633
|
}
|
|
4633
4634
|
/**
|
|
@@ -4644,11 +4645,11 @@ function deduplicateMethodNames(plans, _ctx) {
|
|
|
4644
4645
|
if (count <= 1) continue;
|
|
4645
4646
|
const dupes = plans.filter((p) => p.method === name);
|
|
4646
4647
|
if (new Set(dupes.map((d) => d.op.path.replace(/\/\{[^}]+\}$/, ""))).size <= 1) continue;
|
|
4647
|
-
const nameWords = new Set(splitCamelWords(name).map(singularize$
|
|
4648
|
+
const nameWords = new Set(splitCamelWords(name).map(singularize$4));
|
|
4648
4649
|
const scored = dupes.map((d) => {
|
|
4649
4650
|
return {
|
|
4650
4651
|
plan: d,
|
|
4651
|
-
score: d.op.path.split("/").filter((s) => s && !s.startsWith("{")).flatMap((s) => s.split("_")).map(singularize$
|
|
4652
|
+
score: d.op.path.split("/").filter((s) => s && !s.startsWith("{")).flatMap((s) => s.split("_")).map(singularize$4).filter((w) => nameWords.has(w)).length
|
|
4652
4653
|
};
|
|
4653
4654
|
});
|
|
4654
4655
|
scored.sort((a, b) => b.score - a.score);
|
|
@@ -5942,6 +5943,7 @@ function isSupportedFieldType(ref, ownerModelName, shared, ctx) {
|
|
|
5942
5943
|
const resolvedName = resolveInterfaceName(ref.name, ctx);
|
|
5943
5944
|
if (ctx.apiSurface?.interfaces?.[resolvedName] || ctx.apiSurface?.typeAliases?.[resolvedName]) return true;
|
|
5944
5945
|
if (isAdoptedModelName(ref.name)) return true;
|
|
5946
|
+
if (shared.modelToService.has(ref.name)) return true;
|
|
5945
5947
|
return liveSurfaceHasManagedFile(`src/${shared.resolveDir(shared.modelToService.get(ref.name))}/interfaces/${fileName$3(ref.name)}.interface.ts`);
|
|
5946
5948
|
}
|
|
5947
5949
|
case "enum": {
|
|
@@ -5988,12 +5990,14 @@ function generateModels$7(models, ctx, shared) {
|
|
|
5988
5990
|
if ((ctx.apiSurface?.interfaces?.[depName])?.sourceFile === parentPath) forceGenerate.add(dep);
|
|
5989
5991
|
}
|
|
5990
5992
|
}
|
|
5993
|
+
const discriminatedSkip = ctx._discriminatedModelNames;
|
|
5991
5994
|
for (const originalModel of models) {
|
|
5992
5995
|
const model = projectedByName.get(originalModel.name) ?? originalModel;
|
|
5993
5996
|
if (!reachableModels.has(model.name)) continue;
|
|
5994
5997
|
if (interfaceEligibleModels && !interfaceEligibleModels.has(model.name)) continue;
|
|
5995
5998
|
if (isListMetadataModel(model)) continue;
|
|
5996
5999
|
if (isListWrapperModel(model)) continue;
|
|
6000
|
+
if (discriminatedSkip?.has(model.name)) continue;
|
|
5997
6001
|
const service = modelToService.get(model.name);
|
|
5998
6002
|
const isOwnedModel = isNodeOwnedService(ctx, service);
|
|
5999
6003
|
if (!isOwnedModel && !modelHasNewFields(model, ctx) && !forceGenerate.has(model.name)) continue;
|
|
@@ -6325,6 +6329,7 @@ function generateSerializers(models, ctx, shared) {
|
|
|
6325
6329
|
if ((ctx.apiSurface?.interfaces?.[depName])?.sourceFile === parentPath) forceGenerateSerializer.add(dep);
|
|
6326
6330
|
}
|
|
6327
6331
|
}
|
|
6332
|
+
const discriminatedSerializerSkip = ctx._discriminatedModelNames;
|
|
6328
6333
|
const eligibleModels = [];
|
|
6329
6334
|
for (const originalModel of models) {
|
|
6330
6335
|
const model = projectedByName.get(originalModel.name) ?? originalModel;
|
|
@@ -6332,6 +6337,7 @@ function generateSerializers(models, ctx, shared) {
|
|
|
6332
6337
|
if (serializerEligibleModels && !serializerEligibleModels.has(model.name)) continue;
|
|
6333
6338
|
if (isListMetadataModel(model)) continue;
|
|
6334
6339
|
if (isListWrapperModel(model)) continue;
|
|
6340
|
+
if (discriminatedSerializerSkip?.has(model.name)) continue;
|
|
6335
6341
|
if (!isNodeOwnedService(ctx, modelToService.get(model.name)) && !modelHasNewFields(model, ctx) && !forceGenerateSerializer.has(model.name)) continue;
|
|
6336
6342
|
eligibleModels.push(model);
|
|
6337
6343
|
}
|
|
@@ -7643,6 +7649,445 @@ function generateSerializerTests(spec, ctx) {
|
|
|
7643
7649
|
return files;
|
|
7644
7650
|
}
|
|
7645
7651
|
//#endregion
|
|
7652
|
+
//#region src/node/discriminated-models.ts
|
|
7653
|
+
function detectDiscriminatedShape(modelName, rawSchemas) {
|
|
7654
|
+
const schema = rawSchemas[modelName];
|
|
7655
|
+
if (!schema?.allOf) return null;
|
|
7656
|
+
let baseObject = null;
|
|
7657
|
+
let oneOfVariants = null;
|
|
7658
|
+
for (const member of schema.allOf) {
|
|
7659
|
+
const resolved = resolveRef(member, rawSchemas);
|
|
7660
|
+
if (resolved.oneOf) {
|
|
7661
|
+
if (oneOfVariants) return null;
|
|
7662
|
+
oneOfVariants = resolved.oneOf;
|
|
7663
|
+
} else if (resolved.properties) baseObject = mergeBase(baseObject, resolved);
|
|
7664
|
+
else if (resolved.allOf) {
|
|
7665
|
+
const nestedBase = flattenObjectAllOf(resolved, rawSchemas);
|
|
7666
|
+
baseObject = mergeBase(baseObject, nestedBase);
|
|
7667
|
+
}
|
|
7668
|
+
}
|
|
7669
|
+
if (!oneOfVariants || oneOfVariants.length < 2) return null;
|
|
7670
|
+
const flattenedVariants = oneOfVariants.map((v) => flattenVariant(v, rawSchemas));
|
|
7671
|
+
const discProp = findSharedDiscriminator(flattenedVariants);
|
|
7672
|
+
if (!discProp) return null;
|
|
7673
|
+
const variants = flattenedVariants.map((fv) => {
|
|
7674
|
+
const discValue = readConstString(fv.alwaysProperties.get(discProp));
|
|
7675
|
+
if (!discValue) return null;
|
|
7676
|
+
return {
|
|
7677
|
+
nameSuffix: variantNameSuffix(discValue),
|
|
7678
|
+
discriminatorValue: discValue,
|
|
7679
|
+
fields: variantFields(fv, discProp, modelName, rawSchemas)
|
|
7680
|
+
};
|
|
7681
|
+
}).filter((v) => v !== null);
|
|
7682
|
+
if (variants.length !== flattenedVariants.length) return null;
|
|
7683
|
+
return {
|
|
7684
|
+
modelName,
|
|
7685
|
+
baseFields: baseObject ? collectObjectFields(baseObject, modelName, rawSchemas) : [],
|
|
7686
|
+
discriminatorProperty: discProp,
|
|
7687
|
+
discriminatorPropertyDomain: toCamelCase(discProp),
|
|
7688
|
+
variants
|
|
7689
|
+
};
|
|
7690
|
+
}
|
|
7691
|
+
function mergeBase(prev, next) {
|
|
7692
|
+
if (!prev) return next;
|
|
7693
|
+
return {
|
|
7694
|
+
type: "object",
|
|
7695
|
+
properties: {
|
|
7696
|
+
...prev.properties ?? {},
|
|
7697
|
+
...next.properties ?? {}
|
|
7698
|
+
},
|
|
7699
|
+
required: [...new Set([...prev.required ?? [], ...next.required ?? []])]
|
|
7700
|
+
};
|
|
7701
|
+
}
|
|
7702
|
+
function flattenObjectAllOf(schema, rawSchemas) {
|
|
7703
|
+
let merged = {
|
|
7704
|
+
type: "object",
|
|
7705
|
+
properties: {},
|
|
7706
|
+
required: []
|
|
7707
|
+
};
|
|
7708
|
+
for (const sub of schema.allOf ?? []) {
|
|
7709
|
+
const resolved = resolveRef(sub, rawSchemas);
|
|
7710
|
+
if (resolved.properties) merged = mergeBase(merged, resolved);
|
|
7711
|
+
else if (resolved.allOf) merged = mergeBase(merged, flattenObjectAllOf(resolved, rawSchemas));
|
|
7712
|
+
}
|
|
7713
|
+
return merged;
|
|
7714
|
+
}
|
|
7715
|
+
function flattenVariant(variant, rawSchemas) {
|
|
7716
|
+
const resolved = resolveRef(variant, rawSchemas);
|
|
7717
|
+
if (resolved.properties && !resolved.allOf && !resolved.oneOf) {
|
|
7718
|
+
const props = /* @__PURE__ */ new Map();
|
|
7719
|
+
for (const [k, v] of Object.entries(resolved.properties)) props.set(k, v);
|
|
7720
|
+
return {
|
|
7721
|
+
alwaysProperties: props,
|
|
7722
|
+
optionalProperties: /* @__PURE__ */ new Map(),
|
|
7723
|
+
required: new Set(resolved.required ?? [])
|
|
7724
|
+
};
|
|
7725
|
+
}
|
|
7726
|
+
if (resolved.allOf) {
|
|
7727
|
+
let agg = {
|
|
7728
|
+
alwaysProperties: /* @__PURE__ */ new Map(),
|
|
7729
|
+
optionalProperties: /* @__PURE__ */ new Map(),
|
|
7730
|
+
required: /* @__PURE__ */ new Set()
|
|
7731
|
+
};
|
|
7732
|
+
let initialized = false;
|
|
7733
|
+
for (const member of resolved.allOf) {
|
|
7734
|
+
const memberView = flattenVariant(member, rawSchemas);
|
|
7735
|
+
if (!initialized) {
|
|
7736
|
+
agg = {
|
|
7737
|
+
alwaysProperties: new Map(memberView.alwaysProperties),
|
|
7738
|
+
optionalProperties: new Map(memberView.optionalProperties),
|
|
7739
|
+
required: new Set(memberView.required)
|
|
7740
|
+
};
|
|
7741
|
+
initialized = true;
|
|
7742
|
+
continue;
|
|
7743
|
+
}
|
|
7744
|
+
for (const [k, v] of memberView.alwaysProperties) if (!agg.alwaysProperties.has(k) && !agg.optionalProperties.has(k)) agg.alwaysProperties.set(k, v);
|
|
7745
|
+
for (const [k, v] of memberView.optionalProperties) if (!agg.alwaysProperties.has(k) && !agg.optionalProperties.has(k)) agg.optionalProperties.set(k, v);
|
|
7746
|
+
for (const r of memberView.required) agg.required.add(r);
|
|
7747
|
+
}
|
|
7748
|
+
return agg;
|
|
7749
|
+
}
|
|
7750
|
+
if (resolved.oneOf) {
|
|
7751
|
+
const memberViews = resolved.oneOf.map((m) => flattenVariant(m, rawSchemas));
|
|
7752
|
+
const allKeys = /* @__PURE__ */ new Set();
|
|
7753
|
+
for (const view of memberViews) {
|
|
7754
|
+
for (const k of view.alwaysProperties.keys()) allKeys.add(k);
|
|
7755
|
+
for (const k of view.optionalProperties.keys()) allKeys.add(k);
|
|
7756
|
+
}
|
|
7757
|
+
const always = /* @__PURE__ */ new Map();
|
|
7758
|
+
const optional = /* @__PURE__ */ new Map();
|
|
7759
|
+
const requiredEverywhere = /* @__PURE__ */ new Set();
|
|
7760
|
+
for (const key of allKeys) {
|
|
7761
|
+
const inAll = memberViews.every((v) => v.alwaysProperties.has(key) || v.optionalProperties.has(key));
|
|
7762
|
+
const merged = mergeFieldSchemas(memberViews.map((v) => v.alwaysProperties.get(key) ?? v.optionalProperties.get(key)).filter((s) => Boolean(s)));
|
|
7763
|
+
if (inAll) always.set(key, merged);
|
|
7764
|
+
else optional.set(key, merged);
|
|
7765
|
+
if (inAll && memberViews.every((v) => v.required.has(key))) requiredEverywhere.add(key);
|
|
7766
|
+
}
|
|
7767
|
+
return {
|
|
7768
|
+
alwaysProperties: always,
|
|
7769
|
+
optionalProperties: optional,
|
|
7770
|
+
required: requiredEverywhere
|
|
7771
|
+
};
|
|
7772
|
+
}
|
|
7773
|
+
return {
|
|
7774
|
+
alwaysProperties: /* @__PURE__ */ new Map(),
|
|
7775
|
+
optionalProperties: /* @__PURE__ */ new Map(),
|
|
7776
|
+
required: /* @__PURE__ */ new Set()
|
|
7777
|
+
};
|
|
7778
|
+
}
|
|
7779
|
+
function mergeFieldSchemas(schemas) {
|
|
7780
|
+
if (schemas.length === 0) return {};
|
|
7781
|
+
if (schemas.length === 1) return schemas[0];
|
|
7782
|
+
if (schemas.every((s) => s.type === "boolean" && typeof s.const === "boolean")) return {
|
|
7783
|
+
type: "boolean",
|
|
7784
|
+
description: schemas[0].description
|
|
7785
|
+
};
|
|
7786
|
+
if (schemas.every((s) => s.type === "string" && typeof s.const === "string")) {
|
|
7787
|
+
const values = schemas.map((s) => s.const);
|
|
7788
|
+
if (new Set(values).size === 1) return schemas[0];
|
|
7789
|
+
return {
|
|
7790
|
+
type: "string",
|
|
7791
|
+
description: schemas[0].description
|
|
7792
|
+
};
|
|
7793
|
+
}
|
|
7794
|
+
return schemas[0];
|
|
7795
|
+
}
|
|
7796
|
+
function findSharedDiscriminator(variants) {
|
|
7797
|
+
if (variants.length < 2) return null;
|
|
7798
|
+
const firstAlways = variants[0].alwaysProperties;
|
|
7799
|
+
for (const propName of firstAlways.keys()) {
|
|
7800
|
+
let allConst = true;
|
|
7801
|
+
const values = [];
|
|
7802
|
+
for (const v of variants) {
|
|
7803
|
+
const val = readConstString(v.alwaysProperties.get(propName));
|
|
7804
|
+
if (val === null) {
|
|
7805
|
+
allConst = false;
|
|
7806
|
+
break;
|
|
7807
|
+
}
|
|
7808
|
+
values.push(val);
|
|
7809
|
+
}
|
|
7810
|
+
if (allConst && new Set(values).size === values.length) return propName;
|
|
7811
|
+
}
|
|
7812
|
+
return null;
|
|
7813
|
+
}
|
|
7814
|
+
function readConstString(schema) {
|
|
7815
|
+
if (!schema) return null;
|
|
7816
|
+
if (typeof schema.const === "string") return schema.const;
|
|
7817
|
+
if (Array.isArray(schema.enum) && schema.enum.length === 1 && typeof schema.enum[0] === "string") return schema.enum[0];
|
|
7818
|
+
return null;
|
|
7819
|
+
}
|
|
7820
|
+
function variantNameSuffix(constValue) {
|
|
7821
|
+
return toPascalCase(constValue);
|
|
7822
|
+
}
|
|
7823
|
+
function collectObjectFields(schema, parentName, rawSchemas) {
|
|
7824
|
+
const props = schema.properties ?? {};
|
|
7825
|
+
const required = new Set(schema.required ?? []);
|
|
7826
|
+
const fields = [];
|
|
7827
|
+
for (const [name, propSchema] of Object.entries(props)) fields.push(buildField(name, propSchema, required.has(name), parentName, rawSchemas));
|
|
7828
|
+
return fields;
|
|
7829
|
+
}
|
|
7830
|
+
function variantFields(fv, discriminatorProperty, parentName, rawSchemas) {
|
|
7831
|
+
const fields = [];
|
|
7832
|
+
for (const [name, propSchema] of fv.alwaysProperties) {
|
|
7833
|
+
if (name === discriminatorProperty) continue;
|
|
7834
|
+
fields.push(buildField(name, propSchema, fv.required.has(name), parentName, rawSchemas));
|
|
7835
|
+
}
|
|
7836
|
+
for (const [name, propSchema] of fv.optionalProperties) {
|
|
7837
|
+
if (name === discriminatorProperty) continue;
|
|
7838
|
+
fields.push(buildField(name, propSchema, false, parentName, rawSchemas));
|
|
7839
|
+
}
|
|
7840
|
+
return fields;
|
|
7841
|
+
}
|
|
7842
|
+
function buildField(rawName, schema, required, parentName, rawSchemas) {
|
|
7843
|
+
const modelDeps = /* @__PURE__ */ new Set();
|
|
7844
|
+
const domainType = rawSchemaToTS(schema, parentName, rawName, false, modelDeps, rawSchemas);
|
|
7845
|
+
const wireType = rawSchemaToTS(schema, parentName, rawName, true, modelDeps, rawSchemas);
|
|
7846
|
+
return {
|
|
7847
|
+
name: rawName,
|
|
7848
|
+
description: schema.description,
|
|
7849
|
+
required,
|
|
7850
|
+
domainType,
|
|
7851
|
+
wireType,
|
|
7852
|
+
modelDeps,
|
|
7853
|
+
hasDateTime: schemaHasDateTime(schema)
|
|
7854
|
+
};
|
|
7855
|
+
}
|
|
7856
|
+
function schemaHasDateTime(schema) {
|
|
7857
|
+
if (schema.format === "date-time" && typeOf(schema) === "string") return true;
|
|
7858
|
+
if (schema.items && schemaHasDateTime(schema.items)) return true;
|
|
7859
|
+
return false;
|
|
7860
|
+
}
|
|
7861
|
+
function typeOf(schema) {
|
|
7862
|
+
if (Array.isArray(schema.type)) return schema.type.find((t) => t !== "null");
|
|
7863
|
+
return schema.type;
|
|
7864
|
+
}
|
|
7865
|
+
function isNullable(schema) {
|
|
7866
|
+
return Array.isArray(schema.type) && schema.type.includes("null");
|
|
7867
|
+
}
|
|
7868
|
+
function rawSchemaToTS(schema, parentName, fieldName, isWire, modelDeps, rawSchemas) {
|
|
7869
|
+
if (schema.$ref) {
|
|
7870
|
+
const refName = schema.$ref.split("/").pop();
|
|
7871
|
+
modelDeps.add(refName);
|
|
7872
|
+
const domain = toPascalCase(refName);
|
|
7873
|
+
return isWire ? wireInterfaceName(domain) : domain;
|
|
7874
|
+
}
|
|
7875
|
+
if (typeof schema.const === "string") return `'${schema.const}'`;
|
|
7876
|
+
if (typeof schema.const === "boolean") return String(schema.const);
|
|
7877
|
+
const baseType = typeOf(schema);
|
|
7878
|
+
const nullable = isNullable(schema);
|
|
7879
|
+
let core;
|
|
7880
|
+
if (baseType === "string") core = !isWire && schema.format === "date-time" ? "Date" : "string";
|
|
7881
|
+
else if (baseType === "integer" || baseType === "number") core = "number";
|
|
7882
|
+
else if (baseType === "boolean") core = "boolean";
|
|
7883
|
+
else if (baseType === "array" && schema.items) core = `${parenthesizeUnion(rawSchemaToTS(schema.items, parentName, singularize$3(fieldName), isWire, modelDeps, rawSchemas))}[]`;
|
|
7884
|
+
else if (baseType === "object" && schema.properties) {
|
|
7885
|
+
const synthName = `${parentName}_${singularize$3(fieldName)}`;
|
|
7886
|
+
modelDeps.add(synthName);
|
|
7887
|
+
const domain = toPascalCase(synthName);
|
|
7888
|
+
return isWire ? wireInterfaceName(domain) : domain;
|
|
7889
|
+
} else core = "unknown";
|
|
7890
|
+
return nullable ? `${core} | null` : core;
|
|
7891
|
+
}
|
|
7892
|
+
function parenthesizeUnion(t) {
|
|
7893
|
+
return /\s\|\s/.test(t) ? `(${t})` : t;
|
|
7894
|
+
}
|
|
7895
|
+
function singularize$3(name) {
|
|
7896
|
+
if (name.endsWith("ies") && name.length > 3) return `${name.slice(0, -3)}y`;
|
|
7897
|
+
if (name.endsWith("s") && !name.endsWith("ss")) return name.slice(0, -1);
|
|
7898
|
+
return name;
|
|
7899
|
+
}
|
|
7900
|
+
function resolveRef(schema, rawSchemas) {
|
|
7901
|
+
if (!schema.$ref) return schema;
|
|
7902
|
+
const segments = schema.$ref.split("/");
|
|
7903
|
+
return rawSchemas[segments[segments.length - 1]] ?? schema;
|
|
7904
|
+
}
|
|
7905
|
+
function planDiscriminatedModels(models, ctx) {
|
|
7906
|
+
const plans = /* @__PURE__ */ new Map();
|
|
7907
|
+
const spec = loadRawSpec();
|
|
7908
|
+
if (!spec?.components?.schemas) return plans;
|
|
7909
|
+
const rawSchemas = spec.components.schemas;
|
|
7910
|
+
const { modelToService, resolveDir } = createServiceDirResolver(models, ctx.spec.services, ctx);
|
|
7911
|
+
for (const model of models) {
|
|
7912
|
+
const shape = detectDiscriminatedShape(model.name, rawSchemas);
|
|
7913
|
+
if (!shape) continue;
|
|
7914
|
+
const modelDir = resolveDir(modelToService.get(model.name));
|
|
7915
|
+
plans.set(model.name, {
|
|
7916
|
+
shape,
|
|
7917
|
+
modelDir
|
|
7918
|
+
});
|
|
7919
|
+
}
|
|
7920
|
+
return plans;
|
|
7921
|
+
}
|
|
7922
|
+
function generateDiscriminatedFiles(plans, ctx) {
|
|
7923
|
+
const files = [];
|
|
7924
|
+
for (const plan of plans.values()) {
|
|
7925
|
+
files.push(buildInterfaceFile(plan, ctx));
|
|
7926
|
+
files.push(buildSerializerFile(plan, ctx));
|
|
7927
|
+
}
|
|
7928
|
+
return files;
|
|
7929
|
+
}
|
|
7930
|
+
function buildInterfaceFile(plan, _ctx) {
|
|
7931
|
+
const { shape, modelDir } = plan;
|
|
7932
|
+
const domain = toPascalCase(shape.modelName);
|
|
7933
|
+
const wire = wireInterfaceName(domain);
|
|
7934
|
+
const lines = [];
|
|
7935
|
+
const imports = collectImports$2(plan);
|
|
7936
|
+
if (imports.length > 0) {
|
|
7937
|
+
for (const imp of imports) lines.push(`import type { ${imp.symbols.join(", ")} } from '${imp.path}';`);
|
|
7938
|
+
lines.push("");
|
|
7939
|
+
}
|
|
7940
|
+
for (const variant of shape.variants) {
|
|
7941
|
+
const variantDomain = `${domain}${variant.nameSuffix}`;
|
|
7942
|
+
const variantWire = `${variantDomain}Response`;
|
|
7943
|
+
lines.push(...buildInterfaceBody(variantDomain, shape, variant, false));
|
|
7944
|
+
lines.push("");
|
|
7945
|
+
lines.push(...buildInterfaceBody(variantWire, shape, variant, true));
|
|
7946
|
+
lines.push("");
|
|
7947
|
+
}
|
|
7948
|
+
const variantNames = shape.variants.map((v) => `${domain}${v.nameSuffix}`);
|
|
7949
|
+
lines.push(`export type ${domain} = ${variantNames.join(" | ")};`);
|
|
7950
|
+
lines.push("");
|
|
7951
|
+
const wireVariantNames = shape.variants.map((v) => `${domain}${v.nameSuffix}Response`);
|
|
7952
|
+
lines.push(`export type ${wire} = ${wireVariantNames.join(" | ")};`);
|
|
7953
|
+
return {
|
|
7954
|
+
path: `src/${modelDir}/interfaces/${fileName$3(shape.modelName)}.interface.ts`,
|
|
7955
|
+
content: lines.join("\n") + "\n",
|
|
7956
|
+
overwriteExisting: true
|
|
7957
|
+
};
|
|
7958
|
+
}
|
|
7959
|
+
function buildInterfaceBody(name, shape, variant, isWire) {
|
|
7960
|
+
const lines = [];
|
|
7961
|
+
lines.push(`export interface ${name} {`);
|
|
7962
|
+
for (const field of shape.baseFields) pushFieldLine(lines, field, isWire);
|
|
7963
|
+
const discKey = isWire ? shape.discriminatorProperty : shape.discriminatorPropertyDomain;
|
|
7964
|
+
lines.push(` ${discKey}: '${variant.discriminatorValue}';`);
|
|
7965
|
+
for (const field of variant.fields) pushFieldLine(lines, field, isWire);
|
|
7966
|
+
lines.push("}");
|
|
7967
|
+
return lines;
|
|
7968
|
+
}
|
|
7969
|
+
function pushFieldLine(lines, field, isWire) {
|
|
7970
|
+
const key = isWire ? field.name : toCamelCase(field.name);
|
|
7971
|
+
const opt = field.required ? "" : "?";
|
|
7972
|
+
const type = isWire ? field.wireType : field.domainType;
|
|
7973
|
+
if (field.description) lines.push(` /** ${field.description} */`);
|
|
7974
|
+
lines.push(` ${key}${opt}: ${type};`);
|
|
7975
|
+
}
|
|
7976
|
+
function collectImports$2(plan) {
|
|
7977
|
+
const deps = /* @__PURE__ */ new Set();
|
|
7978
|
+
for (const field of plan.shape.baseFields) for (const d of field.modelDeps) deps.add(d);
|
|
7979
|
+
for (const variant of plan.shape.variants) for (const field of variant.fields) for (const d of field.modelDeps) deps.add(d);
|
|
7980
|
+
const symbols = [];
|
|
7981
|
+
for (const dep of [...deps].sort()) {
|
|
7982
|
+
const domain = toPascalCase(dep);
|
|
7983
|
+
symbols.push(domain);
|
|
7984
|
+
const wire = wireInterfaceName(domain);
|
|
7985
|
+
if (wire !== domain) symbols.push(wire);
|
|
7986
|
+
}
|
|
7987
|
+
if (symbols.length === 0) return [];
|
|
7988
|
+
return symbols.map((sym) => {
|
|
7989
|
+
return {
|
|
7990
|
+
path: `./${fileName$3(toSnakeFromPascal(sym.replace(/Response$/, "")))}.interface`,
|
|
7991
|
+
symbols: [sym]
|
|
7992
|
+
};
|
|
7993
|
+
}).reduce((acc, cur) => {
|
|
7994
|
+
const existing = acc.find((a) => a.path === cur.path);
|
|
7995
|
+
if (existing) existing.symbols.push(...cur.symbols);
|
|
7996
|
+
else acc.push(cur);
|
|
7997
|
+
return acc;
|
|
7998
|
+
}, []);
|
|
7999
|
+
}
|
|
8000
|
+
function toSnakeFromPascal(s) {
|
|
8001
|
+
return s.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").toLowerCase();
|
|
8002
|
+
}
|
|
8003
|
+
function buildSerializerFile(plan, _ctx) {
|
|
8004
|
+
const { shape, modelDir } = plan;
|
|
8005
|
+
const domain = toPascalCase(shape.modelName);
|
|
8006
|
+
const wire = wireInterfaceName(domain);
|
|
8007
|
+
const lines = [];
|
|
8008
|
+
const interfaceImportPath = `../interfaces/${fileName$3(shape.modelName)}.interface`;
|
|
8009
|
+
lines.push(`import type { ${domain}, ${wire} } from '${interfaceImportPath}';`);
|
|
8010
|
+
const allDeps = /* @__PURE__ */ new Set();
|
|
8011
|
+
for (const field of shape.baseFields) for (const d of field.modelDeps) allDeps.add(d);
|
|
8012
|
+
for (const variant of shape.variants) for (const field of variant.fields) for (const d of field.modelDeps) allDeps.add(d);
|
|
8013
|
+
for (const dep of [...allDeps].sort()) {
|
|
8014
|
+
const depDomain = toPascalCase(dep);
|
|
8015
|
+
const depFile = fileName$3(toSnakeFromPascal(depDomain));
|
|
8016
|
+
lines.push(`import { deserialize${depDomain}, serialize${depDomain} } from './${depFile}.serializer';`);
|
|
8017
|
+
}
|
|
8018
|
+
lines.push("");
|
|
8019
|
+
lines.push(`export const deserialize${domain} = (response: ${wire}): ${domain} => {`);
|
|
8020
|
+
lines.push(` switch (response.${shape.discriminatorProperty}) {`);
|
|
8021
|
+
for (const variant of shape.variants) {
|
|
8022
|
+
lines.push(` case '${variant.discriminatorValue}':`);
|
|
8023
|
+
lines.push(` return {`);
|
|
8024
|
+
for (const field of shape.baseFields) lines.push(` ${assignmentLine(field, false, allDeps)},`);
|
|
8025
|
+
lines.push(` ${shape.discriminatorPropertyDomain}: '${variant.discriminatorValue}',`);
|
|
8026
|
+
for (const field of variant.fields) lines.push(` ${assignmentLine(field, false, allDeps)},`);
|
|
8027
|
+
lines.push(` };`);
|
|
8028
|
+
}
|
|
8029
|
+
lines.push(` default:`);
|
|
8030
|
+
lines.push(` throw new Error(\`Unknown ${shape.discriminatorProperty}: \${(response as { ${shape.discriminatorProperty}: string }).${shape.discriminatorProperty}}\`);`);
|
|
8031
|
+
lines.push(` }`);
|
|
8032
|
+
lines.push(`};`);
|
|
8033
|
+
lines.push("");
|
|
8034
|
+
lines.push(`export const serialize${domain} = (model: ${domain}): ${wire} => {`);
|
|
8035
|
+
lines.push(` switch (model.${shape.discriminatorPropertyDomain}) {`);
|
|
8036
|
+
for (const variant of shape.variants) {
|
|
8037
|
+
lines.push(` case '${variant.discriminatorValue}':`);
|
|
8038
|
+
lines.push(` return {`);
|
|
8039
|
+
for (const field of shape.baseFields) lines.push(` ${assignmentLine(field, true, allDeps)},`);
|
|
8040
|
+
lines.push(` ${shape.discriminatorProperty}: '${variant.discriminatorValue}',`);
|
|
8041
|
+
for (const field of variant.fields) lines.push(` ${assignmentLine(field, true, allDeps)},`);
|
|
8042
|
+
lines.push(` };`);
|
|
8043
|
+
}
|
|
8044
|
+
lines.push(` }`);
|
|
8045
|
+
lines.push(`};`);
|
|
8046
|
+
return {
|
|
8047
|
+
path: `src/${modelDir}/serializers/${fileName$3(shape.modelName)}.serializer.ts`,
|
|
8048
|
+
content: lines.join("\n") + "\n",
|
|
8049
|
+
overwriteExisting: true
|
|
8050
|
+
};
|
|
8051
|
+
}
|
|
8052
|
+
function assignmentLine(field, serialize, _allDeps) {
|
|
8053
|
+
const camel = toCamelCase(field.name);
|
|
8054
|
+
const snake = field.name;
|
|
8055
|
+
const lhs = serialize ? snake : camel;
|
|
8056
|
+
const rhsKey = serialize ? camel : snake;
|
|
8057
|
+
const source = serialize ? `model.${rhsKey}` : `response.${rhsKey}`;
|
|
8058
|
+
if (field.hasDateTime) {
|
|
8059
|
+
if (serialize) {
|
|
8060
|
+
if (field.required) return `${lhs}: ${source}.toISOString()`;
|
|
8061
|
+
return `${lhs}: ${source} != null ? ${source}.toISOString() : undefined`;
|
|
8062
|
+
}
|
|
8063
|
+
if (field.required) return `${lhs}: new Date(${source})`;
|
|
8064
|
+
return `${lhs}: ${source} != null ? new Date(${source}) : undefined`;
|
|
8065
|
+
}
|
|
8066
|
+
const arrayDep = arrayItemModelDep(field);
|
|
8067
|
+
if (arrayDep) {
|
|
8068
|
+
const fn = serialize ? `serialize${arrayDep}` : `deserialize${arrayDep}`;
|
|
8069
|
+
if (field.required) return `${lhs}: ${source}.map(${fn})`;
|
|
8070
|
+
return `${lhs}: ${source} != null ? ${source}.map(${fn}) : undefined`;
|
|
8071
|
+
}
|
|
8072
|
+
const scalarDep = scalarModelDepName(field);
|
|
8073
|
+
if (scalarDep) {
|
|
8074
|
+
const fn = serialize ? `serialize${scalarDep}` : `deserialize${scalarDep}`;
|
|
8075
|
+
if (field.required) return `${lhs}: ${fn}(${source})`;
|
|
8076
|
+
return `${lhs}: ${source} != null ? ${fn}(${source}) : undefined`;
|
|
8077
|
+
}
|
|
8078
|
+
return `${lhs}: ${source}`;
|
|
8079
|
+
}
|
|
8080
|
+
function arrayItemModelDep(field) {
|
|
8081
|
+
const m = field.domainType.match(/^([A-Z]\w*)\[\]$/);
|
|
8082
|
+
if (m && field.modelDeps.size > 0) return m[1];
|
|
8083
|
+
return null;
|
|
8084
|
+
}
|
|
8085
|
+
function scalarModelDepName(field) {
|
|
8086
|
+
const stripped = field.domainType.replace(/\s*\|\s*null$/, "");
|
|
8087
|
+
if (/^[A-Z]\w*$/.test(stripped) && field.modelDeps.size === 1) return toPascalCase([...field.modelDeps][0]);
|
|
8088
|
+
return null;
|
|
8089
|
+
}
|
|
8090
|
+
//#endregion
|
|
7646
8091
|
//#region src/node/node-overrides.ts
|
|
7647
8092
|
const OPERATION_OVERRIDES = {
|
|
7648
8093
|
"POST /organizations/{organizationId}/groups": { methodName: "create_group" },
|
|
@@ -7662,31 +8107,71 @@ const contextCache = /* @__PURE__ */ new WeakMap();
|
|
|
7662
8107
|
function operationKey(resolved) {
|
|
7663
8108
|
return `${resolved.operation.httpMethod.toUpperCase()} ${resolved.operation.path}`;
|
|
7664
8109
|
}
|
|
8110
|
+
/**
|
|
8111
|
+
* Apply oneOf / allOf+oneOf enrichment (flattening variant fields onto the
|
|
8112
|
+
* parent model, plus synthetic models/enums for inline shapes) so the rest
|
|
8113
|
+
* of the Node emitter sees a richer `spec.models`.
|
|
8114
|
+
*
|
|
8115
|
+
* Without this, `ConnectApplication` (and any other `allOf [base, oneOf [...]]`
|
|
8116
|
+
* schema whose first variant is itself wrapped in `allOf`) loses every
|
|
8117
|
+
* non-M2M field — the IR parser's discriminator detection silently skips
|
|
8118
|
+
* variants whose properties live behind another `allOf`. Mirrors what the
|
|
8119
|
+
* Go / Kotlin / .NET emitters already do.
|
|
8120
|
+
*
|
|
8121
|
+
* Discriminated bases produced by `enrichModelsFromSpec` get their original
|
|
8122
|
+
* fields restored — Node emits flat interfaces today, not TS sum types, so
|
|
8123
|
+
* an empty base would otherwise drop the common fields.
|
|
8124
|
+
*/
|
|
8125
|
+
function enrichSpecModels(models) {
|
|
8126
|
+
const enriched = enrichModelsFromSpec(models);
|
|
8127
|
+
const originalByName = new Map(models.map((m) => [m.name, m]));
|
|
8128
|
+
return enriched.map((m) => {
|
|
8129
|
+
if (m.discriminator && m.fields.length === 0) {
|
|
8130
|
+
const original = originalByName.get(m.name);
|
|
8131
|
+
if (original && original.fields.length > 0) return {
|
|
8132
|
+
...m,
|
|
8133
|
+
fields: original.fields
|
|
8134
|
+
};
|
|
8135
|
+
}
|
|
8136
|
+
return m;
|
|
8137
|
+
});
|
|
8138
|
+
}
|
|
7665
8139
|
function withNodeOperationOverrides(ctx) {
|
|
7666
8140
|
const cached = contextCache.get(ctx);
|
|
7667
8141
|
if (cached) return cached;
|
|
8142
|
+
const enrichedModels = enrichSpecModels(ctx.spec.models);
|
|
8143
|
+
const specChanged = enrichedModels.length !== ctx.spec.models.length || enrichedModels.some((m, i) => m !== ctx.spec.models[i]);
|
|
8144
|
+
const enrichedSpec = specChanged ? {
|
|
8145
|
+
...ctx.spec,
|
|
8146
|
+
models: enrichedModels
|
|
8147
|
+
} : ctx.spec;
|
|
7668
8148
|
const resolvedOperations = ctx.resolvedOperations;
|
|
7669
8149
|
if (!resolvedOperations?.length) {
|
|
7670
|
-
|
|
7671
|
-
|
|
8150
|
+
const next = specChanged ? {
|
|
8151
|
+
...ctx,
|
|
8152
|
+
spec: enrichedSpec
|
|
8153
|
+
} : ctx;
|
|
8154
|
+
contextCache.set(ctx, next);
|
|
8155
|
+
return next;
|
|
7672
8156
|
}
|
|
7673
|
-
let
|
|
8157
|
+
let opsChanged = false;
|
|
7674
8158
|
const nextResolved = resolvedOperations.map((resolved) => {
|
|
7675
8159
|
const override = OPERATION_OVERRIDES[operationKey(resolved)];
|
|
7676
8160
|
if (!override) return resolved;
|
|
7677
8161
|
const methodName = override.methodName ?? resolved.methodName;
|
|
7678
8162
|
const mountOn = override.mountOn ?? resolved.mountOn;
|
|
7679
8163
|
if (methodName === resolved.methodName && mountOn === resolved.mountOn) return resolved;
|
|
7680
|
-
|
|
8164
|
+
opsChanged = true;
|
|
7681
8165
|
return {
|
|
7682
8166
|
...resolved,
|
|
7683
8167
|
methodName,
|
|
7684
8168
|
mountOn
|
|
7685
8169
|
};
|
|
7686
8170
|
});
|
|
7687
|
-
const next =
|
|
8171
|
+
const next = opsChanged || specChanged ? {
|
|
7688
8172
|
...ctx,
|
|
7689
|
-
resolvedOperations: nextResolved
|
|
8173
|
+
...opsChanged ? { resolvedOperations: nextResolved } : {},
|
|
8174
|
+
...specChanged ? { spec: enrichedSpec } : {}
|
|
7690
8175
|
} : ctx;
|
|
7691
8176
|
contextCache.set(ctx, next);
|
|
7692
8177
|
return next;
|
|
@@ -7897,17 +8382,51 @@ function applyLiveSurface(files, ctx, surface) {
|
|
|
7897
8382
|
}
|
|
7898
8383
|
return out;
|
|
7899
8384
|
}
|
|
8385
|
+
/**
|
|
8386
|
+
* Flatten oneOf / allOf+oneOf variant fields from the raw spec onto each
|
|
8387
|
+
* model. `enrichModelsFromSpec` produces (a) extra optional fields on models
|
|
8388
|
+
* whose schema is `allOf [base, oneOf [...]]`, and (b) synthetic models /
|
|
8389
|
+
* enums for inline objects encountered inside variants (e.g. the inline
|
|
8390
|
+
* `redirect_uris` item shape on `ConnectApplication`).
|
|
8391
|
+
*
|
|
8392
|
+
* Node, like Go / Kotlin / .NET, emits flat interfaces rather than a sum
|
|
8393
|
+
* type, so on `enrichModelsFromSpec`-marked discriminated bases we restore
|
|
8394
|
+
* the original IR fields — otherwise the base interface would be empty.
|
|
8395
|
+
* A future change can emit a real TS discriminated union; for now the goal
|
|
8396
|
+
* is parity with the other flat-emit languages so every variant field is
|
|
8397
|
+
* at least reachable.
|
|
8398
|
+
*/
|
|
8399
|
+
function enrichModelsForNode(models) {
|
|
8400
|
+
const enriched = enrichModelsFromSpec(models);
|
|
8401
|
+
const originalByName = new Map(models.map((m) => [m.name, m]));
|
|
8402
|
+
return enriched.map((m) => {
|
|
8403
|
+
if (m.discriminator && m.fields.length === 0) {
|
|
8404
|
+
const original = originalByName.get(m.name);
|
|
8405
|
+
if (original && original.fields.length > 0) return {
|
|
8406
|
+
...m,
|
|
8407
|
+
fields: original.fields
|
|
8408
|
+
};
|
|
8409
|
+
}
|
|
8410
|
+
return m;
|
|
8411
|
+
});
|
|
8412
|
+
}
|
|
7900
8413
|
const nodeEmitter = {
|
|
7901
8414
|
language: "node",
|
|
7902
8415
|
generateModels(models, ctx) {
|
|
7903
8416
|
const nodeCtx = withNodeOperationOverrides(ctx);
|
|
7904
8417
|
const surface = getSurface(nodeCtx);
|
|
7905
|
-
|
|
8418
|
+
const enriched = enrichModelsForNode(models);
|
|
8419
|
+
const discPlans = planDiscriminatedModels(enriched, nodeCtx);
|
|
8420
|
+
nodeCtx._discriminatedModelNames = new Set(discPlans.keys());
|
|
8421
|
+
const standardFiles = generateModelsAndSerializers(enriched, nodeCtx);
|
|
8422
|
+
const discFiles = generateDiscriminatedFiles(discPlans, nodeCtx);
|
|
8423
|
+
return applyLiveSurface([...standardFiles, ...discFiles], nodeCtx, surface);
|
|
7906
8424
|
},
|
|
7907
8425
|
generateEnums(enums, ctx) {
|
|
7908
8426
|
const nodeCtx = withNodeOperationOverrides(ctx);
|
|
7909
8427
|
const surface = getSurface(nodeCtx);
|
|
7910
|
-
|
|
8428
|
+
const syntheticEnums = getSyntheticEnums();
|
|
8429
|
+
return applyLiveSurface(generateEnums$7([...enums, ...syntheticEnums], nodeCtx), nodeCtx, surface);
|
|
7911
8430
|
},
|
|
7912
8431
|
generateResources(services, ctx) {
|
|
7913
8432
|
const nodeCtx = withNodeOperationOverrides(ctx);
|
|
@@ -7917,7 +8436,7 @@ const nodeEmitter = {
|
|
|
7917
8436
|
generateClient(spec, ctx) {
|
|
7918
8437
|
const nodeCtx = withNodeOperationOverrides(ctx);
|
|
7919
8438
|
const surface = getSurface(nodeCtx);
|
|
7920
|
-
return applyLiveSurface(generateClient$7(spec, nodeCtx), nodeCtx, surface);
|
|
8439
|
+
return applyLiveSurface(generateClient$7(nodeCtx.spec, nodeCtx), nodeCtx, surface);
|
|
7921
8440
|
},
|
|
7922
8441
|
generateErrors(_ctx) {
|
|
7923
8442
|
return [];
|
|
@@ -13845,15 +14364,37 @@ function ensureTrailingNewlines$5(files) {
|
|
|
13845
14364
|
for (const f of files) if (f.content && !f.content.endsWith("\n")) f.content += "\n";
|
|
13846
14365
|
return files;
|
|
13847
14366
|
}
|
|
14367
|
+
/**
|
|
14368
|
+
* Flatten oneOf / allOf+oneOf variant fields onto each base model and pull
|
|
14369
|
+
* in synthetic models / enums for inline variant shapes. PHP emits flat
|
|
14370
|
+
* classes (no sum types), so a discriminated base whose IR fields the
|
|
14371
|
+
* parser stripped (post-allOf-aware detection) gets its original fields
|
|
14372
|
+
* restored to avoid silently dropping variant data.
|
|
14373
|
+
*/
|
|
14374
|
+
function enrichModelsForPhp(models) {
|
|
14375
|
+
const enriched = enrichModelsFromSpec(models);
|
|
14376
|
+
const originalByName = new Map(models.map((m) => [m.name, m]));
|
|
14377
|
+
return enriched.map((m) => {
|
|
14378
|
+
if (m.discriminator && m.fields.length === 0) {
|
|
14379
|
+
const original = originalByName.get(m.name);
|
|
14380
|
+
if (original && original.fields.length > 0) return {
|
|
14381
|
+
...m,
|
|
14382
|
+
fields: original.fields
|
|
14383
|
+
};
|
|
14384
|
+
}
|
|
14385
|
+
return m;
|
|
14386
|
+
});
|
|
14387
|
+
}
|
|
13848
14388
|
const phpEmitter = {
|
|
13849
14389
|
language: "php",
|
|
13850
14390
|
generateModels(models, ctx) {
|
|
13851
14391
|
ensureNamingInitialized(ctx);
|
|
13852
|
-
return ensureTrailingNewlines$5(generateModels$5(models, ctx));
|
|
14392
|
+
return ensureTrailingNewlines$5(generateModels$5(enrichModelsForPhp(models), ctx));
|
|
13853
14393
|
},
|
|
13854
14394
|
generateEnums(enums, ctx) {
|
|
13855
14395
|
ensureNamingInitialized(ctx);
|
|
13856
|
-
|
|
14396
|
+
const syntheticEnums = getSyntheticEnums();
|
|
14397
|
+
return ensureTrailingNewlines$5(generateEnums$5([...enums, ...syntheticEnums], ctx));
|
|
13857
14398
|
},
|
|
13858
14399
|
generateResources(services, ctx) {
|
|
13859
14400
|
ensureNamingInitialized(ctx);
|
|
@@ -24436,13 +24977,37 @@ function ensureTrailingNewlines$1(files) {
|
|
|
24436
24977
|
for (const f of files) if (f.content && !f.content.endsWith("\n")) f.content += "\n";
|
|
24437
24978
|
return files;
|
|
24438
24979
|
}
|
|
24980
|
+
/**
|
|
24981
|
+
* Flatten oneOf / allOf+oneOf variant fields onto each base model and pick
|
|
24982
|
+
* up the synthetic models / enums `enrichModelsFromSpec` produces for inline
|
|
24983
|
+
* variant shapes. Ruby emits flat hash-backed models, not sum types, so a
|
|
24984
|
+
* discriminated base whose IR fields were stripped (the new EventSchema-
|
|
24985
|
+
* style behaviour after the parser learned to walk allOf-wrapped variants)
|
|
24986
|
+
* has its original fields restored — otherwise `ConnectApplication`-style
|
|
24987
|
+
* bases would silently lose every variant field they had previously.
|
|
24988
|
+
*/
|
|
24989
|
+
function enrichModelsForRuby(models) {
|
|
24990
|
+
const enriched = enrichModelsFromSpec(models);
|
|
24991
|
+
const originalByName = new Map(models.map((m) => [m.name, m]));
|
|
24992
|
+
return enriched.map((m) => {
|
|
24993
|
+
if (m.discriminator && m.fields.length === 0) {
|
|
24994
|
+
const original = originalByName.get(m.name);
|
|
24995
|
+
if (original && original.fields.length > 0) return {
|
|
24996
|
+
...m,
|
|
24997
|
+
fields: original.fields
|
|
24998
|
+
};
|
|
24999
|
+
}
|
|
25000
|
+
return m;
|
|
25001
|
+
});
|
|
25002
|
+
}
|
|
24439
25003
|
const rubyEmitter = {
|
|
24440
25004
|
language: "ruby",
|
|
24441
25005
|
generateModels(models, ctx) {
|
|
24442
|
-
return ensureTrailingNewlines$1(generateModels$1(models, ctx));
|
|
25006
|
+
return ensureTrailingNewlines$1(generateModels$1(enrichModelsForRuby(models), ctx));
|
|
24443
25007
|
},
|
|
24444
25008
|
generateEnums(enums, ctx) {
|
|
24445
|
-
|
|
25009
|
+
const syntheticEnums = getSyntheticEnums();
|
|
25010
|
+
return ensureTrailingNewlines$1(generateEnums$1([...enums, ...syntheticEnums], ctx));
|
|
24446
25011
|
},
|
|
24447
25012
|
generateResources(services, ctx) {
|
|
24448
25013
|
return ensureTrailingNewlines$1(generateResources$1(services, ctx));
|
|
@@ -26731,14 +27296,37 @@ function ensureTrailingNewlines(files) {
|
|
|
26731
27296
|
for (const f of files) if (f.content && !f.content.endsWith("\n")) f.content += "\n";
|
|
26732
27297
|
return files;
|
|
26733
27298
|
}
|
|
27299
|
+
/**
|
|
27300
|
+
* Flatten oneOf / allOf+oneOf variant fields onto each base model and pull
|
|
27301
|
+
* in synthetic models / enums for inline variant shapes. Rust emits flat
|
|
27302
|
+
* structs (a synthesised enum-union from `UnionRegistry` exists, but the
|
|
27303
|
+
* field-on-base pattern is what matches `ConnectApplication` today). A
|
|
27304
|
+
* discriminated base whose IR fields the parser stripped gets its original
|
|
27305
|
+
* fields restored to avoid losing variant data.
|
|
27306
|
+
*/
|
|
27307
|
+
function enrichModelsForRust(models) {
|
|
27308
|
+
const enriched = enrichModelsFromSpec(models);
|
|
27309
|
+
const originalByName = new Map(models.map((m) => [m.name, m]));
|
|
27310
|
+
return enriched.map((m) => {
|
|
27311
|
+
if (m.discriminator && m.fields.length === 0) {
|
|
27312
|
+
const original = originalByName.get(m.name);
|
|
27313
|
+
if (original && original.fields.length > 0) return {
|
|
27314
|
+
...m,
|
|
27315
|
+
fields: original.fields
|
|
27316
|
+
};
|
|
27317
|
+
}
|
|
27318
|
+
return m;
|
|
27319
|
+
});
|
|
27320
|
+
}
|
|
26734
27321
|
const rustEmitter = {
|
|
26735
27322
|
language: "rust",
|
|
26736
27323
|
generateModels(models, ctx) {
|
|
26737
27324
|
unionRegistry.reset();
|
|
26738
|
-
return ensureTrailingNewlines(generateModels(models, ctx, unionRegistry));
|
|
27325
|
+
return ensureTrailingNewlines(generateModels(enrichModelsForRust(models), ctx, unionRegistry));
|
|
26739
27326
|
},
|
|
26740
27327
|
generateEnums(enums, ctx) {
|
|
26741
|
-
|
|
27328
|
+
const syntheticEnums = getSyntheticEnums();
|
|
27329
|
+
return ensureTrailingNewlines(generateEnums([...enums, ...syntheticEnums], ctx));
|
|
26742
27330
|
},
|
|
26743
27331
|
generateResources(services, ctx) {
|
|
26744
27332
|
return ensureTrailingNewlines(generateResources(services, ctx, unionRegistry));
|
|
@@ -26814,4 +27402,4 @@ const workosEmittersPlugin = {
|
|
|
26814
27402
|
//#endregion
|
|
26815
27403
|
export { pythonEmitter as _, rustExtractor as a, pythonExtractor as c, rustEmitter as d, rubyEmitter as f, phpEmitter as g, goEmitter as h, kotlinExtractor as i, rubyExtractor as l, dotnetEmitter as m, elixirExtractor as n, goExtractor as o, kotlinEmitter as p, dotnetExtractor as r, phpExtractor as s, workosEmittersPlugin as t, nodeExtractor as u, nodeEmitter as v };
|
|
26816
27404
|
|
|
26817
|
-
//# sourceMappingURL=plugin-
|
|
27405
|
+
//# sourceMappingURL=plugin-BxVeu2v9.mjs.map
|