@@ -1842,4 +1842,217 @@ describe('extractAllFieldsToTypesCompact: true', () => {
18421842
18431843 await validate ( content ) ;
18441844 } ) ;
1845+
1846+ it ( 'should not separate conditional inline fragments when extractAllFieldsToTypesCompact is enabled' , async ( ) => {
1847+ // Regression: with extractAllFieldsToTypesCompact, @skip/@include inline fragments were pushed into
1848+ // selectionNodesByTypeNameConditional, causing duplicate type declarations (a syntax error).
1849+ const schema = buildSchema ( /* GraphQL */ `
1850+ type Query {
1851+ user: User
1852+ }
1853+ type User {
1854+ id: ID!
1855+ name: String!
1856+ age: Int!
1857+ }
1858+ ` ) ;
1859+
1860+ const doc = parse ( /* GraphQL */ `
1861+ query GetUser($showAge: Boolean!) {
1862+ user {
1863+ id
1864+ name
1865+ ... on User @include(if: $showAge) {
1866+ age
1867+ }
1868+ }
1869+ }
1870+ ` ) ;
1871+
1872+ const config : TypeScriptDocumentsPluginConfig = {
1873+ extractAllFieldsToTypesCompact : true ,
1874+ omitOperationSuffix : true ,
1875+ } ;
1876+
1877+ const { content } = await plugin (
1878+ schema ,
1879+ [ { location : 'test-file.ts' , document : doc } ] ,
1880+ config ,
1881+ {
1882+ outputFile : '' ,
1883+ } ,
1884+ ) ;
1885+
1886+ // Should produce valid TypeScript — no duplicate type declarations
1887+ await validate ( content ) ;
1888+
1889+ // The conditional inline fragment fields should be merged into a single flat type, not split out
1890+ expect ( content ) . toContain ( 'GetUser_user' ) ;
1891+
1892+ // Should NOT produce duplicate export type declarations for the same name
1893+ const duplicateRegex = / e x p o r t t y p e G e t U s e r _ u s e r / g;
1894+ const matches = content . match ( duplicateRegex ) ;
1895+ expect ( matches ) . toHaveLength ( 1 ) ;
1896+ } ) ;
1897+
1898+ it ( 'should not separate conditional fragment spreads when extractAllFieldsToTypesCompact is enabled' , async ( ) => {
1899+ // Regression: conditional fragment spreads (@skip/@include) were pushed into
1900+ // selectionNodesByTypeNameConditional, causing missing/duplicate type declarations.
1901+ const schema = buildSchema ( /* GraphQL */ `
1902+ type Query {
1903+ user: User
1904+ }
1905+ type User {
1906+ id: ID!
1907+ name: String!
1908+ age: Int!
1909+ }
1910+ ` ) ;
1911+
1912+ const doc = parse ( /* GraphQL */ `
1913+ fragment UserAge on User {
1914+ age
1915+ }
1916+
1917+ query GetUser($showAge: Boolean!) {
1918+ user {
1919+ id
1920+ name
1921+ ...UserAge @include(if: $showAge)
1922+ }
1923+ }
1924+ ` ) ;
1925+
1926+ const config : TypeScriptDocumentsPluginConfig = {
1927+ extractAllFieldsToTypesCompact : true ,
1928+ omitOperationSuffix : true ,
1929+ } ;
1930+
1931+ const { content } = await plugin (
1932+ schema ,
1933+ [ { location : 'test-file.ts' , document : doc } ] ,
1934+ config ,
1935+ {
1936+ outputFile : '' ,
1937+ } ,
1938+ ) ;
1939+
1940+ // Should produce valid TypeScript — no duplicate type declarations
1941+ await validate ( content ) ;
1942+
1943+ // The user type should be present
1944+ expect ( content ) . toContain ( 'GetUser_user' ) ;
1945+
1946+ // Should NOT produce duplicate export type declarations for the same name
1947+ const duplicateRegex = / e x p o r t t y p e G e t U s e r _ u s e r / g;
1948+ const matches = content . match ( duplicateRegex ) ;
1949+ expect ( matches ) . toHaveLength ( 1 ) ;
1950+ } ) ;
1951+
1952+ it ( 'should merge all fields into a single flat type with both conditional and unconditional selections' , async ( ) => {
1953+ const schema = buildSchema ( /* GraphQL */ `
1954+ type Query {
1955+ product: Product
1956+ }
1957+ type Product {
1958+ id: ID!
1959+ title: String!
1960+ price: Float!
1961+ discount: Float
1962+ }
1963+ ` ) ;
1964+
1965+ const doc = parse ( /* GraphQL */ `
1966+ query GetProduct($showPrice: Boolean!) {
1967+ product {
1968+ id
1969+ title
1970+ ... on Product @include(if: $showPrice) {
1971+ price
1972+ discount
1973+ }
1974+ }
1975+ }
1976+ ` ) ;
1977+
1978+ const config : TypeScriptDocumentsPluginConfig = {
1979+ extractAllFieldsToTypesCompact : true ,
1980+ omitOperationSuffix : true ,
1981+ } ;
1982+
1983+ const { content } = await plugin (
1984+ schema ,
1985+ [ { location : 'test-file.ts' , document : doc } ] ,
1986+ config ,
1987+ {
1988+ outputFile : '' ,
1989+ } ,
1990+ ) ;
1991+
1992+ await validate ( content ) ;
1993+
1994+ // All fields (including those from conditional inline fragment) should be in the same type
1995+ expect ( content ) . toContain ( 'id' ) ;
1996+ expect ( content ) . toContain ( 'title' ) ;
1997+ expect ( content ) . toContain ( 'price' ) ;
1998+ expect ( content ) . toContain ( 'discount' ) ;
1999+
2000+ // Only one type declaration for GetProduct_product
2001+ const duplicateRegex = / e x p o r t t y p e G e t P r o d u c t _ p r o d u c t / g;
2002+ expect ( content . match ( duplicateRegex ) ) . toHaveLength ( 1 ) ;
2003+ } ) ;
2004+
2005+ it ( 'should handle nested fragment spreads with conditional directives without missing fields' , async ( ) => {
2006+ // Regression: nested conditional fragment spreads did not propagate transitively,
2007+ // causing missing fields in generated types.
2008+ const schema = buildSchema ( /* GraphQL */ `
2009+ type Query {
2010+ order: Order
2011+ }
2012+ type Order {
2013+ id: ID!
2014+ total: Float!
2015+ status: String!
2016+ }
2017+ ` ) ;
2018+
2019+ const doc = parse ( /* GraphQL */ `
2020+ fragment OrderStatus on Order {
2021+ status
2022+ }
2023+
2024+ fragment OrderDetails on Order {
2025+ total
2026+ ...OrderStatus @skip(if: false)
2027+ }
2028+
2029+ query GetOrder {
2030+ order {
2031+ id
2032+ ...OrderDetails
2033+ }
2034+ }
2035+ ` ) ;
2036+
2037+ const config : TypeScriptDocumentsPluginConfig = {
2038+ extractAllFieldsToTypesCompact : true ,
2039+ omitOperationSuffix : true ,
2040+ } ;
2041+
2042+ const { content } = await plugin (
2043+ schema ,
2044+ [ { location : 'test-file.ts' , document : doc } ] ,
2045+ config ,
2046+ {
2047+ outputFile : '' ,
2048+ } ,
2049+ ) ;
2050+
2051+ await validate ( content ) ;
2052+
2053+ // Should not produce duplicate type declarations
2054+ const duplicateRegex = / e x p o r t t y p e G e t O r d e r _ o r d e r / g;
2055+ const matches = content . match ( duplicateRegex ) ;
2056+ expect ( matches ) . toHaveLength ( 1 ) ;
2057+ } ) ;
18452058} ) ;
0 commit comments