Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/breezy-seals-sparkle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphql-eslint/eslint-plugin': patch
---

fix caching issues for `no-unreachable-types` / `no-unused-fields` rules for multi projects
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { custom } from 'custom-graphql-tag';

/* MyGraphQL */ `
fragment UserFields on User {
fragment UserFields on AnotherUser {
firstName
lastName
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
type User {
type AnotherUser {
firstName: String
lastName: String
}

type Query {
users: [User]
users: [AnotherUser]
}
8 changes: 4 additions & 4 deletions packages/plugin/__tests__/__snapshots__/examples.spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,8 @@ exports[`Examples > should work in multiple projects 1`] = `
desc: Rename to \`users\`,
fix: {
range: [
141,
141,
148,
148,
],
text: query users ,
},
Expand Down Expand Up @@ -268,10 +268,10 @@ Accepted type: ID.,
messages: [
{
column: 6,
endColumn: 10,
endColumn: 17,
endLine: 1,
line: 1,
message: type "User" must have exactly one non-nullable unique identifier.
message: type "AnotherUser" must have exactly one non-nullable unique identifier.
Accepted name: id.
Accepted type: ID.,
nodeType: Name,
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin/src/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import debugFactory from 'debug';

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

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

set(cacheKey: K, result: T): void {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin/src/documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ModuleCache } from './cache.js';
import { Pointer } from './types.js';

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

const handleVirtualPath = (documents: Source[]): Source[] => {
const filepathMap: Record<string, number> = Object.create(null);
Expand Down
14 changes: 8 additions & 6 deletions packages/plugin/src/rules/no-unreachable-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import {
NameNode,
visit,
} from 'graphql';
import { GraphQLProjectConfig } from 'graphql-config';
import lowerCase from 'lodash.lowercase';
import { ModuleCache } from '../cache.js';
import { GraphQLESTreeNode } from '../estree-converter/index.js';
import { GraphQLESLintRule } from '../types.js';
import { getTypeName, requireGraphQLSchemaFromContext } from '../utils.js';
Expand All @@ -33,7 +35,7 @@ const KINDS = [

type ReachableTypes = Set<string>;

let reachableTypesCache: ReachableTypes;
const reachableTypesCache = new ModuleCache<GraphQLProjectConfig['schema'], ReachableTypes>();

const RequestDirectiveLocations = new Set<string>([
DirectiveLocation.QUERY,
Expand All @@ -49,8 +51,9 @@ const RequestDirectiveLocations = new Set<string>([
function getReachableTypes(schema: GraphQLSchema): ReachableTypes {
// We don't want cache reachableTypes on test environment
// Otherwise reachableTypes will be same for all tests
if (process.env.NODE_ENV !== 'test' && reachableTypesCache) {
return reachableTypesCache;
const cachedValue = reachableTypesCache.get(schema);
if (process.env.NODE_ENV !== 'test' && cachedValue) {
return cachedValue;
}
const reachableTypes: ReachableTypes = new Set();

Expand Down Expand Up @@ -106,9 +109,8 @@ function getReachableTypes(schema: GraphQLSchema): ReachableTypes {
}
}
}

reachableTypesCache = reachableTypes;
return reachableTypesCache;
reachableTypesCache.set(schema, reachableTypes);
return reachableTypes;
}

export const rule: GraphQLESLintRule = {
Expand Down
13 changes: 8 additions & 5 deletions packages/plugin/src/rules/no-unused-fields.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { GraphQLSchema, TypeInfo, visit, visitWithTypeInfo } from 'graphql';
import { GraphQLProjectConfig } from 'graphql-config';
import { ModuleCache } from '../cache.js';
import { SiblingOperations } from '../siblings.js';
import { GraphQLESLintRule } from '../types.js';
import { requireGraphQLSchemaFromContext, requireSiblingsOperations } from '../utils.js';
Expand All @@ -7,13 +9,14 @@ const RULE_ID = 'no-unused-fields';

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

let usedFieldsCache: UsedFields;
const usedFieldsCache = new ModuleCache<GraphQLProjectConfig['schema'], UsedFields>();

function getUsedFields(schema: GraphQLSchema, operations: SiblingOperations): UsedFields {
// We don't want cache usedFields on test environment
// Otherwise usedFields will be same for all tests
if (process.env.NODE_ENV !== 'test' && usedFieldsCache) {
return usedFieldsCache;
const cachedValue = usedFieldsCache.get(schema);
if (process.env.NODE_ENV !== 'test' && cachedValue) {
return cachedValue;
}
const usedFields: UsedFields = Object.create(null);
const typeInfo = new TypeInfo(schema);
Expand All @@ -37,8 +40,8 @@ function getUsedFields(schema: GraphQLSchema, operations: SiblingOperations): Us
for (const { document } of allDocuments) {
visit(document, visitor);
}
usedFieldsCache = usedFields;
return usedFieldsCache;
usedFieldsCache.set(schema, usedFields);
return usedFields;
}

export const rule: GraphQLESLintRule = {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { GraphQLProjectConfig } from 'graphql-config';
import { ModuleCache } from './cache.js';
import { Pointer, Schema } from './types.js';

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

export function getSchema(project: GraphQLProjectConfig): Schema {
Expand Down