Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphQL v16 Support #724

Merged
merged 23 commits into from Nov 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/green-lions-grow.md
@@ -0,0 +1,5 @@
---
'@graphql-eslint/eslint-plugin': minor
---

GraphQL v16 support
6 changes: 3 additions & 3 deletions .github/workflows/canary.yml
Expand Up @@ -32,10 +32,10 @@ jobs:
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-16-node-modules-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-16-8-16-node-modules-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-16-node-modules-${{ hashFiles('yarn.lock') }}
${{ runner.os }}-16-node-modules-
${{ runner.os }}-16-8-16-node-modules-${{ hashFiles('yarn.lock') }}
${{ runner.os }}-16-8-16-node-modules-
- name: Install Dependencies using Yarn
run: yarn install && git checkout yarn.lock && yarn patch-package
- name: Release Canary
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Expand Up @@ -35,10 +35,10 @@ jobs:
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-16-node-modules-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-16-8-16-node-modules-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-16-node-modules-${{ hashFiles('yarn.lock') }}
${{ runner.os }}-16-node-modules-
${{ runner.os }}-16-8-16-node-modules-${{ hashFiles('yarn.lock') }}
${{ runner.os }}-16-8-16-node-modules-
- name: Install Dependencies using Yarn
run: yarn install && git checkout yarn.lock && yarn patch-package
- name: Create Release Pull Request or Publish to npm
Expand Down
36 changes: 25 additions & 11 deletions .github/workflows/tests.yml
Expand Up @@ -25,17 +25,23 @@ jobs:
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-16-node-modules-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-16-8-16-node-modules-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-16-node-modules-${{ hashFiles('yarn.lock') }}
${{ runner.os }}-16-node-modules-
${{ runner.os }}-16-8-16-node-modules-${{ hashFiles('yarn.lock') }}
${{ runner.os }}-16-8-16-node-modules-
- name: Install Dependencies using Yarn
run: yarn install && git checkout yarn.lock
- name: Lint
run: yarn lint
typecheck:
name: TypeScript Type Checking
runs-on: ubuntu-latest
strategy:
matrix:
graphql_version:
# - 14
- 15
- 16
steps:
- name: Checkout Master
uses: actions/checkout@v2
Expand All @@ -49,10 +55,12 @@ jobs:
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-16-node-modules-${{ hashFiles('yarn.lock') }}
key: ${{runner.os}}-16-8-${{matrix.graphql_version}}-node-modules-${{hashFiles('yarn.lock')}}
restore-keys: |
${{ runner.os }}-16-node-modules-${{ hashFiles('yarn.lock') }}
${{ runner.os }}-16-node-modules-
${{runner.os}}-16-8-${{matrix.graphql_version}}-node-modules-${{hashFiles('yarn.lock')}}
${{runner.os}}-16-8-${{matrix.graphql_version}}-node-modules-
- name: Use GraphQL v${{matrix.graphql_version}}
run: node ./scripts/match-graphql.js ${{matrix.graphql_version}}
- name: Install Dependencies using Yarn
run: yarn install && git checkout yarn.lock
- name: Build
Expand All @@ -64,14 +72,18 @@ jobs:
path: packages/plugin/dist

