@graphql-eslint/eslint-plugin
Version:
GraphQL plugin for ESLint
112 lines (111 loc) • 4.29 kB
JavaScript
import path from 'path';
import { requireSiblingsOperations } from '../utils.js';
const RULE_ID = 'require-import-fragment';
const SUGGESTION_ID = 'add-import-expression';
export const rule = {
meta: {
type: 'suggestion',
docs: {
category: 'Operations',
description: 'Require fragments to be imported via an import expression.',
url: `https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/${RULE_ID}.md`,
examples: [
{
title: 'Incorrect',
code: /* GraphQL */ `
query {
user {
...UserFields
}
}
`,
},
{
title: 'Incorrect',
code: /* GraphQL */ `
# import 'post-fields.fragment.graphql'
query {
user {
...UserFields
}
}
`,
},
{
title: 'Incorrect',
code: /* GraphQL */ `
# import UserFields from 'post-fields.fragment.graphql'
query {
user {
...UserFields
}
}
`,
},
{
title: 'Correct',
code: /* GraphQL */ `
# import UserFields from 'user-fields.fragment.graphql'
query {
user {
...UserFields
}
}
`,
},
],
requiresSiblings: true,
isDisabledForAllConfig: true,
},
hasSuggestions: true,
messages: {
[RULE_ID]: 'Expected "{{fragmentName}}" fragment to be imported.',
[SUGGESTION_ID]: 'Add import expression for "{{fragmentName}}".',
},
schema: [],
},
create(context) {
const comments = context.getSourceCode().getAllComments();
const siblings = requireSiblingsOperations(RULE_ID, context);
const filePath = context.getFilename();
return {
'FragmentSpread > .name'(node) {
var _a;
const fragmentName = node.value;
const fragmentsFromSiblings = siblings.getFragment(fragmentName);
for (const comment of comments) {
if (comment.type !== 'Line')
continue;
// 1. could start with extra whitespace
// 2. match both named/default import
const isPossibleImported = new RegExp(`^\\s*import\\s+(${fragmentName}\\s+from\\s+)?['"]`).test(comment.value);
if (!isPossibleImported)
continue;
const extractedImportPath = (_a = comment.value.match(/(["'])((?:\1|.)*?)\1/)) === null || _a === void 0 ? void 0 : _a[2];
if (!extractedImportPath)
continue;
const importPath = path.join(path.dirname(filePath), extractedImportPath);
const hasInSiblings = fragmentsFromSiblings.some(source => source.filePath === importPath);
if (hasInSiblings)
return;
}
const fragmentInSameFile = fragmentsFromSiblings.some(source => source.filePath === filePath);
if (fragmentInSameFile)
return;
const suggestedFilePaths = fragmentsFromSiblings.length
? fragmentsFromSiblings.map(o => path.relative(path.dirname(filePath), o.filePath))
: ['CHANGE_ME.graphql'];
context.report({
node,
messageId: RULE_ID,
data: { fragmentName },
suggest: suggestedFilePaths.map(suggestedPath => ({
messageId: SUGGESTION_ID,
data: { fragmentName },
fix: fixer => fixer.insertTextBeforeRange([0, 0], `# import ${fragmentName} from '${suggestedPath}'\n`),
})),
});
},
};
},
};