@@ -5,13 +5,24 @@ import okio.buffer
55import okio.sink
66import java.io.File
77
8- fun IntrospectionSchema.toSDL (file : File ) {
8+ /* *
9+ * Previous versions of this method used to encode defaultValues as Json elements. For an example:
10+ * "defaultValue": [0, 1]
11+ *
12+ * This is wrong. The spec mandates defaultValue to be GraphQL encoded String:
13+ * "defaultValue": "[0, 1]"
14+ *
15+ * For backward compatibility, use [legacyDefaultValues] = true
16+ */
17+ fun IntrospectionSchema.toSDL (file : File , legacyDefaultValues : Boolean ) {
918 file.sink().buffer().use {
10- toSDL(it)
19+ toSDL(it, legacyDefaultValues )
1120 }
1221}
1322
14- fun IntrospectionSchema.toSDL (sink : BufferedSink ) {
23+ fun IntrospectionSchema.toSDL (file : File ) = toSDL(file, true )
24+
25+ fun IntrospectionSchema.toSDL (sink : BufferedSink , legacyDefaultValues : Boolean ) {
1526 val builtinsTypes = setOf (
1627 " Int" , " Float" , " String" , " Boolean" , " ID" ,
1728 " __Directive" , " __DirectiveLocation" , " __EnumValue" , " __Field" , " __InputValue" , " __Schema" , " __Type" , " __TypeKind"
@@ -25,9 +36,9 @@ fun IntrospectionSchema.toSDL(sink: BufferedSink) {
2536 when (it) {
2637 is IntrospectionSchema .Type .Scalar -> it.toSDL(sink)
2738 is IntrospectionSchema .Type .Enum -> it.toSDL(sink)
28- is IntrospectionSchema .Type .InputObject -> it.toSDL(sink)
29- is IntrospectionSchema .Type .Interface -> it.toSDL(sink)
30- is IntrospectionSchema .Type .Object -> it.toSDL(sink, allInterfaces)
39+ is IntrospectionSchema .Type .InputObject -> it.toSDL(sink, legacyDefaultValues )
40+ is IntrospectionSchema .Type .Interface -> it.toSDL(sink, legacyDefaultValues )
41+ is IntrospectionSchema .Type .Object -> it.toSDL(sink, allInterfaces, legacyDefaultValues )
3142 is IntrospectionSchema .Type .Union -> it.toSDL(sink)
3243 }
3344 // Add a newline as a separation
@@ -40,6 +51,8 @@ fun IntrospectionSchema.toSDL(sink: BufferedSink) {
4051 sink.writeUtf8(" }\n " )
4152}
4253
54+ fun IntrospectionSchema.toSDL (sink : BufferedSink ) = toSDL(sink, true )
55+
4356private fun BufferedSink.writeDescription (description : String? , indent : String = "") {
4457 if (! description.isNullOrBlank()) {
4558 writeUtf8(
@@ -86,11 +99,11 @@ private fun IntrospectionSchema.Type.Enum.Value.toSDL(sink: BufferedSink) {
8699 sink.writeDeprecatedDirective(isDeprecated, deprecationReason)
87100}
88101
89- private fun IntrospectionSchema.Type.InputObject.toSDL (sink : BufferedSink ) {
102+ private fun IntrospectionSchema.Type.InputObject.toSDL (sink : BufferedSink , legacyDefaultValues : Boolean ) {
90103 sink.writeDescription(description)
91104 sink.writeUtf8(" input $name {\n " )
92105 inputFields.forEach {
93- it.toSDL(sink)
106+ it.toSDL(sink, legacyDefaultValues )
94107 sink.writeUtf8(" \n " )
95108 }
96109 sink.writeUtf8(" }\n " )
@@ -132,33 +145,40 @@ private fun BufferedSink.writeValue(value: Any?) {
132145 }
133146}
134147
135- private fun IntrospectionSchema.InputField.toSDL (sink : BufferedSink ) {
148+ private fun IntrospectionSchema.InputField.toSDL (sink : BufferedSink , legacyDefaultValues : Boolean ) {
136149 sink.writeDescription(description, " " )
137150 sink.writeUtf8(" $name : ${type.asGraphQLType()} " )
138151 if (defaultValue != null ) {
139152 sink.writeUtf8(" = " )
140- sink.writeValue(defaultValue)
153+ if (! legacyDefaultValues && defaultValue is String ) {
154+ // defaultValue is already encoded as GraphQL, we can pass it verbatim
155+ sink.writeUtf8(defaultValue)
156+ } else {
157+ // legacy mode if we bump into an introspection schema that doesn't encode the default value
158+ sink.writeValue(defaultValue)
159+ }
160+
141161 }
142162 sink.writeDeprecatedDirective(isDeprecated, deprecationReason)
143163}
144164
145- private fun IntrospectionSchema.Type.Interface.toSDL (sink : BufferedSink ) {
165+ private fun IntrospectionSchema.Type.Interface.toSDL (sink : BufferedSink , legacyDefaultValue : Boolean ) {
146166 sink.writeDescription(description)
147167 sink.writeUtf8(" interface $name {\n " )
148168 fields?.forEach {
149- it.toSDL(sink)
169+ it.toSDL(sink, legacyDefaultValue )
150170 sink.writeUtf8(" \n " )
151171 }
152172 sink.writeUtf8(" }\n " )
153173}
154174
155- private fun IntrospectionSchema.Field.toSDL (sink : BufferedSink ) {
175+ private fun IntrospectionSchema.Field.toSDL (sink : BufferedSink , legacyDefaultValue : Boolean ) {
156176 sink.writeDescription(description, " " )
157177 sink.writeUtf8(" $name " )
158178 if (args.isNotEmpty()) {
159179 sink.writeUtf8(" (" )
160180 args.forEachIndexed { index, arg ->
161- arg.toSDL(sink)
181+ arg.toSDL(sink, legacyDefaultValue )
162182 if (index != args.size - 1 ) {
163183 sink.writeUtf8(" , " )
164184 }
@@ -169,20 +189,26 @@ private fun IntrospectionSchema.Field.toSDL(sink: BufferedSink) {
169189 sink.writeDeprecatedDirective(isDeprecated, deprecationReason)
170190}
171191
172- private fun IntrospectionSchema.Field.Argument.toSDL (sink : BufferedSink ) {
192+ private fun IntrospectionSchema.Field.Argument.toSDL (sink : BufferedSink , legacyDefaultValue : Boolean ) {
173193 if (! description.isNullOrBlank()) {
174194 // Write the description inline
175195 sink.writeUtf8(" \"\"\" $description \"\"\" " )
176196 }
177197 sink.writeUtf8(" $name : ${type.asGraphQLType()} " )
178198 if (defaultValue != null ) {
179199 sink.writeUtf8(" = " )
180- sink.writeValue(defaultValue)
200+ if (! legacyDefaultValue && defaultValue is String ) {
201+ // defaultValue is already encoded as GraphQL, we can pass it verbatim
202+ sink.writeUtf8(defaultValue)
203+ } else {
204+ // legacy mode if we bump into an introspection schema that doesn't encode the default value
205+ sink.writeValue(defaultValue)
206+ }
181207 }
182208 sink.writeDeprecatedDirective(isDeprecated, deprecationReason)
183209}
184210
185- private fun IntrospectionSchema.Type.Object.toSDL (sink : BufferedSink , interfaces : List <IntrospectionSchema .Type .Interface >) {
211+ private fun IntrospectionSchema.Type.Object.toSDL (sink : BufferedSink , interfaces : List <IntrospectionSchema .Type .Interface >, legacyDefaultValue : Boolean ) {
186212 sink.writeDescription(description, " " )
187213 sink.writeUtf8(" type $name " )
188214 val implements = interfaces.filter {
@@ -203,7 +229,7 @@ private fun IntrospectionSchema.Type.Object.toSDL(sink: BufferedSink, interfaces
203229 sink.writeUtf8(" {\n " )
204230
205231 fields?.forEach {
206- it.toSDL(sink)
232+ it.toSDL(sink, legacyDefaultValue )
207233 sink.writeUtf8(" \n " )
208234 }
209235
0 commit comments