import { schemaPolicyApiRouter } from '../src/api';

describe('policy checks', () => {
  it('should return a known list of rules', async () => {
    const result = await schemaPolicyApiRouter
      .createCaller({ req: { log: console } as any })
      .availableRules();

    expect(Object.keys(result).length).toBe(22);
  });

  it('should return empty result where there are not lint rules', async () => {
    const result = await schemaPolicyApiRouter
      .createCaller({ req: { log: console } as any })
      .checkPolicy({
        source: 'type Query { foo: String }',
        schema: 'type Query { foo: String }',
        target: '1',
        policy: {},
      });

    expect(result.length).toBe(0);
  });

  it('should return errors correctly', async () => {
    const result = await schemaPolicyApiRouter
      .createCaller({ req: { log: console } as any })
      .checkPolicy({
        source: 'type Query { foo: String! }',
        schema: 'type Query { foo: String! }',
        target: '1',
        policy: {
          'require-nullable-result-in-root': ['error'],
        },
      });

    expect(result.length).toBe(1);
    expect(result).toMatchInlineSnapshot(`
      [
        {
          column: 19,
          endColumn: 25,
          endLine: 1,
          line: 1,
          message: Unexpected non-null result String in type "Query",
          messageId: require-nullable-result-in-root,
          nodeType: NonNullType,
          ruleId: require-nullable-result-in-root,
          severity: 2,
          suggestions: [
            {
              desc: Make String nullable,
              fix: {
                range: [
                  18,
                  25,
                ],
                text: String,
              },
            },
          ],
        },
      ]
    `);
  });

  it('should return warnings correctly', async () => {
    const result = await schemaPolicyApiRouter
      .createCaller({ req: { log: console } as any })
      .checkPolicy({
        source: 'type Query { foo: String }',
        schema: 'type Query { foo: String }',
        target: '1',
        policy: {
          'require-description': ['warn', { types: true, FieldDefinition: true }],
        },
      });

    expect(result.length).toBe(2);
    expect(result).toMatchInlineSnapshot(`
      [
        {
          column: 6,
          endColumn: 11,
          endLine: 1,
          line: 1,
          message: Description is required for type "Query",
          messageId: require-description,
          nodeType: null,
          ruleId: require-description,
          severity: 1,
        },
        {
          column: 14,
          endColumn: 17,
          endLine: 1,
          line: 1,
          message: Description is required for field "foo" in type "Query",
          messageId: require-description,
          nodeType: null,
          ruleId: require-description,
          severity: 1,
        },
      ]
    `);
  });

  it('refreshes edge types per run', async () => {
    const caller = schemaPolicyApiRouter.createCaller({ req: { log: console } as any });
    const userSchema = `
      type Query {
        # 'first' limits results; 'after' is the cursor to start from
        users(first: Int, after: String): UserConnection!
      }

      type UserConnection {
        edges: [UserEdge!]!
        pageInfo: PageInfo!
        totalCount: Int!
      }

      type UserEdge {
        node: User!
        cursor: String!
      }

      type PageInfo {
        hasNextPage: Boolean!
        endCursor: String
      }

      interface Node {
        id: ID!
      }

      type User {
        id: ID!
        name: String!
      }
    `;
    const result = await caller.checkPolicy({
      source: userSchema,
      schema: userSchema,
      target: '1',
      policy: {
        'relay-edge-types': [
          2,
          {
            withEdgeSuffix: true,
            shouldImplementNode: true,
            listTypeCanWrapOnlyEdgeType: false,
          },
        ],
      },
    });

    expect(result.length).toBe(1);
    expect(result[0].message).toBe("Edge type's field \`node\` must implement \`Node\` interface.");

    const noUserSchema = `
      type Query {
        # 'first' limits results; 'after' is the cursor to start from
        noUsers(first: Int, after: String): NoUserConnection!
      }

      type NoUserConnection {
        edges: [NoUserEdge!]!
        pageInfo: PageInfo!
        totalCount: Int!
      }

      type NoUserEdge {
        node: NoUser!
        cursor: String!
      }

      type PageInfo {
        hasNextPage: Boolean!
        endCursor: String
      }

      interface Node {
        id: ID!
      }

      type NoUser {
        id: ID!
        name: String!
      }
    `;
    const noUserResult = await caller.checkPolicy({
      source: noUserSchema,
      schema: noUserSchema,
      target: '1',
      policy: {
        'relay-edge-types': [
          2,
          {
            withEdgeSuffix: true,
            shouldImplementNode: true,
            listTypeCanWrapOnlyEdgeType: false,
          },
        ],
      },
    });

    expect(noUserResult.length).toBe(1);
    expect(noUserResult[0].message).toBe(
      "Edge type's field \`node\` must implement \`Node\` interface.",
    );
  });

  it('should support type extensions', async () => {
    const result = await schemaPolicyApiRouter
      .createCaller({ req: { log: console } as any })
      .checkPolicy({
        source: `type Query extend type Query { foo: Foo } type Foo { id: ID! }`,
        schema: `type Query extend type Query { foo: Foo } type Foo { id: ID! }`,
        target: '1',
        policy: {
          'no-unreachable-types': [2],
        },
      });
    expect(result).toHaveLength(0);
  });

  /** To ensure existing policies dont break during upgrades */
  it.each(policies)('should support existing policies', async policy => {
    await expect(
      schemaPolicyApiRouter.createCaller({ req: { log: console } as any }).checkPolicy({
        source: 'type Query { foo: String }',
        schema: 'type Query { foo: String }',
        target: '1',
        policy,
      }),
    ).resolves.toBeDefined();
  });
});

