@@ -1601,3 +1601,226 @@ describe('extractAllFieldsToTypes: true', () => {
16011601 await validate ( content ) ;
16021602 } ) ;
16031603} ) ;
1604+
1605+ describe ( 'extractAllFieldsToTypesCompact: true' , ( ) => {
1606+ const validate = async ( content : Types . PluginOutput ) => {
1607+ const m = mergeOutputs ( [ content ] ) ;
1608+ validateTs ( m , undefined , undefined , undefined , [ ] ) ;
1609+
1610+ return m ;
1611+ } ;
1612+
1613+ const companySchema = buildSchema ( /* GraphQL */ `
1614+ type Query {
1615+ company(id: ID!): Company
1616+ }
1617+ type Company {
1618+ id: ID!
1619+ name: String!
1620+ score: Float
1621+ reviewCount: Int
1622+ office: Office
1623+ }
1624+ type Office {
1625+ id: ID!
1626+ location: Location
1627+ }
1628+ type Location {
1629+ formatted: String
1630+ }
1631+ ` ) ;
1632+
1633+ const companyDoc = parse ( /* GraphQL */ `
1634+ query GetCompanyInfo($id: ID!) {
1635+ company(id: $id) {
1636+ id
1637+ name
1638+ score
1639+ reviewCount
1640+ office {
1641+ id
1642+ location {
1643+ formatted
1644+ }
1645+ }
1646+ }
1647+ }
1648+ ` ) ;
1649+
1650+ it ( 'should generate compact type names without GraphQL type names (Apollo Tooling style)' , async ( ) => {
1651+ const config : TypeScriptDocumentsPluginConfig = {
1652+ extractAllFieldsToTypesCompact : true ,
1653+ nonOptionalTypename : true ,
1654+ omitOperationSuffix : true ,
1655+ } ;
1656+ const { content } = await plugin ( companySchema , [ { location : 'test-file.ts' , document : companyDoc } ] , config , {
1657+ outputFile : '' ,
1658+ } ) ;
1659+ expect ( content ) . toMatchInlineSnapshot ( `
1660+ "export type GetCompanyInfo_company_office_location = { __typename: 'Location', formatted: string | null };
1661+
1662+ export type GetCompanyInfo_company_office = { __typename: 'Office', id: string, location: GetCompanyInfo_company_office_location | null };
1663+
1664+ export type GetCompanyInfo_company = { __typename: 'Company', id: string, name: string, score: number | null, reviewCount: number | null, office: GetCompanyInfo_company_office | null };
1665+
1666+ export type GetCompanyInfo = { __typename: 'Query', company: GetCompanyInfo_company | null };
1667+
1668+
1669+ export type GetCompanyInfoVariables = Exact<{
1670+ id: string;
1671+ }>;
1672+ "
1673+ ` ) ;
1674+
1675+ await validate ( content ) ;
1676+ } ) ;
1677+
1678+ it ( 'should work with unions and interfaces in compact mode' , async ( ) => {
1679+ const schema = buildSchema ( /* GraphQL */ `
1680+ type Query {
1681+ animals: [Animal!]!
1682+ }
1683+ interface Animal {
1684+ name: String!
1685+ owner: Person!
1686+ }
1687+ type Cat implements Animal {
1688+ name: String!
1689+ owner: Person!
1690+ }
1691+ type Dog implements Animal {
1692+ name: String!
1693+ owner: Person!
1694+ }
1695+ union Person = Trainer | Veterinarian
1696+ type Trainer {
1697+ name: String!
1698+ }
1699+ type Veterinarian {
1700+ name: String!
1701+ }
1702+ ` ) ;
1703+
1704+ const doc = parse ( /* GraphQL */ `
1705+ query GetAnimals {
1706+ animals {
1707+ name
1708+ owner {
1709+ ... on Trainer {
1710+ name
1711+ }
1712+ ... on Veterinarian {
1713+ name
1714+ }
1715+ }
1716+ }
1717+ }
1718+ ` ) ;
1719+
1720+ const config : TypeScriptDocumentsPluginConfig = {
1721+ extractAllFieldsToTypesCompact : true ,
1722+ nonOptionalTypename : true ,
1723+ omitOperationSuffix : true ,
1724+ } ;
1725+ const { content } = await plugin ( schema , [ { location : 'test-file.ts' , document : doc } ] , config , { outputFile : '' } ) ;
1726+
1727+ // Verify the naming follows Apollo Tooling style (field names only, no intermediate type names)
1728+ expect ( content ) . toContain ( 'GetAnimals_animals_owner_Trainer' ) ;
1729+ expect ( content ) . toContain ( 'GetAnimals_animals_owner_Veterinarian' ) ;
1730+ expect ( content ) . toContain ( 'GetAnimals_animals_owner' ) ;
1731+ expect ( content ) . toContain ( 'GetAnimals_animals_Cat' ) ;
1732+ expect ( content ) . toContain ( 'GetAnimals_animals_Dog' ) ;
1733+ expect ( content ) . toContain ( 'GetAnimals_animals' ) ;
1734+
1735+ // Should NOT contain intermediate type names in the field paths (like Animal between animals and owner)
1736+ expect ( content ) . not . toContain ( 'GetAnimals_animals_Animal_owner' ) ;
1737+
1738+ await validate ( content ) ;
1739+ } ) ;
1740+
1741+ it ( 'should automatically enable extractAllFieldsToTypes when extractAllFieldsToTypesCompact is true' , async ( ) => {
1742+ const config : TypeScriptDocumentsPluginConfig = {
1743+ extractAllFieldsToTypes : false ,
1744+ extractAllFieldsToTypesCompact : true ,
1745+ nonOptionalTypename : true ,
1746+ omitOperationSuffix : true ,
1747+ } ;
1748+ const { content } = await plugin ( companySchema , [ { location : 'test-file.ts' , document : companyDoc } ] , config , {
1749+ outputFile : '' ,
1750+ } ) ;
1751+
1752+ // When extractAllFieldsToTypesCompact is true, extractAllFieldsToTypes should be automatically enabled
1753+ // So types should be extracted, not inlined
1754+ expect ( content ) . toContain ( 'GetCompanyInfo_company_office_location' ) ;
1755+ expect ( content ) . toContain ( 'GetCompanyInfo_company_office' ) ;
1756+ expect ( content ) . toContain ( 'GetCompanyInfo_company' ) ;
1757+ expect ( content ) . toContain ( 'export type GetCompanyInfo' ) ;
1758+
1759+ await validate ( content ) ;
1760+ } ) ;
1761+
1762+ it ( 'should apply compact naming to fragments' , async ( ) => {
1763+ const schema = buildSchema ( /* GraphQL */ `
1764+ type Query {
1765+ user(id: ID!): User
1766+ }
1767+ interface User {
1768+ id: ID!
1769+ profile: Profile
1770+ }
1771+ type AdminUser implements User {
1772+ id: ID!
1773+ profile: Profile
1774+ permissions: [String!]!
1775+ }
1776+ type RegularUser implements User {
1777+ id: ID!
1778+ profile: Profile
1779+ }
1780+ type Profile {
1781+ name: String!
1782+ contact: Contact
1783+ }
1784+ type Contact {
1785+ email: String
1786+ }
1787+ ` ) ;
1788+
1789+ const doc = parse ( /* GraphQL */ `
1790+ fragment UserProfile on User {
1791+ id
1792+ profile {
1793+ name
1794+ contact {
1795+ email
1796+ }
1797+ }
1798+ }
1799+ query GetUser($id: ID!) {
1800+ user(id: $id) {
1801+ ...UserProfile
1802+ ... on AdminUser {
1803+ permissions
1804+ }
1805+ }
1806+ }
1807+ ` ) ;
1808+
1809+ const config : TypeScriptDocumentsPluginConfig = {
1810+ extractAllFieldsToTypesCompact : true ,
1811+ nonOptionalTypename : true ,
1812+ omitOperationSuffix : true ,
1813+ } ;
1814+ const { content } = await plugin ( schema , [ { location : 'test-file.ts' , document : doc } ] , config , { outputFile : '' } ) ;
1815+
1816+ // Fragment types should use compact naming (no intermediate type names)
1817+ expect ( content ) . toContain ( 'UserProfile_profile_contact' ) ;
1818+ expect ( content ) . toContain ( 'UserProfile_profile' ) ;
1819+
1820+ // Should NOT contain type names in fragment paths
1821+ expect ( content ) . not . toContain ( 'UserProfile_profile_Profile_contact' ) ;
1822+ expect ( content ) . not . toContain ( 'UserProfile_profile_Profile_contact_Contact' ) ;
1823+
1824+ await validate ( content ) ;
1825+ } ) ;
1826+ } ) ;
0 commit comments