@graphql-eslint/eslint-plugin 4.3.0 → 4.4.0-alpha-20241207210859-41eb4549764dc0314b5bd4f257ea6667b178540e
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/cjs/cache.js +6 -2
- package/cjs/configs/operations-all.js +2 -2
- package/cjs/configs/schema-all.js +2 -2
- package/cjs/configs/schema-recommended.js +1 -1
- package/cjs/documents.js +13 -7
- package/cjs/estree-converter/converter.js +17 -8
- package/cjs/estree-converter/utils.js +22 -9
- package/cjs/graphql-config.js +13 -6
- package/cjs/index.d.cts +18 -4
- package/cjs/meta.js +1 -1
- package/cjs/parser.js +36 -9
- package/cjs/processor.js +48 -20
- package/cjs/rules/alphabetize/index.js +99 -47
- package/cjs/rules/description-style/index.js +10 -6
- package/cjs/rules/graphql-js-validation.js +142 -108
- package/cjs/rules/index.d.cts +18 -4
- package/cjs/rules/input-name/index.js +51 -38
- package/cjs/rules/lone-executable-definition/index.js +15 -6
- package/cjs/rules/match-document-filename/index.d.cts +4 -3
- package/cjs/rules/match-document-filename/index.js +63 -37
- package/cjs/rules/naming-convention/index.d.cts +6 -10
- package/cjs/rules/naming-convention/index.js +179 -82
- package/cjs/rules/no-anonymous-operations/index.js +8 -5
- package/cjs/rules/no-deprecated/index.js +27 -13
- package/cjs/rules/no-duplicate-fields/index.js +15 -8
- package/cjs/rules/no-hashtag-description/index.js +18 -10
- package/cjs/rules/no-one-place-fragments/index.js +17 -10
- package/cjs/rules/no-root-type/index.js +15 -8
- package/cjs/rules/no-scalar-result-type-on-mutation/index.js +20 -12
- package/cjs/rules/no-typename-prefix/index.js +25 -21
- package/cjs/rules/no-unreachable-types/index.js +34 -17
- package/cjs/rules/no-unused-fields/index.js +56 -30
- package/cjs/rules/relay-arguments/index.js +31 -13
- package/cjs/rules/relay-connection-types/index.js +31 -9
- package/cjs/rules/relay-edge-types/index.js +84 -41
- package/cjs/rules/relay-page-info/index.js +31 -14
- package/cjs/rules/require-deprecation-date/index.js +20 -9
- package/cjs/rules/require-deprecation-reason/index.js +8 -5
- package/cjs/rules/require-description/index.d.cts +79 -13
- package/cjs/rules/require-description/index.js +67 -49
- package/cjs/rules/require-field-of-type-query-in-mutation-result/index.js +21 -10
- package/cjs/rules/require-import-fragment/index.js +20 -11
- package/cjs/rules/require-nullable-fields-with-oneof/index.js +12 -5
- package/cjs/rules/require-nullable-result-in-root/index.js +32 -27
- package/cjs/rules/require-selections/index.js +88 -46
- package/cjs/rules/require-type-pattern-with-oneof/index.js +14 -10
- package/cjs/rules/selection-set-depth/index.js +19 -10
- package/cjs/rules/strict-id-in-types/index.js +32 -19
- package/cjs/rules/unique-enum-value-names/index.js +4 -3
- package/cjs/rules/unique-fragment-name/index.js +25 -18
- package/cjs/rules/unique-operation-name/index.js +5 -5
- package/cjs/schema.js +14 -8
- package/cjs/siblings.js +60 -32
- package/cjs/utils.js +23 -9
- package/esm/cache.js +6 -2
- package/esm/configs/operations-all.js +2 -2
- package/esm/configs/schema-all.js +2 -2
- package/esm/configs/schema-recommended.js +1 -1
- package/esm/documents.js +13 -7
- package/esm/estree-converter/converter.js +17 -8
- package/esm/estree-converter/utils.js +22 -9
- package/esm/graphql-config.js +13 -6
- package/esm/index.d.ts +18 -4
- package/esm/meta.js +1 -1
- package/esm/parser.js +36 -9
- package/esm/processor.js +48 -20
- package/esm/rules/alphabetize/index.js +99 -47
- package/esm/rules/description-style/index.js +10 -6
- package/esm/rules/graphql-js-validation.js +142 -108
- package/esm/rules/index.d.ts +18 -4
- package/esm/rules/input-name/index.js +51 -38
- package/esm/rules/lone-executable-definition/index.js +15 -6
- package/esm/rules/match-document-filename/index.d.ts +4 -3
- package/esm/rules/match-document-filename/index.js +63 -37
- package/esm/rules/naming-convention/index.d.ts +6 -10
- package/esm/rules/naming-convention/index.js +179 -82
- package/esm/rules/no-anonymous-operations/index.js +8 -5
- package/esm/rules/no-deprecated/index.js +27 -13
- package/esm/rules/no-duplicate-fields/index.js +15 -8
- package/esm/rules/no-hashtag-description/index.js +18 -10
- package/esm/rules/no-one-place-fragments/index.js +17 -10
- package/esm/rules/no-root-type/index.js +15 -8
- package/esm/rules/no-scalar-result-type-on-mutation/index.js +20 -12
- package/esm/rules/no-typename-prefix/index.js +25 -21
- package/esm/rules/no-unreachable-types/index.js +34 -17
- package/esm/rules/no-unused-fields/index.js +56 -30
- package/esm/rules/relay-arguments/index.js +31 -13
- package/esm/rules/relay-connection-types/index.js +31 -9
- package/esm/rules/relay-edge-types/index.js +84 -41
- package/esm/rules/relay-page-info/index.js +31 -14
- package/esm/rules/require-deprecation-date/index.js +20 -9
- package/esm/rules/require-deprecation-reason/index.js +8 -5
- package/esm/rules/require-description/index.d.ts +79 -13
- package/esm/rules/require-description/index.js +67 -49
- package/esm/rules/require-field-of-type-query-in-mutation-result/index.js +21 -10
- package/esm/rules/require-import-fragment/index.js +20 -11
- package/esm/rules/require-nullable-fields-with-oneof/index.js +12 -5
- package/esm/rules/require-nullable-result-in-root/index.js +32 -27
- package/esm/rules/require-selections/index.js +88 -46
- package/esm/rules/require-type-pattern-with-oneof/index.js +14 -10
- package/esm/rules/selection-set-depth/index.js +19 -10
- package/esm/rules/strict-id-in-types/index.js +32 -19
- package/esm/rules/unique-enum-value-names/index.js +4 -3
- package/esm/rules/unique-fragment-name/index.js +25 -18
- package/esm/rules/unique-operation-name/index.js +5 -5
- package/esm/schema.js +15 -8
- package/esm/siblings.js +60 -32
- package/esm/utils.js +23 -9
- package/index.browser.js +1871 -1160
- package/package.json +1 -1
package/cjs/siblings.js
CHANGED
@@ -6,12 +6,18 @@ var _utilsjs = require('./utils.js');
|
|
6
6
|
const siblingOperationsCache = /* @__PURE__ */ new Map();
|
7
7
|
function getSiblings(documents) {
|
8
8
|
if (documents.length === 0) {
|
9
|
-
let printed =
|
10
|
-
const noopWarn = () =>
|
11
|
-
|
12
|
-
|
9
|
+
let printed = false;
|
10
|
+
const noopWarn = () => {
|
11
|
+
if (!printed) {
|
12
|
+
_utilsjs.logger.warn(
|
13
|
+
"getSiblingOperations was called without any operations. Make sure to set graphql-config `documents` field to make this feature available! See https://the-guild.dev/graphql/config/docs/user/documents for more info"
|
14
|
+
);
|
15
|
+
printed = true;
|
16
|
+
}
|
17
|
+
return [];
|
18
|
+
};
|
13
19
|
return {
|
14
|
-
available:
|
20
|
+
available: false,
|
15
21
|
getFragment: noopWarn,
|
16
22
|
getFragments: noopWarn,
|
17
23
|
getFragmentByType: noopWarn,
|
@@ -22,18 +28,23 @@ function getSiblings(documents) {
|
|
22
28
|
};
|
23
29
|
}
|
24
30
|
const value = siblingOperationsCache.get(documents);
|
25
|
-
if (value)
|
31
|
+
if (value) {
|
26
32
|
return value;
|
33
|
+
}
|
27
34
|
let fragmentsCache = null;
|
28
35
|
const getFragments = () => {
|
29
36
|
if (fragmentsCache === null) {
|
30
37
|
const result = [];
|
31
|
-
for (const source of documents)
|
32
|
-
for (const definition of _optionalChain([source, 'access', _ => _.document, 'optionalAccess', _2 => _2.definitions]) || [])
|
33
|
-
definition.kind === _graphql.Kind.FRAGMENT_DEFINITION
|
34
|
-
|
35
|
-
|
36
|
-
|
38
|
+
for (const source of documents) {
|
39
|
+
for (const definition of _optionalChain([source, 'access', _ => _.document, 'optionalAccess', _2 => _2.definitions]) || []) {
|
40
|
+
if (definition.kind === _graphql.Kind.FRAGMENT_DEFINITION) {
|
41
|
+
result.push({
|
42
|
+
filePath: source.location,
|
43
|
+
document: definition
|
44
|
+
});
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
37
48
|
fragmentsCache = result;
|
38
49
|
}
|
39
50
|
return fragmentsCache;
|
@@ -42,37 +53,54 @@ function getSiblings(documents) {
|
|
42
53
|
const getOperations = () => {
|
43
54
|
if (cachedOperations === null) {
|
44
55
|
const result = [];
|
45
|
-
for (const source of documents)
|
46
|
-
for (const definition of _optionalChain([source, 'access', _3 => _3.document, 'optionalAccess', _4 => _4.definitions]) || [])
|
47
|
-
definition.kind === _graphql.Kind.OPERATION_DEFINITION
|
48
|
-
|
49
|
-
|
50
|
-
|
56
|
+
for (const source of documents) {
|
57
|
+
for (const definition of _optionalChain([source, 'access', _3 => _3.document, 'optionalAccess', _4 => _4.definitions]) || []) {
|
58
|
+
if (definition.kind === _graphql.Kind.OPERATION_DEFINITION) {
|
59
|
+
result.push({
|
60
|
+
filePath: source.location,
|
61
|
+
document: definition
|
62
|
+
});
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
51
66
|
cachedOperations = result;
|
52
67
|
}
|
53
68
|
return cachedOperations;
|
54
|
-
}
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
);
|
61
|
-
|
69
|
+
};
|
70
|
+
const getFragment = (name) => getFragments().filter((f) => f.document.name.value === name);
|
71
|
+
const collectFragments = (selectable, recursive, collected = /* @__PURE__ */ new Map()) => {
|
72
|
+
_graphql.visit.call(void 0, selectable, {
|
73
|
+
FragmentSpread(spread) {
|
74
|
+
const fragmentName = spread.name.value;
|
75
|
+
const [fragment] = getFragment(fragmentName);
|
76
|
+
if (!fragment) {
|
77
|
+
_utilsjs.logger.warn(
|
78
|
+
`Unable to locate fragment named "${fragmentName}", please make sure it's loaded using "parserOptions.operations"`
|
79
|
+
);
|
80
|
+
return;
|
81
|
+
}
|
82
|
+
if (!collected.has(fragmentName)) {
|
83
|
+
collected.set(fragmentName, fragment.document);
|
84
|
+
if (recursive) {
|
85
|
+
collectFragments(fragment.document, recursive, collected);
|
86
|
+
}
|
87
|
+
}
|
62
88
|
}
|
63
|
-
|
64
|
-
|
65
|
-
}
|
66
|
-
|
89
|
+
});
|
90
|
+
return collected;
|
91
|
+
};
|
92
|
+
const siblingOperations = {
|
93
|
+
available: true,
|
67
94
|
getFragment,
|
68
95
|
getFragments,
|
69
96
|
getFragmentByType: (typeName) => getFragments().filter((f) => f.document.typeCondition.name.value === typeName),
|
70
|
-
getFragmentsInUse: (selectable, recursive =
|
97
|
+
getFragmentsInUse: (selectable, recursive = true) => Array.from(collectFragments(selectable, recursive).values()),
|
71
98
|
getOperation: (name) => getOperations().filter((o) => _optionalChain([o, 'access', _5 => _5.document, 'access', _6 => _6.name, 'optionalAccess', _7 => _7.value]) === name),
|
72
99
|
getOperations,
|
73
100
|
getOperationByType: (type) => getOperations().filter((o) => o.document.operation === type)
|
74
101
|
};
|
75
|
-
|
102
|
+
siblingOperationsCache.set(documents, siblingOperations);
|
103
|
+
return siblingOperations;
|
76
104
|
}
|
77
105
|
|
78
106
|
|
package/cjs/utils.js
CHANGED
@@ -2,24 +2,27 @@
|
|
2
2
|
var _lodashlowercase = require('lodash.lowercase'); var _lodashlowercase2 = _interopRequireDefault(_lodashlowercase);
|
3
3
|
function requireGraphQLOperations(ruleId, context) {
|
4
4
|
const { siblingOperations } = context.sourceCode.parserServices;
|
5
|
-
if (!siblingOperations.available)
|
5
|
+
if (!siblingOperations.available) {
|
6
6
|
throw new Error(
|
7
7
|
`Rule \`${ruleId}\` requires graphql-config \`documents\` field to be set and loaded. See https://the-guild.dev/graphql/eslint/docs/usage#providing-operations for more info`
|
8
8
|
);
|
9
|
+
}
|
9
10
|
return siblingOperations;
|
10
11
|
}
|
11
12
|
function requireGraphQLSchema(ruleId, context) {
|
12
13
|
const { schema } = context.sourceCode.parserServices;
|
13
|
-
if (!schema)
|
14
|
+
if (!schema) {
|
14
15
|
throw new Error(
|
15
16
|
`Rule \`${ruleId}\` requires graphql-config \`schema\` field to be set and loaded. See https://the-guild.dev/graphql/eslint/docs/usage#providing-schema for more info`
|
16
17
|
);
|
18
|
+
}
|
17
19
|
return schema;
|
18
20
|
}
|
19
21
|
const chalk = {
|
20
22
|
red: (str) => `\x1B[31m${str}\x1B[39m`,
|
21
23
|
yellow: (str) => `\x1B[33m${str}\x1B[39m`
|
22
|
-
}
|
24
|
+
};
|
25
|
+
const logger = {
|
23
26
|
error: (...args) => (
|
24
27
|
// eslint-disable-next-line no-console
|
25
28
|
console.error(chalk.red("error"), "[graphql-eslint]", ...args)
|
@@ -28,17 +31,25 @@ const chalk = {
|
|
28
31
|
// eslint-disable-next-line no-console
|
29
32
|
console.warn(chalk.yellow("warning"), "[graphql-eslint]", ...args)
|
30
33
|
)
|
31
|
-
}
|
34
|
+
};
|
35
|
+
const slash = (path) => path.replaceAll("\\", "/");
|
36
|
+
const VIRTUAL_DOCUMENT_REGEX = /[/\\]\d+_document.graphql$/;
|
37
|
+
const CWD = process.cwd();
|
38
|
+
const getTypeName = (node) => "type" in node ? getTypeName(node.type) : "name" in node && node.name ? node.name.value : "";
|
39
|
+
const TYPES_KINDS = [
|
32
40
|
_graphql.Kind.OBJECT_TYPE_DEFINITION,
|
33
41
|
_graphql.Kind.INTERFACE_TYPE_DEFINITION,
|
34
42
|
_graphql.Kind.ENUM_TYPE_DEFINITION,
|
35
43
|
_graphql.Kind.SCALAR_TYPE_DEFINITION,
|
36
44
|
_graphql.Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
37
45
|
_graphql.Kind.UNION_TYPE_DEFINITION
|
38
|
-
]
|
46
|
+
];
|
47
|
+
const pascalCase = (str) => _lodashlowercase2.default.call(void 0, str).split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
48
|
+
const camelCase = (str) => {
|
39
49
|
const result = pascalCase(str);
|
40
50
|
return result.charAt(0).toLowerCase() + result.slice(1);
|
41
|
-
}
|
51
|
+
};
|
52
|
+
const convertCase = (style, str) => {
|
42
53
|
switch (style) {
|
43
54
|
case "camelCase":
|
44
55
|
return camelCase(str);
|
@@ -65,14 +76,17 @@ function getLocation(start, fieldName = "") {
|
|
65
76
|
}
|
66
77
|
};
|
67
78
|
}
|
68
|
-
const REPORT_ON_FIRST_CHARACTER = { column: 0, line: 1 }
|
79
|
+
const REPORT_ON_FIRST_CHARACTER = { column: 0, line: 1 };
|
80
|
+
const ARRAY_DEFAULT_OPTIONS = {
|
69
81
|
type: "array",
|
70
|
-
uniqueItems:
|
82
|
+
uniqueItems: true,
|
71
83
|
minItems: 1,
|
72
84
|
items: {
|
73
85
|
type: "string"
|
74
86
|
}
|
75
|
-
}
|
87
|
+
};
|
88
|
+
const englishJoinWords = (words) => new Intl.ListFormat("en-US", { type: "disjunction" }).format(words);
|
89
|
+
const DisplayNodeNameMap = {
|
76
90
|
[_graphql.Kind.ARGUMENT]: "argument",
|
77
91
|
[_graphql.Kind.BOOLEAN]: "boolean",
|
78
92
|
[_graphql.Kind.DIRECTIVE_DEFINITION]: "directive",
|
package/esm/cache.js
CHANGED
@@ -3,20 +3,24 @@ const log = debugFactory("graphql-eslint:ModuleCache");
|
|
3
3
|
class ModuleCache {
|
4
4
|
map = /* @__PURE__ */ new Map();
|
5
5
|
set(cacheKey, result) {
|
6
|
-
|
6
|
+
if (false) return;
|
7
|
+
this.map.set(cacheKey, { lastSeen: process.hrtime(), result });
|
8
|
+
log("setting entry for", cacheKey);
|
7
9
|
}
|
8
10
|
get(cacheKey, settings = {
|
9
11
|
lifetime: 10
|
10
12
|
/* seconds */
|
11
13
|
}) {
|
14
|
+
if (false) return;
|
12
15
|
const value = this.map.get(cacheKey);
|
13
16
|
if (!value) {
|
14
17
|
log("cache miss for", cacheKey);
|
15
18
|
return;
|
16
19
|
}
|
17
20
|
const { lastSeen, result } = value;
|
18
|
-
if (process.env.NODE || process.hrtime(lastSeen)[0] < settings.lifetime)
|
21
|
+
if (process.env.NODE || process.hrtime(lastSeen)[0] < settings.lifetime) {
|
19
22
|
return result;
|
23
|
+
}
|
20
24
|
}
|
21
25
|
}
|
22
26
|
export {
|
@@ -4,9 +4,9 @@ var operations_all_default = {
|
|
4
4
|
"@graphql-eslint/alphabetize": [
|
5
5
|
"error",
|
6
6
|
{
|
7
|
-
definitions:
|
7
|
+
definitions: true,
|
8
8
|
selections: ["OperationDefinition", "FragmentDefinition"],
|
9
|
-
variables:
|
9
|
+
variables: true,
|
10
10
|
arguments: ["Field", "Directive"],
|
11
11
|
groups: ["...", "id", "*", "{"]
|
12
12
|
}
|
@@ -4,9 +4,9 @@ var schema_all_default = {
|
|
4
4
|
"@graphql-eslint/alphabetize": [
|
5
5
|
"error",
|
6
6
|
{
|
7
|
-
definitions:
|
7
|
+
definitions: true,
|
8
8
|
fields: ["ObjectTypeDefinition", "InterfaceTypeDefinition", "InputObjectTypeDefinition"],
|
9
|
-
values:
|
9
|
+
values: true,
|
10
10
|
arguments: ["FieldDefinition", "Field", "DirectiveDefinition", "Directive"],
|
11
11
|
groups: ["id", "*", "createdAt", "updatedAt"]
|
12
12
|
}
|
@@ -54,7 +54,7 @@ var schema_recommended_default = {
|
|
54
54
|
"@graphql-eslint/require-deprecation-reason": "error",
|
55
55
|
"@graphql-eslint/require-description": [
|
56
56
|
"error",
|
57
|
-
{ types:
|
57
|
+
{ types: true, DirectiveDefinition: true, rootField: true }
|
58
58
|
],
|
59
59
|
"@graphql-eslint/strict-id-in-types": "error",
|
60
60
|
"@graphql-eslint/unique-directive-names": "error",
|
package/esm/documents.js
CHANGED
@@ -2,17 +2,20 @@ import path from "node:path";
|
|
2
2
|
import debugFactory from "debug";
|
3
3
|
import fg from "fast-glob";
|
4
4
|
import { ModuleCache } from "./cache.js";
|
5
|
-
const debug = debugFactory("graphql-eslint:operations")
|
5
|
+
const debug = debugFactory("graphql-eslint:operations");
|
6
|
+
const operationsCache = new ModuleCache();
|
7
|
+
const handleVirtualPath = (documents) => {
|
6
8
|
const filepathMap = /* @__PURE__ */ Object.create(null);
|
7
9
|
return documents.map((source) => {
|
8
10
|
const location = source.location;
|
9
|
-
if ([".gql", ".graphql"].some((extension) => location.endsWith(extension)))
|
11
|
+
if ([".gql", ".graphql"].some((extension) => location.endsWith(extension))) {
|
10
12
|
return {
|
11
13
|
...source,
|
12
14
|
// When using glob pattern e.g. `**/*.gql` location contains always forward slashes even on
|
13
15
|
// Windows
|
14
16
|
location: path.resolve(location)
|
15
17
|
};
|
18
|
+
}
|
16
19
|
filepathMap[location] ??= -1;
|
17
20
|
const index = filepathMap[location] += 1;
|
18
21
|
return {
|
@@ -20,23 +23,26 @@ const debug = debugFactory("graphql-eslint:operations"), operationsCache = new M
|
|
20
23
|
location: path.resolve(location, `${index}_document.graphql`)
|
21
24
|
};
|
22
25
|
});
|
23
|
-
}
|
26
|
+
};
|
27
|
+
const getDocuments = (project) => {
|
24
28
|
const documentsKey = project.documents;
|
25
|
-
if (!documentsKey)
|
29
|
+
if (!documentsKey) {
|
26
30
|
return [];
|
31
|
+
}
|
27
32
|
let siblings = operationsCache.get(documentsKey);
|
28
33
|
if (!siblings) {
|
29
34
|
debug("Loading operations from %o", project.documents);
|
30
35
|
const documents = project.loadDocumentsSync(project.documents, {
|
31
|
-
skipGraphQLImport:
|
36
|
+
skipGraphQLImport: true,
|
32
37
|
pluckConfig: project.extensions.pluckConfig
|
33
38
|
});
|
34
39
|
if (debug.enabled) {
|
35
40
|
debug("Loaded %d operations", documents.length);
|
36
|
-
const operationsPaths = fg.sync(project.documents, { absolute:
|
41
|
+
const operationsPaths = fg.sync(project.documents, { absolute: true });
|
37
42
|
debug("Operations pointers %O", operationsPaths);
|
38
43
|
}
|
39
|
-
siblings = handleVirtualPath(documents)
|
44
|
+
siblings = handleVirtualPath(documents);
|
45
|
+
operationsCache.set(documentsKey, siblings);
|
40
46
|
}
|
41
47
|
return siblings;
|
42
48
|
};
|
@@ -6,14 +6,16 @@ import {
|
|
6
6
|
} from "graphql";
|
7
7
|
import { convertLocation } from "./utils.js";
|
8
8
|
function convertToESTree(node, schema) {
|
9
|
-
const typeInfo = schema && new TypeInfo(schema)
|
9
|
+
const typeInfo = schema && new TypeInfo(schema);
|
10
|
+
const visitor = {
|
10
11
|
leave(node2, key, parent) {
|
11
12
|
const leadingComments = "description" in node2 && node2.description ? [
|
12
13
|
{
|
13
14
|
type: node2.description.block ? "Block" : "Line",
|
14
15
|
value: node2.description.value
|
15
16
|
}
|
16
|
-
] : []
|
17
|
+
] : [];
|
18
|
+
const calculatedTypeInfo = typeInfo ? {
|
17
19
|
argument: typeInfo.getArgument(),
|
18
20
|
defaultValue: typeInfo.getDefaultValue(),
|
19
21
|
directive: typeInfo.getDirective(),
|
@@ -23,12 +25,19 @@ function convertToESTree(node, schema) {
|
|
23
25
|
parentInputType: typeInfo.getParentInputType(),
|
24
26
|
parentType: typeInfo.getParentType(),
|
25
27
|
gqlType: typeInfo.getType()
|
26
|
-
} : {}
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
} : {};
|
29
|
+
const rawNode = () => {
|
30
|
+
if (parent && key !== void 0) {
|
31
|
+
return parent[key];
|
32
|
+
}
|
33
|
+
return node2.kind === Kind.DOCUMENT ? {
|
34
|
+
...node2,
|
35
|
+
definitions: node2.definitions.map(
|
36
|
+
(definition) => definition.rawNode()
|
37
|
+
)
|
38
|
+
} : node2;
|
39
|
+
};
|
40
|
+
const commonFields = {
|
32
41
|
...node2,
|
33
42
|
type: node2.kind,
|
34
43
|
loc: convertLocation(node2.loc),
|
@@ -6,9 +6,14 @@ import {
|
|
6
6
|
TokenKind
|
7
7
|
} from "graphql";
|
8
8
|
import { valueFromASTUntyped } from "graphql/utilities/valueFromASTUntyped.js";
|
9
|
-
const valueFromNode = (...args) =>
|
9
|
+
const valueFromNode = (...args) => {
|
10
|
+
return valueFromASTUntyped(...args);
|
11
|
+
};
|
10
12
|
function getBaseType(type) {
|
11
|
-
|
13
|
+
if (isNonNullType(type) || isListType(type)) {
|
14
|
+
return getBaseType(type.ofType);
|
15
|
+
}
|
16
|
+
return type;
|
12
17
|
}
|
13
18
|
function convertToken(token, type) {
|
14
19
|
const { line, column, end, start, value } = token;
|
@@ -33,20 +38,24 @@ function convertToken(token, type) {
|
|
33
38
|
};
|
34
39
|
}
|
35
40
|
function extractTokens(filePath, code) {
|
36
|
-
const source = new Source(code, filePath)
|
41
|
+
const source = new Source(code, filePath);
|
42
|
+
const lexer = new Lexer(source);
|
43
|
+
const tokens = [];
|
37
44
|
let token = lexer.advance();
|
38
|
-
|
45
|
+
while (token && token.kind !== TokenKind.EOF) {
|
39
46
|
const result = convertToken(token, token.kind);
|
40
|
-
tokens.push(result)
|
47
|
+
tokens.push(result);
|
48
|
+
token = lexer.advance();
|
41
49
|
}
|
42
50
|
return tokens;
|
43
51
|
}
|
44
52
|
function extractComments(loc) {
|
45
|
-
if (!loc)
|
53
|
+
if (!loc) {
|
46
54
|
return [];
|
55
|
+
}
|
47
56
|
const comments = [];
|
48
57
|
let token = loc.startToken;
|
49
|
-
|
58
|
+
while (token) {
|
50
59
|
if (token.kind === TokenKind.COMMENT) {
|
51
60
|
const comment = convertToken(
|
52
61
|
token,
|
@@ -60,7 +69,8 @@ function extractComments(loc) {
|
|
60
69
|
return comments;
|
61
70
|
}
|
62
71
|
function convertLocation(location) {
|
63
|
-
const { startToken, endToken, source, start, end } = location
|
72
|
+
const { startToken, endToken, source, start, end } = location;
|
73
|
+
const loc = {
|
64
74
|
start: {
|
65
75
|
/*
|
66
76
|
* Kind.Document has startToken: { line: 0, column: 0 }, we set line as 1 and column as 0
|
@@ -74,7 +84,10 @@ function convertLocation(location) {
|
|
74
84
|
},
|
75
85
|
source: source.body
|
76
86
|
};
|
77
|
-
|
87
|
+
if (loc.start.column === loc.end.column) {
|
88
|
+
loc.end.column += end - start;
|
89
|
+
}
|
90
|
+
return loc;
|
78
91
|
}
|
79
92
|
export {
|
80
93
|
convertLocation,
|
package/esm/graphql-config.js
CHANGED
@@ -6,15 +6,16 @@ import { CodeFileLoader } from "@graphql-tools/code-file-loader";
|
|
6
6
|
const debug = debugFactory("graphql-eslint:graphql-config");
|
7
7
|
let graphQLConfig;
|
8
8
|
function getFirstExistingPath(filePath) {
|
9
|
-
|
9
|
+
while (!fs.existsSync(filePath)) {
|
10
10
|
filePath = path.dirname(filePath);
|
11
|
+
}
|
11
12
|
return filePath;
|
12
13
|
}
|
13
14
|
function loadOnDiskGraphQLConfig(filePath) {
|
14
15
|
return loadConfigSync({
|
15
16
|
// load config relative to the file being linted
|
16
17
|
rootDir: getFirstExistingPath(path.dirname(filePath)),
|
17
|
-
throwOnMissing:
|
18
|
+
throwOnMissing: false,
|
18
19
|
extensions: [codeFileLoaderExtension]
|
19
20
|
});
|
20
21
|
}
|
@@ -22,21 +23,27 @@ function loadGraphQLConfig({
|
|
22
23
|
graphQLConfig: config,
|
23
24
|
filePath
|
24
25
|
}) {
|
25
|
-
if (process.env.NODE_ENV !== "test" && graphQLConfig)
|
26
|
+
if (process.env.NODE_ENV !== "test" && graphQLConfig) {
|
26
27
|
return graphQLConfig;
|
28
|
+
}
|
27
29
|
debug("parserOptions.graphQLConfig: %o", config);
|
28
30
|
const onDiskConfig = !config && loadOnDiskGraphQLConfig(filePath);
|
29
|
-
|
31
|
+
if (onDiskConfig) {
|
32
|
+
debug("GraphQL-Config path %o", onDiskConfig.filepath);
|
33
|
+
}
|
30
34
|
const configOptions = config && ("projects" in config || "schemaPath" in config) ? config : {
|
31
35
|
// if `schema` is `undefined` will throw error `Project 'default' not found`
|
32
36
|
schema: config?.schema ?? "",
|
33
37
|
...config
|
34
38
|
};
|
35
|
-
|
39
|
+
graphQLConfig = onDiskConfig || new GraphQLConfig({ config: configOptions, filepath: "" }, [codeFileLoaderExtension]);
|
40
|
+
return graphQLConfig;
|
36
41
|
}
|
37
42
|
const codeFileLoaderExtension = (api) => {
|
38
43
|
const { schema, documents } = api.loaders;
|
39
|
-
|
44
|
+
schema.register(new CodeFileLoader());
|
45
|
+
documents.register(new CodeFileLoader());
|
46
|
+
return { name: "code-file-loaders" };
|
40
47
|
};
|
41
48
|
export {
|
42
49
|
getFirstExistingPath,
|
package/esm/index.d.ts
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
import { RuleOptions } from './rules/require-description/index.js';
|
2
1
|
import { CaseStyle } from './utils.js';
|
3
2
|
export { requireGraphQLOperations, requireGraphQLSchema } from './utils.js';
|
4
3
|
import * as graphql from 'graphql';
|
@@ -101,9 +100,9 @@ declare const _default: {
|
|
101
100
|
forbiddenPatterns?: {
|
102
101
|
[x: string]: unknown;
|
103
102
|
}[] | undefined;
|
104
|
-
|
103
|
+
requiredPattern?: {
|
105
104
|
[x: string]: unknown;
|
106
|
-
}
|
105
|
+
} | undefined;
|
107
106
|
forbiddenPrefixes?: string[] | undefined;
|
108
107
|
forbiddenSuffixes?: string[] | undefined;
|
109
108
|
requiredPrefixes?: string[] | undefined;
|
@@ -141,7 +140,22 @@ declare const _default: {
|
|
141
140
|
argumentName?: string | undefined;
|
142
141
|
}[]>;
|
143
142
|
'require-deprecation-reason': GraphQLESLintRule;
|
144
|
-
'require-description': GraphQLESLintRule<
|
143
|
+
'require-description': GraphQLESLintRule<{
|
144
|
+
types?: true | undefined;
|
145
|
+
OperationDefinition?: boolean | undefined;
|
146
|
+
ScalarTypeDefinition?: boolean | undefined;
|
147
|
+
ObjectTypeDefinition?: boolean | undefined;
|
148
|
+
FieldDefinition?: boolean | undefined;
|
149
|
+
InputValueDefinition?: boolean | undefined;
|
150
|
+
InterfaceTypeDefinition?: boolean | undefined;
|
151
|
+
UnionTypeDefinition?: boolean | undefined;
|
152
|
+
EnumTypeDefinition?: boolean | undefined;
|
153
|
+
EnumValueDefinition?: boolean | undefined;
|
154
|
+
InputObjectTypeDefinition?: boolean | undefined;
|
155
|
+
DirectiveDefinition?: boolean | undefined;
|
156
|
+
rootField?: true | undefined;
|
157
|
+
ignoredSelectors?: string[] | undefined;
|
158
|
+
}[]>;
|
145
159
|
'require-field-of-type-query-in-mutation-result': GraphQLESLintRule;
|
146
160
|
'require-import-fragment': GraphQLESLintRule;
|
147
161
|
'require-nullable-fields-with-oneof': GraphQLESLintRule;
|
package/esm/meta.js
CHANGED
package/esm/parser.js
CHANGED
@@ -23,19 +23,42 @@ const LEGACY_PARSER_OPTIONS_KEYS = [
|
|
23
23
|
"operations"
|
24
24
|
];
|
25
25
|
function parseForESLint(code, options) {
|
26
|
-
for (const key of LEGACY_PARSER_OPTIONS_KEYS)
|
27
|
-
if (key in options)
|
26
|
+
for (const key of LEGACY_PARSER_OPTIONS_KEYS) {
|
27
|
+
if (key in options) {
|
28
28
|
throw new Error(
|
29
29
|
`\`parserOptions.${key}\` was removed in graphql-eslint@4. Use physical graphql-config for setting schema and documents or \`parserOptions.graphQLConfig\` for programmatic usage.`
|
30
30
|
);
|
31
|
+
}
|
32
|
+
}
|
31
33
|
try {
|
32
|
-
const { filePath } = options
|
33
|
-
|
34
|
-
|
34
|
+
const { filePath } = options;
|
35
|
+
const { document } = parseGraphQLSDL(filePath, code, { noLocation: false });
|
36
|
+
let project;
|
37
|
+
let schema, documents;
|
38
|
+
if (true) {
|
39
|
+
const gqlConfig = loadGraphQLConfig(options);
|
40
|
+
project = gqlConfig.getProjectForFile(getFirstExistingPath(filePath));
|
41
|
+
documents = getDocuments(project);
|
42
|
+
} else {
|
43
|
+
documents = [
|
44
|
+
parseGraphQLSDL(
|
45
|
+
"operation.graphql",
|
46
|
+
options.graphQLConfig.documents,
|
47
|
+
{ noLocation: true }
|
48
|
+
)
|
49
|
+
];
|
50
|
+
}
|
35
51
|
try {
|
36
|
-
|
52
|
+
if (true) {
|
53
|
+
schema = getSchema(project);
|
54
|
+
} else {
|
55
|
+
schema = buildSchema(options.graphQLConfig.schema);
|
56
|
+
}
|
37
57
|
} catch (error) {
|
38
|
-
|
58
|
+
if (error instanceof Error) {
|
59
|
+
error.message = `Error while loading schema: ${error.message}`;
|
60
|
+
}
|
61
|
+
throw error;
|
39
62
|
}
|
40
63
|
const rootTree = convertToESTree(document, schema);
|
41
64
|
return {
|
@@ -54,9 +77,12 @@ function parseForESLint(code, options) {
|
|
54
77
|
}
|
55
78
|
};
|
56
79
|
} catch (error) {
|
57
|
-
if (error instanceof Error
|
80
|
+
if (error instanceof Error) {
|
81
|
+
error.message = `[graphql-eslint] ${error.message}`;
|
82
|
+
}
|
83
|
+
if (error instanceof GraphQLError) {
|
58
84
|
const location = error.locations?.[0];
|
59
|
-
|
85
|
+
const eslintError = {
|
60
86
|
index: error.positions?.[0],
|
61
87
|
...location && {
|
62
88
|
lineNumber: location.line,
|
@@ -64,6 +90,7 @@ function parseForESLint(code, options) {
|
|
64
90
|
},
|
65
91
|
message: error.message
|
66
92
|
};
|
93
|
+
throw eslintError;
|
67
94
|
}
|
68
95
|
throw error;
|
69
96
|
}
|