@@ -25,12 +25,8 @@ import {
2525 type UnionStatementNode ,
2626} from "@typespec/compiler/ast" ;
2727import { camelCase , constantCase , pascalCase , split , splitSeparateNumbers } from "change-case" ;
28- import { GraphQLScalarType } from "graphql" ;
29-
30- export const ANY_SCALAR = new GraphQLScalarType ( {
31- name : "Any" ,
32- } ) ;
3328
29+ /** Generate a GraphQL type name for a templated model (e.g., `ListOfString`). */
3430export function getTemplatedModelName ( model : Model ) : string {
3531 const name = getTypeName ( model , { } ) ;
3632 const baseName = toTypeName ( name . replace ( / < [ ^ > ] * > / g, "" ) ) ;
@@ -56,12 +52,14 @@ function splitWithAcronyms(
5652 } ) ;
5753}
5854
55+ /** Convert a name to PascalCase for GraphQL type names. */
5956export function toTypeName ( name : string ) : string {
6057 return pascalCase ( sanitizeNameForGraphQL ( getNameWithoutNamespace ( name ) ) , {
6158 split : splitWithAcronyms . bind ( null , split , false ) ,
6259 } ) ;
6360}
6461
62+ /** Sanitize a name to be a valid GraphQL identifier. */
6563export function sanitizeNameForGraphQL ( name : string , prefix : string = "" ) : string {
6664 name = name . replace ( "[]" , "Array" ) ;
6765 name = name . replaceAll ( / \W / g, "_" ) ;
@@ -71,13 +69,15 @@ export function sanitizeNameForGraphQL(name: string, prefix: string = ""): strin
7169 return name ;
7270}
7371
72+ /** Convert a name to CONSTANT_CASE for GraphQL enum members. */
7473export function toEnumMemberName ( enumName : string , name : string ) {
7574 return constantCase ( sanitizeNameForGraphQL ( name , enumName ) , {
7675 split : splitSeparateNumbers ,
7776 prefixCharacters : "_" ,
7877 } ) ;
7978}
8079
80+ /** Convert a name to camelCase for GraphQL field names. */
8181export function toFieldName ( name : string ) : string {
8282 return camelCase ( sanitizeNameForGraphQL ( name ) , {
8383 prefixCharacters : "_" ,
@@ -90,6 +90,7 @@ function getNameWithoutNamespace(name: string): string {
9090 return parts [ parts . length - 1 ] ;
9191}
9292
93+ /** Generate a GraphQL type name for a union, including anonymous unions. */
9394export function getUnionName ( union : Union , program : Program ) : string {
9495 // SyntaxKind.UnionExpression: Foo | Bar
9596 // SyntaxKind.UnionStatement: union FooBarUnion { Foo, Bar }
@@ -169,33 +170,38 @@ function getUnionNameForOperation(program: Program, union: Union): string {
169170 return toTypeName ( getTypeName ( operation ) ) ;
170171}
171172
173+ /** Convert a namespaced name to a single name by replacing dots with underscores. */
172174export function getSingleNameWithNamespace ( name : string ) : string {
173175 return name . trim ( ) . replace ( / \. / g, "_" ) ;
174176}
175177
176- // TODO: To replace this with the type-utils isArrayModelType function
178+ /**
179+ * Check if a model is an array type.
180+ */
177181export function isArray ( model : Model ) : model is ArrayModelType {
178182 return Boolean ( model . indexer && model . indexer . key . name === "integer" ) ;
179183}
180184
181- // TODO: To replace this with the type-utils isRecordModelType function
182- // The type-utils function takes an used program as an argument
183- // and this function is used in the selector which does not have access to
184- // the program
185+ /**
186+ * Check if a model is a record/map type.
187+ */
185188export function isRecordType ( type : Model ) : type is RecordModelType {
186189 return Boolean ( type . indexer && type . indexer . key . name === "string" ) ;
187190}
188191
192+ /** Check if a model is an array of scalars or enums. */
189193export function isScalarOrEnumArray ( type : Model ) : type is ArrayModelType {
190194 return (
191195 isArray ( type ) && ( type . indexer ?. value . kind === "Scalar" || type . indexer ?. value . kind === "Enum" )
192196 ) ;
193197}
194198
199+ /** Check if a model is an array of unions. */
195200export function isUnionArray ( type : Model ) : type is ArrayModelType {
196201 return isArray ( type ) && type . indexer ?. value . kind === "Union" ;
197202}
198203
204+ /** Extract the element type from an array model, or return the model itself. */
199205export function unwrapModel ( model : ArrayModelType ) : Model | Scalar | Enum | Union ;
200206export function unwrapModel ( model : Exclude < Model , ArrayModelType > ) : Model ;
201207export function unwrapModel ( model : Model ) : Model | Scalar | Enum | Union {
@@ -212,6 +218,7 @@ export function unwrapModel(model: Model): Model | Scalar | Enum | Union {
212218 return model ;
213219}
214220
221+ /** Unwrap array types to get the inner element type. */
215222export function unwrapType ( type : Model ) : Model | Scalar | Enum | Union ;
216223export function unwrapType ( type : Type ) : Type ;
217224export function unwrapType ( type : Type ) : Type {
@@ -221,6 +228,7 @@ export function unwrapType(type: Type): Type {
221228 return type ;
222229}
223230
231+ /** Get the GraphQL description for a type from its doc comments. */
224232export function getGraphQLDoc ( program : Program , type : Type ) : string | undefined {
225233 // GraphQL uses CommonMark for descriptions
226234 // https://spec.graphql.org/October2021/#sec-Descriptions
@@ -239,11 +247,12 @@ ${getTypeName(type)}
239247
240248 if ( doc ) {
241249 doc = doc . trim ( ) ;
242- doc . replaceAll ( "\\n" , "\n" ) ;
250+ doc = doc . replaceAll ( "\\n" , "\n" ) ;
243251 }
244252 return doc ;
245253}
246254
255+ /** Generate a string representation of template arguments (e.g., `StringAndInt`). */
247256export function getTemplateString (
248257 type : Type ,
249258 options : { conjunction : string ; prefix : string } = { conjunction : "And" , prefix : "" } ,
@@ -264,6 +273,7 @@ function getTemplateStringInternal(
264273 : "" ;
265274}
266275
276+ /** Check if a model should be emitted as a GraphQL object type (not an array, record, or never). */
267277export function isTrueModel ( model : Model ) : boolean {
268278 /* eslint-disable no-fallthrough */
269279 switch ( true ) {
0 commit comments