@graphql-eslint/eslint-plugin 2.3.0-alpha-f7157af.0 → 2.3.2-alpha-2901045.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/README.md +1 -1
- package/docs/README.md +1 -1
- package/docs/custom-rules.md +3 -3
- package/docs/rules/alphabetize.md +6 -1
- package/docs/rules/avoid-duplicate-fields.md +6 -1
- package/docs/rules/avoid-operation-name-prefix.md +5 -1
- package/docs/rules/avoid-scalar-result-type-on-mutation.md +6 -1
- package/docs/rules/avoid-typename-prefix.md +6 -1
- package/docs/rules/description-style.md +6 -1
- package/docs/rules/executable-definitions.md +6 -1
- package/docs/rules/fields-on-correct-type.md +6 -1
- package/docs/rules/fragments-on-composite-type.md +6 -1
- package/docs/rules/input-name.md +6 -1
- package/docs/rules/known-argument-names.md +6 -1
- package/docs/rules/known-directives.md +6 -1
- package/docs/rules/known-fragment-names.md +6 -1
- package/docs/rules/known-type-names.md +6 -1
- package/docs/rules/lone-anonymous-operation.md +6 -1
- package/docs/rules/lone-schema-definition.md +6 -1
- package/docs/rules/match-document-filename.md +6 -1
- package/docs/rules/naming-convention.md +6 -1
- package/docs/rules/no-anonymous-operations.md +6 -1
- package/docs/rules/no-case-insensitive-enum-values-duplicates.md +5 -1
- package/docs/rules/no-deprecated.md +6 -1
- package/docs/rules/no-fragment-cycles.md +6 -1
- package/docs/rules/no-hashtag-description.md +6 -1
- package/docs/rules/no-operation-name-suffix.md +5 -1
- package/docs/rules/no-undefined-variables.md +6 -1
- package/docs/rules/no-unreachable-types.md +6 -1
- package/docs/rules/no-unused-fields.md +6 -1
- package/docs/rules/no-unused-fragments.md +6 -1
- package/docs/rules/no-unused-variables.md +6 -1
- package/docs/rules/one-field-subscriptions.md +6 -1
- package/docs/rules/overlapping-fields-can-be-merged.md +6 -1
- package/docs/rules/possible-fragment-spread.md +6 -1
- package/docs/rules/possible-type-extension.md +6 -1
- package/docs/rules/provided-required-arguments.md +6 -1
- package/docs/rules/require-deprecation-date.md +6 -1
- package/docs/rules/require-deprecation-reason.md +6 -1
- package/docs/rules/require-description.md +6 -1
- package/docs/rules/require-field-of-type-query-in-mutation-result.md +6 -1
- package/docs/rules/require-id-when-available.md +6 -1
- package/docs/rules/scalar-leafs.md +6 -1
- package/docs/rules/selection-set-depth.md +6 -1
- package/docs/rules/strict-id-in-types.md +6 -1
- package/docs/rules/unique-argument-names.md +6 -1
- package/docs/rules/unique-directive-names-per-location.md +6 -1
- package/docs/rules/unique-directive-names.md +6 -1
- package/docs/rules/unique-enum-value-names.md +6 -1
- package/docs/rules/unique-field-definition-names.md +6 -1
- package/docs/rules/unique-fragment-name.md +6 -1
- package/docs/rules/unique-input-field-names.md +6 -1
- package/docs/rules/unique-operation-name.md +6 -1
- package/docs/rules/unique-operation-types.md +6 -1
- package/docs/rules/unique-type-names.md +6 -1
- package/docs/rules/unique-variable-names.md +6 -1
- package/docs/rules/value-literals-of-correct-type.md +6 -1
- package/docs/rules/variables-are-input-types.md +6 -1
- package/docs/rules/variables-in-allowed-position.md +6 -1
- package/index.js +167 -55
- package/index.mjs +167 -55
- package/package.json +1 -1
- package/testkit.d.ts +5 -3
- package/types.d.ts +2 -0
- package/utils.d.ts +4 -0
package/index.mjs
CHANGED
@@ -9,6 +9,8 @@ import depthLimit from 'graphql-depth-limit';
|
|
9
9
|
import { parseCode } from '@graphql-tools/graphql-tag-pluck';
|
10
10
|
import { loadConfigSync, GraphQLConfig } from 'graphql-config';
|
11
11
|
import { CodeFileLoader } from '@graphql-tools/code-file-loader';
|
12
|
+
import { RuleTester, Linter } from 'eslint';
|
13
|
+
import { codeFrameColumns } from '@babel/code-frame';
|
12
14
|
|
13
15
|
/*
|
14
16
|
* 🚨 IMPORTANT! Do not manually modify this file. Run: `yarn generate-configs`
|
@@ -236,6 +238,24 @@ const convertCase = (style, str) => {
|
|
236
238
|
return lowerCase(str).replace(/ /g, '-');
|
237
239
|
}
|
238
240
|
};
|
241
|
+
function getLocation(loc, fieldName = '', offset) {
|
242
|
+
const { start } = loc;
|
243
|
+
/*
|
244
|
+
* ESLint has 0-based column number
|
245
|
+
* https://eslint.org/docs/developer-guide/working-with-rules#contextreport
|
246
|
+
*/
|
247
|
+
const { offsetStart = 1, offsetEnd = 1 } = offset !== null && offset !== void 0 ? offset : {};
|
248
|
+
return {
|
249
|
+
start: {
|
250
|
+
line: start.line,
|
251
|
+
column: start.column - offsetStart,
|
252
|
+
},
|
253
|
+
end: {
|
254
|
+
line: start.line,
|
255
|
+
column: start.column - offsetEnd + fieldName.length,
|
256
|
+
},
|
257
|
+
};
|
258
|
+
}
|
239
259
|
|
240
260
|
function extractRuleName(stack) {
|
241
261
|
const match = (stack || '').match(/validation[/\\\\]rules[/\\\\](.*?)\.js:/) || [];
|
@@ -286,6 +306,7 @@ const validationToRule = (name, ruleName, docs, getDocumentNode) => {
|
|
286
306
|
meta: {
|
287
307
|
docs: {
|
288
308
|
...docs,
|
309
|
+
graphQLJSRuleName: ruleName,
|
289
310
|
category: 'Validation',
|
290
311
|
recommended: true,
|
291
312
|
requiresSchema,
|
@@ -585,7 +606,7 @@ const rule = {
|
|
585
606
|
],
|
586
607
|
},
|
587
608
|
messages: {
|
588
|
-
[ALPHABETIZE]: '"{{ currName }}" should be before "{{ prevName }}"
|
609
|
+
[ALPHABETIZE]: '"{{ currName }}" should be before "{{ prevName }}"',
|
589
610
|
},
|
590
611
|
schema: {
|
591
612
|
type: 'array',
|
@@ -642,19 +663,9 @@ const rule = {
|
|
642
663
|
for (const node of nodes) {
|
643
664
|
const currName = node.name.value;
|
644
665
|
if (prevName && prevName > currName) {
|
645
|
-
const { start, end } = node.name.loc;
|
646
666
|
const isVariableNode = node.kind === Kind.VARIABLE;
|
647
667
|
context.report({
|
648
|
-
loc: {
|
649
|
-
start: {
|
650
|
-
line: start.line,
|
651
|
-
column: start.column - (isVariableNode ? 2 : 1),
|
652
|
-
},
|
653
|
-
end: {
|
654
|
-
line: end.line,
|
655
|
-
column: end.column,
|
656
|
-
},
|
657
|
-
},
|
668
|
+
loc: getLocation(node.loc, node.name.value, { offsetEnd: isVariableNode ? 0 : 1 }),
|
658
669
|
messageId: ALPHABETIZE,
|
659
670
|
data: isVariableNode
|
660
671
|
? {
|
@@ -784,6 +795,7 @@ const rule$1 = {
|
|
784
795
|
messages: {
|
785
796
|
[AVOID_DUPLICATE_FIELDS]: `{{ type }} "{{ fieldName }}" defined multiple times.`,
|
786
797
|
},
|
798
|
+
schema: [],
|
787
799
|
},
|
788
800
|
create(context) {
|
789
801
|
return {
|
@@ -903,15 +915,16 @@ const rule$2 = {
|
|
903
915
|
const testKeyword = caseSensitive ? keyword : keyword.toLowerCase();
|
904
916
|
const testName = caseSensitive ? node.name.value : node.name.value.toLowerCase();
|
905
917
|
if (testName.startsWith(testKeyword)) {
|
918
|
+
const { start } = node.name.loc;
|
906
919
|
context.report({
|
907
920
|
loc: {
|
908
921
|
start: {
|
909
|
-
line:
|
910
|
-
column:
|
922
|
+
line: start.line,
|
923
|
+
column: start.column - 1,
|
911
924
|
},
|
912
925
|
end: {
|
913
|
-
line:
|
914
|
-
column:
|
926
|
+
line: start.line,
|
927
|
+
column: start.column - 1 + testKeyword.length,
|
915
928
|
},
|
916
929
|
},
|
917
930
|
data: {
|
@@ -954,6 +967,7 @@ const rule$3 = {
|
|
954
967
|
},
|
955
968
|
],
|
956
969
|
},
|
970
|
+
schema: [],
|
957
971
|
},
|
958
972
|
create(context) {
|
959
973
|
const schema = requireGraphQLSchemaFromContext('avoid-scalar-result-type-on-mutation', context);
|
@@ -1009,22 +1023,33 @@ const rule$4 = {
|
|
1009
1023
|
messages: {
|
1010
1024
|
[AVOID_TYPENAME_PREFIX]: `Field "{{ fieldName }}" starts with the name of the parent type "{{ typeName }}"`,
|
1011
1025
|
},
|
1026
|
+
schema: [],
|
1012
1027
|
},
|
1013
1028
|
create(context) {
|
1014
1029
|
return {
|
1015
1030
|
'ObjectTypeDefinition, ObjectTypeExtension, InterfaceTypeDefinition, InterfaceTypeExtension'(node) {
|
1016
1031
|
const typeName = node.name.value;
|
1017
|
-
const lowerTypeName =
|
1032
|
+
const lowerTypeName = typeName.toLowerCase();
|
1018
1033
|
for (const field of node.fields) {
|
1019
|
-
const fieldName = field.name.value
|
1020
|
-
if (fieldName
|
1034
|
+
const fieldName = field.name.value;
|
1035
|
+
if (fieldName.toLowerCase().startsWith(lowerTypeName)) {
|
1036
|
+
const { start } = field.loc;
|
1021
1037
|
context.report({
|
1022
|
-
node: field.name,
|
1023
1038
|
data: {
|
1024
1039
|
fieldName,
|
1025
1040
|
typeName,
|
1026
1041
|
},
|
1027
1042
|
messageId: AVOID_TYPENAME_PREFIX,
|
1043
|
+
loc: {
|
1044
|
+
start: {
|
1045
|
+
line: start.line,
|
1046
|
+
column: start.column - 1,
|
1047
|
+
},
|
1048
|
+
end: {
|
1049
|
+
line: start.line,
|
1050
|
+
column: start.column - 1 + lowerTypeName.length,
|
1051
|
+
},
|
1052
|
+
},
|
1028
1053
|
});
|
1029
1054
|
}
|
1030
1055
|
}
|
@@ -1352,7 +1377,8 @@ const rule$7 = {
|
|
1352
1377
|
var _a;
|
1353
1378
|
if (options.fileExtension && options.fileExtension !== fileExtension) {
|
1354
1379
|
context.report({
|
1355
|
-
|
1380
|
+
// Report on first character
|
1381
|
+
loc: { column: 0, line: 1 },
|
1356
1382
|
messageId: MATCH_EXTENSION,
|
1357
1383
|
data: {
|
1358
1384
|
fileExtension,
|
@@ -1384,7 +1410,8 @@ const rule$7 = {
|
|
1384
1410
|
const filenameWithExtension = filename + expectedExtension;
|
1385
1411
|
if (expectedFilename !== filenameWithExtension) {
|
1386
1412
|
context.report({
|
1387
|
-
|
1413
|
+
// Report on first character
|
1414
|
+
loc: { column: 0, line: 1 },
|
1388
1415
|
messageId: MATCH_STYLE,
|
1389
1416
|
data: {
|
1390
1417
|
expectedFilename,
|
@@ -1722,20 +1749,24 @@ const rule$9 = {
|
|
1722
1749
|
messages: {
|
1723
1750
|
[NO_ANONYMOUS_OPERATIONS]: `Anonymous GraphQL operations are forbidden. Please make sure to name your {{ operation }}!`,
|
1724
1751
|
},
|
1752
|
+
schema: [],
|
1725
1753
|
},
|
1726
1754
|
create(context) {
|
1727
1755
|
return {
|
1728
1756
|
OperationDefinition(node) {
|
1729
|
-
|
1757
|
+
var _a;
|
1758
|
+
const isAnonymous = (((_a = node.name) === null || _a === void 0 ? void 0 : _a.value) || '').length === 0;
|
1759
|
+
if (isAnonymous) {
|
1760
|
+
const { start } = node.loc;
|
1730
1761
|
context.report({
|
1731
1762
|
loc: {
|
1732
1763
|
start: {
|
1733
|
-
column:
|
1734
|
-
line:
|
1764
|
+
column: start.column - 1,
|
1765
|
+
line: start.line,
|
1735
1766
|
},
|
1736
1767
|
end: {
|
1737
|
-
column:
|
1738
|
-
line:
|
1768
|
+
column: start.column - 1 + node.operation.length,
|
1769
|
+
line: start.line,
|
1739
1770
|
},
|
1740
1771
|
},
|
1741
1772
|
data: {
|
@@ -1785,6 +1816,7 @@ const rule$a = {
|
|
1785
1816
|
messages: {
|
1786
1817
|
[ERROR_MESSAGE_ID]: `Case-insensitive enum values duplicates are not allowed! Found: "{{ found }}"`,
|
1787
1818
|
},
|
1819
|
+
schema: [],
|
1788
1820
|
},
|
1789
1821
|
create(context) {
|
1790
1822
|
return {
|
@@ -1879,6 +1911,7 @@ const rule$b = {
|
|
1879
1911
|
messages: {
|
1880
1912
|
[NO_DEPRECATED]: `This {{ type }} is marked as deprecated in your GraphQL schema {{ reason }}`,
|
1881
1913
|
},
|
1914
|
+
schema: [],
|
1882
1915
|
},
|
1883
1916
|
create(context) {
|
1884
1917
|
return {
|
@@ -1965,6 +1998,7 @@ const rule$c = {
|
|
1965
1998
|
],
|
1966
1999
|
},
|
1967
2000
|
type: 'suggestion',
|
2001
|
+
schema: [],
|
1968
2002
|
},
|
1969
2003
|
create(context) {
|
1970
2004
|
return {
|
@@ -2025,15 +2059,28 @@ const rule$d = {
|
|
2025
2059
|
messages: {
|
2026
2060
|
[NO_OPERATION_NAME_SUFFIX]: `Unnecessary "{{ invalidSuffix }}" suffix in your operation name!`,
|
2027
2061
|
},
|
2062
|
+
schema: [],
|
2028
2063
|
},
|
2029
2064
|
create(context) {
|
2030
2065
|
return {
|
2031
2066
|
'OperationDefinition, FragmentDefinition'(node) {
|
2032
|
-
|
2033
|
-
|
2034
|
-
|
2067
|
+
var _a;
|
2068
|
+
const name = ((_a = node.name) === null || _a === void 0 ? void 0 : _a.value) || '';
|
2069
|
+
if (name.length > 0) {
|
2070
|
+
const invalidSuffix = 'operation' in node ? node.operation : 'fragment';
|
2071
|
+
if (name.toLowerCase().endsWith(invalidSuffix)) {
|
2072
|
+
const { start, end } = node.name.loc;
|
2035
2073
|
context.report({
|
2036
|
-
|
2074
|
+
loc: {
|
2075
|
+
start: {
|
2076
|
+
column: start.column - 1 + name.length - invalidSuffix.length,
|
2077
|
+
line: start.line,
|
2078
|
+
},
|
2079
|
+
end: {
|
2080
|
+
column: end.column - 1 + name.length,
|
2081
|
+
line: end.line,
|
2082
|
+
},
|
2083
|
+
},
|
2037
2084
|
data: {
|
2038
2085
|
invalidSuffix,
|
2039
2086
|
},
|
@@ -2090,6 +2137,7 @@ const rule$e = {
|
|
2090
2137
|
},
|
2091
2138
|
fixable: 'code',
|
2092
2139
|
type: 'suggestion',
|
2140
|
+
schema: [],
|
2093
2141
|
},
|
2094
2142
|
create(context) {
|
2095
2143
|
const reachableTypes = requireReachableTypesFromContext(RULE_NAME, context);
|
@@ -2181,6 +2229,7 @@ const rule$f = {
|
|
2181
2229
|
},
|
2182
2230
|
fixable: 'code',
|
2183
2231
|
type: 'suggestion',
|
2232
|
+
schema: [],
|
2184
2233
|
},
|
2185
2234
|
create(context) {
|
2186
2235
|
const usedFields = requireUsedFieldsFromContext(RULE_NAME$1, context);
|
@@ -2446,6 +2495,7 @@ const rule$h = {
|
|
2446
2495
|
],
|
2447
2496
|
},
|
2448
2497
|
type: 'suggestion',
|
2498
|
+
schema: [],
|
2449
2499
|
},
|
2450
2500
|
create(context) {
|
2451
2501
|
return {
|
@@ -2482,15 +2532,18 @@ const DESCRIBABLE_NODES = [
|
|
2482
2532
|
function verifyRule(context, node) {
|
2483
2533
|
if (node) {
|
2484
2534
|
if (!node.description || !node.description.value || node.description.value.trim().length === 0) {
|
2535
|
+
const { start, end } = ('name' in node ? node.name : node).loc;
|
2485
2536
|
context.report({
|
2486
2537
|
loc: {
|
2487
2538
|
start: {
|
2488
|
-
line:
|
2489
|
-
column:
|
2539
|
+
line: start.line,
|
2540
|
+
column: start.column - 1,
|
2490
2541
|
},
|
2491
2542
|
end: {
|
2492
|
-
line:
|
2493
|
-
column:
|
2543
|
+
line: end.line,
|
2544
|
+
column:
|
2545
|
+
// node.name don't exist on SchemaDefinition
|
2546
|
+
'name' in node ? end.column - 1 + node.name.value.length : end.column,
|
2494
2547
|
},
|
2495
2548
|
},
|
2496
2549
|
messageId: REQUIRE_DESCRIPTION_ERROR,
|
@@ -2604,6 +2657,7 @@ const rule$j = {
|
|
2604
2657
|
},
|
2605
2658
|
],
|
2606
2659
|
},
|
2660
|
+
schema: [],
|
2607
2661
|
},
|
2608
2662
|
create(context) {
|
2609
2663
|
const schema = requireGraphQLSchemaFromContext(RULE_NAME$2, context);
|
@@ -3140,11 +3194,7 @@ const rule$m = {
|
|
3140
3194
|
const RULE_NAME$3 = 'unique-fragment-name';
|
3141
3195
|
const UNIQUE_FRAGMENT_NAME = 'UNIQUE_FRAGMENT_NAME';
|
3142
3196
|
const checkNode = (context, node, ruleName, messageId) => {
|
3143
|
-
|
3144
|
-
const documentName = (_a = node.name) === null || _a === void 0 ? void 0 : _a.value;
|
3145
|
-
if (!documentName) {
|
3146
|
-
return;
|
3147
|
-
}
|
3197
|
+
const documentName = node.name.value;
|
3148
3198
|
const siblings = requireSiblingsOperations(ruleName, context);
|
3149
3199
|
const siblingDocuments = node.kind === Kind.FRAGMENT_DEFINITION ? siblings.getFragment(documentName) : siblings.getOperation(documentName);
|
3150
3200
|
const filepath = context.getFilename();
|
@@ -3155,7 +3205,6 @@ const checkNode = (context, node, ruleName, messageId) => {
|
|
3155
3205
|
return isSameName && !isSamePath;
|
3156
3206
|
});
|
3157
3207
|
if (conflictingDocuments.length > 0) {
|
3158
|
-
const { start, end } = node.name.loc;
|
3159
3208
|
context.report({
|
3160
3209
|
messageId,
|
3161
3210
|
data: {
|
@@ -3164,16 +3213,7 @@ const checkNode = (context, node, ruleName, messageId) => {
|
|
3164
3213
|
.map(f => `\t${relative(process.cwd(), getOnDiskFilepath(f.filePath))}`)
|
3165
3214
|
.join('\n'),
|
3166
3215
|
},
|
3167
|
-
loc:
|
3168
|
-
start: {
|
3169
|
-
line: start.line,
|
3170
|
-
column: start.column - 1,
|
3171
|
-
},
|
3172
|
-
end: {
|
3173
|
-
line: end.line,
|
3174
|
-
column: end.column - 1,
|
3175
|
-
},
|
3176
|
-
},
|
3216
|
+
loc: getLocation(node.name.loc, documentName),
|
3177
3217
|
});
|
3178
3218
|
}
|
3179
3219
|
};
|
@@ -3223,6 +3263,7 @@ const rule$n = {
|
|
3223
3263
|
messages: {
|
3224
3264
|
[UNIQUE_FRAGMENT_NAME]: 'Fragment named "{{ documentName }}" already defined in:\n{{ summary }}',
|
3225
3265
|
},
|
3266
|
+
schema: [],
|
3226
3267
|
},
|
3227
3268
|
create(context) {
|
3228
3269
|
return {
|
@@ -3285,10 +3326,11 @@ const rule$o = {
|
|
3285
3326
|
messages: {
|
3286
3327
|
[UNIQUE_OPERATION_NAME]: 'Operation named "{{ documentName }}" already defined in:\n{{ summary }}',
|
3287
3328
|
},
|
3329
|
+
schema: [],
|
3288
3330
|
},
|
3289
3331
|
create(context) {
|
3290
3332
|
return {
|
3291
|
-
OperationDefinition(node) {
|
3333
|
+
'OperationDefinition[name!=undefined]'(node) {
|
3292
3334
|
checkNode(context, node, RULE_NAME$4, UNIQUE_OPERATION_NAME);
|
3293
3335
|
},
|
3294
3336
|
};
|
@@ -3718,22 +3760,92 @@ function parseForESLint(code, options = {}) {
|
|
3718
3760
|
}
|
3719
3761
|
}
|
3720
3762
|
|
3721
|
-
class GraphQLRuleTester extends
|
3763
|
+
class GraphQLRuleTester extends RuleTester {
|
3722
3764
|
constructor(parserOptions = {}) {
|
3723
|
-
|
3765
|
+
const config = {
|
3724
3766
|
parser: require.resolve('@graphql-eslint/eslint-plugin'),
|
3725
3767
|
parserOptions: {
|
3726
3768
|
...parserOptions,
|
3727
3769
|
skipGraphQLConfig: true,
|
3728
3770
|
},
|
3729
|
-
}
|
3771
|
+
};
|
3772
|
+
super(config);
|
3773
|
+
this.config = config;
|
3730
3774
|
}
|
3731
3775
|
fromMockFile(path) {
|
3732
3776
|
return readFileSync(resolve(__dirname, `../tests/mocks/${path}`), 'utf-8');
|
3733
3777
|
}
|
3734
3778
|
runGraphQLTests(name, rule, tests) {
|
3735
3779
|
super.run(name, rule, tests);
|
3780
|
+
// Skip snapshot testing if `expect` variable is not defined
|
3781
|
+
if (typeof expect === 'undefined') {
|
3782
|
+
return;
|
3783
|
+
}
|
3784
|
+
const linter = new Linter();
|
3785
|
+
linter.defineRule(name, rule);
|
3786
|
+
for (const testCase of tests.invalid) {
|
3787
|
+
const verifyConfig = getVerifyConfig(name, this.config, testCase);
|
3788
|
+
defineParser(linter, verifyConfig.parser);
|
3789
|
+
const { code, filename } = testCase;
|
3790
|
+
const messages = linter.verify(code, verifyConfig, { filename });
|
3791
|
+
for (const message of messages) {
|
3792
|
+
if (message.fatal) {
|
3793
|
+
throw new Error(message.message);
|
3794
|
+
}
|
3795
|
+
const messageForSnapshot = visualizeEslintMessage(code, message);
|
3796
|
+
// eslint-disable-next-line no-undef
|
3797
|
+
expect(messageForSnapshot).toMatchSnapshot();
|
3798
|
+
}
|
3799
|
+
}
|
3800
|
+
}
|
3801
|
+
}
|
3802
|
+
function getVerifyConfig(ruleId, testerConfig, testCase) {
|
3803
|
+
const { options, parserOptions, parser = testerConfig.parser } = testCase;
|
3804
|
+
return {
|
3805
|
+
...testerConfig,
|
3806
|
+
parser,
|
3807
|
+
parserOptions: {
|
3808
|
+
...testerConfig.parserOptions,
|
3809
|
+
...parserOptions,
|
3810
|
+
},
|
3811
|
+
rules: {
|
3812
|
+
[ruleId]: ['error', ...(Array.isArray(options) ? options : [])],
|
3813
|
+
},
|
3814
|
+
};
|
3815
|
+
}
|
3816
|
+
const parsers = new WeakMap();
|
3817
|
+
function defineParser(linter, parser) {
|
3818
|
+
if (!parser) {
|
3819
|
+
return;
|
3820
|
+
}
|
3821
|
+
if (!parsers.has(linter)) {
|
3822
|
+
parsers.set(linter, new Set());
|
3823
|
+
}
|
3824
|
+
const defined = parsers.get(linter);
|
3825
|
+
if (!defined.has(parser)) {
|
3826
|
+
defined.add(parser);
|
3827
|
+
linter.defineParser(parser, require(parser));
|
3736
3828
|
}
|
3737
3829
|
}
|
3830
|
+
function visualizeEslintMessage(text, result) {
|
3831
|
+
const { line, column, endLine, endColumn, message } = result;
|
3832
|
+
const location = {
|
3833
|
+
start: {
|
3834
|
+
line,
|
3835
|
+
column,
|
3836
|
+
},
|
3837
|
+
};
|
3838
|
+
if (typeof endLine === 'number' && typeof endColumn === 'number') {
|
3839
|
+
location.end = {
|
3840
|
+
line: endLine,
|
3841
|
+
column: endColumn,
|
3842
|
+
};
|
3843
|
+
}
|
3844
|
+
return codeFrameColumns(text, location, {
|
3845
|
+
linesAbove: Number.POSITIVE_INFINITY,
|
3846
|
+
linesBelow: Number.POSITIVE_INFINITY,
|
3847
|
+
message,
|
3848
|
+
});
|
3849
|
+
}
|
3738
3850
|
|
3739
3851
|
export { GraphQLRuleTester, configs, convertDescription, convertLocation, convertRange, convertToESTree, extractCommentsFromAst, getBaseType, isNodeWithDescription, parse, parseForESLint, processors, rules, valueFromNode };
|
package/package.json
CHANGED
package/testkit.d.ts
CHANGED
@@ -13,8 +13,11 @@ export declare type GraphQLInvalidTestCase<T> = GraphQLValidTestCase<T> & {
|
|
13
13
|
errors: number | Array<RuleTester.TestCaseError | string>;
|
14
14
|
output?: string | null;
|
15
15
|
};
|
16
|
-
declare
|
17
|
-
|
16
|
+
export declare class GraphQLRuleTester extends RuleTester {
|
17
|
+
config: {
|
18
|
+
parser: string;
|
19
|
+
parserOptions: ParserOptions;
|
20
|
+
};
|
18
21
|
constructor(parserOptions?: ParserOptions);
|
19
22
|
fromMockFile(path: string): string;
|
20
23
|
runGraphQLTests<Config>(name: string, rule: GraphQLESLintRule, tests: {
|
@@ -22,4 +25,3 @@ export declare class GraphQLRuleTester extends GraphQLRuleTester_base {
|
|
22
25
|
invalid: GraphQLInvalidTestCase<Config>[];
|
23
26
|
}): void;
|
24
27
|
}
|
25
|
-
export {};
|
package/types.d.ts
CHANGED
@@ -56,9 +56,11 @@ export declare type RuleDocsInfo<T> = Rule.RuleMetaData & {
|
|
56
56
|
usage?: T;
|
57
57
|
}[];
|
58
58
|
optionsForConfig?: T;
|
59
|
+
graphQLJSRuleName?: string;
|
59
60
|
};
|
60
61
|
};
|
61
62
|
export declare type GraphQLESLintRule<Options = any[], WithTypeInfo extends boolean = false> = {
|
62
63
|
create(context: GraphQLESLintRuleContext<Options>): GraphQLESLintRuleListener<WithTypeInfo>;
|
63
64
|
meta: Rule.RuleMetaData & RuleDocsInfo<Options>;
|
64
65
|
};
|
66
|
+
export declare type ValueOf<T> = T[keyof T];
|
package/utils.d.ts
CHANGED
@@ -33,4 +33,8 @@ export declare enum CaseStyle {
|
|
33
33
|
}
|
34
34
|
export declare const camelCase: (str: string) => string;
|
35
35
|
export declare const convertCase: (style: CaseStyle, str: string) => string;
|
36
|
+
export declare function getLocation(loc: Partial<AST.SourceLocation>, fieldName?: string, offset?: {
|
37
|
+
offsetStart?: number;
|
38
|
+
offsetEnd?: number;
|
39
|
+
}): AST.SourceLocation;
|
36
40
|
export {};
|