@graphql-eslint/eslint-plugin 3.2.0-alpha-2e742a6.0 → 3.2.0-alpha-4ca7218.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +56 -45
- package/index.mjs +56 -45
- package/package.json +10 -3
- package/types.d.ts +2 -2
package/index.js
CHANGED
@@ -334,7 +334,7 @@ function getLocation(loc, fieldName = '', offset) {
|
|
334
334
|
};
|
335
335
|
}
|
336
336
|
|
337
|
-
function
|
337
|
+
function validateDocument(sourceNode, context, schema, documentNode, rule) {
|
338
338
|
if (documentNode.definitions.length === 0) {
|
339
339
|
return;
|
340
340
|
}
|
@@ -365,9 +365,9 @@ const getFragmentDefsAndFragmentSpreads = (schema, node) => {
|
|
365
365
|
fragmentDefs.add(`${node.name.value}:${node.typeCondition.name.value}`);
|
366
366
|
},
|
367
367
|
FragmentSpread(node) {
|
368
|
-
const
|
369
|
-
if (
|
370
|
-
fragmentSpreads.add(`${node.name.value}:${
|
368
|
+
const parentType = typeInfo.getParentType();
|
369
|
+
if (parentType) {
|
370
|
+
fragmentSpreads.add(`${node.name.value}:${parentType.name}`);
|
371
371
|
}
|
372
372
|
},
|
373
373
|
});
|
@@ -378,56 +378,57 @@ const getMissingFragments = (schema, node) => {
|
|
378
378
|
const { fragmentDefs, fragmentSpreads } = getFragmentDefsAndFragmentSpreads(schema, node);
|
379
379
|
return [...fragmentSpreads].filter(name => !fragmentDefs.has(name));
|
380
380
|
};
|
381
|
-
const handleMissingFragments = ({
|
381
|
+
const handleMissingFragments = ({ ruleId, context, schema, node }) => {
|
382
382
|
const missingFragments = getMissingFragments(schema, node);
|
383
383
|
if (missingFragments.length > 0) {
|
384
384
|
const siblings = requireSiblingsOperations(ruleId, context);
|
385
385
|
const fragmentsToAdd = [];
|
386
386
|
for (const missingFragment of missingFragments) {
|
387
387
|
const [fragmentName, fragmentTypeName] = missingFragment.split(':');
|
388
|
-
const
|
388
|
+
const [foundFragment] = siblings
|
389
389
|
.getFragment(fragmentName)
|
390
390
|
.map(source => source.document)
|
391
391
|
.filter(fragment => fragment.typeCondition.name.value === fragmentTypeName);
|
392
|
-
if (
|
393
|
-
|
394
|
-
console.warn(`You have ${fragments.length} fragments that have same name ${fragmentName} and same type ${fragmentTypeName}. That can provoke unexpected result for "${ruleId}" rule.`);
|
392
|
+
if (foundFragment) {
|
393
|
+
fragmentsToAdd.push(foundFragment);
|
395
394
|
}
|
396
|
-
fragmentsToAdd.push(fragments[0]);
|
397
395
|
}
|
398
396
|
if (fragmentsToAdd.length > 0) {
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
397
|
+
// recall fn to make sure to add fragments inside fragments
|
398
|
+
return handleMissingFragments({
|
399
|
+
ruleId,
|
400
|
+
context,
|
401
|
+
schema,
|
402
|
+
node: {
|
403
|
+
kind: graphql.Kind.DOCUMENT,
|
404
|
+
definitions: [...node.definitions, ...fragmentsToAdd],
|
405
|
+
},
|
406
|
+
});
|
403
407
|
}
|
404
408
|
}
|
405
409
|
return node;
|
406
410
|
};
|
407
|
-
const validationToRule = (
|
408
|
-
var _a;
|
411
|
+
const validationToRule = (ruleId, ruleName, docs, getDocumentNode) => {
|
409
412
|
let ruleFn = null;
|
410
413
|
try {
|
411
414
|
ruleFn = require(`graphql/validation/rules/${ruleName}Rule`)[`${ruleName}Rule`];
|
412
415
|
}
|
413
|
-
catch (
|
416
|
+
catch (_a) {
|
414
417
|
try {
|
415
418
|
ruleFn = require(`graphql/validation/rules/${ruleName}`)[`${ruleName}Rule`];
|
416
419
|
}
|
417
|
-
catch (
|
420
|
+
catch (_b) {
|
418
421
|
ruleFn = require('graphql/validation')[`${ruleName}Rule`];
|
419
422
|
}
|
420
423
|
}
|
421
|
-
const requiresSchema = (_a = docs.requiresSchema) !== null && _a !== void 0 ? _a : true;
|
422
424
|
return {
|
423
|
-
[
|
425
|
+
[ruleId]: {
|
424
426
|
meta: {
|
425
427
|
docs: {
|
426
428
|
recommended: true,
|
427
429
|
...docs,
|
428
430
|
graphQLJSRuleName: ruleName,
|
429
|
-
|
430
|
-
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${name}.md`,
|
431
|
+
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${ruleId}.md`,
|
431
432
|
description: `${docs.description}\n\n> This rule is a wrapper around a \`graphql-js\` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/${ruleName}Rule.ts).`,
|
432
433
|
},
|
433
434
|
},
|
@@ -436,19 +437,14 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
|
|
436
437
|
Document(node) {
|
437
438
|
if (!ruleFn) {
|
438
439
|
// eslint-disable-next-line no-console
|
439
|
-
console.warn(`You rule "${
|
440
|
+
console.warn(`You rule "${ruleId}" depends on a GraphQL validation rule "${ruleName}" but it's not available in the "graphql-js" version you are using. Skipping...`);
|
440
441
|
return;
|
441
442
|
}
|
442
|
-
const schema = requiresSchema ? requireGraphQLSchemaFromContext(
|
443
|
-
const documentNode =
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
node: documentNode,
|
448
|
-
ruleId: name,
|
449
|
-
context,
|
450
|
-
})
|
451
|
-
: documentNode, ruleFn);
|
443
|
+
const schema = docs.requiresSchema ? requireGraphQLSchemaFromContext(ruleId, context) : null;
|
444
|
+
const documentNode = getDocumentNode
|
445
|
+
? getDocumentNode({ ruleId, context, schema, node: node.rawNode() })
|
446
|
+
: node.rawNode();
|
447
|
+
validateDocument(node, context, schema, documentNode, ruleFn);
|
452
448
|
},
|
453
449
|
};
|
454
450
|
},
|
@@ -458,21 +454,27 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
|
|
458
454
|
const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-definitions', 'ExecutableDefinitions', {
|
459
455
|
category: 'Operations',
|
460
456
|
description: `A GraphQL document is only valid for execution if all definitions are either operation or fragment definitions.`,
|
457
|
+
requiresSchema: true,
|
461
458
|
}), validationToRule('fields-on-correct-type', 'FieldsOnCorrectType', {
|
462
459
|
category: 'Operations',
|
463
460
|
description: 'A GraphQL document is only valid if all fields selected are defined by the parent type, or are an allowed meta field such as `__typename`.',
|
461
|
+
requiresSchema: true,
|
464
462
|
}), validationToRule('fragments-on-composite-type', 'FragmentsOnCompositeTypes', {
|
465
463
|
category: 'Operations',
|
466
464
|
description: `Fragments use a type condition to determine if they apply, since fragments can only be spread into a composite type (object, interface, or union), the type condition must also be a composite type.`,
|
465
|
+
requiresSchema: true,
|
467
466
|
}), validationToRule('known-argument-names', 'KnownArgumentNames', {
|
468
467
|
category: ['Schema', 'Operations'],
|
469
468
|
description: `A GraphQL field is only valid if all supplied arguments are defined by that field.`,
|
469
|
+
requiresSchema: true,
|
470
470
|
}), validationToRule('known-directives', 'KnownDirectives', {
|
471
471
|
category: ['Schema', 'Operations'],
|
472
472
|
description: `A GraphQL document is only valid if all \`@directives\` are known by the schema and legally positioned.`,
|
473
|
+
requiresSchema: true,
|
473
474
|
}), validationToRule('known-fragment-names', 'KnownFragmentNames', {
|
474
475
|
category: 'Operations',
|
475
476
|
description: `A GraphQL document is only valid if all \`...Fragment\` fragment spreads refer to fragments defined in the same document.`,
|
477
|
+
requiresSchema: true,
|
476
478
|
requiresSiblings: true,
|
477
479
|
examples: [
|
478
480
|
{
|
@@ -523,27 +525,31 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
523
525
|
}, handleMissingFragments), validationToRule('known-type-names', 'KnownTypeNames', {
|
524
526
|
category: ['Schema', 'Operations'],
|
525
527
|
description: `A GraphQL document is only valid if referenced types (specifically variable definitions and fragment conditions) are defined by the type schema.`,
|
528
|
+
requiresSchema: true,
|
526
529
|
}), validationToRule('lone-anonymous-operation', 'LoneAnonymousOperation', {
|
527
530
|
category: 'Operations',
|
528
531
|
description: `A GraphQL document is only valid if when it contains an anonymous operation (the query short-hand) that it contains only that one operation definition.`,
|
532
|
+
requiresSchema: true,
|
529
533
|
}), validationToRule('lone-schema-definition', 'LoneSchemaDefinition', {
|
530
534
|
category: 'Schema',
|
531
535
|
description: `A GraphQL document is only valid if it contains only one schema definition.`,
|
532
|
-
requiresSchema: false,
|
533
536
|
}), validationToRule('no-fragment-cycles', 'NoFragmentCycles', {
|
534
537
|
category: 'Operations',
|
535
538
|
description: `A GraphQL fragment is only valid when it does not have cycles in fragments usage.`,
|
539
|
+
requiresSchema: true,
|
536
540
|
}), validationToRule('no-undefined-variables', 'NoUndefinedVariables', {
|
537
541
|
category: 'Operations',
|
538
542
|
description: `A GraphQL operation is only valid if all variables encountered, both directly and via fragment spreads, are defined by that operation.`,
|
543
|
+
requiresSchema: true,
|
539
544
|
requiresSiblings: true,
|
540
545
|
}, handleMissingFragments), validationToRule('no-unused-fragments', 'NoUnusedFragments', {
|
541
546
|
category: 'Operations',
|
542
547
|
description: `A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations.`,
|
548
|
+
requiresSchema: true,
|
543
549
|
requiresSiblings: true,
|
544
|
-
}, ({
|
550
|
+
}, ({ ruleId, context, schema, node }) => {
|
545
551
|
const siblings = requireSiblingsOperations(ruleId, context);
|
546
|
-
const
|
552
|
+
const FilePathToDocumentsMap = [...siblings.getOperations(), ...siblings.getFragments()].reduce((map, { filePath, document }) => {
|
547
553
|
var _a;
|
548
554
|
(_a = map[filePath]) !== null && _a !== void 0 ? _a : (map[filePath] = []);
|
549
555
|
map[filePath].push(document);
|
@@ -555,8 +561,8 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
555
561
|
return node;
|
556
562
|
}
|
557
563
|
// skip iteration over documents for current filepath
|
558
|
-
delete
|
559
|
-
for (const [filePath, documents] of Object.entries(
|
564
|
+
delete FilePathToDocumentsMap[currentFilePath];
|
565
|
+
for (const [filePath, documents] of Object.entries(FilePathToDocumentsMap)) {
|
560
566
|
const missingFragments = getMissingFragments(schema, {
|
561
567
|
kind: graphql.Kind.DOCUMENT,
|
562
568
|
definitions: documents,
|
@@ -575,70 +581,75 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
575
581
|
}), validationToRule('no-unused-variables', 'NoUnusedVariables', {
|
576
582
|
category: 'Operations',
|
577
583
|
description: `A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment.`,
|
584
|
+
requiresSchema: true,
|
578
585
|
requiresSiblings: true,
|
579
586
|
}, handleMissingFragments), validationToRule('overlapping-fields-can-be-merged', 'OverlappingFieldsCanBeMerged', {
|
580
587
|
category: 'Operations',
|
581
588
|
description: `A selection set is only valid if all fields (including spreading any fragments) either correspond to distinct response names or can be merged without ambiguity.`,
|
589
|
+
requiresSchema: true,
|
582
590
|
}), validationToRule('possible-fragment-spread', 'PossibleFragmentSpreads', {
|
583
591
|
category: 'Operations',
|
584
592
|
description: `A fragment spread is only valid if the type condition could ever possibly be true: if there is a non-empty intersection of the possible parent types, and possible types which pass the type condition.`,
|
593
|
+
requiresSchema: true,
|
585
594
|
}), validationToRule('possible-type-extension', 'PossibleTypeExtensions', {
|
586
595
|
category: 'Schema',
|
587
596
|
description: `A type extension is only valid if the type is defined and has the same kind.`,
|
588
|
-
requiresSchema: false,
|
589
597
|
recommended: false, // TODO: enable after https://github.com/dotansimha/graphql-eslint/issues/787 will be fixed
|
590
598
|
}), validationToRule('provided-required-arguments', 'ProvidedRequiredArguments', {
|
591
599
|
category: ['Schema', 'Operations'],
|
592
600
|
description: `A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.`,
|
601
|
+
requiresSchema: true,
|
593
602
|
}), validationToRule('scalar-leafs', 'ScalarLeafs', {
|
594
603
|
category: 'Operations',
|
595
604
|
description: `A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.`,
|
605
|
+
requiresSchema: true,
|
596
606
|
}), validationToRule('one-field-subscriptions', 'SingleFieldSubscriptions', {
|
597
607
|
category: 'Operations',
|
598
608
|
description: `A GraphQL subscription is valid only if it contains a single root field.`,
|
609
|
+
requiresSchema: true,
|
599
610
|
}), validationToRule('unique-argument-names', 'UniqueArgumentNames', {
|
600
611
|
category: 'Operations',
|
601
612
|
description: `A GraphQL field or directive is only valid if all supplied arguments are uniquely named.`,
|
613
|
+
requiresSchema: true,
|
602
614
|
}), validationToRule('unique-directive-names', 'UniqueDirectiveNames', {
|
603
615
|
category: 'Schema',
|
604
616
|
description: `A GraphQL document is only valid if all defined directives have unique names.`,
|
605
|
-
requiresSchema: false,
|
606
617
|
}), validationToRule('unique-directive-names-per-location', 'UniqueDirectivesPerLocation', {
|
607
618
|
category: ['Schema', 'Operations'],
|
608
619
|
description: `A GraphQL document is only valid if all non-repeatable directives at a given location are uniquely named.`,
|
620
|
+
requiresSchema: true,
|
609
621
|
}), validationToRule('unique-enum-value-names', 'UniqueEnumValueNames', {
|
610
622
|
category: 'Schema',
|
611
623
|
description: `A GraphQL enum type is only valid if all its values are uniquely named.`,
|
612
|
-
requiresSchema: false,
|
613
624
|
recommended: false,
|
614
625
|
}), validationToRule('unique-field-definition-names', 'UniqueFieldDefinitionNames', {
|
615
626
|
category: 'Schema',
|
616
627
|
description: `A GraphQL complex type is only valid if all its fields are uniquely named.`,
|
617
|
-
requiresSchema: false,
|
618
628
|
}), validationToRule('unique-input-field-names', 'UniqueInputFieldNames', {
|
619
629
|
category: 'Operations',
|
620
630
|
description: `A GraphQL input object value is only valid if all supplied fields are uniquely named.`,
|
621
|
-
requiresSchema: false,
|
622
631
|
}), validationToRule('unique-operation-types', 'UniqueOperationTypes', {
|
623
632
|
category: 'Schema',
|
624
633
|
description: `A GraphQL document is only valid if it has only one type per operation.`,
|
625
|
-
requiresSchema: false,
|
626
634
|
}), validationToRule('unique-type-names', 'UniqueTypeNames', {
|
627
635
|
category: 'Schema',
|
628
636
|
description: `A GraphQL document is only valid if all defined types have unique names.`,
|
629
|
-
requiresSchema: false,
|
630
637
|
}), validationToRule('unique-variable-names', 'UniqueVariableNames', {
|
631
638
|
category: 'Operations',
|
632
639
|
description: `A GraphQL operation is only valid if all its variables are uniquely named.`,
|
640
|
+
requiresSchema: true,
|
633
641
|
}), validationToRule('value-literals-of-correct-type', 'ValuesOfCorrectType', {
|
634
642
|
category: 'Operations',
|
635
643
|
description: `A GraphQL document is only valid if all value literals are of the type expected at their position.`,
|
644
|
+
requiresSchema: true,
|
636
645
|
}), validationToRule('variables-are-input-types', 'VariablesAreInputTypes', {
|
637
646
|
category: 'Operations',
|
638
647
|
description: `A GraphQL operation is only valid if all the variables it defines are of input types (scalar, enum, or input object).`,
|
648
|
+
requiresSchema: true,
|
639
649
|
}), validationToRule('variables-in-allowed-position', 'VariablesInAllowedPosition', {
|
640
650
|
category: 'Operations',
|
641
651
|
description: `Variables passed to field arguments conform to type.`,
|
652
|
+
requiresSchema: true,
|
642
653
|
}));
|
643
654
|
|
644
655
|
const ALPHABETIZE = 'ALPHABETIZE';
|
package/index.mjs
CHANGED
@@ -328,7 +328,7 @@ function getLocation(loc, fieldName = '', offset) {
|
|
328
328
|
};
|
329
329
|
}
|
330
330
|
|
331
|
-
function
|
331
|
+
function validateDocument(sourceNode, context, schema, documentNode, rule) {
|
332
332
|
if (documentNode.definitions.length === 0) {
|
333
333
|
return;
|
334
334
|
}
|
@@ -359,9 +359,9 @@ const getFragmentDefsAndFragmentSpreads = (schema, node) => {
|
|
359
359
|
fragmentDefs.add(`${node.name.value}:${node.typeCondition.name.value}`);
|
360
360
|
},
|
361
361
|
FragmentSpread(node) {
|
362
|
-
const
|
363
|
-
if (
|
364
|
-
fragmentSpreads.add(`${node.name.value}:${
|
362
|
+
const parentType = typeInfo.getParentType();
|
363
|
+
if (parentType) {
|
364
|
+
fragmentSpreads.add(`${node.name.value}:${parentType.name}`);
|
365
365
|
}
|
366
366
|
},
|
367
367
|
});
|
@@ -372,56 +372,57 @@ const getMissingFragments = (schema, node) => {
|
|
372
372
|
const { fragmentDefs, fragmentSpreads } = getFragmentDefsAndFragmentSpreads(schema, node);
|
373
373
|
return [...fragmentSpreads].filter(name => !fragmentDefs.has(name));
|
374
374
|
};
|
375
|
-
const handleMissingFragments = ({
|
375
|
+
const handleMissingFragments = ({ ruleId, context, schema, node }) => {
|
376
376
|
const missingFragments = getMissingFragments(schema, node);
|
377
377
|
if (missingFragments.length > 0) {
|
378
378
|
const siblings = requireSiblingsOperations(ruleId, context);
|
379
379
|
const fragmentsToAdd = [];
|
380
380
|
for (const missingFragment of missingFragments) {
|
381
381
|
const [fragmentName, fragmentTypeName] = missingFragment.split(':');
|
382
|
-
const
|
382
|
+
const [foundFragment] = siblings
|
383
383
|
.getFragment(fragmentName)
|
384
384
|
.map(source => source.document)
|
385
385
|
.filter(fragment => fragment.typeCondition.name.value === fragmentTypeName);
|
386
|
-
if (
|
387
|
-
|
388
|
-
console.warn(`You have ${fragments.length} fragments that have same name ${fragmentName} and same type ${fragmentTypeName}. That can provoke unexpected result for "${ruleId}" rule.`);
|
386
|
+
if (foundFragment) {
|
387
|
+
fragmentsToAdd.push(foundFragment);
|
389
388
|
}
|
390
|
-
fragmentsToAdd.push(fragments[0]);
|
391
389
|
}
|
392
390
|
if (fragmentsToAdd.length > 0) {
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
391
|
+
// recall fn to make sure to add fragments inside fragments
|
392
|
+
return handleMissingFragments({
|
393
|
+
ruleId,
|
394
|
+
context,
|
395
|
+
schema,
|
396
|
+
node: {
|
397
|
+
kind: Kind.DOCUMENT,
|
398
|
+
definitions: [...node.definitions, ...fragmentsToAdd],
|
399
|
+
},
|
400
|
+
});
|
397
401
|
}
|
398
402
|
}
|
399
403
|
return node;
|
400
404
|
};
|
401
|
-
const validationToRule = (
|
402
|
-
var _a;
|
405
|
+
const validationToRule = (ruleId, ruleName, docs, getDocumentNode) => {
|
403
406
|
let ruleFn = null;
|
404
407
|
try {
|
405
408
|
ruleFn = require(`graphql/validation/rules/${ruleName}Rule`)[`${ruleName}Rule`];
|
406
409
|
}
|
407
|
-
catch (
|
410
|
+
catch (_a) {
|
408
411
|
try {
|
409
412
|
ruleFn = require(`graphql/validation/rules/${ruleName}`)[`${ruleName}Rule`];
|
410
413
|
}
|
411
|
-
catch (
|
414
|
+
catch (_b) {
|
412
415
|
ruleFn = require('graphql/validation')[`${ruleName}Rule`];
|
413
416
|
}
|
414
417
|
}
|
415
|
-
const requiresSchema = (_a = docs.requiresSchema) !== null && _a !== void 0 ? _a : true;
|
416
418
|
return {
|
417
|
-
[
|
419
|
+
[ruleId]: {
|
418
420
|
meta: {
|
419
421
|
docs: {
|
420
422
|
recommended: true,
|
421
423
|
...docs,
|
422
424
|
graphQLJSRuleName: ruleName,
|
423
|
-
|
424
|
-
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${name}.md`,
|
425
|
+
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${ruleId}.md`,
|
425
426
|
description: `${docs.description}\n\n> This rule is a wrapper around a \`graphql-js\` validation function. [You can find its source code here](https://github.com/graphql/graphql-js/blob/main/src/validation/rules/${ruleName}Rule.ts).`,
|
426
427
|
},
|
427
428
|
},
|
@@ -430,19 +431,14 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
|
|
430
431
|
Document(node) {
|
431
432
|
if (!ruleFn) {
|
432
433
|
// eslint-disable-next-line no-console
|
433
|
-
console.warn(`You rule "${
|
434
|
+
console.warn(`You rule "${ruleId}" depends on a GraphQL validation rule "${ruleName}" but it's not available in the "graphql-js" version you are using. Skipping...`);
|
434
435
|
return;
|
435
436
|
}
|
436
|
-
const schema = requiresSchema ? requireGraphQLSchemaFromContext(
|
437
|
-
const documentNode =
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
node: documentNode,
|
442
|
-
ruleId: name,
|
443
|
-
context,
|
444
|
-
})
|
445
|
-
: documentNode, ruleFn);
|
437
|
+
const schema = docs.requiresSchema ? requireGraphQLSchemaFromContext(ruleId, context) : null;
|
438
|
+
const documentNode = getDocumentNode
|
439
|
+
? getDocumentNode({ ruleId, context, schema, node: node.rawNode() })
|
440
|
+
: node.rawNode();
|
441
|
+
validateDocument(node, context, schema, documentNode, ruleFn);
|
446
442
|
},
|
447
443
|
};
|
448
444
|
},
|
@@ -452,21 +448,27 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
|
|
452
448
|
const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-definitions', 'ExecutableDefinitions', {
|
453
449
|
category: 'Operations',
|
454
450
|
description: `A GraphQL document is only valid for execution if all definitions are either operation or fragment definitions.`,
|
451
|
+
requiresSchema: true,
|
455
452
|
}), validationToRule('fields-on-correct-type', 'FieldsOnCorrectType', {
|
456
453
|
category: 'Operations',
|
457
454
|
description: 'A GraphQL document is only valid if all fields selected are defined by the parent type, or are an allowed meta field such as `__typename`.',
|
455
|
+
requiresSchema: true,
|
458
456
|
}), validationToRule('fragments-on-composite-type', 'FragmentsOnCompositeTypes', {
|
459
457
|
category: 'Operations',
|
460
458
|
description: `Fragments use a type condition to determine if they apply, since fragments can only be spread into a composite type (object, interface, or union), the type condition must also be a composite type.`,
|
459
|
+
requiresSchema: true,
|
461
460
|
}), validationToRule('known-argument-names', 'KnownArgumentNames', {
|
462
461
|
category: ['Schema', 'Operations'],
|
463
462
|
description: `A GraphQL field is only valid if all supplied arguments are defined by that field.`,
|
463
|
+
requiresSchema: true,
|
464
464
|
}), validationToRule('known-directives', 'KnownDirectives', {
|
465
465
|
category: ['Schema', 'Operations'],
|
466
466
|
description: `A GraphQL document is only valid if all \`@directives\` are known by the schema and legally positioned.`,
|
467
|
+
requiresSchema: true,
|
467
468
|
}), validationToRule('known-fragment-names', 'KnownFragmentNames', {
|
468
469
|
category: 'Operations',
|
469
470
|
description: `A GraphQL document is only valid if all \`...Fragment\` fragment spreads refer to fragments defined in the same document.`,
|
471
|
+
requiresSchema: true,
|
470
472
|
requiresSiblings: true,
|
471
473
|
examples: [
|
472
474
|
{
|
@@ -517,27 +519,31 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
517
519
|
}, handleMissingFragments), validationToRule('known-type-names', 'KnownTypeNames', {
|
518
520
|
category: ['Schema', 'Operations'],
|
519
521
|
description: `A GraphQL document is only valid if referenced types (specifically variable definitions and fragment conditions) are defined by the type schema.`,
|
522
|
+
requiresSchema: true,
|
520
523
|
}), validationToRule('lone-anonymous-operation', 'LoneAnonymousOperation', {
|
521
524
|
category: 'Operations',
|
522
525
|
description: `A GraphQL document is only valid if when it contains an anonymous operation (the query short-hand) that it contains only that one operation definition.`,
|
526
|
+
requiresSchema: true,
|
523
527
|
}), validationToRule('lone-schema-definition', 'LoneSchemaDefinition', {
|
524
528
|
category: 'Schema',
|
525
529
|
description: `A GraphQL document is only valid if it contains only one schema definition.`,
|
526
|
-
requiresSchema: false,
|
527
530
|
}), validationToRule('no-fragment-cycles', 'NoFragmentCycles', {
|
528
531
|
category: 'Operations',
|
529
532
|
description: `A GraphQL fragment is only valid when it does not have cycles in fragments usage.`,
|
533
|
+
requiresSchema: true,
|
530
534
|
}), validationToRule('no-undefined-variables', 'NoUndefinedVariables', {
|
531
535
|
category: 'Operations',
|
532
536
|
description: `A GraphQL operation is only valid if all variables encountered, both directly and via fragment spreads, are defined by that operation.`,
|
537
|
+
requiresSchema: true,
|
533
538
|
requiresSiblings: true,
|
534
539
|
}, handleMissingFragments), validationToRule('no-unused-fragments', 'NoUnusedFragments', {
|
535
540
|
category: 'Operations',
|
536
541
|
description: `A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations.`,
|
542
|
+
requiresSchema: true,
|
537
543
|
requiresSiblings: true,
|
538
|
-
}, ({
|
544
|
+
}, ({ ruleId, context, schema, node }) => {
|
539
545
|
const siblings = requireSiblingsOperations(ruleId, context);
|
540
|
-
const
|
546
|
+
const FilePathToDocumentsMap = [...siblings.getOperations(), ...siblings.getFragments()].reduce((map, { filePath, document }) => {
|
541
547
|
var _a;
|
542
548
|
(_a = map[filePath]) !== null && _a !== void 0 ? _a : (map[filePath] = []);
|
543
549
|
map[filePath].push(document);
|
@@ -549,8 +555,8 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
549
555
|
return node;
|
550
556
|
}
|
551
557
|
// skip iteration over documents for current filepath
|
552
|
-
delete
|
553
|
-
for (const [filePath, documents] of Object.entries(
|
558
|
+
delete FilePathToDocumentsMap[currentFilePath];
|
559
|
+
for (const [filePath, documents] of Object.entries(FilePathToDocumentsMap)) {
|
554
560
|
const missingFragments = getMissingFragments(schema, {
|
555
561
|
kind: Kind.DOCUMENT,
|
556
562
|
definitions: documents,
|
@@ -569,70 +575,75 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
|
|
569
575
|
}), validationToRule('no-unused-variables', 'NoUnusedVariables', {
|
570
576
|
category: 'Operations',
|
571
577
|
description: `A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment.`,
|
578
|
+
requiresSchema: true,
|
572
579
|
requiresSiblings: true,
|
573
580
|
}, handleMissingFragments), validationToRule('overlapping-fields-can-be-merged', 'OverlappingFieldsCanBeMerged', {
|
574
581
|
category: 'Operations',
|
575
582
|
description: `A selection set is only valid if all fields (including spreading any fragments) either correspond to distinct response names or can be merged without ambiguity.`,
|
583
|
+
requiresSchema: true,
|
576
584
|
}), validationToRule('possible-fragment-spread', 'PossibleFragmentSpreads', {
|
577
585
|
category: 'Operations',
|
578
586
|
description: `A fragment spread is only valid if the type condition could ever possibly be true: if there is a non-empty intersection of the possible parent types, and possible types which pass the type condition.`,
|
587
|
+
requiresSchema: true,
|
579
588
|
}), validationToRule('possible-type-extension', 'PossibleTypeExtensions', {
|
580
589
|
category: 'Schema',
|
581
590
|
description: `A type extension is only valid if the type is defined and has the same kind.`,
|
582
|
-
requiresSchema: false,
|
583
591
|
recommended: false, // TODO: enable after https://github.com/dotansimha/graphql-eslint/issues/787 will be fixed
|
584
592
|
}), validationToRule('provided-required-arguments', 'ProvidedRequiredArguments', {
|
585
593
|
category: ['Schema', 'Operations'],
|
586
594
|
description: `A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.`,
|
595
|
+
requiresSchema: true,
|
587
596
|
}), validationToRule('scalar-leafs', 'ScalarLeafs', {
|
588
597
|
category: 'Operations',
|
589
598
|
description: `A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.`,
|
599
|
+
requiresSchema: true,
|
590
600
|
}), validationToRule('one-field-subscriptions', 'SingleFieldSubscriptions', {
|
591
601
|
category: 'Operations',
|
592
602
|
description: `A GraphQL subscription is valid only if it contains a single root field.`,
|
603
|
+
requiresSchema: true,
|
593
604
|
}), validationToRule('unique-argument-names', 'UniqueArgumentNames', {
|
594
605
|
category: 'Operations',
|
595
606
|
description: `A GraphQL field or directive is only valid if all supplied arguments are uniquely named.`,
|
607
|
+
requiresSchema: true,
|
596
608
|
}), validationToRule('unique-directive-names', 'UniqueDirectiveNames', {
|
597
609
|
category: 'Schema',
|
598
610
|
description: `A GraphQL document is only valid if all defined directives have unique names.`,
|
599
|
-
requiresSchema: false,
|
600
611
|
}), validationToRule('unique-directive-names-per-location', 'UniqueDirectivesPerLocation', {
|
601
612
|
category: ['Schema', 'Operations'],
|
602
613
|
description: `A GraphQL document is only valid if all non-repeatable directives at a given location are uniquely named.`,
|
614
|
+
requiresSchema: true,
|
603
615
|
}), validationToRule('unique-enum-value-names', 'UniqueEnumValueNames', {
|
604
616
|
category: 'Schema',
|
605
617
|
description: `A GraphQL enum type is only valid if all its values are uniquely named.`,
|
606
|
-
requiresSchema: false,
|
607
618
|
recommended: false,
|
608
619
|
}), validationToRule('unique-field-definition-names', 'UniqueFieldDefinitionNames', {
|
609
620
|
category: 'Schema',
|
610
621
|
description: `A GraphQL complex type is only valid if all its fields are uniquely named.`,
|
611
|
-
requiresSchema: false,
|
612
622
|
}), validationToRule('unique-input-field-names', 'UniqueInputFieldNames', {
|
613
623
|
category: 'Operations',
|
614
624
|
description: `A GraphQL input object value is only valid if all supplied fields are uniquely named.`,
|
615
|
-
requiresSchema: false,
|
616
625
|
}), validationToRule('unique-operation-types', 'UniqueOperationTypes', {
|
617
626
|
category: 'Schema',
|
618
627
|
description: `A GraphQL document is only valid if it has only one type per operation.`,
|
619
|
-
requiresSchema: false,
|
620
628
|
}), validationToRule('unique-type-names', 'UniqueTypeNames', {
|
621
629
|
category: 'Schema',
|
622
630
|
description: `A GraphQL document is only valid if all defined types have unique names.`,
|
623
|
-
requiresSchema: false,
|
624
631
|
}), validationToRule('unique-variable-names', 'UniqueVariableNames', {
|
625
632
|
category: 'Operations',
|
626
633
|
description: `A GraphQL operation is only valid if all its variables are uniquely named.`,
|
634
|
+
requiresSchema: true,
|
627
635
|
}), validationToRule('value-literals-of-correct-type', 'ValuesOfCorrectType', {
|
628
636
|
category: 'Operations',
|
629
637
|
description: `A GraphQL document is only valid if all value literals are of the type expected at their position.`,
|
638
|
+
requiresSchema: true,
|
630
639
|
}), validationToRule('variables-are-input-types', 'VariablesAreInputTypes', {
|
631
640
|
category: 'Operations',
|
632
641
|
description: `A GraphQL operation is only valid if all the variables it defines are of input types (scalar, enum, or input object).`,
|
642
|
+
requiresSchema: true,
|
633
643
|
}), validationToRule('variables-in-allowed-position', 'VariablesInAllowedPosition', {
|
634
644
|
category: 'Operations',
|
635
645
|
description: `Variables passed to field arguments conform to type.`,
|
646
|
+
requiresSchema: true,
|
636
647
|
}));
|
637
648
|
|
638
649
|
const ALPHABETIZE = 'ALPHABETIZE';
|
package/package.json
CHANGED
@@ -1,20 +1,27 @@
|
|
1
1
|
{
|
2
2
|
"name": "@graphql-eslint/eslint-plugin",
|
3
|
-
"version": "3.2.0-alpha-
|
3
|
+
"version": "3.2.0-alpha-4ca7218.0",
|
4
|
+
"description": "GraphQL plugin for ESLint",
|
4
5
|
"sideEffects": false,
|
5
6
|
"peerDependencies": {
|
6
7
|
"graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
|
7
8
|
},
|
8
9
|
"dependencies": {
|
9
10
|
"@babel/code-frame": "7.16.0",
|
10
|
-
"@graphql-tools/code-file-loader": "7.2.
|
11
|
+
"@graphql-tools/code-file-loader": "7.2.3",
|
11
12
|
"@graphql-tools/graphql-tag-pluck": "7.1.4",
|
12
|
-
"@graphql-tools/utils": "8.5.
|
13
|
+
"@graphql-tools/utils": "8.5.4",
|
13
14
|
"graphql-config": "4.1.0",
|
14
15
|
"graphql-depth-limit": "1.1.0",
|
15
16
|
"lodash.lowercase": "4.3.0"
|
16
17
|
},
|
17
18
|
"repository": "https://github.com/dotansimha/graphql-eslint",
|
19
|
+
"keywords": [
|
20
|
+
"eslint",
|
21
|
+
"eslintplugin",
|
22
|
+
"eslint-plugin",
|
23
|
+
"graphql"
|
24
|
+
],
|
18
25
|
"author": "Dotan Simha <dotansimha@gmail.com>",
|
19
26
|
"license": "MIT",
|
20
27
|
"main": "index.js",
|
package/types.d.ts
CHANGED
@@ -49,8 +49,8 @@ export declare type CategoryType = 'Schema' | 'Operations';
|
|
49
49
|
export declare type RuleDocsInfo<T> = {
|
50
50
|
docs: Omit<Rule.RuleMetaData['docs'], 'category'> & {
|
51
51
|
category: CategoryType | CategoryType[];
|
52
|
-
requiresSchema?:
|
53
|
-
requiresSiblings?:
|
52
|
+
requiresSchema?: true;
|
53
|
+
requiresSiblings?: true;
|
54
54
|
examples?: {
|
55
55
|
title: string;
|
56
56
|
code: string;
|