Skip to content

Commit 0094548

Browse files
authored
Add cache for graphql-config loading (#235)
1 parent c2124ad commit 0094548

File tree

5 files changed

+51
-38
lines changed

5 files changed

+51
-38
lines changed

.changeset/cool-frogs-kiss.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-eslint/eslint-plugin': patch
3+
---
4+
5+
Load graphql config file only once

packages/plugin/src/graphql-config.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { GraphQLConfig, GraphQLExtensionDeclaration, loadConfigSync } from 'graphql-config';
2+
import { schemaLoaders } from './schema';
3+
import { operationsLoaders } from './sibling-operations';
4+
import { ParserOptions } from './types';
5+
6+
export function loadGraphqlConfig(options: ParserOptions): GraphQLConfig | null {
7+
if (options?.skipGraphQLConfig) return null;
8+
if (!graphqlConfig) {
9+
graphqlConfig = loadConfigSync({
10+
throwOnEmpty: false,
11+
throwOnMissing: false,
12+
extensions: [addCodeFileLoaderExtension],
13+
});
14+
}
15+
16+
return graphqlConfig;
17+
}
18+
19+
let graphqlConfig: GraphQLConfig | null;
20+
21+
const addCodeFileLoaderExtension: GraphQLExtensionDeclaration = api => {
22+
schemaLoaders.forEach(loader => api.loaders.schema.register(loader));
23+
operationsLoaders.forEach(loader => api.loaders.documents.register(loader));
24+
return { name: 'graphql-eslint-loaders' };
25+
};

packages/plugin/src/parser.ts

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,16 @@ import { GraphQLError, TypeInfo } from 'graphql';
44
import { Linter } from 'eslint';
55
import { GraphQLESLintParseResult, ParserOptions } from './types';
66
import { extractTokens } from './utils';
7-
import { getSchema, schemaLoaders } from './schema';
8-
import { getSiblingOperations, operationsLoaders } from './sibling-operations';
9-
import { loadConfigSync, GraphQLConfig, GraphQLExtensionDeclaration } from 'graphql-config';
7+
import { getSchema } from './schema';
8+
import { getSiblingOperations } from './sibling-operations';
9+
import { loadGraphqlConfig } from './graphql-config';
1010

1111
export function parse(code: string, options?: ParserOptions): Linter.ESLintParseResult['ast'] {
1212
return parseForESLint(code, options).ast;
1313
}
1414

15-
const addCodeFileLoaderExtension: GraphQLExtensionDeclaration = api => {
16-
schemaLoaders.forEach(loader => api.loaders.schema.register(loader));
17-
operationsLoaders.forEach(loader => api.loaders.documents.register(loader));
18-
return { name: 'graphql-eslint-loaders' };
19-
};
20-
2115
export function parseForESLint(code: string, options?: ParserOptions): GraphQLESLintParseResult {
22-
const gqlConfig: GraphQLConfig | null = options?.skipGraphQLConfig
23-
? null
24-
: loadConfigSync({
25-
throwOnEmpty: false,
26-
throwOnMissing: false,
27-
extensions: [addCodeFileLoaderExtension],
28-
});
29-
16+
const gqlConfig = loadGraphqlConfig(options);
3017
const schema = getSchema(options, gqlConfig);
3118
const siblingOperations = getSiblingOperations(options, gqlConfig);
3219
const parserServices = {

packages/plugin/src/schema.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,34 +23,32 @@ export const schemaLoaders: Loader<string, SingleFileOptions>[] = [
2323
new GraphQLFileLoader(),
2424
new JsonFileLoader(),
2525
new UrlLoader(),
26-
]
26+
];
2727

2828
export function getSchema(options: ParserOptions, gqlConfig: GraphQLConfig): GraphQLSchema | null {
2929
let schema: GraphQLSchema | null = null;
3030

3131
// We first try to use graphql-config for loading the schema, based on the type of the file,
3232
// We are using the directory of the file as the key for the schema caching, to avoid reloading of the schema.
33-
if (options && options.filePath && !options.skipGraphQLConfig) {
33+
if (gqlConfig && options?.filePath) {
3434
const fileDir = dirname(options.filePath);
3535

3636
if (schemaCache.has(fileDir)) {
3737
schema = schemaCache.get(fileDir);
3838
} else {
39-
if (gqlConfig) {
40-
const projectForFile = gqlConfig.getProjectForFile(options.filePath);
39+
const projectForFile = gqlConfig.getProjectForFile(options.filePath);
4140

42-
if (projectForFile) {
43-
schema = projectForFile.getSchemaSync();
44-
schemaCache.set(fileDir, schema);
45-
}
41+
if (projectForFile) {
42+
schema = projectForFile.getSchemaSync();
43+
schemaCache.set(fileDir, schema);
4644
}
4745
}
4846
}
4947

5048
// If schema was not loaded yet, and user configured it in the parserConfig, we can try to load it,
5149
// In this case, the cache key is the path for the schema. This is needed in order to allow separate
5250
// configurations for different file paths (a very edgey case).
53-
if (options && !schema && options.schema) {
51+
if (!schema && options?.schema) {
5452
const schemaKey = Array.isArray(options.schema) ? options.schema.join(',') : options.schema;
5553

5654
if (schemaCache.has(schemaKey)) {

packages/plugin/src/sibling-operations.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const operationsLoaders: Loader<string, SingleFileOptions>[] = [
3030
document: parse(pointer),
3131
}),
3232
},
33-
]
33+
];
3434

3535
export type SiblingOperations = {
3636
available: boolean;
@@ -60,32 +60,30 @@ export function getSiblingOperations(options: ParserOptions, gqlConfig: GraphQLC
6060

6161
// We first try to use graphql-config for loading the operations paths, based on the type of the file,
6262
// We are using the directory of the file as the key for the schema caching, to avoid reloading of the schema.
63-
if (options && options.filePath && !options.skipGraphQLConfig) {
63+
if (gqlConfig && options?.filePath) {
6464
const fileDir = dirname(options.filePath);
6565

6666
if (operationsCache.has(fileDir)) {
6767
siblings = operationsCache.get(fileDir);
6868
} else {
69-
if (gqlConfig) {
70-
const projectForFile = gqlConfig.getProjectForFile(options.filePath);
69+
const projectForFile = gqlConfig.getProjectForFile(options.filePath);
7170

72-
if (projectForFile) {
73-
siblings = projectForFile.getDocumentsSync();
74-
operationsCache.set(fileDir, siblings);
75-
}
71+
if (projectForFile) {
72+
siblings = projectForFile.getDocumentsSync();
73+
operationsCache.set(fileDir, siblings);
7674
}
7775
}
7876
}
7977

80-
if (options && options.operations && !siblings) {
78+
if (!siblings && options?.operations) {
8179
const loadPaths = Array.isArray(options.operations) ? options.operations : [options.operations] || [];
8280
const loadKey = loadPaths.join(',');
8381

84-
if (!operationsCache.has(loadKey)) {
82+
if (operationsCache.has(loadKey)) {
83+
siblings = operationsCache.get(loadKey);
84+
} else {
8585
siblings = loadSiblings(process.cwd(), loadPaths);
8686
operationsCache.set(loadKey, siblings);
87-
} else {
88-
siblings = operationsCache.get(loadKey);
8987
}
9088
}
9189

0 commit comments

Comments
 (0)