Skip to content

Commit

Permalink
fix race condition of loading loadGraphQLConfig() when `processor.p…
Browse files Browse the repository at this point in the history
…reprocess()` can be called before `parseForESLint()` (#1170)

* fix race condition of loading `loadGraphQLConfig()` when `processor.preprocess()` can be called before `parseForESLint()`

* one last time

* one yet last time

* one yet yet last time
  • Loading branch information
dimaMachina committed Sep 26, 2022
1 parent 02125cb commit 0b8acdc
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 45 deletions.
5 changes: 5 additions & 0 deletions .changeset/tiny-geese-type.md
@@ -0,0 +1,5 @@
---
'@graphql-eslint/eslint-plugin': patch
---

fix race condition of loading `loadGraphQLConfig()` when `processor.preprocess()` can be called before `parseForESLint()`
3 changes: 1 addition & 2 deletions examples/basic/package.json
@@ -1,10 +1,9 @@
{
"name": "@graphql-eslint/example-basic",
"private": true,
"version": "0.0.1",
"version": "0.0.0",
"repository": "https://github.com/B2o5T/graphql-eslint",
"author": "Dotan Simha <dotansimha@gmail.com>",
"license": "MIT",
"scripts": {
"lint": "eslint ."
},
Expand Down
3 changes: 1 addition & 2 deletions examples/code-file/package.json
@@ -1,10 +1,9 @@
{
"name": "@graphql-eslint/example-code-file",
"private": true,
"version": "0.0.1",
"version": "0.0.0",
"repository": "https://github.com/B2o5T/graphql-eslint",
"author": "Dotan Simha <dotansimha@gmail.com>",
"license": "MIT",
"scripts": {
"lint": "eslint ."
},
Expand Down
3 changes: 1 addition & 2 deletions examples/graphql-config-code-file/package.json
@@ -1,10 +1,9 @@
{
"name": "@graphql-eslint/example-graphql-config-code-file",
"private": true,
"version": "0.0.1",
"version": "0.0.0",
"repository": "https://github.com/B2o5T/graphql-eslint",
"author": "Dotan Simha <dotansimha@gmail.com>",
"license": "MIT",
"scripts": {
"lint": "eslint --ext graphql,js ."
},
Expand Down
3 changes: 1 addition & 2 deletions examples/graphql-config/package.json
@@ -1,10 +1,9 @@
{
"name": "@graphql-eslint/example-graphql-config",
"private": true,
"version": "0.0.1",
"version": "0.0.0",
"repository": "https://github.com/B2o5T/graphql-eslint",
"author": "Dotan Simha <dotansimha@gmail.com>",
"license": "MIT",
"scripts": {
"lint": "eslint ."
},
Expand Down
3 changes: 1 addition & 2 deletions examples/monorepo/package.json
@@ -1,8 +1,7 @@
{
"name": "monorepo",
"version": "0.0.1",
"version": "0.0.0",
"private": true,
"license": "MIT",
"author": "Dimitri POSTOLOV",
"scripts": {
"lint": "eslint ."
Expand Down
3 changes: 1 addition & 2 deletions examples/prettier/package.json
@@ -1,10 +1,9 @@
{
"name": "@graphql-eslint/example-prettier",
"private": true,
"version": "0.0.1",
"version": "0.0.0",
"repository": "https://github.com/B2o5T/graphql-eslint",
"author": "JounQin <admin@1stg.me>",
"license": "MIT",
"scripts": {
"lint": "eslint ."
},
Expand Down
20 changes: 11 additions & 9 deletions packages/plugin/src/graphql-config.ts
Expand Up @@ -12,22 +12,24 @@ import { ParserOptions } from './types';
const debug = debugFactory('graphql-eslint:graphql-config');
let graphQLConfig: GraphQLConfig;

export function loadOnDiskGraphQLConfig(filePath: string): GraphQLConfig {
return loadConfigSync({
// load config relative to the file being linted
rootDir: filePath ? dirname(filePath) : undefined,
throwOnEmpty: false,
throwOnMissing: false,
extensions: [addCodeFileLoaderExtension],
});
}

export function loadGraphQLConfig(options: ParserOptions = {}): GraphQLConfig {
// We don't want cache config on test environment
// Otherwise schema and documents will be same for all tests
if (process.env.NODE_ENV !== 'test' && graphQLConfig) {
return graphQLConfig;
}

const onDiskConfig = options.skipGraphQLConfig
? null
: loadConfigSync({
// load config relative to the file being linted
rootDir: options.filePath ? dirname(options.filePath) : undefined,
throwOnEmpty: false,
throwOnMissing: false,
extensions: [addCodeFileLoaderExtension],
});
const onDiskConfig = !options.skipGraphQLConfig && loadOnDiskGraphQLConfig(options.filePath);

debug('options.skipGraphQLConfig: %o', options.skipGraphQLConfig);
if (onDiskConfig) {
Expand Down
43 changes: 21 additions & 22 deletions packages/plugin/src/processor.ts
@@ -1,40 +1,39 @@
import { Linter } from 'eslint';
import { parseCode, GraphQLTagPluckOptions } from '@graphql-tools/graphql-tag-pluck';
import { asArray } from '@graphql-tools/utils';
import { loadGraphQLConfig } from './graphql-config';
import { GraphQLConfig } from 'graphql-config';
import { loadOnDiskGraphQLConfig } from './graphql-config';

export type Block = Linter.ProcessorFile & {
lineOffset: number;
offset: number;
};

let RELEVANT_KEYWORDS: string[];
let graphQLTagPluckOptions: GraphQLTagPluckOptions;

const blocksMap = new Map<string, Block[]>();

let onDiskConfig: GraphQLConfig;

export const processor: Linter.Processor<Block | string> = {
supportsAutofix: true,
preprocess(code, filePath) {
if (!RELEVANT_KEYWORDS) {
graphQLTagPluckOptions = loadGraphQLConfig().getDefault()?.extensions?.graphqlTagPluck;
onDiskConfig ||= loadOnDiskGraphQLConfig(filePath);
const graphQLTagPluckOptions: GraphQLTagPluckOptions =
onDiskConfig?.getProjectForFile?.(filePath)?.extensions?.graphqlTagPluck;
const {
modules = [],
globalGqlIdentifierName = ['gql', 'graphql'],
gqlMagicComment = 'GraphQL',
} = graphQLTagPluckOptions || {};

const {
modules = [],
globalGqlIdentifierName = ['gql', 'graphql'],
gqlMagicComment = 'GraphQL',
} = graphQLTagPluckOptions || {};

RELEVANT_KEYWORDS = [
...new Set(
[
...modules.map(({ identifier }) => identifier),
...asArray(globalGqlIdentifierName),
gqlMagicComment,
].filter(Boolean)
),
];
}
const RELEVANT_KEYWORDS: string[] = [
...new Set(
[
...modules.map(({ identifier }) => identifier),
...asArray(globalGqlIdentifierName),
gqlMagicComment,
].filter(Boolean)
),
];

if (RELEVANT_KEYWORDS.every(keyword => !code.includes(keyword))) {
return [code];
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin/tests/processor-with-graphql-config.spec.ts
@@ -1,8 +1,8 @@
import { Block, processor } from '../src/processor';

jest.mock('../src/graphql-config', () => ({
loadGraphQLConfig: jest.fn(() => ({
getDefault: () => ({
loadOnDiskGraphQLConfig: jest.fn(() => ({
getProjectForFile: () => ({
extensions: {
graphqlTagPluck: {
modules: [{ name: 'custom-gql-tag', identifier: 'custom' }],
Expand Down

0 comments on commit 0b8acdc

Please sign in to comment.