Skip to content

Commit 08a8a13

Browse files
authored
fix caching issues for no-unreachable-types / no-unused-fields rules for multi projects (#2455)
* aa * update tests * fix lint
1 parent 7e23fa4 commit 08a8a13

File tree

9 files changed

+31
-21
lines changed

9 files changed

+31
-21
lines changed

Diff for: .changeset/breezy-seals-sparkle.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-eslint/eslint-plugin': patch
3+
---
4+
5+
fix caching issues for `no-unreachable-types` / `no-unused-fields` rules for multi projects

Diff for: examples/multiple-projects-graphql-config/query.second-project.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { custom } from 'custom-graphql-tag';
22

33
/* MyGraphQL */ `
4-
fragment UserFields on User {
4+
fragment UserFields on AnotherUser {
55
firstName
66
lastName
77
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
type User {
1+
type AnotherUser {
22
firstName: String
33
lastName: String
44
}
55

66
type Query {
7-
users: [User]
7+
users: [AnotherUser]
88
}

Diff for: packages/plugin/__tests__/__snapshots__/examples.spec.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,8 @@ exports[`Examples > should work in multiple projects 1`] = `
236236
desc: Rename to \`users\`,
237237
fix: {
238238
range: [
239-
141,
240-
141,
239+
148,
240+
148,
241241
],
242242
text: query users ,
243243
},
@@ -268,10 +268,10 @@ Accepted type: ID.,
268268
messages: [
269269
{
270270
column: 6,
271-
endColumn: 10,
271+
endColumn: 17,
272272
endLine: 1,
273273
line: 1,
274-
message: type "User" must have exactly one non-nullable unique identifier.
274+
message: type "AnotherUser" must have exactly one non-nullable unique identifier.
275275
Accepted name: id.
276276
Accepted type: ID.,
277277
nodeType: Name,

Diff for: packages/plugin/src/cache.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import debugFactory from 'debug';
44

55
const log = debugFactory('graphql-eslint:ModuleCache');
66

7-
export class ModuleCache<T, K = any> {
7+
export class ModuleCache<K, T> {
88
map = new Map<K, { lastSeen: [number, number]; result: T }>();
99

1010
set(cacheKey: K, result: T): void {

Diff for: packages/plugin/src/documents.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { ModuleCache } from './cache.js';
77
import { Pointer } from './types.js';
88

99
const debug = debugFactory('graphql-eslint:operations');
10-
const operationsCache = new ModuleCache<Source[]>();
10+
const operationsCache = new ModuleCache<GraphQLProjectConfig['documents'], Source[]>();
1111

1212
const handleVirtualPath = (documents: Source[]): Source[] => {
1313
const filepathMap: Record<string, number> = Object.create(null);

Diff for: packages/plugin/src/rules/no-unreachable-types.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import {
88
NameNode,
99
visit,
1010
} from 'graphql';
11+
import { GraphQLProjectConfig } from 'graphql-config';
1112
import lowerCase from 'lodash.lowercase';
13+
import { ModuleCache } from '../cache.js';
1214
import { GraphQLESTreeNode } from '../estree-converter/index.js';
1315
import { GraphQLESLintRule } from '../types.js';
1416
import { getTypeName, requireGraphQLSchemaFromContext } from '../utils.js';
@@ -33,7 +35,7 @@ const KINDS = [
3335

3436
type ReachableTypes = Set<string>;
3537

36-
let reachableTypesCache: ReachableTypes;
38+
const reachableTypesCache = new ModuleCache<GraphQLProjectConfig['schema'], ReachableTypes>();
3739

3840
const RequestDirectiveLocations = new Set<string>([
3941
DirectiveLocation.QUERY,
@@ -49,8 +51,9 @@ const RequestDirectiveLocations = new Set<string>([
4951
function getReachableTypes(schema: GraphQLSchema): ReachableTypes {
5052
// We don't want cache reachableTypes on test environment
5153
// Otherwise reachableTypes will be same for all tests
52-
if (process.env.NODE_ENV !== 'test' && reachableTypesCache) {
53-
return reachableTypesCache;
54+
const cachedValue = reachableTypesCache.get(schema);
55+
if (process.env.NODE_ENV !== 'test' && cachedValue) {
56+
return cachedValue;
5457
}
5558
const reachableTypes: ReachableTypes = new Set();
5659

@@ -106,9 +109,8 @@ function getReachableTypes(schema: GraphQLSchema): ReachableTypes {
106109
}
107110
}
108111
}
109-
110-
reachableTypesCache = reachableTypes;
111-
return reachableTypesCache;
112+
reachableTypesCache.set(schema, reachableTypes);
113+
return reachableTypes;
112114
}
113115

114116
export const rule: GraphQLESLintRule = {

Diff for: packages/plugin/src/rules/no-unused-fields.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { GraphQLSchema, TypeInfo, visit, visitWithTypeInfo } from 'graphql';
2+
import { GraphQLProjectConfig } from 'graphql-config';
3+
import { ModuleCache } from '../cache.js';
24
import { SiblingOperations } from '../siblings.js';
35
import { GraphQLESLintRule } from '../types.js';
46
import { requireGraphQLSchemaFromContext, requireSiblingsOperations } from '../utils.js';
@@ -7,13 +9,14 @@ const RULE_ID = 'no-unused-fields';
79

810
type UsedFields = Record<string, Set<string>>;
911

10-
let usedFieldsCache: UsedFields;
12+
const usedFieldsCache = new ModuleCache<GraphQLProjectConfig['schema'], UsedFields>();
1113

1214
function getUsedFields(schema: GraphQLSchema, operations: SiblingOperations): UsedFields {
1315
// We don't want cache usedFields on test environment
1416
// Otherwise usedFields will be same for all tests
15-
if (process.env.NODE_ENV !== 'test' && usedFieldsCache) {
16-
return usedFieldsCache;
17+
const cachedValue = usedFieldsCache.get(schema);
18+
if (process.env.NODE_ENV !== 'test' && cachedValue) {
19+
return cachedValue;
1720
}
1821
const usedFields: UsedFields = Object.create(null);
1922
const typeInfo = new TypeInfo(schema);
@@ -37,8 +40,8 @@ function getUsedFields(schema: GraphQLSchema, operations: SiblingOperations): Us
3740
for (const { document } of allDocuments) {
3841
visit(document, visitor);
3942
}
40-
usedFieldsCache = usedFields;
41-
return usedFieldsCache;
43+
usedFieldsCache.set(schema, usedFields);
44+
return usedFields;
4245
}
4346

4447
export const rule: GraphQLESLintRule = {

Diff for: packages/plugin/src/schema.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { GraphQLProjectConfig } from 'graphql-config';
55
import { ModuleCache } from './cache.js';
66
import { Pointer, Schema } from './types.js';
77

8-
const schemaCache = new ModuleCache<GraphQLSchema>();
8+
const schemaCache = new ModuleCache<GraphQLProjectConfig['schema'], GraphQLSchema>();
99
const debug = debugFactory('graphql-eslint:schema');
1010

1111
export function getSchema(project: GraphQLProjectConfig): Schema {

0 commit comments

Comments
 (0)