diff --git a/generators/java-v2/dynamic-snippets/src/context/DynamicSnippetsGeneratorContext.ts b/generators/java-v2/dynamic-snippets/src/context/DynamicSnippetsGeneratorContext.ts index f526815ede65..3f013687eafe 100644 --- a/generators/java-v2/dynamic-snippets/src/context/DynamicSnippetsGeneratorContext.ts +++ b/generators/java-v2/dynamic-snippets/src/context/DynamicSnippetsGeneratorContext.ts @@ -29,6 +29,16 @@ const RESERVED_NAMES = new Set([ "getClass" ]); +/** + * Information about an inline type's location as a nested class. + */ +interface InlineTypeInfo { + /** The class reference for the owner (top-level) type */ + ownerClassRef: java.ClassReference; + /** The nested path from the owner to this type (e.g., ["Bar", "Type1", "Bar_"]) */ + nestedPath: string[]; +} + export class DynamicSnippetsGeneratorContext extends AbstractDynamicSnippetsGeneratorContext { public ir: FernIr.dynamic.DynamicIntermediateRepresentation; public customConfig: BaseJavaCustomConfigSchema; @@ -36,6 +46,9 @@ export class DynamicSnippetsGeneratorContext extends AbstractDynamicSnippetsGene public dynamicTypeLiteralMapper: DynamicTypeLiteralMapper; public filePropertyMapper: FilePropertyMapper; + /** Mapping from type ID to inline type info (only populated when enable-inline-types is true) */ + private inlineTypeInfoByTypeId: Map = new Map(); + constructor({ ir, config, @@ -51,6 +64,359 @@ export class DynamicSnippetsGeneratorContext extends AbstractDynamicSnippetsGene this.dynamicTypeMapper = new DynamicTypeMapper({ context: this }); this.dynamicTypeLiteralMapper = new DynamicTypeLiteralMapper({ context: this }); this.filePropertyMapper = new FilePropertyMapper({ context: this }); + + // Build inline type mapping if enable-inline-types is true + if (this.customConfig["enable-inline-types"]) { + this.buildInlineTypeMapping(); + } + } + + /** + * Builds a mapping from inline type IDs to their nested class locations. + * This traverses all types in the IR and finds inline types, recording their + * owner class and nested path. + */ + private buildInlineTypeMapping(): void { + // First pass: find all non-inline types (these are the potential owners) + for (const [typeId, namedType] of Object.entries(this.ir.types)) { + // Use type assertion to access the inline property (added to dynamic IR but not yet in published SDK) + const isInline = (namedType.declaration as { inline?: boolean }).inline; + if (!isInline) { + // This is a top-level type that can own inline types + const ownerClassRef = this.getOwnerClassReference(namedType); + const usedNames = new Map(); + this.traverseTypeForInlineChildren({ + namedType, + ownerClassRef, + parentPath: [], + usedNames + }); + } + } + } + + /** + * Gets the class reference for a top-level (non-inline) type. + */ + private getOwnerClassReference(namedType: FernIr.dynamic.NamedType): java.ClassReference { + const declaration = namedType.declaration; + // Determine if this is a request type or a regular type + // Request types go in the requests package, others go in types package + const packageName = this.getTypesPackageName(declaration.fernFilepath); + return java.classReference({ + name: this.getClassName(declaration.name), + packageName + }); + } + + /** + * Traverses a type to find inline children and record their locations. + */ + private traverseTypeForInlineChildren({ + namedType, + ownerClassRef, + parentPath, + usedNames + }: { + namedType: FernIr.dynamic.NamedType; + ownerClassRef: java.ClassReference; + parentPath: string[]; + usedNames: Map; + }): void { + switch (namedType.type) { + case "object": + this.traverseObjectProperties({ + properties: namedType.properties, + ownerClassRef, + parentPath, + usedNames + }); + break; + case "discriminatedUnion": + this.traverseDiscriminatedUnion({ + union: namedType, + ownerClassRef, + parentPath, + usedNames + }); + break; + case "undiscriminatedUnion": + this.traverseUndiscriminatedUnion({ + union: namedType, + ownerClassRef, + parentPath, + usedNames + }); + break; + case "alias": + this.traverseTypeReference({ + typeReference: namedType.typeReference, + propertyName: namedType.declaration.name, + ownerClassRef, + parentPath, + usedNames + }); + break; + case "enum": + // Enums don't have nested types + break; + default: + assertNever(namedType); + } + } + + /** + * Traverses object properties to find inline types. + */ + private traverseObjectProperties({ + properties, + ownerClassRef, + parentPath, + usedNames + }: { + properties: FernIr.dynamic.NamedParameter[]; + ownerClassRef: java.ClassReference; + parentPath: string[]; + usedNames: Map; + }): void { + for (const property of properties) { + this.traverseTypeReference({ + typeReference: property.typeReference, + propertyName: property.name.name, + ownerClassRef, + parentPath, + usedNames + }); + } + } + + /** + * Traverses a discriminated union to find inline types. + */ + private traverseDiscriminatedUnion({ + union, + ownerClassRef, + parentPath, + usedNames + }: { + union: FernIr.dynamic.DiscriminatedUnionType; + ownerClassRef: java.ClassReference; + parentPath: string[]; + usedNames: Map; + }): void { + for (const [, singleUnionType] of Object.entries(union.types)) { + switch (singleUnionType.type) { + case "samePropertiesAsObject": + // The variant references another type by typeId + // Construct the TypeReference object manually (factory function not available in published SDK) + this.traverseTypeReference({ + typeReference: { type: "named", value: singleUnionType.typeId } as FernIr.dynamic.TypeReference, + propertyName: singleUnionType.discriminantValue.name, + ownerClassRef, + parentPath, + usedNames + }); + // Also traverse the properties + if (singleUnionType.properties) { + this.traverseObjectProperties({ + properties: singleUnionType.properties, + ownerClassRef, + parentPath, + usedNames + }); + } + break; + case "singleProperty": + this.traverseTypeReference({ + typeReference: singleUnionType.typeReference, + propertyName: singleUnionType.discriminantValue.name, + ownerClassRef, + parentPath, + usedNames + }); + if (singleUnionType.properties) { + this.traverseObjectProperties({ + properties: singleUnionType.properties, + ownerClassRef, + parentPath, + usedNames + }); + } + break; + case "noProperties": + if (singleUnionType.properties) { + this.traverseObjectProperties({ + properties: singleUnionType.properties, + ownerClassRef, + parentPath, + usedNames + }); + } + break; + default: + assertNever(singleUnionType); + } + } + } + + /** + * Traverses an undiscriminated union to find inline types. + */ + private traverseUndiscriminatedUnion({ + union, + ownerClassRef, + parentPath, + usedNames + }: { + union: FernIr.dynamic.UndiscriminatedUnionType; + ownerClassRef: java.ClassReference; + parentPath: string[]; + usedNames: Map; + }): void { + for (let i = 0; i < union.types.length; i++) { + const typeRef = union.types[i]; + // For undiscriminated unions, we use a synthetic name based on index + const syntheticName: FernIr.dynamic.Name = { + originalName: `variant${i}`, + camelCase: { safeName: `variant${i}`, unsafeName: `variant${i}` }, + pascalCase: { safeName: `Variant${i}`, unsafeName: `Variant${i}` }, + snakeCase: { safeName: `variant_${i}`, unsafeName: `variant_${i}` }, + screamingSnakeCase: { safeName: `VARIANT_${i}`, unsafeName: `VARIANT_${i}` } + }; + if (typeRef != null) { + this.traverseTypeReference({ + typeReference: typeRef, + propertyName: syntheticName, + ownerClassRef, + parentPath, + usedNames + }); + } + } + } + + /** + * Traverses a type reference to find inline types. + */ + private traverseTypeReference({ + typeReference, + propertyName, + ownerClassRef, + parentPath, + usedNames + }: { + typeReference: FernIr.dynamic.TypeReference; + propertyName: FernIr.dynamic.Name; + ownerClassRef: java.ClassReference; + parentPath: string[]; + usedNames: Map; + }): void { + switch (typeReference.type) { + case "named": { + const childTypeId = typeReference.value; + const childNamed = this.resolveNamedType({ typeId: childTypeId }); + if (childNamed == null) { + return; + } + // Use type assertion to access the inline property (added to dynamic IR but not yet in published SDK) + const isChildInline = (childNamed.declaration as { inline?: boolean }).inline; + if (isChildInline) { + // This is an inline type - record its location + const baseName = this.getClassName(propertyName); + const nestedName = this.getUniqueNestedName(baseName, usedNames); + const childPath = [...parentPath, nestedName]; + + this.inlineTypeInfoByTypeId.set(childTypeId, { + ownerClassRef, + nestedPath: childPath + }); + + // Recursively traverse the inline type's children + const childUsedNames = new Map(); + this.traverseTypeForInlineChildren({ + namedType: childNamed, + ownerClassRef, + parentPath: childPath, + usedNames: childUsedNames + }); + } + break; + } + case "list": + case "set": + this.traverseTypeReference({ + typeReference: typeReference.value, + propertyName, + ownerClassRef, + parentPath, + usedNames + }); + break; + case "map": { + // Use type assertion to access key and value properties of map type + const mapType = typeReference as FernIr.dynamic.TypeReference.Map; + this.traverseTypeReference({ + typeReference: mapType.key, + propertyName, + ownerClassRef, + parentPath, + usedNames + }); + this.traverseTypeReference({ + typeReference: mapType.value, + propertyName, + ownerClassRef, + parentPath, + usedNames + }); + break; + } + case "optional": + case "nullable": + this.traverseTypeReference({ + typeReference: typeReference.value, + propertyName, + ownerClassRef, + parentPath, + usedNames + }); + break; + case "primitive": + case "literal": + case "unknown": + // These don't contain nested types + break; + default: + assertNever(typeReference); + } + } + + /** + * Gets a unique nested class name, handling collisions by appending underscores. + */ + private getUniqueNestedName(baseName: string, usedNames: Map): string { + const count = usedNames.get(baseName) ?? 0; + usedNames.set(baseName, count + 1); + if (count === 0) { + return baseName; + } + return baseName + "_".repeat(count); + } + + /** + * Gets the class reference for an inline type, constructing the nested class name. + */ + private getInlineClassReference(typeId: string): java.ClassReference | undefined { + const info = this.inlineTypeInfoByTypeId.get(typeId); + if (info == null) { + return undefined; + } + // Construct the nested class name (e.g., "GetDiscriminatedUnionRequest.Bar.Type1") + const nestedName = [info.ownerClassRef.name, ...info.nestedPath].join("."); + return java.classReference({ + name: nestedName, + packageName: info.ownerClassRef.packageName + }); } public clone(): DynamicSnippetsGeneratorContext { @@ -122,6 +488,35 @@ export class DynamicSnippetsGeneratorContext extends AbstractDynamicSnippetsGene }); } + /** + * Gets the Java class reference for a named type, handling inline types correctly. + * For inline types, this returns a nested class reference (e.g., "GetDiscriminatedUnionRequest.Bar"). + * For non-inline types, this returns a regular class reference. + */ + public getJavaClassReferenceForNamedType({ + typeId, + declaration + }: { + typeId: string; + declaration: FernIr.dynamic.Declaration; + }): java.ClassReference { + // Check if this is an inline type and we have inline types enabled + // Use type assertion to access the inline property (added to dynamic IR but not yet in published SDK) + const isInline = (declaration as { inline?: boolean }).inline; + if (this.customConfig["enable-inline-types"] && isInline) { + const inlineRef = this.getInlineClassReference(typeId); + if (inlineRef != null) { + return inlineRef; + } + } + + // Fallback to regular class reference + return java.classReference({ + name: declaration.name.pascalCase.unsafeName, + packageName: this.getTypesPackageName(declaration.fernFilepath) + }); + } + public getNullableClassReference(): java.ClassReference { return java.classReference({ name: "Nullable", diff --git a/generators/java-v2/dynamic-snippets/src/context/DynamicTypeLiteralMapper.ts b/generators/java-v2/dynamic-snippets/src/context/DynamicTypeLiteralMapper.ts index ab11c663dc2f..acd203462577 100644 --- a/generators/java-v2/dynamic-snippets/src/context/DynamicTypeLiteralMapper.ts +++ b/generators/java-v2/dynamic-snippets/src/context/DynamicTypeLiteralMapper.ts @@ -67,11 +67,13 @@ export class DynamicTypeLiteralMapper { case "map": return this.convertMap({ map: args.typeReference, value: args.value, as: args.as }); case "named": { - const named = this.context.resolveNamedType({ typeId: args.typeReference.value }); + const typeId = args.typeReference.value; + const named = this.context.resolveNamedType({ typeId }); if (named == null) { return java.TypeLiteral.nop(); } return this.convertNamed({ + typeId, named, value: args.value, as: args.as, @@ -278,11 +280,13 @@ export class DynamicTypeLiteralMapper { } private convertNamed({ + typeId, named, value, as, inUndiscriminatedUnion }: { + typeId: string; named: FernIr.dynamic.NamedType; value: unknown; as?: DynamicTypeLiteralMapper.ConvertedAs; @@ -293,30 +297,34 @@ export class DynamicTypeLiteralMapper { return this.convert({ typeReference: named.typeReference, value, as, inUndiscriminatedUnion }); case "discriminatedUnion": return this.convertDiscriminatedUnion({ + typeId, discriminatedUnion: named, value }); case "enum": - return this.convertEnum({ enum_: named, value }); + return this.convertEnum({ typeId, enum_: named, value }); case "object": - return this.convertObject({ object_: named, value, as }); + return this.convertObject({ typeId, object_: named, value, as }); case "undiscriminatedUnion": // Don't pass inUndiscriminatedUnion here - we're AT the undiscriminated union level, // not within it. The flag should only apply to the variants within the union. - return this.convertUndiscriminatedUnion({ undiscriminatedUnion: named, value }); + return this.convertUndiscriminatedUnion({ typeId, undiscriminatedUnion: named, value }); default: assertNever(named); } } private convertDiscriminatedUnion({ + typeId, discriminatedUnion, value }: { + typeId: string; discriminatedUnion: FernIr.dynamic.DiscriminatedUnionType; value: unknown; }): java.TypeLiteral { - const classReference = this.context.getJavaClassReferenceFromDeclaration({ + const classReference = this.context.getJavaClassReferenceForNamedType({ + typeId, declaration: discriminatedUnion.declaration }); const discriminatedUnionTypeInstance = this.context.resolveDiscriminatedUnionTypeInstance({ @@ -329,8 +337,9 @@ export class DynamicTypeLiteralMapper { const unionVariant = discriminatedUnionTypeInstance.singleDiscriminatedUnionType; switch (unionVariant.type) { case "samePropertiesAsObject": { + const variantTypeId = unionVariant.typeId; const named = this.context.resolveNamedType({ - typeId: unionVariant.typeId + typeId: variantTypeId }); if (named == null) { return java.TypeLiteral.nop(); @@ -339,7 +348,13 @@ export class DynamicTypeLiteralMapper { java.invokeMethod({ on: classReference, method: this.context.getPropertyName(unionVariant.discriminantValue.name), - arguments_: [this.convertNamed({ named, value: discriminatedUnionTypeInstance.value })] + arguments_: [ + this.convertNamed({ + typeId: variantTypeId, + named, + value: discriminatedUnionTypeInstance.value + }) + ] }) ); } @@ -382,10 +397,12 @@ export class DynamicTypeLiteralMapper { } private convertObject({ + typeId, object_, value, as }: { + typeId: string; object_: FernIr.dynamic.ObjectType; value: unknown; as?: DynamicTypeLiteralMapper.ConvertedAs; @@ -399,7 +416,8 @@ export class DynamicTypeLiteralMapper { ? properties.filter((property) => !this.context.isDirectLiteral(property.typeReference)) : properties; return java.TypeLiteral.builder({ - classReference: this.context.getJavaClassReferenceFromDeclaration({ + classReference: this.context.getJavaClassReferenceForNamedType({ + typeId, declaration: object_.declaration }), parameters: filteredProperties.map((property) => { @@ -416,13 +434,22 @@ export class DynamicTypeLiteralMapper { }); } - private convertEnum({ enum_, value }: { enum_: FernIr.dynamic.EnumType; value: unknown }): java.TypeLiteral { + private convertEnum({ + typeId, + enum_, + value + }: { + typeId: string; + enum_: FernIr.dynamic.EnumType; + value: unknown; + }): java.TypeLiteral { const name = this.getEnumValueName({ enum_, value }); if (name == null) { return java.TypeLiteral.nop(); } return java.TypeLiteral.enum_({ - classReference: this.context.getJavaClassReferenceFromDeclaration({ + classReference: this.context.getJavaClassReferenceForNamedType({ + typeId, declaration: enum_.declaration }), value: name @@ -449,9 +476,11 @@ export class DynamicTypeLiteralMapper { } private convertUndiscriminatedUnion({ + typeId, undiscriminatedUnion, value }: { + typeId: string; undiscriminatedUnion: FernIr.dynamic.UndiscriminatedUnionType; value: unknown; }): java.TypeLiteral { @@ -462,14 +491,16 @@ export class DynamicTypeLiteralMapper { if (result == null) { return java.TypeLiteral.nop(); } + const classReference = this.context.getJavaClassReferenceForNamedType({ + typeId, + declaration: undiscriminatedUnion.declaration + }); if (this.context.isPrimitive(result.valueTypeReference)) { // Primitive types overload the 'of' method rather than // defining a separate method from the type. return java.TypeLiteral.reference( java.invokeMethod({ - on: this.context.getJavaClassReferenceFromDeclaration({ - declaration: undiscriminatedUnion.declaration - }), + on: classReference, method: "of", arguments_: [result.typeInstantiation] }) @@ -479,9 +510,7 @@ export class DynamicTypeLiteralMapper { // This matches the Java SDK's generated code pattern return java.TypeLiteral.reference( java.invokeMethod({ - on: this.context.getJavaClassReferenceFromDeclaration({ - declaration: undiscriminatedUnion.declaration - }), + on: classReference, method: "of", arguments_: [result.typeInstantiation] }) diff --git a/generators/java-v2/dynamic-snippets/src/context/DynamicTypeMapper.ts b/generators/java-v2/dynamic-snippets/src/context/DynamicTypeMapper.ts index 13159214bcd1..386b8a3ed2e8 100644 --- a/generators/java-v2/dynamic-snippets/src/context/DynamicTypeMapper.ts +++ b/generators/java-v2/dynamic-snippets/src/context/DynamicTypeMapper.ts @@ -30,11 +30,12 @@ export class DynamicTypeMapper { ); } case "named": { - const named = this.context.resolveNamedType({ typeId: args.typeReference.value }); + const typeId = args.typeReference.value; + const named = this.context.resolveNamedType({ typeId }); if (named == null) { return this.convertUnknown(); } - return this.convertNamed({ named }); + return this.convertNamed({ typeId, named }); } case "optional": case "nullable": { @@ -51,7 +52,7 @@ export class DynamicTypeMapper { } } - private convertNamed({ named }: { named: FernIr.dynamic.NamedType }): java.Type { + private convertNamed({ typeId, named }: { typeId: string; named: FernIr.dynamic.NamedType }): java.Type { switch (named.type) { case "alias": return this.convert({ typeReference: named.typeReference }); @@ -60,9 +61,9 @@ export class DynamicTypeMapper { case "object": case "undiscriminatedUnion": return java.Type.reference( - java.classReference({ - name: this.context.getClassName(named.declaration.name), - packageName: this.context.getTypesPackageName(named.declaration.fernFilepath) + this.context.getJavaClassReferenceForNamedType({ + typeId, + declaration: named.declaration }) ); default: diff --git a/generators/java/sdk/versions.yml b/generators/java/sdk/versions.yml index ad72f088bdf2..846de4391723 100644 --- a/generators/java/sdk/versions.yml +++ b/generators/java/sdk/versions.yml @@ -1,3 +1,14 @@ +- version: 3.23.2 + changelogEntry: + - summary: | + Fix dynamic snippets to correctly reference inline types as nested classes. When `enable-inline-types` + is configured, types are generated as nested static classes within parent types (e.g., + `GetDiscriminatedUnionRequest.Bar`). Dynamic snippets now correctly reference these nested classes + instead of trying to import them from `com.seed.object.types.*` where they don't exist. + type: fix + createdAt: "2025-12-06" + irVersion: 61 + - version: 3.23.1 changelogEntry: - summary: | diff --git a/packages/cli/ete-tests/src/tests/dependencies/__snapshots__/dependencies.test.ts.snap b/packages/cli/ete-tests/src/tests/dependencies/__snapshots__/dependencies.test.ts.snap index c411a7e76721..3834cce19031 100644 --- a/packages/cli/ete-tests/src/tests/dependencies/__snapshots__/dependencies.test.ts.snap +++ b/packages/cli/ete-tests/src/tests/dependencies/__snapshots__/dependencies.test.ts.snap @@ -660,7 +660,8 @@ exports[`dependencies > correctly incorporates dependencies 1`] = ` } ], "file": null - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -731,7 +732,8 @@ exports[`dependencies > correctly incorporates dependencies 1`] = ` "safeName": "Y" } } - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -841,7 +843,8 @@ exports[`dependencies > correctly incorporates dependencies 1`] = ` "safeName": "X" } } - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -917,7 +920,8 @@ exports[`dependencies > correctly incorporates dependencies 1`] = ` } ], "file": null - } + }, + "inline": null }, "location": { "method": "GET", @@ -1249,4 +1253,4 @@ exports[`dependencies > correctly incorporates dependencies 1`] = ` }" `; -exports[`dependencies > file dependencies 1`] = `5757723`; +exports[`dependencies > file dependencies 1`] = `5762035`; diff --git a/packages/cli/ete-tests/src/tests/ir/__snapshots__/ir.test.ts.snap b/packages/cli/ete-tests/src/tests/ir/__snapshots__/ir.test.ts.snap index 89d8eeae04ed..f10cda415883 100644 --- a/packages/cli/ete-tests/src/tests/ir/__snapshots__/ir.test.ts.snap +++ b/packages/cli/ete-tests/src/tests/ir/__snapshots__/ir.test.ts.snap @@ -1285,7 +1285,8 @@ exports[`ir > {"name":"extended-examples"} 1`] = ` "safeName": "App" } } - } + }, + "inline": null }, "properties": [ { @@ -1415,7 +1416,8 @@ exports[`ir > {"name":"extended-examples"} 1`] = ` "safeName": "Commons" } } - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -1486,7 +1488,8 @@ exports[`ir > {"name":"extended-examples"} 1`] = ` "safeName": "Commons" } } - } + }, + "inline": null }, "properties": [ { @@ -2238,7 +2241,8 @@ exports[`ir > {"name":"file-upload"} 1`] = ` "safeName": "FileUpload" } } - } + }, + "inline": null }, "location": { "method": "POST", @@ -2308,7 +2312,8 @@ exports[`ir > {"name":"file-upload"} 1`] = ` "safeName": "FileUpload" } } - } + }, + "inline": null }, "pathParameters": [], "queryParameters": [], @@ -9642,7 +9647,8 @@ exports[`ir > {"name":"multiple-environment-urls"} 1`] = ` "safeName": "EndpointUrls" } } - } + }, + "inline": null }, "location": { "method": "GET", @@ -9722,7 +9728,8 @@ exports[`ir > {"name":"multiple-environment-urls"} 1`] = ` "safeName": "EndpointUrls" } } - } + }, + "inline": null }, "location": { "method": "POST", @@ -9802,7 +9809,8 @@ exports[`ir > {"name":"multiple-environment-urls"} 1`] = ` "safeName": "ServiceUrl" } } - } + }, + "inline": null }, "location": { "method": "GET", @@ -12566,7 +12574,8 @@ exports[`ir > {"name":"nested-example-reference"} 1`] = ` "safeName": "Nested" } } - } + }, + "inline": null }, "properties": [ { @@ -12676,7 +12685,8 @@ exports[`ir > {"name":"nested-example-reference"} 1`] = ` "safeName": "Nested" } } - } + }, + "inline": null }, "properties": [ { @@ -12778,7 +12788,8 @@ exports[`ir > {"name":"nested-example-reference"} 1`] = ` "safeName": "Nested" } } - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -12892,7 +12903,8 @@ exports[`ir > {"name":"nested-example-reference"} 1`] = ` "safeName": "Nested" } } - } + }, + "inline": null }, "location": { "method": "POST", @@ -13894,7 +13906,8 @@ exports[`ir > {"name":"packages"} 1`] = ` "allParts": [], "packagePath": [], "file": null - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -13967,7 +13980,8 @@ exports[`ir > {"name":"packages"} 1`] = ` } ], "file": null - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -14038,7 +14052,8 @@ exports[`ir > {"name":"packages"} 1`] = ` "safeName": "Importer" } } - } + }, + "inline": null }, "properties": [ { @@ -14207,7 +14222,8 @@ exports[`ir > {"name":"packages"} 1`] = ` "safeName": "A" } } - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -14243,7 +14259,8 @@ exports[`ir > {"name":"packages"} 1`] = ` "allParts": [], "packagePath": [], "file": null - } + }, + "inline": null }, "location": { "method": "GET", @@ -16990,7 +17007,8 @@ exports[`ir > {"name":"response-property"} 1`] = ` "safeName": "Service" } } - } + }, + "inline": null }, "properties": [ { @@ -17090,7 +17108,8 @@ exports[`ir > {"name":"response-property"} 1`] = ` "safeName": "Service" } } - } + }, + "inline": null }, "properties": [ { @@ -17190,7 +17209,8 @@ exports[`ir > {"name":"response-property"} 1`] = ` "safeName": "Service" } } - } + }, + "inline": null }, "properties": [ { @@ -17323,7 +17343,8 @@ exports[`ir > {"name":"response-property"} 1`] = ` "safeName": "Service" } } - } + }, + "inline": null }, "location": { "method": "POST", @@ -17409,7 +17430,8 @@ exports[`ir > {"name":"response-property"} 1`] = ` "safeName": "Service" } } - } + }, + "inline": null }, "location": { "method": "POST", @@ -19184,7 +19206,8 @@ exports[`ir > {"name":"simple","audiences":["internal"]} 1`] = ` "safeName": "Commons" } } - } + }, + "inline": null }, "properties": [ { @@ -19284,7 +19307,8 @@ exports[`ir > {"name":"simple","audiences":["internal"]} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "properties": [ { @@ -19420,7 +19444,8 @@ exports[`ir > {"name":"simple","audiences":["internal"]} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "location": { "method": "POST", @@ -23176,7 +23201,8 @@ exports[`ir > {"name":"simple","audiences":["test"]} 1`] = ` "safeName": "Commons" } } - } + }, + "inline": null }, "properties": [ { @@ -23276,7 +23302,8 @@ exports[`ir > {"name":"simple","audiences":["test"]} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -23347,7 +23374,8 @@ exports[`ir > {"name":"simple","audiences":["test"]} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "properties": [ { @@ -23517,7 +23545,8 @@ exports[`ir > {"name":"simple","audiences":["test"]} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "location": { "method": "POST", @@ -38161,7 +38190,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Commons" } } - } + }, + "inline": null }, "properties": [ { @@ -38261,7 +38291,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Commons" } } - } + }, + "inline": null }, "properties": [ { @@ -38361,7 +38392,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Commons" } } - } + }, + "inline": null }, "types": [ { @@ -38455,7 +38487,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Director" } } - } + }, + "inline": null }, "properties": [ { @@ -38585,7 +38618,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Director" } } - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -38656,7 +38690,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Director" } } - } + }, + "inline": null }, "typeReference": { "type": "literal", @@ -38730,7 +38765,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Director" } } - } + }, + "inline": null }, "typeReference": { "type": "literal", @@ -38804,7 +38840,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -38875,7 +38912,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -38946,7 +38984,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -39017,7 +39056,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "properties": [ { @@ -39177,7 +39217,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "properties": [ { @@ -39310,7 +39351,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "properties": [ { @@ -39410,7 +39452,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "properties": [], "additionalProperties": false @@ -39479,7 +39522,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "discriminant": { "name": { @@ -39681,7 +39725,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "properties": [ { @@ -39780,7 +39825,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "properties": [ { @@ -39983,7 +40029,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "location": { "method": "POST", @@ -40069,7 +40116,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "location": { "method": "POST", @@ -40155,7 +40203,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "location": { "method": "GET", @@ -40225,7 +40274,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "pathParameters": [ { @@ -40370,7 +40420,8 @@ exports[`ir > {"name":"simple"} 1`] = ` "safeName": "Imdb" } } - } + }, + "inline": null }, "location": { "method": "DELETE", @@ -41367,7 +41418,8 @@ exports[`ir > {"name":"streaming"} 1`] = ` "safeName": "Streaming" } } - } + }, + "inline": null }, "location": { "method": "POST", @@ -41447,7 +41499,8 @@ exports[`ir > {"name":"streaming"} 1`] = ` "safeName": "Streaming" } } - } + }, + "inline": null }, "location": { "method": "POST", @@ -41517,7 +41570,8 @@ exports[`ir > {"name":"streaming"} 1`] = ` "safeName": "Streaming" } } - } + }, + "inline": null }, "pathParameters": [], "queryParameters": [], @@ -42814,7 +42868,8 @@ exports[`ir > {"name":"variables"} 1`] = ` "safeName": "Commons" } } - } + }, + "inline": null }, "typeReference": { "type": "primitive", @@ -42888,7 +42943,8 @@ exports[`ir > {"name":"variables"} 1`] = ` "safeName": "Service" } } - } + }, + "inline": null }, "location": { "method": "POST", diff --git a/packages/cli/generation/ir-generator/src/dynamic-snippets/DynamicSnippetsConverter.ts b/packages/cli/generation/ir-generator/src/dynamic-snippets/DynamicSnippetsConverter.ts index 4bb8ef41fa3f..187e67510f58 100644 --- a/packages/cli/generation/ir-generator/src/dynamic-snippets/DynamicSnippetsConverter.ts +++ b/packages/cli/generation/ir-generator/src/dynamic-snippets/DynamicSnippetsConverter.ts @@ -455,7 +455,10 @@ export class DynamicSnippetsConverter { } private convertTypeDeclaration(typeDeclaration: TypeDeclaration): DynamicSnippets.NamedType { - const declaration = this.convertDeclaration(typeDeclaration.name); + const declaration = this.convertDeclaration({ + ...typeDeclaration.name, + inline: typeDeclaration.inline + }); switch (typeDeclaration.shape.type) { case "alias": return this.convertAlias({ declaration, alias: typeDeclaration.shape }); @@ -744,14 +747,17 @@ export class DynamicSnippetsConverter { private convertDeclaration({ name, - fernFilepath + fernFilepath, + inline }: { name: Name; fernFilepath: FernFilepath; + inline?: boolean; }): DynamicSnippets.Declaration { return { name, - fernFilepath + fernFilepath, + inline }; } diff --git a/packages/cli/generation/ir-migrations/src/migrations/v61-to-v60/__test__/__snapshots__/migrateFromV61ToV60.test.ts.snap b/packages/cli/generation/ir-migrations/src/migrations/v61-to-v60/__test__/__snapshots__/migrateFromV61ToV60.test.ts.snap index 9f463bd83082..b51948d07a0a 100644 --- a/packages/cli/generation/ir-migrations/src/migrations/v61-to-v60/__test__/__snapshots__/migrateFromV61ToV60.test.ts.snap +++ b/packages/cli/generation/ir-migrations/src/migrations/v61-to-v60/__test__/__snapshots__/migrateFromV61ToV60.test.ts.snap @@ -103,6 +103,7 @@ exports[`migrateFromV61ToV60 > streaming 1`] = ` }, "packagePath": [], }, + "inline": undefined, "name": { "camelCase": { "safeName": "generate", @@ -241,6 +242,7 @@ exports[`migrateFromV61ToV60 > streaming 1`] = ` }, "packagePath": [], }, + "inline": undefined, "name": { "camelCase": { "safeName": "generateequest", @@ -320,6 +322,7 @@ exports[`migrateFromV61ToV60 > streaming 1`] = ` }, "packagePath": [], }, + "inline": undefined, "name": { "camelCase": { "safeName": "generateStream", @@ -458,6 +461,7 @@ exports[`migrateFromV61ToV60 > streaming 1`] = ` }, "packagePath": [], }, + "inline": undefined, "name": { "camelCase": { "safeName": "generateStreamRequest", @@ -543,6 +547,7 @@ exports[`migrateFromV61ToV60 > streaming 1`] = ` }, "packagePath": [], }, + "inline": undefined, "name": { "camelCase": { "safeName": "streamResponse", diff --git a/packages/commons/test-utils/src/__test__/createSampleIr/snapshots/example-definition-1.ir.json b/packages/commons/test-utils/src/__test__/createSampleIr/snapshots/example-definition-1.ir.json index bd500b184069..119527d85c53 100644 --- a/packages/commons/test-utils/src/__test__/createSampleIr/snapshots/example-definition-1.ir.json +++ b/packages/commons/test-utils/src/__test__/createSampleIr/snapshots/example-definition-1.ir.json @@ -107,6 +107,7 @@ }, "packagePath": [], }, + "inline": undefined, "name": { "camelCase": { "safeName": "order", @@ -368,6 +369,7 @@ }, "packagePath": [], }, + "inline": undefined, "name": { "camelCase": { "safeName": "orderItem", @@ -531,6 +533,7 @@ }, "packagePath": [], }, + "inline": undefined, "name": { "camelCase": { "safeName": "orderStatus", diff --git a/packages/ir-sdk/fern/apis/ir-types-latest/definition/dynamic/declaration.yml b/packages/ir-sdk/fern/apis/ir-types-latest/definition/dynamic/declaration.yml index c577be7a00c0..295459235465 100644 --- a/packages/ir-sdk/fern/apis/ir-types-latest/definition/dynamic/declaration.yml +++ b/packages/ir-sdk/fern/apis/ir-types-latest/definition/dynamic/declaration.yml @@ -5,3 +5,6 @@ types: properties: fernFilepath: commons.FernFilepath name: commons.Name + inline: + docs: Whether this type is an inline type that should be generated as a nested class. + type: optional diff --git a/packages/ir-sdk/src/sdk/api/resources/dynamic/resources/declaration/types/Declaration.ts b/packages/ir-sdk/src/sdk/api/resources/dynamic/resources/declaration/types/Declaration.ts index 80793712ae94..b229ac1182b0 100644 --- a/packages/ir-sdk/src/sdk/api/resources/dynamic/resources/declaration/types/Declaration.ts +++ b/packages/ir-sdk/src/sdk/api/resources/dynamic/resources/declaration/types/Declaration.ts @@ -7,4 +7,6 @@ import * as FernIr from "../../../../../index"; export interface Declaration { fernFilepath: FernIr.dynamic.FernFilepath; name: FernIr.dynamic.Name; + /** Whether this type is an inline type that should be generated as a nested class. */ + inline: boolean | undefined; } diff --git a/packages/ir-sdk/src/sdk/serialization/resources/dynamic/resources/declaration/types/Declaration.ts b/packages/ir-sdk/src/sdk/serialization/resources/dynamic/resources/declaration/types/Declaration.ts index 49537ebe00c0..f444274079cb 100644 --- a/packages/ir-sdk/src/sdk/serialization/resources/dynamic/resources/declaration/types/Declaration.ts +++ b/packages/ir-sdk/src/sdk/serialization/resources/dynamic/resources/declaration/types/Declaration.ts @@ -14,11 +14,13 @@ export const Declaration: core.serialization.ObjectSchema< > = core.serialization.objectWithoutOptionalProperties({ fernFilepath: FernFilepath, name: Name, + inline: core.serialization.boolean().optional(), }); export declare namespace Declaration { export interface Raw { fernFilepath: FernFilepath.Raw; name: Name.Raw; + inline?: boolean | null; } } diff --git a/packages/snippets/core/src/__test__/__snapshots__/generateDynamicIR.test.ts.snap b/packages/snippets/core/src/__test__/__snapshots__/generateDynamicIR.test.ts.snap index c775f0ea2078..f872a72a0b2f 100644 --- a/packages/snippets/core/src/__test__/__snapshots__/generateDynamicIR.test.ts.snap +++ b/packages/snippets/core/src/__test__/__snapshots__/generateDynamicIR.test.ts.snap @@ -11,6 +11,7 @@ exports[`generateDynamicIR > go 1`] = ` "file": undefined, "packagePath": [], }, + "inline": undefined, "name": { "camelCase": { "safeName": "getTestData", @@ -62,6 +63,7 @@ exports[`generateDynamicIR > go 1`] = ` "file": undefined, "packagePath": [], }, + "inline": undefined, "name": { "camelCase": { "safeName": "getTestDataResponse", diff --git a/seed/java-sdk/seed.yml b/seed/java-sdk/seed.yml index fc12f3c005d1..93fdcf327d3b 100644 --- a/seed/java-sdk/seed.yml +++ b/seed/java-sdk/seed.yml @@ -306,7 +306,6 @@ allowedFailures: - exhaustive:publish-to - exhaustive:signed_publish - extends - - java-inline-types:no-wrapped-aliases - nullable-optional:with-nullable-annotation - nullable-optional:collapse-optional-nullable - request-parameters @@ -314,8 +313,6 @@ allowedFailures: # Snippet failures; many of these failures are due to the fact that a # required list of query parameters is not actually required by the builder. - - java-inline-types:inline - - java-inline-types:enable-forward-compatible-enums - nullable:wrapped-aliases - nullable:no-custom-config - pagination-custom