@graphql-eslint/eslint-plugin
Version:
GraphQL plugin for ESLint
86 lines (85 loc) • 2.86 kB
JavaScript
import { ARRAY_DEFAULT_OPTIONS, pascalCase, getLocation } from '../utils.js';
const RULE_ID = 'lone-executable-definition';
const definitionTypes = ['fragment', 'query', 'mutation', 'subscription'];
const schema = {
type: 'array',
maxItems: 1,
items: {
type: 'object',
minProperties: 1,
additionalProperties: false,
properties: {
ignore: {
...ARRAY_DEFAULT_OPTIONS,
maxItems: 3,
items: {
enum: definitionTypes,
},
description: 'Allow certain definitions to be placed alongside others.',
},
},
},
};
export const rule = {
meta: {
type: 'suggestion',
docs: {
category: 'Operations',
description: 'Require queries, mutations, subscriptions or fragments to be located in separate files.',
url: `https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/${RULE_ID}.md`,
examples: [
{
title: 'Incorrect',
code: /* GraphQL */ `
query Foo {
id
}
fragment Bar on Baz {
id
}
`,
},
{
title: 'Correct',
code: /* GraphQL */ `
query Foo {
id
}
`,
},
],
},
messages: {
[RULE_ID]: '{{name}} should be in a separate file.',
},
schema,
},
create(context) {
var _a;
const ignore = new Set(((_a = context.options[0]) === null || _a === void 0 ? void 0 : _a.ignore) || []);
const definitions = [];
return {
':matches(OperationDefinition, FragmentDefinition)'(node) {
const type = 'operation' in node ? node.operation : 'fragment';
if (!ignore.has(type)) {
definitions.push({ type, node });
}
},
'Program:exit'() {
var _a, _b;
for (const { node, type } of definitions.slice(1) /* ignore first definition */) {
let name = pascalCase(type);
const definitionName = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value;
if (definitionName) {
name += ` "${definitionName}"`;
}
context.report({
loc: ((_b = node.name) === null || _b === void 0 ? void 0 : _b.loc) || getLocation(node.loc.start, type),
messageId: RULE_ID,
data: { name },
});
}
},
};
},
};