/**
 * A list of policies representing existing rule options that we must support.
 * This includes different error levels, config options, and rule sets to capture
 * different interactions.
 */
const policies = [
  {
    'relay-edge-types': [
      2,
      {
        withEdgeSuffix: true,
        shouldImplementNode: true,
        listTypeCanWrapOnlyEdgeType: false,
      },
    ],
    'naming-convention': [
      2,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: 'UPPER_CASE',
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'Argument[type.type=InputObjectTypeDefinition]': {
          style: 'PascalCase',
          suffix: 'Args',
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'strict-id-in-types': [
      1,
      {
        exceptions: {
          suffixes: ['PageInfo', 'Edge', 'Connection', 'Nested', 'Error', 'Payload'],
        },
        acceptedIdNames: ['id'],
        acceptedIdTypes: ['ID'],
      },
    ],
    'require-description': [
      2,
      {
        types: true,
        rootField: false,
        FieldDefinition: true,
        EnumTypeDefinition: true,
        DirectiveDefinition: true,
        EnumValueDefinition: false,
        UnionTypeDefinition: true,
        InputValueDefinition: false,
        ObjectTypeDefinition: true,
        ScalarTypeDefinition: true,
        InterfaceTypeDefinition: true,
        InputObjectTypeDefinition: true,
      },
    ],
    'relay-connection-types': [2],
    'require-deprecation-date': [1, { argumentName: 'deleteBy' }],
    'require-deprecation-reason': [2],
  },
  {
    'naming-convention': [
      1,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: 'UPPER_CASE',
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
  },
  {
    'input-name': [
      1,
      {
        checkQueries: false,
        checkInputType: true,
        checkMutations: true,
        caseSensitiveInputType: true,
      },
    ],
    'relay-edge-types': [
      1,
      {
        withEdgeSuffix: true,
        shouldImplementNode: false,
        listTypeCanWrapOnlyEdgeType: true,
      },
    ],
    'naming-convention': [
      1,
      {
        types: { style: 'PascalCase', forbiddenSuffixes: ['Failure'] },
        Argument: {
          style: 'camelCase',
          forbiddenPrefixes: ['userUuid'],
          forbiddenSuffixes: ['UserId', 'userUuid'],
        },
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: {
          style: 'UPPER_CASE',
          ignorePattern: '^federation_',
        },
        InputValueDefinition: {
          style: 'camelCase',
          forbiddenSuffixes: ['UserId'],
        },
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['post', 'put', 'mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription', 'subscribe'],
          forbiddenSuffixes: ['Subscription'],
        },
        'FieldDefinition[parent.name.value=/.*(Error|Exception)/]': {
          forbiddenPrefixes: ['message'],
          forbiddenSuffixes: ['Message'],
        },
      },
    ],
    'strict-id-in-types': [
      1,
      {
        exceptions: {
          types: [
            'MonetaryAmount',
            'PageInfo',
            'MarketReturn',
            'InvestmentCategory',
            'SecurityHeadline',
            'ETFPrice',
            'StatementLink',
            'Eligibility',
            'Image',
            'StringKeyAsset',
          ],
          suffixes: ['CurrencyAmount', 'Error', 'Exception', 'Failure'],
        },
        acceptedIdNames: ['id'],
        acceptedIdTypes: ['ID'],
      },
    ],
    'require-nullable-fields-with-oneof': [2],
  },
  {
    'input-name': [
      2,
      {
        checkQueries: false,
        checkInputType: true,
        checkMutations: true,
        caseSensitiveInputType: false,
      },
    ],
    alphabetize: [1, { values: ['EnumTypeDefinition'], definitions: false }],
    'relay-edge-types': [
      1,
      {
        withEdgeSuffix: true,
        shouldImplementNode: false,
        listTypeCanWrapOnlyEdgeType: true,
      },
    ],
    'naming-convention': [
      1,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: 'UPPER_CASE',
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'no-scalar-result-type-on-mutation': [2],
  },
  {
    'input-name': [
      2,
      {
        checkQueries: false,
        checkInputType: true,
        checkMutations: false,
        caseSensitiveInputType: false,
      },
    ],
    'require-description': [
      1,
      {
        types: true,
        DirectiveDefinition: true,
        ScalarTypeDefinition: true,
        InterfaceTypeDefinition: true,
      },
    ],
    'require-nullable-fields-with-oneof': [2],
  },
  {
    'input-name': [
      1,
      {
        checkQueries: false,
        checkInputType: true,
        checkMutations: true,
        caseSensitiveInputType: false,
      },
    ],
    'naming-convention': [
      1,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: 'UPPER_CASE',
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'require-deprecation-date': [1],
    'no-case-insensitive-enum-values-duplicates': [1],
  },
  {
    'input-name': [
      2,
      {
        checkQueries: false,
        checkInputType: false,
        checkMutations: true,
        caseSensitiveInputType: true,
      },
    ],
    alphabetize: [1, { definitions: false }],
    'naming-convention': [
      2,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: 'UPPER_CASE',
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
  },
  {},
  {
    'require-deprecation-date': [1, { argumentName: 'deletionDate' }],
    'no-case-insensitive-enum-values-duplicates': [1],
  },
  {
    alphabetize: [
      1,
      {
        fields: ['ObjectTypeDefinition'],
        values: ['EnumTypeDefinition'],
        arguments: ['FieldDefinition'],
        definitions: false,
      },
    ],
  },
  {
    'strict-id-in-types': [1, { acceptedIdNames: ['id'], acceptedIdTypes: ['ID'] }],
  },
  {
    'naming-convention': [
      1,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: 'UPPER_CASE',
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'strict-id-in-types': [1, { acceptedIdNames: ['id'], acceptedIdTypes: ['ID'] }],
    'require-description': [1, { types: true, rootField: true, DirectiveDefinition: true }],
    'no-unreachable-types': [1],
    'no-case-insensitive-enum-values-duplicates': [1],
  },
  {
    'relay-arguments': [1, { includeBoth: true }],
    'relay-edge-types': [
      1,
      {
        withEdgeSuffix: true,
        shouldImplementNode: true,
        listTypeCanWrapOnlyEdgeType: false,
      },
    ],
    'require-deprecation-date': [1],
    'no-case-insensitive-enum-values-duplicates': [1],
  },
  {
    'input-name': [
      2,
      {
        checkQueries: false,
        checkInputType: true,
        checkMutations: false,
        caseSensitiveInputType: false,
      },
    ],
    alphabetize: [1, { values: ['EnumTypeDefinition'], definitions: false }],
    'relay-arguments': [2, { includeBoth: false }],
    'relay-edge-types': [
      2,
      {
        withEdgeSuffix: false,
        shouldImplementNode: false,
        listTypeCanWrapOnlyEdgeType: false,
      },
    ],
    'description-style': [2, { style: 'block' }],
    'naming-convention': [
      2,
      {
        types: {
          style: 'PascalCase',
          forbiddenPrefixes: ['Type', 'type'],
          forbiddenSuffixes: ['Type', 'type'],
        },
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        EnumTypeDefinition: {
          forbiddenPrefixes: ['enum', 'Enum'],
          forbiddenSuffixes: ['enum', 'Enum'],
        },
        FragmentDefinition: {
          style: 'PascalCase',
          forbiddenPrefixes: ['Fragment'],
          forbiddenSuffixes: ['Fragment'],
        },
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: 'UPPER_CASE',
        UnionTypeDefinition: {
          style: 'PascalCase',
          forbiddenPrefixes: ['union', 'Union'],
          forbiddenSuffixes: ['union', 'Union'],
        },
        InputValueDefinition: 'camelCase',
        ObjectTypeDefinition: {
          forbiddenPrefixes: ['Type'],
          forbiddenSuffixes: ['Type'],
        },
        InterfaceTypeDefinition: {
          style: 'PascalCase',
          forbiddenPrefixes: ['interface', 'Interface'],
          forbiddenSuffixes: ['interface', 'Interface'],
        },
        InputObjectTypeDefinition: 'PascalCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get', 'list'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          requiredPrefixes: ['create', 'update', 'delete', 'terminate', 'add', 'remove'],
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'relay-connection-types': [2],
    'require-deprecation-reason': [2],
  },
  {
    'input-name': [
      1,
      {
        checkQueries: true,
        checkInputType: true,
        checkMutations: true,
        caseSensitiveInputType: true,
      },
    ],
    alphabetize: [
      1,
      {
        fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
        values: ['EnumTypeDefinition'],
        arguments: ['FieldDefinition', 'Field', 'DirectiveDefinition', 'Directive'],
        definitions: false,
      },
    ],
    'no-root-type': [1, { disallow: ['mutation', 'subscription'] }],
    'relay-arguments': [1, { includeBoth: true }],
    'description-style': [1, { style: 'inline' }],
    'naming-convention': [
      1,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: 'UPPER_CASE',
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'strict-id-in-types': [1, { acceptedIdNames: ['id'], acceptedIdTypes: ['ID'] }],
    'require-description': [
      2,
      {
        types: true,
        rootField: true,
        FieldDefinition: true,
        EnumTypeDefinition: true,
        DirectiveDefinition: true,
        EnumValueDefinition: true,
        OperationDefinition: true,
        UnionTypeDefinition: true,
        InputValueDefinition: true,
        ObjectTypeDefinition: true,
        ScalarTypeDefinition: true,
        InterfaceTypeDefinition: true,
        InputObjectTypeDefinition: true,
      },
    ],
    'no-unreachable-types': [1],
    'require-deprecation-date': [1],
    'require-type-pattern-with-oneof': [1],
    'require-nullable-fields-with-oneof': [1],
    'no-case-insensitive-enum-values-duplicates': [1],
    'require-field-of-type-query-in-mutation-result': [1],
  },
  {
    'input-name': [
      2,
      {
        checkQueries: false,
        checkInputType: true,
        checkMutations: false,
        caseSensitiveInputType: true,
      },
    ],
    alphabetize: [
      1,
      {
        fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
        values: ['EnumTypeDefinition'],
        arguments: ['FieldDefinition', 'Field', 'DirectiveDefinition'],
        definitions: true,
      },
    ],
    'relay-arguments': [2, { includeBoth: true }],
    'relay-edge-types': [
      2,
      {
        withEdgeSuffix: true,
        shouldImplementNode: true,
        listTypeCanWrapOnlyEdgeType: false,
      },
    ],
    'description-style': [2, { style: 'block' }],
    'naming-convention': [
      2,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: 'UPPER_CASE',
        InputValueDefinition: 'camelCase',
        allowLeadingUnderscore: true,
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'create', 'delete', 'get', 'is', 'remove', 'set', 'update'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: [
            'mutation',
            'create',
            'delete',
            'get',
            'is',
            'remove',
            'set',
            'update',
          ],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'require-description': [2, { rootField: true }],
    'relay-connection-types': [2],
    'require-deprecation-reason': [2],
    'no-scalar-result-type-on-mutation': [2],
  },
  {
    'input-name': [
      1,
      {
        checkQueries: true,
        checkInputType: true,
        checkMutations: true,
        caseSensitiveInputType: true,
      },
    ],
    alphabetize: [
      1,
      {
        fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
        values: ['EnumTypeDefinition'],
        arguments: ['Field', 'Directive', 'DirectiveDefinition', 'FieldDefinition'],
        definitions: true,
      },
    ],
  },
  {
    alphabetize: [
      2,
      {
        fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
        arguments: ['Field', 'FieldDefinition'],
        definitions: false,
      },
    ],
  },
  { 'strict-id-in-types': [0] },
  {
    'require-description': [
      1,
      {
        types: true,
        rootField: false,
        FieldDefinition: false,
        EnumTypeDefinition: false,
        DirectiveDefinition: false,
        OperationDefinition: false,
        InputValueDefinition: false,
        ScalarTypeDefinition: false,
        InputObjectTypeDefinition: false,
      },
    ],
  },
  {
    'input-name': [
      1,
      {
        checkQueries: false,
        checkInputType: false,
        checkMutations: true,
        caseSensitiveInputType: true,
      },
    ],
    alphabetize: [
      2,
      {
        fields: ['ObjectTypeDefinition', 'InterfaceTypeDefinition', 'InputObjectTypeDefinition'],
        values: ['EnumTypeDefinition'],
        arguments: ['FieldDefinition', 'Field', 'DirectiveDefinition', 'Directive'],
        definitions: true,
      },
    ],
    'description-style': [2, { style: 'block' }],
    'naming-convention': [
      2,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: 'UPPER_CASE',
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'require-description': [
      1,
      {
        types: true,
        rootField: true,
        FieldDefinition: true,
        EnumTypeDefinition: true,
        DirectiveDefinition: true,
        EnumValueDefinition: true,
        OperationDefinition: true,
        UnionTypeDefinition: true,
        InputValueDefinition: true,
        ObjectTypeDefinition: true,
        ScalarTypeDefinition: true,
        InterfaceTypeDefinition: true,
        InputObjectTypeDefinition: true,
      },
    ],
    'no-unreachable-types': [1],
    'require-deprecation-date': [1],
    'no-case-insensitive-enum-values-duplicates': [1],
    'require-field-of-type-query-in-mutation-result': [1],
  },
  { 'require-deprecation-reason': [1] },
  {
    'input-name': [
      1,
      {
        checkQueries: true,
        checkInputType: true,
        checkMutations: true,
        caseSensitiveInputType: false,
      },
    ],
    'no-root-type': [1, { disallow: ['subscription'] }],
    'description-style': [1, { style: 'block' }],
    'naming-convention': [
      1,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'PascalCase',
        EnumValueDefinition: 'UPPER_CASE',
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'no-unreachable-types': [1],
    'no-case-insensitive-enum-values-duplicates': [1],
  },
  {
    'require-description': [
      1,
      {
        types: true,
        DirectiveDefinition: true,
        ScalarTypeDefinition: true,
        InterfaceTypeDefinition: true,
      },
    ],
  },
  {
    'input-name': [
      1,
      {
        checkQueries: true,
        checkInputType: true,
        checkMutations: true,
        caseSensitiveInputType: true,
      },
    ],
    'relay-arguments': [1, { includeBoth: true }],
    'relay-edge-types': [
      1,
      {
        withEdgeSuffix: true,
        shouldImplementNode: true,
        listTypeCanWrapOnlyEdgeType: true,
      },
    ],
    'require-description': [
      1,
      {
        types: true,
        FieldDefinition: true,
        EnumTypeDefinition: true,
        InputValueDefinition: true,
        ObjectTypeDefinition: true,
        InputObjectTypeDefinition: true,
      },
    ],
  },
  {
    'input-name': [0],
    alphabetize: [0],
    'relay-arguments': [0],
    'relay-page-info': [0],
    'relay-edge-types': [0],
    'naming-convention': [0],
    'no-hashtag-description': [0],
    'relay-connection-types': [0],
    'require-deprecation-reason': [0],
    'no-scalar-result-type-on-mutation': [0],
    'no-case-insensitive-enum-values-duplicates': [0],
  },
  {
    'naming-convention': [
      1,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: 'UPPER_CASE',
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get', 'list', 'fetch'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'require-description': [1, { types: true, rootField: true }],
    'no-unreachable-types': [1],
    'no-hashtag-description': [1],
    'require-deprecation-reason': [1],
    'require-nullable-result-in-root': [1],
    'no-scalar-result-type-on-mutation': [1],
  },
  {
    'no-root-type': [2, { disallow: ['subscription'] }],
    'relay-arguments': [2, { includeBoth: true }],
    'description-style': [2, { style: 'block' }],
    'relay-connection-types': [2],
    'require-deprecation-reason': [2],
    'no-scalar-result-type-on-mutation': [2],
    'require-nullable-fields-with-oneof': [2],
  },
  {
    'naming-convention': [
      2,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'no-typename-prefix': [2],
    'require-deprecation-date': [2, { argumentName: 'deletionDate' }],
    'require-deprecation-reason': [2],
    'no-scalar-result-type-on-mutation': [2],
    'no-case-insensitive-enum-values-duplicates': [2],
  },
  {
    'relay-arguments': [1, { includeBoth: true }],
    'relay-page-info': [2],
    'relay-edge-types': [
      1,
      {
        withEdgeSuffix: true,
        shouldImplementNode: true,
        listTypeCanWrapOnlyEdgeType: true,
      },
    ],
    'description-style': [2, { style: 'block' }],
    'naming-convention': [
      2,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'require-description': [
      1,
      {
        types: true,
        rootField: true,
        FieldDefinition: true,
        EnumTypeDefinition: true,
        DirectiveDefinition: true,
        OperationDefinition: true,
        UnionTypeDefinition: true,
        InputValueDefinition: true,
        ObjectTypeDefinition: true,
        ScalarTypeDefinition: true,
        InterfaceTypeDefinition: true,
        InputObjectTypeDefinition: true,
      },
    ],
    'require-deprecation-reason': [2],
  },
  {
    'input-name': [
      2,
      {
        checkQueries: false,
        checkInputType: true,
        checkMutations: true,
        caseSensitiveInputType: false,
      },
    ],
    'relay-arguments': [1, { includeBoth: false }],
    'relay-page-info': [1],
    'relay-edge-types': [
      1,
      {
        withEdgeSuffix: true,
        shouldImplementNode: false,
        listTypeCanWrapOnlyEdgeType: false,
      },
    ],
    'description-style': [2, { style: 'block' }],
    'naming-convention': [
      2,
      {
        types: 'PascalCase',
        Argument: 'camelCase',
        FieldDefinition: 'camelCase',
        DirectiveDefinition: 'camelCase',
        EnumValueDefinition: {
          style: 'UPPER_CASE',
          ignorePattern: '^(User)',
        },
        InputValueDefinition: 'camelCase',
        'FieldDefinition[parent.name.value=Query]': {
          forbiddenPrefixes: ['query', 'get'],
          forbiddenSuffixes: ['Query'],
        },
        'FieldDefinition[parent.name.value=Mutation]': {
          forbiddenPrefixes: ['mutation'],
          forbiddenSuffixes: ['Mutation'],
        },
        'FieldDefinition[parent.name.value=Subscription]': {
          forbiddenPrefixes: ['subscription'],
          forbiddenSuffixes: ['Subscription'],
        },
      },
    ],
    'no-typename-prefix': [1],
    'strict-id-in-types': [
      2,
      {
        exceptions: {
          types: ['PageInfo', 'Email', 'Phone', 'TimeZone', 'Subscriber', 'Customer'],
          suffixes: ['Payload', 'Connection', 'Edge', 'Error'],
        },
        acceptedIdNames: ['id'],
        acceptedIdTypes: ['ID'],
      },
    ],
    'no-hashtag-description': [2],
    'relay-connection-types': [1],
    'require-deprecation-date': [1],
    'require-deprecation-reason': [2],
    'no-scalar-result-type-on-mutation': [2],
  },
];