test:
name: Testing on Node ${{matrix.node_version}} with ESLint v${{matrix.eslint_version}}
name: Testing on Node ${{matrix.node_version}} with ESLint v${{matrix.eslint_version}} and GraphQL v${{matrix.graphql_version}}
timeout-minutes: 60
runs-on: ubuntu-latest
needs: [lint, typecheck]
needs: [typecheck]
strategy:
matrix:
node_version: [12, 16]
eslint_version: [7.32.0, 8]
graphql_version:
# - 14
- 15
- 16
steps:
- name: Checkout Master
uses: actions/checkout@v2
Expand All @@ -85,10 +97,12 @@ jobs:
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{runner.os}}-${{matrix.node_version}}-${{matrix.eslint_version}}-node-modules-${{hashFiles('yarn.lock')}}
key: ${{runner.os}}-${{matrix.node_version}}-${{matrix.eslint_version}}-${{matrix.graphql_version}}-node-modules-${{hashFiles('yarn.lock')}}
restore-keys: |
${{runner.os}}-${{matrix.node_version}}-${{matrix.eslint_version}}-node-modules-${{hashFiles('yarn.lock')}}
${{runner.os}}-${{matrix.node_version}}-${{matrix.eslint_version}}-node-modules-
${{runner.os}}-${{matrix.node_version}}-${{matrix.eslint_version}}-${{matrix.graphql_version}}-node-modules-${{hashFiles('yarn.lock')}}
${{runner.os}}-${{matrix.node_version}}-${{matrix.eslint_version}}-${{matrix.graphql_version}}-node-modules-
- name: Use GraphQL v${{matrix.graphql_version}}
run: node ./scripts/match-graphql.js ${{matrix.graphql_version}}
- name: Use ESLint v${{matrix.eslint_version}}
run: node scripts/match-eslint.mjs ${{matrix.eslint_version}}
- name: Install Dependencies using Yarn
Expand Down
13 changes: 12 additions & 1 deletion .vscode/settings.json
@@ -1,3 +1,14 @@
{
"eslint.enable": true
"eslint.enable": true,
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true,
"**/node_modules": true,
"test-lib": true,
"lib": true,
"coverage": true,
"npm": true,
"**/dist": true
},
"typescript.tsdk": "node_modules/typescript/lib"
}
5 changes: 4 additions & 1 deletion babel.config.js
@@ -1,3 +1,6 @@
module.exports = {
presets: [['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript'],
presets: [
['@babel/preset-env', { targets: { node: process.versions.node.split('.')[0] } }],
'@babel/preset-typescript',
],
};
2 changes: 1 addition & 1 deletion examples/basic/package.json
Expand Up @@ -9,7 +9,7 @@
"lint": "eslint ."
},
"dependencies": {
"graphql": "15.7.1"
"graphql": "16.0.1"
},
"devDependencies": {
"@graphql-eslint/eslint-plugin": "2.3.2",
Expand Down
2 changes: 1 addition & 1 deletion examples/code-file/package.json
Expand Up @@ -9,7 +9,7 @@
"lint": "eslint ."
},
"dependencies": {
"graphql": "15.7.1"
"graphql": "16.0.1"
},
"devDependencies": {
"@graphql-eslint/eslint-plugin": "2.3.2",
Expand Down
2 changes: 1 addition & 1 deletion examples/graphql-config-code-file/package.json
Expand Up @@ -9,7 +9,7 @@
"lint": "eslint --ext graphql,js ."
},
"dependencies": {
"graphql": "15.7.1",
"graphql": "16.0.1",
"graphql-tag": "^2.12.5"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion examples/graphql-config/package.json
Expand Up @@ -9,7 +9,7 @@
"lint": "eslint ."
},
"dependencies": {
"graphql": "15.7.1"
"graphql": "16.0.1"
},
"devDependencies": {
"@graphql-eslint/eslint-plugin": "2.3.2",
Expand Down
2 changes: 1 addition & 1 deletion examples/prettier/package.json
Expand Up @@ -9,7 +9,7 @@
"lint": "eslint ."
},
"dependencies": {
"graphql": "15.7.1"
"graphql": "16.0.1"
},
"devDependencies": {
"@graphql-eslint/eslint-plugin": "2.3.2",
Expand Down
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -56,7 +56,8 @@
"typescript": "4.4.4"
},
"resolutions": {
"@changesets/git": "1.1.2"
"@changesets/git": "1.1.2",
"graphql": "16.0.1"
},
"lint-staged": {
"{packages,scripts}/**/*.{ts,tsx,js,jsx,cjs,mjs}": [
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin/package.json
Expand Up @@ -41,7 +41,7 @@
"@types/graphql-depth-limit": "1.1.3",
"@types/lodash.lowercase": "4.3.6",
"bob-the-bundler": "1.5.1",
"graphql": "15.7.2",
"graphql": "16.0.1",
"typescript": "4.4.4"
},
"peerDependencies": {
Expand Down
9 changes: 4 additions & 5 deletions packages/plugin/src/estree-parser/converter.ts
@@ -1,15 +1,14 @@
import { convertDescription, convertLocation, convertRange, extractCommentsFromAst } from './utils';
import { GraphQLESTreeNode, SafeGraphQLType } from './estree-ast';
import { ASTNode, TypeNode, TypeInfo, visit, visitWithTypeInfo, Location, Kind, DocumentNode } from 'graphql';
import { Comment } from 'estree';
import { ASTNode, TypeNode, TypeInfo, visit, visitWithTypeInfo, Location, Kind, DocumentNode, ASTVisitor } from 'graphql';

export function convertToESTree<T extends ASTNode>(
node: T,
typeInfo?: TypeInfo
): { rootTree: GraphQLESTreeNode<T>; comments: Comment[] } {
const visitor = { leave: convertNode(typeInfo) };
) {
const visitor: ASTVisitor = { leave: convertNode(typeInfo) };
return {
rootTree: visit(node, typeInfo ? visitWithTypeInfo(typeInfo, visitor) : visitor),
rootTree: visit(node, typeInfo ? visitWithTypeInfo(typeInfo, visitor) : visitor) as GraphQLESTreeNode<T>,
comments: extractCommentsFromAst(node.loc),
};
}
Expand Down
5 changes: 2 additions & 3 deletions packages/plugin/src/graphql-ast.ts
@@ -1,9 +1,8 @@
import {
ASTNode,
Visitor,
ASTVisitor,
TypeInfo,
GraphQLSchema,
ASTKindToNode,
visit,
isInterfaceType,
visitWithTypeInfo,
Expand Down Expand Up @@ -41,7 +40,7 @@ export function getReachableTypes(schema: GraphQLSchema): ReachableTypes {
}
};

const visitor: Visitor<ASTKindToNode> = {
const visitor: ASTVisitor = {
InterfaceTypeDefinition: collect,
ObjectTypeDefinition: collect,
InputValueDefinition: collect,
Expand Down
6 changes: 3 additions & 3 deletions packages/plugin/src/parser.ts
@@ -1,5 +1,5 @@
import { parseGraphQLSDL } from '@graphql-tools/utils';
import { GraphQLError, TypeInfo } from 'graphql';
import { ASTNode, GraphQLError, TypeInfo, Source } from 'graphql';
import { Linter } from 'eslint';
import { convertToESTree } from './estree-parser';
import { GraphQLESLintParseResult, ParserOptions, ParserServices } from './types';
Expand Down Expand Up @@ -32,8 +32,8 @@ export function parseForESLint(code: string, options: ParserOptions = {}): Graph
noLocation: false,
});

const { rootTree, comments } = convertToESTree(graphqlAst.document, schema ? new TypeInfo(schema) : null);
const tokens = extractTokens(code);
const { rootTree, comments } = convertToESTree(graphqlAst.document as ASTNode, schema ? new TypeInfo(schema) : null);
const tokens = extractTokens(new Source(code, filePath));

return {
services: parserServices,
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin/src/rules/graphql-js-validation.ts
Expand Up @@ -22,7 +22,7 @@ export function validateDoc(
): void {
if (documentNode?.definitions?.length > 0) {
try {
const validationErrors = schema ? validate(schema, documentNode, rules) : validateSDL(documentNode, null, rules);
const validationErrors = schema ? validate(schema, documentNode, rules) : validateSDL(documentNode, null, rules as any);

for (const error of validationErrors) {
const validateRuleName = ruleName || `[${extractRuleName(error.stack)}]`;
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin/src/rules/no-deprecated.ts
Expand Up @@ -86,7 +86,7 @@ const rule: GraphQLESLintRule<[], true> = {
const typeInfo = node.typeInfo();

if (typeInfo && typeInfo.enumValue) {
if (typeInfo.enumValue.isDeprecated) {
if (typeInfo.enumValue.deprecationReason) {
const enumValueName = node.value;
context.report({
loc: getLocation(node.loc, enumValueName),
Expand All @@ -104,7 +104,7 @@ const rule: GraphQLESLintRule<[], true> = {
const typeInfo = node.typeInfo();

if (typeInfo && typeInfo.fieldDef) {
if (typeInfo.fieldDef.isDeprecated) {
if (typeInfo.fieldDef.deprecationReason) {
const fieldName = node.name.value;
context.report({
loc: getLocation(node.loc, fieldName),
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin/src/rules/require-description.ts
Expand Up @@ -49,7 +49,7 @@ const rule: GraphQLESLintRule<RequireDescriptionRuleConfig> = {
examples: [
{
title: 'Incorrect',
usage: [{ on: ['ObjectTypeDefinition', 'FieldDefinition'] }],
usage: [{ on: [Kind.OBJECT_TYPE_DEFINITION, Kind.FIELD_DEFINITION] }],
code: /* GraphQL */ `
type someTypeName {
name: String
Expand All @@ -58,7 +58,7 @@ const rule: GraphQLESLintRule<RequireDescriptionRuleConfig> = {
},
{
title: 'Correct',
usage: [{ on: ['ObjectTypeDefinition', 'FieldDefinition'] }],
usage: [{ on: [Kind.OBJECT_TYPE_DEFINITION, Kind.FIELD_DEFINITION] }],
code: /* GraphQL */ `
"""
Some type description
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin/src/sibling-operations.ts
Expand Up @@ -120,7 +120,7 @@ export function getSiblingOperations(options: ParserOptions, gqlConfig: GraphQLC
if (definition.kind === Kind.FRAGMENT_DEFINITION) {
result.push({
filePath: source.location,
document: definition,
document: definition as FragmentDefinitionNode,
});
}
}
Expand All @@ -141,7 +141,7 @@ export function getSiblingOperations(options: ParserOptions, gqlConfig: GraphQLC
if (definition.kind === Kind.OPERATION_DEFINITION) {
result.push({
filePath: source.location,
document: definition,
document: definition as OperationDefinitionNode,
});
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin/src/utils.ts
Expand Up @@ -77,8 +77,8 @@ function getLexer(source: Source): Lexer {
throw new Error(`Unsupported GraphQL version! Please make sure to use GraphQL v14 or newer!`);
}

export function extractTokens(source: string): AST.Token[] {
const lexer = getLexer(new Source(source));
export function extractTokens(source: Source): AST.Token[] {
const lexer = getLexer(source);
const tokens: AST.Token[] = [];
let token = lexer.advance();

Expand Down
10 changes: 7 additions & 3 deletions packages/plugin/tests/mocks/graphql-server.ts
@@ -1,11 +1,13 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment -- ignore type errors from `graphql` package
// @ts-nocheck
import { readFileSync } from 'fs';
import { resolve } from 'path';
import { createServer, Server, IncomingMessage, ServerResponse } from 'http';
import { buildSchema, getIntrospectionQuery, graphqlSync } from 'graphql';
import { buildSchema, introspectionFromSchema } from 'graphql';

const sdlSchema = readFileSync(resolve(__dirname, 'user-schema.graphql'), 'utf8');
const graphqlSchemaObj = buildSchema(sdlSchema);
const introspectionQueryResult = graphqlSync(graphqlSchemaObj, getIntrospectionQuery());
const introspectionQueryResult = introspectionFromSchema(graphqlSchemaObj);

class TestGraphQLServer {
private server: Server;
Expand Down Expand Up @@ -38,7 +40,9 @@ class TestGraphQLServer {
if (pathname === '/') {
const { query } = await this.parseData(req);
if (query.includes('query IntrospectionQuery')) {
res.end(JSON.stringify(introspectionQueryResult));
res.end(JSON.stringify({
data: introspectionQueryResult
}));
}
} else if (pathname === '/my-headers') {
res.end(JSON.stringify(req.headers));
Expand Down
5 changes: 4 additions & 1 deletion packages/plugin/tests/schema.spec.ts
Expand Up @@ -17,7 +17,7 @@ describe('schema', () => {
expect(graphQLSchema).toBeInstanceOf(GraphQLSchema);

const sdlString = printSchema(graphQLSchema);
expect(sdlString).toBe(schemaOnDisk);
expect(sdlString.trim()).toBe(schemaOnDisk.trim());
};

describe('GraphQLFileLoader', () => {
Expand Down Expand Up @@ -54,6 +54,9 @@ describe('schema', () => {
url = chunk.toString().trimRight();
done();
});
local.stderr.on('data', chunk => {
throw new Error(chunk.toString().trimRight());
});
});

afterAll(done => {
Expand Down
5 changes: 2 additions & 3 deletions patches/eslint+8.1.0.patch
@@ -1,8 +1,8 @@
diff --git a/node_modules/eslint/lib/rule-tester/rule-tester.js b/node_modules/eslint/lib/rule-tester/rule-tester.js
index 324af7b..e771420 100644
index 7f590a5..5368321 100644
--- a/node_modules/eslint/lib/rule-tester/rule-tester.js
+++ b/node_modules/eslint/lib/rule-tester/rule-tester.js
@@ -943,8 +943,18 @@ class RuleTester {
@@ -946,7 +946,17 @@ class RuleTester {
"Expected no autofixes to be suggested"
);
} else {
Expand All @@ -21,4 +21,3 @@ index 324af7b..e771420 100644
}
} else {
assert.strictEqual(
result.output,