Repository: graphql/graphql-js
Pull request #3566 (2022-05-10 10:50:45)

validateSchema: unify check of root types

netlify[bot]: ### <span aria-hidden="true">👷</span> Deploy Preview for *compassionate-pike-271cb3* processing.


|  Name | Link |
|---------------------------------|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 94ec0820a1e11abc0f6a2937bcde47afdc1259b1 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/compassionate-pike-271cb3/deploys/627a4386797d0e00085d43e0 |
github-actions[bot]: Hi @IvanGoncharov, I'm @github-actions bot happy to help you with this PR 👋

<details>
<summary> Supported commands </summary>

Please post this commands in separate comments and only one per comment:
* `@github-actions run-benchmark` - Run benchmark comparing base and merge commits for this PR
* `@github-actions publish-pr-on-npm` - Build package from this PR and publish it on NPM
</details>


Patch:
diff --git a/src/jsutils/capitalize.ts b/src/jsutils/capitalize.ts
new file mode 100644
index 00000000..064dddcf
--- /dev/null
+++ b/src/jsutils/capitalize.ts
@@ -0,0 +1,6 @@
+/**
+ * Converts the first character of string to upper case and the remaining to lower case.
+ */
+export function capitalize(str: string): string {
+  return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
+}
diff --git a/src/type/validate.ts b/src/type/validate.ts
index 126e97d9..9ce66543 100644
--- a/src/type/validate.ts
+++ b/src/type/validate.ts
@@ -1,3 +1,4 @@
+import { capitalize } from '../jsutils/capitalize';
 import { inspect } from '../jsutils/inspect';
 import type { Maybe } from '../jsutils/Maybe';
 
@@ -112,37 +113,25 @@ class SchemaValidationContext {
 
 function validateRootTypes(context: SchemaValidationContext): void {
   const schema = context.schema;
-  const queryType = schema.getQueryType();
-  if (!queryType) {
+
+  if (schema.getQueryType() == null) {
     context.reportError('Query root type must be provided.', schema.astNode);
-  } else if (!isObjectType(queryType)) {
-    context.reportError(
-      `Query root type must be Object type, it cannot be ${inspect(
-        queryType,
-      )}.`,
-      getOperationTypeNode(schema, OperationTypeNode.QUERY) ??
-        (queryType as any).astNode,
-    );
   }
 
-  const mutationType = schema.getMutationType();
-  if (mutationType && !isObjectType(mutationType)) {
-    context.reportError(
-      'Mutation root type must be Object type if provided, it cannot be ' +
-        `${inspect(mutationType)}.`,
-      getOperationTypeNode(schema, OperationTypeNode.MUTATION) ??
-        (mutationType as any).astNode,
-    );
-  }
+  for (const operationType of Object.values(OperationTypeNode)) {
+    const rootType = schema.getRootType(operationType);
 
-  const subscriptionType = schema.getSubscriptionType();
-  if (subscriptionType && !isObjectType(subscriptionType)) {
-    context.reportError(
-      'Subscription root type must be Object type if provided, it cannot be ' +
-        `${inspect(subscriptionType)}.`,
-      getOperationTypeNode(schema, OperationTypeNode.SUBSCRIPTION) ??
-        (subscriptionType as any).astNode,
-    );
+    if (rootType != null && !isObjectType(rootType)) {
+      const operationTypeStr = capitalize(operationType);
+      const rootTypeStr = inspect(rootType);
+      context.reportError(
+        operationType === OperationTypeNode.QUERY
+          ? `${operationTypeStr} root type must be Object type, it cannot be ${rootTypeStr}.`
+          : `${operationTypeStr} root type must be Object type if provided, it cannot be ${rootTypeStr}.`,
+        getOperationTypeNode(schema, operationType) ??
+          (rootType as any).astNode,
+      );
+    }
   }
 }
 


Test patch:
diff --git a/src/jsutils/__tests__/capitalize-test.ts b/src/jsutils/__tests__/capitalize-test.ts
new file mode 100644
index 00000000..48ae886c
--- /dev/null
+++ b/src/jsutils/__tests__/capitalize-test.ts
@@ -0,0 +1,21 @@
+import { expect } from 'chai';
+import { describe, it } from 'mocha';
+
+import { capitalize } from '../capitalize';
+
+describe('capitalize', () => {
+  it('Converts the first character of string to upper case and the remaining to lower case', () => {
+    expect(capitalize('')).to.equal('');
+
+    expect(capitalize('a')).to.equal('A');
+    expect(capitalize('A')).to.equal('A');
+
+    expect(capitalize('ab')).to.equal('Ab');
+    expect(capitalize('aB')).to.equal('Ab');
+    expect(capitalize('Ab')).to.equal('Ab');
+    expect(capitalize('AB')).to.equal('Ab');
+
+    expect(capitalize('platypus')).to.equal('Platypus');
+    expect(capitalize('PLATYPUS')).to.equal('Platypus');
+  });
+});